> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing

> Test organization, patterns, TDD workflow, and commands

# Testing

Voltaire uses a strict TDD approach. Tests are first-class citizens, never stubs or placeholders.

## Core Principle

<Warning>
  **Every line correct. No stubs, no commented tests.**

  If a test exists, it passes. If it doesn't pass, fix it or delete it.
</Warning>

## Test Organization

### Zig Tests

Inline in source files:

```
src/primitives/Address/address.zig     # Implementation + tests
src/crypto/Keccak256/keccak256.zig     # Implementation + tests
```

### TypeScript Tests

Separate test files:

```
src/primitives/Address/Address.test.ts
src/primitives/Address/Address.wasm.test.ts
src/crypto/Keccak256/Keccak256.test.ts
```

### Benchmarks

```
src/primitives/Address/address.bench.zig   # Zig benchmarks (zbench)
src/primitives/Address/Address.bench.ts    # TS benchmarks (mitata)
```

## Running Tests

### Zig Tests

```bash theme={null}
# All Zig tests
zig build test

# Filter by name
zig build -Dtest-filter=Address
zig build -Dtest-filter=keccak
zig build -Dtest-filter="fromHex"

# With debug output
zig build test 2>&1 | head -100
```

### TypeScript Tests

```bash theme={null}
# Watch mode (development)
bun run test

# Single run
bun run test:run

# Filter tests
bun run test -- address
bun run test -- "Address.fromHex"

# Coverage report
bun run test:coverage

# Specific test suites
bun run test:native      # Native FFI
bun run test:wasm        # WASM
```

## TDD Workflow

### The Loop

1. Write failing test
2. Implement minimal code to pass
3. Refactor
4. Run `zig build && zig build test`
5. Repeat

```bash theme={null}
# Keep this running in a terminal
while true; do zig build && zig build test && bun run test:run; sleep 2; done
```

### Bug Fixing

**Always produce a failing test first:**

```zig theme={null}
test "regression: fromHex handles mixed case" {
    // This was failing before the fix
    const addr = try Address.fromHex("0x742D35Cc6634c0532925A3b844Bc9e7595f251E3");
    try testing.expectEqual(@as(u8, 0x74), addr.bytes[0]);
}
```

Then fix the implementation. The test stays forever.

## Zig Test Patterns

### Basic Assertion

```zig theme={null}
const testing = std.testing;

test "Address.fromHex valid input" {
    const addr = try Address.fromHex("0x742d35cc6634c0532925a3b844bc9e7595f251e3");
    try testing.expectEqual(@as(u8, 0x74), addr.bytes[0]);
    try testing.expectEqual(@as(u8, 0x2d), addr.bytes[1]);
}
```

### Error Testing

```zig theme={null}
test "Address.fromHex rejects invalid length" {
    const result = Address.fromHex("0x123");
    try testing.expectError(error.InvalidLength, result);
}

test "Address.fromHex rejects invalid characters" {
    const result = Address.fromHex("0xgggggggggggggggggggggggggggggggggggggggg");
    try testing.expectError(error.InvalidHexDigit, result);
}
```

### Slice Comparison

```zig theme={null}
test "Address.toHex output" {
    const addr = Address{ .bytes = [_]u8{0x74} ++ [_]u8{0} ** 19 };
    const hex = addr.toHex();
    try testing.expectEqualSlices(u8, "0x7400000000000000000000000000000000000000", &hex);
}
```

### Debug Output

```zig theme={null}
test "complex operation" {
    testing.log_level = .debug;

    const result = try complexOperation();
    std.log.debug("result: {x}", .{result});

    try testing.expect(result.len > 0);
}
```

### Memory Testing

```zig theme={null}
test "no memory leaks" {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const result = try encode(allocator, data);
    defer allocator.free(result);

    // If we get here without leak detection, test passes
}
```

## TypeScript Test Patterns

### Basic Test

```typescript theme={null}
import { describe, it, expect } from "vitest";
import * as Address from "./index.js";

describe("Address", () => {
  describe("fromHex", () => {
    it("converts valid lowercase hex", () => {
      const addr = Address.fromHex("0x742d35cc6634c0532925a3b844bc9e7595f251e3");
      expect(addr).toBeInstanceOf(Uint8Array);
      expect(addr.length).toBe(20);
    });

    it("converts valid checksummed hex", () => {
      const addr = Address.fromHex("0x742d35Cc6634C0532925a3b844Bc9e7595f251e3");
      expect(addr[0]).toBe(0x74);
    });
  });
});
```

### Error Testing

```typescript theme={null}
describe("fromHex", () => {
  it("throws on invalid hex", () => {
    expect(() => Address.fromHex("0xinvalid")).toThrow();
  });

  it("throws InvalidAddressError", () => {
    expect(() => Address.fromHex("0x123")).toThrow(InvalidAddressError);
  });

  it("throws with descriptive message", () => {
    expect(() => Address.fromHex("bad")).toThrow(/invalid.*address/i);
  });
});
```

### Async Testing

```typescript theme={null}
describe("async operations", () => {
  it("resolves with valid data", async () => {
    const result = await fetchAddress(id);
    expect(result).toBeDefined();
  });

  it("rejects on network error", async () => {
    await expect(fetchAddress("invalid")).rejects.toThrow();
  });
});
```

### Table-Driven Tests

```typescript theme={null}
describe("toChecksummed", () => {
  const cases = [
    { input: "0x742d35cc6634c0532925a3b844bc9e7595f251e3", expected: "0x742d35Cc6634C0532925a3b844Bc9e7595f251e3" },
    { input: "0x0000000000000000000000000000000000000000", expected: "0x0000000000000000000000000000000000000000" },
    { input: "0xffffffffffffffffffffffffffffffffffffffff", expected: "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF" },
  ];

  it.each(cases)("checksums $input", ({ input, expected }) => {
    const addr = Address.fromHex(input);
    expect(Address.toChecksummed(addr)).toBe(expected);
  });
});
```

## Cross-Validation

Validate against known-good vectors (no external libs):

```typescript theme={null}
import * as Address from "./index.js";

describe("checksum test vectors", () => {
  const cases = [
    ["0x742d35cc6634c0532925a3b844bc9e7595f251e3", "0x742d35Cc6634C0532925a3b844Bc9e7595f251e3"],
    ["0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000"],
    ["0xffffffffffffffffffffffffffffffffffffffff", "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF"],
  ] as const;

  it.each(cases)("checksums %s", (input, expected) => {
    const ours = Address.toChecksummed(Address.fromHex(input));
    expect(ours).toBe(expected);
  });
});
```

## Test Coverage

### Generating Coverage

```bash theme={null}
# TypeScript coverage
bun run test:coverage

# View report
open coverage/index.html
```

### Coverage Goals

* Core primitives: 100%
* Crypto functions: 100%
* Edge cases: exhaustive
* Error paths: covered

## Fuzz Testing

### Zig Fuzz Tests

```zig theme={null}
// address.fuzz.zig
const std = @import("std");
const Address = @import("address.zig").Address;

test "fuzz: fromHex roundtrip" {
    var input: [40]u8 = undefined;

    // Generate random hex
    var rng = std.Random.DefaultPrng.init(0);
    for (&input) |*c| {
        const idx = rng.random().int(u4);
        c.* = "0123456789abcdef"[idx];
    }

    const hex = "0x" ++ input;
    const addr = try Address.fromHex(hex);
    const output = addr.toHex();

    try std.testing.expectEqualSlices(u8, &hex, &output);
}
```

### Running Fuzz Tests

```bash theme={null}
# Enable fuzzing
zig build test -Dfuzz=true
```

## Security Testing

```bash theme={null}
# Run security-focused tests
zig build test-security

# Constant-time verification
zig build test -Dtest-filter=secure
```

### What Security Tests Cover

* Constant-time comparisons
* No timing leaks
* Input validation
* Memory clearing after sensitive ops
* Edge case handling

## Benchmarks

### Zig Benchmarks

```zig theme={null}
// address.bench.zig
const zbench = @import("zbench");

pub fn benchFromHex(b: *zbench.Benchmark) void {
    const hex = "0x742d35cc6634c0532925a3b844bc9e7595f251e3";

    b.run(struct {
        fn f() void {
            _ = Address.fromHex(hex) catch unreachable;
        }
    }.f);
}
```

### TypeScript Benchmarks

```typescript theme={null}
// Address.bench.ts
import { bench, run } from "mitata";
import * as Address from "./index.js";

bench("Address.fromHex", () => {
  Address.fromHex("0x742d35cc6634c0532925a3b844bc9e7595f251e3");
});

bench("Address.toChecksummed", () => {
  Address.toChecksummed(addr);
});

await run();
```

### Running Benchmarks

```bash theme={null}
# Zig benchmarks
zig build bench -Dwith-benches=true

# TypeScript benchmarks
bun run bench
```

## Common Mistakes

<Warning>
  Avoid these testing anti-patterns:
</Warning>

```typescript theme={null}
// ❌ Commented out test (remove or implement)
// it("handles edge case", () => {
//   // implement here when ready
// });

// ❌ Empty test
it("does something", () => {});

// ❌ Test with placeholder
it("validates input", () => {
  // add real assertions here
  expect(true).toBe(true);
});

// ❌ Skipped test
it.skip("broken test", () => { ... });
```

All of these should either be:

1. Implemented properly
2. Deleted entirely
