Files
cell/tests/compile.cm

130 lines
3.5 KiB
Plaintext

// Compile-time diagnostics tests — verify the type checker catches errors
var fd = use('fd')
var shop = use('internal/shop')
var streamline = use('streamline')
var tmpfile = "/tmp/_cell_compile_test.cm"
function write_source(src) {
fd.slurpwrite(tmpfile, stone(blob(src)))
}
function get_diagnostics(src) {
write_source(src)
var compiled = shop.mcode_file(tmpfile)
compiled._warn = true
var optimized = streamline(compiled)
if (optimized._diagnostics == null) return []
return optimized._diagnostics
}
function has_diagnostic(diags, severity, pattern) {
var i = 0
while (i < length(diags)) {
if (diags[i].severity == severity && search(diags[i].message, pattern) != null) {
return true
}
i = i + 1
}
return false
}
function expect(diags, severity, pattern) {
if (!has_diagnostic(diags, severity, pattern)) {
return `expected ${severity} matching '${pattern}', got ${text(length(diags))} diagnostic(s)`
}
return null
}
function expect_clean(diags) {
if (length(diags) > 0) {
return `expected no diagnostics, got ${text(length(diags))}`
}
return null
}
return {
// === Store errors ===
test_store_field_on_array: function() {
var d = get_diagnostics("var a = []\na[\"x\"] = 1")
return expect(d, "error", "storing named property on array")
},
test_store_index_on_record: function() {
var d = get_diagnostics("var a = {}\na[1] = 1")
return expect(d, "error", "storing numeric index on record")
},
test_store_field_on_text: function() {
var d = get_diagnostics("var s = \"hello\"\ns.x = 1")
return expect(d, "error", "storing property on text")
},
test_store_index_on_text: function() {
var d = get_diagnostics("var s = \"hello\"\ns[0] = 1")
return expect(d, "error", "storing index on text")
},
test_push_on_text: function() {
var d = get_diagnostics("var s = \"hello\"\ns[] = 1")
return expect(d, "error", "push on text")
},
test_push_on_record: function() {
var d = get_diagnostics("var r = {}\nr[] = 1")
return expect(d, "error", "push on record")
},
// === Invoke errors ===
test_invoke_null: function() {
var d = get_diagnostics("var x = null\nx()")
return expect(d, "error", "invoking null")
},
test_invoke_number: function() {
var d = get_diagnostics("var x = 42\nx()")
return expect(d, "error", "invoking")
},
test_invoke_text: function() {
var d = get_diagnostics("var x = \"hello\"\nx()")
return expect(d, "error", "invoking")
},
// === Warnings ===
test_field_on_array_warns: function() {
var d = get_diagnostics("var a = [1, 2]\nvar x = a.name")
return expect(d, "warning", "named property access on array")
},
test_field_on_text_warns: function() {
var d = get_diagnostics("var s = \"hello\"\nvar x = s.name")
return expect(d, "warning", "named property access on text")
},
test_record_key_on_record_warns: function() {
var d = get_diagnostics("var r = {a: 1}\nvar k = {}\nvar x = r[k]")
return expect(d, "warning", "record key on record")
},
// === Clean code produces no diagnostics ===
test_clean_array_ops: function() {
var d = get_diagnostics("var a = [1, 2, 3]\nvar x = a[0]\na[1] = 5\na[] = 4")
return expect_clean(d)
},
test_clean_record_ops: function() {
var d = get_diagnostics("var r = {a: 1, b: 2}\nvar x = r.a\nr.c = 3")
return expect_clean(d)
},
test_clean_function_call: function() {
var d = get_diagnostics("function f(a, b) { return a + b }\nvar x = f(1, 2)")
return expect_clean(d)
}
}