Skip to content

Commit 6c9b3df

Browse files
committed
Remove unexported error cases and restructure error format
Drop test cases for errors not exported by `bitcoinkernel.h` (`TxInputIndex`, `SpentOutputsMismatch`, `InvalidFlags`) to align with actual API capabilities. Enhance error representation from `{type, variant}` to `{code: {type, member}}` structure
1 parent b55fd95 commit 6c9b3df

File tree

5 files changed

+84
-179
lines changed

5 files changed

+84
-179
lines changed

cmd/mock-handler/main.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,13 @@ func handleRequest(line string, testIndex map[string]string) error {
7979
filename, ok := testIndex[req.ID]
8080
if !ok {
8181
resp := runner.Response{
82-
ID: req.ID,
82+
ID: req.ID,
83+
Success: false,
8384
Error: &runner.Error{
84-
Type: "Handler",
85-
Variant: "UnknownTest",
85+
Code: runner.ErrorCode{
86+
Type: "Handler",
87+
Member: "UNKNOWN_TEST",
88+
},
8689
},
8790
}
8891
return writeResponse(resp)
@@ -92,10 +95,13 @@ func handleRequest(line string, testIndex map[string]string) error {
9295
suite, err := runner.LoadTestSuiteFromFS(testdata.FS, filename)
9396
if err != nil {
9497
resp := runner.Response{
95-
ID: req.ID,
98+
ID: req.ID,
99+
Success: false,
96100
Error: &runner.Error{
97-
Type: "Handler",
98-
Variant: "LoadError",
101+
Code: runner.ErrorCode{
102+
Type: "Handler",
103+
Member: "LOAD_ERROR",
104+
},
99105
},
100106
}
101107
return writeResponse(resp)
@@ -111,10 +117,13 @@ func handleRequest(line string, testIndex map[string]string) error {
111117
}
112118
if testCase == nil {
113119
resp := runner.Response{
114-
ID: req.ID,
120+
ID: req.ID,
121+
Success: false,
115122
Error: &runner.Error{
116-
Type: "Handler",
117-
Variant: "TestNotFound",
123+
Code: runner.ErrorCode{
124+
Type: "Handler",
125+
Member: "TEST_NOT_FOUND",
126+
},
118127
},
119128
}
120129
return writeResponse(resp)
@@ -123,10 +132,13 @@ func handleRequest(line string, testIndex map[string]string) error {
123132
// Verify method matches
124133
if req.Method != testCase.Method {
125134
resp := runner.Response{
126-
ID: req.ID,
135+
ID: req.ID,
136+
Success: false,
127137
Error: &runner.Error{
128-
Type: "Handler",
129-
Variant: "MethodMismatch",
138+
Code: runner.ErrorCode{
139+
Type: "Handler",
140+
Member: "METHOD_MISMATCH",
141+
},
130142
},
131143
}
132144
return writeResponse(resp)

runner/runner.go

Lines changed: 33 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package runner
22

33
import (
44
"bufio"
5-
"bytes"
65
"embed"
76
"encoding/json"
87
"fmt"
@@ -142,87 +141,68 @@ func (tr *TestRunner) runTest(test TestCase) SingleTestResult {
142141

143142
// validateResponse checks if response matches expected result
144143
func validateResponse(test TestCase, resp *Response) SingleTestResult {
145-
// Check if we expected an error
146-
if test.Expected.Error != nil {
147-
if resp.Error == nil {
148-
return SingleTestResult{
149-
TestID: test.ID,
150-
Passed: false,
151-
Message: fmt.Sprintf("Expected error type %s, but got no error", test.Expected.Error.Type),
152-
}
153-
}
154-
155-
// Check error type
156-
if resp.Error.Type != test.Expected.Error.Type {
157-
return SingleTestResult{
158-
TestID: test.ID,
159-
Passed: false,
160-
Message: fmt.Sprintf("Expected error type %s, got %s", test.Expected.Error.Type, resp.Error.Type),
144+
// Check success flag matches
145+
if test.Expected.Success != resp.Success {
146+
if test.Expected.Success {
147+
errMsg := "Expected success=true, but got success=false"
148+
if resp.Error != nil {
149+
errMsg += fmt.Sprintf(" with error: %s.%s", resp.Error.Code.Type, resp.Error.Code.Member)
161150
}
162-
}
163-
164-
// Check error variant if specified
165-
if test.Expected.Error.Variant != "" && resp.Error.Variant != test.Expected.Error.Variant {
166151
return SingleTestResult{
167152
TestID: test.ID,
168153
Passed: false,
169-
Message: fmt.Sprintf("Expected error variant %s, got %s", test.Expected.Error.Variant, resp.Error.Variant),
154+
Message: errMsg,
170155
}
171156
}
172-
173157
return SingleTestResult{
174158
TestID: test.ID,
175-
Passed: true,
176-
Message: "Test passed (expected error matched)",
159+
Passed: false,
160+
Message: "Expected success=false, but got success=true",
177161
}
178162
}
179163

180-
// Check if we expected success
181-
if test.Expected.Success != nil {
182-
if resp.Error != nil {
183-
errMsg := fmt.Sprintf("Expected success, but got error: %s", resp.Error.Type)
184-
if resp.Error.Variant != "" {
185-
errMsg += fmt.Sprintf(" (variant: %s)", resp.Error.Variant)
186-
}
164+
// If we expected an error with specific code, validate it
165+
if test.Expected.Error != nil {
166+
if resp.Error == nil {
187167
return SingleTestResult{
188168
TestID: test.ID,
189169
Passed: false,
190-
Message: errMsg,
170+
Message: fmt.Sprintf("Expected error %s.%s, but got no error", test.Expected.Error.Code.Type, test.Expected.Error.Code.Member),
191171
}
192172
}
193173

194-
if resp.Success == nil {
174+
// Check error code type
175+
if resp.Error.Code.Type != test.Expected.Error.Code.Type {
195176
return SingleTestResult{
196177
TestID: test.ID,
197178
Passed: false,
198-
Message: "Expected success, but response contained no success field",
179+
Message: fmt.Sprintf("Expected error type %s, got %s", test.Expected.Error.Code.Type, resp.Error.Code.Type),
199180
}
200181
}
201182

202-
// Normalize JSON for comparison
203-
var expectedData, actualData interface{}
204-
if err := json.Unmarshal(bytes.TrimSpace(*test.Expected.Success), &expectedData); err != nil {
183+
// Check error code member
184+
if resp.Error.Code.Member != test.Expected.Error.Code.Member {
205185
return SingleTestResult{
206186
TestID: test.ID,
207187
Passed: false,
208-
Message: fmt.Sprintf("Invalid expected JSON: %v", err),
188+
Message: fmt.Sprintf("Expected error member %s, got %s", test.Expected.Error.Code.Member, resp.Error.Code.Member),
209189
}
210190
}
211-
if err := json.Unmarshal(bytes.TrimSpace(*resp.Success), &actualData); err != nil {
212-
return SingleTestResult{
213-
TestID: test.ID,
214-
Passed: false,
215-
Message: fmt.Sprintf("Invalid response JSON: %v", err),
216-
}
191+
192+
return SingleTestResult{
193+
TestID: test.ID,
194+
Passed: true,
195+
Message: "Test passed (expected error matched)",
217196
}
218-
expectedNormalized, _ := json.Marshal(expectedData)
219-
actualNormalized, _ := json.Marshal(actualData)
197+
}
220198

221-
if !bytes.Equal(expectedNormalized, actualNormalized) {
199+
// Success case with no specific error expected
200+
if test.Expected.Success {
201+
if resp.Error != nil {
222202
return SingleTestResult{
223203
TestID: test.ID,
224204
Passed: false,
225-
Message: fmt.Sprintf("Success mismatch:\nExpected: %s\nActual: %s", string(expectedNormalized), string(actualNormalized)),
205+
Message: fmt.Sprintf("Expected success with no error, but got error: %s.%s", resp.Error.Code.Type, resp.Error.Code.Member),
226206
}
227207
}
228208
return SingleTestResult{
@@ -231,10 +211,12 @@ func validateResponse(test TestCase, resp *Response) SingleTestResult {
231211
Message: "Test passed",
232212
}
233213
}
214+
215+
// Failure case with no specific error code (just success=false)
234216
return SingleTestResult{
235217
TestID: test.ID,
236-
Passed: false,
237-
Message: "Test has no expected result defined",
218+
Passed: true,
219+
Message: "Test passed (expected failure without specific error)",
238220
}
239221
}
240222

runner/types.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ type TestCase struct {
1515

1616
// TestExpectation defines what response is expected
1717
type TestExpectation struct {
18-
Success *json.RawMessage `json:"success,omitempty"` // Expected successful result
19-
Error *Error `json:"error,omitempty"` // Expected error
18+
Success bool `json:"success"` // Whether operation should succeed
19+
Error *Error `json:"error,omitempty"` // Expected error details
2020
}
2121

2222
// TestSuite represents a collection of test cases
@@ -35,13 +35,17 @@ type Request struct {
3535

3636
// Response represents a response from the handler
3737
type Response struct {
38-
ID string `json:"id"`
39-
Success *json.RawMessage `json:"success,omitempty"`
40-
Error *Error `json:"error,omitempty"`
38+
ID string `json:"id"`
39+
Success bool `json:"success"` // Whether operation succeeded
40+
Error *Error `json:"error,omitempty"` // Error details (if success=false)
4141
}
4242

4343
// Error represents an error response
4444
type Error struct {
45-
Type string `json:"type"`
46-
Variant string `json:"variant,omitempty"`
45+
Code ErrorCode `json:"code"`
46+
}
47+
48+
type ErrorCode struct {
49+
Type string `json:"type"` // e.g., "btck_ScriptVerifyStatus"
50+
Member string `json:"member"` // e.g., "ERROR_INVALID_FLAGS_COMBINATION"
4751
}

testdata/script_verify_errors.json

Lines changed: 13 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@
2222
"spent_outputs": []
2323
},
2424
"expected": {
25-
"error": {
26-
"type": "ScriptVerify",
27-
"variant": "Invalid"
28-
}
25+
"success": false
2926
}
3027
},
3128
{
@@ -48,10 +45,7 @@
4845
"spent_outputs": []
4946
},
5047
"expected": {
51-
"error": {
52-
"type": "ScriptVerify",
53-
"variant": "Invalid"
54-
}
48+
"success": false
5549
}
5650
},
5751
{
@@ -74,100 +68,7 @@
7468
"spent_outputs": []
7569
},
7670
"expected": {
77-
"error": {
78-
"type": "ScriptVerify",
79-
"variant": "Invalid"
80-
}
81-
}
82-
},
83-
{
84-
"id": "error_tx_input_index_out_of_bounds",
85-
"description": "Input index exceeds the number of inputs in the transaction",
86-
"method": "btck_script_pubkey_verify",
87-
"params": {
88-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
89-
"amount": 0,
90-
"tx_hex": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700",
91-
"input_index": 999,
92-
"flags": [
93-
"btck_ScriptVerificationFlags_P2SH",
94-
"btck_ScriptVerificationFlags_DERSIG",
95-
"btck_ScriptVerificationFlags_NULLDUMMY",
96-
"btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY",
97-
"btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY",
98-
"btck_ScriptVerificationFlags_WITNESS"
99-
],
100-
"spent_outputs": [
101-
{
102-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
103-
"value": 100000
104-
}
105-
]
106-
},
107-
"expected": {
108-
"error": {
109-
"type": "ScriptVerify",
110-
"variant": "TxInputIndex"
111-
}
112-
}
113-
},
114-
{
115-
"id": "error_spent_outputs_mismatch",
116-
"description": "Spent outputs array length doesn't match transaction input count",
117-
"method": "btck_script_pubkey_verify",
118-
"params": {
119-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
120-
"amount": 0,
121-
"tx_hex": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700",
122-
"input_index": 0,
123-
"flags": [
124-
"btck_ScriptVerificationFlags_P2SH",
125-
"btck_ScriptVerificationFlags_DERSIG",
126-
"btck_ScriptVerificationFlags_NULLDUMMY",
127-
"btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY",
128-
"btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY",
129-
"btck_ScriptVerificationFlags_WITNESS"
130-
],
131-
"spent_outputs": [
132-
{
133-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
134-
"value": 100000
135-
},
136-
{
137-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
138-
"value": 100000
139-
}
140-
]
141-
},
142-
"expected": {
143-
"error": {
144-
"type": "ScriptVerify",
145-
"variant": "SpentOutputsMismatch"
146-
}
147-
}
148-
},
149-
{
150-
"id": "error_invalid_flags",
151-
"description": "Verification flags contain invalid bits",
152-
"method": "btck_script_pubkey_verify",
153-
"params": {
154-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
155-
"amount": 0,
156-
"tx_hex": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700",
157-
"input_index": 0,
158-
"flags": 4294967295,
159-
"spent_outputs": [
160-
{
161-
"script_pubkey_hex": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
162-
"value": 100000
163-
}
164-
]
165-
},
166-
"expected": {
167-
"error": {
168-
"type": "ScriptVerify",
169-
"variant": "InvalidFlags"
170-
}
71+
"success": false
17172
}
17273
},
17374
{
@@ -188,9 +89,12 @@
18889
]
18990
},
19091
"expected": {
92+
"success": false,
19193
"error": {
192-
"type": "ScriptVerify",
193-
"variant": "InvalidFlagsCombination"
94+
"code": {
95+
"type": "btck_ScriptVerifyStatus",
96+
"member": "ERROR_INVALID_FLAGS_COMBINATION"
97+
}
19498
}
19599
}
196100
},
@@ -207,9 +111,12 @@
207111
"spent_outputs": []
208112
},
209113
"expected": {
114+
"success": false,
210115
"error": {
211-
"type": "ScriptVerify",
212-
"variant": "SpentOutputsRequired"
116+
"code": {
117+
"type": "btck_ScriptVerifyStatus",
118+
"member": "ERROR_SPENT_OUTPUTS_REQUIRED"
119+
}
213120
}
214121
}
215122
}

0 commit comments

Comments
 (0)