Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

1use itertools::Itertools; 2use lsp_types::{ 3 CodeActionContext, CodeActionParams, PartialResultParams, Position, Range, Url, 4 WorkDoneProgressParams, 5}; 6 7use super::*; 8 9fn code_actions(tester: &TestProject<'_>, range: Range) -> Option<Vec<lsp_types::CodeAction>> { 10 let position = Position { 11 line: 0, 12 character: 0, 13 }; 14 15 tester.at(position, |engine, params, _| { 16 let params = CodeActionParams { 17 text_document: params.text_document, 18 range, 19 context: CodeActionContext::default(), 20 work_done_progress_params: WorkDoneProgressParams::default(), 21 partial_result_params: PartialResultParams::default(), 22 }; 23 engine.code_actions(params).result.unwrap() 24 }) 25} 26 27fn actions_with_title( 28 titles: Vec<&str>, 29 tester: &TestProject<'_>, 30 range: Range, 31) -> Vec<lsp_types::CodeAction> { 32 code_actions(tester, range) 33 .into_iter() 34 .flatten() 35 .filter(|action| titles.contains(&action.title.as_str())) 36 .collect_vec() 37} 38 39fn owned_actions_with_title( 40 titles: Vec<&str>, 41 tester: TestProject<'_>, 42 range: Range, 43) -> Vec<lsp_types::CodeAction> { 44 actions_with_title(titles, &tester, range) 45} 46 47fn apply_code_action(title: &str, tester: TestProject<'_>, range: Range) -> String { 48 let titles = vec![title]; 49 let changes = actions_with_title(titles, &tester, range) 50 .pop() 51 .expect("No action with the given title") 52 .edit 53 .expect("No workspace edit found") 54 .changes 55 .expect("No text edit found"); 56 apply_code_edit(tester, changes) 57} 58 59fn apply_code_edit( 60 tester: TestProject<'_>, 61 changes: HashMap<Url, Vec<lsp_types::TextEdit>>, 62) -> String { 63 let mut changed_files: HashMap<Url, String> = HashMap::new(); 64 for (uri, change) in changes { 65 let code = match changed_files.get(&uri) { 66 Some(code) => code, 67 None => tester 68 .src_from_module_url(&uri) 69 .expect(&format!("no src for url {:?}", uri)), 70 }; 71 let code = super::apply_code_edit(code, change); 72 let _ = changed_files.insert(uri, code); 73 } 74 75 show_code_edits(tester, changed_files) 76} 77 78fn show_code_edits(tester: TestProject<'_>, changed_files: HashMap<Url, String>) -> String { 79 let format_code = |url: &Url, code: &String| { 80 format!( 81 "// --- Edits applied to module '{}'\n{}", 82 tester.module_name_from_url(url).expect("a module"), 83 code 84 ) 85 }; 86 87 // If the file that changed is the main one we just show its code. 88 if changed_files.len() == 1 { 89 let mut changed = changed_files.iter().peekable(); 90 let (url, code) = changed.peek().unwrap(); 91 if tester.module_name_from_url(url) == Some("app".into()) { 92 code.to_string() 93 } else { 94 format_code(url, code) 95 } 96 } else { 97 // If more than a single file changed we want to add the name of the 98 // file before each! 99 changed_files 100 .iter() 101 .map(|(url, code)| format_code(url, code)) 102 .join("\n") 103 } 104} 105 106const REMOVE_UNUSED_IMPORTS: &str = "Remove unused imports"; 107const REMOVE_REDUNDANT_TUPLES: &str = "Remove redundant tuples"; 108const CONVERT_TO_CASE: &str = "Convert to case"; 109const USE_LABEL_SHORTHAND_SYNTAX: &str = "Use label shorthand syntax"; 110const FILL_LABELS: &str = "Fill labels"; 111const ASSIGN_UNUSED_RESULT: &str = "Assign unused Result value to `_`"; 112const ADD_MISSING_PATTERNS: &str = "Add missing patterns"; 113const ADD_ANNOTATION: &str = "Add type annotation"; 114const ADD_ANNOTATIONS: &str = "Add type annotations"; 115const CONVERT_FROM_USE: &str = "Convert from `use`"; 116const CONVERT_TO_USE: &str = "Convert to `use`"; 117const EXTRACT_VARIABLE: &str = "Extract variable"; 118const EXTRACT_CONSTANT: &str = "Extract constant"; 119const EXPAND_FUNCTION_CAPTURE: &str = "Expand function capture"; 120const GENERATE_DYNAMIC_DECODER: &str = "Generate dynamic decoder"; 121const GENERATE_TO_JSON_FUNCTION: &str = "Generate to-JSON function"; 122const PATTERN_MATCH_ON_ARGUMENT: &str = "Pattern match on argument"; 123const PATTERN_MATCH_ON_VARIABLE: &str = "Pattern match on variable"; 124const GENERATE_FUNCTION: &str = "Generate function"; 125const CONVERT_TO_FUNCTION_CALL: &str = "Convert to function call"; 126const INLINE_VARIABLE: &str = "Inline variable"; 127const CONVERT_TO_PIPE: &str = "Convert to pipe"; 128const INTERPOLATE_STRING: &str = "Interpolate string"; 129const FILL_UNUSED_FIELDS: &str = "Fill unused fields"; 130const REMOVE_ALL_ECHOS_FROM_THIS_MODULE: &str = "Remove all `echo`s from this module"; 131const WRAP_IN_BLOCK: &str = "Wrap in block"; 132const GENERATE_VARIANT: &str = "Generate variant"; 133const REMOVE_BLOCK: &str = "Remove block"; 134const REMOVE_OPAQUE_FROM_PRIVATE_TYPE: &str = "Remove opaque from private type"; 135const COLLAPSE_NESTED_CASE: &str = "Collapse nested case"; 136 137macro_rules! assert_code_action { 138 ($title:expr, $code:literal, $range:expr $(,)?) => { 139 let project = TestProject::for_source($code); 140 assert_code_action!($title, project, $range); 141 }; 142 143 ($title:expr, $project:expr, $range:expr $(,)?) => { 144 let src = $project.src; 145 let range = $range.find_range(src); 146 let result = apply_code_action($title, $project, range); 147 let output = format!( 148 "----- BEFORE ACTION\n{}\n\n----- AFTER ACTION\n{}", 149 hover::show_hover(src, range, range.end), 150 result 151 ); 152 insta::assert_snapshot!(insta::internals::AutoName, output, src); 153 }; 154} 155 156macro_rules! assert_no_code_actions { 157 ($title:ident $(| $titles:ident)*, $code:literal, $range:expr $(,)?) => { 158 let project = TestProject::for_source($code); 159 assert_no_code_actions!($title $(| $titles)*, project, $range); 160 }; 161 162 ($title:ident $(| $titles:ident)*, $project:expr, $range:expr $(,)?) => { 163 let src = $project.src; 164 let range = $range.find_range(src); 165 let all_titles = vec![$title $(, $titles)*]; 166 let expected: Vec<lsp_types::CodeAction> = vec![]; 167 let result = owned_actions_with_title(all_titles, $project, range); 168 assert_eq!(expected, result); 169 }; 170} 171 172#[test] 173fn fix_truncated_segment_1() { 174 let name = "Replace with `1`"; 175 assert_code_action!( 176 name, 177 r#" 178pub fn main() { 179 <<1, 257, 259:size(1)>> 180}"#, 181 find_position_of("257").to_selection() 182 ); 183} 184 185#[test] 186fn fix_truncated_segment_2() { 187 let name = "Replace with `0`"; 188 assert_code_action!( 189 name, 190 r#" 191pub fn main() { 192 <<1, 1024:size(10)>> 193}"#, 194 find_position_of("size").to_selection() 195 ); 196} 197 198#[test] 199fn generate_variant_with_fields_in_same_module() { 200 assert_code_action!( 201 GENERATE_VARIANT, 202 r#" 203pub type Wibble { 204 Wibble 205} 206 207pub fn main() -> Wibble { 208 Wobble(1) 209}"#, 210 find_position_of("Wobble").to_selection() 211 ); 212} 213 214#[test] 215fn generate_variant_with_no_fields_in_same_module() { 216 assert_code_action!( 217 GENERATE_VARIANT, 218 r#" 219pub type Wibble { 220 Wibble 221} 222 223pub fn main() -> Wibble { 224 Wobble 225}"#, 226 find_position_of("Wobble").to_selection() 227 ); 228} 229 230#[test] 231fn generate_variant_with_labels_in_same_module() { 232 assert_code_action!( 233 GENERATE_VARIANT, 234 r#" 235pub type Wibble { 236 Wibble 237} 238 239pub fn main() -> Wibble { 240 Wobble("hello", label: 1) 241}"#, 242 find_position_of("Wobble").to_selection() 243 ); 244} 245 246#[test] 247fn generate_variant_from_pattern_with_fields() { 248 assert_code_action!( 249 GENERATE_VARIANT, 250 r#" 251pub type Wibble { 252 Wibble 253} 254 255pub fn new() { Wibble } 256 257pub fn main() -> Wibble { 258 let assert Wobble(1) = new() 259} 260 261"#, 262 find_position_of("Wobble").to_selection() 263 ); 264} 265 266#[test] 267fn generate_variant_from_pattern_with_labelled_fields() { 268 assert_code_action!( 269 GENERATE_VARIANT, 270 r#" 271pub type Wibble { 272 Wibble 273} 274 275pub fn new() { Wibble } 276 277pub fn main() -> Wibble { 278 let assert Wobble("hello", label: 1) = new() 279} 280 281"#, 282 find_position_of("Wobble").to_selection() 283 ); 284} 285 286#[test] 287fn generate_variant_from_pattern_with_no_fields() { 288 assert_code_action!( 289 GENERATE_VARIANT, 290 r#" 291pub type Wibble { 292 Wibble 293} 294 295pub fn new() { Wibble } 296 297pub fn main() -> Wibble { 298 let assert Wobble = new() 299} 300 301"#, 302 find_position_of("Wobble").to_selection() 303 ); 304} 305 306#[test] 307fn generate_unqualified_variant_in_other_module() { 308 let src = r#" 309import other 310 311pub fn main() -> other.Wibble { 312 let assert Wobble = new() 313} 314 315pub fn new() -> other.Wibble { todo } 316"#; 317 318 assert_code_action!( 319 GENERATE_VARIANT, 320 TestProject::for_source(src).add_module("other", "pub type Wibble"), 321 find_position_of("Wobble").to_selection() 322 ); 323} 324 325#[test] 326fn generate_qualified_variant_in_other_module() { 327 let src = r#" 328import other 329 330pub fn main() -> other.Wibble { 331 let assert other.Wobble = new() 332} 333 334pub fn new() -> other.Wibble { todo } 335"#; 336 assert_code_action!( 337 GENERATE_VARIANT, 338 TestProject::for_source(src).add_module("other", "pub type Wibble"), 339 find_position_of("Wobble").to_selection() 340 ); 341} 342 343#[test] 344fn do_not_generate_variant_if_one_with_the_same_name_exists() { 345 assert_no_code_actions!( 346 GENERATE_VARIANT, 347 r#" 348pub fn main() -> Wibble { 349 let assert Wobble = new() 350} 351 352pub type Wibble { 353 Wobble(n: Int) 354} 355 356pub fn new() -> Wibble { todo } 357"#, 358 find_position_of("Wobble").to_selection() 359 ); 360} 361 362#[test] 363fn do_not_generate_variant_if_one_with_the_same_name_exists_in_other_module() { 364 let src = r#" 365import other.{type Wibble} 366 367pub fn main() -> Wibble { 368 let assert Wobble = new() 369} 370 371pub fn new() -> Wibble { todo } 372"#; 373 assert_no_code_actions!( 374 GENERATE_VARIANT, 375 TestProject::for_source(src).add_module("other", "pub type Wibble { Wobble(String) }"), 376 find_position_of("Wobble").to_selection() 377 ); 378} 379 380#[test] 381fn do_not_generate_qualified_variant_if_one_with_the_same_name_exists_in_other_module() { 382 let src = r#" 383import other.{type Wibble} 384 385pub fn main() -> Wibble { 386 let assert other.Wobble = new() 387} 388 389pub fn new() -> Wibble { todo } 390"#; 391 assert_no_code_actions!( 392 GENERATE_VARIANT, 393 TestProject::for_source(src).add_module("other", "pub type Wibble { Wobble(String) }"), 394 find_position_of("Wobble").to_selection() 395 ); 396} 397 398#[test] 399fn fill_unused_fields_with_ignored_labelled_fields() { 400 assert_code_action!( 401 FILL_UNUSED_FIELDS, 402 r#" 403pub type Wibble { Wibble(Int, label1: String, label2: Int) } 404 405pub fn main() { 406 let Wibble(_, ..) = todo 407}"#, 408 find_position_of("..").to_selection() 409 ); 410} 411 412#[test] 413fn fill_unused_fields_with_ignored_positional_fields() { 414 assert_code_action!( 415 FILL_UNUSED_FIELDS, 416 r#" 417pub type Wibble { Wibble(Int, label1: String, label2: Int) } 418 419pub fn main() { 420 let Wibble(label1:, label2:, ..) = todo 421}"#, 422 find_position_of("..").to_selection() 423 ); 424} 425 426#[test] 427fn fill_unused_fields_with_all_positional_fields() { 428 assert_code_action!( 429 FILL_UNUSED_FIELDS, 430 r#" 431pub type Wibble { Wibble(Int, String) } 432 433pub fn main() { 434 let Wibble(..) = todo 435}"#, 436 find_position_of("..").to_selection() 437 ); 438} 439 440#[test] 441fn fill_unused_fields_with_ignored_mixed_fields() { 442 assert_code_action!( 443 FILL_UNUSED_FIELDS, 444 r#" 445pub type Wibble { Wibble(Int, String, label1: String, label2: Int) } 446 447pub fn main() { 448 let Wibble(_, label2:, ..) = todo 449}"#, 450 find_position_of("..").to_selection() 451 ); 452} 453 454#[test] 455fn fill_unused_fields_with_all_ignored_fields() { 456 assert_code_action!( 457 FILL_UNUSED_FIELDS, 458 r#" 459pub type Wibble { Wibble(Int, label1: String, label2: Int) } 460 461pub fn main() { 462 let Wibble(..) = todo 463}"#, 464 find_position_of("..").to_selection() 465 ); 466} 467 468#[test] 469fn fill_unused_fields_with_ignored_fields_never_calls_a_positional_arg_as_a_labelled_one() { 470 assert_code_action!( 471 FILL_UNUSED_FIELDS, 472 r#" 473pub type Wibble { Wibble(Int, int: Int) } 474 475pub fn main() { 476 let Wibble(..) = todo 477}"#, 478 find_position_of("..").to_selection() 479 ); 480} 481 482#[test] 483fn remove_echo() { 484 assert_code_action!( 485 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 486 "pub fn main() { 487 echo 1 + 2 488}", 489 find_position_of("echo").to_selection() 490 ); 491} 492 493#[test] 494fn remove_echo_with_message() { 495 assert_code_action!( 496 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 497 r#"pub fn main() { 498 echo 1 + 2 as "message" 499}"#, 500 find_position_of("echo").to_selection() 501 ); 502} 503 504#[test] 505fn remove_echo_with_message_and_comment() { 506 assert_code_action!( 507 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 508 r#"pub fn main() { 509 echo 1 + 2 510 // Hello! 511 as "message" 512}"#, 513 find_position_of("echo").to_selection() 514 ); 515} 516 517#[test] 518fn remove_echo_with_message_and_comment_2() { 519 assert_code_action!( 520 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 521 r#"pub fn main() { 522 echo 1 + 2 as 523 // Hello! 524 "message" 525}"#, 526 find_position_of("echo").to_selection() 527 ); 528} 529 530#[test] 531fn remove_echo_with_message_and_comment_3() { 532 assert_code_action!( 533 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 534 r#"pub fn main() { 535 echo 1 + 2 as 536 // Hello! 537 "message" 538 539 Nil 540}"#, 541 find_position_of("echo").to_selection() 542 ); 543} 544 545#[test] 546fn remove_echo_selecting_expression() { 547 assert_code_action!( 548 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 549 "pub fn main() { 550 echo 1 + 2 551}", 552 find_position_of("1").select_until(find_position_of("2")) 553 ); 554} 555 556#[test] 557fn remove_echo_selecting_message() { 558 assert_code_action!( 559 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 560 r#"pub fn main() { 561 echo 1 + 2 as "message" 562}"#, 563 find_position_of("message").to_selection() 564 ); 565} 566 567#[test] 568fn remove_echo_as_function_arg() { 569 assert_code_action!( 570 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 571 "pub fn main() { 572 wibble([], echo 1 + 2) 573}", 574 find_position_of("1").to_selection() 575 ); 576} 577 578#[test] 579fn remove_echo_in_pipeline_step() { 580 assert_code_action!( 581 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 582 "pub fn main() { 583 [1, 2, 3] 584 |> echo 585 |> wibble 586}", 587 find_position_of("echo").to_selection() 588 ); 589} 590 591#[test] 592fn remove_echo_in_pipeline_step_with_message() { 593 assert_code_action!( 594 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 595 r#"pub fn main() { 596 [1, 2, 3] 597 |> echo as message 598 |> wibble 599}"#, 600 find_position_of("echo").to_selection() 601 ); 602} 603 604#[test] 605fn remove_echo_in_single_line_pipeline_step() { 606 assert_code_action!( 607 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 608 "pub fn main() { 609 [1, 2, 3] |> echo |> wibble 610}", 611 find_position_of("echo").to_selection() 612 ); 613} 614 615#[test] 616fn remove_echo_in_single_line_pipeline_step_with_message() { 617 assert_code_action!( 618 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 619 r#"pub fn main() { 620 [1, 2, 3] |> echo as "message" |> wibble 621}"#, 622 find_position_of("echo").to_selection() 623 ); 624} 625 626#[test] 627fn remove_echo_last_in_long_pipeline_step() { 628 assert_code_action!( 629 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 630 "pub fn main() { 631 [1, 2, 3] 632 |> wibble 633 |> echo 634}", 635 find_position_of("echo").to_selection() 636 ); 637} 638 639#[test] 640fn remove_echo_last_in_long_pipeline_step_with_message() { 641 assert_code_action!( 642 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 643 r#"pub fn main() { 644 [1, 2, 3] 645 |> wibble 646 |> echo as "message" 647}"#, 648 find_position_of("echo").to_selection() 649 ); 650} 651 652#[test] 653fn remove_echo_last_in_short_pipeline_step() { 654 assert_code_action!( 655 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 656 "pub fn main() { 657 [1, 2, 3] 658 |> echo 659}", 660 find_position_of("echo").to_selection() 661 ); 662} 663 664#[test] 665fn remove_echo_last_in_short_pipeline_step_with_message() { 666 assert_code_action!( 667 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 668 r#"pub fn main() { 669 [1, 2, 3] 670 |> echo as "message" 671}"#, 672 find_position_of("echo").to_selection() 673 ); 674} 675 676#[test] 677fn remove_echo_before_pipeline() { 678 assert_code_action!( 679 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 680 "pub fn main() { 681 echo [1, 2, 3] |> wibble 682}", 683 find_position_of("echo").to_selection() 684 ); 685} 686 687#[test] 688fn remove_echo_before_pipeline_selecting_step() { 689 assert_code_action!( 690 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 691 "pub fn main() { 692 echo [1, 2, 3] |> wibble 693}", 694 find_position_of("wibble").to_selection() 695 ); 696} 697 698#[test] 699fn remove_echo_removes_all_echos() { 700 assert_code_action!( 701 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 702 "pub fn main() { 703 echo wibble(echo 1, 2) 704}", 705 find_position_of("echo").nth_occurrence(2).to_selection() 706 ); 707} 708 709#[test] 710fn remove_echo_removes_all_echos_1() { 711 assert_code_action!( 712 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 713 "pub fn main() { 714 echo 1 |> echo |> echo |> wibble |> echo 715 echo wibble(echo 1, echo 2) 716 echo 1 717}", 718 find_position_of("echo").nth_occurrence(2).to_selection() 719 ); 720} 721 722#[test] 723fn remove_echo_removes_entire_echo_statement_used_with_literals() { 724 assert_code_action!( 725 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 726 "pub fn main() { 727 echo 1 728 Nil 729}", 730 find_position_of("echo").to_selection() 731 ); 732} 733 734#[test] 735fn remove_echo_removes_entire_echo_statement_used_with_literals_and_message() { 736 assert_code_action!( 737 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 738 r#"pub fn main() { 739 echo 1 as "message" 740 Nil 741}"#, 742 find_position_of("echo").to_selection() 743 ); 744} 745 746#[test] 747fn remove_echo_removes_entire_echo_statement_used_with_a_var() { 748 assert_code_action!( 749 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 750 "pub fn main() { 751 let a = 1 752 echo a 753 Nil 754}", 755 find_position_of("echo").to_selection() 756 ); 757} 758 759#[test] 760fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals() { 761 assert_code_action!( 762 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 763 r#"pub fn main() { 764 echo 1 765 echo "wibble" 766 Nil 767}"#, 768 find_position_of("echo").to_selection() 769 ); 770} 771 772#[test] 773fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_but_stops_at_comments() { 774 assert_code_action!( 775 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 776 r#"pub fn main() { 777 echo 1 778 779 // Oh no I hope I'm not deleted by the code action!! 780 Nil 781}"#, 782 find_position_of("echo").to_selection() 783 ); 784} 785 786#[test] 787fn remove_echo_removes_entire_echo_statement_used_with_literals_in_a_fn() { 788 assert_code_action!( 789 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 790 "pub fn main() { 791 fn() { 792 echo 1 793 Nil 794 } 795}", 796 find_position_of("echo").to_selection() 797 ); 798} 799 800#[test] 801fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_in_a_fn() { 802 assert_code_action!( 803 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 804 r#"pub fn main() { 805 fn() { 806 echo 1 807 echo "wibble" 808 Nil 809 } 810}"#, 811 find_position_of("echo").to_selection() 812 ); 813} 814 815#[test] 816fn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return() { 817 assert_code_action!( 818 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 819 "pub fn main() { 820 echo 1 821}", 822 find_position_of("echo").to_selection() 823 ); 824} 825 826#[test] 827fn remove_echo_with_message_removes_does_not_remove_entire_echo_statement_if_its_the_return() { 828 assert_code_action!( 829 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 830 r#"pub fn main() { 831 echo 1 as "message" 832}"#, 833 find_position_of("echo").to_selection() 834 ); 835} 836 837#[test] 838fn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return_of_a_fn() { 839 assert_code_action!( 840 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 841 r#"pub fn main() { 842 fn() { 843 echo 1 844 } 845}"#, 846 find_position_of("echo").to_selection() 847 ); 848} 849 850#[test] 851fn split_string() { 852 assert_code_action!( 853 INTERPOLATE_STRING, 854 r#"pub fn main() { 855 "wibble wobble woo" 856}"#, 857 find_position_of("wobble").to_selection() 858 ); 859} 860 861#[test] 862fn no_split_string_right_at_the_start() { 863 assert_no_code_actions!( 864 INTERPOLATE_STRING, 865 r#"pub fn main() { 866 "wibble wobble woo" 867}"#, 868 find_position_of("wibble").to_selection() 869 ); 870} 871 872#[test] 873fn no_split_string_right_at_the_end() { 874 assert_no_code_actions!( 875 INTERPOLATE_STRING, 876 r#"pub fn main() { 877 "wibble wobble woo" 878}"#, 879 find_position_of("\"").nth_occurrence(2).to_selection() 880 ); 881} 882 883#[test] 884fn no_split_string_before_the_start() { 885 assert_no_code_actions!( 886 INTERPOLATE_STRING, 887 r#"pub fn main() { 888 "wibble wobble woo" 889}"#, 890 find_position_of("\"").to_selection() 891 ); 892} 893 894#[test] 895fn no_split_string_after_the_end() { 896 assert_no_code_actions!( 897 INTERPOLATE_STRING, 898 r#"pub fn main() { 899 "wibble wobble woo"//we need this comment so we can put the cursor _after_ the closing quote 900}"#, 901 find_position_of("\"/").under_last_char().to_selection() 902 ); 903} 904 905#[test] 906fn interpolate_string_inside_string() { 907 assert_code_action!( 908 INTERPOLATE_STRING, 909 r#"pub fn main() { 910 "wibble wobble woo" 911}"#, 912 find_position_of("wobble").select_until(find_position_of("wobble ").under_last_char()), 913 ); 914} 915 916#[test] 917fn fallback_to_split_string_when_selecting_invalid_name() { 918 assert_code_action!( 919 INTERPOLATE_STRING, 920 r#"pub fn main() { 921 "wibble wobble woo woo" 922}"#, 923 find_position_of("wobble").select_until(find_position_of("woo ").under_last_char()), 924 ); 925} 926 927#[test] 928fn splitting_string_as_first_pipeline_step_inserts_brackets() { 929 assert_code_action!( 930 INTERPOLATE_STRING, 931 r#"pub fn main() { 932 "wibble wobble" |> io.println 933}"#, 934 find_position_of(" wobble").to_selection(), 935 ); 936} 937 938#[test] 939fn interpolating_string_as_first_pipeline_step_inserts_brackets() { 940 assert_code_action!( 941 INTERPOLATE_STRING, 942 r#"pub fn main() { 943 "wibble wobble woo" |> io.println 944}"#, 945 find_position_of("wobble ").select_until(find_position_of("wobble ").under_last_char()), 946 ); 947} 948 949#[test] 950fn test_remove_unused_simple() { 951 let src = " 952// test 953import // comment 954list as lispy 955import result 956import option 957 958pub fn main() { 959 result.is_ok 960} 961"; 962 963 assert_code_action!( 964 REMOVE_UNUSED_IMPORTS, 965 TestProject::for_source(src) 966 .add_hex_module("list", "") 967 .add_hex_module("result", "") 968 .add_hex_module("option", ""), 969 find_position_of("// test").select_until(find_position_of("option")), 970 ); 971} 972 973#[test] 974fn test_remove_unused_start_of_file() { 975 let src = "import option 976import result 977 978pub fn main() { 979 result.is_ok 980} 981"; 982 assert_code_action!( 983 REMOVE_UNUSED_IMPORTS, 984 TestProject::for_source(src) 985 .add_hex_module("option", "") 986 .add_hex_module("result", ""), 987 find_position_of("import").select_until(find_position_of("pub")), 988 ); 989} 990 991#[test] 992fn test_remove_unused_alias() { 993 let src = " 994// test 995import result.{is_ok} as res 996import option 997 998pub fn main() { 999 is_ok 1000} 1001"; 1002 assert_code_action!( 1003 REMOVE_UNUSED_IMPORTS, 1004 TestProject::for_source(src) 1005 .add_hex_module("result", "pub fn is_ok() {}") 1006 .add_hex_module("option", ""), 1007 find_position_of("// test").select_until(find_position_of("pub")), 1008 ); 1009} 1010 1011#[test] 1012fn test_remove_unused_value() { 1013 let src = " 1014// test 1015import result.{is_ok} 1016import option 1017 1018pub fn main() { 1019 result.is_ok 1020} 1021"; 1022 assert_code_action!( 1023 REMOVE_UNUSED_IMPORTS, 1024 TestProject::for_source(src) 1025 .add_hex_module("result", "pub fn is_ok() {}") 1026 .add_hex_module("option", ""), 1027 find_position_of("// test").select_until(find_position_of("pub")), 1028 ); 1029} 1030 1031#[test] 1032fn test_remove_aliased_unused_value() { 1033 let src = " 1034// test 1035import result.{is_ok as ok} 1036import option 1037 1038pub fn main() { 1039 result.is_ok 1040} 1041"; 1042 assert_code_action!( 1043 REMOVE_UNUSED_IMPORTS, 1044 TestProject::for_source(src) 1045 .add_hex_module("result", "pub fn is_ok() {}") 1046 .add_hex_module("option", ""), 1047 find_position_of("// test").select_until(find_position_of("pub")), 1048 ); 1049} 1050 1051#[test] 1052fn test_remove_multiple_unused_values() { 1053 let src = " 1054// test 1055import result.{type Unused, used, unused, unused_again, type Used, used_again} 1056 1057pub fn main(x: Used) { 1058 #(used, used_again) 1059} 1060"; 1061 assert_code_action!( 1062 REMOVE_UNUSED_IMPORTS, 1063 TestProject::for_source(src).add_hex_module( 1064 "result", 1065 " 1066pub const used = 1 1067pub const unused = 2 1068pub const unused_again = 3 1069pub const used_again = 4 1070pub type Unused 1071pub type Used 1072" 1073 ), 1074 find_position_of("// test").select_until(find_position_of("pub")), 1075 ); 1076} 1077 1078#[test] 1079fn test_remove_multiple_unused_values_2() { 1080 let src = " 1081// test 1082import result.{type Unused, used, unused, type Used, unused_again} 1083 1084pub fn main(x: Used) { 1085 used 1086} 1087"; 1088 assert_code_action!( 1089 REMOVE_UNUSED_IMPORTS, 1090 TestProject::for_source(src).add_hex_module( 1091 "result", 1092 " 1093pub const used = 1 1094pub const unused = 2 1095pub const unused_again = 3 1096pub type Unused 1097pub type Used 1098" 1099 ), 1100 find_position_of("// test").select_until(find_position_of("pub")), 1101 ); 1102} 1103 1104#[test] 1105fn test_remove_entire_unused_import() { 1106 let src = " 1107// test 1108import result.{unused, unused_again} 1109 1110pub fn main() { 1111 todo 1112} 1113"; 1114 assert_code_action!( 1115 REMOVE_UNUSED_IMPORTS, 1116 TestProject::for_source(src).add_hex_module( 1117 "result", 1118 " 1119pub const used = 1 1120pub const unused = 2 1121pub const unused_again = 3 1122pub type Unused 1123pub type Used 1124" 1125 ), 1126 find_position_of("// test").select_until(find_position_of("pub")), 1127 ); 1128} 1129 1130#[test] 1131fn test_remove_redundant_tuple_in_case_subject_simple() { 1132 assert_code_action!( 1133 REMOVE_REDUNDANT_TUPLES, 1134 "pub fn main() { 1135 case #(1) { #(a) -> 0 } 1136 case #(1, 2) { #(a, b) -> 0 } 1137}", 1138 find_position_of("case").select_until(find_position_of("#(1, 2)").under_last_char()) 1139 ); 1140} 1141 1142#[test] 1143fn test_remove_redundant_tuple_with_catch_all_pattern() { 1144 assert_code_action!( 1145 REMOVE_REDUNDANT_TUPLES, 1146 "pub fn main() { 1147 case #(1, 2) { 1148 #(1, 2) -> 0 1149 _ -> 1 1150 } 1151}", 1152 find_position_of("case").select_until(find_position_of("#(1, 2)").under_last_char()) 1153 ); 1154} 1155 1156#[test] 1157fn test_remove_multiple_redundant_tuple_with_catch_all_pattern() { 1158 assert_code_action!( 1159 REMOVE_REDUNDANT_TUPLES, 1160 "pub fn main() { 1161 case #(1, 2), #(3, 4) { 1162 #(2, 2), #(2, 2) -> 0 1163 #(1, 2), _ -> 0 1164 _, #(1, 2) -> 0 1165 _, _ -> 1 1166 } 1167}", 1168 find_position_of("case").select_until(find_position_of("#(3, 4)")) 1169 ); 1170} 1171 1172#[test] 1173fn test_remove_redundant_tuple_in_case_subject_nested() { 1174 assert_code_action!( 1175 REMOVE_REDUNDANT_TUPLES, 1176 "pub fn main() { 1177 case #(case #(0) { #(a) -> 0 }) { #(b) -> 0 } 1178}", 1179 find_position_of("case").select_until(find_position_of("#(b)")) 1180 ); 1181} 1182 1183#[test] 1184fn test_remove_redundant_tuple_in_case_retain_extras() { 1185 assert_code_action!( 1186 REMOVE_REDUNDANT_TUPLES, 1187 " 1188pub fn main() { 1189 case 1190 #( 1191 // first comment 1192 1, 1193 // second comment 1194 2, 1195 3 // third comment before comma 1196 1197 , 1198 1199 // fourth comment after comma 1200 1201 ) 1202 { 1203 #( 1204 // first comment 1205 a, 1206 // second comment 1207 b, 1208 c // third comment before comma 1209 1210 , 1211 1212 // fourth comment after comma 1213 1214 ) -> 0 1215 } 1216} 1217", 1218 find_position_of("#").select_until(find_position_of("// first")) 1219 ); 1220} 1221 1222#[test] 1223fn test_remove_redundant_tuple_in_case_subject_ignore_empty_tuple() { 1224 assert_no_code_actions!( 1225 REMOVE_REDUNDANT_TUPLES, 1226 " 1227pub fn main() { 1228 case #() { #() -> 0 } 1229} 1230", 1231 find_position_of("case").select_until(find_position_of("0")) 1232 ); 1233} 1234 1235#[test] 1236fn test_remove_redundant_tuple_in_case_subject_only_safe_remove() { 1237 assert_code_action!( 1238 REMOVE_REDUNDANT_TUPLES, 1239 " 1240pub fn main() { 1241 case #(0), #(1) { 1242 #(1), #(b) -> 0 1243 a, #(0) -> 1 // The first of this clause is not a tuple 1244 #(a), #(b) -> 2 1245 } 1246} 1247", 1248 find_position_of("#(0)").select_until(find_position_of("#(1)")) 1249 ); 1250} 1251 1252#[test] 1253fn rename_invalid_const() { 1254 assert_code_action!( 1255 "Rename to my_invalid_constant", 1256 "const myInvalid_Constant = 42", 1257 find_position_of("_Constant").to_selection(), 1258 ); 1259} 1260 1261#[test] 1262fn rename_invalid_parameter() { 1263 assert_code_action!( 1264 "Rename to num_a", 1265 "fn add(numA: Int, num_b: Int) { numA + num_b }", 1266 find_position_of("numA").to_selection() 1267 ); 1268} 1269 1270#[test] 1271fn rename_invalid_parameter_name2() { 1272 assert_code_action!( 1273 "Rename to param_name", 1274 "fn pass(label paramName: Bool) { paramName }", 1275 find_position_of("paramName").to_selection() 1276 ); 1277} 1278 1279#[test] 1280fn rename_invalid_parameter_name3() { 1281 assert_code_action!( 1282 "Rename to num_a", 1283 "pub fn main() { 1284 let add = fn(numA: Int, num_b: Int) { numA + num_b } 1285}", 1286 find_position_of("let add").select_until(find_position_of("num_b")) 1287 ); 1288} 1289 1290#[test] 1291fn rename_invalid_parameter_discard() { 1292 assert_code_action!( 1293 "Rename to _ignore_me", 1294 "fn ignore(_ignoreMe: Bool) { 98 }", 1295 find_position_of("ignore").select_until(find_position_of("98")) 1296 ); 1297} 1298 1299#[test] 1300fn rename_invalid_parameter_discard_name2() { 1301 assert_code_action!( 1302 "Rename to _ignore_me", 1303 "fn ignore(labelled_discard _ignoreMe: Bool) { 98 }", 1304 find_position_of("ignore").select_until(find_position_of("98")) 1305 ); 1306} 1307 1308#[test] 1309fn rename_invalid_parameter_discard_name3() { 1310 assert_code_action!( 1311 "Rename to _ignore_me", 1312 "pub fn main() { 1313 let ignore = fn(_ignoreMe: Bool) { 98 } 1314}", 1315 find_position_of("ignore").select_until(find_position_of("98")) 1316 ); 1317} 1318 1319#[test] 1320fn rename_invalid_parameter_label() { 1321 assert_code_action!( 1322 "Rename to this_is_a_label", 1323 "fn func(thisIsALabel param: Int) { param }", 1324 find_position_of("thisIs").select_until(find_position_of("Int")) 1325 ); 1326} 1327 1328#[test] 1329fn rename_invalid_parameter_label2() { 1330 assert_code_action!( 1331 "Rename to this_is_a_label", 1332 "fn ignore(thisIsALabel _ignore: Int) { 25 }", 1333 find_position_of("thisIs").under_char('i').to_selection() 1334 ); 1335} 1336 1337#[test] 1338fn rename_invalid_constructor() { 1339 assert_code_action!( 1340 "Rename to TheConstructor", 1341 "type MyType { The_Constructor(Int) }", 1342 find_position_of("The_").under_char('h').to_selection(), 1343 ); 1344} 1345 1346#[test] 1347fn rename_invalid_constructor_arg() { 1348 assert_code_action!( 1349 "Rename to inner_int", 1350 "type IntWrapper { IntWrapper(innerInt: Int) }", 1351 find_position_of("IntWrapper") 1352 .nth_occurrence(2) 1353 .select_until(find_position_of(": Int")) 1354 ); 1355} 1356 1357#[test] 1358fn rename_invalid_custom_type() { 1359 assert_code_action!( 1360 "Rename to BoxedValue", 1361 "type Boxed_value { Box(Int) }", 1362 find_position_of("Box").select_until(find_position_of("_value")) 1363 ); 1364} 1365 1366#[test] 1367fn rename_invalid_type_alias() { 1368 assert_code_action!( 1369 "Rename to FancyBool", 1370 "type Fancy_Bool = Bool", 1371 find_position_of("Fancy") 1372 .under_char('a') 1373 .select_until(find_position_of("=")) 1374 ); 1375} 1376 1377#[test] 1378fn rename_invalid_function() { 1379 assert_code_action!( 1380 "Rename to do_stuff", 1381 "fn doStuff() {}", 1382 find_position_of("fn").select_until(find_position_of("{}")) 1383 ); 1384} 1385 1386#[test] 1387fn rename_invalid_variable() { 1388 assert_code_action!( 1389 "Rename to the_answer", 1390 "pub fn main() { 1391 let theAnswer = 42 1392}", 1393 find_position_of("theAnswer").select_until(find_position_of("Answer")) 1394 ); 1395} 1396 1397#[test] 1398fn rename_invalid_variable_discard() { 1399 assert_code_action!( 1400 "Rename to _boring_number", 1401 "pub fn main() { 1402 let _boringNumber = 72 1403}", 1404 find_position_of("let").select_until(find_position_of("72")) 1405 ); 1406} 1407 1408#[test] 1409fn rename_invalid_use() { 1410 assert_code_action!( 1411 "Rename to use_var", 1412 "fn use_test(f) { f(Nil) } 1413pub fn main() {use useVar <- use_test()}", 1414 find_position_of("use") 1415 .nth_occurrence(2) 1416 .select_until(find_position_of("use_test()")) 1417 ); 1418} 1419 1420#[test] 1421fn rename_invalid_use_discard() { 1422 assert_code_action!( 1423 "Rename to _discard_var", 1424 "fn use_test(f) { f(Nil) } 1425pub fn main() {use _discardVar <- use_test()}", 1426 find_position_of("_discardVar") 1427 .under_last_char() 1428 .to_selection() 1429 ); 1430} 1431 1432#[test] 1433fn rename_invalid_pattern_assignment() { 1434 assert_code_action!( 1435 "Rename to the_answer", 1436 "pub fn main() { 1437 let assert 42 as theAnswer = 42 1438}", 1439 find_position_of("let").select_until(find_position_of("= 42")) 1440 ); 1441} 1442 1443#[test] 1444fn rename_invalid_list_pattern() { 1445 assert_code_action!( 1446 "Rename to the_element", 1447 "pub fn main() { 1448 let assert [theElement] = [9.4] 1449}", 1450 find_position_of("assert").select_until(find_position_of("9.4")) 1451 ); 1452} 1453 1454#[test] 1455fn rename_invalid_list_pattern_discard() { 1456 assert_code_action!( 1457 "Rename to _elem_one", 1458 "pub fn main() { 1459 let assert [_elemOne] = [False] 1460}", 1461 find_position_of("[_elemOne]") 1462 .under_char('O') 1463 .to_selection() 1464 ); 1465} 1466 1467#[test] 1468fn rename_invalid_constructor_pattern() { 1469 assert_code_action!( 1470 "Rename to inner_value", 1471 "pub type Box { Box(Int) } 1472pub fn main() { 1473 let Box(innerValue) = Box(203) 1474}", 1475 find_position_of("innerValue").to_selection() 1476 ); 1477} 1478 1479#[test] 1480fn rename_invalid_constructor_pattern_discard() { 1481 assert_code_action!( 1482 "Rename to _ignored_inner", 1483 "pub type Box { Box(Int) } 1484pub fn main() { 1485 let Box(_ignoredInner) = Box(203) 1486}", 1487 find_position_of("_").select_until(find_position_of("203")) 1488 ); 1489} 1490 1491#[test] 1492fn rename_invalid_tuple_pattern() { 1493 assert_code_action!( 1494 "Rename to second_value", 1495 "pub fn main() { 1496 let #(a, secondValue) = #(1, 2) 1497}", 1498 find_position_of("secondValue") 1499 .select_until(find_position_of("secondValue").under_char('n')) 1500 ); 1501} 1502 1503#[test] 1504fn rename_invalid_tuple_pattern_discard() { 1505 assert_code_action!( 1506 "Rename to _second_value", 1507 "pub fn main() { 1508 let #(a, _secondValue) = #(1, 2) 1509}", 1510 find_position_of("_secondValue") 1511 .under_char('_') 1512 .select_until(find_position_of("#(1, 2)")) 1513 ); 1514} 1515 1516#[test] 1517fn rename_invalid_bit_array_pattern() { 1518 assert_code_action!( 1519 "Rename to bit_value", 1520 "pub fn main() { 1521 let assert <<bitValue>> = <<73>> 1522}", 1523 find_position_of("<<").select_until(find_position_of(">>")) 1524 ); 1525} 1526 1527#[test] 1528fn rename_invalid_bit_array_pattern_discard() { 1529 assert_code_action!( 1530 "Rename to _i_dont_care", 1531 "pub fn main() { 1532 let assert <<_iDontCare>> = <<97>> 1533}", 1534 find_position_of("<<").select_until(find_position_of("Care")) 1535 ); 1536} 1537 1538#[test] 1539fn rename_invalid_string_prefix_pattern() { 1540 assert_code_action!( 1541 "Rename to cool_suffix", 1542 r#"pub fn main() { 1543 let assert "prefix" <> coolSuffix = "prefix-suffix" 1544}"#, 1545 find_position_of("<>").select_until(find_position_of("-suffix")) 1546 ); 1547} 1548 1549#[test] 1550fn rename_invalid_string_prefix_pattern_discard() { 1551 assert_code_action!( 1552 "Rename to _boring_suffix", 1553 r#"pub fn main() { 1554 let assert "prefix" <> _boringSuffix = "prefix-suffix" 1555}"#, 1556 find_position_of("<>").select_until(find_position_of("Suffix")) 1557 ); 1558} 1559 1560#[test] 1561fn rename_invalid_string_prefix_pattern_alias() { 1562 assert_code_action!( 1563 "Rename to the_prefix", 1564 r#"pub fn main() { 1565 let assert "prefix" as thePrefix <> _suffix = "prefix-suffix" 1566}"#, 1567 find_position_of("prefix").select_until(find_position_of("-suffix")) 1568 ); 1569} 1570 1571#[test] 1572fn rename_invalid_case_variable() { 1573 assert_code_action!( 1574 "Rename to twenty_one", 1575 "pub fn main() { 1576 case 21 { twentyOne -> {Nil} } 1577}", 1578 find_position_of("case").select_until(find_position_of("Nil")) 1579 ); 1580} 1581 1582#[test] 1583fn rename_invalid_case_variable_discard() { 1584 assert_code_action!( 1585 "Rename to _twenty_one", 1586 "pub fn main() { 1587 case 21 { _twentyOne -> {Nil} } 1588}", 1589 find_position_of("21").select_until(find_position_of("->")) 1590 ); 1591} 1592 1593#[test] 1594fn rename_invalid_type_parameter_name() { 1595 assert_code_action!( 1596 "Rename to inner_type", 1597 "type Wrapper(innerType) {}", 1598 find_position_of("innerType").select_until(find_position_of(")")) 1599 ); 1600} 1601 1602#[test] 1603fn rename_invalid_type_alias_parameter_name() { 1604 assert_code_action!( 1605 "Rename to phantom_type", 1606 "type Phantom(phantomType) = Int", 1607 find_position_of("phantomType").select_until(find_position_of(")")) 1608 ); 1609} 1610 1611#[test] 1612fn rename_invalid_function_type_parameter_name() { 1613 assert_code_action!( 1614 "Rename to some_type", 1615 "fn identity(value: someType) { value }", 1616 find_position_of("someType").select_until(find_position_of(")")) 1617 ); 1618} 1619 1620#[test] 1621fn test_convert_assert_result_to_case() { 1622 assert_code_action!( 1623 CONVERT_TO_CASE, 1624 "pub fn main() { 1625 let assert Ok(value) = Ok(1) 1626}", 1627 find_position_of("assert").select_until(find_position_of("assert").under_char('r')), 1628 ); 1629} 1630 1631#[test] 1632fn test_convert_let_assert_to_case_indented() { 1633 assert_code_action!( 1634 CONVERT_TO_CASE, 1635 "pub fn main() { 1636 { 1637 let assert Ok(value) = Ok(1) 1638 } 1639}", 1640 find_position_of("Ok").to_selection() 1641 ); 1642} 1643 1644#[test] 1645fn test_convert_let_assert_to_case_multi_variables() { 1646 assert_code_action!( 1647 CONVERT_TO_CASE, 1648 "pub fn main() { 1649 let assert [var1, var2, _var3, var4] = [1, 2, 3, 4] 1650}", 1651 find_position_of("var1").select_until(find_position_of("_var").under_last_char()) 1652 ); 1653} 1654 1655#[test] 1656fn test_convert_let_assert_to_case_discard() { 1657 assert_code_action!( 1658 CONVERT_TO_CASE, 1659 "pub fn main() { 1660 let assert [_elem] = [6] 1661}", 1662 find_position_of("assert").select_until(find_position_of("[6]").under_last_char()), 1663 ); 1664} 1665 1666#[test] 1667fn test_convert_let_assert_to_case_no_variables() { 1668 assert_code_action!( 1669 CONVERT_TO_CASE, 1670 "pub fn main() { 1671 let assert [] = [] 1672}", 1673 find_position_of("[]").to_selection(), 1674 ); 1675} 1676 1677#[test] 1678fn test_convert_let_assert_alias_to_case() { 1679 assert_code_action!( 1680 CONVERT_TO_CASE, 1681 "pub fn main() { 1682 let assert 10 as ten = 10 1683}", 1684 find_position_of("as").select_until(find_position_of("ten")), 1685 ); 1686} 1687 1688#[test] 1689fn test_convert_let_assert_tuple_to_case() { 1690 assert_code_action!( 1691 CONVERT_TO_CASE, 1692 "pub fn main() { 1693 let assert #(first, 10, third) = #(5, 10, 15) 1694} 1695", 1696 find_position_of("let").to_selection(), 1697 ); 1698} 1699 1700#[test] 1701fn test_convert_let_assert_bit_array_to_case() { 1702 assert_code_action!( 1703 CONVERT_TO_CASE, 1704 "pub fn main() { 1705 let assert <<bits1, bits2>> = <<73, 98>> 1706}", 1707 find_position_of("bits").select_until(find_position_of("2")), 1708 ); 1709} 1710 1711#[test] 1712fn test_convert_let_assert_string_prefix_to_case() { 1713 assert_code_action!( 1714 CONVERT_TO_CASE, 1715 r#"pub fn main() { 1716 let assert "_" <> thing = "_Hello" 1717}"#, 1718 find_position_of("_").to_selection() 1719 ); 1720} 1721 1722#[test] 1723fn test_convert_let_assert_string_prefix_pattern_alias_to_case() { 1724 assert_code_action!( 1725 CONVERT_TO_CASE, 1726 r#"pub fn main() { 1727 let assert "123" as one_two_three <> rest = "123456" 1728}"#, 1729 find_position_of("123").select_until(find_position_of("123456")), 1730 ); 1731} 1732 1733#[test] 1734fn test_convert_inner_let_assert_to_case() { 1735 assert_code_action!( 1736 CONVERT_TO_CASE, 1737 r#"pub fn main() { 1738 let assert [wibble] = { 1739 let assert Ok(wobble) = { 1740 Ok(1) 1741 } 1742 [wobble] 1743 } 1744}"#, 1745 find_position_of("wobble").under_char('l').to_selection() 1746 ); 1747} 1748 1749#[test] 1750fn test_convert_outer_let_assert_to_case() { 1751 assert_code_action!( 1752 CONVERT_TO_CASE, 1753 r#"pub fn main() { 1754 let assert [wibble] = { 1755 let assert Ok(wobble) = { 1756 Ok(1) 1757 } 1758 [wobble] 1759 } 1760}"#, 1761 find_position_of("wibble") 1762 .under_char('i') 1763 .select_until(find_position_of("= {")), 1764 ); 1765} 1766 1767#[test] 1768fn test_convert_let_assert_with_message_to_case() { 1769 assert_code_action!( 1770 CONVERT_TO_CASE, 1771 r#" 1772pub fn expect(value, message) { 1773 let assert Ok(inner) = value as message 1774 inner 1775} 1776"#, 1777 find_position_of("assert").select_until(find_position_of("=")), 1778 ); 1779} 1780 1781#[test] 1782fn test_convert_assert_custom_type_with_label_shorthands_to_case() { 1783 assert_code_action!( 1784 CONVERT_TO_CASE, 1785 " 1786pub type Wibble { Wibble(arg: Int, arg2: Float) } 1787pub fn main() { 1788 let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0) 1789} 1790", 1791 find_position_of("arg2:,").select_until(find_position_of("1.0")), 1792 ); 1793} 1794 1795#[test] 1796fn label_shorthand_action_works_on_labelled_call_args() { 1797 assert_code_action!( 1798 USE_LABEL_SHORTHAND_SYNTAX, 1799 r#" 1800pub fn main() { 1801 let arg1 = 1 1802 let arg2 = 2 1803 wibble(arg2: arg2, arg1: arg1) 1804} 1805 1806pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 1807"#, 1808 find_position_of("wibble") 1809 .under_char('i') 1810 .select_until(find_position_of("arg1: arg1")), 1811 ); 1812} 1813 1814#[test] 1815fn label_shorthand_action_works_on_labelled_constructor_call_args() { 1816 assert_code_action!( 1817 USE_LABEL_SHORTHAND_SYNTAX, 1818 r#" 1819pub fn main() { 1820 let arg1 = 1 1821 let arg2 = 2 1822 Wibble(arg2: arg2, arg1: arg1) 1823} 1824 1825pub type Wibble { Wibble(arg1: Int, arg2: Int) } 1826"#, 1827 find_position_of("Wibble").select_until(find_position_of("arg1: arg1").under_char(':')), 1828 ); 1829} 1830 1831#[test] 1832fn label_shorthand_action_only_applies_to_selected_args() { 1833 assert_code_action!( 1834 USE_LABEL_SHORTHAND_SYNTAX, 1835 r#" 1836pub fn main() { 1837 let arg1 = 1 1838 let arg2 = 2 1839 Wibble(arg2: arg2, arg1: arg1) 1840} 1841 1842pub type Wibble { Wibble(arg1: Int, arg2: Int) } 1843"#, 1844 find_position_of("Wibble").select_until(find_position_of("arg2: arg2").under_char(':')), 1845 ); 1846} 1847 1848#[test] 1849fn label_shorthand_action_works_on_labelled_update_call_args() { 1850 assert_code_action!( 1851 USE_LABEL_SHORTHAND_SYNTAX, 1852 r#" 1853pub fn main() { 1854 let arg1 = 1 1855 Wibble(..todo, arg1: arg1) 1856} 1857 1858pub type Wibble { Wibble(arg1: Int, arg2: Int) } 1859"#, 1860 find_position_of("..todo").select_until(find_position_of("arg1: arg1").under_last_char()), 1861 ); 1862} 1863 1864#[test] 1865fn label_shorthand_action_works_on_labelled_pattern_call_args() { 1866 assert_code_action!( 1867 USE_LABEL_SHORTHAND_SYNTAX, 1868 r#" 1869pub fn main() { 1870 let Wibble(arg1: arg1, arg2: arg2) = todo 1871 arg1 + arg2 1872} 1873 1874pub type Wibble { Wibble(arg1: Int, arg2: Int) } 1875"#, 1876 find_position_of("let").select_until(find_position_of("todo").under_last_char()), 1877 ); 1878} 1879 1880#[test] 1881fn label_shorthand_action_doesnt_come_up_for_arguments_with_different_label() { 1882 assert_no_code_actions!( 1883 USE_LABEL_SHORTHAND_SYNTAX, 1884 r#" 1885pub fn main() { 1886 let Wibble(arg1: arg_1, arg2: arg_2) = todo 1887 arg_1 + arg_2 1888} 1889 1890pub type Wibble { Wibble(arg1: Int, arg2: Int) } 1891"#, 1892 find_position_of("arg_1").select_until(find_position_of("arg_2").under_last_char()) 1893 ); 1894} 1895 1896#[test] 1897fn fill_in_labelled_args_with_some_arguments_already_supplied() { 1898 assert_code_action!( 1899 FILL_LABELS, 1900 r#" 1901pub fn main() { 1902 wibble(1,) 1903} 1904 1905pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 1906 "#, 1907 find_position_of("wibble(").under_char('b').to_selection(), 1908 ); 1909} 1910 1911#[test] 1912fn fill_in_labelled_args_with_some_arguments_already_supplied_2() { 1913 assert_code_action!( 1914 FILL_LABELS, 1915 r#" 1916pub fn main() { 1917 wibble(arg2: 1) 1918} 1919 1920pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 1921 "#, 1922 find_position_of("wibble(").to_selection(), 1923 ); 1924} 1925 1926#[test] 1927fn fill_in_labelled_args_with_some_arguments_already_supplied_3() { 1928 assert_code_action!( 1929 FILL_LABELS, 1930 r#" 1931pub fn main() { 1932 wibble(1, arg3: 2) 1933} 1934 1935pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil } 1936 "#, 1937 find_position_of("wibble(").to_selection(), 1938 ); 1939} 1940 1941#[test] 1942fn fill_in_labelled_args_works_with_regular_function() { 1943 assert_code_action!( 1944 FILL_LABELS, 1945 r#" 1946pub fn main() { 1947 wibble() 1948} 1949 1950pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 1951 "#, 1952 find_position_of("wibble(").to_selection(), 1953 ); 1954} 1955 1956#[test] 1957fn fill_in_labelled_args_works_with_record_constructor() { 1958 assert_code_action!( 1959 FILL_LABELS, 1960 r#" 1961pub fn main() { 1962 Wibble() 1963} 1964 1965pub type Wibble { Wibble(arg1: Int, arg2: String) } 1966 "#, 1967 find_position_of("Wibble").select_until(find_position_of("Wibble()").under_last_char()), 1968 ); 1969} 1970 1971#[test] 1972fn fill_in_labelled_args_works_with_pipes() { 1973 assert_code_action!( 1974 FILL_LABELS, 1975 r#" 1976pub fn main() { 1977 1 |> wibble() 1978} 1979 1980pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 1981 "#, 1982 find_position_of("wibble()") 1983 .under_last_char() 1984 .to_selection(), 1985 ); 1986} 1987 1988#[test] 1989fn fill_in_labelled_args_works_with_pipes_2() { 1990 assert_code_action!( 1991 FILL_LABELS, 1992 r#" 1993pub fn main() { 1994 1 |> wibble() 1995} 1996 1997pub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil } 1998 "#, 1999 find_position_of("wibble()") 2000 .under_last_char() 2001 .to_selection(), 2002 ); 2003} 2004 2005#[test] 2006fn fill_in_labelled_args_works_with_use() { 2007 assert_code_action!( 2008 FILL_LABELS, 2009 r#" 2010pub fn main() { 2011 use <- wibble() 2012 todo 2013} 2014 2015pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2016 "#, 2017 find_position_of("wibble(").select_until(find_position_of("wibble()").under_last_char()), 2018 ); 2019} 2020 2021#[test] 2022fn fill_in_labelled_args_works_with_use_2() { 2023 assert_code_action!( 2024 FILL_LABELS, 2025 r#" 2026pub fn main() { 2027 use <- wibble(arg1: 1) 2028 todo 2029} 2030 2031pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil } 2032 "#, 2033 find_position_of("wibble(").select_until(find_position_of("1").under_last_char()), 2034 ); 2035} 2036 2037#[test] 2038fn fill_in_labelled_args_works_with_use_3() { 2039 assert_code_action!( 2040 FILL_LABELS, 2041 r#" 2042pub fn main() { 2043 use <- wibble(arg2: 2) 2044 todo 2045} 2046 2047pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil } 2048 "#, 2049 find_position_of("wibble(").select_until(find_position_of("2").under_last_char()), 2050 ); 2051} 2052 2053#[test] 2054fn fill_in_labelled_args_selects_innermost_function() { 2055 assert_code_action!( 2056 FILL_LABELS, 2057 r#" 2058pub fn main() { 2059 wibble( 2060 wibble() 2061 ) 2062} 2063 2064pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2065 "#, 2066 find_position_of("wibble()") 2067 .under_last_char() 2068 .to_selection(), 2069 ); 2070} 2071 2072#[test] 2073fn use_label_shorthand_works_for_nested_calls() { 2074 assert_code_action!( 2075 USE_LABEL_SHORTHAND_SYNTAX, 2076 r#" 2077pub fn wibble(arg arg: Int) -> Int { arg } 2078 2079pub fn main() { 2080 let arg = 1 2081 wibble(wibble(arg: arg)) 2082} 2083 "#, 2084 find_position_of("main").select_until(find_position_of("}").nth_occurrence(2)), 2085 ); 2086} 2087 2088#[test] 2089fn use_label_shorthand_works_for_nested_record_updates() { 2090 assert_code_action!( 2091 USE_LABEL_SHORTHAND_SYNTAX, 2092 r#" 2093pub type Wibble { Wibble(arg: Int, arg2: Wobble) } 2094pub type Wobble { Wobble(arg: Int, arg2: String) } 2095 2096pub fn main() { 2097 let arg = 1 2098 let arg2 = "a" 2099 Wibble(..todo, arg2: Wobble(arg: arg, arg2: arg2)) 2100} 2101 "#, 2102 find_position_of("todo").select_until(find_position_of("arg2: arg2")), 2103 ); 2104} 2105 2106#[test] 2107fn use_label_shorthand_works_for_nested_patterns() { 2108 assert_code_action!( 2109 USE_LABEL_SHORTHAND_SYNTAX, 2110 r#" 2111pub type Wibble { Wibble(arg: Int, arg2: Wobble) } 2112pub type Wobble { Wobble(arg: Int, arg2: String) } 2113 2114pub fn main() { 2115 let Wibble(arg2: Wobble(arg: arg, arg2: arg2), ..) = todo 2116} 2117 "#, 2118 find_position_of("main").select_until(find_position_of("todo")), 2119 ); 2120} 2121 2122#[test] 2123fn use_label_shorthand_works_for_alternative_patterns() { 2124 assert_code_action!( 2125 USE_LABEL_SHORTHAND_SYNTAX, 2126 r#" 2127pub type Wibble { Wibble(arg: Int, arg2: String) } 2128 2129pub fn main() { 2130 case Wibble(1, "wibble") { 2131 Wibble(arg2: arg2, ..) | Wibble(arg: 1, arg2: arg2) -> todo 2132 } 2133} 2134 "#, 2135 find_position_of("main").select_until(find_position_of("todo")), 2136 ); 2137} 2138 2139#[test] 2140fn test_assign_unused_result() { 2141 assert_code_action!( 2142 ASSIGN_UNUSED_RESULT, 2143 r#" 2144pub fn main() { 2145 let x = 1 2146 Ok(x) 2147 Nil 2148} 2149"#, 2150 find_position_of("Ok").select_until(find_position_of("(x)")), 2151 ); 2152} 2153 2154#[test] 2155fn test_assign_unused_result_in_block() { 2156 assert_code_action!( 2157 ASSIGN_UNUSED_RESULT, 2158 r#" 2159pub fn main() { 2160 { 2161 let x = 1 2162 Ok(x) 2163 Nil 2164 } 2165 Nil 2166} 2167"#, 2168 find_position_of("Ok").select_until(find_position_of("(x)")), 2169 ); 2170} 2171 2172#[test] 2173fn test_assign_unused_result_on_block_start() { 2174 assert_code_action!( 2175 ASSIGN_UNUSED_RESULT, 2176 r#" 2177pub fn main() { 2178 { 2179 let x = 1 2180 Ok(x) 2181 Ok(x) 2182 } 2183 Nil 2184} 2185"#, 2186 find_position_of("{").nth_occurrence(2).to_selection() 2187 ); 2188} 2189 2190#[test] 2191fn test_assign_unused_result_on_block_end() { 2192 assert_code_action!( 2193 ASSIGN_UNUSED_RESULT, 2194 r#" 2195pub fn main() { 2196 { 2197 let x = 1 2198 Ok(x) 2199 Ok(x) 2200 } 2201 Nil 2202} 2203"#, 2204 find_position_of("}").to_selection() 2205 ); 2206} 2207 2208#[test] 2209#[should_panic(expected = "No action with the given title")] 2210fn test_assign_unused_result_inside_block() { 2211 assert_code_action!( 2212 ASSIGN_UNUSED_RESULT, 2213 r#" 2214pub fn main() { 2215 { 2216 let x = 1 2217 Nil 2218 Ok(x) 2219 } 2220} 2221"#, 2222 find_position_of("Ok").select_until(find_position_of("(x)")) 2223 ); 2224} 2225 2226#[test] 2227fn test_assign_unused_result_only_first_action() { 2228 assert_code_action!( 2229 ASSIGN_UNUSED_RESULT, 2230 r#" 2231pub fn main() { 2232 let x = 1 2233 Ok(x) 2234 Ok(x) 2235 Nil 2236} 2237"#, 2238 find_position_of("Ok").select_until(find_position_of("(x)")) 2239 ); 2240} 2241 2242#[test] 2243#[should_panic(expected = "No action with the given title")] 2244fn test_assign_unused_result_not_on_return_value() { 2245 assert_code_action!( 2246 ASSIGN_UNUSED_RESULT, 2247 r#" 2248pub fn main() { 2249 let x = 1 2250 Ok(x) 2251} 2252"#, 2253 find_position_of("Ok").select_until(find_position_of("(x)")) 2254 ); 2255} 2256 2257#[test] 2258#[should_panic(expected = "No action with the given title")] 2259fn test_assign_unused_result_not_on_return_value_in_block() { 2260 assert_code_action!( 2261 ASSIGN_UNUSED_RESULT, 2262 r#" 2263pub fn main() { 2264 let _ = { 2265 let x = 1 2266 Ok(x) 2267 } 2268 Nil 2269}"#, 2270 find_position_of("Ok").select_until(find_position_of("(x)")) 2271 ); 2272} 2273 2274#[test] 2275fn test_import_module_from_function() { 2276 let src = " 2277pub fn main() { 2278 result.is_ok() 2279} 2280"; 2281 2282 assert_code_action!( 2283 "Import `result`", 2284 TestProject::for_source(src).add_hex_module("result", "pub fn is_ok() {}"), 2285 find_position_of("result").select_until(find_position_of(".")) 2286 ); 2287} 2288 2289#[test] 2290fn test_import_path_module_from_function() { 2291 let src = r#" 2292pub fn main() { 2293 io.println("Hello, world!") 2294} 2295"#; 2296 2297 assert_code_action!( 2298 "Import `gleam/io`", 2299 TestProject::for_source(src) 2300 .add_hex_module("gleam/io", "pub fn println(message: String) {}"), 2301 find_position_of("io").select_until(find_position_of(".")) 2302 ); 2303} 2304 2305#[test] 2306fn test_import_module_from_type() { 2307 let src = "type Wobble = wibble.Wubble"; 2308 2309 assert_code_action!( 2310 "Import `mod/wibble`", 2311 TestProject::for_source(src).add_hex_module("mod/wibble", "pub type Wubble { Wubble }"), 2312 find_position_of("wibble").select_until(find_position_of(".")) 2313 ); 2314} 2315 2316#[test] 2317fn test_import_module_from_constructor() { 2318 let src = " 2319pub fn main() { 2320 let value = values.Value(10) 2321} 2322"; 2323 2324 assert_code_action!( 2325 "Import `values`", 2326 TestProject::for_source(src).add_hex_module("values", "pub type Value { Value(Int) }"), 2327 find_position_of("values").select_until(find_position_of(".")) 2328 ); 2329} 2330 2331#[test] 2332fn test_rename_module_for_imported() { 2333 let src = r#" 2334import gleam/io 2335 2336pub fn main() { 2337 i.println("Hello, world!") 2338} 2339"#; 2340 2341 assert_code_action!( 2342 "Did you mean `io`", 2343 TestProject::for_source(src) 2344 .add_hex_module("gleam/io", "pub fn println(message: String) {}"), 2345 find_position_of("i.").select_until(find_position_of("println")) 2346 ); 2347} 2348 2349#[test] 2350fn test_import_similar_module() { 2351 let src = " 2352pub fn main() { 2353 reult.is_ok() 2354} 2355"; 2356 2357 assert_code_action!( 2358 "Import `result`", 2359 TestProject::for_source(src).add_hex_module("result", "pub fn is_ok() {}"), 2360 find_position_of("reult").select_until(find_position_of(".")) 2361 ); 2362} 2363 2364#[test] 2365fn test_no_action_to_import_module_without_value() { 2366 // The language server should not suggest a code action 2367 // to import a module if it doesn't have a value with 2368 // the same name as we are trying to access 2369 let src = " 2370pub fn main() { 2371 io.hello_world() 2372} 2373"; 2374 2375 let title = "Import `io`"; 2376 2377 assert_no_code_actions!( 2378 title, 2379 TestProject::for_source(src).add_hex_module("io", "pub fn println() {}"), 2380 find_position_of("io").select_until(find_position_of(".")) 2381 ); 2382} 2383 2384#[test] 2385fn test_no_action_to_import_module_without_type() { 2386 let src = "type Name = int.String"; 2387 2388 let title = "Import `int`"; 2389 2390 assert_no_code_actions!( 2391 title, 2392 TestProject::for_source(src).add_hex_module("int", ""), 2393 find_position_of("int").select_until(find_position_of(".")) 2394 ); 2395} 2396 2397#[test] 2398fn test_no_action_to_import_module_with_private_value() { 2399 // The language server should not suggest a code action 2400 // to import a module if the value we are trying to 2401 // access is private. 2402 let src = " 2403pub fn main() { 2404 mod.internal() 2405} 2406"; 2407 2408 let title = "Import `mod`"; 2409 2410 assert_no_code_actions!( 2411 title, 2412 TestProject::for_source(src).add_hex_module("mod", "fn internal() {}"), 2413 find_position_of("mod").select_until(find_position_of(".")) 2414 ); 2415} 2416 2417#[test] 2418fn test_no_action_to_import_module_with_private_type() { 2419 let src = "type T = module.T"; 2420 2421 let title = "Import `module`"; 2422 2423 assert_no_code_actions!( 2424 title, 2425 TestProject::for_source(src).add_hex_module("module", "type T { T }"), 2426 find_position_of("module").select_until(find_position_of(".")) 2427 ); 2428} 2429 2430#[test] 2431fn test_no_action_to_import_module_with_constructor_named_same_as_type() { 2432 let src = "type NotAType = shapes.Rectangle"; 2433 2434 let title = "Import `shapes`"; 2435 2436 assert_no_code_actions!( 2437 title, 2438 TestProject::for_source(src) 2439 .add_hex_module("shapes", "pub type Shape { Rectangle, Circle }"), 2440 find_position_of("shapes").select_until(find_position_of(".")) 2441 ); 2442} 2443 2444#[test] 2445fn add_missing_patterns_bool() { 2446 assert_code_action!( 2447 ADD_MISSING_PATTERNS, 2448 " 2449pub fn main(bool: Bool) { 2450 case bool {} 2451} 2452", 2453 find_position_of("case").select_until(find_position_of("bool {")) 2454 ); 2455} 2456 2457#[test] 2458fn add_missing_patterns_custom_type() { 2459 assert_code_action!( 2460 ADD_MISSING_PATTERNS, 2461 " 2462type Wibble { 2463 Wibble 2464 Wobble 2465 Wubble 2466} 2467 2468pub fn main(wibble: Wibble) { 2469 case wibble { 2470 Wobble -> Nil 2471 } 2472} 2473", 2474 find_position_of("case").select_until(find_position_of("wibble {")) 2475 ); 2476} 2477 2478#[test] 2479fn add_missing_patterns_tuple() { 2480 assert_code_action!( 2481 ADD_MISSING_PATTERNS, 2482 " 2483pub fn main(two_at_once: #(Bool, Result(Int, Nil))) { 2484 case two_at_once { 2485 #(False, Error(_)) -> Nil 2486 } 2487} 2488", 2489 find_position_of("case").select_until(find_position_of("two_at_once {")) 2490 ); 2491} 2492 2493#[test] 2494fn add_missing_patterns_list() { 2495 assert_code_action!( 2496 ADD_MISSING_PATTERNS, 2497 " 2498pub fn main() { 2499 let list = [1, 2, 3] 2500 case list { 2501 [a, b, c, 4 as d] -> d 2502 } 2503} 2504", 2505 find_position_of("case").select_until(find_position_of("list {")) 2506 ); 2507} 2508 2509#[test] 2510fn add_missing_patterns_infinite() { 2511 assert_code_action!( 2512 ADD_MISSING_PATTERNS, 2513 r#" 2514pub fn main() { 2515 let value = 3 2516 case value { 2517 1 -> "one" 2518 2 -> "two" 2519 3 -> "three" 2520 } 2521} 2522"#, 2523 find_position_of("case").select_until(find_position_of("value {")) 2524 ); 2525} 2526 2527#[test] 2528fn add_missing_patterns_multi() { 2529 assert_code_action!( 2530 ADD_MISSING_PATTERNS, 2531 r#" 2532pub fn main(a: Bool) { 2533 let b = 1 2534 case a, b { 2535 2536 } 2537} 2538"#, 2539 find_position_of("case").select_until(find_position_of("b {")) 2540 ); 2541} 2542 2543#[test] 2544fn add_missing_patterns_inline() { 2545 // Ensure we correctly detect the indentation, if the case expression 2546 // does not start at the beginning of the line 2547 assert_code_action!( 2548 ADD_MISSING_PATTERNS, 2549 r#" 2550pub fn main(a: Bool) { 2551 let value = case a {} 2552} 2553"#, 2554 find_position_of("case").select_until(find_position_of("a {")) 2555 ); 2556} 2557 2558#[test] 2559fn import_module_from_pattern() { 2560 let src = " 2561pub fn main(res) { 2562 case res { 2563 result.Ok(_) -> Nil 2564 result.Error(_) -> Nil 2565 } 2566} 2567"; 2568 2569 assert_code_action!( 2570 "Import `result`", 2571 TestProject::for_source(src) 2572 .add_hex_module("result", "pub type Result(v, e) { Ok(v) Error(e) }"), 2573 find_position_of("result").select_until(find_position_of(".")) 2574 ); 2575} 2576 2577#[test] 2578fn annotate_function() { 2579 assert_code_action!( 2580 ADD_ANNOTATIONS, 2581 r#" 2582pub fn add_one(thing) { 2583 thing + 1 2584} 2585"#, 2586 find_position_of("fn").select_until(find_position_of("(")) 2587 ); 2588} 2589 2590#[test] 2591fn annotate_function_with_annotated_return_type() { 2592 assert_code_action!( 2593 ADD_ANNOTATION, 2594 r#" 2595pub fn add_one(thing) -> Int { 2596 thing + 1 2597} 2598"#, 2599 find_position_of("fn").select_until(find_position_of("(")) 2600 ); 2601} 2602 2603#[test] 2604fn annotate_function_with_partially_annotated_parameters() { 2605 assert_code_action!( 2606 ADD_ANNOTATION, 2607 r#" 2608pub fn add(a: Float, b) -> Float { 2609 a +. b 2610} 2611"#, 2612 find_position_of("fn").select_until(find_position_of("(")) 2613 ); 2614} 2615 2616#[test] 2617fn no_code_action_for_fully_annotated_function() { 2618 assert_no_code_actions!( 2619 ADD_ANNOTATION | ADD_ANNOTATIONS, 2620 r#" 2621pub fn do_a_thing(a: Int, b: Float) -> String { 2622 todo 2623} 2624"#, 2625 find_position_of("fn").select_until(find_position_of("(")) 2626 ); 2627} 2628 2629#[test] 2630fn annotate_anonymous_function() { 2631 assert_code_action!( 2632 ADD_ANNOTATIONS, 2633 r#" 2634pub fn add_curry(a) { 2635 fn(b) { a + b } 2636} 2637"#, 2638 find_position_of("fn(").select_until(find_position_of("b)")) 2639 ); 2640} 2641 2642#[test] 2643fn annotate_anonymous_function_with_annotated_return_type() { 2644 assert_code_action!( 2645 ADD_ANNOTATION, 2646 r#" 2647pub fn add_curry(a) { 2648 fn(b) -> Int { a + b } 2649} 2650"#, 2651 find_position_of("fn(").select_until(find_position_of("b)")) 2652 ); 2653} 2654 2655#[test] 2656fn annotate_anonymous_function_with_partially_annotated_parameters() { 2657 assert_code_action!( 2658 ADD_ANNOTATIONS, 2659 r#" 2660pub fn main() { 2661 fn(a, b: Int, c) { a + b + c } 2662} 2663"#, 2664 find_position_of("fn(").select_until(find_position_of("c)")) 2665 ); 2666} 2667 2668#[test] 2669fn no_code_action_for_fully_annotated_anonymous_function() { 2670 assert_no_code_actions!( 2671 ADD_ANNOTATION | ADD_ANNOTATIONS, 2672 r#" 2673pub fn main() { 2674 fn(a: Int, b: Int) -> Int { a - b } 2675} 2676"#, 2677 find_position_of("fn(").select_until(find_position_of("Int)")) 2678 ); 2679} 2680 2681#[test] 2682fn annotate_use() { 2683 assert_code_action!( 2684 ADD_ANNOTATIONS, 2685 r#" 2686pub fn wibble(wobble: fn(Int, Int) -> Int) { 2687 wobble(1, 2) 2688} 2689 2690pub fn main() { 2691 use a, b <- wibble 2692 a + b 2693} 2694"#, 2695 find_position_of("use").select_until(find_position_of("<-")) 2696 ); 2697} 2698 2699#[test] 2700fn annotate_use_with_partially_annotated_parameters() { 2701 assert_code_action!( 2702 ADD_ANNOTATION, 2703 r#" 2704pub fn wibble(wobble: fn(Int, Int) -> Int) { 2705 wobble(1, 2) 2706} 2707 2708pub fn main() { 2709 use a: Int, b <- wibble 2710 a + b 2711} 2712"#, 2713 find_position_of("use").select_until(find_position_of("<-")) 2714 ); 2715} 2716 2717#[test] 2718fn no_code_action_for_fully_annotated_use() { 2719 assert_no_code_actions!( 2720 ADD_ANNOTATION | ADD_ANNOTATIONS, 2721 r#" 2722pub fn wibble(wobble: fn(Int, Int) -> Int) { 2723 wobble(1, 2) 2724} 2725 2726pub fn main() { 2727 use a: Int, b: Int <- wibble 2728 a + b 2729} 2730"#, 2731 find_position_of("use").select_until(find_position_of("<-")) 2732 ); 2733} 2734 2735#[test] 2736fn annotate_constant() { 2737 assert_code_action!( 2738 ADD_ANNOTATION, 2739 r#" 2740pub const my_constant = 20 2741"#, 2742 find_position_of("const").select_until(find_position_of("=")) 2743 ); 2744} 2745 2746#[test] 2747fn no_code_action_for_annotated_constant() { 2748 assert_no_code_actions!( 2749 ADD_ANNOTATION | ADD_ANNOTATIONS, 2750 r#" 2751pub const PI: Float = 3.14159 2752"#, 2753 find_position_of("const").select_until(find_position_of("=")) 2754 ); 2755} 2756 2757#[test] 2758fn annotate_local_variable() { 2759 assert_code_action!( 2760 ADD_ANNOTATION, 2761 r#" 2762pub fn main() { 2763 let my_value = 10 2764} 2765"#, 2766 find_position_of("let").select_until(find_position_of("=")) 2767 ); 2768} 2769 2770#[test] 2771fn annotate_local_variable_with_pattern() { 2772 assert_code_action!( 2773 ADD_ANNOTATION, 2774 r#" 2775type Wibble { 2776 Wibble(a: Int, b: Int, c: Int) 2777} 2778 2779pub fn main() { 2780 let Wibble(a, b, c) = Wibble(1, 2, 3) 2781} 2782"#, 2783 find_position_of("let").select_until(find_position_of("=")) 2784 ); 2785} 2786 2787#[test] 2788fn annotate_local_variable_with_pattern2() { 2789 assert_code_action!( 2790 ADD_ANNOTATION, 2791 r#" 2792pub fn main(values) { 2793 let #(left, right) = values 2794} 2795"#, 2796 find_position_of("let").select_until(find_position_of("=")) 2797 ); 2798} 2799 2800#[test] 2801fn annotate_local_variable_let_assert() { 2802 assert_code_action!( 2803 ADD_ANNOTATION, 2804 r#" 2805pub fn fallible() -> Result(Int, Nil) { 2806 todo 2807} 2808 2809pub fn main() { 2810 let assert Ok(value) = fallible() 2811} 2812"#, 2813 find_position_of("let").select_until(find_position_of("=")) 2814 ); 2815} 2816 2817#[test] 2818fn annotate_nested_local_variable() { 2819 assert_code_action!( 2820 ADD_ANNOTATION, 2821 r#" 2822pub fn main() { 2823 let a = { 2824 let b = 10 2825 b + 1 2826 } 2827} 2828"#, 2829 find_position_of("let b").select_until(find_position_of("b =")) 2830 ); 2831} 2832 2833#[test] 2834fn no_code_action_for_annotated_local_variable() { 2835 assert_no_code_actions!( 2836 ADD_ANNOTATION | ADD_ANNOTATIONS, 2837 r#" 2838pub fn main() { 2839 let typed: Int = 1.2 2840} 2841"#, 2842 find_position_of("let").select_until(find_position_of("=")) 2843 ); 2844} 2845 2846#[test] 2847fn adding_annotations_correctly_prints_type_variables() { 2848 assert_code_action!( 2849 ADD_ANNOTATIONS, 2850 r#" 2851pub fn map_result(input, function) { 2852 case input { 2853 Ok(value) -> Ok(function(value)) 2854 Error(error) -> Error(error) 2855 } 2856} 2857"#, 2858 find_position_of("fn").select_until(find_position_of("(")) 2859 ); 2860} 2861 2862#[test] 2863fn add_multiple_annotations() { 2864 assert_code_action!( 2865 ADD_ANNOTATIONS, 2866 r#" 2867pub const my_constant = 20 2868 2869pub fn add_my_constant(value) { 2870 let result = value + my_constant 2871 result 2872} 2873"#, 2874 find_position_of("pub const").select_until(find_position_of("}")) 2875 ); 2876} 2877 2878#[test] 2879fn different_annotations_create_compatible_type_variables() { 2880 assert_code_action!( 2881 ADD_ANNOTATIONS, 2882 r#" 2883pub fn do_generic_things(a, b) { 2884 let a_value = a 2885 let b_value = b 2886 let other_value = a_value 2887} 2888"#, 2889 find_position_of("let a_value").select_until(find_position_of("}")) 2890 ); 2891} 2892 2893#[test] 2894fn adding_annotations_prints_type_variable_names() { 2895 assert_code_action!( 2896 ADD_ANNOTATIONS, 2897 r#" 2898pub fn do_generic_things(a: type_a, b: type_b) { 2899 let a_value = a 2900 let b_value = b 2901 let other_value = a_value 2902} 2903"#, 2904 find_position_of("let a_value").select_until(find_position_of("}")) 2905 ); 2906} 2907 2908#[test] 2909fn adding_annotations_prints_contextual_types() { 2910 assert_code_action!( 2911 ADD_ANNOTATION, 2912 r#" 2913pub type IntAlias = Int 2914 2915pub fn main() { 2916 let value = 20 2917} 2918"#, 2919 find_position_of("let").select_until(find_position_of("value")) 2920 ); 2921} 2922 2923#[test] 2924fn adding_annotations_prints_contextual_types2() { 2925 assert_code_action!( 2926 ADD_ANNOTATION, 2927 r#" 2928pub type Result 2929 2930pub fn main() { 2931 let value = Ok(12) 2932} 2933"#, 2934 find_position_of("let").select_until(find_position_of("=")) 2935 ); 2936} 2937 2938#[test] 2939fn adding_annotations_prints_contextual_types3() { 2940 let src = r#" 2941import wibble 2942 2943pub fn main() { 2944 let value = wibble.Wibble 2945} 2946"#; 2947 2948 assert_code_action!( 2949 ADD_ANNOTATION, 2950 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 2951 find_position_of("let").select_until(find_position_of("=")) 2952 ); 2953} 2954 2955#[test] 2956fn add_annotation_triggers_on_function_curly_brace() { 2957 assert_code_action!( 2958 ADD_ANNOTATION, 2959 "pub fn main() { 1 }", 2960 find_position_of("{").to_selection(), 2961 ); 2962} 2963 2964#[test] 2965fn add_annotation_triggers_on_empty_space_before_function_curly_brace() { 2966 assert_code_action!( 2967 ADD_ANNOTATION, 2968 "pub fn main() { 1 }", 2969 find_position_of(" ").nth_occurrence(3).to_selection(), 2970 ); 2971} 2972 2973#[test] 2974fn adding_annotations_prints_contextual_types4() { 2975 let src = r#" 2976import wibble as wobble 2977 2978pub fn main() { 2979 let value = wobble.Wibble 2980} 2981"#; 2982 2983 assert_code_action!( 2984 ADD_ANNOTATION, 2985 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 2986 find_position_of("let").select_until(find_position_of("=")) 2987 ); 2988} 2989 2990#[test] 2991fn adding_annotations_prints_contextual_types5() { 2992 let src = r#" 2993import wibble.{type Wibble as Wobble} 2994 2995pub fn main() { 2996 let value = wibble.Wibble 2997} 2998"#; 2999 3000 assert_code_action!( 3001 ADD_ANNOTATION, 3002 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 3003 find_position_of("let").select_until(find_position_of("=")) 3004 ); 3005} 3006 3007#[test] 3008// https://github.com/gleam-lang/gleam/issues/3789 3009fn no_code_actions_to_add_annotations_for_pipe() { 3010 assert_no_code_actions!( 3011 ADD_ANNOTATION | ADD_ANNOTATIONS, 3012 r#" 3013fn do_something(a: Int) { a } 3014 3015pub fn main() { 3016 10 |> do_something 3017} 3018"#, 3019 find_position_of("10").select_until(find_position_of("|>")) 3020 ); 3021} 3022 3023#[test] 3024// https://github.com/gleam-lang/gleam/issues/3789#issuecomment-2455805734 3025fn add_correct_type_annotation_for_non_variable_use() { 3026 assert_code_action!( 3027 ADD_ANNOTATION, 3028 r#" 3029fn usable(f) { 3030 f(#(1, 2)) 3031} 3032 3033pub fn main() { 3034 use #(a, b) <- usable 3035 a + b 3036} 3037"#, 3038 find_position_of("use").select_until(find_position_of("b)")) 3039 ); 3040} 3041 3042#[test] 3043fn test_qualified_to_unqualified_import_basic_with_argument() { 3044 let src = r#" 3045import option 3046 3047pub fn main() { 3048 option.Some(1) 3049} 3050"#; 3051 assert_code_action!( 3052 "Unqualify option.Some", 3053 TestProject::for_source(src) 3054 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3055 find_position_of(".Some").select_until(find_position_of("(1)")), 3056 ); 3057} 3058 3059#[test] 3060fn test_qualified_to_unqualified_import_basic_record_without_argument() { 3061 let src = r#" 3062import wobble 3063 3064pub fn main() { 3065 wobble.Wibble 3066} 3067"#; 3068 assert_code_action!( 3069 "Unqualify wobble.Wibble", 3070 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"), 3071 find_position_of(".W").select_until(find_position_of("ibble")) 3072 ); 3073} 3074 3075#[test] 3076fn test_qualified_to_unqualified_import_custom_type_record_declaration() { 3077 let src = r#" 3078import wobble 3079 3080pub type Wibble { 3081 Wibble(wibble: wobble.Wobble) 3082} 3083"#; 3084 assert_code_action!( 3085 "Unqualify wobble.Wobble", 3086 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"), 3087 find_position_of(".").select_until(find_position_of("Wobble")) 3088 ); 3089} 3090 3091#[test] 3092fn test_qualified_to_unqualified_import_basic_type_without_argument() { 3093 let src = r#" 3094import wobble 3095 3096pub fn identity(x: wobble.Wobble) -> wobble.Wobble { 3097 x 3098} 3099"#; 3100 assert_code_action!( 3101 "Unqualify wobble.Wobble", 3102 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"), 3103 find_position_of(".").select_until(find_position_of("Wobble")) 3104 ); 3105} 3106 3107#[test] 3108fn test_qualified_to_unqualified_record_value_constructor_module_name() { 3109 let src = r#" 3110import option 3111 3112pub fn main() { 3113 option.Some(1) 3114} 3115"#; 3116 assert_code_action!( 3117 "Unqualify option.Some", 3118 TestProject::for_source(src) 3119 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3120 find_position_of("option").nth_occurrence(2).to_selection() 3121 ); 3122} 3123 3124#[test] 3125fn test_qualified_to_unqualified_import_basic_multiple() { 3126 let src = r#" 3127import option 3128 3129pub fn main() { 3130 option.Some(1) 3131 option.Some(1) 3132 todo 3133} 3134"#; 3135 assert_code_action!( 3136 "Unqualify option.Some", 3137 TestProject::for_source(src) 3138 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3139 find_position_of(".Some").select_until(find_position_of("(1)")), 3140 ); 3141} 3142 3143#[test] 3144fn test_qualified_to_unqualified_import_when_unqualified_exists() { 3145 let src = r#" 3146import option.{Some} 3147 3148pub fn main() { 3149 option.Some(1) 3150} 3151"#; 3152 assert_code_action!( 3153 "Unqualify option.Some", 3154 TestProject::for_source(src) 3155 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3156 find_position_of(".Some").select_until(find_position_of("(1)")), 3157 ); 3158} 3159 3160#[test] 3161fn test_qualified_to_unqualified_import_with_comma() { 3162 let src = r#" 3163import option.{None, } 3164 3165pub fn main() { 3166 option.Some(1) 3167} 3168"#; 3169 assert_code_action!( 3170 "Unqualify option.Some", 3171 TestProject::for_source(src) 3172 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3173 find_position_of(".Some").select_until(find_position_of("(1)")), 3174 ); 3175} 3176 3177#[test] 3178fn test_qualified_to_unqualified_import_with_comma_pos_not_end() { 3179 let src = r#" 3180import option.{None, } as opt 3181 3182pub fn main() { 3183 opt.Some(1) 3184} 3185"#; 3186 assert_code_action!( 3187 "Unqualify opt.Some", 3188 TestProject::for_source(src) 3189 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3190 find_position_of(".Some").select_until(find_position_of("(1)")), 3191 ); 3192} 3193 3194#[test] 3195fn test_qualified_to_unqualified_import_different_constructors() { 3196 let src = r#" 3197import option 3198 3199pub fn main() { 3200 option.Some(1) 3201 option.None 3202}"#; 3203 assert_code_action!( 3204 "Unqualify option.Some", 3205 TestProject::for_source(src) 3206 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3207 find_position_of(".Some").select_until(find_position_of("(1)")), 3208 ); 3209} 3210 3211#[test] 3212fn test_qualified_to_unqualified_import_no_action_when_already_unqualified() { 3213 let src = r#" 3214import option.{Some, None} 3215 3216pub fn main() { 3217 Some(1) 3218 Some(1) 3219 todo 3220} 3221"#; 3222 let title = "Unqualify option.Some"; 3223 assert_no_code_actions!( 3224 title, 3225 TestProject::for_source(src) 3226 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3227 find_position_of("Some(").select_until(find_position_of("1)")), 3228 ); 3229} 3230 3231#[test] 3232fn test_qualified_to_unqualified_import_with_alias() { 3233 let src = r#" 3234import option as opt 3235 3236pub fn main() { 3237 opt.Some(1) 3238} 3239"#; 3240 assert_code_action!( 3241 "Unqualify opt.Some", 3242 TestProject::for_source(src) 3243 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3244 find_position_of("opt.Some").select_until(find_position_of("(1)")), 3245 ); 3246} 3247 3248#[test] 3249fn test_qualified_to_unqualified_import_with_alias_multiple() { 3250 let src = r#" 3251import option as opt 3252 3253pub fn main() { 3254 opt.Some(1) 3255 opt.Some(1) 3256} 3257 3258pub fn identity(x: opt.Option(Int)) -> opt.Option(Int) { 3259 opt.Some(1) 3260 x 3261} 3262"#; 3263 assert_code_action!( 3264 "Unqualify opt.Some", 3265 TestProject::for_source(src) 3266 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3267 find_position_of("opt.Some").select_until(find_position_of("(1)")), 3268 ); 3269} 3270 3271#[test] 3272fn test_qualified_to_unqualified_import_multiple_imports() { 3273 let src = r#" 3274import option 3275import wobble 3276 3277pub fn main() { 3278 option.Some(2) 3279 wobble.Wibble(1) 3280} 3281"#; 3282 assert_code_action!( 3283 "Unqualify wobble.Wibble", 3284 TestProject::for_source(src) 3285 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3286 .add_hex_module("wobble", "pub type Wobble { Wibble(Int)} "), 3287 find_position_of(".Wibble").select_until(find_position_of("(1)")), 3288 ); 3289} 3290 3291#[test] 3292fn test_qualified_to_unqualified_import_in_case_with_argument() { 3293 let src = r#" 3294import option 3295 3296pub fn main(x) { 3297 case option.Some(1) { 3298 option.Some(value) -> value 3299 option.None -> 0 3300 } 3301} 3302"#; 3303 assert_code_action!( 3304 "Unqualify option.Some", 3305 TestProject::for_source(src) 3306 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3307 find_position_of(".Some(").select_until(find_position_of("(1)")) 3308 ); 3309} 3310 3311#[test] 3312fn test_qualified_to_unqualified_import_in_case_without_argument() { 3313 let src = r#" 3314import wobble 3315 3316pub fn main() { 3317 case wobble.Wibble { 3318 wobble.Wibble -> 1 3319 wobble.Wubble(1) -> 2 3320 } 3321} 3322"#; 3323 assert_code_action!( 3324 "Unqualify wobble.Wibble", 3325 TestProject::for_source(src) 3326 .add_hex_module("wobble", "pub type Wobble { Wibble Wubble(Int) }"), 3327 find_position_of(".W").select_until(find_position_of("ibble")) 3328 ); 3329} 3330 3331#[test] 3332fn test_qualified_to_unqualified_import_in_pattern() { 3333 let src = r#" 3334import option 3335 3336pub fn main() -> Int { 3337 case option.Some(1) { 3338 option.Some(value) -> value 3339 option.None -> 0 3340 } 3341} 3342"#; 3343 assert_code_action!( 3344 "Unqualify option.Some", 3345 TestProject::for_source(src) 3346 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3347 find_position_of(".Some(va").select_until(find_position_of("lue)")), 3348 ); 3349} 3350 3351#[test] 3352fn test_qualified_to_unqualified_import_in_pattern_without_argument() { 3353 let src = r#" 3354import wobble 3355 3356pub fn main() { 3357 case wobble.Wibble { 3358 wobble.Wibble -> 1 3359 wobble.Wubble(1) -> 2 3360 } 3361 let wob = wobble.Wibble 3362 todo 3363} 3364"#; 3365 assert_code_action!( 3366 "Unqualify wobble.Wibble", 3367 TestProject::for_source(src) 3368 .add_hex_module("wobble", "pub type Wobble { Wibble Wubble(Int) }"), 3369 find_position_of("wobble.W").select_until(find_position_of("ibble")) 3370 ); 3371} 3372 3373#[test] 3374fn test_qualified_to_unqualified_import_type() { 3375 let src = r#" 3376import option 3377 3378pub fn main(x) -> option.Option(Int) { 3379 option.Some(1) 3380} 3381"#; 3382 assert_code_action!( 3383 "Unqualify option.Option", 3384 TestProject::for_source(src) 3385 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3386 find_position_of(".Option").select_until(find_position_of("(Int)")), 3387 ); 3388} 3389 3390#[test] 3391fn test_qualified_to_unqualified_import_nested_type_outer() { 3392 let src = r#" 3393import option 3394import wobble 3395pub fn main(x) -> option.Option(wobble.Wibble) { 3396 todo 3397} 3398"#; 3399 assert_code_action!( 3400 "Unqualify option.Option", 3401 TestProject::for_source(src) 3402 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3403 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 3404 find_position_of(".O").select_until(find_position_of("ption(")), 3405 ); 3406} 3407 3408#[test] 3409fn test_qualified_to_unqualified_import_nested_constructor_outer() { 3410 let src = r#" 3411import option 3412import wobble 3413pub fn main(x) -> option.Option(wobble.Wibble) { 3414 option.Some(wobble.Wobble(1)) 3415} 3416"#; 3417 assert_code_action!( 3418 "Unqualify option.Some", 3419 TestProject::for_source(src) 3420 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3421 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 3422 find_position_of(".S").select_until(find_position_of("ome(")), 3423 ); 3424} 3425 3426#[test] 3427fn test_qualified_to_unqualified_import_nested_constructor_inner() { 3428 let src = r#" 3429import option 3430import wobble 3431 3432pub fn main(x) -> option.Option(wobble.Wibble) { 3433 option.Some(wobble.Wobble(1)) 3434} 3435"#; 3436 assert_code_action!( 3437 "Unqualify wobble.Wobble", 3438 TestProject::for_source(src) 3439 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3440 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 3441 find_position_of(".Wobble").select_until(find_position_of("(1)")), 3442 ); 3443} 3444 3445#[test] 3446fn test_qualified_to_unqualified_import_nested_type_inner() { 3447 let src = r#" 3448import option 3449import wobble 3450 3451pub fn main(x) -> option.Option(wobble.Wibble) { 3452 todo 3453} 3454"#; 3455 assert_code_action!( 3456 "Unqualify wobble.Wibble", 3457 TestProject::for_source(src) 3458 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3459 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 3460 find_position_of("wobble.").select_until(find_position_of("Wibble")), 3461 ); 3462} 3463 3464#[test] 3465fn test_qualified_to_unqualified_import_below_constructor() { 3466 let src = r#" 3467 3468pub fn main() { 3469 option.Some(1) 3470} 3471 3472import option 3473"#; 3474 assert_code_action!( 3475 "Unqualify option.Some", 3476 TestProject::for_source(src) 3477 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3478 find_position_of(".Some").select_until(find_position_of("(1)")), 3479 ); 3480} 3481 3482#[test] 3483fn test_qualified_to_unqualified_import_between_constructors() { 3484 let src = r#" 3485 3486pub fn main() { 3487 option.Some(1) 3488} 3489 3490import option 3491 3492pub fn identity(x: option.Option(Int)) -> option.Option(Int) { 3493 option.Some(1) 3494 x 3495} 3496"#; 3497 assert_code_action!( 3498 "Unqualify option.Some", 3499 TestProject::for_source(src) 3500 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3501 find_position_of(".Some").select_until(find_position_of("(1)")), 3502 ); 3503} 3504 3505#[test] 3506fn test_qualified_to_unqualified_import_multiple_line() { 3507 let src = r#" 3508import option.{ 3509 type Option, 3510 None, 3511} 3512 3513pub fn main() { 3514 option.Some(1) 3515} 3516"#; 3517 assert_code_action!( 3518 "Unqualify option.Some", 3519 TestProject::for_source(src) 3520 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3521 find_position_of(".Some").select_until(find_position_of("(1)")), 3522 ); 3523} 3524 3525#[test] 3526fn test_qualified_to_unqualified_import_multiple_line_bad_format_with_trailing_comma() { 3527 let src = r#" 3528import option.{type Option, 3529 None, 3530 3531} 3532 3533pub fn main() { 3534 option.Some(1) 3535} 3536"#; 3537 assert_code_action!( 3538 "Unqualify option.Some", 3539 TestProject::for_source(src) 3540 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3541 find_position_of(".Some").select_until(find_position_of("(1)")), 3542 ); 3543} 3544 3545#[test] 3546fn test_qualified_to_unqualified_import_multiple_line_bad_format_multiple_whitespace() { 3547 let src = r#" 3548import option.{ } 3549 3550pub fn main() { 3551 option.Some(1) 3552} 3553"#; 3554 assert_code_action!( 3555 "Unqualify option.Some", 3556 TestProject::for_source(src) 3557 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3558 find_position_of(".Some").select_until(find_position_of("(1)")), 3559 ); 3560} 3561#[test] 3562fn test_qualified_to_unqualified_import_multiple_line_bad_format_without_trailing_comma() { 3563 let src = r#" 3564import option.{type Option, 3565 None 3566 3567} 3568 3569pub fn main() { 3570 option.Some(1) 3571} 3572"#; 3573 assert_code_action!( 3574 "Unqualify option.Some", 3575 TestProject::for_source(src) 3576 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3577 find_position_of(".Some").select_until(find_position_of("(1)")), 3578 ); 3579} 3580#[test] 3581fn test_qualified_to_unqualified_import_multiple_line_aliased() { 3582 let src = r#" 3583import option.{ 3584 type Option, 3585 None} as opt 3586 3587pub fn main() { 3588 opt.Some(1) 3589} 3590"#; 3591 assert_code_action!( 3592 "Unqualify opt.Some", 3593 TestProject::for_source(src) 3594 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3595 find_position_of(".Some").select_until(find_position_of("(1)")), 3596 ); 3597} 3598 3599#[test] 3600fn test_qualified_to_unqualified_import_in_list_and_tuple() { 3601 let src = r#" 3602import option 3603 3604pub fn main() { 3605 let list = [option.Some(1), option.None] 3606 let tuple = #(option.Some(2), option.None) 3607} 3608"#; 3609 assert_code_action!( 3610 "Unqualify option.Some", 3611 TestProject::for_source(src) 3612 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3613 find_position_of("option.Some").select_until(find_position_of("(1)")), 3614 ); 3615} 3616 3617#[test] 3618fn test_qualified_to_unqualified_import_multiple_generic_type() { 3619 let src = r#" 3620import result 3621 3622pub fn main() -> result.Result(Int, String) { 3623 result.Ok(1) 3624} 3625"#; 3626 assert_code_action!( 3627 "Unqualify result.Result", 3628 TestProject::for_source(src) 3629 .add_hex_module("result", "pub type Result(a, e) { Ok(a) Error(e) }"), 3630 find_position_of(".Result").select_until(find_position_of("(Int")), 3631 ); 3632} 3633 3634#[test] 3635fn test_qualified_to_unqualified_import_constructor_as_argument() { 3636 let src = r#" 3637import option 3638 3639pub fn main() { 3640 option.map(option.Some(1), fn(x) { x + 1 }) 3641} 3642"#; 3643 assert_code_action!( 3644 "Unqualify option.Some", 3645 TestProject::for_source(src).add_hex_module( 3646 "option", 3647 " 3648 pub type Option(v) { Some(v) None } 3649 pub fn map(a, f) { todo } 3650 " 3651 ), 3652 find_position_of("option.Some").select_until(find_position_of("(1)")), 3653 ); 3654} 3655 3656#[test] 3657fn test_qualified_to_unqualified_import_constructor_different_module_same_type_inner() { 3658 let src = r#" 3659import option 3660import opt 3661 3662pub fn main() -> option.Option(opt.Option(Int)) { 3663 todo 3664} 3665"#; 3666 assert_code_action!( 3667 "Unqualify opt.Option", 3668 TestProject::for_source(src) 3669 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3670 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3671 find_position_of("opt.Option").select_until(find_position_of("(Int)")), 3672 ); 3673} 3674#[test] 3675fn test_qualified_to_unqualified_import_constructor_different_module_same_type_outer() { 3676 let src = r#" 3677import option 3678import opt 3679 3680pub fn main() -> option.Option(opt.Option(Int)) { 3681 todo 3682} 3683"#; 3684 assert_code_action!( 3685 "Unqualify option.Option", 3686 TestProject::for_source(src) 3687 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3688 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3689 find_position_of("option.").select_until(find_position_of("Option(")), 3690 ); 3691} 3692#[test] 3693fn test_qualified_to_unqualified_import_constructor_different_module_same_name_inner() { 3694 let src = r#" 3695import option 3696import opt 3697 3698pub fn main() { 3699 option.Some(opt.Some(1)) 3700 todo 3701} 3702"#; 3703 assert_code_action!( 3704 "Unqualify opt.Some", 3705 TestProject::for_source(src) 3706 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3707 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3708 find_position_of("opt.Some").select_until(find_position_of("(1)")), 3709 ); 3710} 3711#[test] 3712fn test_qualified_to_unqualified_import_constructor_different_module_same_name_outer() { 3713 let src = r#" 3714import option 3715import opt 3716 3717pub fn main() { 3718 option.Some(opt.Some(1)) 3719} 3720"#; 3721 assert_code_action!( 3722 "Unqualify option.Some", 3723 TestProject::for_source(src) 3724 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3725 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3726 find_position_of("option.").select_until(find_position_of("Some(")), 3727 ); 3728} 3729 3730#[test] 3731fn test_qualified_to_unqualified_import_constructor_complex_pattern() { 3732 let src = r#" 3733import option 3734 3735pub fn main() { 3736 case [option.Some(1), option.None] { 3737 [option.None, ..] -> todo 3738 [option.Some(_), ..] -> todo 3739 _ -> todo 3740 } 3741 case option.Some(1), option.Some(2) { 3742 option.None, option.Some(_) -> todo 3743 option.Some(_), option.Some(val) -> todo 3744 _ -> todo 3745 } 3746} 3747"#; 3748 assert_code_action!( 3749 "Unqualify option.Some", 3750 TestProject::for_source(src) 3751 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3752 find_position_of("option.").select_until(find_position_of("Some(")), 3753 ); 3754} 3755 3756#[test] 3757fn test_qualified_to_unqualified_import_constructor_constructor_name_exists() { 3758 let src = r#" 3759import option.{Some} 3760import opt 3761 3762pub fn main() -> option.Option(opt.Option(Int)) { 3763 Some(opt.Some(1)) 3764} 3765"#; 3766 let title = "Unqualify opt.Some"; 3767 assert_no_code_actions!( 3768 title, 3769 TestProject::for_source(src) 3770 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3771 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3772 find_position_of("opt.").select_until(find_position_of(".Some(")), 3773 ); 3774} 3775 3776#[test] 3777fn test_qualified_to_unqualified_import_constructor_constructor_name_exists_below() { 3778 let src = r#" 3779import opt 3780 3781pub fn main() -> option.Option(opt.Option(Int)) { 3782 Some(opt.Some(1)) 3783} 3784import option.{Some} 3785"#; 3786 let title = "Unqualify opt.Some"; 3787 assert_no_code_actions!( 3788 title, 3789 TestProject::for_source(src) 3790 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3791 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3792 find_position_of("opt.").select_until(find_position_of(".Some(")), 3793 ); 3794} 3795 3796#[test] 3797fn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists() { 3798 let src = r#" 3799import option.{type Option} 3800import opt 3801 3802pub fn main() -> Option(opt.Option(Int)) { 3803 option.Some(opt.Some(1)) 3804} 3805"#; 3806 let title = "Unqualify opt.Option"; 3807 assert_no_code_actions!( 3808 title, 3809 TestProject::for_source(src) 3810 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3811 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3812 find_position_of("opt.").select_until(find_position_of(".Option(")), 3813 ); 3814} 3815 3816#[test] 3817fn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists_below() { 3818 let src = r#" 3819import opt 3820 3821pub fn main() -> Option(opt.Option(Int)) { 3822 option.Some(opt.Some(1)) 3823} 3824import option.{type Option} 3825"#; 3826 let title = "Unqualify opt.Option"; 3827 assert_no_code_actions!( 3828 title, 3829 TestProject::for_source(src) 3830 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3831 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 3832 find_position_of("opt.").select_until(find_position_of(".Option(")), 3833 ); 3834} 3835#[test] 3836fn test_unqualified_to_qualified_import_function() { 3837 let src = r#" 3838import list.{map} 3839 3840pub fn main() { 3841 let identity = map([1, 2, 3], fn(x) { x }) 3842 let double = map([1, 2, 3], fn(x) { x * 2 }) 3843} 3844"#; 3845 assert_code_action!( 3846 "Qualify map as list.map", 3847 TestProject::for_source(src).add_hex_module("list", "pub fn map(list, f) { todo }"), 3848 find_position_of("map(").select_until(find_position_of("[1, 2, 3]")), 3849 ); 3850} 3851 3852#[test] 3853fn test_unqualified_to_qualified_import_constant() { 3854 let src = r#" 3855import mymath.{pi} 3856 3857pub fn circle_area(radius: Float) -> Float { 3858 pi *. radius *. radius 3859} 3860 3861pub fn circle_circumference(radius: Float) -> Float { 3862 2. *. pi *. radius 3863} 3864"#; 3865 assert_code_action!( 3866 "Qualify pi as mymath.pi", 3867 TestProject::for_source(src).add_hex_module("mymath", "pub const pi = 3.14159"), 3868 find_position_of("pi *.").select_until(find_position_of(" radius")), 3869 ); 3870} 3871 3872#[test] 3873fn test_unqualified_to_qualified_import_record_constructor() { 3874 let src = r#" 3875import user.{type User, User} 3876 3877pub fn create_user(name: String) -> User { 3878 User(name: name, id: 1) 3879} 3880"#; 3881 assert_code_action!( 3882 "Qualify User as user.User", 3883 TestProject::for_source(src) 3884 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"), 3885 find_position_of("User(").select_until(find_position_of("name: name")), 3886 ); 3887} 3888 3889#[test] 3890fn test_unqualified_to_qualified_import_after_constructor() { 3891 let src = r#" 3892pub fn create_user(name: String) -> User { 3893 User(name: name, id: 1) 3894} 3895 3896import user.{type User, User} 3897"#; 3898 assert_code_action!( 3899 "Qualify User as user.User", 3900 TestProject::for_source(src) 3901 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"), 3902 find_position_of("User(").select_until(find_position_of("name: name")), 3903 ); 3904} 3905 3906#[test] 3907fn test_unqualified_to_qualified_import_between_constructors() { 3908 let src = r#" 3909pub fn create_user(name: String) -> User { 3910 User(name: name, id: 1) 3911} 3912 3913import user.{type User, User} 3914 3915pub fn user_list(users: List(User)) -> List(String) { 3916 [User(name: "John", id: 1), 3917 User(name: "Jane", id: 2)] 3918} 3919 3920"#; 3921 assert_code_action!( 3922 "Qualify User as user.User", 3923 TestProject::for_source(src) 3924 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"), 3925 find_position_of("User(").select_until(find_position_of("name: name")), 3926 ); 3927} 3928 3929#[test] 3930fn test_unqualified_to_qualified_import_multiple_occurrences() { 3931 let src = r#" 3932import list.{map, filter} 3933 3934pub fn process_list(items: List(Int)) -> List(Int) { 3935 items 3936 |> map(fn(x) { x + 1 }) 3937 |> map(fn(x) { x * 2 }) 3938} 3939"#; 3940 assert_code_action!( 3941 "Qualify map as list.map", 3942 TestProject::for_source(src).add_hex_module( 3943 "list", 3944 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 3945 ), 3946 find_position_of("|> map").select_until(find_position_of("(fn(x)")), 3947 ); 3948} 3949 3950#[test] 3951fn test_unqualified_to_qualified_import_in_pattern_matching() { 3952 let src = r#" 3953import result.{type Result, Ok, Error} 3954 3955pub fn process_result(res: Result(Int, String)) -> Int { 3956 case res { 3957 Ok(value) -> value 3958 Error(_) -> 0 3959 } 3960} 3961"#; 3962 assert_code_action!( 3963 "Qualify Ok as result.Ok", 3964 TestProject::for_source(src) 3965 .add_hex_module("result", "pub type Result(a, e) { Ok(a) Error(e) }"), 3966 find_position_of("Ok(").select_until(find_position_of("value)")), 3967 ); 3968} 3969 3970#[test] 3971fn test_unqualified_to_qualified_import_type_annotation() { 3972 let src = r#" 3973import option.{type Option, Some} 3974 3975pub fn maybe_increment(x: Option(Int)) -> Option(Int) { 3976 case x { 3977 Some(value) -> Some(value + 1) 3978 _ -> x 3979 } 3980} 3981"#; 3982 assert_code_action!( 3983 "Qualify Option as option.Option", 3984 TestProject::for_source(src) 3985 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 3986 find_position_of("Opt") 3987 .nth_occurrence(2) 3988 .select_until(find_position_of("ion(")), 3989 ); 3990} 3991 3992#[test] 3993fn test_unqualified_to_qualified_import_nested_function_call() { 3994 let src = r#" 3995import list.{map, flatten} 3996import operation.{double} 3997 3998pub fn process_names(names: List(List(Int))) -> List(Int) { 3999 names 4000 |> flatten 4001 |> map(double) 4002} 4003"#; 4004 assert_code_action!( 4005 "Qualify double as operation.double", 4006 TestProject::for_source(src) 4007 .add_hex_module( 4008 "list", 4009 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo } 4010pub fn flatten(lists: List(List(a))) -> List(a) { todo }" 4011 ) 4012 .add_hex_module("operation", "pub fn double(s: Int) -> Int { todo }"), 4013 find_position_of("(dou").select_until(find_position_of("ble)")), 4014 ); 4015} 4016 4017#[test] 4018fn test_unqualified_to_qualified_import_with_alias() { 4019 let src = r#" 4020import list.{map as transform} 4021 4022pub fn double_list(items: List(Int)) -> List(Int) { 4023 transform(items, fn(x) { x * 2 }) 4024} 4025"#; 4026 assert_code_action!( 4027 "Qualify transform as list.map", 4028 TestProject::for_source(src).add_hex_module( 4029 "list", 4030 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4031 ), 4032 find_position_of("transform(").select_until(find_position_of("items,")), 4033 ); 4034} 4035 4036#[test] 4037fn test_unqualified_to_qualified_import_with_alias_and_module_alias() { 4038 let src = r#" 4039import list.{map as transform} as lst 4040 4041pub fn double_list(items: List(Int)) -> List(Int) { 4042 transform(items, fn(x) { x * 2 }) 4043} 4044"#; 4045 assert_code_action!( 4046 "Qualify transform as lst.map", 4047 TestProject::for_source(src).add_hex_module( 4048 "list", 4049 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4050 ), 4051 find_position_of("transform(").select_until(find_position_of("items,")), 4052 ); 4053} 4054 4055#[test] 4056fn test_unqualified_to_qualified_import_import_discarded() { 4057 let src = r#" 4058import list.{map as transform} as _ 4059 4060pub fn double_list(items: List(Int)) -> List(Int) { 4061 transform(items, fn(x) { x * 2 }) 4062} 4063"#; 4064 let title = "Qualify transform as list.map"; 4065 assert_no_code_actions!( 4066 title, 4067 TestProject::for_source(src).add_hex_module( 4068 "list", 4069 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4070 ), 4071 find_position_of("transform(").select_until(find_position_of("items,")), 4072 ); 4073} 4074 4075#[test] 4076fn test_unqualified_to_qualified_import_bad_formatted_type_constructor() { 4077 let src = r#" 4078import option.{type Option, Some} 4079 4080pub fn maybe_increment(x: Option(Int)) -> Option(Int) { 4081 case x { 4082 Some(value) -> Some(value + 1) 4083 _ -> x 4084 } 4085} 4086"#; 4087 assert_code_action!( 4088 "Qualify Option as option.Option", 4089 TestProject::for_source(src) 4090 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4091 find_position_of("Opt") 4092 .nth_occurrence(2) 4093 .select_until(find_position_of("ion(")), 4094 ); 4095} 4096 4097#[test] 4098fn test_unqualified_to_qualified_import_bad_formatted_type_constructor_with_alias() { 4099 let src = r#" 4100import option.{type Option as Maybe, Some} 4101 4102pub fn maybe_increment(x: Maybe(Int)) -> Maybe(Int) { 4103 case x { 4104 Some(value) -> Some(value + 1) 4105 _ -> x 4106 } 4107} 4108"#; 4109 assert_code_action!( 4110 "Qualify Maybe as option.Option", 4111 TestProject::for_source(src) 4112 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4113 find_position_of("May") 4114 .nth_occurrence(2) 4115 .select_until(find_position_of("be(")), 4116 ); 4117} 4118 4119#[test] 4120fn test_unqualified_to_qualified_import_bad_formatted_comma() { 4121 let src = r#" 4122import option.{type Option , Some} 4123 4124pub fn maybe_increment(x: Option(Int)) -> Option(Int) { 4125 case x { 4126 Some(value) -> Some(value + 1) 4127 _ -> x 4128 } 4129} 4130"#; 4131 assert_code_action!( 4132 "Qualify Option as option.Option", 4133 TestProject::for_source(src) 4134 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4135 find_position_of("Opt") 4136 .nth_occurrence(2) 4137 .select_until(find_position_of("ion(")), 4138 ); 4139} 4140 4141#[test] 4142fn test_unqualified_to_qualified_import_in_list_and_tuple() { 4143 let src = r#" 4144import option.{Some} 4145 4146pub fn main() { 4147 let list = [Some(1), option.None] 4148 let tuple = #(Some(2), option.None) 4149} 4150"#; 4151 assert_code_action!( 4152 "Qualify Some as option.Some", 4153 TestProject::for_source(src) 4154 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4155 find_position_of("Some(").select_until(find_position_of("1)")), 4156 ); 4157} 4158#[test] 4159fn test_unqualified_to_qualified_import_constructor_complex_pattern() { 4160 let src = r#" 4161import option.{None, Some} 4162 4163pub fn main() { 4164 case [Some(1), None] { 4165 [None, ..] -> todo 4166 [Some(_), ..] -> todo 4167 _ -> todo 4168 } 4169 case Some(1), Some(2) { 4170 None, Some(_) -> todo 4171 Some(_), Some(val) -> todo 4172 _ -> todo 4173 } 4174} 4175"#; 4176 assert_code_action!( 4177 "Qualify Some as option.Some", 4178 TestProject::for_source(src) 4179 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4180 find_position_of("Some(").select_until(find_position_of("1)")), 4181 ); 4182} 4183 4184#[test] 4185fn test_unqualified_to_qualified_import_multiple_line_aliased() { 4186 let src = r#" 4187import option.{ 4188 type Option, 4189 None, 4190 Some 4191} as opt 4192 4193pub fn main() { 4194 Some(1) 4195} 4196"#; 4197 assert_code_action!( 4198 "Qualify Some as opt.Some", 4199 TestProject::for_source(src) 4200 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4201 find_position_of("Some") 4202 .nth_occurrence(2) 4203 .select_until(find_position_of("(1)")), 4204 ); 4205} 4206 4207#[test] 4208fn test_unqualified_to_qualified_import_multiple_line_bad_format_without_trailing_comma() { 4209 let src = r#" 4210import option.{type Option, 4211 Some 4212 4213} 4214 4215pub fn main() { 4216 Some(1) 4217} 4218"#; 4219 assert_code_action!( 4220 "Qualify Some as option.Some", 4221 TestProject::for_source(src) 4222 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4223 find_position_of("Some") 4224 .nth_occurrence(2) 4225 .select_until(find_position_of("(1)")), 4226 ); 4227} 4228 4229#[test] 4230fn test_unqualified_to_qualified_import_variable_shadowing() { 4231 let src = r#" 4232 4233import wibble.{wobble} 4234 4235pub fn example() { 4236 echo wobble 4237 4238 let wobble = 1 4239 4240 echo wobble 4241 4242 let _ = fn(wobble) { 4243 echo wobble 4244 } 4245 4246 todo 4247} 4248"#; 4249 4250 assert_code_action!( 4251 "Qualify wobble as wibble.wobble", 4252 TestProject::for_source(src).add_hex_module("wibble", "pub fn wobble() { todo }"), 4253 find_position_of("wob") 4254 .nth_occurrence(2) 4255 .select_until(find_position_of("ble").nth_occurrence(3)) 4256 ); 4257} 4258 4259/* TODO: implement qualified unused location 4260#[test] 4261fn test_remove_unused_qualified_action() { 4262 let code = " 4263// test 4264import map.{Map, delete} 4265"; 4266 let expected = " 4267// test 4268 4269"; 4270 assert_eq!(remove_unused_action(code), expected.to_string()) 4271} 4272 4273#[test] 4274fn test_remove_unused_qualified_partial_action() { 4275 let code = " 4276// test 4277import result.{is_ok, is_err} 4278 4279pub fn main() { 4280 is_ok 4281} 4282"; 4283 let expected = " 4284// test 4285import result.{is_ok} 4286 4287pub fn main() { 4288 is_ok 4289} 4290"; 4291 assert_eq!(remove_unused_action(code), expected.to_string()) 4292} 4293 4294#[test] 4295fn test_remove_unused_qualified_partial2_action() { 4296 let code = " 4297// test 4298import result.{all, is_ok, is_err} 4299 4300pub fn main() { 4301 is_ok 4302} 4303"; 4304 let expected = " 4305// test 4306import result.{ is_ok} 4307 4308pub fn main() { 4309 is_ok 4310} 4311"; 4312 assert_eq!(remove_unused_action(code), expected.to_string()) 4313} 4314 4315#[test] 4316fn test_remove_unused_qualified_partial3_action() { 4317 let code = " 4318// test 4319import result.{all, is_ok, is_err} as res 4320 4321pub fn main() { 4322 is_ok 4323} 4324"; 4325 let expected = " 4326// test 4327import result.{ is_ok} as res 4328 4329pub fn main() { 4330 is_ok 4331} 4332"; 4333 assert_eq!(remove_unused_action(code), expected.to_string()) 4334} 4335*/ 4336 4337#[test] 4338fn convert_from_use_expression_with_no_parens() { 4339 let src = r#" 4340pub fn main() { 4341 use <- wibble 4342 todo 4343 todo 4344} 4345 4346fn wibble(f) { 4347 f() 4348} 4349"#; 4350 assert_code_action!( 4351 CONVERT_FROM_USE, 4352 TestProject::for_source(src), 4353 find_position_of("use").select_until(find_position_of("wibble")), 4354 ); 4355} 4356 4357#[test] 4358fn convert_from_use_expression_with_empty_parens() { 4359 let src = r#" 4360pub fn main() { 4361 use <- wibble() 4362 todo 4363 todo 4364} 4365 4366fn wibble(f) { 4367 f() 4368} 4369"#; 4370 assert_code_action!( 4371 CONVERT_FROM_USE, 4372 TestProject::for_source(src), 4373 find_position_of("use").to_selection(), 4374 ); 4375} 4376 4377#[test] 4378fn convert_from_use_expression_with_parens_and_other_args() { 4379 let src = r#" 4380pub fn main() { 4381 use <- wibble(1, 2) 4382 todo 4383 todo 4384} 4385 4386fn wibble(n, m, f) { 4387 f() 4388} 4389"#; 4390 assert_code_action!( 4391 CONVERT_FROM_USE, 4392 TestProject::for_source(src), 4393 find_position_of("wibble").select_until(find_position_of("1")), 4394 ); 4395} 4396 4397#[test] 4398fn convert_from_use_expression_with_single_pattern() { 4399 let src = r#" 4400pub fn main() { 4401 use a <- wibble(1, 2) 4402 todo 4403 todo 4404} 4405 4406fn wibble(n, m, f) { 4407 f(1) 4408} 4409"#; 4410 assert_code_action!( 4411 CONVERT_FROM_USE, 4412 TestProject::for_source(src), 4413 find_position_of("a <-").to_selection(), 4414 ); 4415} 4416 4417#[test] 4418fn convert_from_use_expression_with_multiple_patterns() { 4419 let src = r#" 4420pub fn main() { 4421 use a, b <- wibble(1, 2) 4422 todo 4423 todo 4424} 4425 4426fn wibble(n, m, f) { 4427 f(1, 2) 4428} 4429"#; 4430 assert_code_action!( 4431 CONVERT_FROM_USE, 4432 TestProject::for_source(src), 4433 find_position_of("wibble").to_selection(), 4434 ); 4435} 4436 4437#[test] 4438fn desugar_nested_use_expressions_picks_inner_under_cursor() { 4439 let src = r#" 4440pub fn main() { 4441 use a, b <- wibble(1, 2) 4442 use a, b <- wibble(a, b) 4443 todo 4444} 4445 4446fn wibble(n, m, f) { 4447 f(1, 2) 4448} 4449"#; 4450 assert_code_action!( 4451 CONVERT_FROM_USE, 4452 TestProject::for_source(src), 4453 find_position_of("use").nth_occurrence(2).to_selection(), 4454 ); 4455} 4456 4457#[test] 4458fn convert_from_use_only_triggers_on_the_use_line() { 4459 let src = r#" 4460pub fn main() { 4461 use a, b <- wibble(1, 2) 4462 todo 4463} 4464 4465fn wibble(n, m, f) { 4466 f(1, 2) 4467} 4468"#; 4469 assert_no_code_actions!( 4470 CONVERT_FROM_USE, 4471 TestProject::for_source(src), 4472 find_position_of("todo").to_selection(), 4473 ); 4474} 4475 4476#[test] 4477fn desugar_nested_use_expressions_picks_inner_under_cursor_2() { 4478 let src = r#" 4479pub fn main() { 4480 use a, b <- wibble(1, 2) 4481 use a, b <- wibble(a, b) 4482 todo 4483} 4484 4485fn wibble(n, m, f) { 4486 f(1, 2) 4487} 4488"#; 4489 assert_code_action!( 4490 CONVERT_FROM_USE, 4491 TestProject::for_source(src), 4492 find_position_of("<-").select_until(find_position_of("wibble")), 4493 ); 4494} 4495 4496#[test] 4497fn convert_from_use_expression_with_type_annotations() { 4498 let src = r#" 4499pub fn main() { 4500 use a: Int, b: Int <- wibble(1, 2) 4501 todo 4502} 4503 4504fn wibble(n, m, f) { 4505 f(1, 2) 4506} 4507"#; 4508 assert_code_action!( 4509 CONVERT_FROM_USE, 4510 TestProject::for_source(src), 4511 find_position_of("<-").select_until(find_position_of("wibble")), 4512 ); 4513} 4514 4515#[test] 4516fn convert_from_use_expression_doesnt_work_with_complex_patterns() { 4517 let src = r#" 4518pub fn main() { 4519 use #(a, b), 1 <- wibble(1, 2) 4520 todo 4521} 4522 4523fn wibble(n, m, f) { 4524 f(todo, todo) 4525} 4526"#; 4527 assert_no_code_actions!( 4528 CONVERT_FROM_USE, 4529 TestProject::for_source(src), 4530 find_position_of("<-").select_until(find_position_of("wibble")), 4531 ); 4532} 4533 4534#[test] 4535fn convert_from_use_with_labels() { 4536 let src = r#" 4537pub fn main() { 4538 use a <- wibble(one: 1, two: 2) 4539 todo 4540} 4541 4542fn wibble(one _, two _, three f) { 4543 f(1) 4544} 4545"#; 4546 assert_code_action!( 4547 CONVERT_FROM_USE, 4548 TestProject::for_source(src), 4549 find_position_of("use").to_selection(), 4550 ); 4551} 4552 4553#[test] 4554fn convert_from_use_with_labels_2() { 4555 let src = r#" 4556pub fn main() { 4557 use a <- wibble(1, two: 2) 4558 todo 4559} 4560 4561fn wibble(one _, two _, three f) { 4562 f(1) 4563} 4564"#; 4565 assert_code_action!( 4566 CONVERT_FROM_USE, 4567 TestProject::for_source(src), 4568 find_position_of("use").to_selection(), 4569 ); 4570} 4571 4572#[test] 4573fn convert_from_use_with_labels_3() { 4574 let src = r#" 4575pub fn main() { 4576 use a <- wibble(1, three: 3) 4577 todo 4578} 4579 4580fn wibble(one _, two f, three _) { 4581 f(1) 4582} 4583"#; 4584 assert_code_action!( 4585 CONVERT_FROM_USE, 4586 TestProject::for_source(src), 4587 find_position_of("use").to_selection(), 4588 ); 4589} 4590 4591#[test] 4592fn convert_from_use_with_labels_4() { 4593 let src = r#" 4594pub fn main() { 4595 use a <- wibble(two: 2, three: 3) 4596 todo 4597} 4598 4599fn wibble(one f, two _, three _) { 4600 f(1) 4601} 4602"#; 4603 assert_code_action!( 4604 CONVERT_FROM_USE, 4605 TestProject::for_source(src), 4606 find_position_of("use").to_selection(), 4607 ); 4608} 4609 4610#[test] 4611// https://github.com/gleam-lang/gleam/issues/4149 4612fn convert_from_use_with_trailing_comma() { 4613 let src = r#" 4614pub fn main() { 4615 use a, b <- wibble(1, 2,) 4616 todo 4617} 4618 4619fn wibble(n, m, f) { 4620 f(todo, todo) 4621} 4622"#; 4623 assert_code_action!( 4624 CONVERT_FROM_USE, 4625 TestProject::for_source(src), 4626 find_position_of("<-").select_until(find_position_of("wibble")), 4627 ); 4628} 4629 4630#[test] 4631fn convert_from_use_with_trailing_comma_2() { 4632 let src = r#" 4633pub fn main() { 4634 use a, b <- wibble( 4635 1, 4636 2, 4637 ) 4638 todo 4639} 4640 4641fn wibble(n, m, f) { 4642 f(todo, todo) 4643} 4644"#; 4645 assert_code_action!( 4646 CONVERT_FROM_USE, 4647 TestProject::for_source(src), 4648 find_position_of("<-").select_until(find_position_of("wibble")), 4649 ); 4650} 4651 4652#[test] 4653fn convert_from_use_with_trailing_comma_and_label() { 4654 let src = r#" 4655pub fn main() { 4656 use a, b <- wibble( 4657 1, 4658 wibble: 2, 4659 ) 4660 todo 4661} 4662 4663fn wibble(n, wibble m, wobble f) { 4664 f(todo, todo) 4665} 4666"#; 4667 assert_code_action!( 4668 CONVERT_FROM_USE, 4669 TestProject::for_source(src), 4670 find_position_of("<-").select_until(find_position_of("wibble")), 4671 ); 4672} 4673 4674#[test] 4675fn convert_from_use_multiline_with_no_trailing_comma() { 4676 let src = r#" 4677pub fn main() { 4678 use a, b <- wibble( 4679 1, 4680 2 4681 ) 4682 todo 4683} 4684 4685fn wibble(n, m, f) { 4686 f(todo, todo) 4687} 4688"#; 4689 assert_code_action!( 4690 CONVERT_FROM_USE, 4691 TestProject::for_source(src), 4692 find_position_of("<-").select_until(find_position_of("wibble")), 4693 ); 4694} 4695 4696#[test] 4697fn turn_call_into_use_with_single_line_body() { 4698 let src = r#" 4699pub fn main() { 4700 wibble(fn(a, b) { todo }) 4701} 4702 4703fn wibble(f) { 4704 f(todo, todo) 4705} 4706"#; 4707 assert_code_action!( 4708 CONVERT_TO_USE, 4709 TestProject::for_source(src), 4710 find_position_of("wibble").to_selection(), 4711 ); 4712} 4713 4714#[test] 4715fn turn_call_into_use_with_fn_with_no_args() { 4716 let src = r#" 4717pub fn main() { 4718 wibble(fn() { todo }) 4719} 4720 4721fn wibble(f) { 4722 f() 4723} 4724"#; 4725 assert_code_action!( 4726 CONVERT_TO_USE, 4727 TestProject::for_source(src), 4728 find_position_of("wibble").to_selection(), 4729 ); 4730} 4731 4732#[test] 4733fn turn_call_with_multiple_arguments_into_use() { 4734 let src = r#" 4735pub fn main() { 4736 wibble(1, 2, fn(a) { todo }) 4737} 4738 4739fn wibble(m, n, f) { 4740 f(1) 4741} 4742"#; 4743 assert_code_action!( 4744 CONVERT_TO_USE, 4745 TestProject::for_source(src), 4746 find_position_of("todo").to_selection(), 4747 ); 4748} 4749 4750#[test] 4751fn turn_call_with_multiline_fn_into_use() { 4752 let src = r#" 4753pub fn main() { 4754 wibble(1, 2, fn(a) { 4755 todo 4756 case todo { 4757 _ -> todo 4758 } 4759 }) 4760} 4761 4762fn wibble(m, n, f) { 4763 f(1) 4764} 4765"#; 4766 assert_code_action!( 4767 CONVERT_TO_USE, 4768 TestProject::for_source(src), 4769 find_position_of("1, 2").select_until(find_position_of("fn(a)")), 4770 ); 4771} 4772 4773#[test] 4774fn turn_call_with_fn_with_type_annotations_into_use() { 4775 let src = r#" 4776pub fn main() { 4777 wibble(1, 2, fn(a: Int) { 4778 todo 4779 }) 4780} 4781 4782fn wibble(m, n, f) { 4783 f(1) 4784} 4785"#; 4786 assert_code_action!( 4787 CONVERT_TO_USE, 4788 TestProject::for_source(src), 4789 find_position_of("wibble").select_until(find_position_of("a: ")), 4790 ); 4791} 4792 4793#[test] 4794fn turn_call_into_use_only_works_on_last_call_in_a_block() { 4795 let src = r#" 4796pub fn main() { 4797 wibble(10, 20, fn(a) { todo }) 4798 wibble(1, 2, fn(a) { todo }) 4799} 4800 4801fn wibble(m, n, f) { 4802 f(1) 4803} 4804"#; 4805 assert_no_code_actions!( 4806 CONVERT_TO_USE, 4807 TestProject::for_source(src), 4808 find_position_of("10").to_selection(), 4809 ); 4810} 4811 4812#[test] 4813fn turn_call_into_use_only_works_on_last_call_in_a_block_2() { 4814 let src = r#" 4815pub fn main() { 4816 { 4817 wibble(10, 20, fn(a) { todo }) 4818 wibble(1, 2, fn(a) { todo }) 4819 } 4820 Nil 4821} 4822 4823fn wibble(m, n, f) { 4824 f(1) 4825} 4826"#; 4827 assert_no_code_actions!( 4828 CONVERT_TO_USE, 4829 TestProject::for_source(src), 4830 find_position_of("10").to_selection(), 4831 ); 4832} 4833 4834#[test] 4835fn turn_call_into_use_with_last_function_in_a_block() { 4836 let src = r#" 4837pub fn main() { 4838 { 4839 wibble(10, 20, fn(a) { todo }) 4840 wibble(1, 11, fn(a) { todo }) 4841 } 4842 Nil 4843} 4844 4845fn wibble(m, n, f) { 4846 f(1) 4847} 4848"#; 4849 assert_code_action!( 4850 CONVERT_TO_USE, 4851 TestProject::for_source(src), 4852 find_position_of("wibble(1,").select_until(find_position_of("11")), 4853 ); 4854} 4855 4856#[test] 4857fn turn_call_into_use_starts_from_innermost_function() { 4858 let src = r#" 4859pub fn main() { 4860 wibble(10, 20, fn(a) { 4861 wibble(30, 40, fn(b) { 4862 a + b 4863 }) 4864 }) 4865} 4866 4867fn wibble(m, n, f) { 4868 f(1) 4869} 4870"#; 4871 assert_code_action!( 4872 CONVERT_TO_USE, 4873 TestProject::for_source(src), 4874 find_position_of("30").select_until(find_position_of("40")), 4875 ); 4876} 4877 4878#[test] 4879fn turn_call_into_use_with_another_use_in_the_way() { 4880 let src = r#" 4881pub fn main() { 4882 wibble(10, 20, fn(a) { 4883 use b <- wibble(30, 40) 4884 a + b 4885 }) 4886} 4887 4888fn wibble(m, n, f) { 4889 f(1) 4890} 4891"#; 4892 assert_code_action!( 4893 CONVERT_TO_USE, 4894 TestProject::for_source(src), 4895 find_position_of("use").to_selection(), 4896 ); 4897} 4898 4899#[test] 4900fn turn_call_into_use_with_module_function() { 4901 let src = r#" 4902import other 4903pub fn main() { 4904 other.wibble(10, 20, fn(a) { 4905 todo 4906 a + b 4907 }) 4908} 4909"#; 4910 assert_code_action!( 4911 CONVERT_TO_USE, 4912 TestProject::for_source(src).add_module("other", "pub fn wibble(n, m, f) { todo }"), 4913 find_position_of("wibble").to_selection(), 4914 ); 4915} 4916 4917#[test] 4918// https://github.com/gleam-lang/gleam/issues/4498 4919fn turn_call_into_use_with_out_of_order_arguments() { 4920 assert_code_action!( 4921 CONVERT_TO_USE, 4922 r#" 4923pub fn main() { 4924 fold(0, over: [], with: fn (a, b) { todo }) 4925} 4926 4927fn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc { 4928 todo 4929} 4930"#, 4931 find_position_of("fold").to_selection(), 4932 ); 4933} 4934 4935#[test] 4936fn inexhaustive_let_result_to_case() { 4937 assert_code_action!( 4938 CONVERT_TO_CASE, 4939 "pub fn main(result) { 4940 let Ok(value) = result 4941}", 4942 find_position_of("let").select_until(find_position_of("=")), 4943 ); 4944} 4945 4946#[test] 4947fn inexhaustive_let_to_case_indented() { 4948 assert_code_action!( 4949 CONVERT_TO_CASE, 4950 "pub fn main(result) { 4951 { 4952 let Ok(value) = result 4953 } 4954}", 4955 find_position_of("let").select_until(find_position_of("=")), 4956 ); 4957} 4958 4959#[test] 4960fn inexhaustive_let_to_case_multi_variables() { 4961 assert_code_action!( 4962 CONVERT_TO_CASE, 4963 "pub fn main() { 4964 let [var1, var2, _var3, var4] = [1, 2, 3, 4] 4965}", 4966 find_position_of("let").select_until(find_position_of("=")), 4967 ); 4968} 4969 4970#[test] 4971fn inexhaustive_let_to_case_discard() { 4972 assert_code_action!( 4973 CONVERT_TO_CASE, 4974 "pub fn main() { 4975 let [_elem] = [6] 4976}", 4977 find_position_of("let").select_until(find_position_of("=")), 4978 ); 4979} 4980 4981#[test] 4982fn inexhaustive_let_to_case_no_variables() { 4983 assert_code_action!( 4984 CONVERT_TO_CASE, 4985 "pub fn main() { 4986 let [] = [] 4987}", 4988 find_position_of("let").select_until(find_position_of("=")), 4989 ); 4990} 4991 4992#[test] 4993fn inexhaustive_let_alias_to_case() { 4994 assert_code_action!( 4995 CONVERT_TO_CASE, 4996 "pub fn main() { 4997 let 10 as ten = 10 4998}", 4999 find_position_of("let").select_until(find_position_of("=")), 5000 ); 5001} 5002 5003#[test] 5004fn inexhaustive_let_tuple_to_case() { 5005 assert_code_action!( 5006 CONVERT_TO_CASE, 5007 "pub fn main() { 5008 let #(first, 10, third) = #(5, 10, 15) 5009} 5010", 5011 find_position_of("let").select_until(find_position_of("=")), 5012 ); 5013} 5014 5015#[test] 5016fn inexhaustive_let_bit_array_to_case() { 5017 assert_code_action!( 5018 CONVERT_TO_CASE, 5019 "pub fn main() { 5020 let <<bits1, bits2>> = <<73, 98>> 5021}", 5022 find_position_of("let").select_until(find_position_of("=")), 5023 ); 5024} 5025 5026#[test] 5027fn inexhaustive_let_string_prefix_to_case() { 5028 assert_code_action!( 5029 CONVERT_TO_CASE, 5030 r#"pub fn main() { 5031 let "_" <> thing = "_Hello" 5032}"#, 5033 find_position_of("let").select_until(find_position_of("=")), 5034 ); 5035} 5036 5037#[test] 5038fn inexhaustive_let_string_prefix_pattern_alias_to_case() { 5039 assert_code_action!( 5040 CONVERT_TO_CASE, 5041 r#"pub fn main() { 5042 let "123" as one_two_three <> rest = "123456" 5043}"#, 5044 find_position_of("let").select_until(find_position_of("=")), 5045 ); 5046} 5047 5048#[test] 5049fn inner_inexhaustive_let_to_case() { 5050 assert_code_action!( 5051 CONVERT_TO_CASE, 5052 r#"pub fn main(result) { 5053 let [wibble] = { 5054 let Ok(wobble) = { 5055 result 5056 } 5057 [wobble] 5058 } 5059}"#, 5060 find_position_of("let Ok").select_until(find_position_of(") =")), 5061 ); 5062} 5063 5064#[test] 5065fn outer_inexhaustive_let_to_case() { 5066 assert_code_action!( 5067 CONVERT_TO_CASE, 5068 r#"pub fn main(result) { 5069 let [wibble] = { 5070 let Ok(wobble) = { 5071 result 5072 } 5073 [wobble] 5074 } 5075}"#, 5076 find_position_of("let [").select_until(find_position_of("] =")), 5077 ); 5078} 5079 5080#[test] 5081fn no_code_action_for_exhaustive_let_to_case() { 5082 assert_no_code_actions!( 5083 CONVERT_TO_CASE, 5084 r#"pub fn first(pair) { 5085 let #(first, second) = pair 5086 first 5087}"#, 5088 find_position_of("let").select_until(find_position_of("=")), 5089 ); 5090} 5091 5092#[test] 5093fn extract_variable() { 5094 assert_code_action!( 5095 EXTRACT_VARIABLE, 5096 r#"pub fn main() { 5097 list.map([1, 2, 3], int.add(1, _)) 5098}"#, 5099 find_position_of("[1").select_until(find_position_of("2")) 5100 ); 5101} 5102 5103#[test] 5104fn extract_variable_does_not_extract_a_variable() { 5105 assert_no_code_actions!( 5106 EXTRACT_VARIABLE, 5107 r#"pub fn main() { 5108 let z = 1 5109 let a = [1, 2, z] 5110}"#, 5111 find_position_of("z").nth_occurrence(2).to_selection() 5112 ); 5113} 5114 5115#[test] 5116fn extract_variable_does_not_extract_top_level_statement() { 5117 assert_no_code_actions!( 5118 EXTRACT_VARIABLE, 5119 r#"pub fn main() { 5120 let wibble = 1 5121}"#, 5122 find_position_of("1").to_selection() 5123 ); 5124} 5125 5126#[test] 5127fn extract_variable_does_not_extract_top_level_statement_inside_block() { 5128 assert_no_code_actions!( 5129 EXTRACT_VARIABLE, 5130 r#"pub fn main() { 5131 let x = { 5132 let y = "y" 5133 let w = "w" <> y 5134 w 5135 } 5136}"#, 5137 find_position_of("y").nth_occurrence(2).to_selection() 5138 ); 5139} 5140 5141#[test] 5142fn extract_variable_does_not_extract_top_level_statement_inside_use() { 5143 assert_no_code_actions!( 5144 EXTRACT_VARIABLE, 5145 " 5146pub fn main() { 5147 use x <- try(Ok(1)) 5148 let y = 2 5149 Ok(y + x) 5150} 5151pub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo } 5152", 5153 find_position_of("2").to_selection() 5154 ); 5155} 5156 5157#[test] 5158fn extract_variable_does_not_extract_use() { 5159 assert_no_code_actions!( 5160 EXTRACT_VARIABLE, 5161 " 5162pub fn main() { 5163 use x <- try(Ok(1)) 5164 Ok(x) 5165} 5166pub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo } 5167", 5168 find_position_of("use").to_selection() 5169 ); 5170} 5171 5172#[test] 5173fn extract_variable_does_not_extract_panic() { 5174 assert_no_code_actions!( 5175 EXTRACT_VARIABLE, 5176 r#"pub fn main() { 5177 let x = 1 5178 panic 5179}"#, 5180 find_position_of("panic").to_selection() 5181 ); 5182} 5183 5184#[test] 5185fn extract_variable_does_not_extract_echo() { 5186 assert_no_code_actions!( 5187 EXTRACT_VARIABLE, 5188 r#"pub fn main() { 5189 let x = 1 5190 echo x 5191}"#, 5192 find_position_of("echo").to_selection() 5193 ); 5194} 5195 5196#[test] 5197fn extract_variable_does_not_extract_assignment() { 5198 assert_no_code_actions!( 5199 EXTRACT_VARIABLE, 5200 r#"pub fn main() { 5201 let x = 1 5202}"#, 5203 find_position_of("x").to_selection() 5204 ); 5205} 5206 5207#[test] 5208fn extract_variable_does_not_extract_record_variable_in_record_update() { 5209 assert_no_code_actions!( 5210 EXTRACT_VARIABLE, 5211 r#" 5212type Wibble { Wibble(one: Int, two: Int) } 5213 5214pub fn main() { 5215 let wibble = todo 5216 Wibble(..wibble, one: 1) 5217}"#, 5218 find_position_of("wibble").nth_occurrence(2).to_selection() 5219 ); 5220} 5221 5222#[test] 5223fn extract_variable_from_arg_in_pipelined_call() { 5224 assert_code_action!( 5225 EXTRACT_VARIABLE, 5226 " 5227pub fn main() { 5228 let adder = add 5229 let x = [4, 5, 6] |> map2([1, 2, 3], adder) 5230 x 5231} 5232pub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo } 5233pub fn add(a: Int, b: Int) -> Int { todo } 5234", 5235 find_position_of("[1").to_selection() 5236 ); 5237} 5238 5239#[test] 5240fn extract_variable_from_arg_in_pipelined_call_to_capture() { 5241 assert_code_action!( 5242 EXTRACT_VARIABLE, 5243 " 5244pub fn main() { 5245 let adder = add 5246 let x = adder |> reduce([1, 2, 3], _) 5247 x 5248} 5249pub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo } 5250pub fn add(a: Int, b: Int) -> Int { todo } 5251", 5252 find_position_of("[1").to_selection() 5253 ); 5254} 5255 5256#[test] 5257fn extract_variable_from_arg_in_pipelined_call_of_function_to_capture() { 5258 assert_code_action!( 5259 EXTRACT_VARIABLE, 5260 " 5261pub fn main() { 5262 fn(total, item) { total + item } 5263 |> fold(with: _, from: 0, over: [1, 2, 3]) 5264} 5265pub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo } 5266", 5267 find_position_of("fold").to_selection() 5268 ); 5269} 5270 5271#[test] 5272fn extract_variable_from_arg_in_nested_function_called_in_pipeline() { 5273 assert_code_action!( 5274 EXTRACT_VARIABLE, 5275 " 5276pub fn main() { 5277 let result = 5278 [1, 2, 3] 5279 |> map(add(_, 1)) 5280 |> map(subtract(_, 9)) 5281 5282 result 5283} 5284pub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 5285pub fn add(a: Int, b: Int) -> Int { todo } 5286pub fn subtract(a: Int, b: Int) -> Int { todo } 5287", 5288 find_position_of("9").to_selection() 5289 ); 5290} 5291 5292#[test] 5293fn extract_variable_does_not_extract_an_entire_pipeline_step() { 5294 assert_no_code_actions!( 5295 EXTRACT_VARIABLE, 5296 " 5297pub fn main() { 5298 [1, 2, 3] 5299 |> map(todo) 5300 |> map(todo) 5301} 5302 5303fn map(list, fun) { todo } 5304", 5305 find_position_of("map").to_selection() 5306 ); 5307} 5308 5309#[test] 5310fn extract_variable_does_not_extract_the_last_pipeline_step() { 5311 assert_no_code_actions!( 5312 EXTRACT_VARIABLE, 5313 r#"pub fn main() { 5314 [1, 2, 3] 5315 |> map(todo) 5316 |> map(todo) 5317} 5318 5319fn map(list, fun) { todo } 5320"#, 5321 find_position_of("map").to_selection() 5322 ); 5323} 5324 5325#[test] 5326fn extract_variable_2() { 5327 assert_code_action!( 5328 EXTRACT_VARIABLE, 5329 " 5330pub fn main() { 5331 map([1, 2, 3], add(1, _)) 5332} 5333pub fn add(n, m) { todo } 5334pub fn map(l, f) { todo } 5335", 5336 find_position_of("add").to_selection() 5337 ); 5338} 5339 5340#[test] 5341fn extract_variable_from_capture_arguments() { 5342 assert_no_code_actions!( 5343 EXTRACT_VARIABLE, 5344 r#"pub fn main() { 5345 int.add(1, _) 5346}"#, 5347 find_position_of("_").to_selection() 5348 ); 5349} 5350 5351#[test] 5352fn extract_variable_from_capture_arguments_2() { 5353 assert_code_action!( 5354 EXTRACT_VARIABLE, 5355 r#"pub fn main() { 5356 int.add(11, _) 5357}"#, 5358 find_position_of("11").to_selection() 5359 ); 5360} 5361 5362#[test] 5363fn extract_variable_3() { 5364 assert_code_action!( 5365 EXTRACT_VARIABLE, 5366 r#"pub fn main() { 5367 list.map([1, 2, 3], todo, todo) 5368}"#, 5369 find_position_of("todo") 5370 .nth_occurrence(2) 5371 .select_until(find_position_of("todo)").under_last_char()) 5372 ); 5373} 5374 5375#[test] 5376fn extract_variable_inside_multiline_function_call() { 5377 assert_code_action!( 5378 EXTRACT_VARIABLE, 5379 r#"pub fn main() { 5380 list.map( 5381 [1, 2, 3], 5382 int.add(1, _), 5383 ) 5384}"#, 5385 find_position_of("[1").to_selection() 5386 ); 5387} 5388 5389#[test] 5390fn extract_variable_in_case_branch() { 5391 assert_code_action!( 5392 EXTRACT_VARIABLE, 5393 r#"pub fn main() { 5394 case wibble { 5395 _ -> [1, 2, 3] 5396 } 5397}"#, 5398 find_position_of("[1").to_selection() 5399 ); 5400} 5401 5402#[test] 5403fn extract_variable_in_multiline_case_subject_branch() { 5404 assert_code_action!( 5405 EXTRACT_VARIABLE, 5406 r#"pub fn main() { 5407 case 5408 list.map( 5409 [1, 2, 3], 5410 int.add(1, _) 5411 ) 5412 { 5413 _ -> todo 5414 } 5415}"#, 5416 find_position_of("[1").to_selection() 5417 ); 5418} 5419 5420#[test] 5421fn extract_variable_in_case_branch_using_var() { 5422 assert_code_action!( 5423 EXTRACT_VARIABLE, 5424 r#"pub fn main() { 5425 case todo { 5426 Ok(value) -> 2 * value + 1 5427 Error(_) -> panic 5428 } 5429}"#, 5430 find_position_of("2").select_until(find_position_of("value").nth_occurrence(2)) 5431 ); 5432} 5433 5434#[test] 5435fn extract_variable_in_case_branch_from_second_arg() { 5436 assert_code_action!( 5437 EXTRACT_VARIABLE, 5438 r#"pub fn main() { 5439 case todo { 5440 Ok(_) -> #(Ok(1), Error("s")) 5441 Error(_) -> panic 5442 } 5443}"#, 5444 find_position_of("E").to_selection() 5445 ); 5446} 5447 5448#[test] 5449fn extract_variable_in_use() { 5450 assert_code_action!( 5451 EXTRACT_VARIABLE, 5452 r#"pub fn main() { 5453 use <- wibble([1, 2, 3]) 5454 todo 5455}"#, 5456 find_position_of("[1").to_selection() 5457 ); 5458} 5459 5460#[test] 5461fn extract_variable_inside_use_body() { 5462 assert_code_action!( 5463 EXTRACT_VARIABLE, 5464 r#"pub fn main() { 5465 use <- wibble(todo) 5466 list.map([1, 2, 3], int.add(1, _)) 5467 todo 5468}"#, 5469 find_position_of("[1").to_selection() 5470 ); 5471} 5472 5473#[test] 5474fn extract_variable_in_multiline_use() { 5475 assert_code_action!( 5476 EXTRACT_VARIABLE, 5477 r#"pub fn main() { 5478 use <- wibble( 5479 [1, 2, 3] 5480 ) 5481 todo 5482}"#, 5483 find_position_of("[1").to_selection() 5484 ); 5485} 5486 5487#[test] 5488fn extract_variable_after_nested_anonymous_function() { 5489 assert_code_action!( 5490 EXTRACT_VARIABLE, 5491 r#"pub fn main() { 5492 let f = fn() { 5493 let x = 1 + 2 5494 let ff = fn() { 5495 let y = x + 3 5496 let z = y + x 5497 z 5498 } 5499 let z = x * 4 5500 z 5501 } 5502 let y = 5 + 6 5503 f() 5504}"#, 5505 find_position_of("6").to_selection() 5506 ); 5507} 5508 5509#[test] 5510fn extract_variable_in_nested_anonymous_function() { 5511 assert_code_action!( 5512 EXTRACT_VARIABLE, 5513 r#"pub fn main() { 5514 let f = fn() { 5515 let x = 1 + 2 5516 let ff = fn() { 5517 let y = x + 3 5518 let z = y + x 5519 z 5520 } 5521 let z = x * 4 5522 z 5523 } 5524 let y = 5 + 6 5525 f() 5526}"#, 5527 find_position_of("4").to_selection() 5528 ); 5529} 5530 5531#[test] 5532fn extract_variable_in_double_nested_anonymous_function() { 5533 assert_code_action!( 5534 EXTRACT_VARIABLE, 5535 r#"pub fn main() { 5536 let f = fn() { 5537 let x = 1 + 2 5538 let ff = fn() { 5539 let y = x + 3 5540 let z = y + x 5541 z 5542 } 5543 let z = x * 4 5544 z 5545 } 5546 let y = 5 + 6 5547 f() 5548}"#, 5549 find_position_of("3").to_selection() 5550 ); 5551} 5552 5553#[test] 5554fn extract_variable_in_block() { 5555 assert_code_action!( 5556 EXTRACT_VARIABLE, 5557 r#"pub fn main() { 5558 { 5559 todo 5560 wibble([1, 2, 3]) 5561 todo 5562 } 5563}"#, 5564 find_position_of("2").select_until(find_position_of("3")) 5565 ); 5566} 5567 5568#[test] 5569fn extract_constant_from_call_argument_with_bit_array() { 5570 assert_code_action!( 5571 EXTRACT_CONSTANT, 5572 r#"import gleam/io 5573 5574pub fn main() { 5575 io.debug(<<3:size(8)>>) 5576}"#, 5577 find_position_of("<").select_until(find_position_of("<").nth_occurrence(2)) 5578 ); 5579} 5580 5581#[test] 5582fn extract_constant_from_call_argument_with_float() { 5583 assert_code_action!( 5584 EXTRACT_CONSTANT, 5585 r#"import gleam/float 5586 5587pub fn main() { 5588 float.ceiling(1.9998) 5589}"#, 5590 find_position_of("1").select_until(find_position_of("8")) 5591 ); 5592} 5593 5594#[test] 5595fn extract_constant_from_call_argument_with_int() { 5596 assert_code_action!( 5597 EXTRACT_CONSTANT, 5598 r#"import gleam/list 5599 5600pub fn main() { 5601 list.sample([4, 5, 6], 2) 5602}"#, 5603 find_position_of("2").to_selection() 5604 ); 5605} 5606 5607#[test] 5608fn extract_constant_from_call_argument_with_list() { 5609 assert_code_action!( 5610 EXTRACT_CONSTANT, 5611 r#"import gleam/io 5612 5613pub fn main() { 5614 io.debug(["constant", "another constant"]) 5615}"#, 5616 find_position_of("[").to_selection() 5617 ); 5618} 5619 5620#[test] 5621fn extract_constant_from_call_argument_with_nested_inside() { 5622 assert_code_action!( 5623 EXTRACT_CONSTANT, 5624 r#"import gleam/list 5625 5626pub fn main() { 5627 list.unzip([#(1, 2), #(3, 4)]) 5628}"#, 5629 find_position_of("#").select_until(find_position_of("(").nth_occurrence(3)) 5630 ); 5631} 5632 5633#[test] 5634fn extract_constant_from_call_argument_with_nested_outside() { 5635 assert_code_action!( 5636 EXTRACT_CONSTANT, 5637 r#"import gleam/list 5638 5639pub fn main() { 5640 list.unzip([#(1, 2), #(3, 4)]) 5641}"#, 5642 find_position_of("[").to_selection() 5643 ); 5644} 5645 5646#[test] 5647fn extract_constant_from_call_argument_with_string() { 5648 assert_code_action!( 5649 EXTRACT_CONSTANT, 5650 r#"import gleam/io 5651 5652pub fn main() { 5653 io.print("constant") 5654}"#, 5655 find_position_of("\"").select_until(find_position_of("\"")) 5656 ); 5657} 5658 5659#[test] 5660fn extract_constant_from_call_argument_with_tuple() { 5661 assert_code_action!( 5662 EXTRACT_CONSTANT, 5663 r#"import gleam/io 5664 5665pub fn main() { 5666 io.debug(#(1, 2, 3)) 5667}"#, 5668 find_position_of("#").select_until(find_position_of("(").nth_occurrence(3)) 5669 ); 5670} 5671 5672#[test] 5673fn extract_constant_from_declaration_of_float() { 5674 assert_code_action!( 5675 EXTRACT_CONSTANT, 5676 r#"pub fn main() { 5677 let c = 3.1415 5678}"#, 5679 find_position_of("3").select_until(find_position_of("5")) 5680 ); 5681} 5682 5683#[test] 5684fn extract_constant_from_whole_declaration_of_float() { 5685 assert_code_action!( 5686 EXTRACT_CONSTANT, 5687 r#"import gleam/io 5688 5689pub fn main() { 5690 let c = 3.1415 5691 io.debug(c) 5692}"#, 5693 find_position_of("l") 5694 .nth_occurrence(2) 5695 .select_until(find_position_of("c")) 5696 ); 5697} 5698 5699#[test] 5700fn extract_constant_from_declaration_of_bit_array() { 5701 assert_code_action!( 5702 EXTRACT_CONSTANT, 5703 r#"pub fn main() { 5704 let b = <<"arr":utf32>> 5705}"#, 5706 find_position_of("u") 5707 .nth_occurrence(2) 5708 .select_until(find_position_of(">").nth_occurrence(2)) 5709 ); 5710} 5711 5712#[test] 5713fn extract_constant_from_whole_declaration_of_bit_array() { 5714 assert_code_action!( 5715 EXTRACT_CONSTANT, 5716 r#"import gleam/io 5717 5718const n = 24 5719 5720pub fn main() { 5721 let bits = <<8080:size(n)>> 5722 bits 5723}"#, 5724 find_position_of("l") 5725 .nth_occurrence(2) 5726 .select_until(find_position_of("s").nth_occurrence(2)) 5727 ); 5728} 5729 5730#[test] 5731fn extract_constant_from_declaration_of_bin_op() { 5732 assert_code_action!( 5733 EXTRACT_CONSTANT, 5734 r#"pub fn main() { 5735 let twelve = "1" <> "2" 5736}"#, 5737 find_position_of("<").to_selection() 5738 ); 5739} 5740 5741#[test] 5742fn extract_constant_from_whole_declaration_of_bin_op() { 5743 assert_code_action!( 5744 EXTRACT_CONSTANT, 5745 r#"import gleam/io 5746 5747pub fn main() { 5748 let twelve = "1" <> "2" 5749 io.print(twelve) 5750}"#, 5751 find_position_of("l") 5752 .nth_occurrence(2) 5753 .select_until(find_position_of("e").nth_occurrence(4)) 5754 ); 5755} 5756 5757#[test] 5758fn extract_constant_from_declaration_of_int() { 5759 assert_code_action!( 5760 EXTRACT_CONSTANT, 5761 r#"pub fn main() { 5762 let c = 125 5763}"#, 5764 find_position_of("1").select_until(find_position_of("5")) 5765 ); 5766} 5767 5768#[test] 5769fn extract_constant_from_whole_declaration_of_int() { 5770 assert_code_action!( 5771 EXTRACT_CONSTANT, 5772 r#"import gleam/io 5773 5774pub fn main() { 5775 let c = 125 5776 io.debug(c) 5777}"#, 5778 find_position_of("l") 5779 .nth_occurrence(2) 5780 .select_until(find_position_of("c")) 5781 ); 5782} 5783 5784#[test] 5785fn extract_constant_from_declaration_of_list() { 5786 assert_code_action!( 5787 EXTRACT_CONSTANT, 5788 r#"pub fn main() { 5789 let c = [3.1415, 0.33333333] 5790}"#, 5791 find_position_of("[").to_selection() 5792 ); 5793} 5794 5795#[test] 5796fn extract_constant_from_whole_declaration_of_list() { 5797 assert_code_action!( 5798 EXTRACT_CONSTANT, 5799 r#"import gleam/io 5800 5801pub fn main() { 5802 let c = [3.1415, 0.33333333] 5803 io.debug(c) 5804}"#, 5805 find_position_of("l") 5806 .nth_occurrence(2) 5807 .select_until(find_position_of("c")) 5808 ); 5809} 5810 5811#[test] 5812fn extract_constant_from_declaration_of_nested_inside() { 5813 assert_code_action!( 5814 EXTRACT_CONSTANT, 5815 r#"pub fn main() { 5816 let c = #([1, 2, 3], [3, 2, 1]) 5817}"#, 5818 find_position_of("[").to_selection() 5819 ); 5820} 5821 5822#[test] 5823fn extract_constant_from_declaration_of_nested_outside() { 5824 assert_code_action!( 5825 EXTRACT_CONSTANT, 5826 r#"pub fn main() { 5827 let c = #([1, 2, 3], [3, 2, 1]) 5828}"#, 5829 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 5830 ); 5831} 5832 5833#[test] 5834fn extract_constant_from_whole_declaration_of_nested() { 5835 assert_code_action!( 5836 EXTRACT_CONSTANT, 5837 r#"import gleam/io 5838 5839pub fn main() { 5840 let c = #([1, 2, 3], [3, 2, 1]) 5841 io.debug(c) 5842}"#, 5843 find_position_of("l") 5844 .nth_occurrence(2) 5845 .select_until(find_position_of("c")) 5846 ); 5847} 5848 5849#[test] 5850fn extract_constant_from_declaration_of_string() { 5851 assert_code_action!( 5852 EXTRACT_CONSTANT, 5853 r#"pub fn main() { 5854 let c = "constant" 5855}"#, 5856 find_position_of("\"").select_until(find_position_of("\"")) 5857 ); 5858} 5859 5860#[test] 5861fn extract_constant_from_whole_declaration_of_string() { 5862 assert_code_action!( 5863 EXTRACT_CONSTANT, 5864 r#"import gleam/io 5865 5866pub fn main() { 5867 let c = "constant" 5868 io.debug(c) 5869}"#, 5870 find_position_of("l") 5871 .nth_occurrence(2) 5872 .select_until(find_position_of("c")) 5873 ); 5874} 5875 5876#[test] 5877fn extract_constant_from_declaration_of_tuple() { 5878 assert_code_action!( 5879 EXTRACT_CONSTANT, 5880 r#"pub fn main() { 5881 let #(one, two, three) = #("one", "two", "three") 5882}"#, 5883 find_position_of("#") 5884 .nth_occurrence(2) 5885 .select_until(find_position_of("(").nth_occurrence(3)) 5886 ); 5887} 5888 5889#[test] 5890fn extract_constant_from_whole_declaration_of_tuple() { 5891 assert_code_action!( 5892 EXTRACT_CONSTANT, 5893 r#"import gleam/io 5894 5895pub fn main() { 5896 let c = #("one", "two", "three") 5897 io.debug(c) 5898}"#, 5899 find_position_of("l") 5900 .nth_occurrence(2) 5901 .select_until(find_position_of("c")) 5902 ); 5903} 5904 5905#[test] 5906fn extract_constant_from_literal_within_list() { 5907 assert_code_action!( 5908 EXTRACT_CONSTANT, 5909 r#"pub fn main() { 5910 let c = ["constant", todo] 5911}"#, 5912 find_position_of("\"").select_until(find_position_of("\"")) 5913 ); 5914} 5915 5916#[test] 5917fn extract_constant_from_list_containing_constant() { 5918 assert_code_action!( 5919 EXTRACT_CONSTANT, 5920 r#"const something = "something" 5921 5922pub fn main() { 5923 let c = ["constant", something] 5924}"#, 5925 find_position_of("[").to_selection() 5926 ); 5927} 5928 5929#[test] 5930fn extract_constant_from_literal_within_tuple() { 5931 assert_code_action!( 5932 EXTRACT_CONSTANT, 5933 r#"pub fn main() { 5934 let c = #(0.333334, todo) 5935}"#, 5936 find_position_of("0").select_until(find_position_of("4")) 5937 ); 5938} 5939 5940#[test] 5941fn extract_constant_from_tuple_containing_constant() { 5942 assert_code_action!( 5943 EXTRACT_CONSTANT, 5944 r#"const something = "something" 5945 5946pub fn main() { 5947 let c = #(0.333334, something) 5948}"#, 5949 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 5950 ); 5951} 5952 5953#[test] 5954fn extract_constant_from_nested_inside_in_expr() { 5955 assert_code_action!( 5956 EXTRACT_CONSTANT, 5957 r#"pub fn main() { 5958 [#("a", 0), #("b", 1), #("a", 2)] 5959 |> key_filter("a") 5960}"#, 5961 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 5962 ); 5963} 5964 5965#[test] 5966fn extract_constant_from_nested_outside_in_expr() { 5967 assert_code_action!( 5968 EXTRACT_CONSTANT, 5969 r#"pub fn main() { 5970 [#("a", 0), #("b", 1), #("a", 2)] 5971 |> key_filter("a") 5972}"#, 5973 find_position_of("[").to_selection() 5974 ); 5975} 5976 5977#[test] 5978fn extract_constant_from_return_of_float() { 5979 assert_code_action!( 5980 EXTRACT_CONSTANT, 5981 r#"pub fn main() { 5982 0.25 5983}"#, 5984 find_position_of("0").select_until(find_position_of("5")) 5985 ); 5986} 5987 5988#[test] 5989fn extract_constant_from_return_of_int() { 5990 assert_code_action!( 5991 EXTRACT_CONSTANT, 5992 r#"pub fn main() { 5993 100 5994}"#, 5995 find_position_of("1").select_until(find_position_of("0").nth_occurrence(2)) 5996 ); 5997} 5998 5999#[test] 6000fn extract_constant_from_return_of_list() { 6001 assert_code_action!( 6002 EXTRACT_CONSTANT, 6003 r#"pub fn main() { 6004 [1, 2, 3, 4] 6005}"#, 6006 find_position_of("[").to_selection() 6007 ); 6008} 6009 6010#[test] 6011fn extract_constant_from_return_of_nested_outside() { 6012 assert_code_action!( 6013 EXTRACT_CONSTANT, 6014 r#"pub fn main() { 6015 [#(0.25, 0.75), #(0.5, 1.5)] 6016}"#, 6017 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 6018 ); 6019} 6020 6021#[test] 6022fn extract_constant_from_return_of_string() { 6023 assert_code_action!( 6024 EXTRACT_CONSTANT, 6025 r#"pub fn main() { 6026 "constant" 6027}"#, 6028 find_position_of("\"").select_until(find_position_of("\"")) 6029 ); 6030} 6031 6032#[test] 6033fn extract_constant_from_return_of_tuple() { 6034 assert_code_action!( 6035 EXTRACT_CONSTANT, 6036 r#"pub fn main() { 6037 #(0.25, 0.75) 6038}"#, 6039 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 6040 ); 6041} 6042 6043#[test] 6044fn extract_constant_from_taken_name_by_function() { 6045 assert_code_action!( 6046 EXTRACT_CONSTANT, 6047 r#"fn floats() { 6048 [1.0, 2.0] 6049} 6050 6051pub fn main() { 6052 [0.25, 0.75] 6053}"#, 6054 find_position_of("[").nth_occurrence(2).to_selection() 6055 ); 6056} 6057 6058#[test] 6059fn extract_constant_from_taken_name_by_constant() { 6060 assert_code_action!( 6061 EXTRACT_CONSTANT, 6062 r#"const ints = [1, 2] 6063 6064pub fn main() { 6065 [5, 50] 6066}"#, 6067 find_position_of("[").nth_occurrence(2).to_selection() 6068 ); 6069} 6070 6071#[test] 6072fn extract_constant_in_correct_position_1() { 6073 assert_code_action!( 6074 EXTRACT_CONSTANT, 6075 r#" 6076fn first() { 6077 1 6078} 6079 6080fn second() { 6081 2 6082} 6083 6084fn third() { 6085 3 6086} 6087"#, 6088 find_position_of("1").to_selection() 6089 ); 6090} 6091 6092#[test] 6093fn extract_constant_in_correct_position_2() { 6094 assert_code_action!( 6095 EXTRACT_CONSTANT, 6096 r#" 6097fn first() { 6098 1 6099} 6100 6101fn second() { 6102 2 6103} 6104 6105fn third() { 6106 3 6107} 6108"#, 6109 find_position_of("2").to_selection() 6110 ); 6111} 6112 6113#[test] 6114fn extract_constant_in_correct_position_3() { 6115 assert_code_action!( 6116 EXTRACT_CONSTANT, 6117 r#" 6118fn first() { 6119 1 6120} 6121 6122fn second() { 6123 2 6124} 6125 6126fn third() { 6127 3 6128} 6129"#, 6130 find_position_of("3").to_selection() 6131 ); 6132} 6133 6134#[test] 6135fn extract_constant_declaration_with_proper_indentation() { 6136 assert_code_action!( 6137 EXTRACT_CONSTANT, 6138 r#" 6139pub fn main() { 6140 let fahrenheit = { 6141 let degrees = 64 6142 degrees 6143 } 6144 fahrenheit 6145} 6146"#, 6147 find_position_of("l") 6148 .nth_occurrence(2) 6149 .select_until(find_position_of("s")) 6150 ); 6151} 6152 6153#[test] 6154fn extract_constant_from_nil() { 6155 assert_code_action!( 6156 EXTRACT_CONSTANT, 6157 r#"pub fn main() { 6158 let x = Nil 6159 x 6160} 6161"#, 6162 find_position_of("l").select_until(find_position_of("x")) 6163 ); 6164} 6165 6166#[test] 6167fn extract_constant_from_non_record_variant_1() { 6168 assert_code_action!( 6169 EXTRACT_CONSTANT, 6170 r#"pub type Auth { 6171 Verified 6172 Unverified 6173} 6174 6175pub fn main() { 6176 let a = Unverified 6177 let a = verify(something, a) 6178 6179 a 6180} 6181"#, 6182 find_position_of("U") 6183 .nth_occurrence(2) 6184 .select_until(find_position_of("d").nth_occurrence(3)) 6185 ); 6186} 6187 6188#[test] 6189fn extract_constant_from_non_record_variant_2() { 6190 assert_code_action!( 6191 EXTRACT_CONSTANT, 6192 r#"pub type Auth { 6193 Verified 6194 Unverified 6195} 6196 6197pub fn main() { 6198 let a = verify(something, Unverified) 6199 6200 a 6201} 6202"#, 6203 find_position_of("U") 6204 .nth_occurrence(2) 6205 .select_until(find_position_of("d").nth_occurrence(3)) 6206 ); 6207} 6208 6209#[test] 6210fn extract_constant_from_record_variant_1() { 6211 assert_code_action!( 6212 EXTRACT_CONSTANT, 6213 r#"pub type Auth { 6214 Verified(String) 6215 Unverified 6216} 6217 6218pub fn main() { 6219 let u = Verified("User") 6220 let v = verify(something, u) 6221 6222 v 6223}"#, 6224 find_position_of("l").select_until(find_position_of("u").nth_occurrence(4)) 6225 ); 6226} 6227 6228#[test] 6229fn extract_constant_from_record_variant_2() { 6230 assert_code_action!( 6231 EXTRACT_CONSTANT, 6232 r#"pub type Auth { 6233 Verified(Int) 6234 Unverified 6235} 6236 6237const auth = True 6238 6239const id = 1234 6240 6241pub fn main() { 6242 let v = verify(auth, Verified(id)) 6243 6244 v 6245}"#, 6246 find_position_of("V") 6247 .nth_occurrence(2) 6248 .select_until(find_position_of("(").nth_occurrence(4)) 6249 ); 6250} 6251 6252#[test] 6253fn extract_constant_from_inside_block() { 6254 assert_code_action!( 6255 EXTRACT_CONSTANT, 6256 r#"pub fn main() { 6257 let fahrenheit = { 6258 let degrees = 64 + 32 6259 degrees 6260 } 6261}"#, 6262 find_position_of("32").to_selection() 6263 ); 6264} 6265 6266#[test] 6267fn extract_constant_from_inside_case() { 6268 assert_code_action!( 6269 EXTRACT_CONSTANT, 6270 r#"pub fn main(result) { 6271 case result { 6272 Ok(value) -> value + 1 6273 Error(_) -> panic 6274 } 6275}"#, 6276 find_position_of("1").to_selection() 6277 ); 6278} 6279 6280#[test] 6281fn extract_constant_from_inside_use_1() { 6282 assert_code_action!( 6283 EXTRACT_CONSTANT, 6284 r#"pub fn main() { 6285 use x <- result.try(todo) 6286 Ok(123) 6287}"#, 6288 find_position_of("Ok").to_selection() 6289 ); 6290} 6291 6292#[test] 6293fn extract_constant_from_inside_use_2() { 6294 assert_code_action!( 6295 EXTRACT_CONSTANT, 6296 r#"const number = 123 6297 6298pub fn main() { 6299 use x <- result.try(todo) 6300 Ok(number) 6301}"#, 6302 find_position_of("Ok").to_selection() 6303 ); 6304} 6305 6306#[test] 6307fn do_not_extract_constant_from_pattern() { 6308 assert_no_code_actions!( 6309 EXTRACT_CONSTANT, 6310 r#"pub fn main() { 6311 let #(one, two) = #(1, 2) 6312 one 6313}"#, 6314 find_position_of("l").select_until(find_position_of("(").nth_occurrence(2)) 6315 ); 6316} 6317 6318#[test] 6319fn do_not_extract_constant_from_fn_call_1() { 6320 assert_no_code_actions!( 6321 EXTRACT_CONSTANT, 6322 r#"import gleam/io 6323 6324pub fn main() { 6325 io.print("constant") 6326}"#, 6327 find_position_of("p") 6328 .nth_occurrence(3) 6329 .select_until(find_position_of("t").nth_occurrence(2)) 6330 ); 6331} 6332 6333#[test] 6334fn do_not_extract_constant_from_fn_call_2() { 6335 assert_no_code_actions!( 6336 EXTRACT_CONSTANT, 6337 r#"import gleam/list 6338 6339pub fn main() { 6340 let first = list.first([1, 2, 3]) 6341 first 6342}"#, 6343 find_position_of("l") 6344 .nth_occurrence(3) 6345 .select_until(find_position_of("t").nth_occurrence(4)) 6346 ); 6347} 6348 6349#[test] 6350fn do_not_extract_constant_from_bin_op() { 6351 assert_no_code_actions!( 6352 EXTRACT_CONSTANT, 6353 r#"pub fn main() { 6354 let res = 64 < 32 6355 res 6356}"#, 6357 find_position_of("<").to_selection() 6358 ); 6359} 6360 6361#[test] 6362fn do_not_extract_constant_from_bit_array_1() { 6363 assert_no_code_actions!( 6364 EXTRACT_CONSTANT, 6365 r#"pub fn main() { 6366 let c = "constant" 6367 let res = <<c:utf16>> 6368 res 6369}"#, 6370 find_position_of("<").to_selection() 6371 ); 6372} 6373 6374#[test] 6375fn do_not_extract_constant_from_bit_array_2() { 6376 assert_no_code_actions!( 6377 EXTRACT_CONSTANT, 6378 r#"import gleam/io 6379 6380pub fn main() { 6381 let n = 1234 6382 io.debug(<<8080:size(n)>>) 6383}"#, 6384 find_position_of("<").to_selection() 6385 ); 6386} 6387 6388#[test] 6389fn do_not_extract_constant_from_bit_array_3() { 6390 assert_no_code_actions!( 6391 EXTRACT_CONSTANT, 6392 r#"import gleam/io 6393 6394pub fn main() { 6395 let l = 1234 6396 let r = 1234 6397 let result = <<l:size(r)>> 6398 result 6399}"#, 6400 find_position_of("l") 6401 .nth_occurrence(5) 6402 .select_until(find_position_of("t").nth_occurrence(5)) 6403 ); 6404} 6405 6406#[test] 6407fn do_not_extract_constant_from_list_1() { 6408 assert_no_code_actions!( 6409 EXTRACT_CONSTANT, 6410 r#"pub fn main() { 6411 let c = ["constant", todo] 6412 c 6413}"#, 6414 find_position_of("[").to_selection() 6415 ); 6416} 6417 6418#[test] 6419fn do_not_extract_constant_from_list_2() { 6420 assert_no_code_actions!( 6421 EXTRACT_CONSTANT, 6422 r#"pub fn main() { 6423 [10, todo] 6424}"#, 6425 find_position_of("[").to_selection() 6426 ); 6427} 6428 6429#[test] 6430fn do_not_extract_constant_from_list_3() { 6431 assert_no_code_actions!( 6432 EXTRACT_CONSTANT, 6433 r#"pub fn main() { 6434 let c = [0.25, todo] 6435 c 6436}"#, 6437 find_position_of("l").select_until(find_position_of("c")) 6438 ); 6439} 6440 6441#[test] 6442fn do_not_extract_constant_from_tuple_1() { 6443 assert_no_code_actions!( 6444 EXTRACT_CONSTANT, 6445 r#"pub fn main() { 6446 let c = #("constant", todo) 6447 c 6448}"#, 6449 find_position_of("#").select_until(find_position_of("(")) 6450 ); 6451} 6452 6453#[test] 6454fn do_not_extract_constant_from_tuple_2() { 6455 assert_no_code_actions!( 6456 EXTRACT_CONSTANT, 6457 r#"pub fn main() { 6458 #(10, todo) 6459}"#, 6460 find_position_of("#").select_until(find_position_of("(")) 6461 ); 6462} 6463 6464#[test] 6465fn do_not_extract_constant_from_tuple_3() { 6466 assert_no_code_actions!( 6467 EXTRACT_CONSTANT, 6468 r#"pub fn main() { 6469 let c = #(0.25, todo) 6470 c 6471}"#, 6472 find_position_of("l").select_until(find_position_of("c")) 6473 ); 6474} 6475 6476#[test] 6477fn do_not_extract_constant_from_nested_1() { 6478 assert_no_code_actions!( 6479 EXTRACT_CONSTANT, 6480 r#"pub fn main() { 6481 let c = list.unzip([#(1, 2), #(3, todo)]) 6482 c 6483}"#, 6484 find_position_of("[").to_selection() 6485 ); 6486} 6487 6488#[test] 6489fn do_not_extract_constant_from_nested_2() { 6490 assert_no_code_actions!( 6491 EXTRACT_CONSTANT, 6492 r#"pub fn main() { 6493 [[1.25, 1], [0.25, todo]] 6494}"#, 6495 find_position_of("[").to_selection() 6496 ); 6497} 6498 6499#[test] 6500fn do_not_extract_constant_from_nested_3() { 6501 assert_no_code_actions!( 6502 EXTRACT_CONSTANT, 6503 r#"import gleam/list 6504 6505pub fn main() { 6506 let c = [#(1, 2), #(3, todo)] 6507 c 6508}"#, 6509 find_position_of("l") 6510 .nth_occurrence(3) 6511 .select_until(find_position_of("c")) 6512 ); 6513} 6514 6515#[test] 6516fn do_not_extract_constant_from_record_1() { 6517 assert_no_code_actions!( 6518 EXTRACT_CONSTANT, 6519 r#"type Pair { 6520 Pair(Int, Int) 6521} 6522 6523pub fn main() { 6524 let c = list.unzip([Pair(1, 2), Pair(3, todo)]) 6525 c 6526}"#, 6527 find_position_of("P").nth_occurrence(4).to_selection() 6528 ); 6529} 6530 6531#[test] 6532fn do_not_extract_constant_from_record_2() { 6533 assert_no_code_actions!( 6534 EXTRACT_CONSTANT, 6535 r#"type Couple { 6536 Couple(l: Float, r: Float) 6537} 6538 6539pub fn main() { 6540 #(Couple(1.25, 1.0), Couple(0.25, todo)) 6541}"#, 6542 find_position_of("C").nth_occurrence(4).to_selection() 6543 ); 6544} 6545 6546#[test] 6547fn do_not_extract_constant_from_record_update() { 6548 assert_no_code_actions!( 6549 EXTRACT_CONSTANT, 6550 r#"type Couple { 6551 Couple(l: Int, r: Int) 6552} 6553 6554pub fn main() { 6555 let c = Couple(1, 2) 6556 let cc = Couple(..c, 2) 6557 cc 6558}"#, 6559 find_position_of("C") 6560 .nth_occurrence(4) 6561 .select_until(find_position_of("e").nth_occurrence(7)) 6562 ); 6563} 6564 6565#[test] 6566fn do_not_extract_constant_from_record_capture() { 6567 assert_no_code_actions!( 6568 EXTRACT_CONSTANT, 6569 r#"type Couple { 6570 Couple(l: Int, r: Int) 6571} 6572 6573pub fn main() { 6574 let c = Couple(1, _) 6575 c 6576}"#, 6577 find_position_of("C") 6578 .nth_occurrence(3) 6579 .select_until(find_position_of("e").nth_occurrence(5)) 6580 ); 6581} 6582 6583#[test] 6584fn do_not_extract_top_level_expression_statement() { 6585 assert_no_code_actions!( 6586 EXTRACT_VARIABLE, 6587 r#"pub fn main() { 6588 1 6589} 6590"#, 6591 find_position_of("1").to_selection() 6592 ); 6593} 6594 6595#[test] 6596fn do_not_extract_top_level_expression_in_let_statement() { 6597 assert_no_code_actions!( 6598 EXTRACT_VARIABLE, 6599 r#"pub fn main() { 6600 let a = 1 6601} 6602"#, 6603 find_position_of("1").to_selection() 6604 ); 6605} 6606 6607#[test] 6608fn do_not_extract_top_level_module_call() { 6609 let src = r#" 6610import list 6611pub fn main() { 6612 list.map([1, 2, 3], todo) 6613}"#; 6614 6615 assert_no_code_actions!( 6616 EXTRACT_VARIABLE, 6617 TestProject::for_source(src).add_module("list", "pub fn map(l, f) { todo }"), 6618 find_position_of("map").to_selection() 6619 ); 6620} 6621 6622#[test] 6623fn expand_function_capture() { 6624 assert_code_action!( 6625 EXPAND_FUNCTION_CAPTURE, 6626 r#"pub fn main() { 6627 wibble(_, 1) 6628}"#, 6629 find_position_of("_").to_selection() 6630 ); 6631} 6632 6633#[test] 6634fn expand_function_capture_2() { 6635 assert_code_action!( 6636 EXPAND_FUNCTION_CAPTURE, 6637 r#"pub fn main() { 6638 wibble(1, _) 6639}"#, 6640 find_position_of("wibble").to_selection() 6641 ); 6642} 6643 6644#[test] 6645fn expand_function_capture_does_not_shadow_variables() { 6646 assert_code_action!( 6647 EXPAND_FUNCTION_CAPTURE, 6648 r#"pub fn main() { 6649 let value = 1 6650 let value_2 = 2 6651 wibble(value, _, value_2) 6652}"#, 6653 find_position_of("wibble").to_selection() 6654 ); 6655} 6656 6657#[test] 6658fn expand_function_capture_picks_a_name_based_on_the_type_of_the_hole() { 6659 assert_code_action!( 6660 EXPAND_FUNCTION_CAPTURE, 6661 r#"pub fn main() { 6662 [1, 2, 3] 6663 |> map(add(_, 1)) 6664} 6665 6666pub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo } 6667pub fn add(n, m) { n + m } 6668"#, 6669 find_position_of("add").to_selection() 6670 ); 6671} 6672 6673#[test] 6674fn generate_dynamic_decoder() { 6675 assert_code_action!( 6676 GENERATE_DYNAMIC_DECODER, 6677 " 6678pub type Person { 6679 Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray) 6680} 6681", 6682 find_position_of("type").to_selection() 6683 ); 6684} 6685 6686#[test] 6687fn generate_dynamic_decoder_complex_types() { 6688 let src = " 6689import gleam/option 6690import gleam/dynamic 6691import gleam/dict 6692 6693pub type Something 6694 6695pub type Wibble(value) { 6696 Wibble( 6697 maybe: option.Option(Something), 6698 map: dict.Dict(String, List(value)), 6699 unknown: List(dynamic.Dynamic), 6700 ) 6701} 6702"; 6703 6704 assert_code_action!( 6705 GENERATE_DYNAMIC_DECODER, 6706 TestProject::for_source(src) 6707 .add_module("gleam/option", "pub type Option(a)") 6708 .add_module("gleam/dynamic", "pub type Dynamic") 6709 .add_module("gleam/dict", "pub type Dict(k, v)"), 6710 find_position_of("type W").to_selection() 6711 ); 6712} 6713 6714#[test] 6715fn generate_dynamic_decoder_already_imported_module() { 6716 let src = " 6717import gleam/dynamic/decode as dyn_dec 6718 6719pub type Wibble { 6720 Wibble(a: Int, b: Float, c: String) 6721} 6722"; 6723 6724 assert_code_action!( 6725 GENERATE_DYNAMIC_DECODER, 6726 TestProject::for_source(src).add_module("gleam/dynamic/decode", "pub type Decoder(a)"), 6727 find_position_of("type W").to_selection() 6728 ); 6729} 6730 6731#[test] 6732fn generate_dynamic_decoder_tuple() { 6733 assert_code_action!( 6734 GENERATE_DYNAMIC_DECODER, 6735 " 6736pub type Wibble { 6737 Wibble(tuple: #(Int, Float, #(String, Bool))) 6738} 6739", 6740 find_position_of("type W").to_selection() 6741 ); 6742} 6743 6744#[test] 6745fn generate_dynamic_decoder_recursive_type() { 6746 let src = " 6747import gleam/option 6748 6749pub type LinkedList { 6750 LinkedList(value: Int, next: option.Option(LinkedList)) 6751} 6752"; 6753 assert_code_action!( 6754 GENERATE_DYNAMIC_DECODER, 6755 TestProject::for_source(src).add_module("gleam/option", "pub type Option(a)"), 6756 find_position_of("type").to_selection() 6757 ); 6758} 6759 6760#[test] 6761fn generate_dynamic_decoder_for_multi_variant_type() { 6762 assert_code_action!( 6763 GENERATE_DYNAMIC_DECODER, 6764 " 6765pub type Wibble { 6766 Wibble(wibble: Int, next: Wibble) 6767 Wobble(wobble: Float, text: String, values: List(Bool)) 6768} 6769", 6770 find_position_of("type").to_selection() 6771 ); 6772} 6773 6774#[test] 6775fn generate_dynamic_decoder_for_multi_variant_type_multi_word_name() { 6776 assert_code_action!( 6777 GENERATE_DYNAMIC_DECODER, 6778 " 6779pub type Wibble { 6780 OneTwo(wibble: Int, next: Wibble) 6781 ThreeFour(wobble: Float, text: String, values: List(Bool)) 6782 FiveSixSeven(one_two: Int) 6783} 6784", 6785 find_position_of("type").to_selection() 6786 ); 6787} 6788 6789#[test] 6790fn generate_dynamic_decoder_for_variant_with_no_fields() { 6791 assert_code_action!( 6792 GENERATE_DYNAMIC_DECODER, 6793 " 6794pub type Wibble { 6795 Wibble 6796} 6797", 6798 find_position_of("type").to_selection() 6799 ); 6800} 6801 6802#[test] 6803fn generate_dynamic_decoder_for_variants_with_no_fields() { 6804 assert_code_action!( 6805 GENERATE_DYNAMIC_DECODER, 6806 " 6807pub type Wibble { 6808 Wibble 6809 Wobble 6810 Woo 6811} 6812", 6813 find_position_of("type").to_selection() 6814 ); 6815} 6816 6817#[test] 6818fn generate_dynamic_decoder_for_variants_with_mixed_fields() { 6819 assert_code_action!( 6820 GENERATE_DYNAMIC_DECODER, 6821 " 6822pub type Wibble { 6823 Wibble 6824 Wobble(field: String, field2: Int) 6825} 6826", 6827 find_position_of("type").to_selection() 6828 ); 6829} 6830 6831#[test] 6832fn no_code_action_to_generate_dynamic_decoder_for_type_without_labels() { 6833 assert_no_code_actions!( 6834 GENERATE_DYNAMIC_DECODER, 6835 " 6836pub type Wibble { 6837 Wibble(Int, Int, String) 6838} 6839", 6840 find_position_of("type").to_selection() 6841 ); 6842} 6843 6844#[test] 6845fn pattern_match_on_argument_empty_tuple() { 6846 assert_no_code_actions!( 6847 PATTERN_MATCH_ON_ARGUMENT, 6848 " 6849pub fn main(tuple: #()) { 6850 todo 6851} 6852", 6853 find_position_of("tuple").to_selection() 6854 ); 6855} 6856 6857#[test] 6858fn pattern_match_on_argument_single_item_tuple() { 6859 assert_code_action!( 6860 PATTERN_MATCH_ON_ARGUMENT, 6861 " 6862pub fn main(tuple: #(Int)) { 6863 todo 6864} 6865", 6866 find_position_of(":").to_selection() 6867 ); 6868} 6869 6870#[test] 6871fn pattern_match_on_argument_multi_item_tuple() { 6872 assert_code_action!( 6873 PATTERN_MATCH_ON_ARGUMENT, 6874 " 6875pub fn main(tuple: #(Int, String, Bool)) { 6876 todo 6877} 6878", 6879 find_position_of("tuple").select_until(find_position_of("Int")) 6880 ); 6881} 6882 6883#[test] 6884fn pattern_match_on_argument_uses_case_with_multiple_constructors() { 6885 assert_code_action!( 6886 PATTERN_MATCH_ON_ARGUMENT, 6887 " 6888pub type CannotBeDestructured { 6889 One(one: String) 6890 Two(two: Int) 6891} 6892 6893pub fn main(arg: CannotBeDestructured) { 6894 todo 6895} 6896", 6897 find_position_of("arg").to_selection() 6898 ); 6899} 6900 6901#[test] 6902fn pattern_match_on_argument_with_multiple_constructors_is_nicely_formatted_in_function_with_empty_body() 6903 { 6904 assert_code_action!( 6905 PATTERN_MATCH_ON_ARGUMENT, 6906 " 6907pub type CannotBeDestructured { 6908 One(one: String) 6909 Two(two: Int) 6910} 6911 6912pub fn main(arg: CannotBeDestructured) {} 6913", 6914 find_position_of("arg").to_selection() 6915 ); 6916} 6917 6918#[test] 6919fn pattern_match_on_argument_uses_label_shorthand_syntax_for_labelled_arguments() { 6920 assert_code_action!( 6921 PATTERN_MATCH_ON_ARGUMENT, 6922 " 6923pub type Wibble { 6924 Wobble(Int, String, i_want_to_see_this: String, and_this: Bool) 6925} 6926 6927pub fn main(arg: Wibble) { 6928 todo 6929} 6930", 6931 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2)) 6932 ); 6933} 6934 6935#[test] 6936fn pattern_match_on_argument_with_private_type_from_same_module() { 6937 assert_code_action!( 6938 PATTERN_MATCH_ON_ARGUMENT, 6939 " 6940type Wibble { 6941 Wobble(Int, String) 6942} 6943 6944pub fn main(arg: Wibble) { 6945 todo 6946} 6947", 6948 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2)) 6949 ); 6950} 6951 6952#[test] 6953fn pattern_match_on_value_with_private_type_from_same_module() { 6954 assert_code_action!( 6955 PATTERN_MATCH_ON_VARIABLE, 6956 " 6957type Wibble { 6958 Wobble(Int, String) 6959} 6960 6961pub fn main() { 6962 let wibble = Wobble(1, \"Hello\") 6963 todo 6964} 6965", 6966 find_position_of("wibble").to_selection() 6967 ); 6968} 6969 6970#[test] 6971fn pattern_match_on_clause_variable() { 6972 assert_code_action!( 6973 PATTERN_MATCH_ON_VARIABLE, 6974 " 6975pub fn main() { 6976 case maybe_wibble() { 6977 Ok(something) -> 1 6978 Error(_) -> 2 6979 } 6980} 6981 6982type Wibble { 6983 Wobble 6984 Woo 6985} 6986 6987fn maybe_wibble() { Ok(Wobble) } 6988 6989", 6990 find_position_of("something").to_selection() 6991 ); 6992} 6993 6994#[test] 6995fn pattern_match_on_clause_variable_nested_pattern() { 6996 assert_code_action!( 6997 PATTERN_MATCH_ON_VARIABLE, 6998 " 6999pub fn main() { 7000 case maybe_wibble() { 7001 Ok(Wobble(something)) -> 1 7002 Error(_) -> 2 7003 } 7004} 7005 7006type Wibble { 7007 Wobble(Wibble) 7008 Woo 7009} 7010 7011fn maybe_wibble() { Ok(Woo) } 7012 7013", 7014 find_position_of("something").to_selection() 7015 ); 7016} 7017 7018#[test] 7019fn pattern_match_on_clause_variable_with_block_body() { 7020 assert_code_action!( 7021 PATTERN_MATCH_ON_VARIABLE, 7022 " 7023pub fn main() { 7024 case maybe_wibble() { 7025 Ok(something) -> { 7026 1 7027 2 7028 } 7029 Error(_) -> 2 7030 } 7031} 7032 7033type Wibble { 7034 Wobble 7035 Woo 7036} 7037 7038fn maybe_wibble() { Ok(Wobble) } 7039 7040", 7041 find_position_of("something").to_selection() 7042 ); 7043} 7044 7045#[test] 7046fn pattern_match_on_argument_will_use_qualified_name() { 7047 let src = " 7048import wibble 7049 7050pub fn main(arg: wibble.Wibble) { 7051 todo 7052} 7053"; 7054 7055 let dep = " 7056pub type Wibble { 7057 ThisShouldBeQualified(label: Int) 7058} 7059"; 7060 7061 assert_code_action!( 7062 PATTERN_MATCH_ON_ARGUMENT, 7063 TestProject::for_source(src).add_module("wibble", dep), 7064 find_position_of("wibble").nth_occurrence(2).to_selection() 7065 ); 7066} 7067 7068#[test] 7069fn pattern_match_on_argument_will_use_unqualified_name() { 7070 let src = " 7071import wibble.{ThisShouldBeUnqualified} 7072 7073pub fn main(arg: wibble.Wibble) { 7074 todo 7075} 7076"; 7077 7078 let dep = " 7079pub type Wibble { 7080 ThisShouldBeUnqualified(label: Int) 7081} 7082"; 7083 7084 assert_code_action!( 7085 PATTERN_MATCH_ON_ARGUMENT, 7086 TestProject::for_source(src).add_module("wibble", dep), 7087 find_position_of("Wibble").to_selection() 7088 ); 7089} 7090 7091#[test] 7092fn pattern_match_on_argument_will_use_aliased_constructor_name() { 7093 let src = " 7094import wibble.{Wobble as IWantToSeeThisName} 7095 7096pub fn main(arg: wibble.Wibble) { 7097 todo 7098} 7099"; 7100 7101 let dep = " 7102pub type Wibble { 7103 Wobble(label: Int) 7104} 7105"; 7106 7107 assert_code_action!( 7108 PATTERN_MATCH_ON_ARGUMENT, 7109 TestProject::for_source(src).add_module("wibble", dep), 7110 find_position_of("arg").to_selection() 7111 ); 7112} 7113 7114#[test] 7115fn pattern_match_on_argument_will_use_aliased_module_name() { 7116 let src = " 7117import wibble as i_want_to_see_this_name 7118 7119pub fn main(arg: i_want_to_see_this_name.Wibble) { 7120 todo 7121} 7122"; 7123 7124 let dep = " 7125pub type Wibble { 7126 Wobble(label: Int) 7127} 7128"; 7129 7130 assert_code_action!( 7131 PATTERN_MATCH_ON_ARGUMENT, 7132 TestProject::for_source(src).add_dep_module("wibble", dep), 7133 find_position_of("arg").to_selection() 7134 ); 7135} 7136 7137#[test] 7138fn pattern_match_on_argument_not_available_for_internal_type() { 7139 let src = " 7140import wibble 7141 7142pub fn main(arg: wobble.Wibble) { 7143 todo 7144} 7145"; 7146 7147 let dep = " 7148@internal 7149pub type Wibble { 7150 Wobble(label: Int) 7151} 7152"; 7153 7154 assert_no_code_actions!( 7155 PATTERN_MATCH_ON_ARGUMENT, 7156 TestProject::for_source(src).add_module("wibble", dep), 7157 find_position_of("arg").to_selection() 7158 ); 7159} 7160 7161#[test] 7162fn pattern_match_on_argument_available_for_internal_type_defined_in_current_module() { 7163 assert_code_action!( 7164 PATTERN_MATCH_ON_ARGUMENT, 7165 " 7166@internal 7167pub type Wibble { 7168 Wobble(label: Int) 7169} 7170 7171pub fn main(arg: Wibble) { 7172 todo 7173} 7174", 7175 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2)) 7176 ); 7177} 7178 7179#[test] 7180fn pattern_match_on_argument_preserves_indentation_of_statement_following_inserted_let() { 7181 assert_code_action!( 7182 PATTERN_MATCH_ON_ARGUMENT, 7183 "pub fn main(arg: #(Int, String)) { 7184 todo 7185//^^^^ This should still have two spaces of indentation! 7186}", 7187 find_position_of("arg").to_selection() 7188 ); 7189} 7190 7191#[test] 7192fn pattern_match_on_argument_nicely_formats_code_when_used_on_function_with_empty_body() { 7193 assert_code_action!( 7194 PATTERN_MATCH_ON_ARGUMENT, 7195 "pub fn main(arg: #(Int, String)) {}", 7196 find_position_of("arg").to_selection() 7197 ); 7198} 7199 7200#[test] 7201fn pattern_match_on_argument_single_unlabelled_field_is_not_numbered() { 7202 assert_code_action!( 7203 PATTERN_MATCH_ON_ARGUMENT, 7204 " 7205pub type Wibble { 7206 Wibble(Int) 7207} 7208 7209pub fn main(arg: Wibble) {} 7210", 7211 find_position_of(":").to_selection() 7212 ); 7213} 7214 7215#[test] 7216fn pattern_match_on_let_assignment() { 7217 assert_code_action!( 7218 PATTERN_MATCH_ON_VARIABLE, 7219 " 7220pub fn main() { 7221 let var = #(1, 2) 7222} 7223", 7224 find_position_of("var").to_selection() 7225 ); 7226} 7227 7228#[test] 7229fn pattern_match_on_let_assignment_with_multiple_constructors() { 7230 assert_code_action!( 7231 PATTERN_MATCH_ON_VARIABLE, 7232 " 7233pub type Wibble { 7234 Wobble 7235 Woo 7236} 7237 7238pub fn main() { 7239 let var = Woo 7240 todo 7241} 7242", 7243 find_position_of("var").to_selection() 7244 ); 7245} 7246 7247#[test] 7248fn pattern_match_on_use_assignment() { 7249 assert_code_action!( 7250 PATTERN_MATCH_ON_VARIABLE, 7251 " 7252pub fn main() { 7253 use var <- f 7254} 7255 7256fn f(g) { g(#(1, 2)) } 7257", 7258 find_position_of("var").to_selection() 7259 ); 7260} 7261 7262#[test] 7263fn pattern_match_on_use_assignment_with_multiple_constructors() { 7264 assert_code_action!( 7265 PATTERN_MATCH_ON_VARIABLE, 7266 " 7267pub type Wibble { 7268 Wobble 7269 Woo 7270} 7271 7272pub fn main() { 7273 use var <- f 7274} 7275 7276fn f(g) { g(Wobble) } 7277", 7278 find_position_of("var").to_selection() 7279 ); 7280} 7281 7282#[test] 7283fn pattern_match_on_pattern_use_assignment() { 7284 assert_no_code_actions!( 7285 PATTERN_MATCH_ON_VARIABLE, 7286 " 7287pub fn main() { 7288 use #(a, b) <- f 7289} 7290 7291fn f(g) { g(#(1, 2)) } 7292", 7293 find_position_of("#").to_selection() 7294 ); 7295} 7296 7297#[test] 7298fn pattern_match_on_argument_works_on_fn_arguments() { 7299 assert_code_action!( 7300 PATTERN_MATCH_ON_ARGUMENT, 7301 " 7302pub fn main() { 7303 [#(1, 2)] 7304 |> map(fn(tuple) {}) 7305} 7306 7307fn map(list: List(a), fun: fn(a) -> b) { todo } 7308", 7309 find_position_of("tuple").to_selection() 7310 ); 7311} 7312 7313#[test] 7314fn pattern_match_on_argument_works_on_nested_fn_arguments() { 7315 assert_code_action!( 7316 PATTERN_MATCH_ON_ARGUMENT, 7317 " 7318pub fn main() { 7319 map([[#(1, 2)]], fn(list) { 7320 map(list, fn(tuple) { 7321 todo 7322 }) 7323 }) 7324} 7325 7326fn map(list: List(a), fun: fn(a) -> b) { todo } 7327", 7328 find_position_of("tuple").to_selection() 7329 ); 7330} 7331 7332#[test] 7333fn generate_function_works_with_invalid_call() { 7334 assert_code_action!( 7335 GENERATE_FUNCTION, 7336 " 7337pub fn main() -> Bool { 7338 wibble(1, True, 2.3) 7339} 7340", 7341 find_position_of("wibble").to_selection() 7342 ); 7343} 7344 7345#[test] 7346fn generate_function_works_with_pipeline_steps() { 7347 assert_code_action!( 7348 GENERATE_FUNCTION, 7349 " 7350pub fn main() { 7351 [1, 2, 3] 7352 |> sum 7353 |> int_to_string 7354} 7355 7356fn int_to_string(n: Int) -> String { 7357 todo 7358} 7359", 7360 find_position_of("sum").to_selection() 7361 ); 7362} 7363 7364#[test] 7365fn generate_function_works_with_pipeline_steps_1() { 7366 assert_code_action!( 7367 GENERATE_FUNCTION, 7368 " 7369pub fn main() { 7370 [1, 2, 3] 7371 |> map(int_to_string) 7372 |> join 7373} 7374 7375fn map(list: List(a), fun: fn(a) -> b) -> List(b) { 7376 todo 7377} 7378 7379fn join(n: List(String)) -> String { 7380 todo 7381} 7382", 7383 find_position_of("int_to_string").to_selection() 7384 ); 7385} 7386 7387// https://github.com/gleam-lang/gleam/issues/4177#event-15968345230 7388#[test] 7389fn generate_function_picks_argument_name_based_on_type() { 7390 assert_code_action!( 7391 GENERATE_FUNCTION, 7392 " 7393pub fn main() { 7394 wibble(\"Hello\", 1) 7395} 7396", 7397 find_position_of("wibble").to_selection() 7398 ); 7399} 7400 7401#[test] 7402fn generate_function_wont_generate_two_arguments_with_the_same_name_if_they_have_the_same_type() { 7403 assert_code_action!( 7404 GENERATE_FUNCTION, 7405 " 7406pub fn main() { 7407 wibble(2, 1) 7408} 7409", 7410 find_position_of("wibble").to_selection() 7411 ); 7412} 7413 7414#[test] 7415fn generate_function_takes_labels_into_account() { 7416 assert_code_action!( 7417 GENERATE_FUNCTION, 7418 " 7419pub fn main() { 7420 wibble(2, n: 1) 7421} 7422", 7423 find_position_of("wibble").to_selection() 7424 ); 7425} 7426 7427#[test] 7428fn generate_function_does_not_trigger_if_labels_are_in_the_wrong_order() { 7429 assert_no_code_actions!( 7430 GENERATE_FUNCTION, 7431 " 7432pub fn main() { 7433 wibble(n: 2, 1) 7434} 7435", 7436 find_position_of("wibble").to_selection() 7437 ); 7438} 7439 7440#[test] 7441fn generate_function_does_not_trigger_if_there_are_repeated_labels() { 7442 assert_no_code_actions!( 7443 GENERATE_FUNCTION, 7444 " 7445pub fn main() { 7446 wibble(n: 2, n: 1) 7447} 7448", 7449 find_position_of("wibble").to_selection() 7450 ); 7451} 7452 7453#[test] 7454fn generate_function_generates_argument_names_from_labels() { 7455 assert_code_action!( 7456 GENERATE_FUNCTION, 7457 " 7458pub fn main() { 7459 add(1, addend: 10) 7460} 7461", 7462 find_position_of("add").to_selection() 7463 ); 7464} 7465 7466#[test] 7467fn generate_function_generates_argument_names_from_variables() { 7468 assert_code_action!( 7469 GENERATE_FUNCTION, 7470 " 7471pub fn main() { 7472 let wibble = 10 7473 let wobble = 20 7474 7475 wubble(wibble, wobble, 14) 7476} 7477", 7478 find_position_of("wubble").to_selection() 7479 ); 7480} 7481 7482#[test] 7483fn generate_function_labels_and_arguments_can_share_the_same_name() { 7484 assert_code_action!( 7485 GENERATE_FUNCTION, 7486 " 7487pub fn main() { 7488 let wibble = 10 7489 wubble(wibble, wibble: 14) 7490} 7491", 7492 find_position_of("wubble").to_selection() 7493 ); 7494} 7495 7496#[test] 7497fn generate_function_arguments_with_same_name_get_renamed() { 7498 assert_code_action!( 7499 GENERATE_FUNCTION, 7500 " 7501pub fn main() { 7502 let wibble = 10 7503 wubble(wibble, wibble) 7504} 7505", 7506 find_position_of("wubble").to_selection() 7507 ); 7508} 7509 7510#[test] 7511fn generate_function_arguments_with_labels_and_variables_uses_different_names() { 7512 assert_code_action!( 7513 GENERATE_FUNCTION, 7514 " 7515pub fn main() { 7516 let list = [2, 4, 5] 7517 let value = 1 7518 find(each: value, in: list) 7519} 7520", 7521 find_position_of("find").to_selection() 7522 ); 7523} 7524 7525#[test] 7526fn pattern_match_on_argument_generates_unique_names_even_with_labels() { 7527 assert_code_action!( 7528 PATTERN_MATCH_ON_ARGUMENT, 7529 " 7530pub type Wibble { 7531 Wibble(String, string: String) 7532} 7533 7534pub fn main(wibble: Wibble) { 7535 todo 7536} 7537", 7538 find_position_of("wibble").to_selection() 7539 ); 7540} 7541 7542#[test] 7543fn extract_variable_with_list_with_plural_name_does_not_add_another_s() { 7544 assert_code_action!( 7545 EXTRACT_VARIABLE, 7546 " 7547pub fn main() { 7548 wibble([Names, Names]) 7549} 7550 7551pub type Names { 7552 Names 7553} 7554", 7555 find_position_of("[").to_selection() 7556 ); 7557} 7558 7559#[test] 7560fn convert_to_function_call_works_with_argument_in_first_position() { 7561 assert_code_action!( 7562 CONVERT_TO_FUNCTION_CALL, 7563 " 7564pub fn main() { 7565 [1, 2, 3] 7566 |> map(todo) 7567} 7568 7569fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 7570", 7571 find_position_of("map").to_selection() 7572 ); 7573} 7574 7575#[test] 7576fn generate_json_encoder() { 7577 let src = " 7578pub type Person { 7579 Person(name: String, age: Int, height: Float, is_cool: Bool) 7580} 7581"; 7582 7583 assert_code_action!( 7584 GENERATE_TO_JSON_FUNCTION, 7585 TestProject::for_source(src).add_package_module( 7586 "gleam_json", 7587 "gleam/json", 7588 "pub type Json" 7589 ), 7590 find_position_of("type").to_selection() 7591 ); 7592} 7593 7594#[test] 7595fn convert_to_function_call_works_with_argument_in_first_position_2() { 7596 assert_code_action!( 7597 CONVERT_TO_FUNCTION_CALL, 7598 " 7599pub fn main() { 7600 [1, 2, 3] |> wibble 7601} 7602 7603fn wibble(a) { todo } 7604", 7605 find_position_of("wibble").to_selection() 7606 ); 7607} 7608 7609#[test] 7610fn generate_json_encoder_complex_types() { 7611 let src = " 7612import gleam/option 7613import gleam/dict 7614 7615pub type Something 7616 7617pub type Wibble(value) { 7618 Wibble( 7619 maybe: option.Option(Int), 7620 something: Something, 7621 map: dict.Dict(String, List(Float)), 7622 unknown: List(value), 7623 ) 7624} 7625"; 7626 7627 assert_code_action!( 7628 GENERATE_TO_JSON_FUNCTION, 7629 TestProject::for_source(src) 7630 .add_module("gleam/option", "pub type Option(a)") 7631 .add_module("gleam/dict", "pub type Dict(k, v)") 7632 .add_package_module("gleam_json", "gleam/json", "pub type Json"), 7633 find_position_of("type W").to_selection() 7634 ); 7635} 7636 7637#[test] 7638fn convert_to_function_call_works_with_argument_in_first_position_3() { 7639 assert_code_action!( 7640 CONVERT_TO_FUNCTION_CALL, 7641 " 7642pub fn main() { 7643 [1, 2, 3] |> wibble() 7644} 7645 7646fn wibble(a) { todo } 7647", 7648 find_position_of("wibble").to_selection() 7649 ); 7650} 7651 7652#[test] 7653fn generate_json_encoder_already_imported_module() { 7654 let src = " 7655import gleam/json as json_encoding 7656 7657pub type Wibble { 7658 Wibble(a: Int, b: Float, c: String) 7659} 7660"; 7661 7662 assert_code_action!( 7663 GENERATE_TO_JSON_FUNCTION, 7664 TestProject::for_source(src).add_package_module( 7665 "gleam_json", 7666 "gleam/json", 7667 "pub type Json" 7668 ), 7669 find_position_of("type W").to_selection() 7670 ); 7671} 7672 7673#[test] 7674fn convert_to_function_call_works_with_argument_in_first_position_4() { 7675 assert_code_action!( 7676 CONVERT_TO_FUNCTION_CALL, 7677 " 7678pub fn main() { 7679 [1, 2, 3] |> wibble.wobble 7680} 7681", 7682 find_position_of("wibble").to_selection() 7683 ); 7684} 7685 7686#[test] 7687fn generate_json_encoder_tuple() { 7688 let src = " 7689pub type Wibble { 7690 Wibble(tuple: #(Int, Float, #(String, Bool))) 7691} 7692"; 7693 7694 assert_code_action!( 7695 GENERATE_TO_JSON_FUNCTION, 7696 TestProject::for_source(src).add_package_module( 7697 "gleam_json", 7698 "gleam/json", 7699 "pub type Json" 7700 ), 7701 find_position_of("type W").to_selection() 7702 ); 7703} 7704 7705#[test] 7706fn generate_json_encoder_for_variant_with_no_fields() { 7707 let src = " 7708pub type Wibble { 7709 Wibble 7710} 7711"; 7712 7713 assert_code_action!( 7714 GENERATE_TO_JSON_FUNCTION, 7715 TestProject::for_source(src).add_package_module( 7716 "gleam_json", 7717 "gleam/json", 7718 "pub type Json" 7719 ), 7720 find_position_of("type W").to_selection() 7721 ); 7722} 7723 7724#[test] 7725fn generate_json_encoder_for_type_with_multiple_variants_with_no_fields() { 7726 let src = " 7727pub type Wibble { 7728 Wibble 7729 Wobble 7730 Woo 7731} 7732"; 7733 7734 assert_code_action!( 7735 GENERATE_TO_JSON_FUNCTION, 7736 TestProject::for_source(src).add_package_module( 7737 "gleam_json", 7738 "gleam/json", 7739 "pub type Json" 7740 ), 7741 find_position_of("type W").to_selection() 7742 ); 7743} 7744 7745#[test] 7746fn generate_json_encoder_for_variants_with_mixed_fields() { 7747 let src = " 7748pub type Wibble { 7749 Wibble 7750 Wobble(field: String, field1: Int) 7751} 7752"; 7753 7754 assert_code_action!( 7755 GENERATE_TO_JSON_FUNCTION, 7756 TestProject::for_source(src).add_package_module( 7757 "gleam_json", 7758 "gleam/json", 7759 "pub type Json" 7760 ), 7761 find_position_of("type W").to_selection() 7762 ); 7763} 7764 7765#[test] 7766fn convert_to_function_call_works_with_function_producing_another_function() { 7767 assert_code_action!( 7768 CONVERT_TO_FUNCTION_CALL, 7769 " 7770pub fn main() { 7771 1 |> wibble(2) 7772} 7773 7774fn wibble(c) -> fn(a) -> Nil { 7775 fn(_) { Nil } 7776} 7777", 7778 find_position_of("wibble").to_selection() 7779 ); 7780} 7781 7782#[test] 7783fn generate_json_encoder_recursive_type() { 7784 let src = " 7785import gleam/option.{Some} 7786 7787pub type LinkedList { 7788 LinkedList(value: Int, next: option.Option(LinkedList)) 7789} 7790"; 7791 assert_code_action!( 7792 GENERATE_TO_JSON_FUNCTION, 7793 TestProject::for_source(src) 7794 .add_module("gleam/option", "pub type Option(a) { Some(a) None }") 7795 .add_package_module("gleam_json", "gleam/json", "pub type Json"), 7796 find_position_of("type").to_selection() 7797 ); 7798} 7799 7800#[test] 7801fn convert_to_function_call_works_with_hole_in_first_position() { 7802 assert_code_action!( 7803 CONVERT_TO_FUNCTION_CALL, 7804 " 7805pub fn main() { 7806 [1, 2, 3] 7807 |> map(_, todo) 7808} 7809 7810fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 7811", 7812 find_position_of("[").to_selection() 7813 ); 7814} 7815 7816#[test] 7817fn generate_json_encoder_list_of_tuples() { 7818 let src = " 7819pub type Wibble { 7820 Wibble(values: List(#(Int, String))) 7821} 7822"; 7823 7824 assert_code_action!( 7825 GENERATE_TO_JSON_FUNCTION, 7826 TestProject::for_source(src).add_package_module( 7827 "gleam_json", 7828 "gleam/json", 7829 "pub type Json" 7830 ), 7831 find_position_of("type").to_selection() 7832 ); 7833} 7834 7835#[test] 7836fn generate_json_encoder_for_multi_variant_type() { 7837 let src = " 7838pub type Wibble { 7839 Wibble(wibble: Int, next: Wibble) 7840 Wobble(wobble: Float, text: String, values: List(Bool)) 7841} 7842"; 7843 7844 assert_code_action!( 7845 GENERATE_TO_JSON_FUNCTION, 7846 TestProject::for_source(src).add_package_module( 7847 "gleam_json", 7848 "gleam/json", 7849 "pub type Json" 7850 ), 7851 find_position_of("type").to_selection() 7852 ); 7853} 7854 7855#[test] 7856fn generate_json_encoder_for_multi_variant_type_multi_word_name() { 7857 let src = " 7858pub type Wibble { 7859 OneTwoThree(wibble: Int, next: Wibble) 7860 FourFive(wobble: Float, text: String, values: List(Bool)) 7861 SixSevenEight(one_two: Float) 7862} 7863"; 7864 7865 assert_code_action!( 7866 GENERATE_TO_JSON_FUNCTION, 7867 TestProject::for_source(src).add_package_module( 7868 "gleam_json", 7869 "gleam/json", 7870 "pub type Json" 7871 ), 7872 find_position_of("type").to_selection() 7873 ); 7874} 7875 7876#[test] 7877fn convert_to_function_call_works_with_hole_not_in_first_position() { 7878 assert_code_action!( 7879 CONVERT_TO_FUNCTION_CALL, 7880 " 7881pub fn main() { 7882 fn(a) { todo } 7883 |> map([1, 2, 3], _) 7884} 7885 7886fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 7887", 7888 find_position_of("fn(a)").select_until(find_position_of("map")) 7889 ); 7890} 7891 7892#[test] 7893fn convert_to_function_call_always_inlines_the_first_step() { 7894 assert_code_action!( 7895 CONVERT_TO_FUNCTION_CALL, 7896 " 7897pub fn main() { 7898 [1, 2, 3] 7899 |> map(todo) 7900 |> filter(todo) 7901} 7902 7903fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 7904fn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo } 7905", 7906 find_position_of("[1, 2, 3]").select_until(find_position_of("map")) 7907 ); 7908} 7909 7910#[test] 7911fn convert_to_function_call_works_with_labelled_argument() { 7912 assert_code_action!( 7913 CONVERT_TO_FUNCTION_CALL, 7914 " 7915pub fn main() { 7916 [1, 2, 3] |> wibble(wobble: _, woo:) 7917} 7918", 7919 find_position_of("wibble").to_selection() 7920 ); 7921} 7922 7923#[test] 7924fn convert_to_function_call_works_with_labelled_argument_2() { 7925 assert_code_action!( 7926 CONVERT_TO_FUNCTION_CALL, 7927 " 7928pub fn main() { 7929 [1, 2, 3] |> wibble(wobble:, woo: _) 7930} 7931", 7932 find_position_of("wibble").to_selection() 7933 ); 7934} 7935 7936#[test] 7937fn convert_to_function_call_works_when_piping_an_invalid_module_select() { 7938 assert_code_action!( 7939 CONVERT_TO_FUNCTION_CALL, 7940 " 7941pub fn main() { 7942 wibble.wobble |> woo(_) 7943} 7944", 7945 find_position_of("woo").to_selection() 7946 ); 7947} 7948 7949#[test] 7950fn convert_to_function_call_works_when_piping_a_module_select() { 7951 let src = " 7952import wibble 7953 7954pub fn main() { 7955 wibble.wobble |> woo(_) 7956} 7957 7958fn woo(n) { todo } 7959"; 7960 7961 assert_code_action!( 7962 CONVERT_TO_FUNCTION_CALL, 7963 TestProject::for_source(src).add_module("wibble", "pub const wobble = 1"), 7964 find_position_of("woo").to_selection() 7965 ); 7966} 7967 7968#[test] 7969fn convert_to_function_call_works_with_echo() { 7970 assert_code_action!( 7971 CONVERT_TO_FUNCTION_CALL, 7972 " 7973pub fn main() { 7974 wibble.wobble |> echo 7975} 7976", 7977 find_position_of("echo").to_selection() 7978 ); 7979} 7980 7981#[test] 7982fn no_code_action_to_generate_json_encoder_for_type_without_labels() { 7983 let src = " 7984pub type Wibble { 7985 Wibble(Int, Int, String) 7986} 7987 "; 7988 7989 assert_no_code_actions!( 7990 GENERATE_TO_JSON_FUNCTION, 7991 TestProject::for_source(src).add_package_module( 7992 "gleam_json", 7993 "gleam/json", 7994 "pub type Json" 7995 ), 7996 find_position_of("type").to_selection() 7997 ); 7998} 7999 8000#[test] 8001fn no_code_action_to_generate_json_encoder_without_gleam_json_dependency() { 8002 assert_no_code_actions!( 8003 GENERATE_TO_JSON_FUNCTION, 8004 " 8005pub type Wibble { 8006 Wibble(w: Int) 8007} 8008", 8009 find_position_of("type").to_selection() 8010 ); 8011} 8012 8013#[test] 8014fn inline_variable() { 8015 let src = r#" 8016import gleam/io 8017 8018pub fn main() { 8019 let message = "Hello!" 8020 io.println(message) 8021} 8022"#; 8023 assert_code_action!( 8024 INLINE_VARIABLE, 8025 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 8026 find_position_of("message)").to_selection() 8027 ); 8028} 8029 8030#[test] 8031fn inline_variable_from_definition() { 8032 let src = r#" 8033import gleam/io 8034 8035pub fn main() { 8036 let message = "Hello!" 8037 io.println(message) 8038} 8039"#; 8040 assert_code_action!( 8041 INLINE_VARIABLE, 8042 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 8043 find_position_of("message =").to_selection() 8044 ); 8045} 8046 8047#[test] 8048fn inline_variable_in_nested_scope() { 8049 let src = r#" 8050import gleam/io 8051 8052pub fn main() { 8053 let _ = { 8054 let message = "Hello!" 8055 io.println(message) 8056 } 8057} 8058"#; 8059 assert_code_action!( 8060 INLINE_VARIABLE, 8061 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 8062 find_position_of("message =").to_selection() 8063 ); 8064} 8065 8066#[test] 8067fn inline_variable_in_case_scope() { 8068 let src = r#" 8069import gleam/io 8070 8071pub fn main(x) { 8072 case x { 8073 True -> { 8074 let message = "Hello!" 8075 io.println(message) 8076 } 8077 False -> Nil 8078 } 8079} 8080"#; 8081 assert_code_action!( 8082 INLINE_VARIABLE, 8083 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 8084 find_position_of("message =").to_selection() 8085 ); 8086} 8087 8088#[test] 8089fn no_code_action_to_inline_variable_used_multiple_times() { 8090 let src = r#" 8091import gleam/io 8092 8093pub fn main() { 8094 let message = "Hello!" 8095 io.println(message) 8096 io.debug(message) 8097} 8098"#; 8099 assert_no_code_actions!( 8100 INLINE_VARIABLE, 8101 TestProject::for_source(src).add_module( 8102 "gleam/io", 8103 "pub fn println(value) {} pub fn debug(value) {}" 8104 ), 8105 find_position_of("message =").to_selection() 8106 ); 8107} 8108 8109#[test] 8110fn no_code_action_to_inline_variable_defined_in_complex_pattern() { 8111 let src = r#" 8112import gleam/io 8113 8114pub fn main() { 8115 let #(message, second, _) = todo 8116 io.println(message) 8117} 8118"#; 8119 assert_no_code_actions!( 8120 INLINE_VARIABLE, 8121 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 8122 find_position_of("message)").to_selection() 8123 ); 8124} 8125 8126#[test] 8127fn no_code_action_to_inline_variable_defined_in_case_clause() { 8128 let src = r#" 8129import gleam/io 8130 8131pub fn main(result) { 8132 case result { 8133 Ok(value) -> value 8134 Error(message) -> { 8135 io.println(message) 8136 panic 8137 } 8138 } 8139} 8140"#; 8141 assert_no_code_actions!( 8142 INLINE_VARIABLE, 8143 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 8144 find_position_of("message").nth_occurrence(2).to_selection() 8145 ); 8146} 8147 8148#[test] 8149fn convert_to_pipe_with_function_call_on_first_argument() { 8150 assert_code_action!( 8151 CONVERT_TO_PIPE, 8152 " 8153pub fn main() { 8154 wibble(wobble, woo) 8155} 8156", 8157 find_position_of("wobble").to_selection() 8158 ); 8159} 8160 8161#[test] 8162fn convert_to_pipe_with_function_call_on_second_argument() { 8163 assert_code_action!( 8164 CONVERT_TO_PIPE, 8165 " 8166pub fn main() { 8167 wibble(wobble, woo) 8168} 8169", 8170 find_position_of("woo").to_selection() 8171 ); 8172} 8173 8174#[test] 8175fn convert_to_pipe_with_function_call_on_function_name_extracts_first_argument() { 8176 assert_code_action!( 8177 CONVERT_TO_PIPE, 8178 " 8179pub fn main() { 8180 wibble(wobble, woo) 8181} 8182", 8183 find_position_of("wibble").to_selection() 8184 ); 8185} 8186 8187#[test] 8188fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole() { 8189 assert_code_action!( 8190 CONVERT_TO_PIPE, 8191 " 8192pub fn main() { 8193 wibble(wobble: 1, woo: 2) 8194} 8195", 8196 find_position_of("wobble").to_selection() 8197 ); 8198} 8199 8200#[test] 8201fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole_2() { 8202 assert_code_action!( 8203 CONVERT_TO_PIPE, 8204 " 8205pub fn main() { 8206 wibble(wobble: 1, woo: 2) 8207} 8208", 8209 find_position_of("woo").to_selection() 8210 ); 8211} 8212 8213#[test] 8214fn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole() { 8215 assert_code_action!( 8216 CONVERT_TO_PIPE, 8217 " 8218pub fn main() { 8219 wibble(wobble:, woo:) 8220} 8221", 8222 find_position_of("wobble").to_selection() 8223 ); 8224} 8225 8226#[test] 8227fn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole_2() { 8228 assert_code_action!( 8229 CONVERT_TO_PIPE, 8230 " 8231pub fn main() { 8232 wibble(wobble:, woo:) 8233} 8234", 8235 find_position_of("woo").to_selection() 8236 ); 8237} 8238 8239#[test] 8240fn convert_to_pipe_on_first_step_of_pipeline() { 8241 assert_code_action!( 8242 CONVERT_TO_PIPE, 8243 " 8244pub fn main() { 8245 wibble(wobble, woo) |> wobble 8246} 8247", 8248 find_position_of("wibble").to_selection() 8249 ); 8250} 8251 8252#[test] 8253fn convert_to_pipe_not_allowed_on_other_pipeline_steps() { 8254 assert_no_code_actions!( 8255 CONVERT_TO_PIPE, 8256 " 8257pub fn main() { 8258 wibble(wobble) |> wobble(woo) 8259} 8260", 8261 find_position_of("woo").to_selection() 8262 ); 8263} 8264 8265#[test] 8266fn convert_to_pipe_with_function_returning_other_function() { 8267 assert_code_action!( 8268 CONVERT_TO_PIPE, 8269 " 8270pub fn main() { 8271 wibble(wobble)(woo) 8272} 8273", 8274 find_position_of("woo").to_selection() 8275 ); 8276} 8277 8278#[test] 8279fn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use() { 8280 assert_no_code_actions!( 8281 CONVERT_TO_PIPE, 8282 " 8283pub fn main() { 8284 use <- wibble(wobble) 8285 todo 8286} 8287", 8288 find_position_of("wibble").to_selection() 8289 ); 8290} 8291 8292#[test] 8293fn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use_2() { 8294 assert_no_code_actions!( 8295 CONVERT_TO_PIPE, 8296 " 8297pub fn main() { 8298 use <- wibble(wobble) 8299 todo 8300} 8301", 8302 find_position_of("todo").to_selection() 8303 ); 8304} 8305 8306#[test] 8307fn convert_to_pipe_does_not_work_on_function_with_capture() { 8308 assert_no_code_actions!( 8309 CONVERT_TO_PIPE, 8310 "import gleam/int 8311 8312pub fn main() { 8313 let sum = int.add(1, _) 8314 sum 8315} 8316", 8317 find_position_of("1").to_selection() 8318 ); 8319} 8320 8321#[test] 8322fn convert_to_pipe_does_not_work_on_record_with_capture() { 8323 assert_no_code_actions!( 8324 CONVERT_TO_PIPE, 8325 "pub fn main() { 8326 Ok(_) 8327} 8328", 8329 find_position_of("O").to_selection() 8330 ); 8331} 8332 8333#[test] 8334fn convert_to_pipe_works_inside_body_of_use() { 8335 assert_code_action!( 8336 CONVERT_TO_PIPE, 8337 " 8338pub fn main() { 8339 use <- wibble(wobble) 8340 woo(123) 8341} 8342", 8343 find_position_of("woo").to_selection() 8344 ); 8345} 8346 8347#[test] 8348fn convert_to_pipe_pipes_the_outermost_argument() { 8349 assert_code_action!( 8350 CONVERT_TO_PIPE, 8351 " 8352pub fn main() { 8353 wibble(wobble(woo)) 8354} 8355", 8356 find_position_of("wobble").to_selection() 8357 ); 8358} 8359 8360#[test] 8361fn convert_to_pipe_when_first_arg_is_a_pipe_itself() { 8362 assert_code_action!( 8363 CONVERT_TO_PIPE, 8364 " 8365pub fn main() { 8366 wibble(wobble |> woo, waa) 8367} 8368", 8369 find_position_of("wibble").to_selection() 8370 ); 8371} 8372 8373#[test] 8374fn convert_to_pipe_with_string_concat_adds_braces() { 8375 assert_code_action!( 8376 CONVERT_TO_PIPE, 8377 " 8378pub fn main() { 8379 wibble(wobble <> woo, waa) 8380} 8381", 8382 find_position_of("wibble").to_selection() 8383 ); 8384} 8385 8386#[test] 8387fn convert_to_pipe_with_bool_operator_adds_braces() { 8388 assert_code_action!( 8389 CONVERT_TO_PIPE, 8390 " 8391pub fn main() { 8392 wibble(wobble != woo, waa) 8393} 8394", 8395 find_position_of("wibble").to_selection() 8396 ); 8397} 8398 8399#[test] 8400fn convert_to_pipe_with_sum_adds_no_braces() { 8401 assert_code_action!( 8402 CONVERT_TO_PIPE, 8403 " 8404pub fn main() { 8405 wibble(1 + 1, waa) 8406} 8407", 8408 find_position_of("wibble").to_selection() 8409 ); 8410} 8411 8412#[test] 8413fn convert_to_pipe_with_comparison_adds_braces() { 8414 assert_code_action!( 8415 CONVERT_TO_PIPE, 8416 " 8417pub fn main() { 8418 wibble(1.0 >=. 0.0, waa) 8419} 8420", 8421 find_position_of("wibble").to_selection() 8422 ); 8423} 8424 8425#[test] 8426fn convert_to_pipe_with_complex_binop_adds_braces() { 8427 assert_code_action!( 8428 CONVERT_TO_PIPE, 8429 " 8430fn bug() { 8431 bool.guard(1 == 2 || 2 == 3, Nil, fn() { Nil }) 8432} 8433", 8434 find_position_of("||").to_selection() 8435 ); 8436} 8437 8438// https://github.com/gleam-lang/gleam/issues/4342 8439#[test] 8440fn inline_variable_in_record_update() { 8441 assert_code_action!( 8442 INLINE_VARIABLE, 8443 " 8444type Couple { 8445 Couple(l: Int, r: Int) 8446} 8447 8448pub fn main() { 8449 let c1 = Couple(l: 1, r: 1) 8450 let c2 = Couple(..c1, r: 1) 8451} 8452", 8453 find_position_of("c1,").to_selection() 8454 ); 8455} 8456 8457// https://github.com/gleam-lang/gleam/issues/4430 8458#[test] 8459fn inline_variable_with_record_field() { 8460 assert_code_action!( 8461 INLINE_VARIABLE, 8462 " 8463type Couple { 8464 Couple(l: Int, r: Int) 8465} 8466 8467pub fn main() { 8468 let c1 = Couple(l: 1, r: 1) 8469 let c2 = c1.l 8470 echo c2 8471} 8472", 8473 find_position_of("c2").nth_occurrence(2).to_selection() 8474 ); 8475} 8476 8477#[test] 8478fn wrap_case_clause_in_block() { 8479 assert_code_action!( 8480 WRAP_IN_BLOCK, 8481 " 8482pub fn f(option) { 8483 case option { 8484 Some(content) -> content 8485 None -> panic 8486 } 8487}", 8488 find_position_of("content").nth_occurrence(2).to_selection() 8489 ); 8490} 8491 8492#[test] 8493fn wrap_nested_case_clause_in_block() { 8494 assert_code_action!( 8495 WRAP_IN_BLOCK, 8496 " 8497pub fn f(result) { 8498 case result { 8499 Ok(reresult) -> { 8500 case reresult { 8501 Ok(w) -> w 8502 Error(_) -> panic 8503 } 8504 } 8505 Error(_) -> panic 8506 } 8507}", 8508 find_position_of("w").nth_occurrence(2).to_selection() 8509 ); 8510} 8511 8512#[test] 8513fn wrap_case_clause_with_guard_in_block() { 8514 assert_code_action!( 8515 WRAP_IN_BLOCK, 8516 " 8517pub fn f(option) { 8518 case option { 8519 Some(integer) if integer > 0 -> integer 8520 Some(integer) -> 0 8521 None -> panic 8522 } 8523}", 8524 find_position_of("integer").nth_occurrence(3).to_selection() 8525 ); 8526} 8527 8528#[test] 8529fn wrap_case_clause_with_multiple_patterns_in_block() { 8530 assert_code_action!( 8531 WRAP_IN_BLOCK, 8532 "pub type PokemonType { 8533 Air 8534 Water 8535 Fire 8536} 8537 8538 pub fn f(pokemon_type: PokemonType) { 8539 case pokemon_type { 8540 Water | Air -> soak() 8541 Fire -> burn() 8542 } 8543 }", 8544 find_position_of("soak").to_selection() 8545 ); 8546} 8547 8548#[test] 8549fn wrap_case_clause_inside_assignment_in_block() { 8550 assert_code_action!( 8551 WRAP_IN_BLOCK, 8552 r#"pub type PokemonType { 8553 Air 8554 Water 8555 Fire 8556} 8557 8558 pub fn f(pokemon_type: PokemonType) { 8559 let damage = case pokemon_type { 8560 Water -> soak() 8561 Fire -> burn() 8562 } 8563 8564 "Pokemon did " <> damage 8565 }"#, 8566 find_position_of("burn").to_selection() 8567 ); 8568} 8569 8570#[test] 8571fn wrap_case_assignment_of_record_access_in_block() { 8572 assert_code_action!( 8573 WRAP_IN_BLOCK, 8574 r#" 8575pub type Record { 8576 R(left: Int, right: Int) 8577} 8578 8579pub fn main() { 8580 let r = R(1, 2) 8581 let l = r.left 8582 l 8583} 8584"#, 8585 find_position_of("left").nth_occurrence(2).to_selection() 8586 ); 8587} 8588 8589#[test] 8590fn do_not_wrap_case_clause_in_block_1() { 8591 assert_no_code_actions!( 8592 WRAP_IN_BLOCK, 8593 " 8594pub fn f(option) { 8595 case option { 8596 Some(content) -> { 8597 content 8598 } 8599 None -> panic 8600 } 8601}", 8602 find_position_of("content").nth_occurrence(2).to_selection() 8603 ); 8604} 8605 8606#[test] 8607fn do_not_wrap_case_clause_in_block_2() { 8608 assert_no_code_actions!( 8609 WRAP_IN_BLOCK, 8610 " 8611pub fn f(result) { 8612 case result { 8613 Ok(reresult) -> { 8614 case reresult { 8615 Ok(w) -> { 8616 w 8617 } 8618 Error(_) -> panic 8619 } 8620 } 8621 Error(_) -> panic 8622 } 8623}", 8624 find_position_of("w").nth_occurrence(2).to_selection() 8625 ); 8626} 8627 8628#[test] 8629fn do_not_wrap_case_clause_in_block_3() { 8630 assert_no_code_actions!( 8631 WRAP_IN_BLOCK, 8632 " 8633pub fn f(option) { 8634 case option { 8635 Some(content) -> content 8636 None -> panic 8637 } 8638}", 8639 find_position_of("Some(content)").to_selection() 8640 ); 8641} 8642 8643#[test] 8644fn wrap_assignment_value_in_block() { 8645 assert_code_action!( 8646 WRAP_IN_BLOCK, 8647 r#"pub fn main() { 8648 let var = "value" 8649}"#, 8650 find_position_of("value").select_until(find_position_of("e").nth_occurrence(2)) 8651 ); 8652} 8653 8654#[test] 8655fn do_not_wrap_assignment_value_in_block() { 8656 assert_no_code_actions!( 8657 WRAP_IN_BLOCK, 8658 r#"pub fn main() { 8659 let var = "value" 8660}"#, 8661 find_position_of("var").to_selection() 8662 ); 8663} 8664 8665// https://github.com/gleam-lang/gleam/issues/4427 8666#[test] 8667fn extract_constant_function() { 8668 assert_no_code_actions!( 8669 EXTRACT_CONSTANT, 8670 r#" 8671fn print(x) { 8672 Nil 8673} 8674 8675pub fn main() { 8676 print("Hello") 8677} 8678"#, 8679 find_position_of("print").nth_occurrence(2).to_selection() 8680 ); 8681} 8682 8683#[test] 8684fn fix_float_operator_on_ints() { 8685 let name = "Use `>=`"; 8686 assert_code_action!( 8687 name, 8688 r#" 8689pub fn main() { 8690 1 >=. 2 8691} 8692"#, 8693 find_position_of("1").to_selection() 8694 ); 8695} 8696 8697#[test] 8698fn fix_float_operator_on_ints_2() { 8699 let name = "Use `-`"; 8700 assert_code_action!( 8701 name, 8702 r#" 8703pub fn main() { 8704 1 -. 2 8705} 8706"#, 8707 find_position_of("1").select_until(find_position_of("2")) 8708 ); 8709} 8710 8711#[test] 8712fn fix_float_operator_on_ints_3() { 8713 let name = "Use `*`"; 8714 assert_code_action!( 8715 name, 8716 r#" 8717pub fn main() { 8718 1 *. wobble() 8719} 8720 8721fn wobble() { 3 } 8722"#, 8723 find_position_of("*.").to_selection() 8724 ); 8725} 8726 8727#[test] 8728fn fix_int_operator_on_floats() { 8729 let name = "Use `>=.`"; 8730 assert_code_action!( 8731 name, 8732 r#" 8733pub fn main() { 8734 1.0 >= 2.3 8735} 8736"#, 8737 find_position_of("1").to_selection() 8738 ); 8739} 8740 8741#[test] 8742fn fix_int_operator_on_floats_2() { 8743 let name = "Use `-.`"; 8744 assert_code_action!( 8745 name, 8746 r#" 8747pub fn main() { 8748 1.12 - 2.0 8749} 8750"#, 8751 find_position_of("1").select_until(find_position_of("2.0")) 8752 ); 8753} 8754 8755#[test] 8756fn fix_int_operator_on_floats_3() { 8757 let name = "Use `*.`"; 8758 assert_code_action!( 8759 name, 8760 r#" 8761pub fn main() { 8762 1.3 * wobble() 8763} 8764 8765fn wobble() { 3.2 } 8766"#, 8767 find_position_of("*").to_selection() 8768 ); 8769} 8770 8771#[test] 8772fn fix_plus_operator_on_strings() { 8773 let name = "Use `<>`"; 8774 assert_code_action!( 8775 name, 8776 r#" 8777pub fn main() { 8778 "hello, " + name() 8779} 8780 8781fn name() { "Jak" } 8782"#, 8783 find_position_of("hello").select_until(find_position_of("name()")) 8784 ); 8785} 8786 8787// https://github.com/gleam-lang/gleam/issues/4454 8788#[test] 8789fn unqualify_already_imported_type() { 8790 let src = " 8791import wibble.{type Wibble} 8792 8793pub fn main() -> wibble.Wibble { 8794 todo 8795} 8796"; 8797 8798 assert_code_action!( 8799 "Unqualify wibble.Wibble", 8800 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble"), 8801 find_position_of("wibble.Wibble").to_selection(), 8802 ); 8803} 8804 8805#[test] 8806fn fill_labels_pattern_constructor() { 8807 assert_code_action!( 8808 FILL_LABELS, 8809 " 8810pub type Wibble { 8811 Wibble(a: Int, b: Float, c: String) 8812 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil))) 8813} 8814 8815pub fn main(w: Wibble) { 8816 case w { 8817 Wibble(..) -> todo 8818 Wobble() -> todo 8819 } 8820} 8821", 8822 find_position_of("Wobble()").to_selection(), 8823 ); 8824} 8825 8826#[test] 8827fn fill_labels_pattern_constructor_let_assignment() { 8828 assert_code_action!( 8829 FILL_LABELS, 8830 " 8831pub type Wibble { 8832 Wibble(a: Int, b: Float, c: String) 8833} 8834 8835pub fn main() { 8836 let Wibble() = todo 8837} 8838", 8839 find_position_of("Wibble()").to_selection(), 8840 ); 8841} 8842 8843#[test] 8844fn fill_labels_pattern_constructor_with_some_labels() { 8845 assert_code_action!( 8846 FILL_LABELS, 8847 " 8848pub type Wibble { 8849 Wibble(a: Int, b: Float, c: String) 8850 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil))) 8851} 8852 8853pub fn main(w: Wibble) { 8854 case w { 8855 Wobble(e: <<>>) -> todo 8856 _ -> todo 8857 } 8858} 8859", 8860 find_position_of("Wobble(e").to_selection(), 8861 ); 8862} 8863 8864#[test] 8865fn fill_labels_nested_pattern_constructor() { 8866 assert_code_action!( 8867 FILL_LABELS, 8868 " 8869pub type Wibble { 8870 Wibble(a: Int, b: Float, c: String) 8871 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil))) 8872} 8873 8874pub fn main() { 8875 case todo { 8876 #([Wobble()], 2, 3) -> todo 8877 _ -> todo 8878 } 8879} 8880", 8881 find_position_of("Wobble()").to_selection(), 8882 ); 8883} 8884 8885#[test] 8886// https://github.com/gleam-lang/gleam/issues/4499 8887fn fill_labels_with_function_with_unlabelled_arguments() { 8888 assert_no_code_actions!( 8889 FILL_LABELS, 8890 " 8891pub fn main() { 8892 fold(0, over: [], with: fn(acc, item) { acc + item }) 8893} 8894 8895pub fn fold(over list, from initial, with fun) { todo }", 8896 find_position_of("fold").to_selection(), 8897 ); 8898} 8899 8900#[test] 8901fn add_missing_patterns_with_labels() { 8902 assert_code_action!( 8903 ADD_MISSING_PATTERNS, 8904 " 8905pub type Wibble { 8906 Wibble(integer: Int, float: Float) 8907 Wobble(string: String, bool: Bool) 8908} 8909 8910pub fn main(w: Wibble) { 8911 case w {} 8912} 8913", 8914 find_position_of("case w").select_until(find_position_of("{}")), 8915 ); 8916} 8917 8918// https://github.com/gleam-lang/gleam/issues/3628#issuecomment-2543342212 8919#[test] 8920fn add_missing_patterns_multibyte_grapheme() { 8921 assert_code_action!( 8922 ADD_MISSING_PATTERNS, 8923 r#" 8924// ä 8925fn wibble() { 8926 case True {} 8927} 8928"#, 8929 find_position_of("case").select_until(find_position_of("True {")) 8930 ); 8931} 8932 8933// https://github.com/gleam-lang/gleam/issues/4626 8934#[test] 8935fn add_missing_patterns_opaque_type() { 8936 let src = " 8937import mod 8938 8939pub fn main(w: mod.Wibble) { 8940 case w {} 8941} 8942"; 8943 8944 assert_code_action!( 8945 ADD_MISSING_PATTERNS, 8946 TestProject::for_source(src).add_hex_module( 8947 "mod", 8948 "pub opaque type Wibble { Wibble(Int) Wobble(String) }" 8949 ), 8950 find_position_of("{}").to_selection(), 8951 ); 8952} 8953 8954// https://github.com/gleam-lang/gleam/issues/4653 8955#[test] 8956fn generate_function_capture() { 8957 assert_code_action!( 8958 GENERATE_FUNCTION, 8959 " 8960fn map(list: List(a), f: fn(a) -> b) -> List(b) { 8961 todo 8962} 8963 8964pub fn main() { 8965 map([1, 2, 3], add(_, 1)) 8966} 8967", 8968 find_position_of("add").to_selection() 8969 ); 8970} 8971 8972// https://github.com/gleam-lang/gleam/issues/4660#issuecomment-2932371619 8973#[test] 8974fn inline_variable_label_shorthand() { 8975 assert_code_action!( 8976 INLINE_VARIABLE, 8977 " 8978pub type Example { 8979 Example(sum: Int, nil: Nil) 8980} 8981 8982pub fn main() { 8983 let sum = 1 + 1 8984 8985 Example(Nil, sum:) 8986} 8987", 8988 find_position_of("sum = ").to_selection() 8989 ); 8990} 8991 8992// https://github.com/gleam-lang/gleam/issues/4660 8993#[test] 8994fn no_inline_variable_action_for_parameter() { 8995 assert_no_code_actions!( 8996 INLINE_VARIABLE, 8997 " 8998pub fn main() { 8999 let x = fn(something) { 9000 something 9001 } 9002 9003 x 9004} 9005", 9006 find_position_of("something") 9007 .nth_occurrence(2) 9008 .to_selection() 9009 ); 9010} 9011 9012#[test] 9013fn no_inline_variable_action_when_spanning_multiple_items() { 9014 assert_no_code_actions!( 9015 INLINE_VARIABLE, 9016 " 9017pub fn main(x: Int, y: Int) { 9018 let a = 1 9019 let b = 2 9020 main(a, b) 9021} 9022", 9023 find_position_of("main") 9024 .nth_occurrence(2) 9025 .select_until(find_position_of(")").nth_occurrence(2)) 9026 ); 9027} 9028 9029#[test] 9030fn no_inline_variable_action_for_use_pattern() { 9031 assert_no_code_actions!( 9032 INLINE_VARIABLE, 9033 " 9034pub fn main() { 9035 let x = { 9036 use something <- todo 9037 something 9038 } 9039 9040 x 9041} 9042", 9043 find_position_of("something").to_selection() 9044 ); 9045} 9046 9047#[test] 9048fn no_inline_variable_action_for_case_pattern() { 9049 assert_no_code_actions!( 9050 INLINE_VARIABLE, 9051 " 9052pub fn main() { 9053 let x = case todo { 9054 something -> something 9055 } 9056 9057 x 9058} 9059", 9060 find_position_of("something") 9061 .nth_occurrence(2) 9062 .to_selection() 9063 ); 9064} 9065 9066// https://github.com/gleam-lang/gleam/issues/4675 9067#[test] 9068fn extract_variable_use() { 9069 assert_no_code_actions!( 9070 EXTRACT_VARIABLE, 9071 " 9072pub fn main() { 9073 #({ 9074 use <- todo 9075 todo 9076 }) 9077} 9078 ", 9079 find_position_of("use").to_selection() 9080 ); 9081} 9082 9083// https://github.com/gleam-lang/gleam/issues/4739 9084#[test] 9085fn do_not_import_internal_modules() { 9086 const IMPORT_MODULE: &str = "Import `package/internal`"; 9087 let code = " 9088pub fn main() { 9089 internal.some_internal_function() 9090} 9091"; 9092 9093 assert_no_code_actions!( 9094 IMPORT_MODULE, 9095 TestProject::for_source(code).add_package_module( 9096 "package", 9097 "package/internal", 9098 "pub fn some_internal_function() { todo }" 9099 ), 9100 find_position_of("internal").to_selection() 9101 ); 9102} 9103 9104#[test] 9105fn import_internal_module_from_same_package() { 9106 let code = " 9107pub fn main() { 9108 internal.some_internal_function() 9109} 9110"; 9111 9112 assert_code_action!( 9113 "Import `app/internal`", 9114 TestProject::for_source(code).add_package_module( 9115 "app", 9116 "app/internal", 9117 "pub fn some_internal_function() { todo }" 9118 ), 9119 find_position_of("internal").to_selection() 9120 ); 9121} 9122 9123#[test] 9124fn remove_block_1() { 9125 assert_code_action!( 9126 REMOVE_BLOCK, 9127 "pub fn main() { 9128 { 1 } 9129} 9130", 9131 find_position_of("1").to_selection() 9132 ); 9133} 9134 9135#[test] 9136fn remove_block_2() { 9137 assert_code_action!( 9138 REMOVE_BLOCK, 9139 "pub fn main() { 9140 { main() <> 2 } 9141} 9142", 9143 find_position_of("}").to_selection() 9144 ); 9145} 9146 9147#[test] 9148fn remove_block_3() { 9149 assert_code_action!( 9150 REMOVE_BLOCK, 9151 "pub fn main() { 9152 case 1 { 9153 _ -> { main() <> 2 } 9154 } 9155} 9156", 9157 find_position_of("{").nth_occurrence(3).to_selection() 9158 ); 9159} 9160 9161#[test] 9162fn remove_block_triggers_on_the_innermost_selected_block() { 9163 assert_code_action!( 9164 REMOVE_BLOCK, 9165 "pub fn main(x) { 9166 { 9167 main({ 9168 1 9169 }) 9170 } 9171} 9172", 9173 find_position_of("1").to_selection() 9174 ); 9175} 9176 9177#[test] 9178fn remove_block_does_not_unwrap_a_let_assignment() { 9179 assert_no_code_actions!( 9180 REMOVE_BLOCK, 9181 "pub fn main(x) { 9182 { 9183 let a = 1 9184 } 9185} 9186", 9187 find_position_of("let").to_selection() 9188 ); 9189} 9190 9191#[test] 9192fn remove_block_unwraps_a_single_expression_in_a_binop() { 9193 assert_code_action!( 9194 REMOVE_BLOCK, 9195 "pub fn main(x) { 9196 { main(1) } * 3 9197} 9198", 9199 find_position_of("main").nth_occurrence(2).to_selection() 9200 ); 9201} 9202 9203#[test] 9204fn remove_block_does_not_unwrap_a_binop() { 9205 assert_no_code_actions!( 9206 REMOVE_BLOCK, 9207 "pub fn main(x) { 9208 { 1 * 2 } + 3 9209} 9210", 9211 find_position_of("1").to_selection() 9212 ); 9213} 9214 9215#[test] 9216fn remove_block_does_not_unwrap_a_block_with_multiple_statements() { 9217 assert_no_code_actions!( 9218 REMOVE_BLOCK, 9219 "pub fn main(x) { 9220 { 9221 main(1) 9222 main(2) 9223 } 9224} 9225", 9226 find_position_of("1").to_selection() 9227 ); 9228} 9229 9230#[test] 9231fn remove_opaque_from_private_type() { 9232 assert_code_action!( 9233 REMOVE_OPAQUE_FROM_PRIVATE_TYPE, 9234 "opaque type Wibble { 9235 Wobble 9236} 9237", 9238 find_position_of("Wibble").to_selection() 9239 ); 9240} 9241 9242#[test] 9243fn allow_further_pattern_matching_on_let_tuple_destructuring() { 9244 assert_code_action!( 9245 PATTERN_MATCH_ON_VARIABLE, 9246 "pub fn main(x) { 9247 let #(one, other) = #(Ok(1), Error(Nil)) 9248} 9249", 9250 find_position_of("one").to_selection() 9251 ); 9252} 9253 9254#[test] 9255fn allow_further_pattern_matching_on_let_record_destructuring() { 9256 assert_code_action!( 9257 PATTERN_MATCH_ON_VARIABLE, 9258 "pub fn main(x) { 9259 let Wibble(field:) = Wibble(Ok(Nil)) 9260} 9261 9262pub type Wibble { Wibble(field: Result(Nil, String)) } 9263", 9264 find_position_of("field").to_selection() 9265 ); 9266} 9267 9268#[test] 9269fn allow_further_pattern_matching_on_asserted_result() { 9270 assert_code_action!( 9271 PATTERN_MATCH_ON_VARIABLE, 9272 "pub fn main(x) { 9273 let assert Ok(one) = Ok(Error(Nil)) 9274} 9275", 9276 find_position_of("one").to_selection() 9277 ); 9278} 9279 9280#[test] 9281fn allow_further_pattern_matching_on_asserted_list() { 9282 assert_code_action!( 9283 PATTERN_MATCH_ON_VARIABLE, 9284 "pub fn main(x) { 9285 let assert [first, ..] = [Ok(Nil), ..todo] 9286 todo 9287} 9288", 9289 find_position_of("first").to_selection() 9290 ); 9291} 9292 9293#[test] 9294fn pattern_match_on_list_variable() { 9295 assert_code_action!( 9296 PATTERN_MATCH_ON_ARGUMENT, 9297 "pub fn main(a_list: List(a)) { 9298 todo 9299}", 9300 find_position_of("a_list").to_selection() 9301 ); 9302} 9303 9304#[test] 9305fn collapse_nested_case() { 9306 assert_code_action!( 9307 COLLAPSE_NESTED_CASE, 9308 "pub fn main(x) { 9309 case x { 9310 Ok(var) -> case var { 9311 1 -> 2 9312 2 -> 4 9313 _ -> -1 9314 } 9315 _ -> todo 9316 } 9317}", 9318 find_position_of("var").to_selection() 9319 ); 9320} 9321 9322#[test] 9323fn collapse_nested_case_works_with_blocks() { 9324 assert_code_action!( 9325 COLLAPSE_NESTED_CASE, 9326 "pub fn main(x) { 9327 case x { 9328 Ok(var) -> { 9329 case var { 9330 1 -> 2 9331 2 -> 4 9332 _ -> -1 9333 } 9334 } 9335 _ -> todo 9336 } 9337}", 9338 find_position_of("var").to_selection() 9339 ); 9340} 9341 9342#[test] 9343fn collapse_nested_case_works_with_patterns_defining_multiple_variables() { 9344 assert_code_action!( 9345 COLLAPSE_NESTED_CASE, 9346 "pub fn main(x) { 9347 case x { 9348 Wibble(var, var2) -> 9349 case var { 9350 1 -> 2 9351 2 -> 4 9352 _ -> -1 9353 } 9354 9355 Wobble -> todo 9356 } 9357} 9358 9359pub type Wibble { 9360 Wibble(Int, String) 9361 Wobble 9362} 9363", 9364 find_position_of("var").to_selection() 9365 ); 9366} 9367 9368#[test] 9369fn collapse_nested_case_does_not_remove_labels() { 9370 assert_code_action!( 9371 COLLAPSE_NESTED_CASE, 9372 "pub fn main(x) { 9373 case x { 9374 Wibble(field2:, field: wibble) -> 9375 case wibble { 9376 1 -> 2 9377 2 -> 4 9378 _ -> -1 9379 } 9380 9381 Wobble -> todo 9382 } 9383} 9384 9385pub type Wibble { 9386 Wibble(field: Int, field2: String) 9387 Wobble 9388} 9389", 9390 find_position_of("field").to_selection() 9391 ); 9392} 9393 9394#[test] 9395fn collapse_nested_case_does_not_remove_labels_with_shorthand_syntax() { 9396 assert_code_action!( 9397 COLLAPSE_NESTED_CASE, 9398 "pub fn main(x) { 9399 case x { 9400 Wibble(field2:, field:) -> 9401 case field { 9402 1 -> 2 9403 2 -> 4 9404 _ -> -1 9405 } 9406 9407 Wobble -> todo 9408 } 9409} 9410 9411pub type Wibble { 9412 Wibble(field: Int, field2: String) 9413 Wobble 9414} 9415", 9416 find_position_of("field").to_selection() 9417 ); 9418} 9419 9420#[test] 9421fn collapse_nested_case_works_with_alternative_patterns() { 9422 assert_code_action!( 9423 COLLAPSE_NESTED_CASE, 9424 "pub fn main(x) { 9425 case x { 9426 [first, ..rest] -> 9427 case first { 9428 1 | 2 -> True 9429 3 | 4 | 5 -> False 9430 _ -> False 9431 } 9432 9433 [] -> True 9434 } 9435} 9436", 9437 find_position_of("first").to_selection() 9438 ); 9439} 9440 9441#[test] 9442fn collapse_nested_case_aliases_variable_if_it_is_used() { 9443 assert_code_action!( 9444 COLLAPSE_NESTED_CASE, 9445 "pub fn main(x) { 9446 case x { 9447 [first, ..rest] -> 9448 case first { 9449 1 | 2 -> first 9450 3 | 4 | 5 -> 5 9451 _ -> 0 9452 } 9453 9454 [] -> -1 9455 } 9456} 9457", 9458 find_position_of("first").to_selection() 9459 ); 9460} 9461 9462#[test] 9463fn collapse_nested_case_does_not_ignore_outer_guards() { 9464 assert_code_action!( 9465 COLLAPSE_NESTED_CASE, 9466 "pub fn main(x) { 9467 case x { 9468 [first, ..rest] if True -> 9469 case first { 9470 1 -> 1.1 9471 _ -> 0.0 *. 10.0 9472 } 9473 9474 [] -> 1.1 9475 } 9476} 9477", 9478 find_position_of("first").to_selection() 9479 ); 9480} 9481 9482#[test] 9483fn collapse_nested_case_does_not_ignore_inner_guards() { 9484 assert_code_action!( 9485 COLLAPSE_NESTED_CASE, 9486 "pub fn main(x) { 9487 case x { 9488 [first, ..rest] -> 9489 case first { 9490 1 -> 1.1 9491 _ if True -> 0.0 *. 10.0 9492 _ -> 0.0 9493 } 9494 9495 [] -> 1.1 9496 } 9497} 9498", 9499 find_position_of("first").to_selection() 9500 ); 9501} 9502 9503#[test] 9504fn collapse_nested_case_combines_inner_and_outer_guards() { 9505 assert_code_action!( 9506 COLLAPSE_NESTED_CASE, 9507 "pub fn main(x) { 9508 case x { 9509 [first, ..rest] if False -> 9510 case first { 9511 1 if False -> 1.1 9512 _ if True -> 0.0 *. 10.0 9513 _ -> 0.0 9514 } 9515 9516 [] -> 1.1 9517 } 9518} 9519", 9520 find_position_of("first").to_selection() 9521 ); 9522} 9523 9524#[test] 9525fn collapse_nested_case_combines_inner_and_outer_guards_and_adds_parentheses_when_needed() { 9526 assert_code_action!( 9527 COLLAPSE_NESTED_CASE, 9528 "pub fn main(x) { 9529 case x { 9530 [first, ..rest] if False || True -> 9531 case first { 9532 1 if False && True -> 1.1 9533 _ if True || False -> 0.0 *. 10.0 9534 _ -> 0.0 9535 } 9536 9537 [] -> 1.1 9538 } 9539} 9540", 9541 find_position_of("first").to_selection() 9542 ); 9543} 9544 9545// https://github.com/gleam-lang/gleam/issues/3786 9546#[test] 9547fn type_variables_from_other_functions_do_not_change_annotations() { 9548 assert_code_action!( 9549 ADD_ANNOTATIONS, 9550 " 9551fn wibble(a: a, b: b, c: c) -> d { todo } 9552 9553fn pair(a, b) { 9554 #(a, b) 9555} 9556", 9557 find_position_of("pair").to_selection() 9558 ); 9559} 9560 9561#[test] 9562fn type_variables_from_other_functions_do_not_change_annotations_constant() { 9563 assert_code_action!( 9564 ADD_ANNOTATION, 9565 " 9566fn wibble(a: a, b: b, c: c) -> d { todo } 9567 9568const empty = [] 9569", 9570 find_position_of("empty").to_selection() 9571 ); 9572} 9573 9574#[test] 9575fn type_variables_are_not_duplicated_when_adding_annotations() { 9576 assert_code_action!( 9577 ADD_ANNOTATIONS, 9578 " 9579fn wibble(a: a, b: b, c: c) -> d { todo } 9580 9581fn many_args(a, b, c, d: d, e: a, f, g) { 9582 todo 9583} 9584", 9585 find_position_of("many_args").to_selection() 9586 ); 9587} 9588 9589#[test] 9590fn type_variables_in_let_bindings_are_considered_when_adding_annotations() { 9591 assert_code_action!( 9592 ADD_ANNOTATIONS, 9593 " 9594fn wibble(a, b, c) { 9595 let x: a = todo 9596 fn(a: b, b: c) -> d { 9597 todo 9598 } 9599} 9600", 9601 find_position_of("wibble").to_selection() 9602 ); 9603} 9604 9605#[test] 9606fn generated_function_annotations_are_not_affected_by_other_functions() { 9607 assert_code_action!( 9608 GENERATE_FUNCTION, 9609 " 9610fn wibble(a: a, b: b, c: c) -> d { todo } 9611 9612pub fn main() { 9613 let x = todo 9614 let y = todo 9615 let #(a, b) = something(x, y) 9616 b 9617} 9618", 9619 find_position_of("something").to_selection() 9620 ); 9621} 9622 9623#[test] 9624fn generate_function_in_other_module() { 9625 let src = " 9626import wibble 9627 9628pub fn main() { 9629 wibble.wibble() 9630 wibble.wobble() 9631} 9632"; 9633 9634 assert_code_action!( 9635 GENERATE_FUNCTION, 9636 TestProject::for_source(src).add_module("wibble", "pub fn wibble() {}"), 9637 find_position_of("wobble").to_selection() 9638 ); 9639} 9640 9641#[test] 9642fn generating_function_in_other_module_uses_local_names() { 9643 let src = r#" 9644import wibble 9645 9646pub fn main() -> List(Nil) { 9647 wibble.wibble(1, #(True, "Hello")) 9648} 9649"#; 9650 9651 assert_code_action!( 9652 GENERATE_FUNCTION, 9653 TestProject::for_source(src).add_module( 9654 "wibble", 9655 "import gleam.{type Int as Number, type Bool as Boolean, type String as Text, type Nil as Nothing}" 9656 ), 9657 find_position_of("wibble(").to_selection() 9658 ); 9659} 9660 9661#[test] 9662fn generating_function_in_other_module_uses_labels() { 9663 let src = r#" 9664import wibble 9665 9666pub fn main() { 9667 wibble.wibble("Unlabelled", int: 1, bool: True) 9668} 9669"#; 9670 9671 assert_code_action!( 9672 GENERATE_FUNCTION, 9673 TestProject::for_source(src).add_module("wibble", ""), 9674 find_position_of("wibble(").to_selection() 9675 ); 9676} 9677 9678#[test] 9679fn no_code_action_to_generate_existing_function_in_other_module() { 9680 let src = r#" 9681import wibble 9682 9683pub fn main() { 9684 wibble.wibble(1, 2, 3) 9685} 9686"#; 9687 9688 assert_no_code_actions!( 9689 GENERATE_FUNCTION, 9690 TestProject::for_source(src).add_module("wibble", "pub fn wibble(a, b, c) { a + b + c }"), 9691 find_position_of("wibble(").to_selection() 9692 ); 9693} 9694 9695#[test] 9696fn do_not_generate_function_in_other_package() { 9697 let src = r#" 9698import maths 9699 9700pub fn main() { 9701 maths.add(1, 2) 9702 maths.subtract(1, 2) 9703} 9704"#; 9705 9706 assert_no_code_actions!( 9707 GENERATE_FUNCTION, 9708 TestProject::for_source(src).add_dep_module("maths", "pub fn add(a, b) { a + b }"), 9709 find_position_of("subtract").to_selection() 9710 ); 9711}