mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Update some tests, delete obsolete ones
This commit is contained in:
parent
bd4006ce3a
commit
d4e4b58dfd
4 changed files with 42 additions and 133 deletions
|
|
@ -66,44 +66,15 @@ test "polymorphic empty list" {
|
|||
}
|
||||
|
||||
test "polymorphic cons function" {
|
||||
// This test is skipped because these features are missing:
|
||||
// - Spread operator `..` in list literals [fails at parse stage - syntax not recognized]
|
||||
// TODO: Enable when spread operator is implemented in the parser
|
||||
|
||||
const source =
|
||||
\\{
|
||||
\\ cons = |x, xs| [x, ..xs]
|
||||
\\ cons = |x, xs| List.concat([x], xs)
|
||||
\\ list1 = cons(1, [2, 3])
|
||||
\\ list2 = cons("a", ["b", "c"])
|
||||
\\ { list1, list2 }
|
||||
\\}
|
||||
;
|
||||
try typeCheck(source, "TODO");
|
||||
}
|
||||
|
||||
test "polymorphic map function" {
|
||||
// This test is skipped because these features are missing:
|
||||
// - If-then-else expressions [fails at parse stage - syntax not recognized]
|
||||
// - Recursive function calls [would fail at canonicalize stage - self-references not resolved]
|
||||
// - List slicing `xs[1..]` [fails at parse stage - range syntax not recognized]
|
||||
// - Spread operator `[x, ..xs]` [fails at parse stage - syntax not recognized]
|
||||
// - List equality comparison `xs == []` [may fail at type-check stage]
|
||||
// Note: List indexing `xs[0]` does parse and canonicalize but may have type issues
|
||||
// TODO: Enable when conditional expressions, recursion, and list operations are implemented
|
||||
|
||||
const source =
|
||||
\\{
|
||||
\\ map = |f, xs|
|
||||
\\ if xs == [] then
|
||||
\\ []
|
||||
\\ else
|
||||
\\ [f(xs[0]), ..map(f, xs[1..])]
|
||||
\\ double = |x| x * 2
|
||||
\\ nums = map(double, [1, 2, 3])
|
||||
\\ { nums }
|
||||
\\}
|
||||
;
|
||||
try typeCheck(source, "TODO");
|
||||
try typeCheck(source, "{ list1: List(item), list2: List(Str) } where [_a.from_num_literal : _arg -> _ret]");
|
||||
}
|
||||
|
||||
test "polymorphic record constructor" {
|
||||
|
|
@ -174,32 +145,6 @@ test "polymorphic swap function" {
|
|||
try typeCheck(source, "{ swapped1: { first: Str, second: _field }, swapped2: { first: _field2, second: [True]_others } } where [_a.from_num_literal : _arg -> _ret, _b.from_num_literal : _arg2 -> _ret2]");
|
||||
}
|
||||
|
||||
test "polymorphic fold function" {
|
||||
// This test is skipped because these features are missing:
|
||||
// - If-then-else expressions [fails at parse stage - syntax not recognized]
|
||||
// - Recursive function calls [would fail at canonicalize stage - self-references not resolved]
|
||||
// - List equality comparison `xs == []` [may fail at type-check stage]
|
||||
// - String concatenation operator `++` [fails at parse or canonicalize stage]
|
||||
// - List slicing `xs[1..]` [fails at parse stage - range syntax not recognized]
|
||||
// Even if parsing succeeded, the canonicalizer doesn't support recursive
|
||||
// let-bindings, and the type checker doesn't handle recursive polymorphic functions.
|
||||
// TODO: Enable when conditional expressions, recursion, and list/string operations are implemented
|
||||
|
||||
const source =
|
||||
\\{
|
||||
\\ fold = |f, acc, xs|
|
||||
\\ if xs == [] then
|
||||
\\ acc
|
||||
\\ else
|
||||
\\ fold(f, f(acc, xs[0]), xs[1..])
|
||||
\\ sum = fold(|a, b| a + b, 0, [1, 2, 3])
|
||||
\\ concat = fold(|a, b| a ++ b, "", ["a", "b", "c"])
|
||||
\\ { sum, concat }
|
||||
\\}
|
||||
;
|
||||
try typeCheck(source, "TODO");
|
||||
}
|
||||
|
||||
test "polymorphic option type simulation" {
|
||||
const source =
|
||||
\\{
|
||||
|
|
@ -228,33 +173,6 @@ test "polymorphic const function" {
|
|||
try typeCheck(source, "{ num: _field, str: Str } where [_a.from_num_literal : _arg -> _ret]");
|
||||
}
|
||||
|
||||
test "shadowing of polymorphic values" {
|
||||
// This test is skipped because these features are missing:
|
||||
// - Type checking for nested block expressions that return values
|
||||
// [parses and canonicalizes successfully, fails at type-check stage]
|
||||
// The inner block `{ id = ...; b = ...; b }` should return `b` as its value.
|
||||
// The type checker fails to properly handle the combination of:
|
||||
// 1. A nested block that shadows a polymorphic identifier
|
||||
// 2. The block returning a value (the final `b` expression)
|
||||
// 3. Continuing to use the original polymorphic `id` after the block
|
||||
// TODO: Enable when nested block expressions with value returns are fully supported
|
||||
|
||||
const source =
|
||||
\\{
|
||||
\\ id = |x| x
|
||||
\\ a = id(1)
|
||||
\\ inner = {
|
||||
\\ id = |x| x + 1 // shadows outer id, now monomorphic
|
||||
\\ b = id(2)
|
||||
\\ b
|
||||
\\ }
|
||||
\\ c = id("test") // uses outer polymorphic id
|
||||
\\ { a, inner, c }
|
||||
\\}
|
||||
;
|
||||
try typeCheck(source, "TODO");
|
||||
}
|
||||
|
||||
test "polymorphic pipe function" {
|
||||
const source =
|
||||
\\{
|
||||
|
|
|
|||
|
|
@ -138,8 +138,8 @@ test "ModuleEnv.Serialized roundtrip" {
|
|||
try testing.expectEqual(@as(usize, 2), original.imports.imports.len()); // Should have 2 unique imports
|
||||
|
||||
// First verify that the CommonEnv data was preserved after deserialization
|
||||
// Should have same 10 identifiers as original: hello, world, TestModule + 7 well-known identifiers from ModuleEnv.init()
|
||||
try testing.expectEqual(@as(u32, 10), env.common.idents.interner.entry_count);
|
||||
// Should have same 21 identifiers as original: hello, world, TestModule + 18 well-known identifiers from ModuleEnv.init()
|
||||
try testing.expectEqual(@as(u32, 21), env.common.idents.interner.entry_count);
|
||||
|
||||
try testing.expectEqual(@as(usize, 1), env.common.exposed_items.count());
|
||||
try testing.expectEqual(@as(?u16, 42), env.common.exposed_items.getNodeIndexById(gpa, @as(u32, @bitCast(hello_idx))));
|
||||
|
|
|
|||
|
|
@ -45,42 +45,6 @@ test "eval simple number" {
|
|||
try runExpectInt("-1234", -1234, .no_trace);
|
||||
}
|
||||
|
||||
test "eval boolean literals" {
|
||||
try runExpectBool("True", true, .no_trace);
|
||||
try runExpectBool("False", false, .no_trace);
|
||||
// Note: Qualified tags like Bool.True and Bool.False don't work yet
|
||||
// See QUALIFIED_TAGS.md for details
|
||||
}
|
||||
|
||||
test "eval unary not operator" {
|
||||
try runExpectBool("!True", false, .no_trace);
|
||||
try runExpectBool("!False", true, .no_trace);
|
||||
}
|
||||
|
||||
test "eval double negation" {
|
||||
try runExpectBool("!!True", true, .no_trace);
|
||||
try runExpectBool("!!False", false, .no_trace);
|
||||
try runExpectBool("!!!True", false, .no_trace);
|
||||
try runExpectBool("!!!False", true, .no_trace);
|
||||
}
|
||||
|
||||
test "eval boolean in lambda expressions" {
|
||||
try runExpectBool("(|x| !x)(True)", false, .no_trace);
|
||||
try runExpectBool("(|x| !x)(False)", true, .no_trace);
|
||||
// Not implemented yet -- the closure return type is still flex var
|
||||
// try runExpectBool("(|x, y| x and y)(True, False)", false, .no_trace);
|
||||
// try runExpectBool("(|x, y| x or y)(False, True)", true, .no_trace);
|
||||
// try runExpectBool("(|x| x and !x)(True)", false, .no_trace);
|
||||
// try runExpectBool("(|x| x or !x)(False)", true, .no_trace);
|
||||
}
|
||||
|
||||
test "eval unary not in conditional expressions" {
|
||||
try runExpectInt("if !True 42 else 99", 99, .no_trace);
|
||||
try runExpectInt("if !False 42 else 99", 42, .no_trace);
|
||||
try runExpectInt("if !!True 42 else 99", 42, .no_trace);
|
||||
try runExpectInt("if !!False 42 else 99", 99, .no_trace);
|
||||
}
|
||||
|
||||
test "if-else" {
|
||||
try runExpectInt("if (1 == 1) 42 else 99", 42, .no_trace);
|
||||
try runExpectInt("if (1 == 2) 42 else 99", 99, .no_trace);
|
||||
|
|
@ -142,17 +106,6 @@ test "comparison binops" {
|
|||
try runExpectInt("if 5 != 5 100 else 200", 200, .no_trace);
|
||||
}
|
||||
|
||||
test "logical binops" {
|
||||
try runExpectInt("if True and True 1 else 0", 1, .no_trace);
|
||||
try runExpectInt("if True and False 1 else 0", 0, .no_trace);
|
||||
try runExpectInt("if False and True 1 else 0", 0, .no_trace);
|
||||
try runExpectInt("if False and False 1 else 0", 0, .no_trace);
|
||||
try runExpectInt("if True or True 1 else 0", 1, .no_trace);
|
||||
try runExpectInt("if True or False 1 else 0", 1, .no_trace);
|
||||
try runExpectInt("if False or True 1 else 0", 1, .no_trace);
|
||||
try runExpectInt("if False or False 1 else 0", 0, .no_trace);
|
||||
}
|
||||
|
||||
test "unary minus" {
|
||||
try runExpectInt("-5", -5, .no_trace);
|
||||
try runExpectInt("-(-10)", 10, .no_trace);
|
||||
|
|
|
|||
|
|
@ -107,6 +107,44 @@ pub fn runExpectInt(src: []const u8, expected_int: i128, should_trace: enum { tr
|
|||
try std.testing.expectEqual(expected_int, int_value);
|
||||
}
|
||||
|
||||
/// Helper function to run an expression and expect a boolean result.
|
||||
pub fn runExpectBool(src: []const u8, expected_bool: bool, should_trace: enum { trace, no_trace }) !void {
|
||||
const resources = try parseAndCanonicalizeExpr(test_allocator, src);
|
||||
defer cleanupParseAndCanonical(test_allocator, resources);
|
||||
|
||||
var test_env_instance = TestEnv.init(test_allocator);
|
||||
defer test_env_instance.deinit();
|
||||
|
||||
const builtin_types = BuiltinTypes.init(resources.builtin_indices, resources.builtin_module.env, resources.builtin_module.env, resources.builtin_module.env);
|
||||
var interpreter = try Interpreter.init(test_allocator, resources.module_env, builtin_types, resources.builtin_module.env, &[_]*const can.ModuleEnv{});
|
||||
defer interpreter.deinit();
|
||||
|
||||
const enable_trace = should_trace == .trace;
|
||||
if (enable_trace) {
|
||||
interpreter.startTrace();
|
||||
}
|
||||
defer if (enable_trace) interpreter.endTrace();
|
||||
|
||||
const ops = test_env_instance.get_ops();
|
||||
const result = try interpreter.evalMinimal(resources.expr_idx, ops);
|
||||
const layout_cache = &interpreter.runtime_layout_store;
|
||||
defer result.decref(layout_cache, ops);
|
||||
|
||||
// For boolean results, read the underlying byte value
|
||||
if (result.layout.tag == .scalar and result.layout.data.scalar.tag == .int) {
|
||||
// Boolean represented as integer (discriminant)
|
||||
const int_val = result.asI128();
|
||||
const bool_val = int_val != 0;
|
||||
try std.testing.expectEqual(expected_bool, bool_val);
|
||||
} else {
|
||||
// Try reading as raw byte (for boolean tag values)
|
||||
std.debug.assert(result.ptr != null);
|
||||
const bool_ptr: *const u8 = @ptrCast(@alignCast(result.ptr.?));
|
||||
const bool_val = bool_ptr.* != 0;
|
||||
try std.testing.expectEqual(expected_bool, bool_val);
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to run an expression and expect an f32 result (with epsilon tolerance).
|
||||
pub fn runExpectF32(src: []const u8, expected_f32: f32, should_trace: enum { trace, no_trace }) !void {
|
||||
const resources = try parseAndCanonicalizeExpr(test_allocator, src);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue