mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
428 lines
11 KiB
Rust
428 lines
11 KiB
Rust
#[macro_use]
|
|
extern crate pretty_assertions;
|
|
|
|
#[macro_use]
|
|
extern crate indoc;
|
|
|
|
mod helpers;
|
|
|
|
#[cfg(test)]
|
|
mod repl_eval {
|
|
use crate::helpers;
|
|
|
|
const ERROR_MESSAGE_START: char = '─';
|
|
|
|
fn expect_success(input: &str, expected: &str) {
|
|
let out = helpers::repl_eval(input);
|
|
|
|
assert_eq!(&out.stderr, "");
|
|
assert_eq!(&out.stdout, expected);
|
|
assert!(out.status.success());
|
|
}
|
|
|
|
fn expect_failure(input: &str, expected: &str) {
|
|
let out = helpers::repl_eval(input);
|
|
|
|
// there may be some other stuff printed (e.g. unification errors)
|
|
// so skip till the header of the first error
|
|
match out.stdout.find(ERROR_MESSAGE_START) {
|
|
Some(index) => {
|
|
assert_eq!(&out.stderr, "");
|
|
assert_eq!(&out.stdout[index..], expected);
|
|
assert!(out.status.success());
|
|
}
|
|
None => {
|
|
assert_eq!(&out.stderr, "");
|
|
assert!(out.status.success());
|
|
panic!(
|
|
"I expected a failure, but there is no error message in stdout:\n\n{}",
|
|
&out.stdout
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn literal_0() {
|
|
expect_success("0", "0 : Num *");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_42() {
|
|
expect_success("42", "42 : Num *");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_0x0() {
|
|
expect_success("0x0", "0 : I64");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_0x42() {
|
|
expect_success("0x42", "66 : I64");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_0point0() {
|
|
expect_success("0.0", "0 : F64");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_4point2() {
|
|
expect_success("4.2", "4.2 : F64");
|
|
}
|
|
|
|
#[test]
|
|
fn num_addition() {
|
|
expect_success("1 + 2", "3 : Num *");
|
|
}
|
|
|
|
#[test]
|
|
fn int_addition() {
|
|
expect_success("0x1 + 2", "3 : I64");
|
|
}
|
|
|
|
#[test]
|
|
fn float_addition() {
|
|
expect_success("1.1 + 2", "3.1 : F64");
|
|
}
|
|
|
|
#[test]
|
|
fn num_rem() {
|
|
expect_success("299 % 10", "Ok 9 : Result I64 [ DivByZero ]*");
|
|
}
|
|
|
|
#[test]
|
|
fn bool_in_record() {
|
|
expect_success("{ x: 1 == 1 }", "{ x: True } : { x : Bool }");
|
|
expect_success(
|
|
"{ z: { y: { x: 1 == 1 } } }",
|
|
"{ z: { y: { x: True } } } : { z : { y : { x : Bool } } }",
|
|
);
|
|
expect_success("{ x: 1 != 1 }", "{ x: False } : { x : Bool }");
|
|
expect_success(
|
|
"{ x: 1 == 1, y: 1 != 1 }",
|
|
"{ x: True, y: False } : { x : Bool, y : Bool }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bool_basic_equality() {
|
|
expect_success("1 == 1", "True : Bool");
|
|
expect_success("1 != 1", "False : Bool");
|
|
}
|
|
|
|
#[test]
|
|
fn arbitrary_tag_unions() {
|
|
expect_success("if 1 == 1 then Red else Green", "Red : [ Green, Red ]*");
|
|
expect_success("if 1 != 1 then Red else Green", "Green : [ Green, Red ]*");
|
|
}
|
|
|
|
#[test]
|
|
fn tag_without_arguments() {
|
|
expect_success("True", "True : [ True ]*");
|
|
expect_success("False", "False : [ False ]*");
|
|
}
|
|
|
|
#[test]
|
|
fn byte_tag_union() {
|
|
expect_success(
|
|
"if 1 == 1 then Red else if 1 == 1 then Green else Blue",
|
|
"Red : [ Blue, Green, Red ]*",
|
|
);
|
|
|
|
expect_success(
|
|
"{ y: { x: if 1 == 1 then Red else if 1 == 1 then Green else Blue } }",
|
|
"{ y: { x: Red } } : { y : { x : [ Blue, Green, Red ]* } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn tag_in_record() {
|
|
expect_success(
|
|
"{ x: Foo 1 2 3, y : 4 }",
|
|
"{ x: Foo 1 2 3, y: 4 } : { x : [ Foo (Num *) (Num *) (Num *) ]*, y : Num * }",
|
|
);
|
|
expect_success(
|
|
"{ x: Foo 1 2 3 }",
|
|
"{ x: Foo 1 2 3 } : { x : [ Foo (Num *) (Num *) (Num *) ]* }",
|
|
);
|
|
expect_success("{ x: Unit }", "{ x: Unit } : { x : [ Unit ]* }");
|
|
}
|
|
|
|
#[test]
|
|
fn single_element_tag_union() {
|
|
expect_success("True 1", "True 1 : [ True (Num *) ]*");
|
|
expect_success("Foo 1 3.14", "Foo 1 3.14 : [ Foo (Num *) F64 ]*");
|
|
}
|
|
|
|
#[test]
|
|
fn tag_with_arguments() {
|
|
expect_success("True 1", "True 1 : [ True (Num *) ]*");
|
|
|
|
expect_success(
|
|
"if 1 == 1 then True 3 else False 3.14",
|
|
"True 3 : [ False F64, True (Num *) ]*",
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn literal_empty_str() {
|
|
expect_success("\"\"", "\"\" : Str");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_ascii_str() {
|
|
expect_success("\"Hello, World!\"", "\"Hello, World!\" : Str");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_utf8_str() {
|
|
expect_success("\"👩👩👦👦\"", "\"👩👩👦👦\" : Str");
|
|
}
|
|
|
|
#[test]
|
|
fn str_concat() {
|
|
expect_success(
|
|
"Str.concat \"Hello, \" \"World!\"",
|
|
"\"Hello, World!\" : Str",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn str_count_graphemes() {
|
|
expect_success("Str.countGraphemes \"å🤔\"", "2 : I64");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_empty_list() {
|
|
expect_success("[]", "[] : List *");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_num_list() {
|
|
expect_success("[ 1, 2, 3 ]", "[ 1, 2, 3 ] : List (Num *)");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_int_list() {
|
|
expect_success("[ 0x1, 0x2, 0x3 ]", "[ 1, 2, 3 ] : List I64");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_float_list() {
|
|
expect_success("[ 1.1, 2.2, 3.3 ]", "[ 1.1, 2.2, 3.3 ] : List F64");
|
|
}
|
|
|
|
#[test]
|
|
fn literal_string_list() {
|
|
expect_success(r#"[ "a", "b", "cd" ]"#, r#"[ "a", "b", "cd" ] : List Str"#);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_string_list() {
|
|
expect_success(
|
|
r#"[ [ [ "a", "b", "cd" ], [ "y", "z" ] ], [ [] ], [] ]"#,
|
|
r#"[ [ [ "a", "b", "cd" ], [ "y", "z" ] ], [ [] ], [] ] : List (List (List Str))"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_num_list() {
|
|
expect_success(
|
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0 ] ], [ [] ], [] ]"#,
|
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0 ] ], [ [] ], [] ] : List (List (List (Num *)))"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_int_list() {
|
|
expect_success(
|
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0x0 ] ], [ [] ], [] ]"#,
|
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0 ] ], [ [] ], [] ] : List (List (List I64))"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_float_list() {
|
|
expect_success(
|
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0.0 ] ], [ [] ], [] ]"#,
|
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0 ] ], [ [] ], [] ] : List (List (List F64))"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_concat() {
|
|
expect_success(
|
|
"List.concat [ 1.1, 2.2 ] [ 3.3, 4.4, 5.5 ]",
|
|
"[ 1.1, 2.2, 3.3, 4.4, 5.5 ] : List F64",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_contains() {
|
|
expect_success("List.contains [] 0", "False : Bool");
|
|
expect_success("List.contains [ 1, 2, 3 ] 2", "True : Bool");
|
|
expect_success("List.contains [ 1, 2, 3 ] 4", "False : Bool");
|
|
}
|
|
|
|
#[test]
|
|
fn list_sum() {
|
|
expect_success("List.sum []", "0 : Num *");
|
|
expect_success("List.sum [ 1, 2, 3 ]", "6 : Num *");
|
|
expect_success("List.sum [ 1.1, 2.2, 3.3 ]", "6.6 : F64");
|
|
}
|
|
|
|
#[test]
|
|
fn empty_record() {
|
|
expect_success("{}", "{} : {}");
|
|
}
|
|
|
|
#[test]
|
|
fn basic_1_field_i64_record() {
|
|
// Even though this gets unwrapped at runtime, the repl should still
|
|
// report it as a record
|
|
expect_success("{ foo: 42 }", "{ foo: 42 } : { foo : Num * }");
|
|
}
|
|
|
|
#[test]
|
|
fn basic_1_field_f64_record() {
|
|
// Even though this gets unwrapped at runtime, the repl should still
|
|
// report it as a record
|
|
expect_success("{ foo: 4.2 }", "{ foo: 4.2 } : { foo : F64 }");
|
|
}
|
|
|
|
#[test]
|
|
fn nested_1_field_i64_record() {
|
|
// Even though this gets unwrapped at runtime, the repl should still
|
|
// report it as a record
|
|
expect_success(
|
|
"{ foo: { bar: { baz: 42 } } }",
|
|
"{ foo: { bar: { baz: 42 } } } : { foo : { bar : { baz : Num * } } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_1_field_f64_record() {
|
|
// Even though this gets unwrapped at runtime, the repl should still
|
|
// report it as a record
|
|
expect_success(
|
|
"{ foo: { bar: { baz: 4.2 } } }",
|
|
"{ foo: { bar: { baz: 4.2 } } } : { foo : { bar : { baz : F64 } } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn basic_2_field_i64_record() {
|
|
expect_success(
|
|
"{ foo: 0x4, bar: 0x2 }",
|
|
"{ bar: 2, foo: 4 } : { bar : I64, foo : I64 }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn basic_2_field_f64_record() {
|
|
expect_success(
|
|
"{ foo: 4.1, bar: 2.3 }",
|
|
"{ bar: 2.3, foo: 4.1 } : { bar : F64, foo : F64 }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn basic_2_field_mixed_record() {
|
|
expect_success(
|
|
"{ foo: 4.1, bar: 2 }",
|
|
"{ bar: 2, foo: 4.1 } : { bar : Num *, foo : F64 }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn basic_3_field_record() {
|
|
expect_success(
|
|
"{ foo: 4.1, bar: 2, baz: 0x5 }",
|
|
"{ bar: 2, baz: 5, foo: 4.1 } : { bar : Num *, baz : I64, foo : F64 }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn list_of_1_field_records() {
|
|
// Even though these get unwrapped at runtime, the repl should still
|
|
// report them as records
|
|
expect_success("[ { foo: 42 } ]", "[ { foo: 42 } ] : List { foo : Num * }");
|
|
}
|
|
|
|
#[test]
|
|
fn list_of_2_field_records() {
|
|
expect_success(
|
|
"[ { foo: 4.1, bar: 2 } ]",
|
|
"[ { bar: 2, foo: 4.1 } ] : List { bar : Num *, foo : F64 }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn three_element_record() {
|
|
// if this tests turns out to fail on 32-bit platforms, look at jit_to_ast_help
|
|
expect_success(
|
|
"{ a: 1, b: 2, c: 3 }",
|
|
"{ a: 1, b: 2, c: 3 } : { a : Num *, b : Num *, c : Num * }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn four_element_record() {
|
|
// if this tests turns out to fail on 32-bit platforms, look at jit_to_ast_help
|
|
expect_success(
|
|
"{ a: 1, b: 2, c: 3, d: 4 }",
|
|
"{ a: 1, b: 2, c: 3, d: 4 } : { a : Num *, b : Num *, c : Num *, d : Num * }",
|
|
);
|
|
}
|
|
|
|
// #[test]
|
|
// fn multiline_string() {
|
|
// // If a string contains newlines, format it as a multiline string in the output
|
|
// expect_success(r#""\n\nhi!\n\n""#, "\"\"\"\n\nhi!\n\n\"\"\"");
|
|
// }
|
|
|
|
#[test]
|
|
fn list_of_3_field_records() {
|
|
expect_success(
|
|
"[ { foo: 4.1, bar: 2, baz: 0x3 } ]",
|
|
"[ { bar: 2, baz: 3, foo: 4.1 } ] : List { bar : Num *, baz : I64, foo : F64 }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn type_problem() {
|
|
expect_failure(
|
|
"1 + \"\"",
|
|
indoc!(
|
|
r#"
|
|
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
|
|
|
The 2nd argument to add is not what I expect:
|
|
|
|
4│ 1 + ""
|
|
^^
|
|
|
|
This argument is a string of type:
|
|
|
|
Str
|
|
|
|
But add needs the 2nd argument to be:
|
|
|
|
Num a
|
|
"#
|
|
),
|
|
);
|
|
}
|
|
|
|
// #[test]
|
|
// fn parse_problem() {
|
|
// // can't find something that won't parse currently
|
|
// }
|
|
//
|
|
// #[test]
|
|
// fn mono_problem() {
|
|
// // can't produce a mono error (non-exhaustive pattern) yet
|
|
// }
|
|
}
|