Skip to content

Commit

Permalink
Merge pull request #67 from twostack/test-refactor
Browse files Browse the repository at this point in the history
Refactoring tests for clarity
  • Loading branch information
stephanfeb authored Aug 21, 2023
2 parents 59e1dc2 + 82333c2 commit 21a9d00
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 136 deletions.
193 changes: 102 additions & 91 deletions test/script/interpreter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:io';
import 'dart:typed_data';

import 'package:buffer/buffer.dart';
import 'package:collection/collection.dart';
import 'package:dartsv/dartsv.dart';
import 'package:dartsv/src/encoding/utils.dart';
import 'package:dartsv/src/script/interpreter.dart';
Expand Down Expand Up @@ -209,54 +210,52 @@ void main() {

};

runScripTestFixtures(File fixtureFile) async {
runScripTestFixtures(testData) {
var testName = "";
List.from(jsonDecode(testData)).forEachIndexed((index, vect) {
if (vect.length == 1) {
testName = vect[0];
} else {

await fixtureFile
.readAsString()
.then((contents) => jsonDecode(contents))
.then((jsonData) {
List.from(jsonData).forEach((vect) {
if (vect.length == 1) {
return;
if (vect.length == 5){
testName = vect[4];
}else{
testName = "vector #${index}";
}
var extraData;
if (vect[0] is List) {
test("${testName}",() {
var extraData;
if (vect[0] is List) {
extraData = (vect as List<dynamic>).removeAt(0);
}
}

String fullScriptString = "${vect[0]} ${vect[1]}";
bool expected = vect[3] == 'OK';
String comment = "";
if (vect.length > 4) {
String fullScriptString = "${vect[0]} ${vect[1]}";
bool expected = vect[3] == 'OK';
String comment = "";
if (vect.length > 4) {
comment = vect[4];
}
}

var txt = "should ${vect[3]} script_tests vector : ${fullScriptString}${comment}";
print(txt);
var txt = "should ${vect[3]} script_tests vector : ${fullScriptString}${comment}";
print(txt);

testFixture(vect, expected, extraData);
});
testFixture(vect, expected, extraData);
});
}
});
}

test('bitcoin SV Node Test vectors', () async {
await runScripTestFixtures(File("${Directory.current.path}/test/data/bitcoind/script_tests_svnode.json"));
});

dataDrivenValidTransactions(File testFixtures) async {
dataDrivenValidTransactions(testData){
var testName = "";
await testFixtures
.readAsString()
.then((contents) => jsonDecode(contents))
.then((jsonData) {
List.from(jsonData).forEach((vect) {
List.from(jsonDecode(testData)).forEach((vect){

if (vect.length == 1) {
testName = vect[0];
print("Testing : ${testName}");
}
if(vect.length == 1){
testName = vect[0];
}

if (vect.length > 1) {
test("$testName", (){

if (vect.length > 1) {
Transaction spendingTx;

try {
Expand All @@ -283,7 +282,7 @@ void main() {
input.prevTxnOutputIndex = -1;
}

print("Spending INPUT : [${i}]");
// print("Spending INPUT : [${i}]");

//reconstruct the key into our Map of Public Keys using the details from
//the parsed transaction
Expand All @@ -307,94 +306,106 @@ void main() {

throw e;
}
}
});

});
}
});
}

dataDrivenInValidTransactions(File testFixtures) async {
dataDrivenInValidTransactions(testData) async {

var testName = "";
await testFixtures.readAsString().then((contents) => jsonDecode(contents)).then((jsonData) {
List.from(jsonData).forEach((vect) {
List.from(jsonDecode(testData)).forEach((vect){

if (vect.length == 1) {
testName = vect[0];
print("Testing : ${testName}");
}

if (vect.length > 1) {
Transaction spendingTx;
bool valid = true;

try {
var inputs = vect[0];
var map = {};
inputs.forEach((input) {
var txid = input[0];
var txoutnum = input[1];
var scriptPubKeyStr = input[2];
map[txid + ':' + txoutnum.toString()] = parseScriptString(scriptPubKeyStr);
});
test("$testName", ()
{
Transaction spendingTx;
bool valid = true;

spendingTx = Transaction.fromHex(vect[1]);
spendingTx.version = 1;
try {
spendingTx.verify();
} on Exception catch (ex) {
valid = false;
}
var inputs = vect[0];
var map = {};
inputs.forEach((input) {
var txid = input[0];
var txoutnum = input[1];
var scriptPubKeyStr = input[2];
map[txid + ':' + txoutnum.toString()] = parseScriptString(scriptPubKeyStr);
});

spendingTx = Transaction.fromHex(vect[1]);
spendingTx.version = 1;
try {
spendingTx.verify();
} on Exception catch (ex) {
valid = false;
}

///all this ceremony to extract Verify Flags
var verifyFlags = parseVerifyFlags(vect[2]);
///all this ceremony to extract Verify Flags
var verifyFlags = parseVerifyFlags(vect[2]);

for (int i = 0; i < spendingTx.inputs.length; i++) {
TransactionInput input = spendingTx.inputs[i];
if (input.prevTxnOutputIndex == 0xffffffff) {
input.prevTxnOutputIndex = -1;
}
for (int i = 0; i < spendingTx.inputs.length; i++) {
TransactionInput input = spendingTx.inputs[i];
if (input.prevTxnOutputIndex == 0xffffffff) {
input.prevTxnOutputIndex = -1;
}

print("Spending INPUT : [${i}]");
print("Spending INPUT : [${i}]");

//reconstruct the key into our Map of Public Keys using the details from
//the parsed transaction
// String txId = HEX.encode(input.prevTxnId);
String keyName = "${input.prevTxnId}:${input.prevTxnOutputIndex}";
//reconstruct the key into our Map of Public Keys using the details from
//the parsed transaction
// String txId = HEX.encode(input.prevTxnId);
String keyName = "${input.prevTxnId}:${input.prevTxnOutputIndex}";

//assert that our parsed transaction has correctly extracted the provided
//UTXO details
// expect(scriptPubKeys.containsKey(keyName), true);
var interp = Interpreter();
interp.correctlySpends(input.script!, map[keyName], spendingTx, i, verifyFlags, Coin.ZERO);
//assert that our parsed transaction has correctly extracted the provided
//UTXO details
// expect(scriptPubKeys.containsKey(keyName), true);
var interp = Interpreter();
interp.correctlySpends(input.script!, map[keyName], spendingTx, i, verifyFlags, Coin.ZERO);

//TODO: Would be better to assert expectation that no exception is thrown ?
//Ans: The whole of the Script Interpreter uses Exception-Handling for error-handling. So no,
// not without a deep refactor of the code.
//TODO: Would be better to assert expectation that no exception is thrown ?
//Ans: The whole of the Script Interpreter uses Exception-Handling for error-handling. So no,
// not without a deep refactor of the code.
}
} on Exception catch (e) {
valid = false;
}
} on Exception catch (e) {
valid = false;
}

if (valid) fail(testName);
if (valid) fail(testName);
});
}
});
});
}


test('bitcoin SV Node valid transaction evaluation fixtures', () async {
await dataDrivenValidTransactions(File("${Directory.current.path}/test/data/bitcoind/tx_valid_svnode.json"));
group('bitcoin SV Node Test vectors', () {
var testData = File("${Directory.current.path}/test/data/bitcoind/script_tests_svnode.json").readAsStringSync();
runScripTestFixtures(testData);
});

group('bitcoin SV Node valid transaction evaluation fixtures', () {
var testData = File("${Directory.current.path}/test/data/bitcoind/tx_valid_svnode.json").readAsStringSync();
dataDrivenValidTransactions(testData);
});

test('bitcoin SV Node invalid transaction evaluation fixtures', () async {
await dataDrivenInValidTransactions(File("${Directory.current.path}/test/data/bitcoind/tx_invalid_svnode.json"));
group('bitcoin SV Node invalid transaction evaluation fixtures', () {
var testData = File("${Directory.current.path}/test/data/bitcoind/tx_invalid_svnode.json").readAsStringSync();
dataDrivenInValidTransactions(testData);
});

test('bitcoind valid transaction evaluation fixtures', () async {
await dataDrivenValidTransactions(File("${Directory.current.path}/test/data/bitcoind/tx_valid.json"));
group('bitcoind valid transaction evaluation fixtures', () {
var testData = File("${Directory.current.path}/test/data/bitcoind/tx_valid.json").readAsStringSync();
dataDrivenValidTransactions(testData);
});

test('bitcoind invalid transaction evaluation fixtures', () async {
await dataDrivenInValidTransactions(File("${Directory.current.path}/test/data/bitcoind/tx_invalid.json"));
group('bitcoind invalid transaction evaluation fixtures', () {
var testData = File("${Directory.current.path}/test/data/bitcoind/tx_invalid.json").readAsStringSync();
dataDrivenInValidTransactions(testData);
});


Expand Down
1 change: 0 additions & 1 deletion test/script/script_builder_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:ffi';
import 'dart:typed_data';

import 'package:dartsv/dartsv.dart';
Expand Down
83 changes: 39 additions & 44 deletions test/transaction/transaction_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:collection/collection.dart';
import 'package:dartsv/dartsv.dart';
import 'package:test/test.dart';

Expand Down Expand Up @@ -220,13 +221,11 @@ main() {
expect(transaction.serialize(), equals(tx1hex));
});

group('transaction creation/serialization test vectors ', () {
var bipFileContents = File("${Directory.current.path}/test/data/tx_creation.json").readAsStringSync();
List.from(jsonDecode(bipFileContents)).forEachIndexed((index, item) {

test('transaction creation/serialization test vectors', () async {
await File("${Directory.current.path}/test/data/tx_creation.json")
.readAsString()
.then((contents) => jsonDecode(contents))
.then((jsonData) {
List.from(jsonData).forEach((item) {
test("Txn Vector #${index}", (){
var privKey = SVPrivateKey.fromWIF(item['sign'][0]);
Map<String, dynamic> utxoMap = item['from'][0][0];

Expand All @@ -247,6 +246,7 @@ main() {
signer.sign(transaction, TransactionOutput(satoshis, scriptPubKey), 0);
expect(transaction.serialize(), equals(item['serialize']));
});

});
});

Expand Down Expand Up @@ -691,52 +691,47 @@ main() {
return sorted.map((value) => original.indexOf(value)).toList();
};

test('input sorting ', () async {
await File("${Directory.current.path}/test/data/bip69.json")
.readAsString()
.then((contents) => jsonDecode(contents))
.then((jsonData) {
HashMap.from(jsonData)["inputs"].forEach((vector) {
var inputSet = vector["inputs"];
var tx = new Transaction();
var txInputs = inputSet.map((input) {
return TransactionInput(
var bipFileContents = File("${Directory.current.path}/test/data/bip69.json").readAsStringSync();
HashMap.from(jsonDecode(bipFileContents))
.forEach((key, value) {
if (key == "outputs") {
value.forEach((outputSet) =>{
test("Input - ${outputSet['description']}", (){
var tx = new Transaction();

var txOutputs = outputSet["outputs"].map((output) {
var txOut = TransactionOutput(BigInt.from(output["value"]), P2PKHDataLockBuilder.fromAddress(fromAddress, utf8.encode(output["script"])).getScriptPubkey());
return txOut;
}).toList();

List<TransactionOutput> outputs = List<TransactionOutput>.from(txOutputs);
tx.outputs.addAll(outputs);
tx.sort();
expect(getIndexOrder(outputs, tx.outputs), equals(outputSet["expected"]));
})
});
}else if(key == "inputs"){
value.forEach((inputSet) => {
test("Output - ${inputSet['description']}", (){

var tx = new Transaction();
var txInputs = inputSet["inputs"].map((input) {
return TransactionInput(
input["txId"],
input["vout"],
TransactionInput.MAX_SEQ_NUMBER,
scriptBuilder: DefaultUnlockBuilder.fromScript(SVScript()));
}).toList();
}).toList();

List<TransactionInput> inputs = List<TransactionInput>.from(txInputs);
tx.inputs.addAll(inputs);
tx.sort();
expect(getIndexOrder(inputs, tx.inputs), equals(vector["expected"]));
List<TransactionInput> inputs = List<TransactionInput>.from(txInputs);
tx.inputs.addAll(inputs);
tx.sort();
expect(getIndexOrder(inputs, tx.inputs), equals(inputSet["expected"]));
})
});
});
}
});


test('output sorting ', () async {
await File("${Directory.current.path}/test/data/bip69.json")
.readAsString()
.then((contents) => jsonDecode(contents))
.then((jsonData) {
HashMap.from(jsonData)["outputs"].forEach((vector) {
var outputSet = vector["outputs"];
var tx = new Transaction();

var txOutputs = outputSet.map((output) {
var txOut = TransactionOutput(BigInt.from(output["value"]), P2PKHDataLockBuilder.fromAddress(fromAddress, utf8.encode(output["script"])).getScriptPubkey());
return txOut;
}).toList();

List<TransactionOutput> outputs = List<TransactionOutput>.from(txOutputs);
tx.outputs.addAll(outputs);
tx.sort();
expect(getIndexOrder(outputs, tx.outputs), equals(vector["expected"]));
});
});
});
});


Expand Down

0 comments on commit 21a9d00

Please sign in to comment.