Make gen_dev tests a single executable

This commit is contained in:
Brendan Hansknecht 2021-11-05 21:04:41 -07:00
parent c595668b37
commit 11ece557ed
13 changed files with 2807 additions and 2780 deletions

View file

@ -0,0 +1,871 @@
#![cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
use crate::assert_evals_to;
use indoc::indoc;
#[test]
fn i64_values() {
assert_evals_to!("0", 0, i64);
assert_evals_to!("-0", 0, i64);
assert_evals_to!("-1", -1, i64);
assert_evals_to!("1", 1, i64);
assert_evals_to!("9_000_000_000_000", 9_000_000_000_000, i64);
assert_evals_to!("-9_000_000_000_000", -9_000_000_000_000, i64);
assert_evals_to!("0b1010", 0b1010, i64);
assert_evals_to!("0o17", 0o17, i64);
assert_evals_to!("0x1000_0000_0000_0000", 0x1000_0000_0000_0000, i64);
}
#[test]
fn f64_values() {
assert_evals_to!("0.0", 0.0, f64);
assert_evals_to!("-0.0", 0.0, f64);
assert_evals_to!("1.0", 1.0, f64);
assert_evals_to!("-1.0", -1.0, f64);
assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64);
assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64);
assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64);
}
#[test]
fn gen_add_i64() {
assert_evals_to!(
indoc!(
r#"
1 + 2 + 3
"#
),
6,
i64
);
}
#[test]
fn gen_add_f64() {
assert_evals_to!(
indoc!(
r#"
1.1 + 2.4 + 3
"#
),
6.5,
f64
);
}
#[test]
fn gen_sub_i64() {
assert_evals_to!(
indoc!(
r#"
1 - 2 - 3
"#
),
-4,
i64
);
}
#[test]
fn gen_mul_i64() {
assert_evals_to!(
indoc!(
r#"
2 * 4 * 6
"#
),
48,
i64
);
}
#[test]
fn i64_force_stack() {
// This claims 33 registers. One more than Arm and RISC-V, and many more than x86-64.
assert_evals_to!(
indoc!(
r#"
a = 0
b = 1
c = 2
d = 3
e = 4
f = 5
g = 6
h = 7
i = 8
j = 9
k = 10
l = 11
m = 12
n = 13
o = 14
p = 15
q = 16
r = 17
s = 18
t = 19
u = 20
v = 21
w = 22
x = 23
y = 24
z = 25
aa = 26
ab = 27
ac = 28
ad = 29
ae = 30
af = 31
ag = 32
a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z + aa + ab + ac + ad + ae + af + ag
"#
),
528,
i64
);
}
#[test]
fn i64_abs() {
assert_evals_to!("Num.abs -6", 6, i64);
assert_evals_to!("Num.abs 7", 7, i64);
assert_evals_to!("Num.abs 0", 0, i64);
assert_evals_to!("Num.abs -0", 0, i64);
assert_evals_to!("Num.abs -1", 1, i64);
assert_evals_to!("Num.abs 1", 1, i64);
assert_evals_to!("Num.abs 9_000_000_000_000", 9_000_000_000_000, i64);
assert_evals_to!("Num.abs -9_000_000_000_000", 9_000_000_000_000, i64);
}
#[test]
fn gen_int_eq() {
assert_evals_to!(
indoc!(
r#"
4 == 4
"#
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
3 == 4
"#
),
false,
bool
);
}
#[test]
fn gen_basic_fn() {
assert_evals_to!(
indoc!(
r#"
always42 : Num.Num (Num.Integer Num.Signed64) -> Num.Num (Num.Integer Num.Signed64)
always42 = \_ -> 42
always42 5
"#
),
42,
i64
);
}
#[test]
fn gen_wrap_add_nums() {
assert_evals_to!(
indoc!(
r#"
add2 = \num1, num2 -> num1 + num2
add2 4 5
"#
),
9,
i64
);
}
#[test]
fn gen_wrap_add_nums_force_stack() {
assert_evals_to!(
indoc!(
r#"
add9 = \num1, num2, num3, num4, num5, num6, num7, num8, num9 -> num1 + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num9
add9 1 2 3 4 5 6 7 8 9
"#
),
45,
i64
);
}
#[test]
fn pow_int() {
assert_evals_to!("Num.powInt 2 3", 8, i64);
}
#[test]
fn acos() {
assert_evals_to!("Num.acos 0.5", 1.0471975511965979, f64);
}
#[test]
fn asin() {
assert_evals_to!("Num.asin 0.5", 0.5235987755982989, f64);
}
#[test]
fn atan() {
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
}
#[test]
fn gen_if_fn() {
assert_evals_to!(
indoc!(
r#"
limitedNegate = \num ->
x =
if num == 1 then
-1
else if num == -1 then
1
else
num
x
limitedNegate 1
"#
),
-1,
i64
);
}
#[test]
fn gen_fib_fn() {
assert_evals_to!(
indoc!(
r#"
fib = \n ->
if n == 0 then
0
else if n == 1 then
1
else
(fib (n - 1)) + (fib (n - 2))
fib 10
"#
),
55,
i64
);
}
#[test]
fn gen_fast_fib_fn() {
assert_evals_to!(
indoc!(
r#"
fib = \n, a, b ->
if n == 0 then
a
else
fib (n - 1) b (a + b)
fib 10 0 1
"#
),
55,
i64
);
}
#[test]
fn f64_abs() {
assert_evals_to!("Num.abs -4.7", 4.7, f64);
assert_evals_to!("Num.abs 5.8", 5.8, f64);
}
#[test]
fn f64_round() {
assert_evals_to!("Num.round 3.6", 4, i64);
assert_evals_to!("Num.round 3.4", 3, i64);
assert_evals_to!("Num.round 2.5", 3, i64);
assert_evals_to!("Num.round -2.3", -2, i64);
assert_evals_to!("Num.round -2.5", -3, i64);
}
// #[test]
// fn f64_sqrt() {
// // FIXME this works with normal types, but fails when checking uniqueness types
// assert_evals_to!(
// indoc!(
// r#"
// when Num.sqrt 100 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 10.0,
// f64
// );
// }
// #[test]
// fn gen_float_eq() {
// assert_evals_to!(
// indoc!(
// r#"
// 1.0 == 1.0
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn gen_div_f64() {
// // FIXME this works with normal types, but fails when checking uniqueness types
// assert_evals_to!(
// indoc!(
// r#"
// when 48 / 2 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 24.0,
// f64
// );
// }
// #[test]
// fn gen_int_neq() {
// assert_evals_to!(
// indoc!(
// r#"
// 4 != 5
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn gen_wrap_int_neq() {
// assert_evals_to!(
// indoc!(
// r#"
// wrappedNotEq : a, a -> Bool
// wrappedNotEq = \num1, num2 ->
// num1 != num2
// wrappedNotEq 2 3
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn gen_sub_f64() {
// assert_evals_to!(
// indoc!(
// r#"
// 1.5 - 2.4 - 3
// "#
// ),
// -3.9,
// f64
// );
// }
// #[test]
// fn gen_div_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when 1000 // 10 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 100,
// i64
// );
// }
// #[test]
// fn gen_div_by_zero_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when 1000 // 0 is
// Err DivByZero -> 99
// _ -> -24
// "#
// ),
// 99,
// i64
// );
// }
// #[test]
// fn gen_rem_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.rem 8 3 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 2,
// i64
// );
// }
// #[test]
// fn gen_rem_div_by_zero_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.rem 8 0 is
// Err DivByZero -> 4
// Ok _ -> -23
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn gen_is_zero_i64() {
// assert_evals_to!("Num.isZero 0", true, bool);
// assert_evals_to!("Num.isZero 1", false, bool);
// }
// #[test]
// fn gen_is_positive_i64() {
// assert_evals_to!("Num.isPositive 0", false, bool);
// assert_evals_to!("Num.isPositive 1", true, bool);
// assert_evals_to!("Num.isPositive -5", false, bool);
// }
// #[test]
// fn gen_is_negative_i64() {
// assert_evals_to!("Num.isNegative 0", false, bool);
// assert_evals_to!("Num.isNegative 3", false, bool);
// assert_evals_to!("Num.isNegative -2", true, bool);
// }
// #[test]
// fn gen_is_positive_f64() {
// assert_evals_to!("Num.isPositive 0.0", false, bool);
// assert_evals_to!("Num.isPositive 4.7", true, bool);
// assert_evals_to!("Num.isPositive -8.5", false, bool);
// }
// #[test]
// fn gen_is_negative_f64() {
// assert_evals_to!("Num.isNegative 0.0", false, bool);
// assert_evals_to!("Num.isNegative 9.9", false, bool);
// assert_evals_to!("Num.isNegative -4.4", true, bool);
// }
// #[test]
// fn gen_is_zero_f64() {
// assert_evals_to!("Num.isZero 0", true, bool);
// assert_evals_to!("Num.isZero 0_0", true, bool);
// assert_evals_to!("Num.isZero 0.0", true, bool);
// assert_evals_to!("Num.isZero 1", false, bool);
// }
// #[test]
// fn gen_is_odd() {
// assert_evals_to!("Num.isOdd 4", false, bool);
// assert_evals_to!("Num.isOdd 5", true, bool);
// }
// #[test]
// fn gen_is_even() {
// assert_evals_to!("Num.isEven 6", true, bool);
// assert_evals_to!("Num.isEven 7", false, bool);
// }
// #[test]
// fn sin() {
// assert_evals_to!("Num.sin 0", 0.0, f64);
// assert_evals_to!("Num.sin 1.41421356237", 0.9877659459922529, f64);
// }
// #[test]
// fn cos() {
// assert_evals_to!("Num.cos 0", 1.0, f64);
// assert_evals_to!("Num.cos 3.14159265359", -1.0, f64);
// }
// #[test]
// fn tan() {
// assert_evals_to!("Num.tan 0", 0.0, f64);
// assert_evals_to!("Num.tan 1", 1.557407724654902, f64);
// }
// #[test]
// fn lt_i64() {
// assert_evals_to!("1 < 2", true, bool);
// assert_evals_to!("1 < 1", false, bool);
// assert_evals_to!("2 < 1", false, bool);
// assert_evals_to!("0 < 0", false, bool);
// }
// #[test]
// fn lte_i64() {
// assert_evals_to!("1 <= 1", true, bool);
// assert_evals_to!("2 <= 1", false, bool);
// assert_evals_to!("1 <= 2", true, bool);
// assert_evals_to!("0 <= 0", true, bool);
// }
// #[test]
// fn gt_i64() {
// assert_evals_to!("2 > 1", true, bool);
// assert_evals_to!("2 > 2", false, bool);
// assert_evals_to!("1 > 1", false, bool);
// assert_evals_to!("0 > 0", false, bool);
// }
// #[test]
// fn gte_i64() {
// assert_evals_to!("1 >= 1", true, bool);
// assert_evals_to!("1 >= 2", false, bool);
// assert_evals_to!("2 >= 1", true, bool);
// assert_evals_to!("0 >= 0", true, bool);
// }
// #[test]
// fn lt_f64() {
// assert_evals_to!("1.1 < 1.2", true, bool);
// assert_evals_to!("1.1 < 1.1", false, bool);
// assert_evals_to!("1.2 < 1.1", false, bool);
// assert_evals_to!("0.0 < 0.0", false, bool);
// }
// #[test]
// fn lte_f64() {
// assert_evals_to!("1.1 <= 1.1", true, bool);
// assert_evals_to!("1.2 <= 1.1", false, bool);
// assert_evals_to!("1.1 <= 1.2", true, bool);
// assert_evals_to!("0.0 <= 0.0", true, bool);
// }
// #[test]
// fn gt_f64() {
// assert_evals_to!("2.2 > 1.1", true, bool);
// assert_evals_to!("2.2 > 2.2", false, bool);
// assert_evals_to!("1.1 > 2.2", false, bool);
// assert_evals_to!("0.0 > 0.0", false, bool);
// }
// #[test]
// fn gte_f64() {
// assert_evals_to!("1.1 >= 1.1", true, bool);
// assert_evals_to!("1.1 >= 1.2", false, bool);
// assert_evals_to!("1.2 >= 1.1", true, bool);
// assert_evals_to!("0.0 >= 0.0", true, bool);
// }
#[test]
fn gen_order_of_arithmetic_ops() {
assert_evals_to!(
indoc!(
r#"
1 + 3 * 7 - 2
"#
),
20,
i64
);
}
// #[test]
// fn gen_order_of_arithmetic_ops_complex_float() {
// assert_evals_to!(
// indoc!(
// r#"
// 3 - 48 * 2.0
// "#
// ),
// -93.0,
// f64
// );
// }
#[test]
fn if_guard_bind_variable_false() {
assert_evals_to!(
indoc!(
r#"
wrapper = \{} ->
when 10 is
x if x == 5 -> 0
_ -> 42
wrapper {}
"#
),
42,
i64
);
}
#[test]
fn if_guard_bind_variable_true() {
assert_evals_to!(
indoc!(
r#"
wrapper = \{} ->
when 10 is
x if x == 10 -> 42
_ -> 0
wrapper {}
"#
),
42,
i64
);
}
#[test]
fn tail_call_elimination() {
assert_evals_to!(
indoc!(
r#"
sum = \n, accum ->
when n is
0 -> accum
_ -> sum (n - 1) (n + accum)
sum 1_000_000 0
"#
),
500000500000,
i64
);
}
// #[test]
// fn int_negate() {
// assert_evals_to!("Num.neg 123", -123, i64);
// }
// #[test]
// fn gen_wrap_int_neg() {
// assert_evals_to!(
// indoc!(
// r#"
// wrappedNeg = \num -> -num
// wrappedNeg 3
// "#
// ),
// -3,
// i64
// );
// }
// #[test]
// fn int_to_float() {
// assert_evals_to!("Num.toFloat 0x9", 9.0, f64);
// }
// #[test]
// fn num_to_float() {
// assert_evals_to!("Num.toFloat 9", 9.0, f64);
// }
// #[test]
// fn float_to_float() {
// assert_evals_to!("Num.toFloat 0.5", 0.5, f64);
// }
// #[test]
// fn int_compare() {
// assert_evals_to!("Num.compare 0 1", RocOrder::Lt, RocOrder);
// assert_evals_to!("Num.compare 1 1", RocOrder::Eq, RocOrder);
// assert_evals_to!("Num.compare 1 0", RocOrder::Gt, RocOrder);
// }
// #[test]
// fn float_compare() {
// assert_evals_to!("Num.compare 0.01 3.14", RocOrder::Lt, RocOrder);
// assert_evals_to!("Num.compare 3.14 3.14", RocOrder::Eq, RocOrder);
// assert_evals_to!("Num.compare 3.14 0.01", RocOrder::Gt, RocOrder);
// }
// #[test]
// fn pow() {
// assert_evals_to!("Num.pow 2.0 2.0", 4.0, f64);
// }
// #[test]
// fn ceiling() {
// assert_evals_to!("Num.ceiling 1.1", 2, i64);
// }
// #[test]
// fn floor() {
// assert_evals_to!("Num.floor 1.9", 1, i64);
// }
// // #[test]
// // #[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
// // fn int_overflow() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // 9_223_372_036_854_775_807 + 1
// // "#
// // ),
// // 0,
// // i64
// // );
// // }
// #[test]
// fn int_add_checked() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 1 2 is
// Ok v -> v
// _ -> -1
// "#
// ),
// 3,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 9_223_372_036_854_775_807 1 is
// Err Overflow -> -1
// Ok v -> v
// "#
// ),
// -1,
// i64
// );
// }
// #[test]
// fn int_add_wrap() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.addWrap 9_223_372_036_854_775_807 1
// "#
// ),
// std::i64::MIN,
// i64
// );
// }
// #[test]
// fn float_add_checked_pass() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 1.0 0.0 is
// Ok v -> v
// Err Overflow -> -1.0
// "#
// ),
// 1.0,
// f64
// );
// }
// #[test]
// fn float_add_checked_fail() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 1.7976931348623157e308 1.7976931348623157e308 is
// Err Overflow -> -1
// Ok v -> v
// "#
// ),
// -1.0,
// f64
// );
// }
// // #[test]
// // #[should_panic(expected = r#"Roc failed with message: "float addition overflowed!"#)]
// // fn float_overflow() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // 1.7976931348623157e308 + 1.7976931348623157e308
// // "#
// // ),
// // 0.0,
// // f64
// // );
// // }
// #[test]
// fn max_i128() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.maxI128
// "#
// ),
// i128::MAX,
// i128
// );
// }
// #[test]
// fn num_max_int() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.maxInt
// "#
// ),
// i64::MAX,
// i64
// );
// }
// #[test]
// fn num_min_int() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.minInt
// "#
// ),
// i64::MIN,
// i64
// );
// }

View file

@ -0,0 +1,933 @@
#![cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
use crate::assert_evals_to;
use indoc::indoc;
#[test]
fn basic_record() {
assert_evals_to!(
indoc!(
r#"
{ y: 17, x: 15, z: 19 }.x
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: 17, z: 19 }.y
"#
),
17,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: 17, z: 19 }.z
"#
),
19,
i64
);
}
#[test]
fn nested_record() {
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a
"#
),
12,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c
"#
),
2,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z
"#
),
19,
i64
);
}
#[test]
fn f64_record() {
assert_evals_to!(
indoc!(
r#"
rec = { y: 17.2, x: 15.1, z: 19.3 }
rec.x
"#
),
15.1,
f64
);
assert_evals_to!(
indoc!(
r#"
rec = { y: 17.2, x: 15.1, z: 19.3 }
rec.y
"#
),
17.2,
f64
);
assert_evals_to!(
indoc!(
r#"
rec = { y: 17.2, x: 15.1, z: 19.3 }
rec.z
"#
),
19.3,
f64
);
}
// #[test]
// fn fn_record() {
// assert_evals_to!(
// indoc!(
// r#"
// getRec = \x -> { y: 17, x, z: 19 }
// (getRec 15).x
// "#
// ),
// 15,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.y
// "#
// ),
// 17,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.z
// "#
// ),
// 19,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.z + rec.x
// "#
// ),
// 34,
// i64
// );
// }
#[test]
fn def_record() {
assert_evals_to!(
indoc!(
r#"
rec = { y: 17, x: 15, z: 19 }
rec.x
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
rec = { x: 15, y: 17, z: 19 }
rec.y
"#
),
17,
i64
);
assert_evals_to!(
indoc!(
r#"
rec = { x: 15, y: 17, z: 19 }
rec.z
"#
),
19,
i64
);
}
#[test]
fn when_on_record() {
assert_evals_to!(
indoc!(
r#"
when { x: 0x2 } is
{ x } -> x + 3
"#
),
5,
i64
);
}
#[test]
fn when_record_with_guard_pattern() {
assert_evals_to!(
indoc!(
r#"
when { x: 0x2, y: 3.14 } is
{ x: var } -> var + 3
"#
),
5,
i64
);
}
#[test]
fn let_with_record_pattern() {
assert_evals_to!(
indoc!(
r#"
{ x } = { x: 0x2, y: 3.14 }
x
"#
),
2,
i64
);
}
#[test]
fn record_guard_pattern() {
assert_evals_to!(
indoc!(
r#"
when { x: 0x2, y: 3.14 } is
{ x: 0x4 } -> 5
{ x } -> x + 3
"#
),
5,
i64
);
}
#[test]
fn twice_record_access() {
assert_evals_to!(
indoc!(
r#"
x = {a: 0x2, b: 0x3 }
x.a + x.b
"#
),
5,
i64
);
}
#[test]
fn empty_record() {
assert_evals_to!(
indoc!(
r#"
v = {}
v
"#
),
(),
()
);
}
#[test]
fn i64_record1_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3 }
"#
),
3,
i64
);
}
// #[test]
// fn i64_record2_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3, y: 5 }
// "#
// ),
// (3, 5),
// (i64, i64)
// );
// }
// // #[test]
// // fn i64_record3_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { x: 3, y: 5, z: 17 }
// // "#
// // ),
// // (3, 5, 17),
// // (i64, i64, i64)
// // );
// // }
// #[test]
// fn f64_record2_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3.1, y: 5.1 }
// "#
// ),
// (3.1, 5.1),
// (f64, f64)
// );
// }
// // #[test]
// // fn f64_record3_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { x: 3.1, y: 5.1, z: 17.1 }
// // "#
// // ),
// // (3.1, 5.1, 17.1),
// // (f64, f64, f64)
// // );
// // }
// // #[test]
// // fn bool_record4_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // record : { a : Bool, b : Bool, c : Bool, d : Bool }
// // record = { a: True, b: True, c : True, d : Bool }
// // record
// // "#
// // ),
// // (true, false, false, true),
// // (bool, bool, bool, bool)
// // );
// // }
// #[test]
// fn i64_record1_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3 }
// "#
// ),
// 3,
// i64
// );
// }
// // #[test]
// // fn i64_record9_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 }
// // "#
// // ),
// // (3, 5, 17, 1, 9, 12, 13, 14, 15),
// // (i64, i64, i64, i64, i64, i64, i64, i64, i64)
// // );
// // }
// // #[test]
// // fn f64_record3_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { x: 3.1, y: 5.1, z: 17.1 }
// // "#
// // ),
// // (3.1, 5.1, 17.1),
// // (f64, f64, f64)
// // );
// // }
// #[test]
// fn bool_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// x : Bool
// x = True
// x
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn optional_field_when_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// main =
// a = f { x: Blue, y: 7 }
// b = f { x: Blue }
// c = f { x: Red, y: 11 }
// d = f { x: Red }
// a * b * c * d
// "#
// ),
// 3 * 5 * 7 * 11,
// i64
// );
// }
// #[test]
// fn optional_field_when_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// a = f { x: Blue, y: 7 }
// b = f { x: Blue }
// c = f { x: Red, y: 11 }
// d = f { x: Red }
// a * b * c * d
// "#
// ),
// 3 * 5 * 7 * 11,
// i64
// );
// }
// #[test]
// fn optional_field_when_no_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_when_no_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// { x ? 10, y } = r
// x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_let_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { y: 9 }
// "#
// ),
// 19,
// i64
// );
// }
// #[test]
// fn optional_field_let_no_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_let_no_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// { x ? 10, y } = r
// x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_function_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \{ x ? 10, y } -> x + y
// f { y: 9 }
// "#
// ),
// 19,
// i64
// );
// }
// #[test]
// #[ignore]
// fn optional_field_function_no_use_default() {
// // blocked on https://github.com/rtfeldman/roc/issues/786
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \{ x ? 10, y } -> x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// #[ignore]
// fn optional_field_function_no_use_default_nested() {
// // blocked on https://github.com/rtfeldman/roc/issues/786
// assert_evals_to!(
// indoc!(
// r#"
// f = \{ x ? 10, y } -> x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_singleton_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { x : 4 } is
// { x ? 3 } -> x
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn optional_field_empty_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { } is
// { x ? 3 } -> x
// "#
// ),
// 3,
// i64
// );
// }
// #[test]
// fn return_record_2() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3, y: 5 }
// "#
// ),
// [3, 5],
// [i64; 2]
// );
// }
// #[test]
// fn return_record_3() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3, y: 5, z: 4 }
// "#
// ),
// (3, 5, 4),
// (i64, i64, i64)
// );
// }
// #[test]
// fn return_record_4() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2 }
// "#
// ),
// [3, 5, 4, 2],
// [i64; 4]
// );
// }
// #[test]
// fn return_record_5() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2, e: 1 }
// "#
// ),
// [3, 5, 4, 2, 1],
// [i64; 5]
// );
// }
// #[test]
// fn return_record_6() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 }
// "#
// ),
// [3, 5, 4, 2, 1, 7],
// [i64; 6]
// );
// }
// #[test]
// fn return_record_7() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 }
// "#
// ),
// [3, 5, 4, 2, 1, 7, 8],
// [i64; 7]
// );
// }
// #[test]
// fn return_record_float_int() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3.14, b: 0x1 }
// "#
// ),
// (3.14, 0x1),
// (f64, i64)
// );
// }
// #[test]
// fn return_record_int_float() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 0x1, b: 3.14 }
// "#
// ),
// (0x1, 3.14),
// (i64, f64)
// );
// }
// #[test]
// fn return_record_float_float() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 6.28, b: 3.14 }
// "#
// ),
// (6.28, 3.14),
// (f64, f64)
// );
// }
// #[test]
// fn return_record_float_float_float() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 6.28, b: 3.14, c: 0.1 }
// "#
// ),
// (6.28, 3.14, 0.1),
// (f64, f64, f64)
// );
// }
// #[test]
// fn return_nested_record() {
// assert_evals_to!(
// indoc!(
// r#"
// { flag: 0x0, payload: { a: 6.28, b: 3.14, c: 0.1 } }
// "#
// ),
// (0x0, (6.28, 3.14, 0.1)),
// (i64, (f64, f64, f64))
// );
// }
// #[test]
// fn accessor() {
// assert_evals_to!(
// indoc!(
// r#"
// .foo { foo: 4 } + .foo { bar: 6.28, foo: 3 }
// "#
// ),
// 7,
// i64
// );
// }
// #[test]
// fn accessor_single_element_record() {
// assert_evals_to!(
// indoc!(
// r#"
// .foo { foo: 4 }
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn update_record() {
// assert_evals_to!(
// indoc!(
// r#"
// rec = { foo: 42, bar: 6 }
// { rec & foo: rec.foo + 1 }
// "#
// ),
// (6, 43),
// (i64, i64)
// );
// }
#[test]
fn update_single_element_record() {
assert_evals_to!(
indoc!(
r#"
rec = { foo: 42}
{ rec & foo: rec.foo + 1 }
"#
),
43,
i64
);
}
// #[test]
// fn booleans_in_record() {
// assert_evals_to!(
// indoc!("{ x: 1 == 1, y: 1 == 1 }"),
// (true, true),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 != 1, y: 1 == 1 }"),
// (false, true),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 == 1, y: 1 != 1 }"),
// (true, false),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 != 1, y: 1 != 1 }"),
// (false, false),
// (bool, bool)
// );
// }
// #[test]
// fn alignment_in_record() {
// assert_evals_to!(
// indoc!("{ c: 32, b: if True then Red else if True then Green else Blue, a: 1 == 1 }"),
// (32i64, true, 2u8),
// (i64, bool, u8)
// );
// }
// #[test]
// fn blue_and_present() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// f { x: Blue, y: 7 }
// "#
// ),
// 7,
// i64
// );
// }
// #[test]
// fn blue_and_absent() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// f { x: Blue }
// "#
// ),
// 3,
// i64
// );
// }

View file

@ -0,0 +1,950 @@
#![cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
//use indoc::indoc;
use crate::assert_evals_to;
// use roc_std::{RocList, RocStr};
// #[test]
// fn str_split_bigger_delimiter_small_str() {
// assert_evals_to!(
// indoc!(
// r#"
// List.len (Str.split "hello" "JJJJ there")
// "#
// ),
// 1,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// when List.first (Str.split "JJJ" "JJJJ there") is
// Ok str ->
// Str.countGraphemes str
// _ ->
// -1
// "#
// ),
// 3,
// i64
// );
// }
// #[test]
// fn str_split_str_concat_repeated() {
// assert_evals_to!(
// indoc!(
// r#"
// when List.first (Str.split "JJJJJ" "JJJJ there") is
// Ok str ->
// str
// |> Str.concat str
// |> Str.concat str
// |> Str.concat str
// |> Str.concat str
// _ ->
// "Not Str!"
// "#
// ),
// RocStr::from_slice(b"JJJJJJJJJJJJJJJJJJJJJJJJJ"),
// RocStr
// );
// }
// #[test]
// fn str_split_small_str_bigger_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// when
// List.first
// (Str.split "JJJ" "0123456789abcdefghi")
// is
// Ok str -> str
// _ -> ""
// "#
// ),
// RocStr::from_slice(b"JJJ"),
// RocStr
// );
// }
// #[test]
// fn str_split_big_str_small_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "01234567789abcdefghi?01234567789abcdefghi" "?"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"01234567789abcdefghi"),
// RocStr::from_slice(b"01234567789abcdefghi")
// ]),
// RocList<RocStr>
// );
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "01234567789abcdefghi 3ch 01234567789abcdefghi" "3ch"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"01234567789abcdefghi "),
// RocStr::from_slice(b" 01234567789abcdefghi")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_small_str_small_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "J!J!J" "!"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"J"),
// RocStr::from_slice(b"J"),
// RocStr::from_slice(b"J")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_bigger_delimiter_big_strs() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "string to split is shorter"
// "than the delimiter which happens to be very very long"
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"string to split is shorter")]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_empty_strs() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "" ""
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"")]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_minimal_example() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "a," ","
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"a"), RocStr::from_slice(b"")]),
// RocList<RocStr>
// )
// }
// #[test]
// fn str_split_small_str_big_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
// "---- ---- ---- ---- ----"
// |> List.len
// "#
// ),
// 3,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
// "---- ---- ---- ---- ----"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"1"),
// RocStr::from_slice(b"2"),
// RocStr::from_slice(b"")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_small_str_20_char_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "3|-- -- -- -- -- -- |4|-- -- -- -- -- -- |"
// "|-- -- -- -- -- -- |"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"3"),
// RocStr::from_slice(b"4"),
// RocStr::from_slice(b"")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_concat_big_to_big() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.concat
// "First string that is fairly long. Longer strings make for different errors. "
// "Second string that is also fairly long. Two long strings test things that might not appear with short strings."
// "#
// ),
// RocStr::from_slice(b"First string that is fairly long. Longer strings make for different errors. Second string that is also fairly long. Two long strings test things that might not appear with short strings."),
// RocStr
// );
// }
#[test]
fn small_str_literal() {
assert_evals_to!(
"\"JJJJJJJJJJJJJJJ\"",
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_zeroed_literal() {
// // Verifies that we zero out unused bytes in the string.
// // This is important so that string equality tests don't randomly
// // fail due to unused memory being there!
// assert_evals_to!(
// "\"J\"",
// [
// 0x4a,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0b1000_0001
// ],
// [u8; 16]
// );
// }
#[test]
fn small_str_concat_empty_first_arg() {
assert_evals_to!(
r#"Str.concat "" "JJJJJJJJJJJJJJJ""#,
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
#[test]
fn small_str_concat_empty_second_arg() {
assert_evals_to!(
r#"Str.concat "JJJJJJJJJJJJJJJ" """#,
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_concat_small_to_big() {
// assert_evals_to!(
// r#"Str.concat "abc" " this is longer than 15 chars""#,
// RocStr::from_slice(b"abc this is longer than 15 chars"),
// RocStr
// );
// }
#[test]
fn small_str_concat_small_to_small_staying_small() {
assert_evals_to!(
r#"Str.concat "J" "JJJJJJJJJJJJJJ""#,
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_concat_small_to_small_overflow_to_big() {
// assert_evals_to!(
// r#"Str.concat "abcdefghijklm" "nopqrstuvwxyz""#,
// RocStr::from_slice(b"abcdefghijklmnopqrstuvwxyz"),
// RocStr
// );
// }
// #[test]
// fn str_concat_empty() {
// assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr);
// }
// #[test]
// fn small_str_is_empty() {
// assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool);
// }
// #[test]
// fn big_str_is_empty() {
// assert_evals_to!(
// r#"Str.isEmpty "this is more than 15 chars long""#,
// false,
// bool
// );
// }
// #[test]
// fn empty_str_is_empty() {
// assert_evals_to!(r#"Str.isEmpty """#, true, bool);
// }
// #[test]
// fn str_starts_with() {
// assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool);
// assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool);
// assert_evals_to!(r#"Str.startsWith "nope" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.startsWith "hell" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.startsWith "" "hello world""#, false, bool);
// }
// #[test]
// fn str_starts_with_code_point() {
// assert_evals_to!(
// &format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
// true,
// bool
// );
// assert_evals_to!(
// &format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32),
// false,
// bool
// );
// }
// #[test]
// fn str_ends_with() {
// assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool);
// assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.endsWith "" "hello world""#, false, bool);
// }
// #[test]
// fn str_count_graphemes_small_str() {
// assert_evals_to!(r#"Str.countGraphemes "å🤔""#, 2, usize);
// }
// #[test]
// fn str_count_graphemes_three_js() {
// assert_evals_to!(r#"Str.countGraphemes "JJJ""#, 3, usize);
// }
// #[test]
// fn str_count_graphemes_big_str() {
// assert_evals_to!(
// r#"Str.countGraphemes "6🤔å🤔e¥🤔çppkd🙃1jdal🦯asdfa∆ltråø˚waia8918.,🏅jjc""#,
// 45,
// usize
// );
// }
// #[test]
// fn str_starts_with_same_big_str() {
// assert_evals_to!(
// r#"Str.startsWith "123456789123456789" "123456789123456789""#,
// true,
// bool
// );
// }
// #[test]
// fn str_starts_with_different_big_str() {
// assert_evals_to!(
// r#"Str.startsWith "12345678912345678910" "123456789123456789""#,
// true,
// bool
// );
// }
// #[test]
// fn str_starts_with_same_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool);
// }
// #[test]
// fn str_starts_with_different_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool);
// }
// #[test]
// fn str_starts_with_false_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
// }
// #[test]
// fn str_from_int() {
// assert_evals_to!(
// r#"Str.fromInt 1234"#,
// roc_std::RocStr::from_slice("1234".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt 0"#,
// roc_std::RocStr::from_slice("0".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt -1"#,
// roc_std::RocStr::from_slice("-1".as_bytes()),
// roc_std::RocStr
// );
// let max = format!("{}", i64::MAX);
// assert_evals_to!(
// r#"Str.fromInt Num.maxInt"#,
// RocStr::from_slice(max.as_bytes()),
// RocStr
// );
// let min = format!("{}", i64::MIN);
// assert_evals_to!(
// r#"Str.fromInt Num.minInt"#,
// RocStr::from_slice(min.as_bytes()),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_ascii() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_ascii() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0x7E ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("abc~".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_unicode() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("∆".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_unicode() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86, 0xC5, 0x93, 0xC2, 0xAC ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("∆œ¬".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_grapheme() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_grapheme() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 0xF0, 0x9F, 0xA4, 0xA0, 0xF0, 0x9F, 0x9A, 0x80 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖🤠🚀".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_all() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 98, 0xE2, 0x88, 0x86 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖b∆".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_invalid_start_byte() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 0x80, 99 ] is
// Err (BadUtf8 InvalidStartByte byteIndex) ->
// if byteIndex == 2 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_unexpected_end_of_sequence() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0xC2 ] is
// Err (BadUtf8 UnexpectedEndOfSequence byteIndex) ->
// if byteIndex == 3 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_expected_continuation() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0xC2, 0x00 ] is
// Err (BadUtf8 ExpectedContinuation byteIndex) ->
// if byteIndex == 3 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_overlong_encoding() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 0xF0, 0x80, 0x80, 0x80 ] is
// Err (BadUtf8 OverlongEncoding byteIndex) ->
// if byteIndex == 1 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_codepoint_too_large() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 0xF4, 0x90, 0x80, 0x80 ] is
// Err (BadUtf8 CodepointTooLarge byteIndex) ->
// if byteIndex == 1 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_surrogate_half() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 0xED, 0xA0, 0x80 ] is
// Err (BadUtf8 EncodesSurrogateHalf byteIndex) ->
// if byteIndex == 2 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_equality() {
// assert_evals_to!(r#""a" == "a""#, true, bool);
// assert_evals_to!(
// r#""loremipsumdolarsitamet" == "loremipsumdolarsitamet""#,
// true,
// bool
// );
// assert_evals_to!(r#""a" != "b""#, true, bool);
// assert_evals_to!(r#""a" == "b""#, false, bool);
// }
// #[test]
// fn str_clone() {
// use roc_std::RocStr;
// let long = RocStr::from_slice("loremipsumdolarsitamet".as_bytes());
// let short = RocStr::from_slice("x".as_bytes());
// let empty = RocStr::from_slice("".as_bytes());
// debug_assert_eq!(long.clone(), long);
// debug_assert_eq!(short.clone(), short);
// debug_assert_eq!(empty.clone(), empty);
// }
// #[test]
// fn nested_recursive_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// Expr : [ Add Expr Expr, Val I64, Var I64 ]
// expr : Expr
// expr = Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))
// printExpr : Expr -> Str
// printExpr = \e ->
// when e is
// Add a b ->
// "Add ("
// |> Str.concat (printExpr a)
// |> Str.concat ") ("
// |> Str.concat (printExpr b)
// |> Str.concat ")"
// Val v -> "Val " |> Str.concat (Str.fromInt v)
// Var v -> "Var " |> Str.concat (Str.fromInt v)
// printExpr expr
// "#
// ),
// RocStr::from_slice(b"Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_small() {
// assert_evals_to!(
// r#"Str.joinWith ["1", "2"] ", " "#,
// RocStr::from("1, 2"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_big() {
// assert_evals_to!(
// r#"Str.joinWith ["10000000", "2000000", "30000000"] ", " "#,
// RocStr::from("10000000, 2000000, 30000000"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_single() {
// assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
// }
// #[test]
// fn str_from_float() {
// assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
// }
// #[test]
// fn str_to_utf8() {
// assert_evals_to!(
// r#"Str.toUtf8 "hello""#,
// RocList::from_slice(&[104, 101, 108, 108, 111]),
// RocList<u8>
// );
// assert_evals_to!(
// r#"Str.toUtf8 "this is a long string""#,
// RocList::from_slice(&[
// 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 108, 111, 110, 103, 32, 115, 116,
// 114, 105, 110, 103
// ]),
// RocList<u8>
// );
// }
// #[test]
// fn str_from_utf8_range() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 5, start: 0 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("hello"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_slice() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 4, start: 1 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ello"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_slice_not_end() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 3, start: 1 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ell"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_order_does_not_matter() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 1, count: 3 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ell"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_out_of_bounds_start_value() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 7, count: 3 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_count_too_high() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 0, count: 6 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_count_too_high_for_start() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 4, count: 3 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }

View file

@ -0,0 +1,249 @@
use libloading::Library;
use roc_build::link::{link, LinkType};
use roc_builtins::bitcode;
use roc_can::builtins::builtin_defs_map;
use roc_collections::all::MutMap;
use tempfile::tempdir;
#[allow(dead_code)]
fn promote_expr_to_module(src: &str) -> String {
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
for line in src.lines() {
// indent the body!
buffer.push_str(" ");
buffer.push_str(line);
buffer.push('\n');
}
buffer
}
#[allow(dead_code)]
pub fn helper<'a>(
arena: &'a bumpalo::Bump,
src: &str,
stdlib: roc_builtins::std::StdLib,
_leak: bool,
lazy_literals: bool,
) -> (String, Vec<roc_problem::can::Problem>, Library) {
use std::path::{Path, PathBuf};
let dir = tempdir().unwrap();
let filename = PathBuf::from("Test.roc");
let src_dir = Path::new("fake/test/path");
let app_o_file = dir.path().join("app.o");
let module_src;
let temp;
if src.starts_with("app") {
// this is already a module
module_src = src;
} else {
// this is an expression, promote it to a module
temp = promote_expr_to_module(src);
module_src = &temp;
}
let exposed_types = MutMap::default();
let loaded = roc_load::file::load_and_monomorphize_from_str(
arena,
filename,
module_src,
&stdlib,
src_dir,
exposed_types,
8,
builtin_defs_map,
);
let mut loaded = loaded.expect("failed to load module");
use roc_load::file::MonomorphizedModule;
let MonomorphizedModule {
procedures: top_procedures,
interns,
exposed_to_host,
..
} = loaded;
let mut procedures = MutMap::default();
for (key, proc) in top_procedures {
procedures.insert(key, proc);
}
// You can comment and uncomment this block out to get more useful information
// while you're working on the dev backend!
{
// println!("=========== Procedures ==========");
// println!("{:?}", procedures);
// println!("=================================\n");
// println!("=========== Interns ==========");
// println!("{:?}", interns);
// println!("=================================\n");
// println!("=========== Exposed ==========");
// println!("{:?}", exposed_to_host);
// println!("=================================\n");
}
debug_assert_eq!(exposed_to_host.len(), 1);
let main_fn_symbol = loaded.entry_point.symbol;
let main_fn_layout = loaded.entry_point.layout;
let mut layout_ids = roc_mono::layout::LayoutIds::default();
let main_fn_name_base = layout_ids
.get_toplevel(main_fn_symbol, &main_fn_layout)
.to_symbol_string(main_fn_symbol, &interns);
let main_fn_name = format!("roc_{}_exposed", main_fn_name_base);
let mut lines = Vec::new();
// errors whose reporting we delay (so we can see that code gen generates runtime errors)
let mut delayed_errors = Vec::new();
for (home, (module_path, src)) in loaded.sources {
use roc_reporting::report::{
can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE,
};
let can_problems = loaded.can_problems.remove(&home).unwrap_or_default();
let type_problems = loaded.type_problems.remove(&home).unwrap_or_default();
let mono_problems = loaded.mono_problems.remove(&home).unwrap_or_default();
let error_count = can_problems.len() + type_problems.len() + mono_problems.len();
if error_count == 0 {
continue;
}
let src_lines: Vec<&str> = src.split('\n').collect();
let palette = DEFAULT_PALETTE;
// Report parsing and canonicalization problems
let alloc = RocDocAllocator::new(&src_lines, home, &interns);
use roc_problem::can::Problem::*;
for problem in can_problems.into_iter() {
// Ignore "unused" problems
match problem {
UnusedDef(_, _) | UnusedArgument(_, _, _) | UnusedImport(_, _) => {
delayed_errors.push(problem);
continue;
}
_ => {
let report = can_problem(&alloc, module_path.clone(), problem);
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
lines.push(buf);
}
}
}
for problem in type_problems {
if let Some(report) = type_problem(&alloc, module_path.clone(), problem) {
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
lines.push(buf);
}
}
for problem in mono_problems {
let report = mono_problem(&alloc, module_path.clone(), problem);
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
lines.push(buf);
}
}
if !lines.is_empty() {
println!("{}", lines.join("\n"));
assert_eq!(0, 1, "Mistakes were made");
}
let env = roc_gen_dev::Env {
arena,
interns,
exposed_to_host: exposed_to_host.keys().copied().collect(),
lazy_literals,
generate_allocators: true, // Needed for testing, since we don't have a platform
};
let target = target_lexicon::Triple::host();
let module_object =
roc_gen_dev::build_module(&env, &target, procedures).expect("failed to compile module");
let module_out = module_object
.write()
.expect("failed to build output object");
std::fs::write(&app_o_file, module_out).expect("failed to write object to file");
// std::fs::copy(&app_o_file, "/tmp/app.o").unwrap();
let (mut child, dylib_path) = link(
&target,
app_o_file.clone(),
// Long term we probably want a smarter way to link in zig builtins.
// With the current method all methods are kept and it adds about 100k to all outputs.
&[app_o_file.to_str().unwrap(), bitcode::OBJ_PATH],
LinkType::Dylib,
)
.expect("failed to link dynamic library");
child.wait().unwrap();
// Load the dylib
let path = dylib_path.as_path().to_str().unwrap();
// std::fs::copy(&path, "/tmp/libapp.so").unwrap();
let lib = unsafe { Library::new(path) }.expect("failed to load shared library");
(main_fn_name, delayed_errors, lib)
}
#[macro_export]
macro_rules! assert_evals_to {
($src:expr, $expected:expr, $ty:ty) => {{
assert_evals_to!($src, $expected, $ty, (|val| val));
}};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
// Same as above, except with an additional transformation argument.
{
assert_evals_to!($src, $expected, $ty, $transform, true);
}
};
($src:expr, $expected:expr, $ty:ty, $transform:expr, $leak:expr) => {
// Run both with and without lazy literal optimization.
{
assert_evals_to!($src, $expected, $ty, $transform, $leak, false);
}
{
assert_evals_to!($src, $expected, $ty, $transform, $leak, true);
}
};
($src:expr, $expected:expr, $ty:ty, $transform:expr, $leak:expr, $lazy_literals:expr) => {
use bumpalo::Bump;
use roc_gen_dev::run_jit_function_raw;
let stdlib = roc_builtins::std::standard_stdlib();
let arena = Bump::new();
let (main_fn_name, errors, lib) =
$crate::helpers::eval::helper(&arena, $src, stdlib, $leak, $lazy_literals);
let transform = |success| {
let expected = $expected;
let given = $transform(success);
assert_eq!(&given, &expected);
};
run_jit_function_raw!(lib, main_fn_name, $ty, transform, errors)
};
}

View file

@ -0,0 +1,44 @@
extern crate bumpalo;
#[macro_use]
pub mod eval;
/// Used in the with_larger_debug_stack() function, for tests that otherwise
/// run out of stack space in debug builds (but don't in --release builds)
#[allow(dead_code)]
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
/// Without this, some tests pass in `cargo test --release` but fail without
/// the --release flag because they run out of stack space. This increases
/// stack size for debug builds only, while leaving the stack space at the default
/// amount for release builds.
#[allow(dead_code)]
#[cfg(debug_assertions)]
pub fn with_larger_debug_stack<F>(run_test: F)
where
F: FnOnce(),
F: Send,
F: 'static,
{
std::thread::Builder::new()
.stack_size(EXPANDED_STACK_SIZE)
.spawn(run_test)
.expect("Error while spawning expanded dev stack size thread")
.join()
.expect("Error while joining expanded dev stack size thread")
}
/// In --release builds, don't increase the stack size. Run the test normally.
/// This way, we find out if any of our tests are blowing the stack even after
/// optimizations in release builds.
#[allow(dead_code)]
#[cfg(not(debug_assertions))]
#[inline(always)]
pub fn with_larger_debug_stack<F>(run_test: F)
where
F: FnOnce() -> (),
F: Send,
F: 'static,
{
run_test()
}

View file

@ -0,0 +1,4 @@
mod helpers;
pub mod dev_num;
pub mod dev_records;
pub mod dev_str;