sigildocs

Testing

Test framework with groups, assertions, and structured results.
(import (sigil test))

Defining Tests

Use test to define a test case and test-group to organize related tests.

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

(test-group "String operations"
  (test "concatenation"
    (assert-equal "hello world" (string-append "hello" " " "world")))
  (test "length"
    (assert-equal 5 (string-length "hello"))))

;; Groups can be nested
(test-group "Collections"
  (test-group "Lists"
    (test "map doubles"
      (assert-equal '(2 4 6) (map (lambda (x) (* x 2)) '(1 2 3))))))

Skipping and Pending Tests

;; Skip a test (temporarily disabled, body not executed)
(test-skip "broken feature"
  (assert-equal 42 (broken-function)))

;; Pending test (placeholder for future work, body not executed)
(test-pending "not yet implemented"
  (assert-true (new-feature-works)))

Both are counted separately in the test summary.

Assertions

Value Equality

(assert-equal expected actual)  ; deep equality (equal?)
(assert-eqv expected actual)    ; value equivalence (eqv?)
(assert-eq expected actual)     ; object identity (eq?)
(assert-equal '(1 2 3) (iota 3 1))   ; pass — deep list comparison
(assert-eqv 3.14 3.14)               ; pass — numeric equivalence
(assert-eq 'foo 'foo)                 ; pass — symbols are interned

Boolean

(assert-true val)   ; passes if val is not #f
(assert-false val)  ; passes if val is #f
(assert-true (> 5 3))
(assert-false (member 'x '(a b c)))

Null Checks

(assert-null val)       ; passes if val is '()
(assert-not-null val)   ; passes if val is not '()
(assert-null (cdr '(1)))
(assert-not-null (filter odd? '(1 2 3)))

Error Checking

(assert-error expr)  ; passes if expr raises an error
(assert-error (car '()))
(assert-error (error "expected failure"))

Unconditional Failure

(assert-fail message)  ; always fails with message
(test "should not reach else branch"
  (if (valid? input)
      (assert-true (process input))
      (assert-fail "input was invalid")))

Running Tests

Every test file should end with (run-tests).

(import (sigil test))

(test "example" (assert-true #t))
(run-tests)

The CLI runs all test files in the workspace:

sigil test              # Run all tests (native + Sigil)
sigil test --sgl        # Run only Sigil tests
sigil test --native     # Run only native (C) tests

Test Results

run-tests produces a test-summary with aggregate results.

  • test-summary-total — total tests run
  • test-summary-passed — tests that passed
  • test-summary-failed — tests that failed
  • test-summary-skipped — tests skipped or pending
  • test-summary-duration-ms — total time in milliseconds
  • test-summary-results — list of test-result records

Each test-result has:

  • test-result-name — test name string
  • test-result-group — group path or #f
  • test-result-passed? — boolean
  • test-result-message — failure message or #f
  • test-result-expected / test-result-actual — values on failure

Common Patterns

Testing a Module

(import (sigil test)
        (sigil json))

(test-group "json-encode"
  (test "encodes string"
    (assert-equal "\"hello\"" (json-encode "hello")))
  (test "encodes number"
    (assert-equal "42" (json-encode 42)))
  (test "encodes dict"
    (let ((result (json-decode (json-encode #{ a: 1 }))))
      (assert-equal 1 (dict-ref result a:)))))

(run-tests)

Testing Error Conditions

(test-group "input validation"
  (test "rejects empty input"
    (assert-error (parse-config "")))
  (test "rejects missing required field"
    (assert-error (parse-config "{}"))))

Test File Structure

packages/my-package/
  test/
    test-core.sgl       # Core functionality tests
    test-parsing.sgl     # Parser tests
    test-output.sgl      # Output formatting tests

Each file is self-contained with its own imports and (run-tests) call.