roc/compiler/fmt/tests/test_fmt.rs
2021-11-27 06:15:48 -08:00

2774 lines
52 KiB
Rust

#[macro_use]
extern crate pretty_assertions;
#[macro_use]
extern crate indoc;
extern crate bumpalo;
extern crate roc_fmt;
#[cfg(test)]
mod test_fmt {
use bumpalo::collections::String;
use bumpalo::Bump;
use roc_fmt::annotation::{Formattable, Newlines, Parens};
use roc_fmt::def::fmt_def;
use roc_fmt::module::fmt_module;
use roc_parse::module::{self, module_defs};
use roc_parse::parser::{Parser, State};
fn expr_formats_to(input: &str, expected: &str) {
let arena = Bump::new();
let input = input.trim_end();
let expected = expected.trim_end();
match roc_parse::test_helpers::parse_expr_with(&arena, input.trim()) {
Ok(actual) => {
let mut buf = String::new_in(&arena);
actual.format_with_options(&mut buf, Parens::NotNeeded, Newlines::Yes, 0);
assert_eq!(buf, expected)
}
Err(error) => panic!("Unexpected parse failure when parsing this for formatting:\n\n{}\n\nParse error was:\n\n{:?}\n\n", input, error)
};
}
fn expr_formats_same(input: &str) {
expr_formats_to(input, input);
}
fn module_formats_to(src: &str, expected: &str) {
let arena = Bump::new();
let src = src.trim_end();
let expected = expected.trim_end();
match module::parse_header(&arena, State::new(src.as_bytes())) {
Ok((actual, state)) => {
let mut buf = String::new_in(&arena);
fmt_module(&mut buf, &actual);
match module_defs().parse(&arena, state) {
Ok((_, loc_defs, _)) => {
for loc_def in loc_defs {
fmt_def(&mut buf, arena.alloc(loc_def.value), 0);
}
}
Err(error) => panic!("Unexpected parse failure when parsing this for defs formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, error)
}
assert_eq!(buf, expected)
}
Err(error) => panic!("Unexpected parse failure when parsing this for module header formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, error)
};
}
fn module_formats_same(input: &str) {
module_formats_to(input, input);
}
// STRING LITERALS
#[test]
fn empty_string() {
expr_formats_same(indoc!(
r#"
""
"#
));
}
#[test]
fn def_with_comment() {
expr_formats_same(indoc!(
r#"
# This variable is for greeting
a = "Hello"
a
"#
));
}
#[test]
fn def_with_comment_and_extra_space() {
expr_formats_to(
indoc!(
r#"
# This variable is for greeting
a = "Hello"
a
"#
),
indoc!(
r#"
# This variable is for greeting
a = "Hello"
a
"#
),
);
}
#[test]
fn force_space_at_beginning_of_comment() {
expr_formats_to(
indoc!(
r#"
#comment
f
"#
),
indoc!(
r#"
# comment
f
"#
),
);
}
#[test]
fn func_def() {
expr_formats_same(indoc!(
r#"
f = \x, y ->
x
f 4
"#
));
}
#[test]
fn new_line_above_return() {
expr_formats_to(
indoc!(
r#"
f = \x, y ->
y = 4
z = 8
x
"string"
"#
),
indoc!(
r#"
f = \x, y ->
y = 4
z = 8
x
"string"
"#
),
);
expr_formats_same(indoc!(
r#"
f = \x, y ->
a = 3
b = 6
c
"string"
"#
));
}
#[test]
fn basic_string() {
expr_formats_same(indoc!(
r#"
"blah"
"#
));
}
#[test]
fn escaped_unicode_string() {
expr_formats_same(indoc!(
r#"
"unicode: \u(A00A)!"
"#
));
}
#[test]
fn escaped_quote_string() {
expr_formats_same(indoc!(
r#"
"\""
"#
));
}
// #[test]
// fn empty_block_string() {
// expr_formats_same(indoc!(
// r#"
// """"""
// "#
// ));
// }
// #[test]
// fn basic_block_string() {
// expr_formats_same(indoc!(
// r#"
// """blah"""
// "#
// ));
// }
// #[test]
// fn newlines_block_string() {
// expr_formats_same(indoc!(
// r#"
// """blah
// spam
// foo"""
// "#
// ));
// }
// #[test]
// fn quotes_block_string() {
// expr_formats_same(indoc!(
// r#"
// """
// "" \""" ""\"
// """
// "#
// ));
// }
#[test]
fn zero() {
expr_formats_same(indoc!(
r#"
0
"#
));
}
#[test]
fn zero_point_zero() {
expr_formats_same(indoc!(
r#"
0.0
"#
));
}
#[test]
fn int_with_underscores() {
expr_formats_same(indoc!(
r#"
1_23_456
"#
));
}
#[test]
fn float_with_underscores() {
expr_formats_same(indoc!(
r#"
1_23_456.7_89_10
"#
));
}
#[test]
fn multi_arg_closure() {
expr_formats_same(indoc!(
r#"
\a, b, c -> a b c
"#
));
}
#[test]
fn destructure_tag_closure() {
expr_formats_same(indoc!(
r#"
\Foo a -> Foo a
"#
));
}
#[test]
fn destructure_nested_tag_closure() {
expr_formats_same(indoc!(
r#"
\Foo (Bar a) -> Foo (Bar a)
"#
));
}
// DEFS
#[test]
fn single_def() {
expr_formats_same(indoc!(
r#"
x = 5
42
"#
));
}
#[test]
fn two_defs() {
expr_formats_same(indoc!(
r#"
x = 5
y = 10
42
"#
));
expr_formats_to(
indoc!(
r#"
x = 5
y = 10
42
"#
),
indoc!(
r#"
x = 5
y = 10
42
"#
),
);
}
#[test]
fn excess_parens() {
expr_formats_to(
indoc!(
r#"
x = (5)
y = ((10))
42
"#
),
indoc!(
r#"
x = 5
y = 10
42
"#
),
);
}
#[test]
fn defs_with_defs() {
expr_formats_to(
indoc!(
r#"
x =
y = 4
z = 8
w
x
"#
),
indoc!(
r#"
x =
y = 4
z = 8
w
x
"#
),
);
}
#[test]
fn comment_between_two_defs() {
expr_formats_same(indoc!(
r#"
x = 5
# Hello
y = 10
42
"#
));
expr_formats_same(indoc!(
r#"
x = 5
# Hello
# two comments
y = 10
42
"#
));
expr_formats_same(indoc!(
r#"
x = 5
# Hello
# two comments
y = 10
# v-- This is the return value
42
"#
));
}
#[test]
fn space_between_comments() {
expr_formats_to(
indoc!(
r#"
# 9
# A
# B
# C
9
"#
),
indoc!(
r#"
# 9
# A
# B
# C
9
"#
),
);
}
#[test]
fn reduce_space_between_comments() {
expr_formats_to(
indoc!(
r#"
# First
# Second
x
"#
),
indoc!(
r#"
# First
# Second
x
"#
),
);
expr_formats_to(
indoc!(
r#"
f = \x ->
# 1st
# 2nd
x
f 4
"#
),
indoc!(
r#"
f = \x ->
# 1st
# 2nd
x
f 4
"#
),
);
}
#[test]
fn doesnt_detect_comment_in_comment() {
expr_formats_same(indoc!(
r#"
# One Comment # Still one Comment
9
"#
));
}
#[test]
fn parenthetical_def() {
expr_formats_same(indoc!(
r#"
(UserId userId) = 5
y = 10
42
"#
));
expr_formats_same(indoc!(
r#"
# A
(UserId userId) = 5
# B
y = 10
42
"#
));
}
#[test]
fn record_destructuring() {
expr_formats_same(indoc!(
r#"
{ x, y } = 5
{ x: 5 } = { x: 5 }
42
"#
));
}
#[test]
fn record_field_destructuring() {
expr_formats_same(indoc!(
r#"
when foo is
{ x: 5 } ->
42
"#
));
}
#[test]
fn record_updating() {
expr_formats_same(indoc!(
r#"
{ shoes & leftShoe: nothing }
"#
));
expr_formats_to(
indoc!(
r#"
{ shoes & rightShoe : nothing }
"#
),
indoc!(
r#"
{ shoes & rightShoe: nothing }
"#
),
);
expr_formats_to(
indoc!(
r#"
{ shoes & rightShoe : nothing }
"#
),
indoc!(
r#"
{ shoes & rightShoe: nothing }
"#
),
);
expr_formats_same(indoc!(
r#"
{ shoes &
rightShoe: newRightShoe,
leftShoe: newLeftShoe,
}
"#
));
expr_formats_to(
indoc!(
r#"
{ shoes
& rightShoe: bareFoot
, leftShoe: bareFoot }
"#
),
indoc!(
r#"
{ shoes &
rightShoe: bareFoot,
leftShoe: bareFoot,
}
"#
),
);
}
#[test]
fn final_comments_in_records() {
expr_formats_same(indoc!(
r#"
{
x: 42,
# comment
}"#
));
expr_formats_same(indoc!(
r#"
{
x: 42,
# comment
# other comment
}"#
));
}
#[test]
fn final_comments_without_comma_in_records() {
expr_formats_to(
indoc!(
r#"
{
y: 41,
# comment 1
x: 42 # comment 2
}"#
),
indoc!(
r#"
{
y: 41,
# comment 1
x: 42,
# comment 2
}"#
),
);
}
#[test]
fn multiple_final_comments_without_comma_in_records() {
expr_formats_to(
indoc!(
r#"
{
y: 41,
x: 42 # comment 1
# comment 2
}"#
),
indoc!(
r#"
{
y: 41,
x: 42,
# comment 1
# comment 2
}"#
),
);
}
#[test]
fn comments_with_newlines_in_records() {
expr_formats_to(
indoc!(
r#"
{
z: 44 #comment 0
,
y: 41, # comment 1
# comment 2
x: 42
# comment 3
# comment 4
}"#
),
indoc!(
r#"
{
z: 44,
# comment 0
y: 41,
# comment 1
# comment 2
x: 42,
# comment 3
# comment 4
}"#
),
);
}
#[test]
fn multiple_final_comments_with_comma_in_records() {
expr_formats_to(
indoc!(
r#"
{
y: 41,
x: 42, # comment 1
# comment 2
}"#
),
indoc!(
r#"
{
y: 41,
x: 42,
# comment 1
# comment 2
}"#
),
);
}
#[test]
fn trailing_comma_in_record_annotation() {
expr_formats_to(
indoc!(
r#"
f: { y : Int *,
x : Int * ,
}
f"#
),
indoc!(
r#"
f :
{
y : Int *,
x : Int *,
}
f"#
),
);
}
#[test]
fn trailing_comma_in_record_annotation_same() {
expr_formats_same(indoc!(
r#"
f :
{
y : Int *,
x : Int *,
}
f"#
));
}
#[test]
fn multiline_type_definition() {
expr_formats_same(indoc!(
r#"
f :
Int *
f"#
));
}
#[test]
fn multiline_empty_record_type_definition() {
expr_formats_same(indoc!(
r#"
f :
{}
f"#
));
}
#[test]
fn type_definition_comment_after_colon() {
expr_formats_to(
indoc!(
r#"
f : # comment
{}
f"#
),
indoc!(
r#"
f :
# comment
{}
f"#
),
);
}
#[test]
#[ignore]
fn final_comment_in_empty_record_type_definition() {
expr_formats_to(
indoc!(
r#"
f :
{ # comment
}
f"#
),
indoc!(
r#"
f :
{
# comment
}
f"#
),
);
}
#[test]
#[ignore]
fn multiline_inside_empty_record_annotation() {
expr_formats_same(indoc!(
r#"
f :
{
}
f"#
));
}
#[test]
fn final_comment_record_annotation() {
expr_formats_to(
indoc!(
r#"
f :
{
x: Int * # comment 1
,
# comment 2
}
f"#
),
indoc!(
r#"
f :
{
x : Int *,
# comment 1
# comment 2
}
f"#
),
);
}
#[test]
fn def_closure() {
expr_formats_same(indoc!(
r#"
identity = \a -> a
identity 42
"#
));
expr_formats_same(indoc!(
r#"
identity = \a ->
a
identity 44
"#
));
expr_formats_same(indoc!(
r#"
identity = \a -> a
# Hello
identity 40
"#
));
expr_formats_to(
indoc!(
r#"
identity = \a
-> a
identity 41
"#
),
indoc!(
r#"
identity = \a -> a
identity 41
"#
),
);
expr_formats_to(
indoc!(
r#"
identity = \a
->
a + b
identity 4010
"#
),
indoc!(
r#"
identity = \a ->
a + b
identity 4010
"#
),
);
expr_formats_same(indoc!(
r#"
identity = \a, b -> a
identity 43
"#
));
// expr_formats_same(indoc!(
// r#"
// identity =
// \{
// x,
// y
// }
// -> a
//
// identity 43
// "#
// ));
expr_formats_same(indoc!(
r#"
identity = \a,
b,
# it's c!!
c
-> a
identity 43
"#
));
}
#[test]
fn closure_multiline_pattern() {
expr_formats_same(indoc!(
r#"
identity = \a,
b,
# it's c!!
c
-> a
identity 43
"#
));
}
// LIST
#[test]
fn empty_list() {
expr_formats_same("[]");
expr_formats_to("[ ]", "[]");
}
#[test]
fn one_item_list() {
expr_formats_same(indoc!("[ 4 ] "));
}
#[test]
fn two_item_list() {
expr_formats_same(indoc!("[ 7, 8 ] "));
expr_formats_to(indoc!("[ 7 , 8 ] "), indoc!("[ 7, 8 ] "));
}
#[test]
fn multi_line_list() {
expr_formats_same(indoc!(
r#"
[
7,
8,
9,
]
"#
));
expr_formats_to(
indoc!(
r#"
[ 17
, 18
, 19
]
"#
),
indoc!(
r#"
[
17,
18,
19,
]
"#
),
);
expr_formats_to(
indoc!(
r#"
[ 27
, 28
, 29
]
"#
),
indoc!(
r#"
[
27,
28,
29,
]
"#
),
);
expr_formats_to(
indoc!(
r#"
[
157, 158,
159
]
"#
),
indoc!(
r#"
[
157,
158,
159,
]
"#
),
);
expr_formats_to(
indoc!(
r#"
[
557, 648,
759, 837
]
"#
),
indoc!(
r#"
[
557,
648,
759,
837,
]
"#
),
);
expr_formats_to(
indoc!(
r#"
[
257, 358,
# Hey!
459
]
"#
),
indoc!(
r#"
[
257,
358,
# Hey!
459,
]
"#
),
);
expr_formats_to(
indoc!(
r#"
[
# Thirty Seven
37
# Thirty Eight
, 38
, 39
]
"#
),
indoc!(
r#"
[
# Thirty Seven
37,
# Thirty Eight
38,
39,
]
"#
),
);
expr_formats_to(
indoc!(
r#"
[ # 47!
# Top 47
47
# Bottom 47
# Top 48
, 48
# Bottom 48
# Top 49
, 49
# Bottom 49
# 49!
]
"#
),
indoc!(
r#"
[
# 47!
# Top 47
47,
# Bottom 47
# Top 48
48,
# Bottom 48
# Top 49
49,
# Bottom 49
# 49!
]
"#
),
);
}
#[test]
fn ending_comments_in_list() {
expr_formats_to(
indoc!(
r#"
[ # Top 49
49
# Bottom 49
,
# 49!
]
"#
),
indoc!(
r#"
[
# Top 49
49,
# Bottom 49
# 49!
]
"#
),
);
}
#[test]
fn multi_line_list_def() {
expr_formats_same(indoc!(
r#"
l =
[
1,
2,
]
l
"#
));
expr_formats_to(
indoc!(
r#"
results = [
Ok 4,
Ok 5
]
allOks results
"#
),
indoc!(
r#"
results =
[
Ok 4,
Ok 5,
]
allOks results
"#
),
);
expr_formats_to(
indoc!(
r#"
results =
# Let's count past 6
[
Ok 6,
Err CountError
]
allOks results
"#
),
indoc!(
r#"
results =
# Let's count past 6
[
Ok 6,
Err CountError,
]
allOks results
"#
),
);
}
// RECORD LITERALS
#[test]
fn empty_record() {
expr_formats_same("{}");
}
#[test]
#[ignore]
fn empty_record_with_comment() {
expr_formats_same(indoc!(
r#"
{
# comment
}"#
));
}
#[test]
#[ignore]
fn empty_record_with_newline() {
expr_formats_to(
indoc!(
r#"
{
}"#
),
"{}",
);
}
#[test]
fn one_field() {
expr_formats_same("{ x: 4 }");
}
#[test]
fn two_fields() {
expr_formats_same("{ x: 4, y: 42 }");
}
#[test]
fn two_fields_newline() {
expr_formats_same(indoc!(
r#"
{
x: 4,
y: 42,
}
"#
));
}
#[test]
fn multi_line_record_def() {
expr_formats_same(indoc!(
r#"
pos =
{
x: 4,
y: 11,
z: 16,
}
pos
"#
));
expr_formats_to(
indoc!(
r#"
pos = {
x: 5,
y: 10,
}
pos
"#
),
indoc!(
r#"
pos =
{
x: 5,
y: 10,
}
pos
"#
),
);
}
#[test]
fn two_fields_center_newline() {
expr_formats_to(
indoc!(
r#"
{ x: 4,
y: 42
}
"#
),
indoc!(
r#"
{
x: 4,
y: 42,
}
"#
),
);
}
#[test]
fn one_unnamed_field() {
expr_formats_same(indoc!(
r#"
foo = 4
{ foo }
"#
));
}
// IF
#[test]
fn single_line_if() {
expr_formats_same(indoc!(
r#"
if foo bar then a b c else d e f
"#
));
expr_formats_same(indoc!(
r#"
if foo (a b c) then a b c else d e f
"#
));
}
#[test]
fn multi_line_if_condition() {
expr_formats_same(indoc!(
r#"
if
waterWillBoil pressure temperature
then
turnOnAc
else
identity
"#
));
}
#[test]
fn multi_line_if_condition_with_spaces() {
expr_formats_to(
indoc!(
r#"
if
willBoil home water
then
\_ -> leave
else
identity
"#
),
indoc!(
r#"
if
willBoil home water
then
\_ -> leave
else
identity
"#
),
);
}
#[test]
fn multi_line_if_condition_with_multi_line_expr_1() {
expr_formats_same(indoc!(
r#"
if
snowWillFall
pressure
temperature
then
bundleUp
else
identity
"#
));
}
#[test]
fn multi_line_if_condition_with_multi_line_expr_2() {
expr_formats_same(indoc!(
r#"
if
1
== 2
then
"yes"
else
"no"
"#
));
}
#[test]
fn if_removes_newlines_from_else() {
expr_formats_to(
indoc!(
r#"
if
isPrime 8
then
nothing
else
# C
# D
# E
# F
just (div 1 8)
"#
),
indoc!(
r#"
if
isPrime 8
then
nothing
else
# C
# D
# E
# F
just (div 1 8)
"#
),
);
}
#[test]
fn if_removes_newlines_from_then() {
expr_formats_to(
indoc!(
r#"
if
isPrime 9
then
# EE
# FF
nothing
# GG
else
just (div 1 9)
"#
),
indoc!(
r#"
if
isPrime 9
then
# EE
# FF
nothing
# GG
else
just (div 1 9)
"#
),
);
}
#[test]
fn if_removes_newlines_from_condition() {
expr_formats_to(
indoc!(
r#"
if
# Is
# It
isPrime 10
# Prime?
then
nothing
else
just (div 1 10)
"#
),
indoc!(
r#"
if
# Is
# It
isPrime 10
# Prime?
then
nothing
else
just (div 1 10)
"#
),
);
}
#[test]
fn multi_line_if() {
expr_formats_to(
indoc!(
r#"
if lessThan four five then
four
else
five
"#
),
indoc!(
r#"
if lessThan four five then
four
else
five
"#
),
);
expr_formats_to(
indoc!(
r#"
if lessThan three four then
three
else
four
"#
),
indoc!(
r#"
if lessThan three four then
three
else
four
"#
),
);
expr_formats_same(indoc!(
r#"
if foo bar then
a b c
else
d e f
"#
));
}
#[test]
fn multi_line_application() {
expr_formats_same(indoc!(
r#"
combine
peanutButter
chocolate
"#
));
}
#[test]
fn partial_multi_line_application() {
expr_formats_to(
indoc!(
r#"
mix vodka
tonic
"#
),
indoc!(
r#"
mix
vodka
tonic
"#
),
);
expr_formats_to(
indoc!(
r#"
f
a b c
"#
),
indoc!(
r#"
f
a
b
c
"#
),
);
}
// WHEN
#[test]
fn integer_when() {
expr_formats_same(indoc!(
r#"
when b is
1 ->
1
_ ->
2
"#
));
}
#[test]
fn integer_when_with_space() {
expr_formats_to(
indoc!(
r#"
when year is
1999 ->
1
_ ->
0
"#
),
indoc!(
r#"
when year is
1999 ->
1
_ ->
0
"#
),
);
}
#[test]
fn when_with_comments() {
expr_formats_same(indoc!(
r#"
when b is
# look at cases
1 ->
# when 1
1
# important
# fall through
_ ->
# case 2
# more comment
2
"#
));
}
#[test]
fn nested_when() {
expr_formats_same(indoc!(
r#"
when b is
_ ->
when c is
_ ->
1
"#
));
}
#[test]
fn when_with_alternatives() {
expr_formats_same(indoc!(
r#"
when b is
1 | 2 ->
when c is
6 | 7 ->
8
3 | 4 ->
5
"#
));
expr_formats_same(indoc!(
r#"
when b is
# a comment here
1 | 2 ->
# a comment there
1
"#
));
expr_formats_to(
indoc!(
r#"
when b is
1 | 2 |3 ->
1
"#
),
indoc!(
r#"
when b is
1 | 2 | 3 ->
1
"#
),
);
expr_formats_to(
indoc!(
r#"
when b is
1 | 2 |
3
->
4
5 | 6 | 7 ->
8
9
| 10 -> 11
12 | 13 ->
when c is
14 | 15 -> 16
17
| 18 -> 19
20 -> 21
"#
),
indoc!(
r#"
when b is
1
| 2
| 3 ->
4
5 | 6 | 7 ->
8
9
| 10 ->
11
12 | 13 ->
when c is
14 | 15 ->
16
17
| 18 ->
19
20 ->
21
"#
),
);
}
#[test]
fn when_with_moving_comments() {
expr_formats_to(
indoc!(
r#"
when b is
1 ->
1 # when 1
# fall through
_ ->
2
"#
),
indoc!(
r#"
when b is
1 ->
1
# when 1
# fall through
_ ->
2
"#
),
);
}
#[test]
fn multi_line_when_condition_1() {
expr_formats_same(indoc!(
r#"
when
complexFunction a b c
is
1 ->
Nothing
_ ->
Just True
"#
));
}
#[test]
fn multi_line_when_condition_2() {
expr_formats_same(indoc!(
r#"
when
# this is quite complicated
complexFunction a b c
# Watch out
is
Complex x y ->
simplify x y
Simple z ->
z
"#
));
}
#[test]
fn multi_line_when_condition_3() {
expr_formats_to(
indoc!(
r#"
x = 2
y = 3
when 1
+ 1 is
2 ->
x
_ ->
y
"#
),
indoc!(
r#"
x = 2
y = 3
when
1
+ 1
is
2 ->
x
_ ->
y
"#
),
);
}
#[test]
fn multi_line_when_condition_4() {
expr_formats_to(
indoc!(
r#"
x = 2
y = 3
when 2
+ 2
is
4 ->
x
_ ->
y
"#
),
indoc!(
r#"
x = 2
y = 3
when
2
+ 2
is
4 ->
x
_ ->
y
"#
),
);
}
// NEWLINES
#[test]
fn multiple_blank_lines_collapse_to_one() {
expr_formats_to(
indoc!(
r#"
x = 5
y = 10
42
"#
),
indoc!(
r#"
x = 5
y = 10
42
"#
),
);
}
#[test]
fn def_returning_closure() {
expr_formats_same(indoc!(
r#"
f = \x -> x
g = \x -> x
\x ->
a = f x
b = f x
x
"#
));
}
#[test]
fn when_guard() {
expr_formats_same(indoc!(
r#"
when maybeScore is
Just score if score > 21 ->
win
_ ->
nextRound
"#
));
}
#[test]
fn when_guard_using_function() {
expr_formats_same(indoc!(
r#"
when authenticationResponse is
Ok user if hasPermission user ->
loadPage route user
Ok user ->
PageNotFound
Err _ ->
ErrorPage
"#
));
}
// ACCESSOR
#[test]
fn accessor() {
expr_formats_same(indoc!(
r#"
.id
"#
));
expr_formats_same(indoc!(
r#"
user.name
"#
));
expr_formats_same(indoc!(
r#"
(getUser userId users).name
"#
));
}
// PRECEDENCE CONFLICT
#[test]
fn precedence_conflict() {
expr_formats_same(indoc!(
r#"
if True == False == True then
False
else
True
"#
));
}
#[test]
fn multi_line_precedence_conflict_1() {
expr_formats_to(
indoc!(
r#"
if True
== False == True
then
False
else
True
"#
),
indoc!(
r#"
if
True
== False
== True
then
False
else
True
"#
),
);
}
#[test]
fn multi_line_precedence_conflict_2() {
expr_formats_to(
indoc!(
r#"
if False
== False == False then
"true"
else
"false"
"#
),
indoc!(
r#"
if
False
== False
== False
then
"true"
else
"false"
"#
),
);
}
#[test]
fn precedence_conflict_functions() {
expr_formats_same(indoc!(
r#"
when f x == g y == h z is
True ->
Ok 1
False ->
Err 2
"#
));
}
#[test]
fn binop_parens() {
expr_formats_same(indoc!(
r#"
if 4 == (6 ^ 6 ^ 7 ^ 8) then
"Hard to believe"
else
"Naturally"
"#
));
expr_formats_same(indoc!(
r#"
if 5 == 1 ^ 1 ^ 1 ^ 1 then
"Not buying it"
else
"True"
"#
));
expr_formats_to(
indoc!(
r#"
if (1 == 1)
&& (2 == 1) && (3 == 2) then
"true"
else
"false"
"#
),
indoc!(
r#"
if
(1 == 1)
&& (2 == 1)
&& (3 == 2)
then
"true"
else
"false"
"#
),
);
}
#[test]
fn precedence_conflict_greater_than() {
expr_formats_same(indoc!(
r#"
3 > 4 > 10
"#
));
}
#[test]
fn precedence_conflict_greater_than_and_less_than() {
expr_formats_same(indoc!(
r#"
1 < 4 > 1
"#
));
}
// UNARY OP
#[test]
fn unary_op() {
expr_formats_same(indoc!(
r#"
y = -4
!x
"#
));
}
// BINARY OP
#[test]
fn binary_op() {
expr_formats_same(indoc!(
r#"
1 == 1
"#
));
}
#[test]
fn binary_op_with_spaces() {
expr_formats_to(
indoc!(
r#"
2 != 3
"#
),
indoc!(
r#"
2 != 3
"#
),
);
}
#[test]
fn multi_line_binary_op_1() {
expr_formats_same(indoc!(
r#"
isLast
&& isEmpty
&& isLoaded
"#
));
}
#[test]
fn multi_line_binary_op_2() {
expr_formats_same(indoc!(
r#"
x = 1
< 2
f x
"#
));
}
#[test]
fn multi_line_binary_op_with_comments() {
expr_formats_to(
indoc!(
r#"
1
* 2
/ 3
// 4
"#
),
indoc!(
r#"
1
* 2
/ 3
// 4
"#
),
);
}
#[test]
fn partial_multi_line_binary_op_1() {
expr_formats_to(
indoc!(
r#"
2 % 3
%% 5
+ 7
"#
),
indoc!(
r#"
2
% 3
%% 5
+ 7
"#
),
);
}
#[test]
fn partial_multi_line_binary_op_2() {
expr_formats_to(
indoc!(
r#"
isGreenLight
&& isRedLight && isYellowLight
"#
),
indoc!(
r#"
isGreenLight
&& isRedLight
&& isYellowLight
"#
),
);
}
// MODULES
#[test]
fn single_line_interface() {
module_formats_same(indoc!(
r#"
interface Foo exposes [] imports []
"#
));
}
#[test]
fn multiline_interface() {
module_formats_same(indoc!(
r#"
interface Foo
exposes []
imports []
"#
));
}
#[test]
fn interface_exposing() {
module_formats_same(indoc!(
r#"
interface Foo
exposes [ Bar, Baz, a, b ]
imports []
"#
));
}
#[test]
fn interface_importing() {
module_formats_same(indoc!(
r#"
interface Foo
exposes [ Bar, Baz, a, b ]
imports [ Blah, Thing.{ foo, bar }, Stuff ]
"#
));
}
#[test]
fn single_line_app() {
module_formats_same(indoc!(
r#"
app "Foo" packages { base: "platform" } imports [] provides [ main ] to base
"#
));
}
#[test]
fn single_line_platform() {
// There are many places that there should probably be spaces, e.g.:
// requires { model=>Model, msg=>Msg } { main : Effect {} }
// ^
// putLine : Str -> Effect {},
// ^
// TODO: improve spacing
module_formats_same(
"platform folkertdev/foo \
requires { model=>Model, msg=>Msg } { main :Effect {} } \
exposes [] \
packages {} \
imports [ Task.{ Task } ] \
provides [ mainForHost ] \
effects fx.Effect \
{ \
putLine :Str -> Effect {}, \
putInt :I64 -> Effect {}, \
getInt :Effect { value : I64, errorCode : [ A, B ], isError : Bool } \
} ",
);
}
/// Annotations and aliases
#[test]
fn list_alias() {
expr_formats_same(indoc!(
r#"
ConsList a : [ Cons a (ConsList a), Nil ]
f : ConsList a -> ConsList a
f = \_ -> Nil
f
"#
));
}
#[test]
fn wildcard() {
expr_formats_same(indoc!(
r#"
f : List *
f = []
a
"#
));
}
#[test]
fn identity() {
expr_formats_same(indoc!(
r#"
f : a -> a
f = []
a
"#
));
}
#[test]
fn multiline_tag_union_annotation() {
expr_formats_same(indoc!(
r#"
b :
[
True,
False,
]
b
"#
));
}
#[test]
fn multiline_tag_union_annotation_with_final_comment() {
expr_formats_to(
indoc!(
r#"
b :
[
True,
# comment 1
False # comment 2
,
# comment 3
]
b
"#
),
indoc!(
r#"
b :
[
True,
# comment 1
False,
# comment 2
# comment 3
]
b
"#
),
);
}
#[test]
fn tag_union() {
expr_formats_same(indoc!(
r#"
f : [ True, False ] -> [ True, False ]
f = \x -> x
a
"#
));
}
// TODO: the current formatting seems a bit odd for multiline function annotations
// (beside weird indentation, note the trailing space after the "->")
// #[test]
// fn multiline_tag_union_function_annotation() {
// expr_formats_same(indoc!(
// r#"
// f :
// [
// True,
// False,
// ] ->
// [
// True,
// False,
// ]
// f = \x -> x
// a
// "#
// ));
// }
#[test]
fn recursive_tag_union() {
expr_formats_same(indoc!(
r#"
f : [ Cons a (ConsList a), Nil ] as ConsList a -> [ Just a, Nothing ]
f = \list ->
when list is
Nil ->
Nothing
Cons first _ ->
Just first
f
"#
));
}
#[test]
fn function_application_package_type() {
expr_formats_same(indoc!(
r#"
main : Task.Task {} []
main = 42
main
"#
));
}
#[test]
fn record_type() {
expr_formats_same(indoc!(
r#"
f : { foo : Int * }
f = { foo: 1000 }
a
"#
));
}
#[test]
fn record_pattern_with_apply_guard() {
expr_formats_same(indoc!(
r#"
when { x: 1 } is
{ x: Just 4 } ->
4
"#
));
}
#[test]
fn record_pattern_with_record_guard() {
expr_formats_same(indoc!(
r#"
when { x: 1 } is
{ x: { x: True } } ->
4
"#
));
}
#[test]
fn body_starts_with_spaces_multiline() {
expr_formats_same(indoc!(
r#"
y =
Foo
1
2
y
"#
));
}
#[test]
fn backpassing_simple() {
expr_formats_same(indoc!(
r#"
getChar = \ctx ->
x <- Task.await (getCharScope scope)
42
42
"#
));
}
#[test]
fn backpassing_apply_tag() {
expr_formats_same(indoc!(
r#"
getChar = \ctx ->
(T val newScope) <- Task.await (getCharScope scope)
42
42
"#
));
}
#[test]
fn backpassing_body_on_newline() {
expr_formats_same(indoc!(
r#"
getChar = \ctx ->
x <-
Task.await (getCharScope scope)
42
42
"#
));
}
// this is a parse error atm
// #[test]
// fn multiline_apply() {
// expr_formats_same(indoc!(
// r#"
// f :
// Result a
// { x : Int *
// , y : Float
// }
// c
// -> Int *
// f =
// \_ -> 4
// "#
// ));
// }
}