sigildocs

Testing

Sigil provides a built-in test framework through (sigil test) and a CLI command for discovering and running tests with helpful output.

Quick Start

Create a test file in your package's test/ directory:

;; test/test-math.sgl
(import (sigil test))

(test-group "arithmetic"
  (test "addition works"
    (assert-equal 4 (+ 2 2)))

  (test "multiplication works"
    (assert-equal 6 (* 2 3))))

Run tests:

sigil test

Writing Tests

Test Structure

Tests are organized with test-group and test:

(import (sigil test))

(test-group "Reader"
  (test "reads integers"
    (assert-equal 42 (read-from-string "42")))

  (test "reads symbols"
    (assert-equal 'foo (read-from-string "foo"))))

(test-group "Compiler"
  (test "compiles lambda"
    (assert-true (procedure? (eval '(lambda (x) x))))))

Assertions

The (sigil test) module provides several assertion functions:

FunctionPurpose
(assert-equal expected actual)Check values are equal
(assert-true expr)Check expression is truthy
(assert-false expr)Check expression is #f
(assert-error thunk)Check that thunk raises an error

Examples:

(test "equality checks"
  (assert-equal '(1 2 3) (list 1 2 3))
  (assert-equal "hello" (string-append "hel" "lo")))

(test "boolean checks"
  (assert-true (pair? '(a . b)))
  (assert-false (null? '(1 2 3))))

(test "error checking"
  (assert-error (lambda () (car 5))))

Test Discovery

Default Behavior

With no arguments, sigil test discovers tests by:

  1. Looking for test/ directory in the project root
  2. Finding all *.sgl files matching patterns:
  • test-*.sgl
  • *-test.sgl
  • Files directly in test/ directory

Running Specific Tests

sigil test test/test-compiler.sgl           # Single file
sigil test test/compiler/                   # Directory
sigil test test-*.sgl                       # Glob pattern
sigil test test/test-reader.sgl test/test-vm.sgl  # Multiple files

Command Line Options

sigil test [options] [file-or-pattern...]

Options:
  --native           Run only native (C) tests
  --sgl              Run only Sigil tests
  -f, --filter PAT   Run only tests matching pattern
  -c, --compact      Compact output (dots instead of names)
  -q, --quiet        Minimal output (exit code only)
  --no-color         Disable colored output
  --fail-fast        Stop on first failure
  -h, --help         Show help

Output Formats

Default (Verbose)

Shows all test names with results:

Running tests...

  Reader
    ✓ reads integers (2ms)
    ✓ reads symbols (1ms)
    ✗ reads floats
      Expected: 3.14
      Actual:   3.14000000001
      at test/test-reader.sgl:42

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  Tests:    156 passed, 1 failed (157 total)
  Time:     1.23s

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Compact Mode (-c)

For faster scanning with many tests:

Reader ✓✓✓✓✓✓✓✓ (8/8)
Compiler ✓✓✓✓✓✗✓✓✓✓ (9/10)
  ✗ handles edge case
    Expected: #t
    Actual:   #f
VM ✓✓✓✓✓✓✓✓✓✓✓✓ (12/12)

  ✓ 29 passed, 1 failed

Quiet Mode (-q)

No output except errors. Exit code indicates pass/fail:

  • 0 — All tests passed
  • 1 — One or more tests failed
  • 2 — Test execution error

Filtering Tests

Run specific tests by pattern:

sigil test -f "reader"        # Tests with "reader" in name
sigil test -f "Reader > int"  # More specific
sigil test -f "compile*"      # Glob pattern

Test File Locations

Tests are organized per-package:

packages/
├── sigil-stdlib/
│   └── test/
│       ├── test-core.sgl
│       ├── test-string.sgl
│       └── test-hygiene.sgl
├── sigil-json/
│   └── test/
│       └── test-json.sgl
└── sigil-http/
    └── test/
        └── test-http.sgl

Native Tests

For packages with C code, native tests use the test framework in packages/sigil-lib/test/test.h:

#include "test.h"

TEST(reader_integers) {
    Value v = sigil_read_string(vm, "42");
    ASSERT(sigil_is_fixnum(v));
    ASSERT_EQ(sigil_fixnum_value(v), 42);
}

TEST(reader_symbols) {
    Value v = sigil_read_string(vm, "foo");
    ASSERT(sigil_is_symbol(v));
}

int main(void) {
    RUN_TEST(reader_integers);
    RUN_TEST(reader_symbols);
    return test_summary();
}

Run native tests only:

sigil test --native

Best Practices

  1. Test file naming: Use test-<feature>.sgl for clarity
  2. Group related tests: Use test-group to organize
  3. Descriptive names: Test names should describe expected behavior
  4. One assertion per test: When possible, keep tests focused
  5. Test edge cases: Include boundary conditions and error cases

Integration with CI

Add to your CI pipeline:

sigil test --quiet

The exit code indicates success (0) or failure (non-zero).