diff --git a/BitcoinKernel.NET.sln b/BitcoinKernel.NET.sln index 9814736..b23123f 100644 --- a/BitcoinKernel.NET.sln +++ b/BitcoinKernel.NET.sln @@ -9,6 +9,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B3 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{F8E63A4F-7D3E-4B2A-9C1D-8A5F6E9B3C2D}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Tests", "tests\BitcoinKernel.Tests\BitcoinKernel.Tests.csproj", "{BC90EFB4-1692-CBCC-EF52-778255F591E2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicUsage", "examples\BasicUsage\BasicUsage.csproj", "{0E2DDF4A-A1FE-5424-03EA-7A8E76751354}" @@ -23,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlockProcessing", "examples EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Core.Tests", "tests\BitcoinKernel.Core.Tests\BitcoinKernel.Core.Tests.csproj", "{267842B2-D915-4B9E-8448-F9B5816D4A0A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "kernel-bindings-test-handler", "tools\kernel-bindings-test-handler\kernel-bindings-test-handler.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -117,6 +121,18 @@ Global {267842B2-D915-4B9E-8448-F9B5816D4A0A}.Release|x64.Build.0 = Release|Any CPU {267842B2-D915-4B9E-8448-F9B5816D4A0A}.Release|x86.ActiveCfg = Release|Any CPU {267842B2-D915-4B9E-8448-F9B5816D4A0A}.Release|x86.Build.0 = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -129,6 +145,7 @@ Global {D6F509B1-C990-0533-2DD1-CFFBA7506249} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} {23E19BC3-8829-42BE-BCB4-A2050BE04975} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {267842B2-D915-4B9E-8448-F9B5816D4A0A} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890} = {F8E63A4F-7D3E-4B2A-9C1D-8A5F6E9B3C2D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B999E480-512A-4C50-9574-4AECEAC73E1C} diff --git a/README.md b/README.md index 8a3e19a..791c93e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # BitcoinKernel.NET .NET bindings and high-level library for [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel), providing access to Bitcoin Core's consensus and validation logic. + + ⚠️🚧 This library is still under contruction. ⚠️🚧 This library uses [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel) which is in an experimental state, do not use for production purposes. @@ -68,6 +70,19 @@ Explore the [examples](examples/) directory for complete working samples: - **[BasicUsage](examples/BasicUsage/)** - Getting started with the high-level API - **[BlockProcessing](examples/BlockProcessing/)** - Block validation and chain management +## Tools + +### Kernel Bindings Test Handler + +A conformance test handler for Kernel bindings Test handler framework, see [tools/kernel-bindings-test-handler](tools/kernel-bindings-test-handler/) for details. + +**Usage:** +```bash +dotnet run --project tools/kernel-bindings-test-handler +``` + +The handler communicates via stdin/stdout and is designed for automated conformance testing. + ## Building from Source ### Prerequisites diff --git a/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs b/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs new file mode 100644 index 0000000..e55a479 --- /dev/null +++ b/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs @@ -0,0 +1,186 @@ +using BitcoinKernel.Core; +using BitcoinKernel.Core.Abstractions; +using BitcoinKernel.Core.Exceptions; +using BitcoinKernel.Core.ScriptVerification; +using BitcoinKernel.Interop.Enums; +using BitcoinKernel.TestHandler.Protocol; + +namespace BitcoinKernel.TestHandler.Handlers; + +/// +/// Handles script_pubkey.verify method requests. +/// +public class ScriptVerifyHandler +{ + private readonly KernelContext _context; + + public ScriptVerifyHandler(KernelContext context) + { + _context = context; + } + + /// + /// Handles a script verification request. + /// + public Response Handle(string requestId, ScriptVerifyParams parameters) + { + try + { + // Parse input data + var scriptPubKey = ScriptPubKey.FromHex(parameters.ScriptPubKeyHex); + var transaction = Transaction.FromHex(parameters.TxHex); + + // Parse spent outputs if provided + var spentOutputs = new List(); + if (parameters.SpentOutputs != null && parameters.SpentOutputs.Any()) + { + foreach (var output in parameters.SpentOutputs) + { + var outputScriptPubKey = ScriptPubKey.FromHex(output.ScriptPubKeyHex); + spentOutputs.Add(new TxOut(outputScriptPubKey, output.Amount)); + } + } + + // Parse flags + var flags = ParseFlags(parameters.Flags); + + // Verify the script + ScriptVerifier.VerifyScript( + scriptPubKey, + parameters.Amount, + transaction, + parameters.InputIndex, + spentOutputs, + flags + ); + + // Success + return new Response + { + Id = requestId, + Success = new { } + }; + } + catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "inputIndex") + { + return new Response + { + Id = requestId, + Error = new ErrorResponse + { + Type = "ScriptVerify", + Variant = "TxInputIndex" + } + }; + } + catch (ScriptVerificationException ex) + { + return new Response + { + Id = requestId, + Error = new ErrorResponse + { + Type = "ScriptVerify", + Variant = MapScriptVerifyStatus(ex.Status) + } + }; + } + catch (Exception +#if DEBUG + ex +#endif + ) + { + // Log to stderr for debugging (can be disabled in production) +#if DEBUG + Console.Error.WriteLine($"Exception: {ex.GetType().Name}: {ex.Message}"); + Console.Error.WriteLine($"StackTrace: {ex.StackTrace}"); +#endif + + // Generic error for unexpected exceptions + return new Response + { + Id = requestId, + Error = new ErrorResponse + { + Type = "ScriptVerify", + Variant = "Invalid" + } + }; + } + } + + /// + /// Parses flags from either uint or string format. + /// + private ScriptVerificationFlags ParseFlags(object? flags) + { + if (flags == null) + return ScriptVerificationFlags.None; + + // Handle numeric flags + if (flags is uint or int or long) + { + return (ScriptVerificationFlags)Convert.ToUInt32(flags); + } + + // Handle System.Text.Json JsonElement + if (flags.GetType().Name == "JsonElement") + { + var jsonElement = (System.Text.Json.JsonElement)flags; + if (jsonElement.ValueKind == System.Text.Json.JsonValueKind.Number) + { + return (ScriptVerificationFlags)jsonElement.GetUInt32(); + } + else if (jsonElement.ValueKind == System.Text.Json.JsonValueKind.String) + { + return ParseFlagString(jsonElement.GetString() ?? string.Empty); + } + } + + // Handle string flags + if (flags is string flagStr) + { + return ParseFlagString(flagStr); + } + + return ScriptVerificationFlags.None; + } + + /// + /// Parses a string flag name to ScriptVerificationFlags. + /// + private ScriptVerificationFlags ParseFlagString(string flagStr) + { + return flagStr.ToUpperInvariant() switch + { + "VERIFY_NONE" or "NONE" => ScriptVerificationFlags.None, + "VERIFY_P2SH" or "P2SH" => ScriptVerificationFlags.P2SH, + "VERIFY_DERSIG" or "DERSIG" => ScriptVerificationFlags.DerSig, + "VERIFY_NULLDUMMY" or "NULLDUMMY" => ScriptVerificationFlags.NullDummy, + "VERIFY_CHECKLOCKTIMEVERIFY" or "CHECKLOCKTIMEVERIFY" => ScriptVerificationFlags.CheckLockTimeVerify, + "VERIFY_CHECKSEQUENCEVERIFY" or "CHECKSEQUENCEVERIFY" => ScriptVerificationFlags.CheckSequenceVerify, + "VERIFY_WITNESS" or "WITNESS" => ScriptVerificationFlags.Witness, + "VERIFY_TAPROOT" or "TAPROOT" => ScriptVerificationFlags.Taproot, + "VERIFY_ALL" or "ALL" => ScriptVerificationFlags.All, + "VERIFY_ALL_PRE_TAPROOT" or "ALL_PRE_TAPROOT" => ScriptVerificationFlags.AllPreTaproot, + _ => throw new ArgumentException($"Unknown flag: {flagStr}") + }; + } + + /// + /// Maps ScriptVerifyStatus to error variant strings. + /// + private string MapScriptVerifyStatus(ScriptVerifyStatus status) + { + return status switch + { + ScriptVerifyStatus.ERROR_TX_INPUT_INDEX => "TxInputIndex", + ScriptVerifyStatus.ERROR_INVALID_FLAGS => "InvalidFlags", + ScriptVerifyStatus.ERROR_INVALID_FLAGS_COMBINATION => "InvalidFlagsCombination", + ScriptVerifyStatus.ERROR_SPENT_OUTPUTS_MISMATCH => "SpentOutputsMismatch", + ScriptVerifyStatus.ERROR_SPENT_OUTPUTS_REQUIRED => "SpentOutputsRequired", + _ => "Invalid" + }; + } +} diff --git a/tools/kernel-bindings-test-handler/Program.cs b/tools/kernel-bindings-test-handler/Program.cs new file mode 100644 index 0000000..ccd89e1 --- /dev/null +++ b/tools/kernel-bindings-test-handler/Program.cs @@ -0,0 +1,146 @@ +using System.Text.Json; +using BitcoinKernel.Core; +using BitcoinKernel.TestHandler.Handlers; +using BitcoinKernel.TestHandler.Protocol; + +namespace BitcoinKernel.TestHandler; + +/// +/// Test handler for Bitcoin Kernel conformance tests. +/// Implements the JSON-RPC-like protocol for testing bindings. +/// +class Program +{ + static async Task Main(string[] args) + { + // Initialize kernel context + using var context = new KernelContext(); + var scriptVerifyHandler = new ScriptVerifyHandler(context); + + // Configure JSON serialization options + var jsonOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + WriteIndented = false + }; + + try + { + // Read requests line-by-line from stdin + string? line; + while ((line = await Console.In.ReadLineAsync()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + + Response response; + try + { + // Parse the request + var request = JsonSerializer.Deserialize(line, jsonOptions); + + if (request == null) + { + response = new Response + { + Id = "unknown", + Error = new ErrorResponse + { + Type = "InvalidRequest" + } + }; + } + else + { + response = HandleRequest(request, scriptVerifyHandler, jsonOptions); + } + } + catch (JsonException) + { + response = new Response + { + Id = "unknown", + Error = new ErrorResponse + { + Type = "InvalidRequest" + } + }; + } + + // Write response to stdout + var responseJson = JsonSerializer.Serialize(response, jsonOptions); + await Console.Out.WriteLineAsync(responseJson); + await Console.Out.FlushAsync(); + } + + return 0; + } + catch (Exception ex) + { + await Console.Error.WriteLineAsync($"Fatal error: {ex.Message}"); + return 1; + } + } + + /// + /// Routes the request to the appropriate handler. + /// + private static Response HandleRequest(Request request, ScriptVerifyHandler scriptVerifyHandler, JsonSerializerOptions jsonOptions) + { + try + { + switch (request.Method) + { + case "script_pubkey.verify": + if (request.Params == null) + { + return new Response + { + Id = request.Id, + Error = new ErrorResponse + { + Type = "InvalidParams" + } + }; + } + + var scriptVerifyParams = JsonSerializer.Deserialize(request.Params.Value, jsonOptions); + + if (scriptVerifyParams == null) + { + return new Response + { + Id = request.Id, + Error = new ErrorResponse + { + Type = "InvalidParams" + } + }; + } + + return scriptVerifyHandler.Handle(request.Id, scriptVerifyParams); + + default: + return new Response + { + Id = request.Id, + Error = new ErrorResponse + { + Type = "MethodNotFound" + } + }; + } + } + catch (Exception) + { + return new Response + { + Id = request.Id, + Error = new ErrorResponse + { + Type = "InternalError" + } + }; + } + } +} diff --git a/tools/kernel-bindings-test-handler/Protocol/Request.cs b/tools/kernel-bindings-test-handler/Protocol/Request.cs new file mode 100644 index 0000000..0d75185 --- /dev/null +++ b/tools/kernel-bindings-test-handler/Protocol/Request.cs @@ -0,0 +1,55 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace BitcoinKernel.TestHandler.Protocol; + +/// +/// Represents a request from the test runner. +/// +public class Request +{ + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + [JsonPropertyName("method")] + public string Method { get; set; } = string.Empty; + + [JsonPropertyName("params")] + public JsonElement? Params { get; set; } +} + +/// +/// Parameters for script_pubkey.verify method. +/// +public class ScriptVerifyParams +{ + [JsonPropertyName("script_pubkey_hex")] + public string ScriptPubKeyHex { get; set; } = string.Empty; + + [JsonPropertyName("amount")] + public long Amount { get; set; } + + [JsonPropertyName("tx_hex")] + public string TxHex { get; set; } = string.Empty; + + [JsonPropertyName("input_index")] + public uint InputIndex { get; set; } + + [JsonPropertyName("spent_outputs")] + public List? SpentOutputs { get; set; } + + [JsonPropertyName("flags")] + public object? Flags { get; set; } // Can be uint or string +} + +/// +/// Represents a spent output. +/// +public class SpentOutput +{ + [JsonPropertyName("script_pubkey_hex")] + public string ScriptPubKeyHex { get; set; } = string.Empty; + + [JsonPropertyName("amount")] + public long Amount { get; set; } +} diff --git a/tools/kernel-bindings-test-handler/Protocol/Response.cs b/tools/kernel-bindings-test-handler/Protocol/Response.cs new file mode 100644 index 0000000..1c49f2a --- /dev/null +++ b/tools/kernel-bindings-test-handler/Protocol/Response.cs @@ -0,0 +1,33 @@ +using System.Text.Json.Serialization; + +namespace BitcoinKernel.TestHandler.Protocol; + +/// +/// Represents a response to the test runner. +/// +public class Response +{ + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + [JsonPropertyName("success")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Success { get; set; } + + [JsonPropertyName("error")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ErrorResponse? Error { get; set; } +} + +/// +/// Represents an error response. +/// +public class ErrorResponse +{ + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + + [JsonPropertyName("variant")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Variant { get; set; } +} diff --git a/tools/kernel-bindings-test-handler/README.md b/tools/kernel-bindings-test-handler/README.md new file mode 100644 index 0000000..9825654 --- /dev/null +++ b/tools/kernel-bindings-test-handler/README.md @@ -0,0 +1,154 @@ +# Kernel Bindings Test Handler + +This is a conformance test handler for the BitcoinKernel.NET library. +It implements the protocol specification [kernel-bindings-test handler-spec](https://github.com/stringintech/kernel-bindings-tests/blob/main/docs/handler-spec.md) for testing Bitcoin Kernel bindings via stdin/stdout JSON-RPC-like communication. + +## Overview + +The handler is a console application that: +- Reads JSON requests line-by-line from stdin +- Processes each request using the BitcoinKernel.Core library +- Writes JSON responses to stdout +- Exits cleanly when stdin closes + +## Protocol + +### Communication +- **Input**: JSON requests on stdin (one per line) +- **Output**: JSON responses on stdout (one per line) + +### Request Format +```json +{ + "id": "unique-request-id", + "method": "method_name", + "params": { /* method-specific parameters */ } +} +``` + +### Response Format +**Success:** +```json +{ + "id": "unique-request-id", + "success": { /* result */ } +} +``` + +**Error:** +```json +{ + "id": "unique-request-id", + "error": { + "type": "error_category", + "variant": "specific_error" + } +} +``` + +## Supported Methods + +### `script_pubkey.verify` + +Verifies a Bitcoin script pubkey against a transaction input. + +**Parameters:** +- `script_pubkey` (string): Hex-encoded script pubkey +- `amount` (number): Amount of the output being spent +- `transaction` (string): Hex-encoded transaction +- `input_index` (number): Index of the transaction input to verify +- `spent_outputs` (array, optional): Array of spent outputs + - Each output contains: `script_pubkey` (string), `amount` (number) +- `script_verify_flags` (number): Script verification flags + +**Success Response:** +```json +{ + "id": "test-id", + "success": {} +} +``` + +**Error Variants:** +- `TxInputIndex`: Input index is out of bounds +- `InvalidFlags`: Invalid verification flags +- `InvalidFlagsCombination`: Invalid flag combination +- `SpentOutputsMismatch`: Spent outputs count doesn't match input count +- `SpentOutputsRequired`: Spent outputs required but not provided +- `Invalid`: Script verification failed + +## Building + +### Build for Development +```bash +dotnet build +``` + +### Build Release Binary +```bash +./build.sh +``` + +This creates a compiled binary at `bin/kernel-bindings-test-handler` that can be invoked directly without `dotnet run`. + +## Running + +### Option 1: Run with dotnet (development) +```bash +dotnet run --project tools/kernel-bindings-test-handler +``` + +### Option 2: Run compiled binary (production) +```bash +./tools/kernel-bindings-test-handler/bin/kernel-bindings-test-handler +``` + +### invoke via Bitcoin Kernel Binding Conformance Tests framework. +Clone the repo and build. + +Execute the test: +```bash + ./build/runner --handler /Users/arjan/Projects/BitcoinKernel.NET/tools/kernel-bindings-test-handler/bin/kernel-bindings-test-handler +``` + +## Testing + +The handler is designed to be used with conformance test suite. Example: + +```bash +echo '{"id":"1","method":"script_pubkey.verify","params":{...}}' | \ + ./bin/kernel-bindings-test-handler +``` + +## Project Structure + +``` +tools/kernel-bindings-test-handler/ +|-- kernel-bindings-test-handler.csproj +|-- Program.cs # Main entry point and request router +|-- Protocol/ +| |-- Request.cs # Request message definitions +| |-- Response.cs # Response message definitions +|-- Handlers/ +| |-- ScriptVerifyHandler.cs # Script verification handler +|-- Bin/ +| |-- Compiled binaries useable for the Bitcoin Kernel Binding Conformance Tests framework +``` + +## Dependencies + +- BitcoinKernel.Core: The core library being tested +- System.Text.Json: JSON serialization + +## Error Handling + +The handler maps BitcoinKernel.Core exceptions to protocol error responses: + +| Exception | Error Type | Error Variant | +|-----------|-----------|---------------| +| ArgumentOutOfRangeException (inputIndex) | ScriptVerify | TxInputIndex | +| ScriptVerificationException (ERROR_INVALID_FLAGS) | ScriptVerify | InvalidFlags | +| ScriptVerificationException (ERROR_INVALID_FLAGS_COMBINATION) | ScriptVerify | InvalidFlagsCombination | +| ScriptVerificationException (ERROR_SPENT_OUTPUTS_MISMATCH) | ScriptVerify | SpentOutputsMismatch | +| ScriptVerificationException (ERROR_SPENT_OUTPUTS_REQUIRED) | ScriptVerify | SpentOutputsRequired | +| Any other exception | ScriptVerify | Invalid | diff --git a/tools/kernel-bindings-test-handler/build.sh b/tools/kernel-bindings-test-handler/build.sh new file mode 100755 index 0000000..b2760e5 --- /dev/null +++ b/tools/kernel-bindings-test-handler/build.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Build the handler as a self-contained executable + +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUTPUT_DIR="$PROJECT_DIR/bin" + +echo "Building kernel-bindings-test-handler..." + +# Create output directory +mkdir -p "$OUTPUT_DIR" + +# Build release version +dotnet publish "$PROJECT_DIR/kernel-bindings-test-handler.csproj" \ + -c Release \ + -o "$OUTPUT_DIR" \ + --self-contained false \ + /p:PublishSingleFile=false + +if [ $? -eq 0 ]; then + echo "✅ Build successful" + echo "Binary location: $OUTPUT_DIR/kernel-bindings-test-handler" + echo "" + echo "Run with: $OUTPUT_DIR/kernel-bindings-test-handler" +else + echo "❌ Build failed" + exit 1 +fi diff --git a/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj b/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj new file mode 100644 index 0000000..45fef66 --- /dev/null +++ b/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj @@ -0,0 +1,19 @@ + + + + Exe + net9.0 + BitcoinKernel.TestHandler + enable + enable + + + + + + + + + + + diff --git a/tools/kernel-bindings-test-handler/test.sh b/tools/kernel-bindings-test-handler/test.sh new file mode 100755 index 0000000..5a867b3 --- /dev/null +++ b/tools/kernel-bindings-test-handler/test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Simple test script to verify the handler responds correctly + +# Example test case (you'll need to replace with actual test data) +echo "Testing kernel-bindings-test-handler..." + +# Build the handler +dotnet build tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj > /dev/null 2>&1 + +if [ $? -ne 0 ]; then + echo "❌ Build failed" + exit 1 +fi + +echo "✅ Build successful" + +# Test 1: Invalid method +echo '{"id":"test-1","method":"invalid.method","params":{}}' | \ + dotnet run --project tools/kernel-bindings-test-handler 2>/dev/null | \ + grep -q '"error"' && echo "✅ Test 1 passed: Invalid method returns error" || echo "❌ Test 1 failed" + + +echo "" +echo "Handler is ready to use with conformance test suites." +echo "Run with: dotnet run --project tools/kernel-bindings-test-handler"