From 01ec4dbb1251751b8bbf62ddb3b3a02dc50d29fc Mon Sep 17 00:00:00 2001
From: Taylor Gerring <taylor.gerring@gmail.com>
Date: Sun, 14 Jun 2015 17:55:03 -0400
Subject: Add stdin option

---
 cmd/ethtest/main.go            |  60 ++++++++++-----
 tests/block_test_util.go       |  80 ++++++++++++++------
 tests/init.go                  |  75 ++++++++++++------
 tests/state_test_util.go       | 166 ++++++++++++++++++++++++----------------
 tests/transaction_test_util.go |  39 ++++++++--
 tests/vm_test_util.go          | 167 +++++++++++++++++++++++++----------------
 6 files changed, 386 insertions(+), 201 deletions(-)

diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go
index a78111797..93bf3ce65 100644
--- a/cmd/ethtest/main.go
+++ b/cmd/ethtest/main.go
@@ -24,6 +24,7 @@ package main
 
 import (
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -55,28 +56,37 @@ var (
 		Name:  "continue",
 		Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
 	}
+	ReadStdInFlag = cli.BoolFlag{
+		Name:  "stdin",
+		Usage: "Accept input from stdin instead of reading from file",
+	}
 )
 
-func runTest(test, file string) error {
-	// glog.Infoln("runTest", test, file)
+func runTestWithReader(test string, r io.Reader) error {
+	glog.Infoln("runTest", test)
 	var err error
 	switch test {
-	case "bc", "BlockTest", "BlockTests", "BlockChainTest":
-		err = tests.RunBlockTest(file)
+	case "bt", "BlockTest", "BlockTests", "BlockChainTest":
+		err = tests.RunBlockTestWithReader(r)
 	case "st", "state", "StateTest", "StateTests":
-		err = tests.RunStateTest(file)
+		err = tests.RunStateTestWithReader(r)
 	case "tx", "TransactionTest", "TransactionTests":
-		err = tests.RunTransactionTests(file)
+		err = tests.RunTransactionTestsWithReader(r)
 	case "vm", "VMTest", "VMTests":
-		err = tests.RunVmTest(file)
+		err = tests.RunVmTestWithReader(r)
 	default:
-		err = fmt.Errorf("Invalid test type specified:", test)
+		err = fmt.Errorf("Invalid test type specified: %v", test)
+	}
+
+	if err != nil {
+		return err
 	}
-	return err
+
+	return nil
 }
 
 func getFiles(path string) ([]string, error) {
-	// glog.Infoln("getFiles", path)
+	glog.Infoln("getFiles", path)
 	var files []string
 	f, err := os.Open(path)
 	if err != nil {
@@ -97,7 +107,7 @@ func getFiles(path string) ([]string, error) {
 			// only go 1 depth and leave directory entires blank
 			if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
 				files[i] = filepath.Join(path, v.Name())
-				// glog.Infoln("Found file", files[i])
+				glog.Infoln("Found file", files[i])
 			}
 		}
 	case mode.IsRegular():
@@ -118,7 +128,7 @@ func runSuite(test, file string) {
 	}
 
 	for _, curTest := range tests {
-		// glog.Infoln("runSuite", curTest, file)
+		glog.Infoln("runSuite", curTest, file)
 		var err error
 		var files []string
 		if test == defaultTest {
@@ -134,16 +144,19 @@ func runSuite(test, file string) {
 		if len(files) == 0 {
 			glog.Warningln("No files matched path")
 		}
-		for _, testfile := range files {
+		for _, curFile := range files {
 			// Skip blank entries
-			if len(testfile) == 0 {
+			if len(curFile) == 0 {
 				continue
 			}
 
-			// TODO allow io.Reader to be passed so Stdin can be piped
-			// RunVmTest(strings.NewReader(os.Args[2]))
-			// RunVmTest(os.Stdin)
-			err := runTest(curTest, testfile)
+			r, err := os.Open(curFile)
+			if err != nil {
+				glog.Fatalln(err)
+			}
+			defer r.Close()
+
+			err = runTestWithReader(curTest, r)
 			if err != nil {
 				if continueOnError {
 					glog.Errorln(err)
@@ -160,8 +173,16 @@ func setupApp(c *cli.Context) {
 	flagTest := c.GlobalString(TestFlag.Name)
 	flagFile := c.GlobalString(FileFlag.Name)
 	continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
+	useStdIn := c.GlobalBool(ReadStdInFlag.Name)
+
+	if !useStdIn {
+		runSuite(flagTest, flagFile)
+	} else {
+		if err := runTestWithReader(flagTest, os.Stdin); err != nil {
+			glog.Fatalln(err)
+		}
 
-	runSuite(flagTest, flagFile)
+	}
 }
 
 func main() {
@@ -178,6 +199,7 @@ func main() {
 		TestFlag,
 		FileFlag,
 		ContinueOnErrorFlag,
+		ReadStdInFlag,
 	}
 
 	if err := app.Run(os.Args); err != nil {
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 21fd07db6..5222b214b 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"encoding/hex"
 	"fmt"
+	"io"
 	"math/big"
 	"path/filepath"
 	"runtime"
@@ -85,15 +86,42 @@ type btTransaction struct {
 	Value    string
 }
 
-func RunBlockTest(filepath string) error {
-	bt, err := LoadBlockTests(filepath)
+func RunBlockTestWithReader(r io.Reader) error {
+	btjs := make(map[string]*btJSON)
+	if err := readJson(r, &btjs); err != nil {
+		return err
+	}
+
+	bt, err := convertBlockTests(btjs)
 	if err != nil {
 		return err
 	}
 
-	// map skipped tests to boolean set
-	skipTest := make(map[string]bool, len(blockSkipTests))
-	for _, name := range blockSkipTests {
+	if err := runBlockTests(bt); err != nil {
+		return err
+	}
+	return nil
+}
+
+func RunBlockTest(file string) error {
+	btjs := make(map[string]*btJSON)
+	if err := readJsonFile(file, &btjs); err != nil {
+		return err
+	}
+
+	bt, err := convertBlockTests(btjs)
+	if err != nil {
+		return err
+	}
+	if err := runBlockTests(bt); err != nil {
+		return err
+	}
+	return nil
+}
+
+func runBlockTests(bt map[string]*BlockTest) error {
+	skipTest := make(map[string]bool, len(BlockSkipTests))
+	for _, name := range BlockSkipTests {
 		skipTest[name] = true
 	}
 
@@ -103,17 +131,19 @@ func RunBlockTest(filepath string) error {
 			glog.Infoln("Skipping block test", name)
 			return nil
 		}
+
 		// test the block
-		if err := testBlock(test); err != nil {
+		if err := runBlockTest(test); err != nil {
 			return err
 		}
 		glog.Infoln("Block test passed: ", name)
+
 	}
 	return nil
-}
 
-func testBlock(test *BlockTest) error {
-	cfg := testEthConfig()
+}
+func runBlockTest(test *BlockTest) error {
+	cfg := test.makeEthConfig()
 	ethereum, err := eth.New(cfg)
 	if err != nil {
 		return err
@@ -144,7 +174,7 @@ func testBlock(test *BlockTest) error {
 	return nil
 }
 
-func testEthConfig() *eth.Config {
+func (test *BlockTest) makeEthConfig() *eth.Config {
 	ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore"))
 
 	return &eth.Config{
@@ -230,7 +260,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
 		if b.BlockHeader == nil {
 			return fmt.Errorf("Block insertion should have failed")
 		}
-		err = validateBlockHeader(b.BlockHeader, cb.Header())
+		err = t.validateBlockHeader(b.BlockHeader, cb.Header())
 		if err != nil {
 			return fmt.Errorf("Block header validation failed: ", err)
 		}
@@ -238,7 +268,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
 	return nil
 }
 
-func validateBlockHeader(h *btHeader, h2 *types.Header) error {
+func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error {
 	expectedBloom := mustConvertBytes(h.Bloom)
 	if !bytes.Equal(expectedBloom, h2.Bloom.Bytes()) {
 		return fmt.Errorf("Bloom: expected: %v, decoded: %v", expectedBloom, h2.Bloom.Bytes())
@@ -341,7 +371,18 @@ func (t *BlockTest) ValidatePostState(statedb *state.StateDB) error {
 	return nil
 }
 
-func convertTest(in *btJSON) (out *BlockTest, err error) {
+func convertBlockTests(in map[string]*btJSON) (map[string]*BlockTest, error) {
+	out := make(map[string]*BlockTest)
+	for name, test := range in {
+		var err error
+		if out[name], err = convertBlockTest(test); err != nil {
+			return out, fmt.Errorf("bad test %q: %v", name, err)
+		}
+	}
+	return out, nil
+}
+
+func convertBlockTest(in *btJSON) (out *BlockTest, err error) {
 	// the conversion handles errors by catching panics.
 	// you might consider this ugly, but the alternative (passing errors)
 	// would be much harder to read.
@@ -450,19 +491,12 @@ func mustConvertUint(in string, base int) uint64 {
 }
 
 func LoadBlockTests(file string) (map[string]*BlockTest, error) {
-	bt := make(map[string]*btJSON)
-	if err := readTestFile(file, &bt); err != nil {
+	btjs := make(map[string]*btJSON)
+	if err := readJsonFile(file, &btjs); err != nil {
 		return nil, err
 	}
 
-	out := make(map[string]*BlockTest)
-	for name, in := range bt {
-		var err error
-		if out[name], err = convertTest(in); err != nil {
-			return out, fmt.Errorf("bad test %q: %v", name, err)
-		}
-	}
-	return out, nil
+	return convertBlockTests(btjs)
 }
 
 // Nothing to see here, please move along...
diff --git a/tests/init.go b/tests/init.go
index 164924ab8..326387341 100644
--- a/tests/init.go
+++ b/tests/init.go
@@ -8,6 +8,8 @@ import (
 	"net/http"
 	"os"
 	"path/filepath"
+
+	// "github.com/ethereum/go-ethereum/logger/glog"
 )
 
 var (
@@ -17,13 +19,40 @@ var (
 	transactionTestDir = filepath.Join(baseDir, "TransactionTests")
 	vmTestDir          = filepath.Join(baseDir, "VMTests")
 
-	blockSkipTests = []string{"SimpleTx3"}
-	transSkipTests = []string{"TransactionWithHihghNonce256"}
-	stateSkipTests = []string{"mload32bitBound_return", "mload32bitBound_return2"}
-	vmSkipTests    = []string{}
+	BlockSkipTests = []string{"SimpleTx3"}
+	TransSkipTests = []string{"TransactionWithHihghNonce256"}
+	StateSkipTests = []string{"mload32bitBound_return", "mload32bitBound_return2"}
+	VmSkipTests    = []string{}
 )
 
-func readJSON(reader io.Reader, value interface{}) error {
+// type TestRunner interface {
+// 	// LoadTest()
+// 	RunTest() error
+// }
+
+// func RunTests(bt map[string]TestRunner, skipTests []string) error {
+// 	// map skipped tests to boolean set
+// 	skipTest := make(map[string]bool, len(skipTests))
+// 	for _, name := range skipTests {
+// 		skipTest[name] = true
+// 	}
+
+// 	for name, test := range bt {
+// 		// if the test should be skipped, return
+// 		if skipTest[name] {
+// 			glog.Infoln("Skipping block test", name)
+// 			return nil
+// 		}
+// 		// test the block
+// 		if err := test.RunTest(); err != nil {
+// 			return err
+// 		}
+// 		glog.Infoln("Block test passed: ", name)
+// 	}
+// 	return nil
+// }
+
+func readJson(reader io.Reader, value interface{}) error {
 	data, err := ioutil.ReadAll(reader)
 	if err != nil {
 		return fmt.Errorf("Error reading JSON file", err.Error())
@@ -39,44 +68,44 @@ func readJSON(reader io.Reader, value interface{}) error {
 	return nil
 }
 
-// findLine returns the line number for the given offset into data.
-func findLine(data []byte, offset int64) (line int) {
-	line = 1
-	for i, r := range string(data) {
-		if int64(i) >= offset {
-			return
-		}
-		if r == '\n' {
-			line++
-		}
-	}
-	return
-}
-
-func readHttpFile(uri string, value interface{}) error {
+func readJsonHttp(uri string, value interface{}) error {
 	resp, err := http.Get(uri)
 	if err != nil {
 		return err
 	}
 	defer resp.Body.Close()
 
-	err = readJSON(resp.Body, value)
+	err = readJson(resp.Body, value)
 	if err != nil {
 		return err
 	}
 	return nil
 }
 
-func readTestFile(fn string, value interface{}) error {
+func readJsonFile(fn string, value interface{}) error {
 	file, err := os.Open(fn)
 	if err != nil {
 		return err
 	}
 	defer file.Close()
 
-	err = readJSON(file, value)
+	err = readJson(file, value)
 	if err != nil {
 		return fmt.Errorf("%s in file %s", err.Error(), fn)
 	}
 	return nil
 }
+
+// findLine returns the line number for the given offset into data.
+func findLine(data []byte, offset int64) (line int) {
+	line = 1
+	for i, r := range string(data) {
+		if int64(i) >= offset {
+			return
+		}
+		if r == '\n' {
+			line++
+		}
+	}
+	return
+}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index ad14168c7..ad3aeea6c 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -3,6 +3,7 @@ package tests
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"math/big"
 	"strconv"
 
@@ -15,100 +16,133 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 )
 
-func RunStateTest(p string) error {
-	skipTest := make(map[string]bool, len(stateSkipTests))
-	for _, name := range stateSkipTests {
-		skipTest[name] = true
+func RunStateTestWithReader(r io.Reader) error {
+	tests := make(map[string]VmTest)
+	if err := readJson(r, &tests); err != nil {
+		return err
 	}
 
+	if err := runStateTests(tests); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func RunStateTest(p string) error {
 	tests := make(map[string]VmTest)
-	readTestFile(p, &tests)
+	if err := readJsonFile(p, &tests); err != nil {
+		return err
+	}
+
+	if err := runStateTests(tests); err != nil {
+		return err
+	}
+
+	return nil
+
+}
+
+func runStateTests(tests map[string]VmTest) error {
+	skipTest := make(map[string]bool, len(StateSkipTests))
+	for _, name := range StateSkipTests {
+		skipTest[name] = true
+	}
 
 	for name, test := range tests {
 		if skipTest[name] {
 			glog.Infoln("Skipping state test", name)
 			return nil
 		}
-		db, _ := ethdb.NewMemDatabase()
-		statedb := state.New(common.Hash{}, db)
-		for addr, account := range test.Pre {
-			obj := StateObjectFromAccount(db, addr, account)
-			statedb.SetStateObject(obj)
-			for a, v := range account.Storage {
-				obj.SetState(common.HexToHash(a), common.HexToHash(s))
-			}
-		}
 
-		// XXX Yeah, yeah...
-		env := make(map[string]string)
-		env["currentCoinbase"] = test.Env.CurrentCoinbase
-		env["currentDifficulty"] = test.Env.CurrentDifficulty
-		env["currentGasLimit"] = test.Env.CurrentGasLimit
-		env["currentNumber"] = test.Env.CurrentNumber
-		env["previousHash"] = test.Env.PreviousHash
-		if n, ok := test.Env.CurrentTimestamp.(float64); ok {
-			env["currentTimestamp"] = strconv.Itoa(int(n))
-		} else {
-			env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+		if err := runStateTest(test); err != nil {
+			return fmt.Errorf("%s: %s\n", name, err.Error())
 		}
 
-		var (
-			ret []byte
-			// gas  *big.Int
-			// err  error
-			logs state.Logs
-		)
+		glog.Infoln("State test passed: ", name)
+		//fmt.Println(string(statedb.Dump()))
+	}
+	return nil
 
-		ret, logs, _, _ = RunState(statedb, env, test.Transaction)
+}
 
-		// // Compare expected  and actual return
-		rexp := common.FromHex(test.Out)
-		if bytes.Compare(rexp, ret) != 0 {
-			return fmt.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
+func runStateTest(test VmTest) error {
+	db, _ := ethdb.NewMemDatabase()
+	statedb := state.New(common.Hash{}, db)
+	for addr, account := range test.Pre {
+		obj := StateObjectFromAccount(db, addr, account)
+		statedb.SetStateObject(obj)
+		for a, v := range account.Storage {
+			obj.SetState(common.HexToHash(a), common.HexToHash(v))
 		}
+	}
 
-		// check post state
-		for addr, account := range test.Post {
-			obj := statedb.GetStateObject(common.HexToAddress(addr))
-			if obj == nil {
-				continue
-			}
+	// XXX Yeah, yeah...
+	env := make(map[string]string)
+	env["currentCoinbase"] = test.Env.CurrentCoinbase
+	env["currentDifficulty"] = test.Env.CurrentDifficulty
+	env["currentGasLimit"] = test.Env.CurrentGasLimit
+	env["currentNumber"] = test.Env.CurrentNumber
+	env["previousHash"] = test.Env.PreviousHash
+	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
+		env["currentTimestamp"] = strconv.Itoa(int(n))
+	} else {
+		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+	}
 
-			if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
-				return fmt.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance()))
-			}
+	var (
+		ret []byte
+		// gas  *big.Int
+		// err  error
+		logs state.Logs
+	)
 
-			if obj.Nonce() != common.String2Big(account.Nonce).Uint64() {
-				return fmt.Errorf("%s's : (%x) nonce failed. Expected %v, got %v\n", name, obj.Address().Bytes()[:4], account.Nonce, obj.Nonce())
-			}
+	ret, logs, _, _ = RunState(statedb, env, test.Transaction)
+
+	// // Compare expected  and actual return
+	rexp := common.FromHex(test.Out)
+	if bytes.Compare(rexp, ret) != 0 {
+		return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
+	}
 
-			for addr, value := range account.Storage {
-				v := obj.GetState(common.HexToHash(addr)).Bytes()
-				vexp := common.FromHex(value)
+	// check post state
+	for addr, account := range test.Post {
+		obj := statedb.GetStateObject(common.HexToAddress(addr))
+		if obj == nil {
+			continue
+		}
 
-				if bytes.Compare(v, vexp) != 0 {
-					return fmt.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v))
-				}
-			}
+		if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
+			return fmt.Errorf("(%x) balance failed. Expected %v, got %v => %v\n", obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance()))
 		}
 
-		statedb.Sync()
-		//if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) {
-		if common.HexToHash(test.PostStateRoot) != statedb.Root() {
-			return fmt.Errorf("%s's : Post state root error. Expected %s, got %x", name, test.PostStateRoot, statedb.Root())
+		if obj.Nonce() != common.String2Big(account.Nonce).Uint64() {
+			return fmt.Errorf("(%x) nonce failed. Expected %v, got %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce())
 		}
 
-		// check logs
-		if len(test.Logs) > 0 {
-			lerr := checkLogs(test.Logs, logs)
-			if lerr != nil {
-				return fmt.Errorf("'%s' ", name, lerr.Error())
+		for addr, value := range account.Storage {
+			v := obj.GetState(common.HexToHash(addr)).Bytes()
+			vexp := common.FromHex(value)
+
+			if bytes.Compare(v, vexp) != 0 {
+				return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v))
 			}
 		}
+	}
 
-		glog.Infoln("State test passed: ", name)
-		//fmt.Println(string(statedb.Dump()))
+	statedb.Sync()
+	//if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) {
+	if common.HexToHash(test.PostStateRoot) != statedb.Root() {
+		return fmt.Errorf("Post state root error. Expected %s, got %x", test.PostStateRoot, statedb.Root())
 	}
+
+	// check logs
+	if len(test.Logs) > 0 {
+		if err := checkLogs(test.Logs, logs); err != nil {
+			return err
+		}
+	}
+
 	return nil
 }
 
diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go
index ef133a99d..af33f2c58 100644
--- a/tests/transaction_test_util.go
+++ b/tests/transaction_test_util.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
+	"io"
 	"runtime"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -31,14 +32,41 @@ type TransactionTest struct {
 	Transaction TtTransaction
 }
 
+func RunTransactionTestsWithReader(r io.Reader) error {
+	skipTest := make(map[string]bool, len(TransSkipTests))
+	for _, name := range TransSkipTests {
+		skipTest[name] = true
+	}
+
+	bt := make(map[string]TransactionTest)
+	if err := readJson(r, &bt); err != nil {
+		return err
+	}
+
+	for name, test := range bt {
+		// if the test should be skipped, return
+		if skipTest[name] {
+			glog.Infoln("Skipping transaction test", name)
+			return nil
+		}
+		// test the block
+		if err := runTransactionTest(test); err != nil {
+			return err
+		}
+		glog.Infoln("Transaction test passed: ", name)
+
+	}
+	return nil
+}
+
 func RunTransactionTests(file string) error {
-	skipTest := make(map[string]bool, len(transSkipTests))
-	for _, name := range transSkipTests {
+	skipTest := make(map[string]bool, len(TransSkipTests))
+	for _, name := range TransSkipTests {
 		skipTest[name] = true
 	}
 
 	bt := make(map[string]TransactionTest)
-	if err := readTestFile(file, &bt); err != nil {
+	if err := readJsonFile(file, &bt); err != nil {
 		return err
 	}
 
@@ -48,8 +76,9 @@ func RunTransactionTests(file string) error {
 			glog.Infoln("Skipping transaction test", name)
 			return nil
 		}
+
 		// test the block
-		if err := runTest(test); err != nil {
+		if err := runTransactionTest(test); err != nil {
 			return err
 		}
 		glog.Infoln("Transaction test passed: ", name)
@@ -58,7 +87,7 @@ func RunTransactionTests(file string) error {
 	return nil
 }
 
-func runTest(txTest TransactionTest) (err error) {
+func runTransactionTest(txTest TransactionTest) (err error) {
 	tx := new(types.Transaction)
 	err = rlp.DecodeBytes(mustConvertBytes(txTest.Rlp), tx)
 
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index 4145d1ebf..f7f1198ec 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -3,6 +3,7 @@ package tests
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"math/big"
 	"strconv"
 
@@ -13,99 +14,135 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 )
 
-func RunVmTest(p string) error {
-	skipTest := make(map[string]bool, len(vmSkipTests))
-	for _, name := range vmSkipTests {
-		skipTest[name] = true
+func RunVmTestWithReader(r io.Reader) error {
+	tests := make(map[string]VmTest)
+	err := readJson(r, &tests)
+	if err != nil {
+		return err
 	}
 
+	if err != nil {
+		return err
+	}
+
+	if err := runVmTests(tests); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func RunVmTest(p string) error {
+
 	tests := make(map[string]VmTest)
-	err := readTestFile(p, &tests)
+	err := readJsonFile(p, &tests)
 	if err != nil {
 		return err
 	}
 
+	if err := runVmTests(tests); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func runVmTests(tests map[string]VmTest) error {
+	skipTest := make(map[string]bool, len(VmSkipTests))
+	for _, name := range VmSkipTests {
+		skipTest[name] = true
+	}
+
 	for name, test := range tests {
 		if skipTest[name] {
 			glog.Infoln("Skipping VM test", name)
 			return nil
 		}
-		db, _ := ethdb.NewMemDatabase()
-		statedb := state.New(common.Hash{}, db)
-		for addr, account := range test.Pre {
-			obj := StateObjectFromAccount(db, addr, account)
-			statedb.SetStateObject(obj)
-			for a, v := range account.Storage {
-				obj.SetState(common.HexToHash(a), common.HexToHash(v))
-			}
+
+		if err := runVmTest(test); err != nil {
+			return fmt.Errorf("%s %s", name, err.Error())
 		}
 
-		// XXX Yeah, yeah...
-		env := make(map[string]string)
-		env["currentCoinbase"] = test.Env.CurrentCoinbase
-		env["currentDifficulty"] = test.Env.CurrentDifficulty
-		env["currentGasLimit"] = test.Env.CurrentGasLimit
-		env["currentNumber"] = test.Env.CurrentNumber
-		env["previousHash"] = test.Env.PreviousHash
-		if n, ok := test.Env.CurrentTimestamp.(float64); ok {
-			env["currentTimestamp"] = strconv.Itoa(int(n))
-		} else {
-			env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+		glog.Infoln("VM test passed: ", name)
+		//fmt.Println(string(statedb.Dump()))
+	}
+	return nil
+}
+
+func runVmTest(test VmTest) error {
+	db, _ := ethdb.NewMemDatabase()
+	statedb := state.New(common.Hash{}, db)
+	for addr, account := range test.Pre {
+		obj := StateObjectFromAccount(db, addr, account)
+		statedb.SetStateObject(obj)
+		for a, v := range account.Storage {
+			obj.SetState(common.HexToHash(a), common.HexToHash(v))
 		}
+	}
 
-		var (
-			ret  []byte
-			gas  *big.Int
-			err  error
-			logs state.Logs
-		)
+	// XXX Yeah, yeah...
+	env := make(map[string]string)
+	env["currentCoinbase"] = test.Env.CurrentCoinbase
+	env["currentDifficulty"] = test.Env.CurrentDifficulty
+	env["currentGasLimit"] = test.Env.CurrentGasLimit
+	env["currentNumber"] = test.Env.CurrentNumber
+	env["previousHash"] = test.Env.PreviousHash
+	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
+		env["currentTimestamp"] = strconv.Itoa(int(n))
+	} else {
+		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+	}
 
-		ret, logs, gas, err = RunVm(statedb, env, test.Exec)
+	var (
+		ret  []byte
+		gas  *big.Int
+		err  error
+		logs state.Logs
+	)
 
-		// Compare expectedand actual return
-		rexp := common.FromHex(test.Out)
-		if bytes.Compare(rexp, ret) != 0 {
-			return fmt.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
-		}
+	ret, logs, gas, err = RunVm(statedb, env, test.Exec)
 
-		// Check gas usage
-		if len(test.Gas) == 0 && err == nil {
-			return fmt.Errorf("%s's gas unspecified, indicating an error. VM returned (incorrectly) successfull", name)
-		} else {
-			gexp := common.Big(test.Gas)
-			if gexp.Cmp(gas) != 0 {
-				return fmt.Errorf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
-			}
+	// Compare expectedand actual return
+	rexp := common.FromHex(test.Out)
+	if bytes.Compare(rexp, ret) != 0 {
+		return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
+	}
+
+	// Check gas usage
+	if len(test.Gas) == 0 && err == nil {
+		return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successfull")
+	} else {
+		gexp := common.Big(test.Gas)
+		if gexp.Cmp(gas) != 0 {
+			return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas)
 		}
+	}
 
-		// check post state
-		for addr, account := range test.Post {
-			obj := statedb.GetStateObject(common.HexToAddress(addr))
-			if obj == nil {
-				continue
-			}
+	// check post state
+	for addr, account := range test.Post {
+		obj := statedb.GetStateObject(common.HexToAddress(addr))
+		if obj == nil {
+			continue
+		}
 
-			for addr, value := range account.Storage {
-				v := obj.GetState(common.HexToHash(addr))
-				vexp := common.HexToHash(value)
+		for addr, value := range account.Storage {
+			v := obj.GetState(common.HexToHash(addr))
+			vexp := common.HexToHash(value)
 
-				if v != vexp {
-					return t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big())
-				}
+			if v != vexp {
+				return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, vexp.BigD(vexp), v.Big(v))
 			}
 		}
+	}
 
-		// check logs
-		if len(test.Logs) > 0 {
-			lerr := checkLogs(test.Logs, logs)
-			if lerr != nil {
-				return fmt.Errorf("'%s' ", name, lerr.Error())
-			}
+	// check logs
+	if len(test.Logs) > 0 {
+		lerr := checkLogs(test.Logs, logs)
+		if lerr != nil {
+			return lerr
 		}
-
-		glog.Infoln("VM test passed: ", name)
-		//fmt.Println(string(statedb.Dump()))
 	}
+
 	return nil
 }
 
-- 
cgit v1.2.3