Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,9 @@ per file, prints `PASS`/`FAIL` per file, and exits non-zero when any test
fails. A project only needs `package.fun` (a `bin` entry is not required);
manifest dependencies are available through the same launcher as `fun run`.

- Assertions: `assert.equal`, `not_equal`, `is_true`, `is_false`, `raises`,
`fail`; each takes an optional trailing message.
- Assertions: `assert.equal`, `not_equal`, `is_true`, `is_false`, `match`,
`contains`, `greater`, `less`, `is_nil`, `not_nil`, `raises`, `fail`; each
takes an optional trailing message.
- `test.fun`, the globals `test`/`assert`/`runTests`, the aliases `as test` /
`as assert`, and dependency keys `test`/`assert` are reserved. A third-party
test library can be imported under another alias.
Expand Down
5 changes: 3 additions & 2 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,9 @@ fun test
`package.fun`(不要求 `bin`);清单里的依赖通过和 `fun run` 相同的项目
启动器生效。

- 断言:`assert.equal`、`not_equal`、`is_true`、`is_false`、`raises`、`fail`,
每个都可带最后一个自定义消息参数。
- 断言:`assert.equal`、`not_equal`、`is_true`、`is_false`、`match`、`contains`、
`greater`、`less`、`is_nil`、`not_nil`、`raises`、`fail`,每个都可带最后一个
自定义消息参数。
- `test.fun`、全局名 `test`/`assert`/`runTests`、别名 `as test`/`as assert`、
依赖键 `test`/`assert` 为保留名;三方测试库请换别名导入。
- `dist/`、`.` 开头目录和 path 依赖目录不会参与发现。
Expand Down
45 changes: 45 additions & 0 deletions fun/lib/test.fun
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
//
// Test files import `test.fun` and register blocks:
// test('name', { assert.equal(1 + 1, 2); });
// Assertions: equal, not_equal, is_true, is_false, match (regex), contains
// (substring), greater, less, is_nil, not_nil, raises, fail; each takes an
// optional trailing message.
// The runner calls `runTests()`; each test file runs in its own process.
var _tests = new [];
var _current = '';
Expand Down Expand Up @@ -58,6 +61,42 @@ fun assert_false(cond, msg)
end if;
end fun;

fun assert_match(s, re, msg)
if not (s =~ re) then
_fail(_compose(msg, "expected a match for '" & _str(s) & "'"));
end if;
end fun;

fun assert_contains(s, part, msg)
if s.subpos(part) < 0 then
_fail(_compose(msg, "expected to contain '" & _str(part) & "', got '" & _str(s) & "'"));
end if;
end fun;

fun assert_greater(actual, limit, msg)
if not (actual > limit) then
_fail(_compose(msg, 'expected > ' & _str(limit) & ', got ' & _str(actual)));
end if;
end fun;

fun assert_less(actual, limit, msg)
if not (actual < limit) then
_fail(_compose(msg, 'expected < ' & _str(limit) & ', got ' & _str(actual)));
end if;
end fun;

fun assert_is_nil(v, msg)
if v <> nil then
_fail(_compose(msg, 'expected nil, got ' & _str(v)));
end if;
end fun;

fun assert_not_nil(v, msg)
if v = nil then
_fail(_compose(msg, 'expected not nil'));
end if;
end fun;

fun assert_raises(block, part, msg)
var raised = false;
var caught = '';
Expand All @@ -83,6 +122,12 @@ var assert = [
not_equal: assert_not_equal,
is_true: assert_true,
is_false: assert_false,
match: assert_match,
contains: assert_contains,
greater: assert_greater,
less: assert_less,
is_nil: assert_is_nil,
not_nil: assert_not_nil,
raises: assert_raises,
fail: assert_fail
];
Expand Down
1 change: 1 addition & 0 deletions fun/test/expected/lib-fun-test-test.fun.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ crash marked FAIL: True
custom message shown: True
diagnostic shown: True
assert.fail shown: True
matcher failure shown: True
passing test quiet: True
failure summary: True
reserved dependency key: True
Expand Down
18 changes: 15 additions & 3 deletions fun/test/lib-fun-test-test.fun
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ var proj = base & 'main proj' & sep;
"test('raises and is_false', {" & nl &
" assert.raises({ assert.fail('boom inside'); }, 'boom inside');" & nl &
' assert.is_false(2 < 1);' & nl &
'});' & nl & nl &
"test('matchers', {" & nl &
" assert.match('hello world', /^hello/);" & nl &
" assert.contains('hello world', 'lo wo');" & nl &
' assert.greater(3, 2);' & nl &
' assert.less(2, 3);' & nl &
' assert.is_nil(nil);' & nl &
" assert.not_nil('x');" & nl &
'});' & nl);
(proj & 'tests' & sep & 'nested' & sep & 'deep_test.fun').save(
"use 'test.fun';" & nl &
Expand Down Expand Up @@ -172,12 +180,12 @@ var mo = loadIf(mlog);
check('test exits 0', m1 = 0);
check('smoke found', has(mo, 'smoke_test.fun') and has(mo, 'PASS (1)'));
check('src test found', has(mo, 'src/b_test.fun'));
check('tests helper reuse', has(mo, 'tests/a_test.fun') and has(mo, 'PASS (3)'));
check('tests helper reuse', has(mo, 'tests/a_test.fun') and has(mo, 'PASS (4)'));
check('nested test found', has(mo, 'tests/nested/deep_test.fun'));
check('dist excluded', not has(mo, 'skip_test.fun'));
check('path dep excluded', not has(mo, 'dep_test.fun'));
check('helper not a test', not has(mo, 'helpers.fun'));
check('summary', has(mo, '4 files, 6 tests: all passed'));
check('summary', has(mo, '4 files, 7 tests: all passed'));

// --- lib-only package (no bin) -------------------------------------------
var libp = base & 'libonly' & sep;
Expand Down Expand Up @@ -221,6 +229,9 @@ var failp = base & 'failing' & sep;
'});' & nl & nl &
"test('explicit fail', {" & nl &
" assert.fail('unexpected state');" & nl &
'});' & nl & nl &
"test('matcher failure', {" & nl &
" assert.match('abc', /xyz/, 'must match');" & nl &
'});' & nl);
(failp & 'crash_test.fun').save(
"use 'test.fun';" & nl &
Expand All @@ -234,8 +245,9 @@ check('crash marked FAIL', has(fo, 'crash_test.fun') and has(fo, 'boom at load')
check('custom message shown', has(fo, 'not ok custom message') and has(fo, 'math is broken'));
check('diagnostic shown', has(fo, 'expected 3, got 2'));
check('assert.fail shown', has(fo, 'not ok explicit fail') and has(fo, 'unexpected state'));
check('matcher failure shown', has(fo, 'not ok matcher failure') and has(fo, 'must match'));
check('passing test quiet', not has(fo, 'ok passing'));
check('failure summary', has(fo, '2 files, 3 tests: 1 passed, 2 failed; 1 file failed to run'));
check('failure summary', has(fo, '2 files, 4 tests: 1 passed, 3 failed; 1 file failed to run'));

// --- reserved names and shadowing ----------------------------------------
var resp = base & 'reserved' & sep;
Expand Down
Loading