// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2021 The Gleam contributors use crate::assert_js; #[test] fn case_on_error() { assert_js!( r#" fn a_result() { Error(1) } pub fn main() { case a_result() { Error(_) -> 1 _ -> 2 } }"# ); } #[test] fn tuple_and_guard() { assert_js!( r#" pub fn go(x) { case #(1, 2) { #(1, a) if a == 2 -> 1 #(_, _) -> 2 } } "#, ) } #[test] fn guard_variable_only_brought_into_scope_when_needed() { assert_js!( r#" pub fn go(x) { case x { // We want `a` to be defined before the guard check, and // `b` to be defined only if the predicate on a matches! [a, b] if a == 1 -> a + b _ -> 2 } } "# ) } // https://github.com/gleam-lang/gleam/issues/4221 #[test] fn guard_variable_only_brought_into_scope_when_needed_1() { assert_js!( r#" pub fn main() { case 1 { i if i == 1 -> True i if i < 2 -> True _ -> False } } "# ) } // https://github.com/gleam-lang/gleam/issues/1187 #[test] fn pointless() { assert_js!( r#" pub fn go(x) { case x { _ -> x } } "#, ) } // https://github.com/gleam-lang/gleam/issues/1188 #[test] fn following_todo() { assert_js!( r#" pub fn go(x) { case x { True -> todo _ -> 1 } } "#, ) } #[test] fn multi_subject_catch_all() { assert_js!( r#" pub fn go(x, y) { case x, y { True, True -> 1 _, _ -> 0 } } "#, ) } #[test] fn multi_subject_or() { assert_js!( r#" pub fn go(x, y) { case x, y { True, _ | _, True -> 1 _, _ -> 0 } } "#, ) } #[test] fn multi_subject_no_catch_all() { assert_js!( r#" pub fn go(x, y) { case x, y { True, _ -> 1 _, True -> 2 False, False -> 0 } } "#, ) } #[test] fn multi_subject_subject_assignments() { assert_js!( r#" pub fn go() { case True, False { True, True -> 1 _, _ -> 0 } } "#, ) } #[test] fn assignment() { assert_js!( r#" pub fn go(x) { let y = case x { True -> 1 _ -> 0 } y } "#, ) } #[test] fn preassign_assignment() { assert_js!( r#" pub fn go(x) { let y = case x() { True -> 1 _ -> 0 } y } "#, ) } // https://github.com/gleam-lang/gleam/issues/1237 #[test] fn pipe() { assert_js!( r#" pub fn go(x, f) { case x |> f { 0 -> 1 _ -> 2 } } "#, ) } #[test] fn result() { assert_js!( r#" pub fn go(x) { case x { Ok(_) -> 1 Error(_) -> 0 } } "#, ) } // https://github.com/gleam-lang/gleam/issues/1506 #[test] fn called_case() { assert_js!( r#" pub fn go(x, y) { case x { 0 -> y _ -> y }() } "#, ) } // https://github.com/gleam-lang/gleam/issues/1978 #[test] fn case_local_var_in_tuple() { assert_js!( r#" pub fn go(x, y) { let z = False case True { x if #(x, z) == #(True, False) -> x _ -> False } } "#, ) } // https://github.com/gleam-lang/gleam/issues/2665 #[test] fn case_branches_guards_are_wrapped_in_parentheses() { assert_js!( r#" pub fn anything() -> a { case [] { [a] if False || True -> a _ -> anything() } } "#, ) } // https://github.com/gleam-lang/gleam/issues/2759 #[test] fn nested_string_prefix_match() { assert_js!( r#" pub fn main() { case Ok(["a", "b c", "d"]) { Ok(["a", "b " <> _, "d"]) -> 1 _ -> 1 } } "# ); } // https://github.com/gleam-lang/gleam/issues/2759 #[test] fn nested_string_prefix_match_that_would_crash_on_js() { assert_js!( r#" pub fn main() { case Ok(["b c", "d"]) { Ok(["b " <> _, "d"]) -> 1 _ -> 1 } } "# ); } #[test] fn slicing_is_handled_properly_with_multiple_branches() { assert_js!( r#" pub fn main() { case "12345" { "0" <> rest -> rest "123" <> rest -> rest _ -> "" } } "# ) } // https://github.com/gleam-lang/gleam/issues/3379 #[test] fn single_clause_variables() { assert_js!( r#" pub fn main() { let text = "first defined" case "defined again" { text -> Nil } let text = "a third time" } "# ) } // https://github.com/gleam-lang/gleam/issues/3379 #[test] fn single_clause_variables_assigned() { assert_js!( r#" pub fn main() { let text = "first defined" let other = case "defined again" { text -> Nil } let text = "a third time" } "# ) } // https://github.com/gleam-lang/gleam/issues/3894 #[test] fn nested_string_prefix_assignment() { assert_js!( r#" type Wibble { Wibble(wobble: String) } pub fn main() { let tmp = Wibble(wobble: "wibble") case tmp { Wibble(wobble: "w" as wibble <> rest) -> wibble <> rest _ -> panic } } "# ) } #[test] fn deeply_nested_string_prefix_assignment() { assert_js!( r#" type Wibble { Wibble(Wobble) } type Wobble { Wobble(wabble: Wabble) } type Wabble { Wabble(tuple: #(Int, String)) } pub fn main() { let tmp = Wibble(Wobble(Wabble(#(42, "wibble")))) case tmp { Wibble(Wobble(Wabble(#(_int, "w" as wibble <> rest)))) -> wibble <> rest _ -> panic } } "# ) } // https://github.com/gleam-lang/gleam/issues/4383 #[test] fn record_update_in_pipeline_in_case_clause() { assert_js!( " pub type Wibble { Wibble(wibble: Int, wobble: Int) } fn identity(x) { x } pub fn go(x) { case x { Wibble(1, _) -> Wibble(..x, wibble: 4) |> identity Wibble(_, 3) -> Wibble(..x, wobble: 10) |> identity _ -> panic } } " ); } #[test] fn pattern_matching_on_aliased_result_constructor() { assert_js!( " import gleam.{Error as E, Ok as O} pub fn go(x) { case x { E(_) -> 1 O(_) -> 2 } } " ); } #[test] fn list_with_guard() { assert_js!( " pub fn go(x) { case x { [] -> 0 [first, ..] if first < 10 -> first * 2 [first, ..] -> first } } " ); } #[test] fn list_with_guard_no_binding() { assert_js!( " pub fn go(x) { case x { [] -> 0 [first, ..] if 1 < 10 -> first * 2 [first, ..] -> first } } " ); } #[test] fn case_building_simple_value_matched_by_pattern() { assert_js!( "pub fn go(x) { case x { 1 -> 2 n -> n } }" ) } #[test] fn case_building_list_matched_by_pattern() { assert_js!( "pub fn go(x) { case x { [] -> [] [a, b] -> [a, b] [1, ..rest] -> [1, ..rest] _ -> x } }" ) } #[test] fn case_building_record_matched_by_pattern() { assert_js!( "pub fn go(x) { case x { Ok(1) -> Ok(1) Ok(n) -> Ok(n) Error(_) -> Error(Nil) } }" ) } #[test] fn case_building_record_with_select_matched_by_pattern() { assert_js!( " import gleam pub fn go(x) { case x { Ok(1) -> gleam.Ok(1) _ -> Error(Nil) } }" ) } #[test] fn case_building_record_with_select_matched_by_pattern_2() { assert_js!( " import gleam pub fn go(x) { case x { gleam.Ok(1) -> gleam.Ok(1) _ -> Error(Nil) } }" ) } #[test] fn case_building_record_with_select_matched_by_pattern_3() { assert_js!( " import gleam pub fn go(x) { case x { gleam.Ok(1) -> Ok(1) _ -> Error(Nil) } }" ) } #[test] fn case_building_matched_string_1() { assert_js!( r#" import gleam pub fn go(x) { case x { "a" <> rest -> "a" <> rest _ -> "" } }"# ) } #[test] fn case_building_matched_string_2() { assert_js!( r#" import gleam pub fn go(x) { case x { "a" as a <> rest -> a <> rest _ -> "" } }"# ) } #[test] fn case_building_matched_value_wrapped_in_block() { assert_js!( r#" import gleam pub fn go(x) { case x { 1 -> { 1 } _ -> 2 } }"# ) } #[test] fn case_building_matched_value_alias() { assert_js!( r#" import gleam pub fn go(x) { case x { Ok(_) as a -> a Error(Nil) -> Error(Nil) } }"# ) } #[test] fn case_building_matched_value_alias_2() { assert_js!( r#" import gleam pub fn go(x) { case x { Ok(1) as a -> Ok(1) Ok(_) -> Ok(2) Error(Nil) -> Error(Nil) } }"# ) } #[test] fn case_building_matched_value_alias_3() { assert_js!( r#" import gleam pub fn go(x) { case x { Ok(1 as a) -> Ok(a) Ok(_) -> Ok(2) Error(Nil) -> Error(Nil) } }"# ) } #[test] fn case_building_matched_no_variant_record() { assert_js!( r#" pub fn go(x) { case x { Ok(Nil) -> Ok(Nil) _ -> Error(Nil) } }"# ) } #[test] fn case_building_matched_no_variant_record_2() { assert_js!( r#" import gleam pub fn go(x) { case x { Ok(gleam.Nil) -> Ok(Nil) _ -> Error(Nil) } }"# ) } #[test] fn case_building_matched_no_variant_record_3() { assert_js!( r#" import gleam pub fn go(x) { case x { Ok(Nil) -> Ok(gleam.Nil) _ -> Error(Nil) } }"# ) } #[test] fn case_building_matched_no_variant_record_4() { assert_js!( r#" import gleam pub fn go(x) { case x { Ok(gleam.Nil) -> Ok(gleam.Nil) _ -> Error(Nil) } }"# ) } #[test] fn case_building_record_with_labels_matched_by_pattern_1() { assert_js!( " pub type Wibble { Wibble(int: Int, string: String) Wobble(Int) } pub fn go(x) { case x { Wibble(1, s) -> Wibble(1, s) _ -> Wobble(1) } }" ) } #[test] fn case_building_record_with_labels_matched_by_pattern_2() { assert_js!( " pub type Wibble { Wibble(int: Int, string: String) Wobble(Int) } pub fn go(x) { case x { Wibble(string:, int:) -> Wibble(string:, int:) _ -> Wobble(1) } }" ) } #[test] fn case_building_record_with_labels_matched_by_pattern_3() { assert_js!( " pub type Wibble { Wibble(int: Int, string: String) Wobble(Int) } pub fn go(x) { case x { // This should not be optimised away! Wibble(string:, int:) -> Wibble(string:, int: 1) _ -> Wobble(1) } }" ) } #[test] fn case_building_record_with_labels_matched_by_pattern_4() { assert_js!( " pub type Wibble { Wibble(int: Int, string: String) Wobble(Int) } pub fn go(x) { case x { Wibble(string:, int:) -> Wibble(int:, string:) _ -> Wobble(1) } }" ) } #[test] fn case_building_record_with_labels_matched_by_pattern_5() { assert_js!( " pub type Wibble { Wibble(int: Int, string: String) Wobble(Int) } pub fn go(x) { case x { Wibble(string:, int: 1) -> Wibble(1, string:) _ -> Wobble(1) } }" ) } #[test] fn case_building_record_with_labels_matched_by_pattern_6() { assert_js!( " pub type Wibble { Wibble(int: Int, string: String) Wobble(Int) } pub fn go(x) { case x { Wibble(1, string:) -> Wibble(string:, int: 1) _ -> Wobble(1) } }" ) } #[test] fn case_with_multiple_subjects_building_simple_value_matched_by_pattern() { assert_js!( "pub fn go(x) { case x, x + 1 { 1, _ -> 2 _, n -> n } }" ) } #[test] fn case_with_multiple_subjects_building_list_matched_by_pattern() { assert_js!( "pub fn go(n, x) { case n, x { 1, [] -> [] _, [a, b] -> [a, b] 3, [1, ..rest] -> [1, ..rest] _, _ -> x } }" ) } #[test] fn case_with_multiple_subjects_building_record_matched_by_pattern() { assert_js!( "pub fn go(x, y) { case x, y { Ok(1), Error(_) -> Ok(1) Error(_), Ok(n) -> Ok(n) _, _ -> Error(Nil) } }" ) } #[test] fn case_with_multiple_subjects_building_same_value_as_two_subjects_one_is_picked() { assert_js!( " import gleam pub fn go(x, y) { case x, y { gleam.Ok(1), Ok(1) -> Ok(1) _, Error(Nil) -> Error(Nil) _, _ -> Error(Nil) } }" ) } #[test] fn interfering_string_pattern_succeeds_if_succeeding() { assert_js!( r#" pub fn wibble(bits) { case bits { <<"aaa", 0, _:bits>> -> 1 // If the first one succeeds, so will the second check, so it won't be // performed twice inside the first if branch! <<"aaa", 1, _:bits>> -> 2 _ -> 3 } }"# ); } #[test] fn string_concatenation_in_clause_guards() { assert_js!( r#" pub fn main() { let wibble = "wob" case wibble { x if x <> "ble" == "wobble" -> 1 _ -> 0 } }"# ); } #[test] fn var_true() { assert_js!( r#" fn true() { True } pub fn main() { let true_ = true() assert 0 == case Nil { _ if true_ -> 0 _ -> 1 } } "# ) } #[test] // https://github.com/gleam-lang/gleam/issues/5283 fn duplicate_name_for_variables_used_in_guards() { assert_js!( r#" pub fn wibble() { let a = case 1337 { n if n == 1347 -> Nil _ -> Nil } let b = case 1337 { n -> Nil } }"# ) } #[test] // https://github.com/gleam-lang/gleam/issues/5283 fn duplicate_name_for_variables_used_in_guards_shadowing_outer_name() { assert_js!( r#" pub fn wibble() { let n = 1 let a = case 1337 { n if n == 1347 -> n _ -> n } let b = case 1337 { n -> Nil } }"# ) } #[test] fn directly_matching_case_subject() { assert_js!( r#" pub fn go() { let x = "ABC" case True { True -> { let x = 79 0 } False -> { let x = True 0 } } x }"# ) } // https://github.com/gleam-lang/gleam/issues/5400 #[test] fn case_matching_single_character_prefixes() { assert_js!( r#" pub fn parse_digit(s: String) -> Int { case s { "0" <> s -> 0 "1" <> s -> 1 "2" <> s -> 2 "3" <> s -> 3 "4" <> s -> 4 "5" <> s -> 5 "6" <> s -> 6 "7" <> s -> 7 "8" <> s -> 8 "9" <> s -> 9 "" -> todo _ -> panic } } "# ); } // https://github.com/gleam-lang/gleam/issues/5467 #[test] fn no_duplicate_let_after_directly_matching_case() { assert_js!( r#" pub fn go() { let x = case #(1, 2) { #(1, b) -> b #(_, b) -> b } let #(a, _b) = #(x, 3) a }"# ) } // https://github.com/gleam-lang/gleam/issues/5743 #[test] fn no_duplicate_pipe_variable_with_case_in_pipeline() { assert_js!( r#" pub fn main() { 0 |> case True { True -> add_one |> identity False -> add_one } |> add_one } fn identity(x) { x } fn add_one(x) { x + 1 }"# ) } #[test] fn list_with_tail_used_in_guard() { assert_js!( r#" pub fn go(x: List(Int), y: List(Int)) { case x { [1, ..x] if [1, 2, ..x] == y -> True _ -> False } }"# ) } // https://github.com/gleam-lang/gleam/issues/5612 #[test] fn no_duplicate_let_after_case_with_same_named_variable_with_declaration_before_and_after() { assert_js!( r#" pub fn go() { let x = 0 let x = x let x = case #(1, 2) { #(_, x) -> x } let x = x x }"# ) } // https://github.com/gleam-lang/gleam/issues/5612 #[test] fn no_duplicate_let_after_case_with_same_named_variable() { assert_js!( r#" pub fn go() { let x = case #(1, 2) { #(_, x) -> x } x }"# ) } // https://github.com/gleam-lang/gleam/issues/5748 #[test] fn no_duplicate_let_when_rebinding_variable_after_directly_matching_case() { assert_js!( r#" pub fn go() { let n = 1 case True { True -> { let n = 99 n } False -> 0 } let n = n + 5 n }"# ) } #[test] fn semicolon_exists_with_directly_matching_case() { assert_js!( r#" pub fn go() { case #(1, 2) { #(a, _) -> a } {2 + 4} * 2 }"# ) } #[test] fn semicolon_exists_with_case() { assert_js!( r#" pub fn go() { case #(1, 2) { #(2, b) -> b #(1, 3) -> 2 #(a, _) -> a } {2 + 4} * 2 }"# ) } // https://github.com/gleam-lang/gleam/issues/6029 #[test] fn bit_array_slice_float_with_number_constructor() { assert_js!( " pub type Number { Number(Int) } pub fn go(bit_array) { case bit_array { <> -> f _ -> 0.0 } } " ); }