Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring tests for clarity #67

Merged
merged 1 commit into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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