tests: the full suite's seven failures on lang/foundations - one compiler fault and six stale expectations
- the test runner re-makes every state between tests again: since12fdc07a state is made by its getter on first use, so re-running L_init_globals left the last test's state in place (state/tested failed its second test); @L_reset_states forgets every lazy state, and the runner calls it before each test - diag_json_case counts errors, and an absent @Ref / @Tint / @OneOf target is a warning sinced82dc31: ref_unknown is 1 error and node_bad 8 - schema_hash.ludic prints 1: a bool is 1 or 0 as text (random_plain's 1 1 1) - permap_check_case looks for the unit warning without the quotes the JSON escapes - baked_test's inputs-hash test makes its directory: each test has a temp directory of its own - ludic deps prints phase 25's five counters too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
9ff219d065
commit
d8baf4e579
7 changed files with 57785 additions and 57592 deletions
|
|
@ -2,7 +2,7 @@
|
|||
# prints), so a tool can tell which data a running build was compiled from; 0 in a release build
|
||||
# (`ludicc --release`, which ludic bundle passes).
|
||||
#
|
||||
# Running it prints: true
|
||||
# Running it prints: 1 (a bool is 1 or 0 as text)
|
||||
program SchemaHash {
|
||||
property Tool {
|
||||
key: string = ""
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ program BakedTest {
|
|||
}
|
||||
|
||||
test "the inputs hash follows the path and the bytes" {
|
||||
Fs.mkdir(dir()) # each test has a temp directory of its own, empty
|
||||
Fs.write_text(dir() + "/in.txt", "abc")
|
||||
let h1 = bake_inputs_hash(dir() + "/in.txt")
|
||||
Fs.write_text(dir() + "/in.txt", "abd")
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ function emit_test_fn(t: Node, idx: int) -> void {
|
|||
# emit every test body plus the runner @main that drives them.
|
||||
function emit_test_runner() -> void {
|
||||
emith("@L_test_fail = internal global i32 0\n")
|
||||
emit_state_reset()
|
||||
emith("@.fmt_test_sum = private unnamed_addr constant [28 x i8] c\"== %d passed, %d failed ==\\0A\\00\"\n")
|
||||
emith("@.fmt_test_none = private unnamed_addr constant [20 x i8] c\"no test named \\22%s\\22\\0A\\00\"\n")
|
||||
var i = 0
|
||||
|
|
@ -181,7 +182,10 @@ function emit_test_runner() -> void {
|
|||
emit(` store i32 {rn1}, ptr %ran\n`)
|
||||
emit(" store i32 0, ptr @L_test_fail\n")
|
||||
# 0.S: every state fresh for each test - the states are what changes, and they are made here
|
||||
if i > 0 { emit(" call void @L_init_globals()\n") }
|
||||
if i > 0 {
|
||||
emit(" call void @L_init_globals()\n")
|
||||
emit(" call void @L_reset_states()\n") # a lazy state is made by its getter, not above
|
||||
}
|
||||
emit(` call void @fn__test_{itoa(i)}()\n`)
|
||||
let f = emit_bind("load i32, ptr @L_test_fail")
|
||||
let isbad = emit_bind(`icmp ne i32 {f}, 0`)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ function emit_state_getter(d: Node) -> void {
|
|||
emit("}\n\n")
|
||||
}
|
||||
|
||||
# the test runner's fresh start between tests: every lazy state forgotten, so its getter makes it
|
||||
# anew from its defaults (0.S: each test's states are fresh) - L_init_globals no longer makes them
|
||||
function emit_state_reset() -> void {
|
||||
emith("define void @L_reset_states() {\nentry:\n")
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
if is_lazy_state(prog[i]) { emith(` store ptr null, ptr @g_{prog[i].s}\n`) }
|
||||
i += 1
|
||||
}
|
||||
emith(" ret void\n}\n")
|
||||
}
|
||||
|
||||
# a read of a state global: its getter's answer, or null when it is not lazy
|
||||
function lazy_state_read(g: Node, s: pointer) -> pointer {
|
||||
if not is_lazy_state(g) { return null }
|
||||
|
|
|
|||
56391
selfhost/ludicc.seed.ll
56391
selfhost/ludicc.seed.ll
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -70,10 +70,12 @@ function permap_check_case() -> void {
|
|||
if not shq(`bin/ludicc examples/lang/permap/permap.ludic --check --diagnostics=json > {js} 2>/dev/null`) { bad2(lbl, capture_line(`head -3 {js}`)); return }
|
||||
if not shq(`bin/ludicc examples/rejected/permap_maps/permap_maps.ludic --check --no-maps > /dev/null 2>&1`) { bad2(lbl, "--no-maps still read the maps"); return }
|
||||
if not shq(`bin/ludicc examples/rejected/permap_unit.ludic --check --diagnostics=json > {js} 2>/dev/null`) { bad2(lbl, "a unit spelling was refused, not warned"); return }
|
||||
if not s_contains(capture(`cat {js}`), "@Unit(\"°\"): the unit is spelled \"deg\"") { bad2(lbl, capture_line(`head -3 {js}`)); return }
|
||||
# the JSON escapes the message's quotes (\"°\"), so the part without them is what is looked for
|
||||
if not s_contains(capture(`cat {js}`), "the unit is spelled") or not s_contains(capture(`cat {js}`), "deg") { bad2(lbl, capture_line(`head -3 {js}`)); return }
|
||||
ok(lbl)
|
||||
}
|
||||
# --check --diagnostics=json: refused, with exactly `n` diagnostics on stdout, one of them holding `want`
|
||||
# --check --diagnostics=json: refused, with exactly `n` ERRORS on stdout (warnings beside them are not
|
||||
# counted), one of the diagnostics holding `want`
|
||||
function diag_json_case(path: pointer, n: int, want: pointer, label: pointer) -> void {
|
||||
let js = `{tmp_dir()}/dj_{flat(path)}.json`
|
||||
if shq(`bin/ludicc examples/{path}.ludic --check --diagnostics=json > {js} 2>/dev/null`) {
|
||||
|
|
@ -512,7 +514,7 @@ function deps_case() -> void {
|
|||
let lbl = "ludic deps: the numbers, --check against a baseline, --dot, --writes"
|
||||
let p = "examples/modules/tangle.ludic"
|
||||
let got = capture(`bin/ludic deps {p} 2>&1`)
|
||||
let want = "modules: 3\ndependencies: 2\nlargest_cycle: 2\ncross_writes: 1\nglobals_written_from_outside: 1\nwidest_function: 1\nwidest_reach: 1\nwidest_write_reach: 1\nin the largest cycle: a b\nthe widest function: a_run (examples/modules/tangle/a/index.ludic:3), 1 state\nthe widest write reach: a_run (examples/modules/tangle/a/index.ludic:3), 1 state it can come to change\n"
|
||||
let want = "modules: 3\ndependencies: 2\nlargest_cycle: 2\ncross_writes: 1\nglobals_written_from_outside: 1\nwidest_function: 1\nwidest_reach: 1\nwidest_write_reach: 1\nframe_allocs: 0\nframe_keeps: 0\nbirth_leaks: 0\nresource_drops: 0\nowned_leaks: 0\nin the largest cycle: a b\nthe widest function: a_run (examples/modules/tangle/a/index.ludic:3), 1 state\nthe widest write reach: a_run (examples/modules/tangle/a/index.ludic:3), 1 state it can come to change\n"
|
||||
if not (s_trim(got) == s_trim(want)) { bad2(lbl, `said [{s_trim(got)}]`); return }
|
||||
let base = `{tmp_dir()}/deps-base.txt`
|
||||
if not shq(`bin/ludic deps {p} --baseline {base} > /dev/null`) { bad2(lbl, "--baseline failed"); return }
|
||||
|
|
@ -1210,8 +1212,8 @@ function cmd_dev_test() -> int {
|
|||
reject_case("rejected/math_into_text", "field a1 of Note wants a string and this is an int", "a Math.* result has its type: an int from Math.max is not text")
|
||||
reject_count("rejected/every_error", 3, "every type error in a program is reported at once, not only the first")
|
||||
diag_json_case("rejected/every_error", 3, "\"line\": 8, \"col\": 15, \"severity\": \"error\", \"message\": \"half takes 1 argument(s) and this call gives 2\"", "--diagnostics=json: every type error as {file, line, col, severity, message}")
|
||||
diag_json_case("rejected/ref_unknown", 2, "@Ref(Shops): this program has no Shops - left unresolved", "--diagnostics=json: an @Ref to a registry the program lacks is a warning beside the error")
|
||||
diag_json_case("rejected/node_bad", 10, "crate.shape is \\\"cube\\\", and field Tool.shape is @OneOf(", "--diagnostics=json: every @Node / @Clip / @Material with no model field, @OneOf of the wrong kind or a row outside its words, and the targets the program lacks as warnings")
|
||||
diag_json_case("rejected/ref_unknown", 1, "@Ref(Shops): this program has no Shops - left unresolved", "--diagnostics=json: an @Ref to a registry the program lacks is a warning beside the error")
|
||||
diag_json_case("rejected/node_bad", 8, "crate.shape is \\\"cube\\\", and field Tool.shape is @OneOf(", "--diagnostics=json: every @Node / @Clip / @Material with no model field, @OneOf of the wrong kind or a row outside its words, and the targets the program lacks as warnings")
|
||||
feat_case("lang/generics", "", "7 Crater Lake a 2 west 7 0.75 2.5 1", "generics.ludic (L5: generic records and functions, nested instances, fn-typed parameters and fields, inference from the result's slot)")
|
||||
reject_case("rejected/generic_unbound", "cannot tell what T is in this call to pool_new", "a call whose type arguments nothing decides is refused")
|
||||
reject_case("rejected/generic_mismatch", "words wants a Pool<string> and this is a Pool<int>", "two instances of one generic are two types")
|
||||
|
|
@ -1244,7 +1246,7 @@ function cmd_dev_test() -> int {
|
|||
feat_case("lang/registry", "", "3 Crate true 2 fire_ring -1", "registry.ludic (L8: a registry filled by def declarations - index constants, a count, the key, a lookup)")
|
||||
reject_case("rejected/registry_unknown", "there is no registry Tables", "a def names a registry that exists")
|
||||
feat_case("lang/attributes", "", "2 1 Lantern 2", "attributes.ludic (editor attributes: @Ref, @OneOf, @Range, @Unit, @Asset, @Color, @AppendOnly, @ByKey - no effect on the program)")
|
||||
feat_case("lang/schema_hash", "", "true", "schema_hash.ludic (Build.schema_hash(): FNV-1a 64 of the program's own schema, 0 in a release)")
|
||||
feat_case("lang/schema_hash", "", "1", "schema_hash.ludic (Build.schema_hash(): FNV-1a 64 of the program's own schema, 0 in a release)")
|
||||
reject_case("rejected/ref_unknown", "field Tool.seller: @Ref(Vendor) names Vendor, which is not a registry", "@Ref names a registry, not another kind of thing")
|
||||
reject_case("rejected/node_bad", "field Tool.grip: @Node(handle) names no field", "@Node names a field of its record")
|
||||
schema_case("lang/attributes", "{\"name\": \"weight\", \"type\": \"float\", \"default\": \"1.0\", \"file\": \"examples/lang/attributes.ludic\", \"line\": 24, \"col\": 33, \"attributes\": [{\"name\": \"Range\", \"args\": [0, 20.5]}, {\"name\": \"Unit\", \"args\": [\"kg\"]}]", "--emit-schema: a field's type, default, place and attributes")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue