Complete guide to testing HQL code on HLVM.
Test the binary works:
make test
This runs basic smoke tests.
deno task test:unit
deno test --allow-all tests/unit/syntax-ternary.test.ts
Rerun tests on file changes:
deno task test:watch
tests/
├── unit/ # Unit tests
│ ├── syntax-*.test.ts # Syntax tests
│ ├── stdlib-*.test.ts # Standard library tests
│ ├── macro-*.test.ts # Macro tests
│ └── organized/ # Feature-organized tests
├── binary/ # Binary/CLI tests
└── e2e/ # End-to-end tests
import { assertEquals } from "jsr:@std/assert@1"//
import hql from "../mod.ts"//
async function run(code: string) {
return await hql.run(code)//
}
Deno.test("addition works", async () => {
const result = await run("(+ 1 2 3)")//
assertEquals(result, 6)//
})//
Deno.test("functions work", async () => {
const result = await run(`
(fn double [x] (* x 2))
(double 5)
`)//
assertEquals(result, 10)//
})//
Create my-test.test.ts:
import { assertEquals, assertThrows } from "jsr:@std/assert@1"//
import hql from "./mod.ts"//
async function run(code: string) {
return await hql.run(code)//
}
Deno.test("my function works", async () => {
const result = await run(`
(fn greet [name]
(+ "Hello, " name))
(greet "World")
`)//
assertEquals(result, "Hello, World")//
})//
Deno.test("division by zero throws", async () => {
await assertThrows(
async () => await run("(/ 1 0)"),
Error,
"Division by zero"
)//
})//
Deno.test("async operations work", async () => {
const result = await run(`
(fn async-double [x]
(await (Promise.resolve (* x 2))))
(await (async-double 5))
`)//
assertEquals(result, 10)//
})//
const result = await hql.run("(+ 1 2)")//
const js = await hql.transpile("(+ 1 2)")//
// js contains JavaScript code
const ast = await hql.parse("(+ 1 2)")//
// ast contains syntax tree
Test individual functions:
// tests/unit/math.test.hql
(fn test-addition []
(assert (=== (+ 1 2) 3))
(assert (=== (+ 10 20 30) 60)))
(test-addition)
Test feature combinations:
// tests/integration/pipeline.test.hql
(fn test-pipeline []
(let numbers [1 2 3 4 5])
(let result
(reduce +
0
(map (fn [x] (* x 2))
(filter (fn [x] (> x 2)) numbers))))
(assert (=== result 24)))
(test-pipeline)
Test bug fixes:
// tests/regression/issue-123.test.hql
(fn test-macro-expansion []
// Ensure macro expands correctly
(macro when [test & body]
`(if ~test (do ~@body)))
(let result (when true 42))
(assert (=== result 42)))
(test-macro-expansion)
Time execution:
hlvm run --time script.hql
Profile compilation:
hlvm compile --time --verbose script.hql
Tests run automatically on:
See .github/workflows/release.yml.
Run same tests as CI:
make test
Use descriptive names:
// Good
Deno.test("map transforms all elements", async () => {
// ...
})//
// Bad
Deno.test("test1", async () => {
// ...
})//
// Good
Deno.test("addition works", async () => {
assertEquals(await run("(+ 1 2)"), 3)//
})//
Deno.test("subtraction works", async () => {
assertEquals(await run("(- 5 3)"), 2)//
})//
// Bad
Deno.test("math works", async () => {
assertEquals(await run("(+ 1 2)"), 3)//
assertEquals(await run("(- 5 3)"), 2)//
})//
Deno.test("empty array", async () => {
assertEquals(await run("(first [])"), null)//
})//
Deno.test("single element", async () => {
assertEquals(await run("(first [1])"), 1)//
})//
Deno.test("multiple elements", async () => {
assertEquals(await run("(first [1 2 3])"), 1)//
})//
Deno.test("file operations", async () => {
// Create test file
await Deno.writeTextFile("/tmp/test.txt", "hello")//
try {
const result = await run(`
(import fs from "npm:fs/promises")
(await (fs.readFile "/tmp/test.txt" "utf-8"))
`)//
assertEquals(result, "hello")//
} finally {
// Clean up
await Deno.remove("/tmp/test.txt")//
}
})//
deno test --allow-all tests/unit/
deno test --allow-all tests/unit/specific.test.ts
All features must have tests.