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

Configure Feed

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

gleam / language-server / src / tests / action.rs
308 kB 15063 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2023 The Gleam contributors 3 4use itertools::Itertools; 5use lsp_types::{ 6 CodeActionContext, CodeActionParams, DocumentChange, PartialResultParams, Position, Uri as Url, 7 WorkDoneProgressParams, 8}; 9 10use super::*; 11use crate::path; 12 13fn code_actions( 14 tester: &TestProject<'_>, 15 origin: Origin, 16 module: &str, 17 range_selector: RangeSelector, 18) -> Vec<lsp_types::CodeAction> { 19 let position = Position { 20 line: 0, 21 character: 0, 22 }; 23 24 tester.in_module_at(origin, module, position, |engine, params, code| { 25 let range = range_selector.find_range(&code); 26 let params = CodeActionParams { 27 text_document: params.text_document, 28 range, 29 context: CodeActionContext::default(), 30 work_done_progress_params: WorkDoneProgressParams::default(), 31 partial_result_params: PartialResultParams::default(), 32 }; 33 engine 34 .code_actions(params) 35 .result 36 .unwrap() 37 .unwrap_or_default() 38 }) 39} 40 41fn actions_with_title( 42 titles: Vec<&str>, 43 tester: &TestProject<'_>, 44 origin: Origin, 45 module: &str, 46 range_selector: RangeSelector, 47) -> Vec<lsp_types::CodeAction> { 48 code_actions(tester, origin, module, range_selector) 49 .into_iter() 50 .filter(|action| titles.contains(&action.title.as_str())) 51 .collect_vec() 52} 53 54fn apply_code_action( 55 title: &str, 56 tester: &TestProject<'_>, 57 origin: Origin, 58 module: &str, 59 range_selector: RangeSelector, 60) -> (String, String) { 61 let titles = vec![title]; 62 let actions = actions_with_title(titles, &tester, origin, module, range_selector); 63 let changes = actions 64 .last() 65 .expect("No action with the given title") 66 .edit 67 .as_ref() 68 .and_then(|edit| edit.changes.as_ref()) 69 .cloned() 70 .unwrap_or_default(); 71 let code_change = apply_code_edit(tester, changes); 72 let file_operations = format_code_action_file_operations(&actions); 73 (code_change, file_operations) 74} 75 76fn apply_code_edit( 77 tester: &TestProject<'_>, 78 changes: HashMap<Url, Vec<lsp_types::TextEdit>>, 79) -> String { 80 let mut changed_files: HashMap<Url, String> = HashMap::new(); 81 for (uri, change) in changes { 82 let code = match changed_files.get(&uri) { 83 Some(code) => code, 84 None => tester 85 .src_from_module_url(&uri) 86 .unwrap_or_else(|| panic!("no src for url {uri:?}")), 87 }; 88 let code = super::apply_code_edit(code, change); 89 let _ = changed_files.insert(uri, code); 90 } 91 92 show_code_edits(tester, changed_files) 93} 94 95fn show_code_edits(tester: &TestProject<'_>, changed_files: HashMap<Url, String>) -> String { 96 let format_code = |url: &Url, code: &String| { 97 format!( 98 "// --- Edits applied to module '{}'\n{}", 99 tester.module_name_from_url(url).expect("a module"), 100 code 101 ) 102 }; 103 104 // If the file that changed is the main one we just show its code. 105 if changed_files.len() == 1 { 106 let mut changed = changed_files.iter().peekable(); 107 let (url, code) = changed.peek().unwrap(); 108 if tester.module_name_from_url(url) == Some("app".into()) { 109 code.to_string() 110 } else { 111 format_code(url, code) 112 } 113 } else { 114 // If more than a single file changed we want to add the name of the 115 // file before each! 116 changed_files 117 .iter() 118 .sorted_by_key(|(url, _)| *url) 119 .map(|(url, code)| format_code(url, code)) 120 .join("\n") 121 } 122} 123 124fn format_code_action_file_operations(actions: &[lsp_types::CodeAction]) -> String { 125 // Display path the same on linux or windows so tests don't fail between targets 126 let normalized_path = |uri: &Url| { 127 format!( 128 "/{}", 129 path(uri) 130 .components() 131 .filter(|component| match component { 132 camino::Utf8Component::Prefix(_) | camino::Utf8Component::RootDir => false, 133 camino::Utf8Component::CurDir 134 | camino::Utf8Component::ParentDir 135 | camino::Utf8Component::Normal(_) => true, 136 }) 137 .join("/") 138 ) 139 }; 140 141 actions 142 .iter() 143 .filter_map(|action| { 144 action 145 .edit 146 .as_ref() 147 .and_then(|edit| edit.document_changes.as_ref()) 148 }) 149 .flatten() 150 .filter_map(|op| match op { 151 DocumentChange::CreateFile(create) => { 152 Some(format!("- Create {}", normalized_path(&create.uri))) 153 } 154 DocumentChange::RenameFile(rename) => Some(format!( 155 "- Rename {} to {}", 156 normalized_path(&rename.old_uri), 157 normalized_path(&rename.new_uri) 158 )), 159 DocumentChange::DeleteFile(delete) => { 160 Some(format!("- Delete {}", normalized_path(&delete.uri))) 161 } 162 DocumentChange::TextDocumentEdit(_) => None, 163 }) 164 .join("\n") 165} 166 167const REMOVE_UNUSED_IMPORTS: &str = "Remove unused imports"; 168const REMOVE_REDUNDANT_TUPLES: &str = "Remove redundant tuples"; 169const CONVERT_TO_CASE: &str = "Convert to case"; 170const USE_LABEL_SHORTHAND_SYNTAX: &str = "Use label shorthand syntax"; 171const FILL_LABELS: &str = "Fill labels"; 172const ASSIGN_UNUSED_RESULT: &str = "Assign unused Result value to `_`"; 173const ADD_MISSING_PATTERNS: &str = "Add missing patterns"; 174const ADD_ANNOTATION: &str = "Add type annotation"; 175const ADD_ANNOTATIONS: &str = "Add type annotations"; 176const ANNOTATE_TOP_LEVEL_DEFINITIONS: &str = "Annotate all top level definitions"; 177const CONVERT_FROM_USE: &str = "Convert from `use`"; 178const CONVERT_TO_USE: &str = "Convert to `use`"; 179const EXTRACT_VARIABLE: &str = "Extract variable"; 180const EXTRACT_CONSTANT: &str = "Extract constant"; 181const EXPAND_FUNCTION_CAPTURE: &str = "Expand function capture"; 182const GENERATE_DYNAMIC_DECODER: &str = "Generate dynamic decoder"; 183const GENERATE_TO_JSON_FUNCTION: &str = "Generate to-JSON function"; 184const PATTERN_MATCH_ON_ARGUMENT: &str = "Pattern match on argument"; 185const PATTERN_MATCH_ON_VARIABLE: &str = "Pattern match on variable"; 186const PATTERN_MATCH_ON_VALUE: &str = "Pattern match on value"; 187const GENERATE_FUNCTION: &str = "Generate function"; 188const CONVERT_TO_FUNCTION_CALL: &str = "Convert to function call"; 189const INLINE_VARIABLE: &str = "Inline variable"; 190const CONVERT_TO_PIPE: &str = "Convert to pipe"; 191const INTERPOLATE_STRING: &str = "Interpolate string"; 192const FILL_UNUSED_FIELDS: &str = "Fill unused fields"; 193const REMOVE_ALL_ECHOS_FROM_THIS_MODULE: &str = "Remove all `echo`s from this module"; 194const WRAP_IN_BLOCK: &str = "Wrap in block"; 195const GENERATE_VARIANT: &str = "Generate variant"; 196const REMOVE_BLOCK: &str = "Remove block"; 197const REMOVE_OPAQUE_FROM_PRIVATE_TYPE: &str = "Remove opaque from private type"; 198const COLLAPSE_NESTED_CASE: &str = "Collapse nested case"; 199const REMOVE_UNREACHABLE_CLAUSES: &str = "Remove unreachable clauses"; 200const ADD_OMITTED_LABELS: &str = "Add omitted labels"; 201const EXTRACT_FUNCTION: &str = "Extract function"; 202const MERGE_CASE_BRANCHES: &str = "Merge case branches"; 203const ADD_MISSING_TYPE_PARAMETER: &str = "Add missing type parameter"; 204const REPLACE_UNDERSCORE_WITH_TYPE: &str = "Replace `_` with type"; 205const WRAP_IN_ANONYMOUS_FUNCTION: &str = "Wrap in anonymous function"; 206const UNWRAP_ANONYMOUS_FUNCTION: &str = "Remove anonymous function wrapper"; 207const REMOVE_REDUNDANT_RECORD_UPDATE: &str = "Remove redundant record update"; 208 209macro_rules! assert_code_action { 210 ($title:expr, $code:literal, $range_selector:expr $(,)?) => { 211 let project = TestProject::for_source($code); 212 assert_code_action!($title, project, $range_selector); 213 }; 214 215 ($title:expr, $project:expr, $range_selector:expr $(,)?) => { 216 assert_code_action!( 217 $title, 218 $project, 219 Origin::Src, 220 LSP_TEST_ROOT_PACKAGE_NAME, 221 $range_selector 222 ); 223 }; 224 225 ($title:expr, $code:literal, $origin:expr, $module:expr, $range_selector:expr $(,)?) => { 226 let project = TestProject::for_source($code); 227 assert_code_action!($title, project, $origin, $module, $range_selector); 228 }; 229 230 ($title:expr, $project:expr, $origin:expr, $module:expr, $range_selector:expr $(,)?) => { 231 let project = &$project; 232 let src = project 233 .src_from_origin_and_module_name($origin, $module) 234 .unwrap(); 235 let range = $range_selector.find_range(src); 236 let (updated_src, file_operations) = 237 apply_code_action($title, project, $origin, $module, $range_selector); 238 239 let mut output = format!( 240 "----- BEFORE ACTION\n{}\n\n----- AFTER ACTION\n{}", 241 hover::show_hover(src, range, range.end), 242 updated_src 243 ); 244 245 if !file_operations.is_empty() { 246 output.push_str(&format!("\n----- FILE OPERATIONS -----\n{file_operations}")); 247 } 248 249 insta::assert_snapshot!(insta::internals::AutoName, output, src); 250 }; 251} 252 253macro_rules! assert_no_code_actions { 254 ($title:ident $(| $titles:ident)*, $code:literal, $range_selector:expr $(,)?) => { 255 let project = TestProject::for_source($code); 256 assert_no_code_actions!($title $(| $titles)*, project, $range_selector); 257 }; 258 259 ($title:ident $(| $titles:ident)*, $project:expr, $range_selector:expr $(,)?) => { 260 let all_titles = vec![$title $(, $titles)*]; 261 let expected: Vec<lsp_types::CodeAction> = vec![]; 262 let result = actions_with_title( 263 all_titles, 264 &$project, 265 Origin::Src, 266 LSP_TEST_ROOT_PACKAGE_NAME, 267 $range_selector 268 ); 269 assert_eq!(expected, result); 270 }; 271 272 ($title:literal $(| $titles:literal)*, $code:literal, $range_selector:expr $(,)?) => { 273 let project = TestProject::for_source($code); 274 assert_no_code_actions!($title $(| $titles)*, project, $range_selector); 275 }; 276 277 ($title:literal $(| $titles:literal)*, $project:expr, $range_selector:expr $(,)?) => { 278 let all_titles = vec![$title $(, $titles)*]; 279 let expected: Vec<lsp_types::CodeAction> = vec![]; 280 let result = actions_with_title( 281 all_titles, 282 &$project, 283 Origin::Src, 284 LSP_TEST_ROOT_PACKAGE_NAME, 285 $range_selector 286 ); 287 assert_eq!(expected, result); 288 }; 289} 290 291#[test] 292fn fix_truncated_segment_1() { 293 let name = "Replace with `1`"; 294 assert_code_action!( 295 name, 296 r#" 297pub fn main() { 298 <<1, 257, 259:size(1)>> 299}"#, 300 find_position_of("257").to_selection() 301 ); 302} 303 304#[test] 305fn fix_truncated_segment_2() { 306 let name = "Replace with `0`"; 307 assert_code_action!( 308 name, 309 r#" 310pub fn main() { 311 <<1, 1024:size(10)>> 312}"#, 313 find_position_of("size").to_selection() 314 ); 315} 316 317#[test] 318fn generate_variant_with_fields_in_same_module() { 319 assert_code_action!( 320 GENERATE_VARIANT, 321 r#" 322pub type Wibble { 323 Wibble 324} 325 326pub fn main() -> Wibble { 327 Wobble(1) 328}"#, 329 find_position_of("Wobble").to_selection() 330 ); 331} 332 333#[test] 334fn generate_variant_with_no_fields_in_same_module() { 335 assert_code_action!( 336 GENERATE_VARIANT, 337 r#" 338pub type Wibble { 339 Wibble 340} 341 342pub fn main() -> Wibble { 343 Wobble 344}"#, 345 find_position_of("Wobble").to_selection() 346 ); 347} 348 349#[test] 350fn generate_variant_with_labels_in_same_module() { 351 assert_code_action!( 352 GENERATE_VARIANT, 353 r#" 354pub type Wibble { 355 Wibble 356} 357 358pub fn main() -> Wibble { 359 Wobble("hello", label: 1) 360}"#, 361 find_position_of("Wobble").to_selection() 362 ); 363} 364 365#[test] 366fn generate_variant_from_pattern_with_fields() { 367 assert_code_action!( 368 GENERATE_VARIANT, 369 r#" 370pub type Wibble { 371 Wibble 372} 373 374pub fn new() { Wibble } 375 376pub fn main() -> Wibble { 377 let assert Wobble(1) = new() 378} 379 380"#, 381 find_position_of("Wobble").to_selection() 382 ); 383} 384 385#[test] 386fn generate_variant_from_pattern_with_labelled_fields() { 387 assert_code_action!( 388 GENERATE_VARIANT, 389 r#" 390pub type Wibble { 391 Wibble 392} 393 394pub fn new() { Wibble } 395 396pub fn main() -> Wibble { 397 let assert Wobble("hello", label: 1) = new() 398} 399 400"#, 401 find_position_of("Wobble").to_selection() 402 ); 403} 404 405#[test] 406fn generate_variant_from_pattern_with_no_fields() { 407 assert_code_action!( 408 GENERATE_VARIANT, 409 r#" 410pub type Wibble { 411 Wibble 412} 413 414pub fn new() { Wibble } 415 416pub fn main() -> Wibble { 417 let assert Wobble = new() 418} 419 420"#, 421 find_position_of("Wobble").to_selection() 422 ); 423} 424 425#[test] 426fn generate_unqualified_variant_in_other_module() { 427 let src = r#" 428import other 429 430pub fn main() -> other.Wibble { 431 let assert Wobble = new() 432} 433 434pub fn new() -> other.Wibble { todo } 435"#; 436 437 assert_code_action!( 438 GENERATE_VARIANT, 439 TestProject::for_source(src).add_module("other", "pub type Wibble"), 440 find_position_of("Wobble").to_selection() 441 ); 442} 443 444#[test] 445fn generate_unqualified_variant_in_other_module_adds_an_unqualified_import_if_other_variants_are_unqualified( 446) { 447 let src = r#" 448import other.{ Wibble } 449 450pub fn main() -> other.Wibble { 451 let assert Wobble = new() 452} 453 454pub fn new() -> other.Wibble { todo } 455"#; 456 457 assert_code_action!( 458 GENERATE_VARIANT, 459 TestProject::for_source(src).add_module( 460 "other", 461 "pub type Wibble { 462 Wibble 463}" 464 ), 465 find_position_of("Wobble").to_selection() 466 ); 467} 468 469#[test] 470fn generate_unqualified_variant_in_other_module_adds_qualification_if_other_variants_are_not_imported( 471) { 472 let src = r#" 473import other 474 475pub fn main() -> other.Wibble { 476 let assert Wobble = new() 477} 478 479pub fn new() -> other.Wibble { todo } 480"#; 481 482 assert_code_action!( 483 GENERATE_VARIANT, 484 TestProject::for_source(src).add_module( 485 "other", 486 "pub type Wibble { 487 Wibble 488}" 489 ), 490 find_position_of("Wobble").to_selection() 491 ); 492} 493 494#[test] 495fn generate_qualified_variant_in_other_module() { 496 let src = r#" 497import other 498 499pub fn main() -> other.Wibble { 500 let assert other.Wobble = new() 501} 502 503pub fn new() -> other.Wibble { todo } 504"#; 505 assert_code_action!( 506 GENERATE_VARIANT, 507 TestProject::for_source(src).add_module("other", "pub type Wibble"), 508 find_position_of("Wobble").to_selection() 509 ); 510} 511 512#[test] 513fn do_not_generate_variant_if_one_with_the_same_name_exists() { 514 assert_no_code_actions!( 515 GENERATE_VARIANT, 516 r#" 517pub fn main() -> Wibble { 518 let assert Wobble = new() 519} 520 521pub type Wibble { 522 Wobble(n: Int) 523} 524 525pub fn new() -> Wibble { todo } 526"#, 527 find_position_of("Wobble").to_selection() 528 ); 529} 530 531#[test] 532fn do_not_generate_variant_if_one_with_the_same_name_exists_in_other_module() { 533 let src = r#" 534import other.{type Wibble} 535 536pub fn main() -> Wibble { 537 let assert Wobble = new() 538} 539 540pub fn new() -> Wibble { todo } 541"#; 542 assert_no_code_actions!( 543 GENERATE_VARIANT, 544 TestProject::for_source(src).add_module("other", "pub type Wibble { Wobble(String) }"), 545 find_position_of("Wobble").to_selection() 546 ); 547} 548 549#[test] 550fn do_not_generate_qualified_variant_if_one_with_the_same_name_exists_in_other_module() { 551 let src = r#" 552import other.{type Wibble} 553 554pub fn main() -> Wibble { 555 let assert other.Wobble = new() 556} 557 558pub fn new() -> Wibble { todo } 559"#; 560 assert_no_code_actions!( 561 GENERATE_VARIANT, 562 TestProject::for_source(src).add_module("other", "pub type Wibble { Wobble(String) }"), 563 find_position_of("Wobble").to_selection() 564 ); 565} 566 567#[test] 568fn fill_unused_fields_with_ignored_labelled_fields() { 569 assert_code_action!( 570 FILL_UNUSED_FIELDS, 571 r#" 572pub type Wibble { Wibble(Int, label1: String, label2: Int) } 573 574pub fn main() { 575 let Wibble(_, ..) = todo 576}"#, 577 find_position_of("..").to_selection() 578 ); 579} 580 581#[test] 582fn fill_unused_fields_with_ignored_positional_fields() { 583 assert_code_action!( 584 FILL_UNUSED_FIELDS, 585 r#" 586pub type Wibble { Wibble(Int, label1: String, label2: Int) } 587 588pub fn main() { 589 let Wibble(label1:, label2:, ..) = todo 590}"#, 591 find_position_of("..").to_selection() 592 ); 593} 594 595#[test] 596fn fill_unused_fields_with_all_positional_fields() { 597 assert_code_action!( 598 FILL_UNUSED_FIELDS, 599 r#" 600pub type Wibble { Wibble(Int, String) } 601 602pub fn main() { 603 let Wibble(..) = todo 604}"#, 605 find_position_of("..").to_selection() 606 ); 607} 608 609#[test] 610fn fill_unused_fields_with_ignored_mixed_fields() { 611 assert_code_action!( 612 FILL_UNUSED_FIELDS, 613 r#" 614pub type Wibble { Wibble(Int, String, label1: String, label2: Int) } 615 616pub fn main() { 617 let Wibble(_, label2:, ..) = todo 618}"#, 619 find_position_of("..").to_selection() 620 ); 621} 622 623#[test] 624fn fill_unused_fields_with_all_ignored_fields() { 625 assert_code_action!( 626 FILL_UNUSED_FIELDS, 627 r#" 628pub type Wibble { Wibble(Int, label1: String, label2: Int) } 629 630pub fn main() { 631 let Wibble(..) = todo 632}"#, 633 find_position_of("..").to_selection() 634 ); 635} 636 637#[test] 638fn fill_unused_fields_with_ignored_fields_never_calls_a_positional_arg_as_a_labelled_one() { 639 assert_code_action!( 640 FILL_UNUSED_FIELDS, 641 r#" 642pub type Wibble { Wibble(Int, int: Int) } 643 644pub fn main() { 645 let Wibble(..) = todo 646}"#, 647 find_position_of("..").to_selection() 648 ); 649} 650 651#[test] 652fn remove_echo() { 653 assert_code_action!( 654 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 655 "pub fn main() { 656 echo 1 + 2 657}", 658 find_position_of("echo").to_selection() 659 ); 660} 661 662#[test] 663fn remove_echo_with_message() { 664 assert_code_action!( 665 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 666 r#"pub fn main() { 667 echo 1 + 2 as "message" 668}"#, 669 find_position_of("echo").to_selection() 670 ); 671} 672 673#[test] 674fn remove_echo_with_message_and_comment() { 675 assert_code_action!( 676 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 677 r#"pub fn main() { 678 echo 1 + 2 679 // Hello! 680 as "message" 681}"#, 682 find_position_of("echo").to_selection() 683 ); 684} 685 686#[test] 687fn remove_echo_with_message_and_comment_2() { 688 assert_code_action!( 689 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 690 r#"pub fn main() { 691 echo 1 + 2 as 692 // Hello! 693 "message" 694}"#, 695 find_position_of("echo").to_selection() 696 ); 697} 698 699#[test] 700fn remove_echo_with_message_and_comment_3() { 701 assert_code_action!( 702 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 703 r#"pub fn main() { 704 echo 1 + 2 as 705 // Hello! 706 "message" 707 708 Nil 709}"#, 710 find_position_of("echo").to_selection() 711 ); 712} 713 714#[test] 715fn remove_echo_selecting_expression() { 716 assert_code_action!( 717 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 718 "pub fn main() { 719 echo 1 + 2 720}", 721 find_position_of("1").select_until(find_position_of("2")) 722 ); 723} 724 725#[test] 726fn remove_echo_selecting_message() { 727 assert_code_action!( 728 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 729 r#"pub fn main() { 730 echo 1 + 2 as "message" 731}"#, 732 find_position_of("message").to_selection() 733 ); 734} 735 736#[test] 737fn remove_echo_as_function_arg() { 738 assert_code_action!( 739 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 740 "pub fn main() { 741 wibble([], echo 1 + 2) 742}", 743 find_position_of("1").to_selection() 744 ); 745} 746 747#[test] 748fn remove_echo_in_pipeline_step() { 749 assert_code_action!( 750 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 751 "pub fn main() { 752 [1, 2, 3] 753 |> echo 754 |> wibble 755}", 756 find_position_of("echo").to_selection() 757 ); 758} 759 760#[test] 761fn remove_echo_in_pipeline_step_with_message() { 762 assert_code_action!( 763 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 764 r#"pub fn main() { 765 [1, 2, 3] 766 |> echo as message 767 |> wibble 768}"#, 769 find_position_of("echo").to_selection() 770 ); 771} 772 773#[test] 774fn remove_echo_in_single_line_pipeline_step() { 775 assert_code_action!( 776 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 777 "pub fn main() { 778 [1, 2, 3] |> echo |> wibble 779}", 780 find_position_of("echo").to_selection() 781 ); 782} 783 784#[test] 785fn remove_echo_in_single_line_pipeline_step_with_message() { 786 assert_code_action!( 787 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 788 r#"pub fn main() { 789 [1, 2, 3] |> echo as "message" |> wibble 790}"#, 791 find_position_of("echo").to_selection() 792 ); 793} 794 795#[test] 796fn remove_echo_last_in_long_pipeline_step() { 797 assert_code_action!( 798 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 799 "pub fn main() { 800 [1, 2, 3] 801 |> wibble 802 |> echo 803}", 804 find_position_of("echo").to_selection() 805 ); 806} 807 808#[test] 809fn remove_echo_last_in_long_pipeline_step_with_message() { 810 assert_code_action!( 811 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 812 r#"pub fn main() { 813 [1, 2, 3] 814 |> wibble 815 |> echo as "message" 816}"#, 817 find_position_of("echo").to_selection() 818 ); 819} 820 821#[test] 822fn remove_echo_last_in_short_pipeline_step() { 823 assert_code_action!( 824 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 825 "pub fn main() { 826 [1, 2, 3] 827 |> echo 828}", 829 find_position_of("echo").to_selection() 830 ); 831} 832 833#[test] 834fn remove_echo_last_in_short_pipeline_step_with_message() { 835 assert_code_action!( 836 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 837 r#"pub fn main() { 838 [1, 2, 3] 839 |> echo as "message" 840}"#, 841 find_position_of("echo").to_selection() 842 ); 843} 844 845#[test] 846fn remove_echo_before_pipeline() { 847 assert_code_action!( 848 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 849 "pub fn main() { 850 echo [1, 2, 3] |> wibble 851}", 852 find_position_of("echo").to_selection() 853 ); 854} 855 856#[test] 857fn remove_echo_before_pipeline_selecting_step() { 858 assert_code_action!( 859 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 860 "pub fn main() { 861 echo [1, 2, 3] |> wibble 862}", 863 find_position_of("wibble").to_selection() 864 ); 865} 866 867#[test] 868fn remove_echo_removes_all_echos() { 869 assert_code_action!( 870 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 871 "pub fn main() { 872 echo wibble(echo 1, 2) 873}", 874 find_position_of("echo").nth_occurrence(2).to_selection() 875 ); 876} 877 878#[test] 879fn remove_echo_removes_all_echos_1() { 880 assert_code_action!( 881 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 882 "pub fn main() { 883 echo 1 |> echo |> echo |> wibble |> echo 884 echo wibble(echo 1, echo 2) 885 echo 1 886}", 887 find_position_of("echo").nth_occurrence(2).to_selection() 888 ); 889} 890 891#[test] 892fn remove_echo_removes_entire_echo_statement_used_with_literals() { 893 assert_code_action!( 894 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 895 "pub fn main() { 896 echo 1 897 Nil 898}", 899 find_position_of("echo").to_selection() 900 ); 901} 902 903#[test] 904fn remove_echo_removes_entire_echo_statement_used_with_literals_and_message() { 905 assert_code_action!( 906 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 907 r#"pub fn main() { 908 echo 1 as "message" 909 Nil 910}"#, 911 find_position_of("echo").to_selection() 912 ); 913} 914 915#[test] 916fn remove_echo_removes_entire_echo_statement_used_with_a_var() { 917 assert_code_action!( 918 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 919 "pub fn main() { 920 let a = 1 921 echo a 922 Nil 923}", 924 find_position_of("echo").to_selection() 925 ); 926} 927 928#[test] 929fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals() { 930 assert_code_action!( 931 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 932 r#"pub fn main() { 933 echo 1 934 echo "wibble" 935 Nil 936}"#, 937 find_position_of("echo").to_selection() 938 ); 939} 940 941#[test] 942fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_but_stops_at_comments() { 943 assert_code_action!( 944 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 945 r#"pub fn main() { 946 echo 1 947 948 // Oh no I hope I'm not deleted by the code action!! 949 Nil 950}"#, 951 find_position_of("echo").to_selection() 952 ); 953} 954 955#[test] 956fn remove_echo_removes_entire_echo_statement_used_with_literals_in_a_fn() { 957 assert_code_action!( 958 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 959 "pub fn main() { 960 fn() { 961 echo 1 962 Nil 963 } 964}", 965 find_position_of("echo").to_selection() 966 ); 967} 968 969#[test] 970fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_in_a_fn() { 971 assert_code_action!( 972 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 973 r#"pub fn main() { 974 fn() { 975 echo 1 976 echo "wibble" 977 Nil 978 } 979}"#, 980 find_position_of("echo").to_selection() 981 ); 982} 983 984#[test] 985fn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return() { 986 assert_code_action!( 987 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 988 "pub fn main() { 989 echo 1 990}", 991 find_position_of("echo").to_selection() 992 ); 993} 994 995#[test] 996fn remove_echo_with_message_removes_does_not_remove_entire_echo_statement_if_its_the_return() { 997 assert_code_action!( 998 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 999 r#"pub fn main() { 1000 echo 1 as "message" 1001}"#, 1002 find_position_of("echo").to_selection() 1003 ); 1004} 1005 1006#[test] 1007fn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return_of_a_fn() { 1008 assert_code_action!( 1009 REMOVE_ALL_ECHOS_FROM_THIS_MODULE, 1010 r#"pub fn main() { 1011 fn() { 1012 echo 1 1013 } 1014}"#, 1015 find_position_of("echo").to_selection() 1016 ); 1017} 1018 1019#[test] 1020fn split_string() { 1021 assert_code_action!( 1022 INTERPOLATE_STRING, 1023 r#"pub fn main() { 1024 "wibble wobble woo" 1025}"#, 1026 find_position_of("wobble").to_selection() 1027 ); 1028} 1029 1030#[test] 1031fn no_split_string_right_at_the_start() { 1032 assert_no_code_actions!( 1033 INTERPOLATE_STRING, 1034 r#"pub fn main() { 1035 "wibble wobble woo" 1036}"#, 1037 find_position_of("wibble").to_selection() 1038 ); 1039} 1040 1041#[test] 1042fn no_split_string_right_at_the_end() { 1043 assert_no_code_actions!( 1044 INTERPOLATE_STRING, 1045 r#"pub fn main() { 1046 "wibble wobble woo" 1047}"#, 1048 find_position_of("\"").nth_occurrence(2).to_selection() 1049 ); 1050} 1051 1052#[test] 1053fn no_split_string_before_the_start() { 1054 assert_no_code_actions!( 1055 INTERPOLATE_STRING, 1056 r#"pub fn main() { 1057 "wibble wobble woo" 1058}"#, 1059 find_position_of("\"").to_selection() 1060 ); 1061} 1062 1063#[test] 1064fn no_split_string_after_the_end() { 1065 assert_no_code_actions!( 1066 INTERPOLATE_STRING, 1067 r#"pub fn main() { 1068 "wibble wobble woo"//we need this comment so we can put the cursor _after_ the closing quote 1069}"#, 1070 find_position_of("\"/").under_last_char().to_selection() 1071 ); 1072} 1073 1074#[test] 1075fn interpolate_string_inside_string() { 1076 assert_code_action!( 1077 INTERPOLATE_STRING, 1078 r#"pub fn main() { 1079 "wibble wobble woo" 1080}"#, 1081 find_position_of("wobble").select_until(find_position_of("wobble ").under_last_char()), 1082 ); 1083} 1084 1085#[test] 1086fn splitting_string_as_first_pipeline_step_inserts_brackets() { 1087 assert_code_action!( 1088 INTERPOLATE_STRING, 1089 r#"pub fn main() { 1090 "wibble wobble" |> io.println 1091}"#, 1092 find_position_of(" wobble").to_selection(), 1093 ); 1094} 1095 1096#[test] 1097fn interpolating_string_as_first_pipeline_step_inserts_brackets() { 1098 assert_code_action!( 1099 INTERPOLATE_STRING, 1100 r#"pub fn main() { 1101 "wibble wobble woo" |> io.println 1102}"#, 1103 find_position_of("wobble ").select_until(find_position_of("wobble ").under_last_char()), 1104 ); 1105} 1106 1107#[test] 1108fn test_remove_unused_simple() { 1109 let src = " 1110// test 1111import // comment 1112list as lispy 1113import result 1114import option 1115 1116pub fn main() { 1117 result.is_ok 1118} 1119"; 1120 1121 assert_code_action!( 1122 REMOVE_UNUSED_IMPORTS, 1123 TestProject::for_source(src) 1124 .add_hex_module("list", "") 1125 .add_hex_module("result", "") 1126 .add_hex_module("option", ""), 1127 find_position_of("// test").select_until(find_position_of("option")), 1128 ); 1129} 1130 1131#[test] 1132fn test_remove_unused_start_of_file() { 1133 let src = "import option 1134import result 1135 1136pub fn main() { 1137 result.is_ok 1138} 1139"; 1140 assert_code_action!( 1141 REMOVE_UNUSED_IMPORTS, 1142 TestProject::for_source(src) 1143 .add_hex_module("option", "") 1144 .add_hex_module("result", ""), 1145 find_position_of("import").select_until(find_position_of("pub")), 1146 ); 1147} 1148 1149#[test] 1150fn test_remove_unused_alias() { 1151 let src = " 1152// test 1153import result.{is_ok} as res 1154import option 1155 1156pub fn main() { 1157 is_ok 1158} 1159"; 1160 assert_code_action!( 1161 REMOVE_UNUSED_IMPORTS, 1162 TestProject::for_source(src) 1163 .add_hex_module("result", "pub fn is_ok() {}") 1164 .add_hex_module("option", ""), 1165 find_position_of("// test").select_until(find_position_of("pub")), 1166 ); 1167} 1168 1169#[test] 1170fn test_remove_unused_value() { 1171 let src = " 1172// test 1173import result.{is_ok} 1174import option 1175 1176pub fn main() { 1177 result.is_ok 1178} 1179"; 1180 assert_code_action!( 1181 REMOVE_UNUSED_IMPORTS, 1182 TestProject::for_source(src) 1183 .add_hex_module("result", "pub fn is_ok() {}") 1184 .add_hex_module("option", ""), 1185 find_position_of("// test").select_until(find_position_of("pub")), 1186 ); 1187} 1188 1189#[test] 1190fn test_remove_aliased_unused_value() { 1191 let src = " 1192// test 1193import result.{is_ok as ok} 1194import option 1195 1196pub fn main() { 1197 result.is_ok 1198} 1199"; 1200 assert_code_action!( 1201 REMOVE_UNUSED_IMPORTS, 1202 TestProject::for_source(src) 1203 .add_hex_module("result", "pub fn is_ok() {}") 1204 .add_hex_module("option", ""), 1205 find_position_of("// test").select_until(find_position_of("pub")), 1206 ); 1207} 1208 1209#[test] 1210fn test_remove_multiple_unused_values() { 1211 let src = " 1212// test 1213import result.{type Unused, used, unused, unused_again, type Used, used_again} 1214 1215pub fn main(x: Used) { 1216 #(used, used_again) 1217} 1218"; 1219 assert_code_action!( 1220 REMOVE_UNUSED_IMPORTS, 1221 TestProject::for_source(src).add_hex_module( 1222 "result", 1223 " 1224pub const used = 1 1225pub const unused = 2 1226pub const unused_again = 3 1227pub const used_again = 4 1228pub type Unused 1229pub type Used 1230" 1231 ), 1232 find_position_of("// test").select_until(find_position_of("pub")), 1233 ); 1234} 1235 1236#[test] 1237fn test_remove_multiple_unused_values_2() { 1238 let src = " 1239// test 1240import result.{type Unused, used, unused, type Used, unused_again} 1241 1242pub fn main(x: Used) { 1243 used 1244} 1245"; 1246 assert_code_action!( 1247 REMOVE_UNUSED_IMPORTS, 1248 TestProject::for_source(src).add_hex_module( 1249 "result", 1250 " 1251pub const used = 1 1252pub const unused = 2 1253pub const unused_again = 3 1254pub type Unused 1255pub type Used 1256" 1257 ), 1258 find_position_of("// test").select_until(find_position_of("pub")), 1259 ); 1260} 1261 1262#[test] 1263fn test_remove_entire_unused_import() { 1264 let src = " 1265// test 1266import result.{unused, unused_again} 1267 1268pub fn main() { 1269 todo 1270} 1271"; 1272 assert_code_action!( 1273 REMOVE_UNUSED_IMPORTS, 1274 TestProject::for_source(src).add_hex_module( 1275 "result", 1276 " 1277pub const used = 1 1278pub const unused = 2 1279pub const unused_again = 3 1280pub type Unused 1281pub type Used 1282" 1283 ), 1284 find_position_of("// test").select_until(find_position_of("pub")), 1285 ); 1286} 1287 1288#[test] 1289fn test_remove_redundant_tuple_in_case_subject_simple() { 1290 assert_code_action!( 1291 REMOVE_REDUNDANT_TUPLES, 1292 "pub fn main() { 1293 case #(1) { #(a) -> 0 } 1294 case #(1, 2) { #(a, b) -> 0 } 1295}", 1296 find_position_of("case").select_until(find_position_of("#(1, 2)").under_last_char()) 1297 ); 1298} 1299 1300#[test] 1301fn test_remove_redundant_tuple_with_catch_all_pattern() { 1302 assert_code_action!( 1303 REMOVE_REDUNDANT_TUPLES, 1304 "pub fn main() { 1305 case #(1, 2) { 1306 #(1, 2) -> 0 1307 _ -> 1 1308 } 1309}", 1310 find_position_of("case").select_until(find_position_of("#(1, 2)").under_last_char()) 1311 ); 1312} 1313 1314#[test] 1315fn test_remove_multiple_redundant_tuple_with_catch_all_pattern() { 1316 assert_code_action!( 1317 REMOVE_REDUNDANT_TUPLES, 1318 "pub fn main() { 1319 case #(1, 2), #(3, 4) { 1320 #(2, 2), #(2, 2) -> 0 1321 #(1, 2), _ -> 0 1322 _, #(1, 2) -> 0 1323 _, _ -> 1 1324 } 1325}", 1326 find_position_of("case").select_until(find_position_of("#(3, 4)")) 1327 ); 1328} 1329 1330#[test] 1331fn test_remove_redundant_tuple_in_case_subject_nested() { 1332 assert_code_action!( 1333 REMOVE_REDUNDANT_TUPLES, 1334 "pub fn main() { 1335 case #(case #(0) { #(a) -> 0 }) { #(b) -> 0 } 1336}", 1337 find_position_of("case").select_until(find_position_of("#(b)")) 1338 ); 1339} 1340 1341#[test] 1342fn test_remove_redundant_tuple_in_case_retain_extras() { 1343 assert_code_action!( 1344 REMOVE_REDUNDANT_TUPLES, 1345 " 1346pub fn main() { 1347 case 1348 #( 1349 // first comment 1350 1, 1351 // second comment 1352 2, 1353 3 // third comment before comma 1354 1355 , 1356 1357 // fourth comment after comma 1358 1359 ) 1360 { 1361 #( 1362 // first comment 1363 a, 1364 // second comment 1365 b, 1366 c // third comment before comma 1367 1368 , 1369 1370 // fourth comment after comma 1371 1372 ) -> 0 1373 } 1374} 1375", 1376 find_position_of("#").select_until(find_position_of("// first")) 1377 ); 1378} 1379 1380#[test] 1381fn test_remove_redundant_tuple_in_case_subject_ignore_empty_tuple() { 1382 assert_no_code_actions!( 1383 REMOVE_REDUNDANT_TUPLES, 1384 " 1385pub fn main() { 1386 case #() { #() -> 0 } 1387} 1388", 1389 find_position_of("case").select_until(find_position_of("0")) 1390 ); 1391} 1392 1393#[test] 1394fn test_remove_redundant_tuple_in_case_subject_only_safe_remove() { 1395 assert_code_action!( 1396 REMOVE_REDUNDANT_TUPLES, 1397 " 1398pub fn main() { 1399 case #(0), #(1) { 1400 #(1), #(b) -> 0 1401 a, #(0) -> 1 // The first of this clause is not a tuple 1402 #(a), #(b) -> 2 1403 } 1404} 1405", 1406 find_position_of("#(0)").select_until(find_position_of("#(1)")) 1407 ); 1408} 1409 1410#[test] 1411fn rename_invalid_const() { 1412 assert_code_action!( 1413 "Rename to my_invalid_constant", 1414 "const myInvalid_Constant = 42", 1415 find_position_of("_Constant").to_selection(), 1416 ); 1417} 1418 1419#[test] 1420fn rename_invalid_parameter() { 1421 assert_code_action!( 1422 "Rename to num_a", 1423 "fn add(numA: Int, num_b: Int) { numA + num_b }", 1424 find_position_of("numA").to_selection() 1425 ); 1426} 1427 1428#[test] 1429fn rename_invalid_parameter_name2() { 1430 assert_code_action!( 1431 "Rename to param_name", 1432 "fn pass(label paramName: Bool) { paramName }", 1433 find_position_of("paramName").to_selection() 1434 ); 1435} 1436 1437#[test] 1438fn rename_invalid_parameter_name3() { 1439 assert_code_action!( 1440 "Rename to num_a", 1441 "pub fn main() { 1442 let add = fn(numA: Int, num_b: Int) { numA + num_b } 1443}", 1444 find_position_of("let add").select_until(find_position_of("num_b")) 1445 ); 1446} 1447 1448#[test] 1449fn rename_invalid_parameter_discard() { 1450 assert_code_action!( 1451 "Rename to _ignore_me", 1452 "fn ignore(_ignoreMe: Bool) { 98 }", 1453 find_position_of("ignore").select_until(find_position_of("98")) 1454 ); 1455} 1456 1457#[test] 1458fn rename_invalid_parameter_discard_name2() { 1459 assert_code_action!( 1460 "Rename to _ignore_me", 1461 "fn ignore(labelled_discard _ignoreMe: Bool) { 98 }", 1462 find_position_of("ignore").select_until(find_position_of("98")) 1463 ); 1464} 1465 1466#[test] 1467fn rename_invalid_parameter_discard_name3() { 1468 assert_code_action!( 1469 "Rename to _ignore_me", 1470 "pub fn main() { 1471 let ignore = fn(_ignoreMe: Bool) { 98 } 1472}", 1473 find_position_of("ignore").select_until(find_position_of("98")) 1474 ); 1475} 1476 1477#[test] 1478fn rename_invalid_parameter_label() { 1479 assert_code_action!( 1480 "Rename to this_is_a_label", 1481 "fn func(thisIsALabel param: Int) { param }", 1482 find_position_of("thisIs").select_until(find_position_of("Int")) 1483 ); 1484} 1485 1486#[test] 1487fn rename_invalid_parameter_label2() { 1488 assert_code_action!( 1489 "Rename to this_is_a_label", 1490 "fn ignore(thisIsALabel _ignore: Int) { 25 }", 1491 find_position_of("thisIs").under_char('i').to_selection() 1492 ); 1493} 1494 1495#[test] 1496fn rename_invalid_constructor() { 1497 assert_code_action!( 1498 "Rename to TheConstructor", 1499 "type MyType { The_Constructor(Int) }", 1500 find_position_of("The_").under_char('h').to_selection(), 1501 ); 1502} 1503 1504#[test] 1505fn rename_invalid_constructor_arg() { 1506 assert_code_action!( 1507 "Rename to inner_int", 1508 "type IntWrapper { IntWrapper(innerInt: Int) }", 1509 find_position_of("IntWrapper") 1510 .nth_occurrence(2) 1511 .select_until(find_position_of(": Int")) 1512 ); 1513} 1514 1515#[test] 1516fn rename_invalid_custom_type() { 1517 assert_code_action!( 1518 "Rename to BoxedValue", 1519 "type Boxed_value { Box(Int) }", 1520 find_position_of("Box").select_until(find_position_of("_value")) 1521 ); 1522} 1523 1524#[test] 1525fn rename_invalid_type_alias() { 1526 assert_code_action!( 1527 "Rename to FancyBool", 1528 "type Fancy_Bool = Bool", 1529 find_position_of("Fancy") 1530 .under_char('a') 1531 .select_until(find_position_of("=")) 1532 ); 1533} 1534 1535#[test] 1536fn rename_invalid_function() { 1537 assert_code_action!( 1538 "Rename to do_stuff", 1539 "fn doStuff() {}", 1540 find_position_of("fn").select_until(find_position_of("{}")) 1541 ); 1542} 1543 1544#[test] 1545fn rename_invalid_variable() { 1546 assert_code_action!( 1547 "Rename to the_answer", 1548 "pub fn main() { 1549 let theAnswer = 42 1550}", 1551 find_position_of("theAnswer").select_until(find_position_of("Answer")) 1552 ); 1553} 1554 1555#[test] 1556fn rename_invalid_variable_discard() { 1557 assert_code_action!( 1558 "Rename to _boring_number", 1559 "pub fn main() { 1560 let _boringNumber = 72 1561}", 1562 find_position_of("let").select_until(find_position_of("72")) 1563 ); 1564} 1565 1566#[test] 1567fn rename_invalid_use() { 1568 assert_code_action!( 1569 "Rename to use_var", 1570 "fn use_test(f) { f(Nil) } 1571pub fn main() {use useVar <- use_test()}", 1572 find_position_of("use") 1573 .nth_occurrence(2) 1574 .select_until(find_position_of("use_test()")) 1575 ); 1576} 1577 1578#[test] 1579fn rename_invalid_use_discard() { 1580 assert_code_action!( 1581 "Rename to _discard_var", 1582 "fn use_test(f) { f(Nil) } 1583pub fn main() {use _discardVar <- use_test()}", 1584 find_position_of("_discardVar") 1585 .under_last_char() 1586 .to_selection() 1587 ); 1588} 1589 1590#[test] 1591fn rename_invalid_pattern_assignment() { 1592 assert_code_action!( 1593 "Rename to the_answer", 1594 "pub fn main() { 1595 let assert 42 as theAnswer = 42 1596}", 1597 find_position_of("let").select_until(find_position_of("= 42")) 1598 ); 1599} 1600 1601#[test] 1602fn rename_invalid_list_pattern() { 1603 assert_code_action!( 1604 "Rename to the_element", 1605 "pub fn main() { 1606 let assert [theElement] = [9.4] 1607}", 1608 find_position_of("assert").select_until(find_position_of("9.4")) 1609 ); 1610} 1611 1612#[test] 1613fn rename_invalid_list_pattern_discard() { 1614 assert_code_action!( 1615 "Rename to _elem_one", 1616 "pub fn main() { 1617 let assert [_elemOne] = [False] 1618}", 1619 find_position_of("[_elemOne]") 1620 .under_char('O') 1621 .to_selection() 1622 ); 1623} 1624 1625#[test] 1626fn rename_invalid_constructor_pattern() { 1627 assert_code_action!( 1628 "Rename to inner_value", 1629 "pub type Box { Box(Int) } 1630pub fn main() { 1631 let Box(innerValue) = Box(203) 1632}", 1633 find_position_of("innerValue").to_selection() 1634 ); 1635} 1636 1637#[test] 1638fn rename_invalid_constructor_pattern_discard() { 1639 assert_code_action!( 1640 "Rename to _ignored_inner", 1641 "pub type Box { Box(Int) } 1642pub fn main() { 1643 let Box(_ignoredInner) = Box(203) 1644}", 1645 find_position_of("_").select_until(find_position_of("203")) 1646 ); 1647} 1648 1649#[test] 1650fn rename_invalid_tuple_pattern() { 1651 assert_code_action!( 1652 "Rename to second_value", 1653 "pub fn main() { 1654 let #(a, secondValue) = #(1, 2) 1655}", 1656 find_position_of("secondValue") 1657 .select_until(find_position_of("secondValue").under_char('n')) 1658 ); 1659} 1660 1661#[test] 1662fn rename_invalid_tuple_pattern_discard() { 1663 assert_code_action!( 1664 "Rename to _second_value", 1665 "pub fn main() { 1666 let #(a, _secondValue) = #(1, 2) 1667}", 1668 find_position_of("_secondValue") 1669 .under_char('_') 1670 .select_until(find_position_of("#(1, 2)")) 1671 ); 1672} 1673 1674#[test] 1675fn rename_invalid_bit_array_pattern() { 1676 assert_code_action!( 1677 "Rename to bit_value", 1678 "pub fn main() { 1679 let assert <<bitValue>> = <<73>> 1680}", 1681 find_position_of("<<").select_until(find_position_of(">>")) 1682 ); 1683} 1684 1685#[test] 1686fn rename_invalid_bit_array_pattern_discard() { 1687 assert_code_action!( 1688 "Rename to _i_dont_care", 1689 "pub fn main() { 1690 let assert <<_iDontCare>> = <<97>> 1691}", 1692 find_position_of("<<").select_until(find_position_of("Care")) 1693 ); 1694} 1695 1696#[test] 1697fn rename_invalid_string_prefix_pattern() { 1698 assert_code_action!( 1699 "Rename to cool_suffix", 1700 r#"pub fn main() { 1701 let assert "prefix" <> coolSuffix = "prefix-suffix" 1702}"#, 1703 find_position_of("<>").select_until(find_position_of("-suffix")) 1704 ); 1705} 1706 1707#[test] 1708fn rename_invalid_string_prefix_pattern_discard() { 1709 assert_code_action!( 1710 "Rename to _boring_suffix", 1711 r#"pub fn main() { 1712 let assert "prefix" <> _boringSuffix = "prefix-suffix" 1713}"#, 1714 find_position_of("<>").select_until(find_position_of("Suffix")) 1715 ); 1716} 1717 1718#[test] 1719fn rename_invalid_string_prefix_pattern_alias() { 1720 assert_code_action!( 1721 "Rename to the_prefix", 1722 r#"pub fn main() { 1723 let assert "prefix" as thePrefix <> _suffix = "prefix-suffix" 1724}"#, 1725 find_position_of("prefix").select_until(find_position_of("-suffix")) 1726 ); 1727} 1728 1729#[test] 1730fn rename_invalid_case_variable() { 1731 assert_code_action!( 1732 "Rename to twenty_one", 1733 "pub fn main() { 1734 case 21 { twentyOne -> {Nil} } 1735}", 1736 find_position_of("case").select_until(find_position_of("Nil")) 1737 ); 1738} 1739 1740#[test] 1741fn rename_invalid_case_variable_discard() { 1742 assert_code_action!( 1743 "Rename to _twenty_one", 1744 "pub fn main() { 1745 case 21 { _twentyOne -> {Nil} } 1746}", 1747 find_position_of("21").select_until(find_position_of("->")) 1748 ); 1749} 1750 1751#[test] 1752fn rename_invalid_type_parameter_name() { 1753 assert_code_action!( 1754 "Rename to inner_type", 1755 "type Wrapper(innerType) {}", 1756 find_position_of("innerType").select_until(find_position_of(")")) 1757 ); 1758} 1759 1760#[test] 1761fn rename_invalid_type_alias_parameter_name() { 1762 assert_code_action!( 1763 "Rename to phantom_type", 1764 "type Phantom(phantomType) = Int", 1765 find_position_of("phantomType").select_until(find_position_of(")")) 1766 ); 1767} 1768 1769#[test] 1770fn rename_invalid_function_type_parameter_name() { 1771 assert_code_action!( 1772 "Rename to some_type", 1773 "fn identity(value: someType) { value }", 1774 find_position_of("someType").select_until(find_position_of(")")) 1775 ); 1776} 1777 1778#[test] 1779fn test_convert_assert_result_to_case() { 1780 assert_code_action!( 1781 CONVERT_TO_CASE, 1782 "pub fn main() { 1783 let assert Ok(value) = Ok(1) 1784}", 1785 find_position_of("assert").select_until(find_position_of("assert").under_char('r')), 1786 ); 1787} 1788 1789#[test] 1790fn test_convert_let_assert_to_case_indented() { 1791 assert_code_action!( 1792 CONVERT_TO_CASE, 1793 "pub fn main() { 1794 { 1795 let assert Ok(value) = Ok(1) 1796 } 1797}", 1798 find_position_of("Ok").to_selection() 1799 ); 1800} 1801 1802#[test] 1803fn test_convert_let_assert_to_case_multi_variables() { 1804 assert_code_action!( 1805 CONVERT_TO_CASE, 1806 "pub fn main() { 1807 let assert [var1, var2, _var3, var4] = [1, 2, 3, 4] 1808}", 1809 find_position_of("var1").select_until(find_position_of("_var").under_last_char()) 1810 ); 1811} 1812 1813#[test] 1814fn test_convert_let_assert_to_case_discard() { 1815 assert_code_action!( 1816 CONVERT_TO_CASE, 1817 "pub fn main() { 1818 let assert [_elem] = [6] 1819}", 1820 find_position_of("assert").select_until(find_position_of("[6]").under_last_char()), 1821 ); 1822} 1823 1824#[test] 1825fn test_convert_let_assert_to_case_no_variables() { 1826 assert_code_action!( 1827 CONVERT_TO_CASE, 1828 "pub fn main() { 1829 let assert [] = [] 1830}", 1831 find_position_of("[]").to_selection(), 1832 ); 1833} 1834 1835#[test] 1836fn test_convert_let_assert_alias_to_case() { 1837 assert_code_action!( 1838 CONVERT_TO_CASE, 1839 "pub fn main() { 1840 let assert 10 as ten = 10 1841}", 1842 find_position_of("as").select_until(find_position_of("ten")), 1843 ); 1844} 1845 1846#[test] 1847fn test_convert_let_assert_tuple_to_case() { 1848 assert_code_action!( 1849 CONVERT_TO_CASE, 1850 "pub fn main() { 1851 let assert #(first, 10, third) = #(5, 10, 15) 1852} 1853", 1854 find_position_of("let").to_selection(), 1855 ); 1856} 1857 1858#[test] 1859fn test_convert_let_assert_bit_array_to_case() { 1860 assert_code_action!( 1861 CONVERT_TO_CASE, 1862 "pub fn main() { 1863 let assert <<bits1, bits2>> = <<73, 98>> 1864}", 1865 find_position_of("bits").select_until(find_position_of("2")), 1866 ); 1867} 1868 1869#[test] 1870fn test_convert_let_assert_string_prefix_to_case() { 1871 assert_code_action!( 1872 CONVERT_TO_CASE, 1873 r#"pub fn main() { 1874 let assert "_" <> thing = "_Hello" 1875}"#, 1876 find_position_of("_").to_selection() 1877 ); 1878} 1879 1880#[test] 1881fn test_convert_let_assert_string_prefix_pattern_alias_to_case() { 1882 assert_code_action!( 1883 CONVERT_TO_CASE, 1884 r#"pub fn main() { 1885 let assert "123" as one_two_three <> rest = "123456" 1886}"#, 1887 find_position_of("123").select_until(find_position_of("123456")), 1888 ); 1889} 1890 1891#[test] 1892fn test_convert_inner_let_assert_to_case() { 1893 assert_code_action!( 1894 CONVERT_TO_CASE, 1895 r#"pub fn main() { 1896 let assert [wibble] = { 1897 let assert Ok(wobble) = { 1898 Ok(1) 1899 } 1900 [wobble] 1901 } 1902}"#, 1903 find_position_of("wobble").under_char('l').to_selection() 1904 ); 1905} 1906 1907#[test] 1908fn test_convert_outer_let_assert_to_case() { 1909 assert_code_action!( 1910 CONVERT_TO_CASE, 1911 r#"pub fn main() { 1912 let assert [wibble] = { 1913 let assert Ok(wobble) = { 1914 Ok(1) 1915 } 1916 [wobble] 1917 } 1918}"#, 1919 find_position_of("wibble") 1920 .under_char('i') 1921 .select_until(find_position_of("= {")), 1922 ); 1923} 1924 1925#[test] 1926fn test_convert_let_assert_with_message_to_case() { 1927 assert_code_action!( 1928 CONVERT_TO_CASE, 1929 r#" 1930pub fn expect(value, message) { 1931 let assert Ok(inner) = value as message 1932 inner 1933} 1934"#, 1935 find_position_of("assert").select_until(find_position_of("=")), 1936 ); 1937} 1938 1939#[test] 1940fn test_convert_assert_custom_type_with_label_shorthands_to_case() { 1941 assert_code_action!( 1942 CONVERT_TO_CASE, 1943 " 1944pub type Wibble { Wibble(arg: Int, arg2: Float) } 1945pub fn main() { 1946 let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0) 1947} 1948", 1949 find_position_of("arg2:,").select_until(find_position_of("1.0")), 1950 ); 1951} 1952 1953#[test] 1954fn test_convert_assert_does_not_appear_if_the_entire_module_is_selected() { 1955 assert_no_code_actions!( 1956 CONVERT_TO_CASE, 1957 " 1958pub type Wibble { Wibble(arg: Int, arg2: Float) } 1959pub fn main() { 1960 let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0) 1961 let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0) 1962} 1963// end 1964", 1965 find_position_of("pub").select_until(find_position_of("// end")), 1966 ); 1967} 1968 1969#[test] 1970fn label_shorthand_action_works_on_labelled_call_args() { 1971 assert_code_action!( 1972 USE_LABEL_SHORTHAND_SYNTAX, 1973 r#" 1974pub fn main() { 1975 let arg1 = 1 1976 let arg2 = 2 1977 wibble(arg2: arg2, arg1: arg1) 1978} 1979 1980pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 1981"#, 1982 find_position_of("wibble") 1983 .under_char('i') 1984 .select_until(find_position_of("arg1: arg1")), 1985 ); 1986} 1987 1988#[test] 1989fn label_shorthand_action_works_on_labelled_constructor_call_args() { 1990 assert_code_action!( 1991 USE_LABEL_SHORTHAND_SYNTAX, 1992 r#" 1993pub fn main() { 1994 let arg1 = 1 1995 let arg2 = 2 1996 Wibble(arg2: arg2, arg1: arg1) 1997} 1998 1999pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2000"#, 2001 find_position_of("Wibble").select_until(find_position_of("arg1: arg1").under_char(':')), 2002 ); 2003} 2004 2005#[test] 2006fn label_shorthand_action_only_applies_to_selected_args() { 2007 assert_code_action!( 2008 USE_LABEL_SHORTHAND_SYNTAX, 2009 r#" 2010pub fn main() { 2011 let arg1 = 1 2012 let arg2 = 2 2013 Wibble(arg2: arg2, arg1: arg1) 2014} 2015 2016pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2017"#, 2018 find_position_of("Wibble").select_until(find_position_of("arg2: arg2").under_char(':')), 2019 ); 2020} 2021 2022#[test] 2023fn label_shorthand_action_works_on_labelled_update_call_args() { 2024 assert_code_action!( 2025 USE_LABEL_SHORTHAND_SYNTAX, 2026 r#" 2027pub fn main() { 2028 let arg1 = 1 2029 Wibble(..todo, arg1: arg1) 2030} 2031 2032pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2033"#, 2034 find_position_of("..todo").select_until(find_position_of("arg1: arg1").under_last_char()), 2035 ); 2036} 2037 2038#[test] 2039fn label_shorthand_action_works_on_labelled_pattern_call_args() { 2040 assert_code_action!( 2041 USE_LABEL_SHORTHAND_SYNTAX, 2042 r#" 2043pub fn main() { 2044 let Wibble(arg1: arg1, arg2: arg2) = todo 2045 arg1 + arg2 2046} 2047 2048pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2049"#, 2050 find_position_of("let").select_until(find_position_of("todo").under_last_char()), 2051 ); 2052} 2053 2054#[test] 2055fn label_shorthand_action_doesnt_come_up_for_arguments_with_different_label() { 2056 assert_no_code_actions!( 2057 USE_LABEL_SHORTHAND_SYNTAX, 2058 r#" 2059pub fn main() { 2060 let Wibble(arg1: arg_1, arg2: arg_2) = todo 2061 arg_1 + arg_2 2062} 2063 2064pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2065"#, 2066 find_position_of("arg_1").select_until(find_position_of("arg_2").under_last_char()) 2067 ); 2068} 2069 2070#[test] 2071fn fill_in_labelled_args_with_some_arguments_already_supplied() { 2072 assert_code_action!( 2073 FILL_LABELS, 2074 r#" 2075pub fn main() { 2076 wibble(1,) 2077} 2078 2079pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2080 "#, 2081 find_position_of("wibble(").under_char('b').to_selection(), 2082 ); 2083} 2084 2085#[test] 2086fn fill_in_labelled_args_with_some_constant_arguments_already_supplied() { 2087 assert_code_action!( 2088 FILL_LABELS, 2089 r#" 2090pub const wibble = Wibble(1,) 2091pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2092 "#, 2093 find_position_of("Wibble(").under_char('b').to_selection(), 2094 ); 2095} 2096 2097#[test] 2098fn fill_in_labelled_args_with_some_arguments_already_supplied_2() { 2099 assert_code_action!( 2100 FILL_LABELS, 2101 r#" 2102pub fn main() { 2103 wibble(arg2: 1) 2104} 2105 2106pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2107 "#, 2108 find_position_of("wibble(").to_selection(), 2109 ); 2110} 2111 2112#[test] 2113fn fill_in_labelled_args_with_some_constant_arguments_already_supplied_2() { 2114 assert_code_action!( 2115 FILL_LABELS, 2116 r#" 2117pub const wibble = Wibble(arg2: 1) 2118pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2119 "#, 2120 find_position_of("Wibble(").to_selection(), 2121 ); 2122} 2123 2124#[test] 2125fn fill_in_labelled_args_with_some_arguments_already_supplied_3() { 2126 assert_code_action!( 2127 FILL_LABELS, 2128 r#" 2129pub fn main() { 2130 wibble(1, arg3: 2) 2131} 2132 2133pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil } 2134 "#, 2135 find_position_of("wibble(").to_selection(), 2136 ); 2137} 2138 2139#[test] 2140fn fill_in_labelled_args_with_some_constant_arguments_already_supplied_3() { 2141 assert_code_action!( 2142 FILL_LABELS, 2143 r#" 2144pub const wibble = Wibble(1, arg3: 2) 2145pub type Wibble { Wibble(arg1: Int, arg2: Int, arg3: Int) } 2146 "#, 2147 find_position_of("Wibble(").to_selection(), 2148 ); 2149} 2150 2151#[test] 2152fn fill_in_labelled_args_works_with_regular_function() { 2153 assert_code_action!( 2154 FILL_LABELS, 2155 r#" 2156pub fn main() { 2157 wibble() 2158} 2159 2160pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2161 "#, 2162 find_position_of("wibble(").to_selection(), 2163 ); 2164} 2165 2166#[test] 2167fn fill_in_labelled_args_works_with_record_constructor() { 2168 assert_code_action!( 2169 FILL_LABELS, 2170 r#" 2171pub fn main() { 2172 Wibble() 2173} 2174 2175pub type Wibble { Wibble(arg1: Int, arg2: String) } 2176 "#, 2177 find_position_of("Wibble").select_until(find_position_of("Wibble()").under_last_char()), 2178 ); 2179} 2180 2181#[test] 2182fn fill_in_labelled_args_works_with_constant_record_constructor() { 2183 assert_code_action!( 2184 FILL_LABELS, 2185 r#" 2186pub const wibble = Wibble() 2187pub type Wibble { Wibble(arg1: Int, arg2: String) } 2188 "#, 2189 find_position_of("Wibble").select_until(find_position_of("Wibble()").under_last_char()), 2190 ); 2191} 2192 2193#[test] 2194fn fill_in_labelled_args_works_with_pattern_and_no_parentheses() { 2195 assert_code_action!( 2196 FILL_LABELS, 2197 r#" 2198pub fn main() { 2199 let assert Ok(Wibble) = Wibble(1, "2") 2200} 2201 2202pub type Wibble { Wibble(arg1: Int, arg2: String) } 2203 "#, 2204 find_position_of("Wibble").select_until(find_position_of("Wibble").under_last_char()), 2205 ); 2206} 2207 2208#[test] 2209fn fill_in_labelled_args_works_with_pattern_and_parentheses() { 2210 assert_code_action!( 2211 FILL_LABELS, 2212 r#" 2213pub fn main() { 2214 let assert Ok(Wibble()) = Wibble(1, "2") 2215} 2216 2217pub type Wibble { Wibble(arg1: Int, arg2: String) } 2218 "#, 2219 find_position_of("Wibble").select_until(find_position_of("Wibble").under_last_char()), 2220 ); 2221} 2222 2223#[test] 2224fn fill_in_labelled_args_works_with_pattern_and_parentheses_with_spaces() { 2225 assert_code_action!( 2226 FILL_LABELS, 2227 r#" 2228pub fn main() { 2229 let assert Ok(Wibble ()) = Wibble(1, "2") 2230} 2231 2232pub type Wibble { Wibble(arg1: Int, arg2: String) } 2233 "#, 2234 find_position_of("Wibble").select_until(find_position_of("Wibble").under_last_char()), 2235 ); 2236} 2237 2238#[test] 2239fn fill_in_labelled_args_works_with_pipes() { 2240 assert_code_action!( 2241 FILL_LABELS, 2242 r#" 2243pub fn main() { 2244 1 |> wibble() 2245} 2246 2247pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2248 "#, 2249 find_position_of("wibble()") 2250 .under_last_char() 2251 .to_selection(), 2252 ); 2253} 2254 2255#[test] 2256fn fill_in_labelled_args_works_with_pipes_2() { 2257 assert_code_action!( 2258 FILL_LABELS, 2259 r#" 2260pub fn main() { 2261 1 |> wibble() 2262} 2263 2264pub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil } 2265 "#, 2266 find_position_of("wibble()") 2267 .under_last_char() 2268 .to_selection(), 2269 ); 2270} 2271 2272#[test] 2273fn fill_in_labelled_args_works_with_use() { 2274 assert_code_action!( 2275 FILL_LABELS, 2276 r#" 2277pub fn main() { 2278 use <- wibble() 2279 todo 2280} 2281 2282pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2283 "#, 2284 find_position_of("wibble(").select_until(find_position_of("wibble()").under_last_char()), 2285 ); 2286} 2287 2288#[test] 2289fn fill_in_labelled_args_works_with_use_2() { 2290 assert_code_action!( 2291 FILL_LABELS, 2292 r#" 2293pub fn main() { 2294 use <- wibble(arg1: 1) 2295 todo 2296} 2297 2298pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil } 2299 "#, 2300 find_position_of("wibble(").select_until(find_position_of("1").under_last_char()), 2301 ); 2302} 2303 2304#[test] 2305fn fill_in_labelled_args_works_with_use_3() { 2306 assert_code_action!( 2307 FILL_LABELS, 2308 r#" 2309pub fn main() { 2310 use <- wibble(arg2: 2) 2311 todo 2312} 2313 2314pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil } 2315 "#, 2316 find_position_of("wibble(").select_until(find_position_of("2").under_last_char()), 2317 ); 2318} 2319 2320#[test] 2321fn fill_in_labelled_args_selects_innermost_function() { 2322 assert_code_action!( 2323 FILL_LABELS, 2324 r#" 2325pub fn main() { 2326 wibble( 2327 wibble() 2328 ) 2329} 2330 2331pub fn wibble(arg1 arg1, arg2 arg2) { Nil } 2332 "#, 2333 find_position_of("wibble()") 2334 .under_last_char() 2335 .to_selection(), 2336 ); 2337} 2338 2339#[test] 2340fn fill_in_labelled_args_in_const_selects_innermost_function() { 2341 assert_code_action!( 2342 FILL_LABELS, 2343 r#" 2344pub const a_constant = Wibble(Wibble()) 2345pub type Wibble { Wibble(arg1: Int, arg2: Int) } 2346 "#, 2347 find_position_of("Wibble()") 2348 .under_last_char() 2349 .to_selection(), 2350 ); 2351} 2352 2353#[test] 2354fn fill_labels_uses_variable_in_scope_with_matching_type() { 2355 assert_code_action!( 2356 FILL_LABELS, 2357 r#" 2358pub type Player { 2359 Player(name: String, team: String) 2360} 2361 2362pub fn main() { 2363 let name = "Priya" 2364 Player(team: "BLU") 2365} 2366"#, 2367 find_position_of("Player").nth_occurrence(3).to_selection(), 2368 ); 2369} 2370 2371#[test] 2372fn fill_in_labelled_args_in_const_uses_constants_in_scope_with_matching_type() { 2373 assert_code_action!( 2374 FILL_LABELS, 2375 r#" 2376pub const power = 10 2377pub const a_constant = Wibble() 2378pub type Wibble { Wibble(power: Int, another_arg: Int) } 2379 "#, 2380 find_position_of("Wibble()") 2381 .under_last_char() 2382 .to_selection(), 2383 ); 2384} 2385 2386#[test] 2387fn fill_labels_falls_back_to_todo_when_type_does_not_match() { 2388 assert_code_action!( 2389 FILL_LABELS, 2390 r#" 2391pub type Player { 2392 Player(name: String, team: String) 2393} 2394 2395pub fn main() { 2396 let name = 1 2397 Player(team: "BLU") 2398} 2399"#, 2400 find_position_of("Player").nth_occurrence(3).to_selection(), 2401 ); 2402} 2403 2404#[test] 2405fn fill_in_labelled_args_in_const_uses_todo_if_constant_in_scope_does_not_match() { 2406 assert_code_action!( 2407 FILL_LABELS, 2408 r#" 2409pub const power = "not an int" 2410pub const a_constant = Wibble() 2411pub type Wibble { Wibble(power: Int, another_arg: Int) } 2412 "#, 2413 find_position_of("Wibble()") 2414 .under_last_char() 2415 .to_selection(), 2416 ); 2417} 2418 2419#[test] 2420fn fill_labels_uses_function_argument_in_scope() { 2421 assert_code_action!( 2422 FILL_LABELS, 2423 r#" 2424pub type Player { 2425 Player(name: String, team: String) 2426} 2427 2428pub fn create_player(name: String) { 2429 Player(team: "BLU") 2430} 2431"#, 2432 find_position_of("Player").nth_occurrence(3).to_selection(), 2433 ); 2434} 2435 2436#[test] 2437fn fill_labels_ignores_variable_defined_after_call() { 2438 assert_code_action!( 2439 FILL_LABELS, 2440 r#" 2441pub type Player { 2442 Player(name: String, team: String) 2443} 2444 2445pub fn main() { 2446 Player(team: "BLU") 2447 let name = "Priya" 2448} 2449"#, 2450 find_position_of("Player").nth_occurrence(3).to_selection(), 2451 ); 2452} 2453 2454#[test] 2455fn fill_labels_multiple_fields_some_matching() { 2456 assert_code_action!( 2457 FILL_LABELS, 2458 r#" 2459pub type Player { 2460 Player(name: String, age: Int, team: String) 2461} 2462 2463pub fn main() { 2464 let name = "Priya" 2465 let age = "not an int" 2466 Player() 2467} 2468"#, 2469 find_position_of("Player").nth_occurrence(3).to_selection(), 2470 ); 2471} 2472 2473#[test] 2474fn fill_labels_all_fields_have_matching_variables() { 2475 assert_code_action!( 2476 FILL_LABELS, 2477 r#" 2478pub type Player { 2479 Player(name: String, age: Int, team: String) 2480} 2481 2482pub fn main() { 2483 let name = "Priya" 2484 let age = 25 2485 let team = "BLU" 2486 Player() 2487} 2488"#, 2489 find_position_of("Player").nth_occurrence(3).to_selection(), 2490 ); 2491} 2492 2493#[test] 2494fn fill_labels_inside_anonymous_function() { 2495 assert_code_action!( 2496 FILL_LABELS, 2497 r#" 2498pub type Player { 2499 Player(name: String, team: String) 2500} 2501 2502pub fn main() { 2503 let name = "Outer" 2504 let callback = fn() { 2505 let name = "Inner" 2506 Player(team: "BLU") 2507 } 2508} 2509"#, 2510 find_position_of("Player").nth_occurrence(3).to_selection(), 2511 ); 2512} 2513 2514#[test] 2515fn fill_labels_variable_from_outer_scope_not_shadowed() { 2516 assert_code_action!( 2517 FILL_LABELS, 2518 r#" 2519pub type Player { 2520 Player(name: String, team: String) 2521} 2522 2523pub fn main() { 2524 let name = "Outer" 2525 let callback = fn() { 2526 Player(team: "BLU") 2527 } 2528} 2529"#, 2530 find_position_of("Player").nth_occurrence(3).to_selection(), 2531 ); 2532} 2533 2534#[test] 2535fn fill_labels_inside_assignment_with_same_name_as_field() { 2536 assert_code_action!( 2537 FILL_LABELS, 2538 r#" 2539pub type Player { 2540 Player(name: String, team: String) 2541} 2542 2543pub fn main() { 2544 let name = Player(team: "BLU") 2545} 2546"#, 2547 find_position_of("Player").nth_occurrence(3).to_selection(), 2548 ); 2549} 2550 2551#[test] 2552fn fill_labels_ignores_underscore_prefixed_variables() { 2553 assert_code_action!( 2554 FILL_LABELS, 2555 r#" 2556pub type Player { 2557 Player(name: String, team: String) 2558} 2559 2560pub fn main() { 2561 let _name = "Priya" 2562 Player(team: "BLU") 2563} 2564"#, 2565 find_position_of("Player").nth_occurrence(3).to_selection(), 2566 ); 2567} 2568 2569#[test] 2570fn fill_labels_variable_out_of_scope_in_block() { 2571 assert_code_action!( 2572 FILL_LABELS, 2573 r#" 2574pub type Player { 2575 Player(name: String, team: String) 2576} 2577 2578pub fn main() { 2579 { 2580 let name = "Priya" 2581 } 2582 Player(team: "BLU") 2583} 2584"#, 2585 find_position_of("Player").nth_occurrence(3).to_selection(), 2586 ); 2587} 2588 2589#[test] 2590fn fill_labels_variable_in_scope_from_case_pattern() { 2591 assert_code_action!( 2592 FILL_LABELS, 2593 r#" 2594pub type Player { 2595 Player(name: String, team: String) 2596} 2597 2598pub fn main(result: Result(String, Nil)) { 2599 case result { 2600 Ok(name) -> Player(team: "BLU") 2601 Error(_) -> Player(team: "RED", name: "Unknown") 2602 } 2603} 2604"#, 2605 find_position_of("Player").nth_occurrence(3).to_selection(), 2606 ); 2607} 2608 2609#[test] 2610fn fill_labels_generic_type_matching() { 2611 assert_code_action!( 2612 FILL_LABELS, 2613 r#" 2614pub type Container(a) { 2615 Container(value: a, label: String) 2616} 2617 2618pub fn main() { 2619 let value = 42 2620 let label = "test" 2621 Container() 2622} 2623"#, 2624 find_position_of("Container") 2625 .nth_occurrence(3) 2626 .to_selection(), 2627 ); 2628} 2629 2630#[test] 2631fn use_label_shorthand_works_for_nested_calls() { 2632 assert_code_action!( 2633 USE_LABEL_SHORTHAND_SYNTAX, 2634 r#" 2635pub fn wibble(arg arg: Int) -> Int { arg } 2636 2637pub fn main() { 2638 let arg = 1 2639 wibble(wibble(arg: arg)) 2640} 2641 "#, 2642 find_position_of("main").select_until(find_position_of("}").nth_occurrence(2)), 2643 ); 2644} 2645 2646#[test] 2647fn use_label_shorthand_works_for_nested_record_updates() { 2648 assert_code_action!( 2649 USE_LABEL_SHORTHAND_SYNTAX, 2650 r#" 2651pub type Wibble { Wibble(arg: Int, arg2: Wobble) } 2652pub type Wobble { Wobble(arg: Int, arg2: String) } 2653 2654pub fn main() { 2655 let arg = 1 2656 let arg2 = "a" 2657 Wibble(..todo, arg2: Wobble(arg: arg, arg2: arg2)) 2658} 2659 "#, 2660 find_position_of("todo").select_until(find_position_of("arg2: arg2")), 2661 ); 2662} 2663 2664#[test] 2665fn use_label_shorthand_works_for_nested_patterns() { 2666 assert_code_action!( 2667 USE_LABEL_SHORTHAND_SYNTAX, 2668 r#" 2669pub type Wibble { Wibble(arg: Int, arg2: Wobble) } 2670pub type Wobble { Wobble(arg: Int, arg2: String) } 2671 2672pub fn main() { 2673 let Wibble(arg2: Wobble(arg: arg, arg2: arg2), ..) = todo 2674} 2675 "#, 2676 find_position_of("main").select_until(find_position_of("todo")), 2677 ); 2678} 2679 2680#[test] 2681fn use_label_shorthand_works_for_alternative_patterns() { 2682 assert_code_action!( 2683 USE_LABEL_SHORTHAND_SYNTAX, 2684 r#" 2685pub type Wibble { Wibble(arg: Int, arg2: String) } 2686 2687pub fn main() { 2688 case Wibble(1, "wibble") { 2689 Wibble(arg2: arg2, ..) | Wibble(arg: 1, arg2: arg2) -> todo 2690 } 2691} 2692 "#, 2693 find_position_of("main").select_until(find_position_of("todo")), 2694 ); 2695} 2696 2697#[test] 2698fn test_assign_unused_result() { 2699 assert_code_action!( 2700 ASSIGN_UNUSED_RESULT, 2701 r#" 2702pub fn main() { 2703 let x = 1 2704 Ok(x) 2705 Nil 2706} 2707"#, 2708 find_position_of("Ok").select_until(find_position_of("(x)")), 2709 ); 2710} 2711 2712#[test] 2713fn test_assign_unused_result_in_block() { 2714 assert_code_action!( 2715 ASSIGN_UNUSED_RESULT, 2716 r#" 2717pub fn main() { 2718 { 2719 let x = 1 2720 Ok(x) 2721 Nil 2722 } 2723 Nil 2724} 2725"#, 2726 find_position_of("Ok").select_until(find_position_of("(x)")), 2727 ); 2728} 2729 2730#[test] 2731fn test_assign_unused_result_on_block_start() { 2732 assert_code_action!( 2733 ASSIGN_UNUSED_RESULT, 2734 r#" 2735pub fn main() { 2736 { 2737 let x = 1 2738 Ok(x) 2739 Ok(x) 2740 } 2741 Nil 2742} 2743"#, 2744 find_position_of("{").nth_occurrence(2).to_selection() 2745 ); 2746} 2747 2748#[test] 2749fn test_assign_unused_result_on_block_end() { 2750 assert_code_action!( 2751 ASSIGN_UNUSED_RESULT, 2752 r#" 2753pub fn main() { 2754 { 2755 let x = 1 2756 Ok(x) 2757 Ok(x) 2758 } 2759 Nil 2760} 2761"#, 2762 find_position_of("}").to_selection() 2763 ); 2764} 2765 2766#[test] 2767#[should_panic(expected = "No action with the given title")] 2768fn test_assign_unused_result_inside_block() { 2769 assert_code_action!( 2770 ASSIGN_UNUSED_RESULT, 2771 r#" 2772pub fn main() { 2773 { 2774 let x = 1 2775 Nil 2776 Ok(x) 2777 } 2778} 2779"#, 2780 find_position_of("Ok").select_until(find_position_of("(x)")) 2781 ); 2782} 2783 2784#[test] 2785fn test_assign_unused_result_only_first_action() { 2786 assert_code_action!( 2787 ASSIGN_UNUSED_RESULT, 2788 r#" 2789pub fn main() { 2790 let x = 1 2791 Ok(x) 2792 Ok(x) 2793 Nil 2794} 2795"#, 2796 find_position_of("Ok").select_until(find_position_of("(x)")) 2797 ); 2798} 2799 2800#[test] 2801#[should_panic(expected = "No action with the given title")] 2802fn test_assign_unused_result_not_on_return_value() { 2803 assert_code_action!( 2804 ASSIGN_UNUSED_RESULT, 2805 r#" 2806pub fn main() { 2807 let x = 1 2808 Ok(x) 2809} 2810"#, 2811 find_position_of("Ok").select_until(find_position_of("(x)")) 2812 ); 2813} 2814 2815#[test] 2816#[should_panic(expected = "No action with the given title")] 2817fn test_assign_unused_result_not_on_return_value_in_block() { 2818 assert_code_action!( 2819 ASSIGN_UNUSED_RESULT, 2820 r#" 2821pub fn main() { 2822 let _ = { 2823 let x = 1 2824 Ok(x) 2825 } 2826 Nil 2827}"#, 2828 find_position_of("Ok").select_until(find_position_of("(x)")) 2829 ); 2830} 2831 2832#[test] 2833fn test_import_module_from_function() { 2834 let src = " 2835pub fn main() { 2836 result.is_ok() 2837} 2838"; 2839 2840 assert_code_action!( 2841 "Import `result`", 2842 TestProject::for_source(src).add_hex_module("result", "pub fn is_ok() {}"), 2843 find_position_of("result").select_until(find_position_of(".")) 2844 ); 2845} 2846 2847#[test] 2848fn test_import_path_module_from_function() { 2849 let src = r#" 2850pub fn main() { 2851 io.println("Hello, world!") 2852} 2853"#; 2854 2855 assert_code_action!( 2856 "Import `gleam/io`", 2857 TestProject::for_source(src) 2858 .add_hex_module("gleam/io", "pub fn println(message: String) {}"), 2859 find_position_of("io").select_until(find_position_of(".")) 2860 ); 2861} 2862 2863#[test] 2864fn test_import_module_from_type() { 2865 let src = "type Wobble = wibble.Wubble"; 2866 2867 assert_code_action!( 2868 "Import `mod/wibble`", 2869 TestProject::for_source(src).add_hex_module("mod/wibble", "pub type Wubble { Wubble }"), 2870 find_position_of("wibble").select_until(find_position_of(".")) 2871 ); 2872} 2873 2874#[test] 2875fn test_import_module_from_constructor() { 2876 let src = " 2877pub fn main() { 2878 let value = values.Value(10) 2879} 2880"; 2881 2882 assert_code_action!( 2883 "Import `values`", 2884 TestProject::for_source(src).add_hex_module("values", "pub type Value { Value(Int) }"), 2885 find_position_of("values").select_until(find_position_of(".")) 2886 ); 2887} 2888 2889#[test] 2890fn test_rename_module_for_imported() { 2891 let src = r#" 2892import gleam/io 2893 2894pub fn main() { 2895 i.println("Hello, world!") 2896} 2897"#; 2898 2899 assert_code_action!( 2900 "Did you mean `io`", 2901 TestProject::for_source(src) 2902 .add_hex_module("gleam/io", "pub fn println(message: String) {}"), 2903 find_position_of("i.").select_until(find_position_of("println")) 2904 ); 2905} 2906 2907#[test] 2908fn test_import_similar_module() { 2909 let src = " 2910pub fn main() { 2911 reult.is_ok() 2912} 2913"; 2914 2915 assert_code_action!( 2916 "Import `result`", 2917 TestProject::for_source(src).add_hex_module("result", "pub fn is_ok() {}"), 2918 find_position_of("reult").select_until(find_position_of(".")) 2919 ); 2920} 2921 2922#[test] 2923fn test_no_action_to_import_module_without_value() { 2924 // The language server should not suggest a code action 2925 // to import a module if it doesn't have a value with 2926 // the same name as we are trying to access 2927 let src = " 2928pub fn main() { 2929 io.hello_world() 2930} 2931"; 2932 2933 let title = "Import `io`"; 2934 2935 assert_no_code_actions!( 2936 title, 2937 TestProject::for_source(src).add_hex_module("io", "pub fn println() {}"), 2938 find_position_of("io").select_until(find_position_of(".")) 2939 ); 2940} 2941 2942#[test] 2943fn test_no_action_to_import_module_without_type() { 2944 let src = "type Name = int.String"; 2945 2946 let title = "Import `int`"; 2947 2948 assert_no_code_actions!( 2949 title, 2950 TestProject::for_source(src).add_hex_module("int", ""), 2951 find_position_of("int").select_until(find_position_of(".")) 2952 ); 2953} 2954 2955#[test] 2956fn test_no_action_to_import_module_with_private_value() { 2957 // The language server should not suggest a code action 2958 // to import a module if the value we are trying to 2959 // access is private. 2960 let src = " 2961pub fn main() { 2962 mod.internal() 2963} 2964"; 2965 2966 let title = "Import `mod`"; 2967 2968 assert_no_code_actions!( 2969 title, 2970 TestProject::for_source(src).add_hex_module("mod", "fn internal() {}"), 2971 find_position_of("mod").select_until(find_position_of(".")) 2972 ); 2973} 2974 2975#[test] 2976fn test_no_action_to_import_module_with_private_type() { 2977 let src = "type T = module.T"; 2978 2979 let title = "Import `module`"; 2980 2981 assert_no_code_actions!( 2982 title, 2983 TestProject::for_source(src).add_hex_module("module", "type T { T }"), 2984 find_position_of("module").select_until(find_position_of(".")) 2985 ); 2986} 2987 2988#[test] 2989fn test_no_action_to_import_module_with_constructor_named_same_as_type() { 2990 let src = "type NotAType = shapes.Rectangle"; 2991 2992 let title = "Import `shapes`"; 2993 2994 assert_no_code_actions!( 2995 title, 2996 TestProject::for_source(src) 2997 .add_hex_module("shapes", "pub type Shape { Rectangle, Circle }"), 2998 find_position_of("shapes").select_until(find_position_of(".")) 2999 ); 3000} 3001 3002#[test] 3003fn add_missing_patterns_bool() { 3004 assert_code_action!( 3005 ADD_MISSING_PATTERNS, 3006 " 3007pub fn main(bool: Bool) { 3008 case bool {} 3009} 3010", 3011 find_position_of("case").select_until(find_position_of("bool {")) 3012 ); 3013} 3014 3015#[test] 3016fn add_missing_patterns_does_not_remove_comment() { 3017 assert_code_action!( 3018 ADD_MISSING_PATTERNS, 3019 " 3020pub fn main(bool: Bool) { 3021 case bool { 3022 // Here is some comment that should not be deleted 3023 } 3024} 3025", 3026 find_position_of("case").select_until(find_position_of("bool {")) 3027 ); 3028} 3029 3030#[test] 3031fn add_missing_patterns_does_not_remove_comment_2() { 3032 assert_code_action!( 3033 ADD_MISSING_PATTERNS, 3034 " 3035pub fn main(bool: Bool) { 3036 case bool { 3037 // Here is some comment that should not be deleted 3038 3039 // Here is some other separate comment! 3040 // And loads of white space that has to be deleted. 3041 3042 3043 3044 3045 3046 } 3047} 3048", 3049 find_position_of("case").select_until(find_position_of("bool {")) 3050 ); 3051} 3052 3053#[test] 3054fn add_missing_patterns_custom_type() { 3055 assert_code_action!( 3056 ADD_MISSING_PATTERNS, 3057 " 3058type Wibble { 3059 Wibble 3060 Wobble 3061 Wubble 3062} 3063 3064pub fn main(wibble: Wibble) { 3065 case wibble { 3066 Wobble -> Nil 3067 } 3068} 3069", 3070 find_position_of("case").select_until(find_position_of("wibble {")) 3071 ); 3072} 3073 3074#[test] 3075fn add_missing_patterns_tuple() { 3076 assert_code_action!( 3077 ADD_MISSING_PATTERNS, 3078 " 3079pub fn main(two_at_once: #(Bool, Result(Int, Nil))) { 3080 case two_at_once { 3081 #(False, Error(_)) -> Nil 3082 } 3083} 3084", 3085 find_position_of("case").select_until(find_position_of("two_at_once {")) 3086 ); 3087} 3088 3089#[test] 3090fn add_missing_patterns_list() { 3091 assert_code_action!( 3092 ADD_MISSING_PATTERNS, 3093 " 3094pub fn main() { 3095 let list = [1, 2, 3] 3096 case list { 3097 [a, b, c, 4 as d] -> d 3098 } 3099} 3100", 3101 find_position_of("case").select_until(find_position_of("list {")) 3102 ); 3103} 3104 3105#[test] 3106fn add_missing_patterns_infinite() { 3107 assert_code_action!( 3108 ADD_MISSING_PATTERNS, 3109 r#" 3110pub fn main() { 3111 let value = 3 3112 case value { 3113 1 -> "one" 3114 2 -> "two" 3115 3 -> "three" 3116 } 3117} 3118"#, 3119 find_position_of("case").select_until(find_position_of("value {")) 3120 ); 3121} 3122 3123#[test] 3124fn add_missing_patterns_multi() { 3125 assert_code_action!( 3126 ADD_MISSING_PATTERNS, 3127 r#" 3128pub fn main(a: Bool) { 3129 let b = 1 3130 case a, b { 3131 3132 } 3133} 3134"#, 3135 find_position_of("case").select_until(find_position_of("b {")) 3136 ); 3137} 3138 3139#[test] 3140fn add_missing_patterns_inline() { 3141 // Ensure we correctly detect the indentation, if the case expression 3142 // does not start at the beginning of the line 3143 assert_code_action!( 3144 ADD_MISSING_PATTERNS, 3145 r#" 3146pub fn main(a: Bool) { 3147 let value = case a {} 3148} 3149"#, 3150 find_position_of("case").select_until(find_position_of("a {")) 3151 ); 3152} 3153 3154#[test] 3155fn import_module_from_pattern() { 3156 let src = " 3157pub fn main(res) { 3158 case res { 3159 result.Ok(_) -> Nil 3160 result.Error(_) -> Nil 3161 } 3162} 3163"; 3164 3165 assert_code_action!( 3166 "Import `result`", 3167 TestProject::for_source(src) 3168 .add_hex_module("result", "pub type Result(v, e) { Ok(v) Error(e) }"), 3169 find_position_of("result").select_until(find_position_of(".")) 3170 ); 3171} 3172 3173#[test] 3174fn annotate_function() { 3175 assert_code_action!( 3176 ADD_ANNOTATIONS, 3177 r#" 3178pub fn add_one(thing) { 3179 thing + 1 3180} 3181"#, 3182 find_position_of("fn").select_until(find_position_of("(")) 3183 ); 3184} 3185 3186#[test] 3187fn annotate_function_with_annotated_return_type() { 3188 assert_code_action!( 3189 ADD_ANNOTATION, 3190 r#" 3191pub fn add_one(thing) -> Int { 3192 thing + 1 3193} 3194"#, 3195 find_position_of("fn").select_until(find_position_of("(")) 3196 ); 3197} 3198 3199#[test] 3200fn annotate_function_with_partially_annotated_parameters() { 3201 assert_code_action!( 3202 ADD_ANNOTATION, 3203 r#" 3204pub fn add(a: Float, b) -> Float { 3205 a +. b 3206} 3207"#, 3208 find_position_of("fn").select_until(find_position_of("(")) 3209 ); 3210} 3211 3212#[test] 3213fn no_code_action_for_fully_annotated_function() { 3214 assert_no_code_actions!( 3215 ADD_ANNOTATION | ADD_ANNOTATIONS, 3216 r#" 3217pub fn do_a_thing(a: Int, b: Float) -> String { 3218 todo 3219} 3220"#, 3221 find_position_of("fn").select_until(find_position_of("(")) 3222 ); 3223} 3224 3225#[test] 3226fn annotate_anonymous_function() { 3227 assert_code_action!( 3228 ADD_ANNOTATIONS, 3229 r#" 3230pub fn add_curry(a) { 3231 fn(b) { a + b } 3232} 3233"#, 3234 find_position_of("fn(").select_until(find_position_of("b)")) 3235 ); 3236} 3237 3238#[test] 3239fn annotate_anonymous_function_with_annotated_return_type() { 3240 assert_code_action!( 3241 ADD_ANNOTATION, 3242 r#" 3243pub fn add_curry(a) { 3244 fn(b) -> Int { a + b } 3245} 3246"#, 3247 find_position_of("fn(").select_until(find_position_of("b)")) 3248 ); 3249} 3250 3251#[test] 3252fn annotate_anonymous_function_with_partially_annotated_parameters() { 3253 assert_code_action!( 3254 ADD_ANNOTATIONS, 3255 r#" 3256pub fn main() { 3257 fn(a, b: Int, c) { a + b + c } 3258} 3259"#, 3260 find_position_of("fn(").select_until(find_position_of("c)")) 3261 ); 3262} 3263 3264#[test] 3265fn no_code_action_for_fully_annotated_anonymous_function() { 3266 assert_no_code_actions!( 3267 ADD_ANNOTATION | ADD_ANNOTATIONS, 3268 r#" 3269pub fn main() { 3270 fn(a: Int, b: Int) -> Int { a - b } 3271} 3272"#, 3273 find_position_of("fn(").select_until(find_position_of("Int)")) 3274 ); 3275} 3276 3277#[test] 3278fn annotate_use() { 3279 assert_code_action!( 3280 ADD_ANNOTATIONS, 3281 r#" 3282pub fn wibble(wobble: fn(Int, Int) -> Int) { 3283 wobble(1, 2) 3284} 3285 3286pub fn main() { 3287 use a, b <- wibble 3288 a + b 3289} 3290"#, 3291 find_position_of("use").select_until(find_position_of("<-")) 3292 ); 3293} 3294 3295#[test] 3296fn annotate_use_with_partially_annotated_parameters() { 3297 assert_code_action!( 3298 ADD_ANNOTATION, 3299 r#" 3300pub fn wibble(wobble: fn(Int, Int) -> Int) { 3301 wobble(1, 2) 3302} 3303 3304pub fn main() { 3305 use a: Int, b <- wibble 3306 a + b 3307} 3308"#, 3309 find_position_of("use").select_until(find_position_of("<-")) 3310 ); 3311} 3312 3313#[test] 3314fn no_code_action_for_fully_annotated_use() { 3315 assert_no_code_actions!( 3316 ADD_ANNOTATION | ADD_ANNOTATIONS, 3317 r#" 3318pub fn wibble(wobble: fn(Int, Int) -> Int) { 3319 wobble(1, 2) 3320} 3321 3322pub fn main() { 3323 use a: Int, b: Int <- wibble 3324 a + b 3325} 3326"#, 3327 find_position_of("use").select_until(find_position_of("<-")) 3328 ); 3329} 3330 3331#[test] 3332fn annotate_constant() { 3333 assert_code_action!( 3334 ADD_ANNOTATION, 3335 r#" 3336pub const my_constant = 20 3337"#, 3338 find_position_of("const").select_until(find_position_of("=")) 3339 ); 3340} 3341 3342#[test] 3343fn no_code_action_for_annotated_constant() { 3344 assert_no_code_actions!( 3345 ADD_ANNOTATION | ADD_ANNOTATIONS, 3346 r#" 3347pub const PI: Float = 3.14159 3348"#, 3349 find_position_of("const").select_until(find_position_of("=")) 3350 ); 3351} 3352 3353#[test] 3354fn annotate_local_variable() { 3355 assert_code_action!( 3356 ADD_ANNOTATION, 3357 r#" 3358pub fn main() { 3359 let my_value = 10 3360} 3361"#, 3362 find_position_of("let").select_until(find_position_of("=")) 3363 ); 3364} 3365 3366#[test] 3367fn annotate_local_variable_with_pattern() { 3368 assert_code_action!( 3369 ADD_ANNOTATION, 3370 r#" 3371type Wibble { 3372 Wibble(a: Int, b: Int, c: Int) 3373} 3374 3375pub fn main() { 3376 let Wibble(a, b, c) = Wibble(1, 2, 3) 3377} 3378"#, 3379 find_position_of("let").select_until(find_position_of("=")) 3380 ); 3381} 3382 3383#[test] 3384fn annotate_local_variable_with_pattern2() { 3385 assert_code_action!( 3386 ADD_ANNOTATION, 3387 r#" 3388pub fn main(values) { 3389 let #(left, right) = values 3390} 3391"#, 3392 find_position_of("let").select_until(find_position_of("=")) 3393 ); 3394} 3395 3396#[test] 3397fn annotate_local_variable_let_assert() { 3398 assert_code_action!( 3399 ADD_ANNOTATION, 3400 r#" 3401pub fn fallible() -> Result(Int, Nil) { 3402 todo 3403} 3404 3405pub fn main() { 3406 let assert Ok(value) = fallible() 3407} 3408"#, 3409 find_position_of("let").select_until(find_position_of("=")) 3410 ); 3411} 3412 3413#[test] 3414fn annotate_nested_local_variable() { 3415 assert_code_action!( 3416 ADD_ANNOTATION, 3417 r#" 3418pub fn main() { 3419 let a = { 3420 let b = 10 3421 b + 1 3422 } 3423} 3424"#, 3425 find_position_of("let b").select_until(find_position_of("b =")) 3426 ); 3427} 3428 3429#[test] 3430fn no_code_action_for_annotated_local_variable() { 3431 assert_no_code_actions!( 3432 ADD_ANNOTATION | ADD_ANNOTATIONS, 3433 r#" 3434pub fn main() { 3435 let typed: Int = 1.2 3436} 3437"#, 3438 find_position_of("let").select_until(find_position_of("=")) 3439 ); 3440} 3441 3442#[test] 3443fn adding_annotations_correctly_prints_type_variables() { 3444 assert_code_action!( 3445 ADD_ANNOTATIONS, 3446 r#" 3447pub fn map_result(input, function) { 3448 case input { 3449 Ok(value) -> Ok(function(value)) 3450 Error(error) -> Error(error) 3451 } 3452} 3453"#, 3454 find_position_of("fn").select_until(find_position_of("(")) 3455 ); 3456} 3457 3458#[test] 3459fn add_multiple_annotations() { 3460 assert_code_action!( 3461 ADD_ANNOTATIONS, 3462 r#" 3463pub const my_constant = 20 3464 3465pub fn add_my_constant(value) { 3466 let result = value + my_constant 3467 result 3468} 3469"#, 3470 find_position_of("pub const").select_until(find_position_of("}")) 3471 ); 3472} 3473 3474#[test] 3475fn different_annotations_create_compatible_type_variables() { 3476 assert_code_action!( 3477 ADD_ANNOTATIONS, 3478 r#" 3479pub fn do_generic_things(a, b) { 3480 let a_value = a 3481 let b_value = b 3482 let other_value = a_value 3483} 3484"#, 3485 find_position_of("let a_value").select_until(find_position_of("}")) 3486 ); 3487} 3488 3489#[test] 3490fn adding_annotations_prints_type_variable_names() { 3491 assert_code_action!( 3492 ADD_ANNOTATIONS, 3493 r#" 3494pub fn do_generic_things(a: type_a, b: type_b) { 3495 let a_value = a 3496 let b_value = b 3497 let other_value = a_value 3498} 3499"#, 3500 find_position_of("let a_value").select_until(find_position_of("}")) 3501 ); 3502} 3503 3504#[test] 3505fn adding_annotations_prints_contextual_types() { 3506 assert_code_action!( 3507 ADD_ANNOTATION, 3508 r#" 3509pub type IntAlias = Int 3510 3511pub fn main() { 3512 let value = 20 3513} 3514"#, 3515 find_position_of("let").select_until(find_position_of("value")) 3516 ); 3517} 3518 3519#[test] 3520fn adding_annotations_prints_contextual_types2() { 3521 assert_code_action!( 3522 ADD_ANNOTATION, 3523 r#" 3524pub type Result 3525 3526pub fn main() { 3527 let value = Ok(12) 3528} 3529"#, 3530 find_position_of("let").select_until(find_position_of("=")) 3531 ); 3532} 3533 3534#[test] 3535fn adding_annotations_prints_contextual_types3() { 3536 let src = r#" 3537import wibble 3538 3539pub fn main() { 3540 let value = wibble.Wibble 3541} 3542"#; 3543 3544 assert_code_action!( 3545 ADD_ANNOTATION, 3546 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 3547 find_position_of("let").select_until(find_position_of("=")) 3548 ); 3549} 3550 3551#[test] 3552fn add_annotation_triggers_on_function_curly_brace() { 3553 assert_code_action!( 3554 ADD_ANNOTATION, 3555 "pub fn main() { 1 }", 3556 find_position_of("{").to_selection(), 3557 ); 3558} 3559 3560#[test] 3561fn add_annotation_triggers_on_empty_space_before_function_curly_brace() { 3562 assert_code_action!( 3563 ADD_ANNOTATION, 3564 "pub fn main() { 1 }", 3565 find_position_of(" ").nth_occurrence(3).to_selection(), 3566 ); 3567} 3568 3569#[test] 3570fn adding_annotations_prints_contextual_types4() { 3571 let src = r#" 3572import wibble as wobble 3573 3574pub fn main() { 3575 let value = wobble.Wibble 3576} 3577"#; 3578 3579 assert_code_action!( 3580 ADD_ANNOTATION, 3581 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 3582 find_position_of("let").select_until(find_position_of("=")) 3583 ); 3584} 3585 3586#[test] 3587fn adding_annotations_prints_contextual_types5() { 3588 let src = r#" 3589import wibble.{type Wibble as Wobble} 3590 3591pub fn main() { 3592 let value = wibble.Wibble 3593} 3594"#; 3595 3596 assert_code_action!( 3597 ADD_ANNOTATION, 3598 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 3599 find_position_of("let").select_until(find_position_of("=")) 3600 ); 3601} 3602 3603#[test] 3604// https://github.com/gleam-lang/gleam/issues/3789 3605fn no_code_actions_to_add_annotations_for_pipe() { 3606 assert_no_code_actions!( 3607 ADD_ANNOTATION | ADD_ANNOTATIONS, 3608 r#" 3609fn do_something(a: Int) { a } 3610 3611pub fn main() { 3612 10 |> do_something 3613} 3614"#, 3615 find_position_of("10").select_until(find_position_of("|>")) 3616 ); 3617} 3618 3619#[test] 3620// https://github.com/gleam-lang/gleam/issues/3789#issuecomment-2455805734 3621fn add_correct_type_annotation_for_non_variable_use() { 3622 assert_code_action!( 3623 ADD_ANNOTATION, 3624 r#" 3625fn usable(f) { 3626 f(#(1, 2)) 3627} 3628 3629pub fn main() { 3630 use #(a, b) <- usable 3631 a + b 3632} 3633"#, 3634 find_position_of("use").select_until(find_position_of("b)")) 3635 ); 3636} 3637 3638#[test] 3639fn test_qualified_to_unqualified_import_basic_with_argument() { 3640 let src = r#" 3641import option 3642 3643pub fn main() { 3644 option.Some(1) 3645} 3646"#; 3647 assert_code_action!( 3648 "Unqualify option.Some", 3649 TestProject::for_source(src) 3650 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3651 find_position_of(".Some").select_until(find_position_of("(1)")), 3652 ); 3653} 3654 3655#[test] 3656fn test_qualified_to_unqualified_import_basic_record_without_argument() { 3657 let src = r#" 3658import wobble 3659 3660pub fn main() { 3661 wobble.Wibble 3662} 3663"#; 3664 assert_code_action!( 3665 "Unqualify wobble.Wibble", 3666 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"), 3667 find_position_of(".W").select_until(find_position_of("ibble")) 3668 ); 3669} 3670 3671#[test] 3672fn test_qualified_to_unqualified_import_custom_type_record_declaration() { 3673 let src = r#" 3674import wobble 3675 3676pub type Wibble { 3677 Wibble(wibble: wobble.Wobble) 3678} 3679"#; 3680 assert_code_action!( 3681 "Unqualify wobble.Wobble", 3682 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"), 3683 find_position_of(".").select_until(find_position_of("Wobble")) 3684 ); 3685} 3686 3687#[test] 3688fn test_qualified_to_unqualified_import_basic_type_without_argument() { 3689 let src = r#" 3690import wobble 3691 3692pub fn identity(x: wobble.Wobble) -> wobble.Wobble { 3693 x 3694} 3695"#; 3696 assert_code_action!( 3697 "Unqualify wobble.Wobble", 3698 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"), 3699 find_position_of(".").select_until(find_position_of("Wobble")) 3700 ); 3701} 3702 3703#[test] 3704fn test_qualified_to_unqualified_record_value_constructor_module_name() { 3705 let src = r#" 3706import option 3707 3708pub fn main() { 3709 option.Some(1) 3710} 3711"#; 3712 assert_code_action!( 3713 "Unqualify option.Some", 3714 TestProject::for_source(src) 3715 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3716 find_position_of("option").nth_occurrence(2).to_selection() 3717 ); 3718} 3719 3720#[test] 3721fn test_qualified_to_unqualified_import_basic_multiple() { 3722 let src = r#" 3723import option 3724 3725pub fn main() { 3726 option.Some(1) 3727 option.Some(1) 3728 todo 3729} 3730"#; 3731 assert_code_action!( 3732 "Unqualify option.Some", 3733 TestProject::for_source(src) 3734 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3735 find_position_of(".Some").select_until(find_position_of("(1)")), 3736 ); 3737} 3738 3739#[test] 3740fn test_qualified_to_unqualified_import_when_unqualified_exists() { 3741 let src = r#" 3742import option.{Some} 3743 3744pub fn main() { 3745 option.Some(1) 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(".Some").select_until(find_position_of("(1)")), 3753 ); 3754} 3755 3756#[test] 3757fn test_qualified_to_unqualified_import_with_comma() { 3758 let src = r#" 3759import option.{None, } 3760 3761pub fn main() { 3762 option.Some(1) 3763} 3764"#; 3765 assert_code_action!( 3766 "Unqualify option.Some", 3767 TestProject::for_source(src) 3768 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3769 find_position_of(".Some").select_until(find_position_of("(1)")), 3770 ); 3771} 3772 3773#[test] 3774fn test_qualified_to_unqualified_import_with_comma_pos_not_end() { 3775 let src = r#" 3776import option.{None, } as opt 3777 3778pub fn main() { 3779 opt.Some(1) 3780} 3781"#; 3782 assert_code_action!( 3783 "Unqualify opt.Some", 3784 TestProject::for_source(src) 3785 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3786 find_position_of(".Some").select_until(find_position_of("(1)")), 3787 ); 3788} 3789 3790#[test] 3791fn test_qualified_to_unqualified_import_different_constructors() { 3792 let src = r#" 3793import option 3794 3795pub fn main() { 3796 option.Some(1) 3797 option.None 3798}"#; 3799 assert_code_action!( 3800 "Unqualify option.Some", 3801 TestProject::for_source(src) 3802 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3803 find_position_of(".Some").select_until(find_position_of("(1)")), 3804 ); 3805} 3806 3807#[test] 3808fn test_qualified_to_unqualified_import_no_action_when_already_unqualified() { 3809 let src = r#" 3810import option.{Some, None} 3811 3812pub fn main() { 3813 Some(1) 3814 Some(1) 3815 todo 3816} 3817"#; 3818 let title = "Unqualify option.Some"; 3819 assert_no_code_actions!( 3820 title, 3821 TestProject::for_source(src) 3822 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3823 find_position_of("Some(").select_until(find_position_of("1)")), 3824 ); 3825} 3826 3827#[test] 3828fn test_qualified_to_unqualified_import_with_alias() { 3829 let src = r#" 3830import option as opt 3831 3832pub fn main() { 3833 opt.Some(1) 3834} 3835"#; 3836 assert_code_action!( 3837 "Unqualify opt.Some", 3838 TestProject::for_source(src) 3839 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3840 find_position_of("opt.Some").select_until(find_position_of("(1)")), 3841 ); 3842} 3843 3844#[test] 3845fn test_qualified_to_unqualified_import_with_alias_multiple() { 3846 let src = r#" 3847import option as opt 3848 3849pub fn main() { 3850 opt.Some(1) 3851 opt.Some(1) 3852} 3853 3854pub fn identity(x: opt.Option(Int)) -> opt.Option(Int) { 3855 opt.Some(1) 3856 x 3857} 3858"#; 3859 assert_code_action!( 3860 "Unqualify opt.Some", 3861 TestProject::for_source(src) 3862 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3863 find_position_of("opt.Some").select_until(find_position_of("(1)")), 3864 ); 3865} 3866 3867#[test] 3868fn test_qualified_to_unqualified_import_multiple_imports() { 3869 let src = r#" 3870import option 3871import wobble 3872 3873pub fn main() { 3874 option.Some(2) 3875 wobble.Wibble(1) 3876} 3877"#; 3878 assert_code_action!( 3879 "Unqualify wobble.Wibble", 3880 TestProject::for_source(src) 3881 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 3882 .add_hex_module("wobble", "pub type Wobble { Wibble(Int)} "), 3883 find_position_of(".Wibble").select_until(find_position_of("(1)")), 3884 ); 3885} 3886 3887#[test] 3888fn test_qualified_to_unqualified_import_in_case_with_argument() { 3889 let src = r#" 3890import option 3891 3892pub fn main(x) { 3893 case option.Some(1) { 3894 option.Some(value) -> value 3895 option.None -> 0 3896 } 3897} 3898"#; 3899 assert_code_action!( 3900 "Unqualify option.Some", 3901 TestProject::for_source(src) 3902 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3903 find_position_of(".Some(").select_until(find_position_of("(1)")) 3904 ); 3905} 3906 3907#[test] 3908fn test_qualified_to_unqualified_import_in_case_without_argument() { 3909 let src = r#" 3910import wobble 3911 3912pub fn main() { 3913 case wobble.Wibble { 3914 wobble.Wibble -> 1 3915 wobble.Wubble(1) -> 2 3916 } 3917} 3918"#; 3919 assert_code_action!( 3920 "Unqualify wobble.Wibble", 3921 TestProject::for_source(src) 3922 .add_hex_module("wobble", "pub type Wobble { Wibble Wubble(Int) }"), 3923 find_position_of(".W").select_until(find_position_of("ibble")) 3924 ); 3925} 3926 3927#[test] 3928fn test_qualified_to_unqualified_import_in_pattern() { 3929 let src = r#" 3930import option 3931 3932pub fn main() -> Int { 3933 case option.Some(1) { 3934 option.Some(value) -> value 3935 option.None -> 0 3936 } 3937} 3938"#; 3939 assert_code_action!( 3940 "Unqualify option.Some", 3941 TestProject::for_source(src) 3942 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3943 find_position_of(".Some(va").select_until(find_position_of("lue)")), 3944 ); 3945} 3946 3947#[test] 3948fn test_qualified_to_unqualified_import_in_pattern_without_argument() { 3949 let src = r#" 3950import wobble 3951 3952pub fn main() { 3953 case wobble.Wibble { 3954 wobble.Wibble -> 1 3955 wobble.Wubble(1) -> 2 3956 } 3957 let wob = wobble.Wibble 3958 todo 3959} 3960"#; 3961 assert_code_action!( 3962 "Unqualify wobble.Wibble", 3963 TestProject::for_source(src) 3964 .add_hex_module("wobble", "pub type Wobble { Wibble Wubble(Int) }"), 3965 find_position_of("wobble.W").select_until(find_position_of("ibble")) 3966 ); 3967} 3968 3969#[test] 3970fn test_qualified_to_unqualified_import_type() { 3971 let src = r#" 3972import option 3973 3974pub fn main(x) -> option.Option(Int) { 3975 option.Some(1) 3976} 3977"#; 3978 assert_code_action!( 3979 "Unqualify option.Option", 3980 TestProject::for_source(src) 3981 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 3982 find_position_of(".Option").select_until(find_position_of("(Int)")), 3983 ); 3984} 3985 3986#[test] 3987fn test_qualified_to_unqualified_only_triggers_within_qualified_value() { 3988 let src = r#" 3989import option 3990 3991pub fn main(x) -> option.Option(Int) { 3992 option.Some(1) 3993} 3994// end 3995"#; 3996 assert_no_code_actions!( 3997 "Unqualify option.Option", 3998 TestProject::for_source(src) 3999 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4000 find_position_of("import").select_until(find_position_of("// end")), 4001 ); 4002} 4003 4004#[test] 4005fn test_qualified_to_unqualified_import_nested_type_outer() { 4006 let src = r#" 4007import option 4008import wobble 4009pub fn main(x) -> option.Option(wobble.Wibble) { 4010 todo 4011} 4012"#; 4013 assert_code_action!( 4014 "Unqualify option.Option", 4015 TestProject::for_source(src) 4016 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4017 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 4018 find_position_of(".O").select_until(find_position_of("ption(")), 4019 ); 4020} 4021 4022#[test] 4023fn test_qualified_to_unqualified_import_nested_constructor_outer() { 4024 let src = r#" 4025import option 4026import wobble 4027pub fn main(x) -> option.Option(wobble.Wibble) { 4028 option.Some(wobble.Wobble(1)) 4029} 4030"#; 4031 assert_code_action!( 4032 "Unqualify option.Some", 4033 TestProject::for_source(src) 4034 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4035 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 4036 find_position_of(".S").select_until(find_position_of("ome(")), 4037 ); 4038} 4039 4040#[test] 4041fn test_qualified_to_unqualified_import_nested_constructor_inner() { 4042 let src = r#" 4043import option 4044import wobble 4045 4046pub fn main(x) -> option.Option(wobble.Wibble) { 4047 option.Some(wobble.Wobble(1)) 4048} 4049"#; 4050 assert_code_action!( 4051 "Unqualify wobble.Wobble", 4052 TestProject::for_source(src) 4053 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4054 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 4055 find_position_of(".Wobble").select_until(find_position_of("(1)")), 4056 ); 4057} 4058 4059#[test] 4060fn test_qualified_to_unqualified_import_nested_type_inner() { 4061 let src = r#" 4062import option 4063import wobble 4064 4065pub fn main(x) -> option.Option(wobble.Wibble) { 4066 todo 4067} 4068"#; 4069 assert_code_action!( 4070 "Unqualify wobble.Wibble", 4071 TestProject::for_source(src) 4072 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4073 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"), 4074 find_position_of("wobble.").select_until(find_position_of("Wibble")), 4075 ); 4076} 4077 4078#[test] 4079fn test_qualified_to_unqualified_aliased_type() { 4080 let src = r#" 4081import wobble 4082 4083pub fn main(x) -> wobble.Wibble(a) { 4084 todo 4085} 4086"#; 4087 assert_code_action!( 4088 "Unqualify wobble.Wibble", 4089 TestProject::for_source(src).add_hex_module("wobble", "pub type Wibble(a) = List(a)"), 4090 find_position_of("wobble.").select_until(find_position_of("Wibble")), 4091 ); 4092} 4093 4094#[test] 4095fn test_qualified_to_unqualified_aliased_type_with_multiple_imports() { 4096 let src = r#" 4097import other/wobble as other 4098import wibble/wobble 4099 4100pub fn main(x) -> wobble.Wibble(a) { 4101 todo 4102} 4103"#; 4104 assert_code_action!( 4105 "Unqualify wobble.Wibble", 4106 TestProject::for_source(src) 4107 .add_hex_module("wibble/wobble", "pub type Wibble(a) = List(a)") 4108 .add_hex_module("other/wobble", "pub type Wibble(a) = List(a)"), 4109 find_position_of("wobble.").select_until(find_position_of("Wibble")), 4110 ); 4111} 4112 4113#[test] 4114fn test_qualified_aliased_to_unqualified_aliased_type() { 4115 let src = r#" 4116import wobble as wob 4117 4118pub fn main(x) -> wob.Wibble(a) { 4119 todo 4120} 4121"#; 4122 assert_code_action!( 4123 "Unqualify wob.Wibble", 4124 TestProject::for_source(src).add_hex_module("wobble", "pub type Wibble(a) = List(a)"), 4125 find_position_of("wob.").select_until(find_position_of("Wibble")), 4126 ); 4127} 4128 4129#[test] 4130fn test_qualified_to_unqualified_import_below_constructor() { 4131 let src = r#" 4132 4133pub fn main() { 4134 option.Some(1) 4135} 4136 4137import option 4138"#; 4139 assert_code_action!( 4140 "Unqualify option.Some", 4141 TestProject::for_source(src) 4142 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4143 find_position_of(".Some").select_until(find_position_of("(1)")), 4144 ); 4145} 4146 4147#[test] 4148fn test_qualified_to_unqualified_import_between_constructors() { 4149 let src = r#" 4150 4151pub fn main() { 4152 option.Some(1) 4153} 4154 4155import option 4156 4157pub fn identity(x: option.Option(Int)) -> option.Option(Int) { 4158 option.Some(1) 4159 x 4160} 4161"#; 4162 assert_code_action!( 4163 "Unqualify option.Some", 4164 TestProject::for_source(src) 4165 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4166 find_position_of(".Some").select_until(find_position_of("(1)")), 4167 ); 4168} 4169 4170#[test] 4171fn test_qualified_to_unqualified_import_multiple_line() { 4172 let src = r#" 4173import option.{ 4174 type Option, 4175 None, 4176} 4177 4178pub fn main() { 4179 option.Some(1) 4180} 4181"#; 4182 assert_code_action!( 4183 "Unqualify option.Some", 4184 TestProject::for_source(src) 4185 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4186 find_position_of(".Some").select_until(find_position_of("(1)")), 4187 ); 4188} 4189 4190#[test] 4191fn test_qualified_to_unqualified_import_multiple_line_bad_format_with_trailing_comma() { 4192 let src = r#" 4193import option.{type Option, 4194 None, 4195 4196} 4197 4198pub fn main() { 4199 option.Some(1) 4200} 4201"#; 4202 assert_code_action!( 4203 "Unqualify option.Some", 4204 TestProject::for_source(src) 4205 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4206 find_position_of(".Some").select_until(find_position_of("(1)")), 4207 ); 4208} 4209 4210#[test] 4211fn test_qualified_to_unqualified_import_multiple_line_bad_format_multiple_whitespace() { 4212 let src = r#" 4213import option.{ } 4214 4215pub fn main() { 4216 option.Some(1) 4217} 4218"#; 4219 assert_code_action!( 4220 "Unqualify option.Some", 4221 TestProject::for_source(src) 4222 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4223 find_position_of(".Some").select_until(find_position_of("(1)")), 4224 ); 4225} 4226#[test] 4227fn test_qualified_to_unqualified_import_multiple_line_bad_format_without_trailing_comma() { 4228 let src = r#" 4229import option.{type Option, 4230 None 4231 4232} 4233 4234pub fn main() { 4235 option.Some(1) 4236} 4237"#; 4238 assert_code_action!( 4239 "Unqualify option.Some", 4240 TestProject::for_source(src) 4241 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4242 find_position_of(".Some").select_until(find_position_of("(1)")), 4243 ); 4244} 4245#[test] 4246fn test_qualified_to_unqualified_import_multiple_line_aliased() { 4247 let src = r#" 4248import option.{ 4249 type Option, 4250 None} as opt 4251 4252pub fn main() { 4253 opt.Some(1) 4254} 4255"#; 4256 assert_code_action!( 4257 "Unqualify opt.Some", 4258 TestProject::for_source(src) 4259 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4260 find_position_of(".Some").select_until(find_position_of("(1)")), 4261 ); 4262} 4263 4264#[test] 4265fn test_qualified_to_unqualified_import_in_list_and_tuple() { 4266 let src = r#" 4267import option 4268 4269pub fn main() { 4270 let list = [option.Some(1), option.None] 4271 let tuple = #(option.Some(2), option.None) 4272} 4273"#; 4274 assert_code_action!( 4275 "Unqualify option.Some", 4276 TestProject::for_source(src) 4277 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4278 find_position_of("option.Some").select_until(find_position_of("(1)")), 4279 ); 4280} 4281 4282#[test] 4283fn test_qualified_to_unqualified_import_multiple_generic_type() { 4284 let src = r#" 4285import result 4286 4287pub fn main() -> result.Result(Int, String) { 4288 result.Ok(1) 4289} 4290"#; 4291 assert_code_action!( 4292 "Unqualify result.Result", 4293 TestProject::for_source(src) 4294 .add_hex_module("result", "pub type Result(a, e) { Ok(a) Error(e) }"), 4295 find_position_of(".Result").select_until(find_position_of("(Int")), 4296 ); 4297} 4298 4299#[test] 4300fn test_qualified_to_unqualified_import_constructor_as_argument() { 4301 let src = r#" 4302import option 4303 4304pub fn main() { 4305 option.map(option.Some(1), fn(x) { x + 1 }) 4306} 4307"#; 4308 assert_code_action!( 4309 "Unqualify option.Some", 4310 TestProject::for_source(src).add_hex_module( 4311 "option", 4312 " 4313 pub type Option(v) { Some(v) None } 4314 pub fn map(a, f) { todo } 4315 " 4316 ), 4317 find_position_of("option.Some").select_until(find_position_of("(1)")), 4318 ); 4319} 4320 4321#[test] 4322fn test_qualified_to_unqualified_import_constructor_different_module_same_type_inner() { 4323 let src = r#" 4324import option 4325import opt 4326 4327pub fn main() -> option.Option(opt.Option(Int)) { 4328 todo 4329} 4330"#; 4331 assert_code_action!( 4332 "Unqualify opt.Option", 4333 TestProject::for_source(src) 4334 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4335 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4336 find_position_of("opt.Option").select_until(find_position_of("(Int)")), 4337 ); 4338} 4339#[test] 4340fn test_qualified_to_unqualified_import_constructor_different_module_same_type_outer() { 4341 let src = r#" 4342import option 4343import opt 4344 4345pub fn main() -> option.Option(opt.Option(Int)) { 4346 todo 4347} 4348"#; 4349 assert_code_action!( 4350 "Unqualify option.Option", 4351 TestProject::for_source(src) 4352 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4353 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4354 find_position_of("option.").select_until(find_position_of("Option(")), 4355 ); 4356} 4357#[test] 4358fn test_qualified_to_unqualified_import_constructor_different_module_same_name_inner() { 4359 let src = r#" 4360import option 4361import opt 4362 4363pub fn main() { 4364 option.Some(opt.Some(1)) 4365 todo 4366} 4367"#; 4368 assert_code_action!( 4369 "Unqualify opt.Some", 4370 TestProject::for_source(src) 4371 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4372 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4373 find_position_of("opt.Some").select_until(find_position_of("(1)")), 4374 ); 4375} 4376#[test] 4377fn test_qualified_to_unqualified_import_constructor_different_module_same_name_outer() { 4378 let src = r#" 4379import option 4380import opt 4381 4382pub fn main() { 4383 option.Some(opt.Some(1)) 4384} 4385"#; 4386 assert_code_action!( 4387 "Unqualify option.Some", 4388 TestProject::for_source(src) 4389 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4390 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4391 find_position_of("option.").select_until(find_position_of("Some(")), 4392 ); 4393} 4394 4395#[test] 4396fn test_qualified_to_unqualified_import_constructor_complex_pattern() { 4397 let src = r#" 4398import option 4399 4400pub fn main() { 4401 case [option.Some(1), option.None] { 4402 [option.None, ..] -> todo 4403 [option.Some(_), ..] -> todo 4404 _ -> todo 4405 } 4406 case option.Some(1), option.Some(2) { 4407 option.None, option.Some(_) -> todo 4408 option.Some(_), option.Some(val) -> todo 4409 _ -> todo 4410 } 4411} 4412"#; 4413 assert_code_action!( 4414 "Unqualify option.Some", 4415 TestProject::for_source(src) 4416 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4417 find_position_of("option.").select_until(find_position_of("Some(")), 4418 ); 4419} 4420 4421#[test] 4422fn test_qualified_to_unqualified_import_constructor_constructor_name_exists() { 4423 let src = r#" 4424import option.{Some} 4425import opt 4426 4427pub fn main() -> option.Option(opt.Option(Int)) { 4428 Some(opt.Some(1)) 4429} 4430"#; 4431 let title = "Unqualify opt.Some"; 4432 assert_no_code_actions!( 4433 title, 4434 TestProject::for_source(src) 4435 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4436 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4437 find_position_of("opt.").select_until(find_position_of(".Some(")), 4438 ); 4439} 4440 4441#[test] 4442fn test_qualified_to_unqualified_import_constructor_constructor_name_exists_below() { 4443 let src = r#" 4444import opt 4445 4446pub fn main() -> option.Option(opt.Option(Int)) { 4447 Some(opt.Some(1)) 4448} 4449import option.{Some} 4450"#; 4451 let title = "Unqualify opt.Some"; 4452 assert_no_code_actions!( 4453 title, 4454 TestProject::for_source(src) 4455 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4456 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4457 find_position_of("opt.").select_until(find_position_of(".Some(")), 4458 ); 4459} 4460 4461#[test] 4462fn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists() { 4463 let src = r#" 4464import option.{type Option} 4465import opt 4466 4467pub fn main() -> Option(opt.Option(Int)) { 4468 option.Some(opt.Some(1)) 4469} 4470"#; 4471 let title = "Unqualify opt.Option"; 4472 assert_no_code_actions!( 4473 title, 4474 TestProject::for_source(src) 4475 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4476 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4477 find_position_of("opt.").select_until(find_position_of(".Option(")), 4478 ); 4479} 4480 4481#[test] 4482fn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists_below() { 4483 let src = r#" 4484import opt 4485 4486pub fn main() -> Option(opt.Option(Int)) { 4487 option.Some(opt.Some(1)) 4488} 4489import option.{type Option} 4490"#; 4491 let title = "Unqualify opt.Option"; 4492 assert_no_code_actions!( 4493 title, 4494 TestProject::for_source(src) 4495 .add_hex_module("option", "pub type Option(v) { Some(v) None }") 4496 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"), 4497 find_position_of("opt.").select_until(find_position_of(".Option(")), 4498 ); 4499} 4500 4501#[test] 4502fn test_qualified_to_unqualified_import_in_constant_var() { 4503 let src = r#" 4504import option 4505 4506const none = option.None 4507"#; 4508 let title = "Unqualify option.None"; 4509 assert_code_action!( 4510 title, 4511 TestProject::for_source(src) 4512 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4513 find_position_of("None").to_selection(), 4514 ); 4515} 4516 4517#[test] 4518fn test_qualified_to_unqualified_import_in_constant_record() { 4519 let src = r#" 4520import option 4521 4522const some = option.Some(1) 4523"#; 4524 let title = "Unqualify option.Some"; 4525 assert_code_action!( 4526 title, 4527 TestProject::for_source(src) 4528 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4529 find_position_of("Some").to_selection(), 4530 ); 4531} 4532 4533#[test] 4534fn test_qualified_to_unqualified_import_in_nested_constant() { 4535 let src = r#" 4536import option 4537 4538type Result(a) { 4539 Result(expected: a, actual: option.Option(a)) 4540} 4541 4542const zero = Result(0, option.None) 4543"#; 4544 let title = "Unqualify option.None"; 4545 assert_code_action!( 4546 title, 4547 TestProject::for_source(src) 4548 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4549 find_position_of("None").to_selection(), 4550 ); 4551} 4552 4553#[test] 4554fn test_qualified_to_unqualified_import_constant_multiple_occurrences() { 4555 let src = r#" 4556import option 4557 4558const a = option.None 4559const b = option.Some(option.None) 4560"#; 4561 let title = "Unqualify option.None"; 4562 assert_code_action!( 4563 title, 4564 TestProject::for_source(src) 4565 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4566 find_position_of("None").nth_occurrence(1).to_selection(), 4567 ); 4568} 4569 4570#[test] 4571fn test_qualified_to_unqualified_import_not_offered_for_function_in_constant() { 4572 let src = r#" 4573import list 4574 4575const mapper = list.map 4576"#; 4577 4578 let title = "Unqualify list.map"; 4579 assert_no_code_actions!( 4580 title, 4581 TestProject::for_source(src).add_hex_module("list", "pub fn map(list, f) { todo }"), 4582 find_position_of("list.map").to_selection(), 4583 ); 4584} 4585 4586#[test] 4587fn test_qualified_to_unqualified_import_not_offered_for_module_constant_in_constant() { 4588 let src = r#" 4589import mymath 4590 4591const x = mymath.pi 4592"#; 4593 4594 let title = "Unqualify mymath.pi"; 4595 assert_no_code_actions!( 4596 title, 4597 TestProject::for_source(src).add_hex_module("mymath", "pub const pi = 3.14159"), 4598 find_position_of("pi").to_selection(), 4599 ); 4600} 4601 4602#[test] 4603fn test_qualified_to_unqualified_import_from_constant_also_updates_functions() { 4604 let src = r#" 4605import option 4606 4607const default = option.None 4608 4609pub fn get_or_default(value: a) { 4610 case value { 4611 option.Some(x) -> x 4612 option.None -> value 4613 } 4614} 4615"#; 4616 let title = "Unqualify option.None"; 4617 assert_code_action!( 4618 title, 4619 TestProject::for_source(src) 4620 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4621 find_position_of("None").nth_occurrence(1).to_selection(), 4622 ); 4623} 4624 4625#[test] 4626fn test_qualified_to_unqualified_import_from_function_also_updates_constants() { 4627 let src = r#" 4628import option 4629 4630const default = option.None 4631 4632pub fn get_or_default(value: a) { 4633 case value { 4634 option.Some(x) -> x 4635 option.None -> value 4636 } 4637} 4638"#; 4639 let title = "Unqualify option.None"; 4640 assert_code_action!( 4641 title, 4642 TestProject::for_source(src) 4643 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4644 find_position_of("None").nth_occurrence(2).to_selection(), 4645 ); 4646} 4647 4648#[test] 4649fn test_unqualified_to_qualified_import_function() { 4650 let src = r#" 4651import list.{map} 4652 4653pub fn main() { 4654 let identity = map([1, 2, 3], fn(x) { x }) 4655 let double = map([1, 2, 3], fn(x) { x * 2 }) 4656} 4657"#; 4658 assert_code_action!( 4659 "Qualify map as list.map", 4660 TestProject::for_source(src).add_hex_module("list", "pub fn map(list, f) { todo }"), 4661 find_position_of("map").nth_occurrence(2).to_selection(), 4662 ); 4663} 4664 4665#[test] 4666fn test_unqualified_to_qualified_only_triggers_when_within_an_expression() { 4667 let src = r#" 4668import list.{map} 4669 4670pub fn main() { 4671 let identity = map([1, 2, 3], fn(x) { x }) 4672 let double = map([1, 2, 3], fn(x) { x * 2 }) 4673} 4674// end 4675"#; 4676 assert_no_code_actions!( 4677 "Qualify map as list.map", 4678 TestProject::for_source(src).add_hex_module("list", "pub fn map(list, f) { todo }"), 4679 find_position_of("import").select_until(find_position_of("// end")), 4680 ); 4681} 4682 4683#[test] 4684fn test_unqualified_to_qualified_import_constant() { 4685 let src = r#" 4686import mymath.{pi} 4687 4688pub fn circle_area(radius: Float) -> Float { 4689 pi *. radius *. radius 4690} 4691 4692pub fn circle_circumference(radius: Float) -> Float { 4693 2. *. pi *. radius 4694} 4695"#; 4696 assert_code_action!( 4697 "Qualify pi as mymath.pi", 4698 TestProject::for_source(src).add_hex_module("mymath", "pub const pi = 3.14159"), 4699 find_position_of("pi").nth_occurrence(2).to_selection(), 4700 ); 4701} 4702 4703#[test] 4704fn test_unqualified_to_qualified_import_record_constructor() { 4705 let src = r#" 4706import user.{type User, User} 4707 4708pub fn create_user(name: String) -> User { 4709 User(name: name, id: 1) 4710} 4711"#; 4712 assert_code_action!( 4713 "Qualify User as user.User", 4714 TestProject::for_source(src) 4715 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"), 4716 find_position_of("User") 4717 .nth_occurrence(4) 4718 .under_char('s') 4719 .to_selection(), 4720 ); 4721} 4722 4723#[test] 4724fn test_unqualified_to_qualified_import_after_constructor() { 4725 let src = r#" 4726pub fn create_user(name: String) -> User { 4727 User(name: name, id: 1) 4728} 4729 4730import user.{type User, User} 4731"#; 4732 assert_code_action!( 4733 "Qualify User as user.User", 4734 TestProject::for_source(src) 4735 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"), 4736 find_position_of("User").nth_occurrence(2).to_selection(), 4737 ); 4738} 4739 4740#[test] 4741fn test_unqualified_to_qualified_import_between_constructors() { 4742 let src = r#" 4743pub fn create_user(name: String) -> User { 4744 User(name: name, id: 1) 4745} 4746 4747import user.{type User, User} 4748 4749pub fn user_list(users: List(User)) -> List(String) { 4750 [User(name: "John", id: 1), 4751 User(name: "Jane", id: 2)] 4752} 4753 4754"#; 4755 assert_code_action!( 4756 "Qualify User as user.User", 4757 TestProject::for_source(src) 4758 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"), 4759 find_position_of("User").nth_occurrence(2).to_selection(), 4760 ); 4761} 4762 4763#[test] 4764fn test_unqualified_to_qualified_import_multiple_occurrences() { 4765 let src = r#" 4766import list.{map, filter} 4767 4768pub fn process_list(items: List(Int)) -> List(Int) { 4769 items 4770 |> map(fn(x) { x + 1 }) 4771 |> map(fn(x) { x * 2 }) 4772} 4773"#; 4774 assert_code_action!( 4775 "Qualify map as list.map", 4776 TestProject::for_source(src).add_hex_module( 4777 "list", 4778 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4779 ), 4780 find_position_of("map").nth_occurrence(2).to_selection(), 4781 ); 4782} 4783 4784#[test] 4785fn test_unqualified_to_qualified_import_in_pattern_matching() { 4786 let src = r#" 4787import result.{type Result, Ok, Error} 4788 4789pub fn process_result(res: Result(Int, String)) -> Int { 4790 case res { 4791 Ok(value) -> value 4792 Error(_) -> 0 4793 } 4794} 4795"#; 4796 assert_code_action!( 4797 "Qualify Ok as result.Ok", 4798 TestProject::for_source(src) 4799 .add_hex_module("result", "pub type Result(a, e) { Ok(a) Error(e) }"), 4800 find_position_of("Ok").nth_occurrence(2).to_selection(), 4801 ); 4802} 4803 4804#[test] 4805fn test_unqualified_to_qualified_import_type_annotation() { 4806 let src = r#" 4807import option.{type Option, Some} 4808 4809pub fn maybe_increment(x: Option(Int)) -> Option(Int) { 4810 case x { 4811 Some(value) -> Some(value + 1) 4812 _ -> x 4813 } 4814} 4815"#; 4816 assert_code_action!( 4817 "Qualify Option as option.Option", 4818 TestProject::for_source(src) 4819 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4820 find_position_of("Opt") 4821 .nth_occurrence(2) 4822 .select_until(find_position_of("ion").nth_occurrence(3)), 4823 ); 4824} 4825 4826#[test] 4827fn test_unqualified_to_qualified_import_nested_function_call() { 4828 let src = r#" 4829import list.{map, flatten} 4830import operation.{double} 4831 4832pub fn process_names(names: List(List(Int))) -> List(Int) { 4833 names 4834 |> flatten 4835 |> map(double) 4836} 4837"#; 4838 assert_code_action!( 4839 "Qualify double as operation.double", 4840 TestProject::for_source(src) 4841 .add_hex_module( 4842 "list", 4843 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo } 4844pub fn flatten(lists: List(List(a))) -> List(a) { todo }" 4845 ) 4846 .add_hex_module("operation", "pub fn double(s: Int) -> Int { todo }"), 4847 find_position_of("dou") 4848 .nth_occurrence(2) 4849 .select_until(find_position_of("ble").nth_occurrence(2)), 4850 ); 4851} 4852 4853#[test] 4854fn test_unqualified_to_qualified_import_with_alias() { 4855 let src = r#" 4856import list.{map as transform} 4857 4858pub fn double_list(items: List(Int)) -> List(Int) { 4859 transform(items, fn(x) { x * 2 }) 4860} 4861"#; 4862 assert_code_action!( 4863 "Qualify transform as list.map", 4864 TestProject::for_source(src).add_hex_module( 4865 "list", 4866 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4867 ), 4868 find_position_of("transform") 4869 .nth_occurrence(2) 4870 .to_selection(), 4871 ); 4872} 4873 4874#[test] 4875fn test_unqualified_to_qualified_import_with_alias_and_module_alias() { 4876 let src = r#" 4877import list.{map as transform} as lst 4878 4879pub fn double_list(items: List(Int)) -> List(Int) { 4880 transform(items, fn(x) { x * 2 }) 4881} 4882"#; 4883 assert_code_action!( 4884 "Qualify transform as lst.map", 4885 TestProject::for_source(src).add_hex_module( 4886 "list", 4887 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4888 ), 4889 find_position_of("transform") 4890 .nth_occurrence(2) 4891 .to_selection(), 4892 ); 4893} 4894 4895#[test] 4896fn test_unqualified_to_qualified_import_import_discarded() { 4897 let src = r#" 4898import list.{map as transform} as _ 4899 4900pub fn double_list(items: List(Int)) -> List(Int) { 4901 transform(items, fn(x) { x * 2 }) 4902} 4903"#; 4904 let title = "Qualify transform as list.map"; 4905 assert_no_code_actions!( 4906 title, 4907 TestProject::for_source(src).add_hex_module( 4908 "list", 4909 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }" 4910 ), 4911 find_position_of("transform") 4912 .nth_occurrence(2) 4913 .to_selection(), 4914 ); 4915} 4916 4917#[test] 4918fn test_unqualified_to_qualified_import_bad_formatted_type_constructor() { 4919 let src = r#" 4920import option.{type Option, Some} 4921 4922pub fn maybe_increment(x: Option(Int)) -> Option(Int) { 4923 case x { 4924 Some(value) -> Some(value + 1) 4925 _ -> x 4926 } 4927} 4928"#; 4929 assert_code_action!( 4930 "Qualify Option as option.Option", 4931 TestProject::for_source(src) 4932 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4933 find_position_of("Opt") 4934 .nth_occurrence(2) 4935 .select_until(find_position_of("ion").nth_occurrence(3)), 4936 ); 4937} 4938 4939#[test] 4940fn test_unqualified_to_qualified_import_bad_formatted_type_constructor_with_alias() { 4941 let src = r#" 4942import option.{type Option as Maybe, Some} 4943 4944pub fn maybe_increment(x: Maybe(Int)) -> Maybe(Int) { 4945 case x { 4946 Some(value) -> Some(value + 1) 4947 _ -> x 4948 } 4949} 4950"#; 4951 assert_code_action!( 4952 "Qualify Maybe as option.Option", 4953 TestProject::for_source(src) 4954 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4955 find_position_of("May") 4956 .nth_occurrence(2) 4957 .select_until(find_position_of("be").nth_occurrence(3)), 4958 ); 4959} 4960 4961#[test] 4962fn test_unqualified_to_qualified_import_bad_formatted_comma() { 4963 let src = r#" 4964import option.{type Option , Some} 4965 4966pub fn maybe_increment(x: Option(Int)) -> Option(Int) { 4967 case x { 4968 Some(value) -> Some(value + 1) 4969 _ -> x 4970 } 4971} 4972"#; 4973 assert_code_action!( 4974 "Qualify Option as option.Option", 4975 TestProject::for_source(src) 4976 .add_hex_module("option", "pub type Option(a) { Some(a) None }"), 4977 find_position_of("Opt") 4978 .nth_occurrence(2) 4979 .select_until(find_position_of("ion").nth_occurrence(3)), 4980 ); 4981} 4982 4983#[test] 4984fn test_unqualified_to_qualified_import_in_list_and_tuple() { 4985 let src = r#" 4986import option.{Some} 4987 4988pub fn main() { 4989 let list = [Some(1), option.None] 4990 let tuple = #(Some(2), option.None) 4991} 4992"#; 4993 assert_code_action!( 4994 "Qualify Some as option.Some", 4995 TestProject::for_source(src) 4996 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 4997 find_position_of("Some(1)").select_until(find_position_of("Some(1)").under_char('e')), 4998 ); 4999} 5000#[test] 5001fn test_unqualified_to_qualified_import_constructor_complex_pattern() { 5002 let src = r#" 5003import option.{None, Some} 5004 5005pub fn main() { 5006 case [Some(1), None] { 5007 [None, ..] -> todo 5008 [Some(_), ..] -> todo 5009 _ -> todo 5010 } 5011 case Some(1), Some(2) { 5012 None, Some(_) -> todo 5013 Some(_), Some(val) -> todo 5014 _ -> todo 5015 } 5016} 5017"#; 5018 assert_code_action!( 5019 "Qualify Some as option.Some", 5020 TestProject::for_source(src) 5021 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 5022 find_position_of("Some(1)").select_until(find_position_of("Some(1)").under_char('e')), 5023 ); 5024} 5025 5026#[test] 5027fn test_unqualified_to_qualified_import_multiple_line_aliased() { 5028 let src = r#" 5029import option.{ 5030 type Option, 5031 None, 5032 Some 5033} as opt 5034 5035pub fn main() { 5036 Some(1) 5037} 5038"#; 5039 assert_code_action!( 5040 "Qualify Some as opt.Some", 5041 TestProject::for_source(src) 5042 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 5043 find_position_of("Some") 5044 .nth_occurrence(2) 5045 .select_until(find_position_of("(1)")), 5046 ); 5047} 5048 5049#[test] 5050fn test_unqualified_to_qualified_import_multiple_line_bad_format_without_trailing_comma() { 5051 let src = r#" 5052import option.{type Option, 5053 Some 5054 5055} 5056 5057pub fn main() { 5058 Some(1) 5059} 5060"#; 5061 assert_code_action!( 5062 "Qualify Some as option.Some", 5063 TestProject::for_source(src) 5064 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 5065 find_position_of("Some") 5066 .nth_occurrence(2) 5067 .select_until(find_position_of("(1)")), 5068 ); 5069} 5070 5071#[test] 5072fn test_unqualified_to_qualified_import_variable_shadowing() { 5073 let src = r#" 5074 5075import wibble.{wobble} 5076 5077pub fn example() { 5078 echo wobble 5079 5080 let wobble = 1 5081 5082 echo wobble 5083 5084 let _ = fn(wobble) { 5085 echo wobble 5086 } 5087 5088 todo 5089} 5090"#; 5091 5092 assert_code_action!( 5093 "Qualify wobble as wibble.wobble", 5094 TestProject::for_source(src).add_hex_module("wibble", "pub fn wobble() { todo }"), 5095 find_position_of("wob") 5096 .nth_occurrence(2) 5097 .select_until(find_position_of("ble").nth_occurrence(3)) 5098 ); 5099} 5100 5101#[test] 5102fn test_unqualified_to_qualified_import_in_constant_var() { 5103 let src = r#" 5104import option.{None} 5105 5106const none = None 5107"#; 5108 let title = "Qualify None as option.None"; 5109 assert_code_action!( 5110 title, 5111 TestProject::for_source(src) 5112 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 5113 find_position_of("None").nth_occurrence(2).to_selection(), 5114 ); 5115} 5116 5117#[test] 5118fn test_unqualified_to_qualified_import_in_constant_record() { 5119 let src = r#" 5120import option.{Some} 5121 5122const some = Some(1) 5123"#; 5124 let title = "Qualify Some as option.Some"; 5125 assert_code_action!( 5126 title, 5127 TestProject::for_source(src) 5128 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 5129 find_position_of("Some").nth_occurrence(2).to_selection() 5130 ); 5131} 5132 5133#[test] 5134fn test_unqualified_to_qualified_import_in_nested_constant() { 5135 let src = r#" 5136import option.{type Option, None} 5137 5138type Result(a) { 5139 Result(expected: a, actual: Option(a)) 5140} 5141 5142const zero = Result(0, None) 5143"#; 5144 let title = "Qualify None as option.None"; 5145 assert_code_action!( 5146 title, 5147 TestProject::for_source(src) 5148 .add_hex_module("option", "pub type Option(v) { Some(v) None }"), 5149 find_position_of("None").nth_occurrence(2).to_selection(), 5150 ); 5151} 5152 5153/* TODO: implement qualified unused location 5154#[test] 5155fn test_remove_unused_qualified_action() { 5156 let code = " 5157// test 5158import map.{Map, delete} 5159"; 5160 let expected = " 5161// test 5162 5163"; 5164 assert_eq!(remove_unused_action(code), expected.to_string()) 5165} 5166 5167#[test] 5168fn test_remove_unused_qualified_partial_action() { 5169 let code = " 5170// test 5171import result.{is_ok, is_err} 5172 5173pub fn main() { 5174 is_ok 5175} 5176"; 5177 let expected = " 5178// test 5179import result.{is_ok} 5180 5181pub fn main() { 5182 is_ok 5183} 5184"; 5185 assert_eq!(remove_unused_action(code), expected.to_string()) 5186} 5187 5188#[test] 5189fn test_remove_unused_qualified_partial2_action() { 5190 let code = " 5191// test 5192import result.{all, is_ok, is_err} 5193 5194pub fn main() { 5195 is_ok 5196} 5197"; 5198 let expected = " 5199// test 5200import result.{ is_ok} 5201 5202pub fn main() { 5203 is_ok 5204} 5205"; 5206 assert_eq!(remove_unused_action(code), expected.to_string()) 5207} 5208 5209#[test] 5210fn test_remove_unused_qualified_partial3_action() { 5211 let code = " 5212// test 5213import result.{all, is_ok, is_err} as res 5214 5215pub fn main() { 5216 is_ok 5217} 5218"; 5219 let expected = " 5220// test 5221import result.{ is_ok} as res 5222 5223pub fn main() { 5224 is_ok 5225} 5226"; 5227 assert_eq!(remove_unused_action(code), expected.to_string()) 5228} 5229*/ 5230 5231#[test] 5232fn convert_from_use_expression_with_no_parens() { 5233 let src = r#" 5234pub fn main() { 5235 use <- wibble 5236 todo 5237 todo 5238} 5239 5240fn wibble(f) { 5241 f() 5242} 5243"#; 5244 assert_code_action!( 5245 CONVERT_FROM_USE, 5246 TestProject::for_source(src), 5247 find_position_of("use").select_until(find_position_of("wibble")), 5248 ); 5249} 5250 5251#[test] 5252fn convert_from_use_expression_with_empty_parens() { 5253 let src = r#" 5254pub fn main() { 5255 use <- wibble() 5256 todo 5257 todo 5258} 5259 5260fn wibble(f) { 5261 f() 5262} 5263"#; 5264 assert_code_action!( 5265 CONVERT_FROM_USE, 5266 TestProject::for_source(src), 5267 find_position_of("use").to_selection(), 5268 ); 5269} 5270 5271#[test] 5272fn convert_from_use_expression_with_parens_and_other_args() { 5273 let src = r#" 5274pub fn main() { 5275 use <- wibble(1, 2) 5276 todo 5277 todo 5278} 5279 5280fn wibble(n, m, f) { 5281 f() 5282} 5283"#; 5284 assert_code_action!( 5285 CONVERT_FROM_USE, 5286 TestProject::for_source(src), 5287 find_position_of("wibble").select_until(find_position_of("1")), 5288 ); 5289} 5290 5291#[test] 5292fn convert_from_use_expression_with_single_pattern() { 5293 let src = r#" 5294pub fn main() { 5295 use a <- wibble(1, 2) 5296 todo 5297 todo 5298} 5299 5300fn wibble(n, m, f) { 5301 f(1) 5302} 5303"#; 5304 assert_code_action!( 5305 CONVERT_FROM_USE, 5306 TestProject::for_source(src), 5307 find_position_of("a <-").to_selection(), 5308 ); 5309} 5310 5311#[test] 5312fn convert_from_use_expression_with_multiple_patterns() { 5313 let src = r#" 5314pub fn main() { 5315 use a, b <- wibble(1, 2) 5316 todo 5317 todo 5318} 5319 5320fn wibble(n, m, f) { 5321 f(1, 2) 5322} 5323"#; 5324 assert_code_action!( 5325 CONVERT_FROM_USE, 5326 TestProject::for_source(src), 5327 find_position_of("wibble").to_selection(), 5328 ); 5329} 5330 5331#[test] 5332fn desugar_nested_use_expressions_picks_inner_under_cursor() { 5333 let src = r#" 5334pub fn main() { 5335 use a, b <- wibble(1, 2) 5336 use a, b <- wibble(a, b) 5337 todo 5338} 5339 5340fn wibble(n, m, f) { 5341 f(1, 2) 5342} 5343"#; 5344 assert_code_action!( 5345 CONVERT_FROM_USE, 5346 TestProject::for_source(src), 5347 find_position_of("use").nth_occurrence(2).to_selection(), 5348 ); 5349} 5350 5351#[test] 5352fn convert_from_use_only_triggers_on_the_use_line() { 5353 let src = r#" 5354pub fn main() { 5355 use a, b <- wibble(1, 2) 5356 todo 5357} 5358 5359fn wibble(n, m, f) { 5360 f(1, 2) 5361} 5362"#; 5363 assert_no_code_actions!( 5364 CONVERT_FROM_USE, 5365 TestProject::for_source(src), 5366 find_position_of("todo").to_selection(), 5367 ); 5368} 5369 5370#[test] 5371fn desugar_nested_use_expressions_picks_inner_under_cursor_2() { 5372 let src = r#" 5373pub fn main() { 5374 use a, b <- wibble(1, 2) 5375 use a, b <- wibble(a, b) 5376 todo 5377} 5378 5379fn wibble(n, m, f) { 5380 f(1, 2) 5381} 5382"#; 5383 assert_code_action!( 5384 CONVERT_FROM_USE, 5385 TestProject::for_source(src), 5386 find_position_of("<-").select_until(find_position_of("wibble")), 5387 ); 5388} 5389 5390#[test] 5391fn convert_from_use_expression_with_type_annotations() { 5392 let src = r#" 5393pub fn main() { 5394 use a: Int, b: Int <- wibble(1, 2) 5395 todo 5396} 5397 5398fn wibble(n, m, f) { 5399 f(1, 2) 5400} 5401"#; 5402 assert_code_action!( 5403 CONVERT_FROM_USE, 5404 TestProject::for_source(src), 5405 find_position_of("<-").select_until(find_position_of("wibble")), 5406 ); 5407} 5408 5409#[test] 5410fn convert_from_use_expression_doesnt_work_with_complex_patterns() { 5411 let src = r#" 5412pub fn main() { 5413 use #(a, b), 1 <- wibble(1, 2) 5414 todo 5415} 5416 5417fn wibble(n, m, f) { 5418 f(todo, todo) 5419} 5420"#; 5421 assert_no_code_actions!( 5422 CONVERT_FROM_USE, 5423 TestProject::for_source(src), 5424 find_position_of("<-").select_until(find_position_of("wibble")), 5425 ); 5426} 5427 5428#[test] 5429fn convert_from_use_with_labels() { 5430 let src = r#" 5431pub fn main() { 5432 use a <- wibble(one: 1, two: 2) 5433 todo 5434} 5435 5436fn wibble(one _, two _, three f) { 5437 f(1) 5438} 5439"#; 5440 assert_code_action!( 5441 CONVERT_FROM_USE, 5442 TestProject::for_source(src), 5443 find_position_of("use").to_selection(), 5444 ); 5445} 5446 5447#[test] 5448fn convert_from_use_with_labels_2() { 5449 let src = r#" 5450pub fn main() { 5451 use a <- wibble(1, two: 2) 5452 todo 5453} 5454 5455fn wibble(one _, two _, three f) { 5456 f(1) 5457} 5458"#; 5459 assert_code_action!( 5460 CONVERT_FROM_USE, 5461 TestProject::for_source(src), 5462 find_position_of("use").to_selection(), 5463 ); 5464} 5465 5466#[test] 5467fn convert_from_use_with_labels_3() { 5468 let src = r#" 5469pub fn main() { 5470 use a <- wibble(1, three: 3) 5471 todo 5472} 5473 5474fn wibble(one _, two f, three _) { 5475 f(1) 5476} 5477"#; 5478 assert_code_action!( 5479 CONVERT_FROM_USE, 5480 TestProject::for_source(src), 5481 find_position_of("use").to_selection(), 5482 ); 5483} 5484 5485#[test] 5486fn convert_from_use_with_labels_4() { 5487 let src = r#" 5488pub fn main() { 5489 use a <- wibble(two: 2, three: 3) 5490 todo 5491} 5492 5493fn wibble(one f, two _, three _) { 5494 f(1) 5495} 5496"#; 5497 assert_code_action!( 5498 CONVERT_FROM_USE, 5499 TestProject::for_source(src), 5500 find_position_of("use").to_selection(), 5501 ); 5502} 5503 5504#[test] 5505// https://github.com/gleam-lang/gleam/issues/4149 5506fn convert_from_use_with_trailing_comma() { 5507 let src = r#" 5508pub fn main() { 5509 use a, b <- wibble(1, 2,) 5510 todo 5511} 5512 5513fn wibble(n, m, f) { 5514 f(todo, todo) 5515} 5516"#; 5517 assert_code_action!( 5518 CONVERT_FROM_USE, 5519 TestProject::for_source(src), 5520 find_position_of("<-").select_until(find_position_of("wibble")), 5521 ); 5522} 5523 5524#[test] 5525fn convert_from_use_with_trailing_comma_2() { 5526 let src = r#" 5527pub fn main() { 5528 use a, b <- wibble( 5529 1, 5530 2, 5531 ) 5532 todo 5533} 5534 5535fn wibble(n, m, f) { 5536 f(todo, todo) 5537} 5538"#; 5539 assert_code_action!( 5540 CONVERT_FROM_USE, 5541 TestProject::for_source(src), 5542 find_position_of("<-").select_until(find_position_of("wibble")), 5543 ); 5544} 5545 5546#[test] 5547fn convert_from_use_with_trailing_comma_and_label() { 5548 let src = r#" 5549pub fn main() { 5550 use a, b <- wibble( 5551 1, 5552 wibble: 2, 5553 ) 5554 todo 5555} 5556 5557fn wibble(n, wibble m, wobble f) { 5558 f(todo, todo) 5559} 5560"#; 5561 assert_code_action!( 5562 CONVERT_FROM_USE, 5563 TestProject::for_source(src), 5564 find_position_of("<-").select_until(find_position_of("wibble")), 5565 ); 5566} 5567 5568#[test] 5569fn convert_from_use_multiline_with_no_trailing_comma() { 5570 let src = r#" 5571pub fn main() { 5572 use a, b <- wibble( 5573 1, 5574 2 5575 ) 5576 todo 5577} 5578 5579fn wibble(n, m, f) { 5580 f(todo, todo) 5581} 5582"#; 5583 assert_code_action!( 5584 CONVERT_FROM_USE, 5585 TestProject::for_source(src), 5586 find_position_of("<-").select_until(find_position_of("wibble")), 5587 ); 5588} 5589 5590#[test] 5591fn turn_call_into_use_with_single_line_body() { 5592 let src = r#" 5593pub fn main() { 5594 wibble(fn(a, b) { todo }) 5595} 5596 5597fn wibble(f) { 5598 f(todo, todo) 5599} 5600"#; 5601 assert_code_action!( 5602 CONVERT_TO_USE, 5603 TestProject::for_source(src), 5604 find_position_of("wibble").to_selection(), 5605 ); 5606} 5607 5608#[test] 5609fn turn_call_into_use_with_fn_with_no_args() { 5610 let src = r#" 5611pub fn main() { 5612 wibble(fn() { todo }) 5613} 5614 5615fn wibble(f) { 5616 f() 5617} 5618"#; 5619 assert_code_action!( 5620 CONVERT_TO_USE, 5621 TestProject::for_source(src), 5622 find_position_of("wibble").to_selection(), 5623 ); 5624} 5625 5626#[test] 5627fn turn_call_with_multiple_arguments_into_use() { 5628 let src = r#" 5629pub fn main() { 5630 wibble(1, 2, fn(a) { todo }) 5631} 5632 5633fn wibble(m, n, f) { 5634 f(1) 5635} 5636"#; 5637 assert_code_action!( 5638 CONVERT_TO_USE, 5639 TestProject::for_source(src), 5640 find_position_of("todo").to_selection(), 5641 ); 5642} 5643 5644#[test] 5645fn turn_call_with_multiline_fn_into_use() { 5646 let src = r#" 5647pub fn main() { 5648 wibble(1, 2, fn(a) { 5649 todo 5650 case todo { 5651 _ -> todo 5652 } 5653 }) 5654} 5655 5656fn wibble(m, n, f) { 5657 f(1) 5658} 5659"#; 5660 assert_code_action!( 5661 CONVERT_TO_USE, 5662 TestProject::for_source(src), 5663 find_position_of("1, 2").select_until(find_position_of("fn(a)")), 5664 ); 5665} 5666 5667#[test] 5668fn turn_call_with_fn_with_type_annotations_into_use() { 5669 let src = r#" 5670pub fn main() { 5671 wibble(1, 2, fn(a: Int) { 5672 todo 5673 }) 5674} 5675 5676fn wibble(m, n, f) { 5677 f(1) 5678} 5679"#; 5680 assert_code_action!( 5681 CONVERT_TO_USE, 5682 TestProject::for_source(src), 5683 find_position_of("wibble").select_until(find_position_of("a: ")), 5684 ); 5685} 5686 5687#[test] 5688fn turn_call_into_use_only_works_on_last_call_in_a_block() { 5689 let src = r#" 5690pub fn main() { 5691 wibble(10, 20, fn(a) { todo }) 5692 wibble(1, 2, fn(a) { todo }) 5693} 5694 5695fn wibble(m, n, f) { 5696 f(1) 5697} 5698"#; 5699 assert_no_code_actions!( 5700 CONVERT_TO_USE, 5701 TestProject::for_source(src), 5702 find_position_of("10").to_selection(), 5703 ); 5704} 5705 5706#[test] 5707fn turn_call_into_use_only_works_on_last_call_in_a_block_2() { 5708 let src = r#" 5709pub fn main() { 5710 { 5711 wibble(10, 20, fn(a) { todo }) 5712 wibble(1, 2, fn(a) { todo }) 5713 } 5714 Nil 5715} 5716 5717fn wibble(m, n, f) { 5718 f(1) 5719} 5720"#; 5721 assert_no_code_actions!( 5722 CONVERT_TO_USE, 5723 TestProject::for_source(src), 5724 find_position_of("10").to_selection(), 5725 ); 5726} 5727 5728#[test] 5729fn turn_call_into_use_with_last_function_in_a_block() { 5730 let src = r#" 5731pub fn main() { 5732 { 5733 wibble(10, 20, fn(a) { todo }) 5734 wibble(1, 11, fn(a) { todo }) 5735 } 5736 Nil 5737} 5738 5739fn wibble(m, n, f) { 5740 f(1) 5741} 5742"#; 5743 assert_code_action!( 5744 CONVERT_TO_USE, 5745 TestProject::for_source(src), 5746 find_position_of("wibble(1,").select_until(find_position_of("11")), 5747 ); 5748} 5749 5750#[test] 5751fn turn_call_into_use_starts_from_innermost_function() { 5752 let src = r#" 5753pub fn main() { 5754 wibble(10, 20, fn(a) { 5755 wibble(30, 40, fn(b) { 5756 a + b 5757 }) 5758 }) 5759} 5760 5761fn wibble(m, n, f) { 5762 f(1) 5763} 5764"#; 5765 assert_code_action!( 5766 CONVERT_TO_USE, 5767 TestProject::for_source(src), 5768 find_position_of("30").select_until(find_position_of("40")), 5769 ); 5770} 5771 5772#[test] 5773fn turn_call_into_use_with_another_use_in_the_way() { 5774 let src = r#" 5775pub fn main() { 5776 wibble(10, 20, fn(a) { 5777 use b <- wibble(30, 40) 5778 a + b 5779 }) 5780} 5781 5782fn wibble(m, n, f) { 5783 f(1) 5784} 5785"#; 5786 assert_code_action!( 5787 CONVERT_TO_USE, 5788 TestProject::for_source(src), 5789 find_position_of("use").to_selection(), 5790 ); 5791} 5792 5793#[test] 5794fn turn_call_into_use_with_module_function() { 5795 let src = r#" 5796import other 5797pub fn main() { 5798 other.wibble(10, 20, fn(a) { 5799 todo 5800 a + b 5801 }) 5802} 5803"#; 5804 assert_code_action!( 5805 CONVERT_TO_USE, 5806 TestProject::for_source(src).add_module("other", "pub fn wibble(n, m, f) { todo }"), 5807 find_position_of("wibble").to_selection(), 5808 ); 5809} 5810 5811#[test] 5812// https://github.com/gleam-lang/gleam/issues/4498 5813fn turn_call_into_use_with_out_of_order_arguments() { 5814 assert_code_action!( 5815 CONVERT_TO_USE, 5816 r#" 5817pub fn main() { 5818 fold(0, over: [], with: fn (a, b) { todo }) 5819} 5820 5821fn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc { 5822 todo 5823} 5824"#, 5825 find_position_of("fold").to_selection(), 5826 ); 5827} 5828 5829#[test] 5830fn inexhaustive_let_result_to_case() { 5831 assert_code_action!( 5832 CONVERT_TO_CASE, 5833 "pub fn main(result) { 5834 let Ok(value) = result 5835}", 5836 find_position_of("let").select_until(find_position_of("=")), 5837 ); 5838} 5839 5840#[test] 5841fn inexhaustive_let_to_case_indented() { 5842 assert_code_action!( 5843 CONVERT_TO_CASE, 5844 "pub fn main(result) { 5845 { 5846 let Ok(value) = result 5847 } 5848}", 5849 find_position_of("let").select_until(find_position_of("=")), 5850 ); 5851} 5852 5853#[test] 5854fn inexhaustive_let_to_case_multi_variables() { 5855 assert_code_action!( 5856 CONVERT_TO_CASE, 5857 "pub fn main() { 5858 let [var1, var2, _var3, var4] = [1, 2, 3, 4] 5859}", 5860 find_position_of("let").select_until(find_position_of("=")), 5861 ); 5862} 5863 5864#[test] 5865fn inexhaustive_let_to_case_discard() { 5866 assert_code_action!( 5867 CONVERT_TO_CASE, 5868 "pub fn main() { 5869 let [_elem] = [6] 5870}", 5871 find_position_of("let").select_until(find_position_of("=")), 5872 ); 5873} 5874 5875#[test] 5876fn inexhaustive_let_to_case_no_variables() { 5877 assert_code_action!( 5878 CONVERT_TO_CASE, 5879 "pub fn main() { 5880 let [] = [] 5881}", 5882 find_position_of("let").select_until(find_position_of("=")), 5883 ); 5884} 5885 5886#[test] 5887fn inexhaustive_let_alias_to_case() { 5888 assert_code_action!( 5889 CONVERT_TO_CASE, 5890 "pub fn main() { 5891 let 10 as ten = 10 5892}", 5893 find_position_of("let").select_until(find_position_of("=")), 5894 ); 5895} 5896 5897#[test] 5898fn cursor_must_be_within_let_assignment_to_trigger_action() { 5899 assert_no_code_actions!( 5900 CONVERT_TO_CASE, 5901 "pub fn main() { 5902 let 10 as ten = 10 5903}", 5904 find_position_of("pub").select_until(find_position_of("}")), 5905 ); 5906} 5907 5908#[test] 5909fn inexhaustive_let_tuple_to_case() { 5910 assert_code_action!( 5911 CONVERT_TO_CASE, 5912 "pub fn main() { 5913 let #(first, 10, third) = #(5, 10, 15) 5914} 5915", 5916 find_position_of("let").select_until(find_position_of("=")), 5917 ); 5918} 5919 5920#[test] 5921fn inexhaustive_let_bit_array_to_case() { 5922 assert_code_action!( 5923 CONVERT_TO_CASE, 5924 "pub fn main() { 5925 let <<bits1, bits2>> = <<73, 98>> 5926}", 5927 find_position_of("let").select_until(find_position_of("=")), 5928 ); 5929} 5930 5931#[test] 5932fn inexhaustive_let_string_prefix_to_case() { 5933 assert_code_action!( 5934 CONVERT_TO_CASE, 5935 r#"pub fn main() { 5936 let "_" <> thing = "_Hello" 5937}"#, 5938 find_position_of("let").select_until(find_position_of("=")), 5939 ); 5940} 5941 5942#[test] 5943fn inexhaustive_let_string_prefix_pattern_alias_to_case() { 5944 assert_code_action!( 5945 CONVERT_TO_CASE, 5946 r#"pub fn main() { 5947 let "123" as one_two_three <> rest = "123456" 5948}"#, 5949 find_position_of("let").select_until(find_position_of("=")), 5950 ); 5951} 5952 5953#[test] 5954fn inner_inexhaustive_let_to_case() { 5955 assert_code_action!( 5956 CONVERT_TO_CASE, 5957 r#"pub fn main(result) { 5958 let [wibble] = { 5959 let Ok(wobble) = { 5960 result 5961 } 5962 [wobble] 5963 } 5964}"#, 5965 find_position_of("let Ok").select_until(find_position_of(") =")), 5966 ); 5967} 5968 5969#[test] 5970fn outer_inexhaustive_let_to_case() { 5971 assert_code_action!( 5972 CONVERT_TO_CASE, 5973 r#"pub fn main(result) { 5974 let [wibble] = { 5975 let Ok(wobble) = { 5976 result 5977 } 5978 [wobble] 5979 } 5980}"#, 5981 find_position_of("let [").select_until(find_position_of("] =")), 5982 ); 5983} 5984 5985#[test] 5986fn second_sibling_inexhaustive_let_to_case() { 5987 assert_code_action!( 5988 CONVERT_TO_CASE, 5989 r#"pub fn main(a, b) { 5990 let Ok(x) = a 5991 let Ok(y) = b 5992 #(x, y) 5993}"#, 5994 find_position_of("let Ok(y)").select_until(find_position_of("= b")), 5995 ); 5996} 5997 5998#[test] 5999fn no_code_action_for_exhaustive_let_to_case() { 6000 assert_no_code_actions!( 6001 CONVERT_TO_CASE, 6002 r#"pub fn first(pair) { 6003 let #(first, second) = pair 6004 first 6005}"#, 6006 find_position_of("let").select_until(find_position_of("=")), 6007 ); 6008} 6009 6010#[test] 6011fn extract_variable() { 6012 assert_code_action!( 6013 EXTRACT_VARIABLE, 6014 r#"pub fn main() { 6015 list.map([1, 2, 3], int.add(1, _)) 6016}"#, 6017 find_position_of("[1").select_until(find_position_of("2")) 6018 ); 6019} 6020 6021#[test] 6022fn extract_can_extract_number_used_as_call_argument() { 6023 assert_code_action!( 6024 EXTRACT_VARIABLE, 6025 r#"pub fn main() { 6026 wibble(label: 1) 6027}"#, 6028 find_position_of("1").to_selection() 6029 ); 6030} 6031 6032#[test] 6033fn extract_can_extract_bool_used_as_call_argument() { 6034 assert_code_action!( 6035 EXTRACT_VARIABLE, 6036 r#"pub fn main() { 6037 wibble(label: True) 6038}"#, 6039 find_position_of("True").to_selection() 6040 ); 6041} 6042 6043#[test] 6044fn extract_variable_ignores_names_in_other_branches() { 6045 assert_code_action!( 6046 EXTRACT_VARIABLE, 6047 r#"pub fn main(x: Result(_, _)) { 6048 case x { 6049 Ok(_) -> { 6050 let int = 1 6051 int + 2 6052 } 6053 Error(_) -> wibble(11) 6054 } 6055 6056}"#, 6057 find_position_of("11").to_selection() 6058 ); 6059} 6060 6061#[test] 6062fn extract_variable_ignores_names_in_other_branches_2() { 6063 assert_code_action!( 6064 EXTRACT_VARIABLE, 6065 r#" 6066pub fn main(x: Result(_, _)) { 6067 case x { 6068 Ok(_) -> { 6069 let int = 1 6070 int + 2 6071 } 6072 Error(_) -> { 6073 wibble(11) 6074 } 6075 } 6076} 6077"#, 6078 find_position_of("11").to_selection() 6079 ); 6080} 6081 6082#[test] 6083fn extract_variable_ignores_names_in_other_blocks() { 6084 assert_code_action!( 6085 EXTRACT_VARIABLE, 6086 r#" 6087pub fn main() { 6088 { 6089 let int = 1 6090 int + 2 6091 } 6092 wibble(11) 6093} 6094"#, 6095 find_position_of("11").to_selection() 6096 ); 6097} 6098 6099#[test] 6100fn extract_variable_ignores_names_in_anonymous_functions() { 6101 assert_code_action!( 6102 EXTRACT_VARIABLE, 6103 r#" 6104pub fn main() { 6105 let fun = fn() { 6106 let int = 1 6107 int + 2 6108 } 6109 6110 wibble(11) 6111} 6112"#, 6113 find_position_of("11").to_selection() 6114 ); 6115} 6116 6117#[test] 6118fn extract_variable_does_not_shadow_names_in_anonymous_function() { 6119 assert_code_action!( 6120 EXTRACT_VARIABLE, 6121 r#" 6122pub fn main() { 6123 let fun = fn() { 6124 let int = 1 6125 wibble(11) 6126 } 6127 fun() 6128} 6129"#, 6130 find_position_of("11").to_selection() 6131 ); 6132} 6133 6134#[test] 6135fn extract_variable_does_not_shadow_name_in_same_branch() { 6136 assert_code_action!( 6137 EXTRACT_VARIABLE, 6138 r#" 6139pub fn main(x: Result(_, _)) { 6140 case x { 6141 Ok(_) -> { 6142 let int = 1 6143 wibble(11) 6144 } 6145 Error(_) -> { 6146 panic 6147 } 6148 } 6149} 6150"#, 6151 find_position_of("11").to_selection() 6152 ); 6153} 6154 6155#[test] 6156fn extract_variable_does_not_shadow_name_in_same_block() { 6157 assert_code_action!( 6158 EXTRACT_VARIABLE, 6159 r#" 6160pub fn main() { 6161 let result = { 6162 let int = 1 6163 wibble(11) 6164 } 6165 result 6166}"#, 6167 find_position_of("11").to_selection() 6168 ); 6169} 6170 6171#[test] 6172fn extract_variable_does_not_extract_a_variable() { 6173 assert_no_code_actions!( 6174 EXTRACT_VARIABLE, 6175 r#"pub fn main() { 6176 let z = 1 6177 let a = [1, 2, z] 6178}"#, 6179 find_position_of("z").nth_occurrence(2).to_selection() 6180 ); 6181} 6182 6183#[test] 6184fn extract_variable_does_not_extract_top_level_statement() { 6185 assert_no_code_actions!( 6186 EXTRACT_VARIABLE, 6187 r#"pub fn main() { 6188 let wibble = 1 6189}"#, 6190 find_position_of("1").to_selection() 6191 ); 6192} 6193 6194#[test] 6195fn extract_variable_does_not_extract_top_level_statement_inside_block() { 6196 assert_no_code_actions!( 6197 EXTRACT_VARIABLE, 6198 r#"pub fn main() { 6199 let x = { 6200 let y = "y" 6201 let w = "w" <> y 6202 w 6203 } 6204}"#, 6205 find_position_of("y").nth_occurrence(2).to_selection() 6206 ); 6207} 6208 6209#[test] 6210fn extract_variable_does_not_extract_top_level_statement_inside_use() { 6211 assert_no_code_actions!( 6212 EXTRACT_VARIABLE, 6213 " 6214pub fn main() { 6215 use x <- try(Ok(1)) 6216 let y = 2 6217 Ok(y + x) 6218} 6219pub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo } 6220", 6221 find_position_of("2").to_selection() 6222 ); 6223} 6224 6225#[test] 6226fn extract_variable_does_not_extract_use() { 6227 assert_no_code_actions!( 6228 EXTRACT_VARIABLE, 6229 " 6230pub fn main() { 6231 use x <- try(Ok(1)) 6232 Ok(x) 6233} 6234pub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo } 6235", 6236 find_position_of("use").to_selection() 6237 ); 6238} 6239 6240#[test] 6241fn extract_variable_does_not_extract_panic() { 6242 assert_no_code_actions!( 6243 EXTRACT_VARIABLE, 6244 r#"pub fn main() { 6245 let x = 1 6246 panic 6247}"#, 6248 find_position_of("panic").to_selection() 6249 ); 6250} 6251 6252#[test] 6253fn extract_variable_does_not_extract_echo() { 6254 assert_no_code_actions!( 6255 EXTRACT_VARIABLE, 6256 r#"pub fn main() { 6257 let x = 1 6258 echo x 6259}"#, 6260 find_position_of("echo").to_selection() 6261 ); 6262} 6263 6264#[test] 6265fn extract_variable_does_not_extract_record_constructor_in_record_update() { 6266 assert_no_code_actions!( 6267 EXTRACT_VARIABLE, 6268 r#" 6269pub fn main() { 6270 Wibble(..todo, a: 1) 6271} 6272 6273pub type Wibble { Wibble(a: Int, b: Int) } 6274"#, 6275 find_position_of("Wibble").to_selection() 6276 ); 6277} 6278 6279#[test] 6280fn extract_variable_does_not_extract_assignment() { 6281 assert_no_code_actions!( 6282 EXTRACT_VARIABLE, 6283 r#"pub fn main() { 6284 let x = 1 6285}"#, 6286 find_position_of("x").to_selection() 6287 ); 6288} 6289 6290#[test] 6291fn extract_variable_does_not_extract_record_variable_in_record_update() { 6292 assert_no_code_actions!( 6293 EXTRACT_VARIABLE, 6294 r#" 6295type Wibble { Wibble(one: Int, two: Int) } 6296 6297pub fn main() { 6298 let wibble = todo 6299 Wibble(..wibble, one: 1) 6300}"#, 6301 find_position_of("wibble").nth_occurrence(2).to_selection() 6302 ); 6303} 6304 6305#[test] 6306fn extract_variable_from_arg_in_pipelined_call() { 6307 assert_code_action!( 6308 EXTRACT_VARIABLE, 6309 " 6310pub fn main() { 6311 let adder = add 6312 let x = [4, 5, 6] |> map2([1, 2, 3], adder) 6313 x 6314} 6315pub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo } 6316pub fn add(a: Int, b: Int) -> Int { todo } 6317", 6318 find_position_of("[1").to_selection() 6319 ); 6320} 6321 6322#[test] 6323fn extract_variable_from_arg_in_pipelined_call_to_capture() { 6324 assert_code_action!( 6325 EXTRACT_VARIABLE, 6326 " 6327pub fn main() { 6328 let adder = add 6329 let x = adder |> reduce([1, 2, 3], _) 6330 x 6331} 6332pub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo } 6333pub fn add(a: Int, b: Int) -> Int { todo } 6334", 6335 find_position_of("[1").to_selection() 6336 ); 6337} 6338 6339#[test] 6340fn extract_variable_from_arg_in_pipelined_call_of_function_to_capture() { 6341 assert_code_action!( 6342 EXTRACT_VARIABLE, 6343 " 6344pub fn main() { 6345 fn(total, item) { total + item } 6346 |> fold(with: _, from: 0, over: [1, 2, 3]) 6347} 6348pub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo } 6349", 6350 find_position_of("fold").to_selection() 6351 ); 6352} 6353 6354#[test] 6355fn extract_variable_from_arg_in_nested_function_called_in_pipeline() { 6356 assert_code_action!( 6357 EXTRACT_VARIABLE, 6358 " 6359pub fn main() { 6360 let result = 6361 [1, 2, 3] 6362 |> map(add(_, 1)) 6363 |> map(subtract(_, 9)) 6364 6365 result 6366} 6367pub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 6368pub fn add(a: Int, b: Int) -> Int { todo } 6369pub fn subtract(a: Int, b: Int) -> Int { todo } 6370", 6371 find_position_of("9").to_selection() 6372 ); 6373} 6374 6375#[test] 6376fn extract_variable_does_not_extract_an_entire_pipeline_step() { 6377 assert_no_code_actions!( 6378 EXTRACT_VARIABLE, 6379 " 6380pub fn main() { 6381 [1, 2, 3] 6382 |> map(todo) 6383 |> map(todo) 6384} 6385 6386fn map(list, fun) { todo } 6387", 6388 find_position_of("map").to_selection() 6389 ); 6390} 6391 6392#[test] 6393fn extract_variable_does_not_extract_the_last_pipeline_step() { 6394 assert_no_code_actions!( 6395 EXTRACT_VARIABLE, 6396 r#"pub fn main() { 6397 [1, 2, 3] 6398 |> map(todo) 6399 |> map(todo) 6400} 6401 6402fn map(list, fun) { todo } 6403"#, 6404 find_position_of("map").to_selection() 6405 ); 6406} 6407 6408#[test] 6409fn extract_variable_2() { 6410 assert_code_action!( 6411 EXTRACT_VARIABLE, 6412 " 6413pub fn main() { 6414 map([1, 2, 3], add(1, _)) 6415} 6416pub fn add(n, m) { todo } 6417pub fn map(l, f) { todo } 6418", 6419 find_position_of("add").to_selection() 6420 ); 6421} 6422 6423#[test] 6424fn extract_variable_from_capture_arguments() { 6425 assert_no_code_actions!( 6426 EXTRACT_VARIABLE, 6427 r#"pub fn main() { 6428 int.add(1, _) 6429}"#, 6430 find_position_of("_").to_selection() 6431 ); 6432} 6433 6434#[test] 6435fn extract_variable_from_capture_arguments_2() { 6436 assert_code_action!( 6437 EXTRACT_VARIABLE, 6438 r#"pub fn main() { 6439 int.add(11, _) 6440}"#, 6441 find_position_of("11").to_selection() 6442 ); 6443} 6444 6445#[test] 6446fn extract_variable_3() { 6447 assert_code_action!( 6448 EXTRACT_VARIABLE, 6449 r#"pub fn main() { 6450 list.map([1, 2, 3], todo, todo) 6451}"#, 6452 find_position_of("todo") 6453 .nth_occurrence(2) 6454 .select_until(find_position_of("todo)").under_last_char()) 6455 ); 6456} 6457 6458#[test] 6459fn extract_variable_inside_multiline_function_call() { 6460 assert_code_action!( 6461 EXTRACT_VARIABLE, 6462 r#"pub fn main() { 6463 list.map( 6464 [1, 2, 3], 6465 int.add(1, _), 6466 ) 6467}"#, 6468 find_position_of("[1").to_selection() 6469 ); 6470} 6471 6472#[test] 6473fn extract_variable_in_case_branch() { 6474 assert_code_action!( 6475 EXTRACT_VARIABLE, 6476 r#"pub fn main() { 6477 case wibble { 6478 _ -> [1, 2, 3] 6479 } 6480}"#, 6481 find_position_of("[1").to_selection() 6482 ); 6483} 6484 6485#[test] 6486fn extract_variable_in_multiline_case_subject_branch() { 6487 assert_code_action!( 6488 EXTRACT_VARIABLE, 6489 r#"pub fn main() { 6490 case 6491 list.map( 6492 [1, 2, 3], 6493 int.add(1, _) 6494 ) 6495 { 6496 _ -> todo 6497 } 6498}"#, 6499 find_position_of("[1").to_selection() 6500 ); 6501} 6502 6503#[test] 6504fn extract_variable_in_case_branch_using_var() { 6505 assert_code_action!( 6506 EXTRACT_VARIABLE, 6507 r#"pub fn main() { 6508 case todo { 6509 Ok(value) -> 2 * value + 1 6510 Error(_) -> panic 6511 } 6512}"#, 6513 find_position_of("2").select_until(find_position_of("value").nth_occurrence(2)) 6514 ); 6515} 6516 6517#[test] 6518fn extract_variable_in_case_branch_from_second_arg() { 6519 assert_code_action!( 6520 EXTRACT_VARIABLE, 6521 r#"pub fn main() { 6522 case todo { 6523 Ok(_) -> #(Ok(1), Error("s")) 6524 Error(_) -> panic 6525 } 6526}"#, 6527 find_position_of("E").to_selection() 6528 ); 6529} 6530 6531#[test] 6532fn extract_variable_in_use() { 6533 assert_code_action!( 6534 EXTRACT_VARIABLE, 6535 r#"pub fn main() { 6536 use <- wibble([1, 2, 3]) 6537 todo 6538}"#, 6539 find_position_of("[1").to_selection() 6540 ); 6541} 6542 6543#[test] 6544fn extract_variable_inside_use_body() { 6545 assert_code_action!( 6546 EXTRACT_VARIABLE, 6547 r#"pub fn main() { 6548 use <- wibble(todo) 6549 list.map([1, 2, 3], int.add(1, _)) 6550 todo 6551}"#, 6552 find_position_of("[1").to_selection() 6553 ); 6554} 6555 6556#[test] 6557fn extract_variable_in_multiline_use() { 6558 assert_code_action!( 6559 EXTRACT_VARIABLE, 6560 r#"pub fn main() { 6561 use <- wibble( 6562 [1, 2, 3] 6563 ) 6564 todo 6565}"#, 6566 find_position_of("[1").to_selection() 6567 ); 6568} 6569 6570#[test] 6571fn extract_variable_after_nested_anonymous_function() { 6572 assert_code_action!( 6573 EXTRACT_VARIABLE, 6574 r#"pub fn main() { 6575 let f = fn() { 6576 let x = 1 + 2 6577 let ff = fn() { 6578 let y = x + 3 6579 let z = y + x 6580 z 6581 } 6582 let z = x * 4 6583 z 6584 } 6585 let y = 5 + 6 6586 f() 6587}"#, 6588 find_position_of("6").to_selection() 6589 ); 6590} 6591 6592#[test] 6593fn extract_variable_in_nested_anonymous_function() { 6594 assert_code_action!( 6595 EXTRACT_VARIABLE, 6596 r#"pub fn main() { 6597 let f = fn() { 6598 let x = 1 + 2 6599 let ff = fn() { 6600 let y = x + 3 6601 let z = y + x 6602 z 6603 } 6604 let z = x * 4 6605 z 6606 } 6607 let y = 5 + 6 6608 f() 6609}"#, 6610 find_position_of("4").to_selection() 6611 ); 6612} 6613 6614#[test] 6615fn extract_variable_in_double_nested_anonymous_function() { 6616 assert_code_action!( 6617 EXTRACT_VARIABLE, 6618 r#"pub fn main() { 6619 let f = fn() { 6620 let x = 1 + 2 6621 let ff = fn() { 6622 let y = x + 3 6623 let z = y + x 6624 z 6625 } 6626 let z = x * 4 6627 z 6628 } 6629 let y = 5 + 6 6630 f() 6631}"#, 6632 find_position_of("3").to_selection() 6633 ); 6634} 6635 6636#[test] 6637fn extract_variable_in_block() { 6638 assert_code_action!( 6639 EXTRACT_VARIABLE, 6640 r#"pub fn main() { 6641 { 6642 todo 6643 wibble([1, 2, 3]) 6644 todo 6645 } 6646}"#, 6647 find_position_of("2").select_until(find_position_of("3")) 6648 ); 6649} 6650 6651#[test] 6652fn extract_variable_and_dont_shadow_existing_variable_in_operator() { 6653 let src = "import gleam/int 6654import random_import as int_2 6655 6656const int_3 = 3 6657 6658fn int_4() { 4 } 6659 6660fn isolated_scope() { 6661 let int_6 = 6 6662 int_6 + 1 6663} 6664 6665pub fn main() { 6666 let int_5 = 5 6667 let result = int_5 + 6 6668 result 6669} 6670"; 6671 6672 assert_code_action!( 6673 EXTRACT_VARIABLE, 6674 TestProject::for_source(src) 6675 .add_hex_module("gleam/int", "") 6676 .add_hex_module("random_import", ""), 6677 find_position_of("6").nth_occurrence(4).to_selection(), 6678 ); 6679} 6680 6681#[test] 6682fn extract_variable_and_dont_shadow_existing_variable_in_argument() { 6683 assert_code_action!( 6684 EXTRACT_VARIABLE, 6685 r#"fn wibble(a, b) { 6686 a + b 6687} 6688 6689fn main() { 6690 let int = 1 6691 wibble(int, 2) 6692}"#, 6693 find_position_of("2").to_selection() 6694 ); 6695} 6696 6697#[test] 6698fn extract_constant_from_call_argument_with_bit_array() { 6699 assert_code_action!( 6700 EXTRACT_CONSTANT, 6701 r#"import gleam/io 6702 6703pub fn main() { 6704 io.debug(<<3:size(8)>>) 6705}"#, 6706 find_position_of("<").select_until(find_position_of("<").nth_occurrence(2)) 6707 ); 6708} 6709 6710#[test] 6711fn extract_constant_from_call_argument_with_float() { 6712 assert_code_action!( 6713 EXTRACT_CONSTANT, 6714 r#"import gleam/float 6715 6716pub fn main() { 6717 float.ceiling(1.9998) 6718}"#, 6719 find_position_of("1").select_until(find_position_of("8")) 6720 ); 6721} 6722 6723#[test] 6724fn extract_constant_from_call_argument_with_int() { 6725 assert_code_action!( 6726 EXTRACT_CONSTANT, 6727 r#"import gleam/list 6728 6729pub fn main() { 6730 list.sample([4, 5, 6], 2) 6731}"#, 6732 find_position_of("2").to_selection() 6733 ); 6734} 6735 6736#[test] 6737fn extract_constant_from_call_argument_with_list() { 6738 assert_code_action!( 6739 EXTRACT_CONSTANT, 6740 r#"import gleam/io 6741 6742pub fn main() { 6743 io.debug(["constant", "another constant"]) 6744}"#, 6745 find_position_of("[").to_selection() 6746 ); 6747} 6748 6749#[test] 6750fn extract_constant_from_call_argument_with_nested_inside() { 6751 assert_code_action!( 6752 EXTRACT_CONSTANT, 6753 r#"import gleam/list 6754 6755pub fn main() { 6756 list.unzip([#(1, 2), #(3, 4)]) 6757}"#, 6758 find_position_of("#").select_until(find_position_of("(").nth_occurrence(3)) 6759 ); 6760} 6761 6762#[test] 6763fn extract_constant_from_call_argument_with_nested_outside() { 6764 assert_code_action!( 6765 EXTRACT_CONSTANT, 6766 r#"import gleam/list 6767 6768pub fn main() { 6769 list.unzip([#(1, 2), #(3, 4)]) 6770}"#, 6771 find_position_of("[").to_selection() 6772 ); 6773} 6774 6775#[test] 6776fn extract_constant_from_call_argument_with_string() { 6777 assert_code_action!( 6778 EXTRACT_CONSTANT, 6779 r#"import gleam/io 6780 6781pub fn main() { 6782 io.print("constant") 6783}"#, 6784 find_position_of("\"").select_until(find_position_of("\"")) 6785 ); 6786} 6787 6788#[test] 6789fn extract_constant_from_call_argument_with_tuple() { 6790 assert_code_action!( 6791 EXTRACT_CONSTANT, 6792 r#"import gleam/io 6793 6794pub fn main() { 6795 io.debug(#(1, 2, 3)) 6796}"#, 6797 find_position_of("#").select_until(find_position_of("(").nth_occurrence(3)) 6798 ); 6799} 6800 6801#[test] 6802fn extract_constant_from_declaration_of_float() { 6803 assert_code_action!( 6804 EXTRACT_CONSTANT, 6805 r#"pub fn main() { 6806 let c = 3.1415 6807}"#, 6808 find_position_of("3").select_until(find_position_of("5")) 6809 ); 6810} 6811 6812#[test] 6813fn extract_constant_from_whole_declaration_of_float() { 6814 assert_code_action!( 6815 EXTRACT_CONSTANT, 6816 r#"import gleam/io 6817 6818pub fn main() { 6819 let c = 3.1415 6820 io.debug(c) 6821}"#, 6822 find_position_of("l") 6823 .nth_occurrence(2) 6824 .select_until(find_position_of("c")) 6825 ); 6826} 6827 6828#[test] 6829fn extract_constant_from_declaration_of_bit_array() { 6830 assert_code_action!( 6831 EXTRACT_CONSTANT, 6832 r#"pub fn main() { 6833 let b = <<"arr":utf32>> 6834}"#, 6835 find_position_of("u") 6836 .nth_occurrence(2) 6837 .select_until(find_position_of(">").nth_occurrence(2)) 6838 ); 6839} 6840 6841#[test] 6842fn extract_constant_from_whole_declaration_of_bit_array() { 6843 assert_code_action!( 6844 EXTRACT_CONSTANT, 6845 r#"import gleam/io 6846 6847const n = 24 6848 6849pub fn main() { 6850 let bits = <<8080:size(n)>> 6851 bits 6852}"#, 6853 find_position_of("l") 6854 .nth_occurrence(2) 6855 .select_until(find_position_of("s").nth_occurrence(2)) 6856 ); 6857} 6858 6859#[test] 6860fn extract_constant_from_declaration_of_bin_op() { 6861 assert_code_action!( 6862 EXTRACT_CONSTANT, 6863 r#"pub fn main() { 6864 let twelve = "1" <> "2" 6865}"#, 6866 find_position_of("<").to_selection() 6867 ); 6868} 6869 6870#[test] 6871fn extract_constant_from_whole_declaration_of_bin_op() { 6872 assert_code_action!( 6873 EXTRACT_CONSTANT, 6874 r#"import gleam/io 6875 6876pub fn main() { 6877 let twelve = "1" <> "2" 6878 io.print(twelve) 6879}"#, 6880 find_position_of("l") 6881 .nth_occurrence(2) 6882 .select_until(find_position_of("e").nth_occurrence(4)) 6883 ); 6884} 6885 6886#[test] 6887fn extract_constant_from_declaration_of_int() { 6888 assert_code_action!( 6889 EXTRACT_CONSTANT, 6890 r#"pub fn main() { 6891 let c = 125 6892}"#, 6893 find_position_of("1").select_until(find_position_of("5")) 6894 ); 6895} 6896 6897#[test] 6898fn extract_constant_from_whole_declaration_of_int() { 6899 assert_code_action!( 6900 EXTRACT_CONSTANT, 6901 r#"import gleam/io 6902 6903pub fn main() { 6904 let c = 125 6905 io.debug(c) 6906}"#, 6907 find_position_of("l") 6908 .nth_occurrence(2) 6909 .select_until(find_position_of("c")) 6910 ); 6911} 6912 6913#[test] 6914fn extract_constant_from_declaration_of_list() { 6915 assert_code_action!( 6916 EXTRACT_CONSTANT, 6917 r#"pub fn main() { 6918 let c = [3.1415, 0.33333333] 6919}"#, 6920 find_position_of("[").to_selection() 6921 ); 6922} 6923 6924#[test] 6925fn extract_constant_from_whole_declaration_of_list() { 6926 assert_code_action!( 6927 EXTRACT_CONSTANT, 6928 r#"import gleam/io 6929 6930pub fn main() { 6931 let c = [3.1415, 0.33333333] 6932 io.debug(c) 6933}"#, 6934 find_position_of("l") 6935 .nth_occurrence(2) 6936 .select_until(find_position_of("c")) 6937 ); 6938} 6939 6940#[test] 6941fn extract_constant_from_declaration_of_nested_inside() { 6942 assert_code_action!( 6943 EXTRACT_CONSTANT, 6944 r#"pub fn main() { 6945 let c = #([1, 2, 3], [3, 2, 1]) 6946}"#, 6947 find_position_of("[").to_selection() 6948 ); 6949} 6950 6951#[test] 6952fn extract_constant_from_declaration_of_nested_outside() { 6953 assert_code_action!( 6954 EXTRACT_CONSTANT, 6955 r#"pub fn main() { 6956 let c = #([1, 2, 3], [3, 2, 1]) 6957}"#, 6958 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 6959 ); 6960} 6961 6962#[test] 6963fn extract_constant_from_whole_declaration_of_nested() { 6964 assert_code_action!( 6965 EXTRACT_CONSTANT, 6966 r#"import gleam/io 6967 6968pub fn main() { 6969 let c = #([1, 2, 3], [3, 2, 1]) 6970 io.debug(c) 6971}"#, 6972 find_position_of("l") 6973 .nth_occurrence(2) 6974 .select_until(find_position_of("c")) 6975 ); 6976} 6977 6978#[test] 6979fn extract_constant_from_declaration_of_string() { 6980 assert_code_action!( 6981 EXTRACT_CONSTANT, 6982 r#"pub fn main() { 6983 let c = "constant" 6984}"#, 6985 find_position_of("\"").select_until(find_position_of("\"")) 6986 ); 6987} 6988 6989#[test] 6990fn extract_constant_from_whole_declaration_of_string() { 6991 assert_code_action!( 6992 EXTRACT_CONSTANT, 6993 r#"import gleam/io 6994 6995pub fn main() { 6996 let c = "constant" 6997 io.debug(c) 6998}"#, 6999 find_position_of("l") 7000 .nth_occurrence(2) 7001 .select_until(find_position_of("c")) 7002 ); 7003} 7004 7005#[test] 7006fn extract_constant_from_declaration_of_tuple() { 7007 assert_code_action!( 7008 EXTRACT_CONSTANT, 7009 r#"pub fn main() { 7010 let #(one, two, three) = #("one", "two", "three") 7011}"#, 7012 find_position_of("#") 7013 .nth_occurrence(2) 7014 .select_until(find_position_of("(").nth_occurrence(3)) 7015 ); 7016} 7017 7018#[test] 7019fn extract_constant_from_whole_declaration_of_tuple() { 7020 assert_code_action!( 7021 EXTRACT_CONSTANT, 7022 r#"import gleam/io 7023 7024pub fn main() { 7025 let c = #("one", "two", "three") 7026 io.debug(c) 7027}"#, 7028 find_position_of("l") 7029 .nth_occurrence(2) 7030 .select_until(find_position_of("c")) 7031 ); 7032} 7033 7034#[test] 7035fn extract_constant_from_literal_within_list() { 7036 assert_code_action!( 7037 EXTRACT_CONSTANT, 7038 r#"pub fn main() { 7039 let c = ["constant", todo] 7040}"#, 7041 find_position_of("\"").select_until(find_position_of("\"")) 7042 ); 7043} 7044 7045#[test] 7046fn extract_constant_from_list_containing_constant() { 7047 assert_code_action!( 7048 EXTRACT_CONSTANT, 7049 r#"const something = "something" 7050 7051pub fn main() { 7052 let c = ["constant", something] 7053}"#, 7054 find_position_of("[").to_selection() 7055 ); 7056} 7057 7058#[test] 7059fn extract_constant_from_literal_within_tuple() { 7060 assert_code_action!( 7061 EXTRACT_CONSTANT, 7062 r#"pub fn main() { 7063 let c = #(0.333334, todo) 7064}"#, 7065 find_position_of("0").select_until(find_position_of("4")) 7066 ); 7067} 7068 7069#[test] 7070fn extract_constant_from_tuple_containing_constant() { 7071 assert_code_action!( 7072 EXTRACT_CONSTANT, 7073 r#"const something = "something" 7074 7075pub fn main() { 7076 let c = #(0.333334, something) 7077}"#, 7078 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 7079 ); 7080} 7081 7082#[test] 7083fn extract_constant_from_nested_inside_in_expr() { 7084 assert_code_action!( 7085 EXTRACT_CONSTANT, 7086 r#"pub fn main() { 7087 [#("a", 0), #("b", 1), #("a", 2)] 7088 |> key_filter("a") 7089}"#, 7090 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 7091 ); 7092} 7093 7094#[test] 7095fn extract_constant_from_nested_outside_in_expr() { 7096 assert_code_action!( 7097 EXTRACT_CONSTANT, 7098 r#"pub fn main() { 7099 [#("a", 0), #("b", 1), #("a", 2)] 7100 |> key_filter("a") 7101}"#, 7102 find_position_of("[").to_selection() 7103 ); 7104} 7105 7106#[test] 7107fn extract_constant_from_return_of_float() { 7108 assert_code_action!( 7109 EXTRACT_CONSTANT, 7110 r#"pub fn main() { 7111 0.25 7112}"#, 7113 find_position_of("0").select_until(find_position_of("5")) 7114 ); 7115} 7116 7117#[test] 7118fn extract_constant_from_return_of_int() { 7119 assert_code_action!( 7120 EXTRACT_CONSTANT, 7121 r#"pub fn main() { 7122 100 7123}"#, 7124 find_position_of("1").select_until(find_position_of("0").nth_occurrence(2)) 7125 ); 7126} 7127 7128#[test] 7129fn extract_constant_from_return_of_list() { 7130 assert_code_action!( 7131 EXTRACT_CONSTANT, 7132 r#"pub fn main() { 7133 [1, 2, 3, 4] 7134}"#, 7135 find_position_of("[").to_selection() 7136 ); 7137} 7138 7139#[test] 7140fn extract_constant_from_return_of_nested_outside() { 7141 assert_code_action!( 7142 EXTRACT_CONSTANT, 7143 r#"pub fn main() { 7144 [#(0.25, 0.75), #(0.5, 1.5)] 7145}"#, 7146 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 7147 ); 7148} 7149 7150#[test] 7151fn extract_constant_from_return_of_string() { 7152 assert_code_action!( 7153 EXTRACT_CONSTANT, 7154 r#"pub fn main() { 7155 "constant" 7156}"#, 7157 find_position_of("\"").select_until(find_position_of("\"")) 7158 ); 7159} 7160 7161#[test] 7162fn extract_constant_from_return_of_tuple() { 7163 assert_code_action!( 7164 EXTRACT_CONSTANT, 7165 r#"pub fn main() { 7166 #(0.25, 0.75) 7167}"#, 7168 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2)) 7169 ); 7170} 7171 7172#[test] 7173fn extract_constant_from_taken_name_by_function() { 7174 assert_code_action!( 7175 EXTRACT_CONSTANT, 7176 r#"fn floats() { 7177 [1.0, 2.0] 7178} 7179 7180pub fn main() { 7181 [0.25, 0.75] 7182}"#, 7183 find_position_of("[").nth_occurrence(2).to_selection() 7184 ); 7185} 7186 7187#[test] 7188fn extract_constant_from_taken_name_by_constant() { 7189 assert_code_action!( 7190 EXTRACT_CONSTANT, 7191 r#"const ints = [1, 2] 7192 7193pub fn main() { 7194 [5, 50] 7195}"#, 7196 find_position_of("[").nth_occurrence(2).to_selection() 7197 ); 7198} 7199 7200#[test] 7201fn extract_constant_in_correct_position_1() { 7202 assert_code_action!( 7203 EXTRACT_CONSTANT, 7204 r#" 7205fn first() { 7206 1 7207} 7208 7209fn second() { 7210 2 7211} 7212 7213fn third() { 7214 3 7215} 7216"#, 7217 find_position_of("1").to_selection() 7218 ); 7219} 7220 7221#[test] 7222fn extract_constant_in_correct_position_2() { 7223 assert_code_action!( 7224 EXTRACT_CONSTANT, 7225 r#" 7226fn first() { 7227 1 7228} 7229 7230fn second() { 7231 2 7232} 7233 7234fn third() { 7235 3 7236} 7237"#, 7238 find_position_of("2").to_selection() 7239 ); 7240} 7241 7242#[test] 7243fn extract_constant_in_correct_position_3() { 7244 assert_code_action!( 7245 EXTRACT_CONSTANT, 7246 r#" 7247fn first() { 7248 1 7249} 7250 7251fn second() { 7252 2 7253} 7254 7255fn third() { 7256 3 7257} 7258"#, 7259 find_position_of("3").to_selection() 7260 ); 7261} 7262 7263#[test] 7264fn extract_constant_declaration_with_proper_indentation() { 7265 assert_code_action!( 7266 EXTRACT_CONSTANT, 7267 r#" 7268pub fn main() { 7269 let fahrenheit = { 7270 let degrees = 64 7271 degrees 7272 } 7273 fahrenheit 7274} 7275"#, 7276 find_position_of("l") 7277 .nth_occurrence(2) 7278 .select_until(find_position_of("s")) 7279 ); 7280} 7281 7282#[test] 7283fn extract_constant_from_nil() { 7284 assert_code_action!( 7285 EXTRACT_CONSTANT, 7286 r#"pub fn main() { 7287 let x = Nil 7288 x 7289} 7290"#, 7291 find_position_of("l").select_until(find_position_of("x")) 7292 ); 7293} 7294 7295#[test] 7296fn extract_constant_from_non_record_variant_1() { 7297 assert_code_action!( 7298 EXTRACT_CONSTANT, 7299 r#"pub type Auth { 7300 Verified 7301 Unverified 7302} 7303 7304pub fn main() { 7305 let a = Unverified 7306 let a = verify(something, a) 7307 7308 a 7309} 7310"#, 7311 find_position_of("U") 7312 .nth_occurrence(2) 7313 .select_until(find_position_of("d").nth_occurrence(3)) 7314 ); 7315} 7316 7317#[test] 7318fn extract_constant_from_non_record_variant_2() { 7319 assert_code_action!( 7320 EXTRACT_CONSTANT, 7321 r#"pub type Auth { 7322 Verified 7323 Unverified 7324} 7325 7326pub fn main() { 7327 let a = verify(something, Unverified) 7328 7329 a 7330} 7331"#, 7332 find_position_of("U") 7333 .nth_occurrence(2) 7334 .select_until(find_position_of("d").nth_occurrence(3)) 7335 ); 7336} 7337 7338#[test] 7339fn extract_constant_from_record_variant_1() { 7340 assert_code_action!( 7341 EXTRACT_CONSTANT, 7342 r#"pub type Auth { 7343 Verified(String) 7344 Unverified 7345} 7346 7347pub fn main() { 7348 let u = Verified("User") 7349 let v = verify(something, u) 7350 7351 v 7352}"#, 7353 find_position_of("l").select_until(find_position_of("u").nth_occurrence(4)) 7354 ); 7355} 7356 7357#[test] 7358fn extract_constant_from_record_variant_2() { 7359 assert_code_action!( 7360 EXTRACT_CONSTANT, 7361 r#"pub type Auth { 7362 Verified(Int) 7363 Unverified 7364} 7365 7366const auth = True 7367 7368const id = 1234 7369 7370pub fn main() { 7371 let v = verify(auth, Verified(id)) 7372 7373 v 7374}"#, 7375 find_position_of("V") 7376 .nth_occurrence(2) 7377 .select_until(find_position_of("(").nth_occurrence(4)) 7378 ); 7379} 7380 7381#[test] 7382fn extract_constant_from_inside_block() { 7383 assert_code_action!( 7384 EXTRACT_CONSTANT, 7385 r#"pub fn main() { 7386 let fahrenheit = { 7387 let degrees = 64 + 32 7388 degrees 7389 } 7390}"#, 7391 find_position_of("32").to_selection() 7392 ); 7393} 7394 7395#[test] 7396fn extract_constant_from_inside_case() { 7397 assert_code_action!( 7398 EXTRACT_CONSTANT, 7399 r#"pub fn main(result) { 7400 case result { 7401 Ok(value) -> value + 1 7402 Error(_) -> panic 7403 } 7404}"#, 7405 find_position_of("1").to_selection() 7406 ); 7407} 7408 7409#[test] 7410fn extract_constant_from_inside_use_1() { 7411 assert_code_action!( 7412 EXTRACT_CONSTANT, 7413 r#"pub fn main() { 7414 use x <- result.try(todo) 7415 Ok(123) 7416}"#, 7417 find_position_of("Ok").to_selection() 7418 ); 7419} 7420 7421#[test] 7422fn extract_constant_from_inside_use_2() { 7423 assert_code_action!( 7424 EXTRACT_CONSTANT, 7425 r#"const number = 123 7426 7427pub fn main() { 7428 use x <- result.try(todo) 7429 Ok(number) 7430}"#, 7431 find_position_of("Ok").to_selection() 7432 ); 7433} 7434 7435#[test] 7436fn do_not_extract_constant_from_pattern() { 7437 assert_no_code_actions!( 7438 EXTRACT_CONSTANT, 7439 r#"pub fn main() { 7440 let #(one, two) = #(1, 2) 7441 one 7442}"#, 7443 find_position_of("l").select_until(find_position_of("(").nth_occurrence(2)) 7444 ); 7445} 7446 7447#[test] 7448fn do_not_extract_constant_from_fn_call_1() { 7449 assert_no_code_actions!( 7450 EXTRACT_CONSTANT, 7451 r#"import gleam/io 7452 7453pub fn main() { 7454 io.print("constant") 7455}"#, 7456 find_position_of("p") 7457 .nth_occurrence(3) 7458 .select_until(find_position_of("t").nth_occurrence(2)) 7459 ); 7460} 7461 7462#[test] 7463fn do_not_extract_constant_from_fn_call_2() { 7464 assert_no_code_actions!( 7465 EXTRACT_CONSTANT, 7466 r#"import gleam/list 7467 7468pub fn main() { 7469 let first = list.first([1, 2, 3]) 7470 first 7471}"#, 7472 find_position_of("l") 7473 .nth_occurrence(3) 7474 .select_until(find_position_of("t").nth_occurrence(4)) 7475 ); 7476} 7477 7478#[test] 7479fn do_not_extract_constant_from_bin_op() { 7480 assert_no_code_actions!( 7481 EXTRACT_CONSTANT, 7482 r#"pub fn main() { 7483 let res = 64 < 32 7484 res 7485}"#, 7486 find_position_of("<").to_selection() 7487 ); 7488} 7489 7490#[test] 7491fn do_not_extract_constant_from_bit_array_1() { 7492 assert_no_code_actions!( 7493 EXTRACT_CONSTANT, 7494 r#"pub fn main() { 7495 let c = "constant" 7496 let res = <<c:utf16>> 7497 res 7498}"#, 7499 find_position_of("<").to_selection() 7500 ); 7501} 7502 7503#[test] 7504fn do_not_extract_constant_from_bit_array_2() { 7505 assert_no_code_actions!( 7506 EXTRACT_CONSTANT, 7507 r#"import gleam/io 7508 7509pub fn main() { 7510 let n = 1234 7511 io.debug(<<8080:size(n)>>) 7512}"#, 7513 find_position_of("<").to_selection() 7514 ); 7515} 7516 7517#[test] 7518fn do_not_extract_constant_from_bit_array_3() { 7519 assert_no_code_actions!( 7520 EXTRACT_CONSTANT, 7521 r#"import gleam/io 7522 7523pub fn main() { 7524 let l = 1234 7525 let r = 1234 7526 let result = <<l:size(r)>> 7527 result 7528}"#, 7529 find_position_of("l") 7530 .nth_occurrence(5) 7531 .select_until(find_position_of("t").nth_occurrence(5)) 7532 ); 7533} 7534 7535#[test] 7536fn do_not_extract_constant_from_list_1() { 7537 assert_no_code_actions!( 7538 EXTRACT_CONSTANT, 7539 r#"pub fn main() { 7540 let c = ["constant", todo] 7541 c 7542}"#, 7543 find_position_of("[").to_selection() 7544 ); 7545} 7546 7547#[test] 7548fn do_not_extract_constant_from_list_2() { 7549 assert_no_code_actions!( 7550 EXTRACT_CONSTANT, 7551 r#"pub fn main() { 7552 [10, todo] 7553}"#, 7554 find_position_of("[").to_selection() 7555 ); 7556} 7557 7558#[test] 7559fn do_not_extract_constant_from_list_3() { 7560 assert_no_code_actions!( 7561 EXTRACT_CONSTANT, 7562 r#"pub fn main() { 7563 let c = [0.25, todo] 7564 c 7565}"#, 7566 find_position_of("l").select_until(find_position_of("c")) 7567 ); 7568} 7569 7570#[test] 7571fn do_not_extract_constant_from_tuple_1() { 7572 assert_no_code_actions!( 7573 EXTRACT_CONSTANT, 7574 r#"pub fn main() { 7575 let c = #("constant", todo) 7576 c 7577}"#, 7578 find_position_of("#").select_until(find_position_of("(")) 7579 ); 7580} 7581 7582#[test] 7583fn do_not_extract_constant_from_tuple_2() { 7584 assert_no_code_actions!( 7585 EXTRACT_CONSTANT, 7586 r#"pub fn main() { 7587 #(10, todo) 7588}"#, 7589 find_position_of("#").select_until(find_position_of("(")) 7590 ); 7591} 7592 7593#[test] 7594fn do_not_extract_constant_from_tuple_3() { 7595 assert_no_code_actions!( 7596 EXTRACT_CONSTANT, 7597 r#"pub fn main() { 7598 let c = #(0.25, todo) 7599 c 7600}"#, 7601 find_position_of("l").select_until(find_position_of("c")) 7602 ); 7603} 7604 7605#[test] 7606fn do_not_extract_constant_from_nested_1() { 7607 assert_no_code_actions!( 7608 EXTRACT_CONSTANT, 7609 r#"pub fn main() { 7610 let c = list.unzip([#(1, 2), #(3, todo)]) 7611 c 7612}"#, 7613 find_position_of("[").to_selection() 7614 ); 7615} 7616 7617#[test] 7618fn do_not_extract_constant_from_nested_2() { 7619 assert_no_code_actions!( 7620 EXTRACT_CONSTANT, 7621 r#"pub fn main() { 7622 [[1.25, 1], [0.25, todo]] 7623}"#, 7624 find_position_of("[").to_selection() 7625 ); 7626} 7627 7628#[test] 7629fn do_not_extract_constant_from_nested_3() { 7630 assert_no_code_actions!( 7631 EXTRACT_CONSTANT, 7632 r#"import gleam/list 7633 7634pub fn main() { 7635 let c = [#(1, 2), #(3, todo)] 7636 c 7637}"#, 7638 find_position_of("l") 7639 .nth_occurrence(3) 7640 .select_until(find_position_of("c")) 7641 ); 7642} 7643 7644#[test] 7645fn do_not_extract_constant_from_record_1() { 7646 assert_no_code_actions!( 7647 EXTRACT_CONSTANT, 7648 r#"type Pair { 7649 Pair(Int, Int) 7650} 7651 7652pub fn main() { 7653 let c = list.unzip([Pair(1, 2), Pair(3, todo)]) 7654 c 7655}"#, 7656 find_position_of("P").nth_occurrence(4).to_selection() 7657 ); 7658} 7659 7660#[test] 7661fn do_not_extract_constant_from_record_2() { 7662 assert_no_code_actions!( 7663 EXTRACT_CONSTANT, 7664 r#"type Couple { 7665 Couple(l: Float, r: Float) 7666} 7667 7668pub fn main() { 7669 #(Couple(1.25, 1.0), Couple(0.25, todo)) 7670}"#, 7671 find_position_of("C").nth_occurrence(4).to_selection() 7672 ); 7673} 7674 7675#[test] 7676fn do_not_extract_constant_from_record_update() { 7677 assert_no_code_actions!( 7678 EXTRACT_CONSTANT, 7679 r#"type Couple { 7680 Couple(l: Int, r: Int) 7681} 7682 7683pub fn main() { 7684 let c = Couple(1, 2) 7685 let cc = Couple(..c, 2) 7686 cc 7687}"#, 7688 find_position_of("C") 7689 .nth_occurrence(4) 7690 .select_until(find_position_of("e").nth_occurrence(7)) 7691 ); 7692} 7693 7694#[test] 7695fn do_not_extract_constant_from_record_capture() { 7696 assert_no_code_actions!( 7697 EXTRACT_CONSTANT, 7698 r#"type Couple { 7699 Couple(l: Int, r: Int) 7700} 7701 7702pub fn main() { 7703 let c = Couple(1, _) 7704 c 7705}"#, 7706 find_position_of("C") 7707 .nth_occurrence(3) 7708 .select_until(find_position_of("e").nth_occurrence(5)) 7709 ); 7710} 7711 7712#[test] 7713fn do_not_extract_top_level_expression_statement() { 7714 assert_no_code_actions!( 7715 EXTRACT_VARIABLE, 7716 r#"pub fn main() { 7717 1 7718} 7719"#, 7720 find_position_of("1").to_selection() 7721 ); 7722} 7723 7724#[test] 7725fn do_not_extract_top_level_expression_in_let_statement() { 7726 assert_no_code_actions!( 7727 EXTRACT_VARIABLE, 7728 r#"pub fn main() { 7729 let a = 1 7730} 7731"#, 7732 find_position_of("1").to_selection() 7733 ); 7734} 7735 7736#[test] 7737fn allow_extracting_multiple_selects() { 7738 assert_code_action!( 7739 EXTRACT_VARIABLE, 7740 r#" 7741pub fn go(wibble: Wibble) { 7742 [ 7743 wibble.wobble.wubble.woo, 7744 todo as "something else", 7745 ] 7746} 7747 7748pub type Wibble { Wibble(wobble: Wobble) } 7749pub type Wobble { Wobble(wubble: Wubble) } 7750pub type Wubble { Wubble(woo: Int) } 7751"#, 7752 find_position_of("wibble") 7753 .nth_occurrence(2) 7754 .select_until(find_position_of("woo")) 7755 ); 7756} 7757 7758#[test] 7759fn allow_extracting_part_of_multiple_selects() { 7760 assert_code_action!( 7761 EXTRACT_VARIABLE, 7762 r#" 7763pub fn go(wibble: Wibble) { 7764 [ 7765 wibble.wobble.wubble.woo, 7766 todo as "something else", 7767 ] 7768} 7769 7770pub type Wibble { Wibble(wobble: Wobble) } 7771pub type Wobble { Wobble(wubble: Wubble) } 7772pub type Wubble { Wubble(woo: Int) } 7773"#, 7774 find_position_of("wubble").to_selection() 7775 ); 7776} 7777 7778#[test] 7779fn do_not_extract_top_level_module_call() { 7780 let src = r#" 7781import list 7782pub fn main() { 7783 list.map([1, 2, 3], todo) 7784}"#; 7785 7786 assert_no_code_actions!( 7787 EXTRACT_VARIABLE, 7788 TestProject::for_source(src).add_module("list", "pub fn map(l, f) { todo }"), 7789 find_position_of("map").to_selection() 7790 ); 7791} 7792 7793#[test] 7794fn expand_function_capture() { 7795 assert_code_action!( 7796 EXPAND_FUNCTION_CAPTURE, 7797 r#"pub fn main() { 7798 wibble(_, 1) 7799}"#, 7800 find_position_of("_").to_selection() 7801 ); 7802} 7803 7804#[test] 7805fn expand_function_capture_2() { 7806 assert_code_action!( 7807 EXPAND_FUNCTION_CAPTURE, 7808 r#"pub fn main() { 7809 wibble(1, _) 7810}"#, 7811 find_position_of("wibble").to_selection() 7812 ); 7813} 7814 7815#[test] 7816fn expand_function_capture_does_not_shadow_variables() { 7817 assert_code_action!( 7818 EXPAND_FUNCTION_CAPTURE, 7819 r#"pub fn main() { 7820 let value = 1 7821 let value_2 = 2 7822 wibble(value, _, value_2) 7823}"#, 7824 find_position_of("wibble").to_selection() 7825 ); 7826} 7827 7828#[test] 7829fn expand_function_capture_picks_a_name_based_on_the_type_of_the_hole() { 7830 assert_code_action!( 7831 EXPAND_FUNCTION_CAPTURE, 7832 r#"pub fn main() { 7833 [1, 2, 3] 7834 |> map(add(_, 1)) 7835} 7836 7837pub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo } 7838pub fn add(n, m) { n + m } 7839"#, 7840 find_position_of("add").to_selection() 7841 ); 7842} 7843 7844#[test] 7845fn expand_function_capture_in_pipeline() { 7846 assert_code_action!( 7847 EXPAND_FUNCTION_CAPTURE, 7848 "pub fn main() { 7849 1 |> wibble(2, _) |> wobble 7850} 7851 7852fn wibble(a, b) { 7853 todo 7854} 7855 7856fn wobble(i) { 7857 todo 7858} 7859 7860", 7861 find_position_of("wibble").to_selection() 7862 ); 7863} 7864 7865#[test] 7866fn generate_dynamic_decoder() { 7867 assert_code_action!( 7868 GENERATE_DYNAMIC_DECODER, 7869 " 7870pub type Person { 7871 Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray) 7872} 7873", 7874 find_position_of("type").to_selection() 7875 ); 7876} 7877 7878#[test] 7879fn generate_dynamic_decoder_only_works_if_withing_a_type() { 7880 assert_no_code_actions!( 7881 GENERATE_DYNAMIC_DECODER, 7882 " 7883pub type Person { 7884 Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray) 7885} 7886 7887pub fn main() { 7888 // unrelated 7889 todo 7890} 7891", 7892 find_position_of("pub type").select_until(find_position_of("todo")) 7893 ); 7894} 7895 7896#[test] 7897fn generate_dynamic_decoder_complex_types() { 7898 let src = " 7899import gleam/option 7900import gleam/dynamic 7901import gleam/dict 7902 7903pub type Something 7904 7905pub type Wibble(value) { 7906 Wibble( 7907 maybe: option.Option(Something), 7908 map: dict.Dict(String, List(value)), 7909 unknown: List(dynamic.Dynamic), 7910 ) 7911} 7912"; 7913 7914 assert_code_action!( 7915 GENERATE_DYNAMIC_DECODER, 7916 TestProject::for_source(src) 7917 .add_module("gleam/option", "pub type Option(a)") 7918 .add_module("gleam/dynamic", "pub type Dynamic") 7919 .add_module("gleam/dict", "pub type Dict(k, v)"), 7920 find_position_of("type W").to_selection() 7921 ); 7922} 7923 7924#[test] 7925fn generate_dynamic_decoder_already_imported_module() { 7926 let src = " 7927import gleam/dynamic/decode as dyn_dec 7928 7929pub type Wibble { 7930 Wibble(a: Int, b: Float, c: String) 7931} 7932"; 7933 7934 assert_code_action!( 7935 GENERATE_DYNAMIC_DECODER, 7936 TestProject::for_source(src).add_module("gleam/dynamic/decode", "pub type Decoder(a)"), 7937 find_position_of("type W").to_selection() 7938 ); 7939} 7940 7941#[test] 7942fn generate_dynamic_decoder_tuple() { 7943 assert_code_action!( 7944 GENERATE_DYNAMIC_DECODER, 7945 " 7946pub type Wibble { 7947 Wibble(tuple: #(Int, Float, #(String, Bool))) 7948} 7949", 7950 find_position_of("type W").to_selection() 7951 ); 7952} 7953 7954#[test] 7955fn generate_dynamic_decoder_recursive_type() { 7956 let src = " 7957import gleam/option 7958 7959pub type LinkedList { 7960 LinkedList(value: Int, next: option.Option(LinkedList)) 7961} 7962"; 7963 assert_code_action!( 7964 GENERATE_DYNAMIC_DECODER, 7965 TestProject::for_source(src).add_module("gleam/option", "pub type Option(a)"), 7966 find_position_of("type").to_selection() 7967 ); 7968} 7969 7970#[test] 7971fn generate_dynamic_decoder_for_multi_variant_type() { 7972 assert_code_action!( 7973 GENERATE_DYNAMIC_DECODER, 7974 " 7975pub type Wibble { 7976 Wibble(wibble: Int, next: Wibble) 7977 Wobble(wobble: Float, text: String, values: List(Bool)) 7978} 7979", 7980 find_position_of("type").to_selection() 7981 ); 7982} 7983 7984#[test] 7985fn generate_dynamic_decoder_for_multi_variant_type_multi_word_name() { 7986 assert_code_action!( 7987 GENERATE_DYNAMIC_DECODER, 7988 " 7989pub type Wibble { 7990 OneTwo(wibble: Int, next: Wibble) 7991 ThreeFour(wobble: Float, text: String, values: List(Bool)) 7992 FiveSixSeven(one_two: Int) 7993} 7994", 7995 find_position_of("type").to_selection() 7996 ); 7997} 7998 7999#[test] 8000fn generate_dynamic_decoder_for_variant_with_no_fields() { 8001 assert_code_action!( 8002 GENERATE_DYNAMIC_DECODER, 8003 " 8004pub type Wibble { 8005 Wibble 8006} 8007", 8008 find_position_of("type").to_selection() 8009 ); 8010} 8011 8012#[test] 8013fn generate_dynamic_decoder_for_variants_with_no_fields() { 8014 assert_code_action!( 8015 GENERATE_DYNAMIC_DECODER, 8016 " 8017pub type Wibble { 8018 Wibble 8019 Wobble 8020 Woo 8021} 8022", 8023 find_position_of("type").to_selection() 8024 ); 8025} 8026 8027#[test] 8028fn generate_dynamic_decoder_for_variants_with_mixed_fields() { 8029 assert_code_action!( 8030 GENERATE_DYNAMIC_DECODER, 8031 " 8032pub type Wibble { 8033 Wibble 8034 Wobble(field: String, field2: Int) 8035} 8036", 8037 find_position_of("type").to_selection() 8038 ); 8039} 8040 8041#[test] 8042fn no_code_action_to_generate_dynamic_decoder_for_type_without_labels() { 8043 assert_no_code_actions!( 8044 GENERATE_DYNAMIC_DECODER, 8045 " 8046pub type Wibble { 8047 Wibble(Int, Int, String) 8048} 8049", 8050 find_position_of("type").to_selection() 8051 ); 8052} 8053 8054#[test] 8055fn pattern_match_on_argument_empty_tuple() { 8056 assert_no_code_actions!( 8057 PATTERN_MATCH_ON_ARGUMENT, 8058 " 8059pub fn main(tuple: #()) { 8060 todo 8061} 8062", 8063 find_position_of("tuple").to_selection() 8064 ); 8065} 8066 8067#[test] 8068fn pattern_match_on_argument_single_item_tuple() { 8069 assert_code_action!( 8070 PATTERN_MATCH_ON_ARGUMENT, 8071 " 8072pub fn main(tuple: #(Int)) { 8073 todo 8074} 8075", 8076 find_position_of(":").to_selection() 8077 ); 8078} 8079 8080#[test] 8081fn pattern_match_on_argument_multi_item_tuple() { 8082 assert_code_action!( 8083 PATTERN_MATCH_ON_ARGUMENT, 8084 " 8085pub fn main(tuple: #(Int, String, Bool)) { 8086 todo 8087} 8088", 8089 find_position_of("tuple").select_until(find_position_of("Int")) 8090 ); 8091} 8092 8093#[test] 8094fn pattern_match_on_argument_uses_case_with_multiple_constructors() { 8095 assert_code_action!( 8096 PATTERN_MATCH_ON_ARGUMENT, 8097 " 8098pub type CannotBeDestructured { 8099 One(one: String) 8100 Two(two: Int) 8101} 8102 8103pub fn main(arg: CannotBeDestructured) { 8104 todo 8105} 8106", 8107 find_position_of("arg").to_selection() 8108 ); 8109} 8110 8111#[test] 8112fn pattern_match_on_argument_with_multiple_constructors_is_nicely_formatted_in_function_with_empty_body( 8113) { 8114 assert_code_action!( 8115 PATTERN_MATCH_ON_ARGUMENT, 8116 " 8117pub type CannotBeDestructured { 8118 One(one: String) 8119 Two(two: Int) 8120} 8121 8122pub fn main(arg: CannotBeDestructured) {} 8123", 8124 find_position_of("arg").to_selection() 8125 ); 8126} 8127 8128#[test] 8129fn pattern_match_on_argument_uses_label_shorthand_syntax_for_labelled_arguments() { 8130 assert_code_action!( 8131 PATTERN_MATCH_ON_ARGUMENT, 8132 " 8133pub type Wibble { 8134 Wobble(Int, String, i_want_to_see_this: String, and_this: Bool) 8135} 8136 8137pub fn main(arg: Wibble) { 8138 todo 8139} 8140", 8141 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2)) 8142 ); 8143} 8144 8145#[test] 8146fn pattern_match_on_argument_with_private_type_from_same_module() { 8147 assert_code_action!( 8148 PATTERN_MATCH_ON_ARGUMENT, 8149 " 8150type Wibble { 8151 Wobble(Int, String) 8152} 8153 8154pub fn main(arg: Wibble) { 8155 todo 8156} 8157", 8158 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2)) 8159 ); 8160} 8161 8162#[test] 8163fn pattern_match_on_value_with_private_type_from_same_module() { 8164 assert_code_action!( 8165 PATTERN_MATCH_ON_VARIABLE, 8166 " 8167type Wibble { 8168 Wobble(Int, String) 8169} 8170 8171pub fn main() { 8172 let wibble = Wobble(1, \"Hello\") 8173 todo 8174} 8175", 8176 find_position_of("wibble").to_selection() 8177 ); 8178} 8179 8180#[test] 8181fn pattern_match_on_call_statement() { 8182 assert_code_action!( 8183 PATTERN_MATCH_ON_VALUE, 8184 " 8185pub fn main() { 8186 wibble() 8187} 8188 8189pub fn wibble() -> Result(Int, String) { todo } 8190", 8191 find_position_of("wibble").to_selection() 8192 ); 8193} 8194 8195#[test] 8196fn pattern_match_on_record_select_statement() { 8197 assert_code_action!( 8198 PATTERN_MATCH_ON_VALUE, 8199 " 8200pub fn main() { 8201 let wibble = Wibble(Ok(1)) 8202 wibble.wobble 8203} 8204 8205pub type Wibble { Wibble(wobble: Result(Int, Nil)) } 8206", 8207 find_position_of("wibble").nth_occurrence(2).to_selection() 8208 ); 8209} 8210 8211#[test] 8212fn pattern_match_on_tuple_index_statement() { 8213 assert_code_action!( 8214 PATTERN_MATCH_ON_VALUE, 8215 " 8216pub fn main() { 8217 let wibble = #(Ok(1), 2) 8218 wibble.0 8219} 8220", 8221 find_position_of("wibble").nth_occurrence(2).to_selection() 8222 ); 8223} 8224 8225#[test] 8226fn pattern_match_on_module_select_statement() { 8227 assert_code_action!( 8228 PATTERN_MATCH_ON_VALUE, 8229 TestProject::for_source( 8230 " 8231import wibble 8232 8233pub fn main() { 8234 wibble.wobble 8235} 8236 " 8237 ) 8238 .add_module("wibble", "pub const wobble = Ok(1)"), 8239 find_position_of("wibble").nth_occurrence(2).to_selection() 8240 ); 8241} 8242 8243#[test] 8244fn pattern_match_on_call_statement_returning_nil() { 8245 assert_no_code_actions!( 8246 PATTERN_MATCH_ON_VALUE, 8247 " 8248pub fn main() { 8249 wibble() 8250} 8251 8252pub fn wibble() -> Nil { todo } 8253", 8254 find_position_of("wibble").to_selection() 8255 ); 8256} 8257 8258#[test] 8259fn pattern_match_on_call_statement_in_the_middle_of_a_function_body() { 8260 assert_code_action!( 8261 PATTERN_MATCH_ON_VALUE, 8262 " 8263pub fn main() { 8264 wibble() 8265 Nil 8266} 8267 8268pub fn wibble() -> Result(Int, String) { todo } 8269", 8270 find_position_of("wibble").to_selection() 8271 ); 8272} 8273 8274#[test] 8275fn pattern_match_on_value_picks_innermost_value_and_not_outer_call() { 8276 assert_no_code_actions!( 8277 PATTERN_MATCH_ON_VALUE, 8278 " 8279pub fn main() { 8280 wibble({ 8281 let match_on_me = wibble(todo) 8282 }) 8283} 8284 8285pub fn wibble(a) -> Result(Int, String) { todo } 8286", 8287 find_position_of("match_on_me").to_selection() 8288 ); 8289} 8290 8291#[test] 8292fn pattern_match_on_value_picks_innermost_value_and_not_outer_call_2() { 8293 assert_code_action!( 8294 PATTERN_MATCH_ON_VARIABLE, 8295 " 8296pub fn main() { 8297 wibble({ 8298 let match_on_me = wibble(todo) 8299 }) 8300} 8301 8302pub fn wibble(a) -> Result(Int, String) { todo } 8303", 8304 find_position_of("match_on_me").to_selection() 8305 ); 8306} 8307 8308#[test] 8309fn pattern_match_on_clause_variable() { 8310 assert_code_action!( 8311 PATTERN_MATCH_ON_VARIABLE, 8312 " 8313pub fn main() { 8314 case maybe_wibble() { 8315 Ok(something) -> 1 8316 Error(_) -> 2 8317 } 8318} 8319 8320type Wibble { 8321 Wobble 8322 Woo 8323} 8324 8325fn maybe_wibble() { Ok(Wobble) } 8326 8327", 8328 find_position_of("something").to_selection() 8329 ); 8330} 8331 8332#[test] 8333// https://github.com/gleam-lang/gleam/issues/5648 8334fn pattern_match_on_variable_defined_inside_anonymous_function() { 8335 assert_code_action!( 8336 PATTERN_MATCH_ON_VARIABLE, 8337 " 8338pub fn main() { 8339 let outcome = apply(#(Ok(1), Nil), fn(pair) { 8340 let #(result, nil) = pair 8341 }) 8342} 8343 8344fn apply(a, f) { f(a) } 8345", 8346 find_position_of("result").to_selection() 8347 ); 8348} 8349 8350#[test] 8351fn pattern_match_on_clause_variable_with_label() { 8352 assert_code_action!( 8353 PATTERN_MATCH_ON_VARIABLE, 8354 " 8355pub fn main() { 8356 case wibble() { 8357 Wobble(wibble: something) -> 1 8358 _ -> 2 8359 } 8360} 8361 8362type Wibble { 8363 Wobble(wibble: Wibble) 8364 Woo 8365} 8366 8367fn new() { Wobble } 8368 8369", 8370 find_position_of("something").to_selection() 8371 ); 8372} 8373 8374#[test] 8375fn pattern_match_on_clause_variable_with_label_shorthand() { 8376 assert_code_action!( 8377 PATTERN_MATCH_ON_VARIABLE, 8378 " 8379pub fn main() { 8380 case new() { 8381 Wobble(wibble:) -> 1 8382 _ -> 2 8383 } 8384} 8385 8386type Wibble { 8387 Wobble(wibble: Wibble) 8388 Woo 8389} 8390 8391fn new() { Wobble } 8392 8393", 8394 find_position_of("wibble").to_selection() 8395 ); 8396} 8397 8398#[test] 8399fn pattern_match_on_clause_variable_nested_pattern() { 8400 assert_code_action!( 8401 PATTERN_MATCH_ON_VARIABLE, 8402 " 8403pub fn main() { 8404 case maybe_wibble() { 8405 Ok(Wobble(something)) -> 1 8406 Error(_) -> 2 8407 } 8408} 8409 8410type Wibble { 8411 Wobble(Wibble) 8412 Woo 8413} 8414 8415fn maybe_wibble() { Ok(Woo) } 8416 8417", 8418 find_position_of("something").to_selection() 8419 ); 8420} 8421 8422#[test] 8423fn pattern_match_on_clause_variable_with_block_body() { 8424 assert_code_action!( 8425 PATTERN_MATCH_ON_VARIABLE, 8426 " 8427pub fn main() { 8428 case maybe_wibble() { 8429 Ok(something) -> { 8430 1 8431 2 8432 } 8433 Error(_) -> 2 8434 } 8435} 8436 8437type Wibble { 8438 Wobble 8439 Woo 8440} 8441 8442fn maybe_wibble() { Ok(Wobble) } 8443 8444", 8445 find_position_of("something").to_selection() 8446 ); 8447} 8448 8449#[test] 8450fn pattern_match_on_argument_will_use_qualified_name() { 8451 let src = " 8452import wibble 8453 8454pub fn main(arg: wibble.Wibble) { 8455 todo 8456} 8457"; 8458 8459 let dep = " 8460pub type Wibble { 8461 ThisShouldBeQualified(label: Int) 8462} 8463"; 8464 8465 assert_code_action!( 8466 PATTERN_MATCH_ON_ARGUMENT, 8467 TestProject::for_source(src).add_module("wibble", dep), 8468 find_position_of("wibble").nth_occurrence(2).to_selection() 8469 ); 8470} 8471 8472#[test] 8473fn pattern_match_on_argument_will_use_unqualified_name() { 8474 let src = " 8475import wibble.{ThisShouldBeUnqualified} 8476 8477pub fn main(arg: wibble.Wibble) { 8478 todo 8479} 8480"; 8481 8482 let dep = " 8483pub type Wibble { 8484 ThisShouldBeUnqualified(label: Int) 8485} 8486"; 8487 8488 assert_code_action!( 8489 PATTERN_MATCH_ON_ARGUMENT, 8490 TestProject::for_source(src).add_module("wibble", dep), 8491 find_position_of("Wibble").to_selection() 8492 ); 8493} 8494 8495#[test] 8496fn pattern_match_on_argument_will_use_aliased_constructor_name() { 8497 let src = " 8498import wibble.{Wobble as IWantToSeeThisName} 8499 8500pub fn main(arg: wibble.Wibble) { 8501 todo 8502} 8503"; 8504 8505 let dep = " 8506pub type Wibble { 8507 Wobble(label: Int) 8508} 8509"; 8510 8511 assert_code_action!( 8512 PATTERN_MATCH_ON_ARGUMENT, 8513 TestProject::for_source(src).add_module("wibble", dep), 8514 find_position_of("arg").to_selection() 8515 ); 8516} 8517 8518#[test] 8519fn pattern_match_on_argument_will_use_aliased_module_name() { 8520 let src = " 8521import wibble as i_want_to_see_this_name 8522 8523pub fn main(arg: i_want_to_see_this_name.Wibble) { 8524 todo 8525} 8526"; 8527 8528 let dep = " 8529pub type Wibble { 8530 Wobble(label: Int) 8531} 8532"; 8533 8534 assert_code_action!( 8535 PATTERN_MATCH_ON_ARGUMENT, 8536 TestProject::for_source(src).add_dep_module("wibble", dep), 8537 find_position_of("arg").to_selection() 8538 ); 8539} 8540 8541#[test] 8542fn pattern_match_on_argument_not_available_for_internal_type() { 8543 let src = " 8544import wibble 8545 8546pub fn main(arg: wobble.Wibble) { 8547 todo 8548} 8549"; 8550 8551 let dep = " 8552@internal 8553pub type Wibble { 8554 Wobble(label: Int) 8555} 8556"; 8557 8558 assert_no_code_actions!( 8559 PATTERN_MATCH_ON_ARGUMENT, 8560 TestProject::for_source(src).add_module("wibble", dep), 8561 find_position_of("arg").to_selection() 8562 ); 8563} 8564 8565#[test] 8566fn pattern_match_on_argument_available_for_internal_type_defined_in_current_module() { 8567 assert_code_action!( 8568 PATTERN_MATCH_ON_ARGUMENT, 8569 " 8570@internal 8571pub type Wibble { 8572 Wobble(label: Int) 8573} 8574 8575pub fn main(arg: Wibble) { 8576 todo 8577} 8578", 8579 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2)) 8580 ); 8581} 8582 8583#[test] 8584fn pattern_match_on_argument_preserves_indentation_of_statement_following_inserted_let() { 8585 assert_code_action!( 8586 PATTERN_MATCH_ON_ARGUMENT, 8587 "pub fn main(arg: #(Int, String)) { 8588 todo 8589//^^^^ This should still have two spaces of indentation! 8590}", 8591 find_position_of("arg").to_selection() 8592 ); 8593} 8594 8595#[test] 8596fn pattern_match_on_argument_nicely_formats_code_when_used_on_function_with_empty_body() { 8597 assert_code_action!( 8598 PATTERN_MATCH_ON_ARGUMENT, 8599 "pub fn main(arg: #(Int, String)) {}", 8600 find_position_of("arg").to_selection() 8601 ); 8602} 8603 8604#[test] 8605fn pattern_match_on_argument_single_unlabelled_field_is_not_numbered() { 8606 assert_code_action!( 8607 PATTERN_MATCH_ON_ARGUMENT, 8608 " 8609pub type Wibble { 8610 Wibble(Int) 8611} 8612 8613pub fn main(arg: Wibble) {} 8614", 8615 find_position_of(":").to_selection() 8616 ); 8617} 8618 8619#[test] 8620fn pattern_match_on_let_assignment() { 8621 assert_code_action!( 8622 PATTERN_MATCH_ON_VARIABLE, 8623 " 8624pub fn main() { 8625 let var = #(1, 2) 8626} 8627", 8628 find_position_of("var").to_selection() 8629 ); 8630} 8631 8632#[test] 8633fn pattern_match_on_let_assignment_with_multiple_constructors() { 8634 assert_code_action!( 8635 PATTERN_MATCH_ON_VARIABLE, 8636 " 8637pub type Wibble { 8638 Wobble 8639 Woo 8640} 8641 8642pub fn main() { 8643 let var = Woo 8644 todo 8645} 8646", 8647 find_position_of("var").to_selection() 8648 ); 8649} 8650 8651#[test] 8652fn pattern_match_on_use_assignment() { 8653 assert_code_action!( 8654 PATTERN_MATCH_ON_VARIABLE, 8655 " 8656pub fn main() { 8657 use var <- f 8658} 8659 8660fn f(g) { g(#(1, 2)) } 8661", 8662 find_position_of("var").to_selection() 8663 ); 8664} 8665 8666#[test] 8667fn pattern_match_on_use_assignment_with_multiple_constructors() { 8668 assert_code_action!( 8669 PATTERN_MATCH_ON_VARIABLE, 8670 " 8671pub type Wibble { 8672 Wobble 8673 Woo 8674} 8675 8676pub fn main() { 8677 use var <- f 8678} 8679 8680fn f(g) { g(Wobble) } 8681", 8682 find_position_of("var").to_selection() 8683 ); 8684} 8685 8686#[test] 8687fn pattern_match_on_pattern_use_assignment() { 8688 assert_no_code_actions!( 8689 PATTERN_MATCH_ON_VARIABLE, 8690 " 8691pub fn main() { 8692 use #(a, b) <- f 8693} 8694 8695fn f(g) { g(#(1, 2)) } 8696", 8697 find_position_of("#").to_selection() 8698 ); 8699} 8700 8701#[test] 8702fn pattern_match_on_argument_works_on_fn_arguments() { 8703 assert_code_action!( 8704 PATTERN_MATCH_ON_ARGUMENT, 8705 " 8706pub fn main() { 8707 [#(1, 2)] 8708 |> map(fn(tuple) {}) 8709} 8710 8711fn map(list: List(a), fun: fn(a) -> b) { todo } 8712", 8713 find_position_of("tuple").to_selection() 8714 ); 8715} 8716 8717#[test] 8718fn pattern_match_on_argument_works_on_nested_fn_arguments() { 8719 assert_code_action!( 8720 PATTERN_MATCH_ON_ARGUMENT, 8721 " 8722pub fn main() { 8723 map([[#(1, 2)]], fn(list) { 8724 map(list, fn(tuple) { 8725 todo 8726 }) 8727 }) 8728} 8729 8730fn map(list: List(a), fun: fn(a) -> b) { todo } 8731", 8732 find_position_of("tuple").to_selection() 8733 ); 8734} 8735 8736#[test] 8737// https://github.com/gleam-lang/gleam/issues/5042 8738fn pattern_match_on_variable_crashes() { 8739 assert_code_action!( 8740 PATTERN_MATCH_ON_VARIABLE, 8741 r#" 8742pub type Wibble { 8743 Wibble(Wobble) 8744} 8745 8746pub type Wobble { 8747 Wobble 8748 Wubble 8749} 8750 8751pub fn main() { 8752 let Wibble(wobble) = todo 8753 8754 case todo { 8755 _ -> todo 8756 } 8757} 8758"#, 8759 find_position_of("wobble").to_selection() 8760 ); 8761} 8762 8763#[test] 8764fn generate_function_works_with_invalid_call() { 8765 assert_code_action!( 8766 GENERATE_FUNCTION, 8767 " 8768pub fn main() -> Bool { 8769 wibble(1, True, 2.3) 8770} 8771", 8772 find_position_of("wibble").to_selection() 8773 ); 8774} 8775 8776#[test] 8777fn generate_function_works_with_constants() { 8778 assert_code_action!( 8779 GENERATE_FUNCTION, 8780 "const wibble: fn(Int) -> String = wobble", 8781 find_position_of("wobble").to_selection() 8782 ); 8783} 8784 8785#[test] 8786fn generate_function_works_with_constants_2() { 8787 assert_code_action!( 8788 GENERATE_FUNCTION, 8789 " 8790type Wibble(a) { 8791 Wibble(fun: fn(Int) -> a) 8792} 8793 8794const wibble: Wibble(Int) = Wibble(missing) 8795", 8796 find_position_of("missing").to_selection() 8797 ); 8798} 8799 8800#[test] 8801fn generate_function_works_with_pipeline_steps() { 8802 assert_code_action!( 8803 GENERATE_FUNCTION, 8804 " 8805pub fn main() { 8806 [1, 2, 3] 8807 |> sum 8808 |> int_to_string 8809} 8810 8811fn int_to_string(n: Int) -> String { 8812 todo 8813} 8814", 8815 find_position_of("sum").to_selection() 8816 ); 8817} 8818 8819#[test] 8820fn generate_function_works_with_pipeline_steps_1() { 8821 assert_code_action!( 8822 GENERATE_FUNCTION, 8823 " 8824pub fn main() { 8825 [1, 2, 3] 8826 |> map(int_to_string) 8827 |> join 8828} 8829 8830fn map(list: List(a), fun: fn(a) -> b) -> List(b) { 8831 todo 8832} 8833 8834fn join(n: List(String)) -> String { 8835 todo 8836} 8837", 8838 find_position_of("int_to_string").to_selection() 8839 ); 8840} 8841 8842// https://github.com/gleam-lang/gleam/issues/4177#event-15968345230 8843#[test] 8844fn generate_function_picks_argument_name_based_on_type() { 8845 assert_code_action!( 8846 GENERATE_FUNCTION, 8847 " 8848pub fn main() { 8849 wibble(\"Hello\", 1) 8850} 8851", 8852 find_position_of("wibble").to_selection() 8853 ); 8854} 8855 8856#[test] 8857fn generate_function_picks_argument_name_based_on_record_access() { 8858 assert_code_action!( 8859 GENERATE_FUNCTION, 8860 " 8861pub type User { 8862 User(id: Int, name: String) 8863} 8864 8865pub fn go(user: User) { 8866 authenticate(user.id, user.name) 8867} 8868", 8869 find_position_of("authenticate").to_selection() 8870 ); 8871} 8872 8873#[test] 8874fn generate_function_wont_generate_two_arguments_with_the_same_name_if_they_have_the_same_type() { 8875 assert_code_action!( 8876 GENERATE_FUNCTION, 8877 " 8878pub fn main() { 8879 wibble(2, 1) 8880} 8881", 8882 find_position_of("wibble").to_selection() 8883 ); 8884} 8885 8886#[test] 8887fn generate_function_takes_labels_into_account() { 8888 assert_code_action!( 8889 GENERATE_FUNCTION, 8890 " 8891pub fn main() { 8892 wibble(2, n: 1) 8893} 8894", 8895 find_position_of("wibble").to_selection() 8896 ); 8897} 8898 8899#[test] 8900fn generate_function_does_not_trigger_if_labels_are_in_the_wrong_order() { 8901 assert_no_code_actions!( 8902 GENERATE_FUNCTION, 8903 " 8904pub fn main() { 8905 wibble(n: 2, 1) 8906} 8907", 8908 find_position_of("wibble").to_selection() 8909 ); 8910} 8911 8912#[test] 8913fn generate_function_does_not_trigger_if_there_are_repeated_labels() { 8914 assert_no_code_actions!( 8915 GENERATE_FUNCTION, 8916 " 8917pub fn main() { 8918 wibble(n: 2, n: 1) 8919} 8920", 8921 find_position_of("wibble").to_selection() 8922 ); 8923} 8924 8925#[test] 8926fn generate_function_generates_argument_names_from_labels() { 8927 assert_code_action!( 8928 GENERATE_FUNCTION, 8929 " 8930pub fn main() { 8931 add(1, addend: 10) 8932} 8933", 8934 find_position_of("add").to_selection() 8935 ); 8936} 8937 8938#[test] 8939fn generate_function_generates_argument_names_from_variables() { 8940 assert_code_action!( 8941 GENERATE_FUNCTION, 8942 " 8943pub fn main() { 8944 let wibble = 10 8945 let wobble = 20 8946 8947 wubble(wibble, wobble, 14) 8948} 8949", 8950 find_position_of("wubble").to_selection() 8951 ); 8952} 8953 8954#[test] 8955fn generate_function_labels_and_arguments_can_share_the_same_name() { 8956 assert_code_action!( 8957 GENERATE_FUNCTION, 8958 " 8959pub fn main() { 8960 let wibble = 10 8961 wubble(wibble, wibble: 14) 8962} 8963", 8964 find_position_of("wubble").to_selection() 8965 ); 8966} 8967 8968#[test] 8969fn generate_function_arguments_with_same_name_get_renamed() { 8970 assert_code_action!( 8971 GENERATE_FUNCTION, 8972 " 8973pub fn main() { 8974 let wibble = 10 8975 wubble(wibble, wibble) 8976} 8977", 8978 find_position_of("wubble").to_selection() 8979 ); 8980} 8981 8982#[test] 8983fn generate_function_arguments_with_labels_and_variables_uses_different_names() { 8984 assert_code_action!( 8985 GENERATE_FUNCTION, 8986 " 8987pub fn main() { 8988 let list = [2, 4, 5] 8989 let value = 1 8990 find(each: value, in: list) 8991} 8992", 8993 find_position_of("find").to_selection() 8994 ); 8995} 8996 8997#[test] 8998fn pattern_match_on_argument_generates_unique_names_even_with_labels() { 8999 assert_code_action!( 9000 PATTERN_MATCH_ON_ARGUMENT, 9001 " 9002pub type Wibble { 9003 Wibble(String, string: String) 9004} 9005 9006pub fn main(wibble: Wibble) { 9007 todo 9008} 9009", 9010 find_position_of("wibble").to_selection() 9011 ); 9012} 9013 9014#[test] 9015fn extract_variable_with_list_with_plural_name_does_not_add_another_s() { 9016 assert_code_action!( 9017 EXTRACT_VARIABLE, 9018 " 9019pub fn main() { 9020 wibble([Names, Names]) 9021} 9022 9023pub type Names { 9024 Names 9025} 9026", 9027 find_position_of("[").to_selection() 9028 ); 9029} 9030 9031#[test] 9032fn convert_to_function_call_works_with_argument_in_first_position() { 9033 assert_code_action!( 9034 CONVERT_TO_FUNCTION_CALL, 9035 " 9036pub fn main() { 9037 [1, 2, 3] 9038 |> map(todo) 9039} 9040 9041fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 9042", 9043 find_position_of("map").to_selection() 9044 ); 9045} 9046 9047#[test] 9048fn generate_json_encoder() { 9049 let src = " 9050pub type Person { 9051 Person(name: String, age: Int, height: Float, is_cool: Bool) 9052} 9053"; 9054 9055 assert_code_action!( 9056 GENERATE_TO_JSON_FUNCTION, 9057 TestProject::for_source(src).add_package_module( 9058 "gleam_json", 9059 "gleam/json", 9060 "pub type Json" 9061 ), 9062 find_position_of("type").to_selection() 9063 ); 9064} 9065 9066#[test] 9067fn generate_json_only_triggers_within_a_type() { 9068 let src = " 9069pub type Person { 9070 Person(name: String, age: Int, height: Float, is_cool: Bool) 9071} 9072 9073pub fn main() { 9074 // unrelated 9075 todo 9076} 9077"; 9078 9079 assert_no_code_actions!( 9080 GENERATE_TO_JSON_FUNCTION, 9081 TestProject::for_source(src).add_package_module( 9082 "gleam_json", 9083 "gleam/json", 9084 "pub type Json" 9085 ), 9086 find_position_of("type").select_until(find_position_of("todo")) 9087 ); 9088} 9089 9090#[test] 9091fn convert_to_function_call_works_with_argument_in_first_position_2() { 9092 assert_code_action!( 9093 CONVERT_TO_FUNCTION_CALL, 9094 " 9095pub fn main() { 9096 [1, 2, 3] |> wibble 9097} 9098 9099fn wibble(a) { todo } 9100", 9101 find_position_of("wibble").to_selection() 9102 ); 9103} 9104 9105#[test] 9106fn generate_json_encoder_complex_types() { 9107 let src = " 9108import gleam/option 9109import gleam/dict 9110 9111pub type Something 9112 9113pub type Wibble(value) { 9114 Wibble( 9115 maybe: option.Option(Int), 9116 something: Something, 9117 map: dict.Dict(String, List(Float)), 9118 unknown: List(value), 9119 ) 9120} 9121"; 9122 9123 assert_code_action!( 9124 GENERATE_TO_JSON_FUNCTION, 9125 TestProject::for_source(src) 9126 .add_module("gleam/option", "pub type Option(a)") 9127 .add_module("gleam/dict", "pub type Dict(k, v)") 9128 .add_package_module("gleam_json", "gleam/json", "pub type Json"), 9129 find_position_of("type W").to_selection() 9130 ); 9131} 9132 9133#[test] 9134fn convert_to_function_call_works_with_argument_in_first_position_3() { 9135 assert_code_action!( 9136 CONVERT_TO_FUNCTION_CALL, 9137 " 9138pub fn main() { 9139 [1, 2, 3] |> wibble() 9140} 9141 9142fn wibble(a) { todo } 9143", 9144 find_position_of("wibble").to_selection() 9145 ); 9146} 9147 9148#[test] 9149fn generate_json_encoder_already_imported_module() { 9150 let src = " 9151import gleam/json as json_encoding 9152 9153pub type Wibble { 9154 Wibble(a: Int, b: Float, c: String) 9155} 9156"; 9157 9158 assert_code_action!( 9159 GENERATE_TO_JSON_FUNCTION, 9160 TestProject::for_source(src).add_package_module( 9161 "gleam_json", 9162 "gleam/json", 9163 "pub type Json" 9164 ), 9165 find_position_of("type W").to_selection() 9166 ); 9167} 9168 9169#[test] 9170fn convert_to_function_call_works_with_argument_in_first_position_4() { 9171 assert_code_action!( 9172 CONVERT_TO_FUNCTION_CALL, 9173 " 9174pub fn main() { 9175 [1, 2, 3] |> wibble.wobble 9176} 9177", 9178 find_position_of("wibble").to_selection() 9179 ); 9180} 9181 9182#[test] 9183fn generate_json_encoder_tuple() { 9184 let src = " 9185pub type Wibble { 9186 Wibble(tuple: #(Int, Float, #(String, Bool))) 9187} 9188"; 9189 9190 assert_code_action!( 9191 GENERATE_TO_JSON_FUNCTION, 9192 TestProject::for_source(src).add_package_module( 9193 "gleam_json", 9194 "gleam/json", 9195 "pub type Json" 9196 ), 9197 find_position_of("type W").to_selection() 9198 ); 9199} 9200 9201#[test] 9202fn generate_json_encoder_for_variant_with_no_fields() { 9203 let src = " 9204pub type Wibble { 9205 Wibble 9206} 9207"; 9208 9209 assert_code_action!( 9210 GENERATE_TO_JSON_FUNCTION, 9211 TestProject::for_source(src).add_package_module( 9212 "gleam_json", 9213 "gleam/json", 9214 "pub type Json" 9215 ), 9216 find_position_of("type W").to_selection() 9217 ); 9218} 9219 9220#[test] 9221fn generate_json_encoder_for_type_with_multiple_variants_with_no_fields() { 9222 let src = " 9223pub type Wibble { 9224 Wibble 9225 Wobble 9226 Woo 9227} 9228"; 9229 9230 assert_code_action!( 9231 GENERATE_TO_JSON_FUNCTION, 9232 TestProject::for_source(src).add_package_module( 9233 "gleam_json", 9234 "gleam/json", 9235 "pub type Json" 9236 ), 9237 find_position_of("type W").to_selection() 9238 ); 9239} 9240 9241#[test] 9242fn generate_json_encoder_for_variants_with_mixed_fields() { 9243 let src = " 9244pub type Wibble { 9245 Wibble 9246 Wobble(field: String, field1: Int) 9247} 9248"; 9249 9250 assert_code_action!( 9251 GENERATE_TO_JSON_FUNCTION, 9252 TestProject::for_source(src).add_package_module( 9253 "gleam_json", 9254 "gleam/json", 9255 "pub type Json" 9256 ), 9257 find_position_of("type W").to_selection() 9258 ); 9259} 9260 9261#[test] 9262fn convert_to_function_call_works_with_function_producing_another_function() { 9263 assert_code_action!( 9264 CONVERT_TO_FUNCTION_CALL, 9265 " 9266pub fn main() { 9267 1 |> wibble(2) 9268} 9269 9270fn wibble(c) -> fn(a) -> Nil { 9271 fn(_) { Nil } 9272} 9273", 9274 find_position_of("wibble").to_selection() 9275 ); 9276} 9277 9278#[test] 9279fn generate_json_encoder_recursive_type() { 9280 let src = " 9281import gleam/option.{Some} 9282 9283pub type LinkedList { 9284 LinkedList(value: Int, next: option.Option(LinkedList)) 9285} 9286"; 9287 assert_code_action!( 9288 GENERATE_TO_JSON_FUNCTION, 9289 TestProject::for_source(src) 9290 .add_module("gleam/option", "pub type Option(a) { Some(a) None }") 9291 .add_package_module("gleam_json", "gleam/json", "pub type Json"), 9292 find_position_of("type").to_selection() 9293 ); 9294} 9295 9296#[test] 9297fn convert_to_function_call_works_with_hole_in_first_position() { 9298 assert_code_action!( 9299 CONVERT_TO_FUNCTION_CALL, 9300 " 9301pub fn main() { 9302 [1, 2, 3] 9303 |> map(_, todo) 9304} 9305 9306fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 9307", 9308 find_position_of("[").to_selection() 9309 ); 9310} 9311 9312#[test] 9313fn generate_json_encoder_list_of_tuples() { 9314 let src = " 9315pub type Wibble { 9316 Wibble(values: List(#(Int, String))) 9317} 9318"; 9319 9320 assert_code_action!( 9321 GENERATE_TO_JSON_FUNCTION, 9322 TestProject::for_source(src).add_package_module( 9323 "gleam_json", 9324 "gleam/json", 9325 "pub type Json" 9326 ), 9327 find_position_of("type").to_selection() 9328 ); 9329} 9330 9331#[test] 9332fn generate_json_encoder_for_multi_variant_type() { 9333 let src = " 9334pub type Wibble { 9335 Wibble(wibble: Int, next: Wibble) 9336 Wobble(wobble: Float, text: String, values: List(Bool)) 9337} 9338"; 9339 9340 assert_code_action!( 9341 GENERATE_TO_JSON_FUNCTION, 9342 TestProject::for_source(src).add_package_module( 9343 "gleam_json", 9344 "gleam/json", 9345 "pub type Json" 9346 ), 9347 find_position_of("type").to_selection() 9348 ); 9349} 9350 9351#[test] 9352fn generate_json_encoder_for_multi_variant_type_multi_word_name() { 9353 let src = " 9354pub type Wibble { 9355 OneTwoThree(wibble: Int, next: Wibble) 9356 FourFive(wobble: Float, text: String, values: List(Bool)) 9357 SixSevenEight(one_two: Float) 9358} 9359"; 9360 9361 assert_code_action!( 9362 GENERATE_TO_JSON_FUNCTION, 9363 TestProject::for_source(src).add_package_module( 9364 "gleam_json", 9365 "gleam/json", 9366 "pub type Json" 9367 ), 9368 find_position_of("type").to_selection() 9369 ); 9370} 9371 9372#[test] 9373fn convert_to_function_call_works_with_hole_not_in_first_position() { 9374 assert_code_action!( 9375 CONVERT_TO_FUNCTION_CALL, 9376 " 9377pub fn main() { 9378 fn(a) { todo } 9379 |> map([1, 2, 3], _) 9380} 9381 9382fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 9383", 9384 find_position_of("fn(a)").select_until(find_position_of("map")) 9385 ); 9386} 9387 9388#[test] 9389fn convert_to_function_call_always_inlines_the_first_step() { 9390 assert_code_action!( 9391 CONVERT_TO_FUNCTION_CALL, 9392 " 9393pub fn main() { 9394 [1, 2, 3] 9395 |> map(todo) 9396 |> filter(todo) 9397} 9398 9399fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 9400fn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo } 9401", 9402 find_position_of("[1, 2, 3]").select_until(find_position_of("map")) 9403 ); 9404} 9405 9406#[test] 9407fn convert_to_function_call_works_with_labelled_argument() { 9408 assert_code_action!( 9409 CONVERT_TO_FUNCTION_CALL, 9410 " 9411pub fn main() { 9412 [1, 2, 3] |> wibble(wobble: _, woo:) 9413} 9414", 9415 find_position_of("wibble").to_selection() 9416 ); 9417} 9418 9419#[test] 9420fn convert_to_function_call_works_with_labelled_argument_2() { 9421 assert_code_action!( 9422 CONVERT_TO_FUNCTION_CALL, 9423 " 9424pub fn main() { 9425 [1, 2, 3] |> wibble(wobble:, woo: _) 9426} 9427", 9428 find_position_of("wibble").to_selection() 9429 ); 9430} 9431 9432#[test] 9433fn convert_to_function_call_works_when_piping_an_invalid_module_select() { 9434 assert_code_action!( 9435 CONVERT_TO_FUNCTION_CALL, 9436 " 9437pub fn main() { 9438 wibble.wobble |> woo(_) 9439} 9440", 9441 find_position_of("woo").to_selection() 9442 ); 9443} 9444 9445#[test] 9446fn convert_to_function_call_works_when_piping_a_module_select() { 9447 let src = " 9448import wibble 9449 9450pub fn main() { 9451 wibble.wobble |> woo(_) 9452} 9453 9454fn woo(n) { todo } 9455"; 9456 9457 assert_code_action!( 9458 CONVERT_TO_FUNCTION_CALL, 9459 TestProject::for_source(src).add_module("wibble", "pub const wobble = 1"), 9460 find_position_of("woo").to_selection() 9461 ); 9462} 9463 9464#[test] 9465fn convert_to_function_call_works_with_echo() { 9466 assert_code_action!( 9467 CONVERT_TO_FUNCTION_CALL, 9468 " 9469pub fn main() { 9470 wibble.wobble |> echo 9471} 9472", 9473 find_position_of("echo").to_selection() 9474 ); 9475} 9476 9477#[test] 9478fn no_code_action_to_generate_json_encoder_for_type_without_labels() { 9479 let src = " 9480pub type Wibble { 9481 Wibble(Int, Int, String) 9482} 9483 "; 9484 9485 assert_no_code_actions!( 9486 GENERATE_TO_JSON_FUNCTION, 9487 TestProject::for_source(src).add_package_module( 9488 "gleam_json", 9489 "gleam/json", 9490 "pub type Json" 9491 ), 9492 find_position_of("type").to_selection() 9493 ); 9494} 9495 9496#[test] 9497fn no_code_action_to_generate_json_encoder_without_gleam_json_dependency() { 9498 assert_no_code_actions!( 9499 GENERATE_TO_JSON_FUNCTION, 9500 " 9501pub type Wibble { 9502 Wibble(w: Int) 9503} 9504", 9505 find_position_of("type").to_selection() 9506 ); 9507} 9508 9509#[test] 9510fn inline_variable() { 9511 let src = r#" 9512import gleam/io 9513 9514pub fn main() { 9515 let message = "Hello!" 9516 io.println(message) 9517} 9518"#; 9519 assert_code_action!( 9520 INLINE_VARIABLE, 9521 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 9522 find_position_of("message)").to_selection() 9523 ); 9524} 9525 9526#[test] 9527fn inline_variable_from_definition() { 9528 let src = r#" 9529import gleam/io 9530 9531pub fn main() { 9532 let message = "Hello!" 9533 io.println(message) 9534} 9535"#; 9536 assert_code_action!( 9537 INLINE_VARIABLE, 9538 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 9539 find_position_of("message =").to_selection() 9540 ); 9541} 9542 9543#[test] 9544fn inline_variable_in_nested_scope() { 9545 let src = r#" 9546import gleam/io 9547 9548pub fn main() { 9549 let _ = { 9550 let message = "Hello!" 9551 io.println(message) 9552 } 9553} 9554"#; 9555 assert_code_action!( 9556 INLINE_VARIABLE, 9557 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 9558 find_position_of("message =").to_selection() 9559 ); 9560} 9561 9562#[test] 9563fn inline_variable_in_case_scope() { 9564 let src = r#" 9565import gleam/io 9566 9567pub fn main(x) { 9568 case x { 9569 True -> { 9570 let message = "Hello!" 9571 io.println(message) 9572 } 9573 False -> Nil 9574 } 9575} 9576"#; 9577 assert_code_action!( 9578 INLINE_VARIABLE, 9579 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 9580 find_position_of("message =").to_selection() 9581 ); 9582} 9583 9584#[test] 9585fn inline_variable_when_over_let_keyword() { 9586 assert_code_action!( 9587 INLINE_VARIABLE, 9588 r#" 9589pub fn main() { 9590 let x = 123 9591 x + 1 9592} 9593"#, 9594 find_position_of("let").to_selection() 9595 ); 9596} 9597 9598#[test] 9599fn no_code_action_to_inline_variable_used_multiple_times() { 9600 let src = r#" 9601import gleam/io 9602 9603pub fn main() { 9604 let message = "Hello!" 9605 io.println(message) 9606 io.debug(message) 9607} 9608"#; 9609 assert_no_code_actions!( 9610 INLINE_VARIABLE, 9611 TestProject::for_source(src).add_module( 9612 "gleam/io", 9613 "pub fn println(value) {} pub fn debug(value) {}" 9614 ), 9615 find_position_of("message =").to_selection() 9616 ); 9617} 9618 9619#[test] 9620fn no_code_action_to_inline_variable_defined_in_complex_pattern() { 9621 let src = r#" 9622import gleam/io 9623 9624pub fn main() { 9625 let #(message, second, _) = todo 9626 io.println(message) 9627} 9628"#; 9629 assert_no_code_actions!( 9630 INLINE_VARIABLE, 9631 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 9632 find_position_of("message)").to_selection() 9633 ); 9634} 9635 9636#[test] 9637fn no_code_action_to_inline_variable_defined_in_case_clause() { 9638 let src = r#" 9639import gleam/io 9640 9641pub fn main(result) { 9642 case result { 9643 Ok(value) -> value 9644 Error(message) -> { 9645 io.println(message) 9646 panic 9647 } 9648 } 9649} 9650"#; 9651 assert_no_code_actions!( 9652 INLINE_VARIABLE, 9653 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"), 9654 find_position_of("message").nth_occurrence(2).to_selection() 9655 ); 9656} 9657 9658#[test] 9659fn convert_to_pipe_with_function_call_on_first_argument() { 9660 assert_code_action!( 9661 CONVERT_TO_PIPE, 9662 " 9663pub fn main() { 9664 wibble(wobble, woo) 9665} 9666", 9667 find_position_of("wobble").to_selection() 9668 ); 9669} 9670 9671#[test] 9672fn convert_to_pipe_with_function_call_on_second_argument() { 9673 assert_code_action!( 9674 CONVERT_TO_PIPE, 9675 " 9676pub fn main() { 9677 wibble(wobble, woo) 9678} 9679", 9680 find_position_of("woo").to_selection() 9681 ); 9682} 9683 9684#[test] 9685fn convert_to_pipe_with_function_call_on_function_name_extracts_first_argument() { 9686 assert_code_action!( 9687 CONVERT_TO_PIPE, 9688 " 9689pub fn main() { 9690 wibble(wobble, woo) 9691} 9692", 9693 find_position_of("wibble").to_selection() 9694 ); 9695} 9696 9697#[test] 9698fn convert_to_pipe_works_in_anonymous_function_inside_a_pipeline() { 9699 assert_code_action!( 9700 CONVERT_TO_PIPE, 9701 " 9702pub fn main() { 9703 wibble |> wobble(fn() { woo(1) }) 9704} 9705", 9706 find_position_of("woo").to_selection() 9707 ); 9708} 9709 9710#[test] 9711fn convert_to_pipe_works_in_final_step_of_a_pipeline() { 9712 assert_code_action!( 9713 CONVERT_TO_PIPE, 9714 " 9715pub fn main() { 9716 wibble |> wobble(woo(1)) 9717} 9718", 9719 find_position_of("woo").to_selection() 9720 ); 9721} 9722 9723#[test] 9724fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole() { 9725 assert_code_action!( 9726 CONVERT_TO_PIPE, 9727 " 9728pub fn main() { 9729 wibble(wobble: 1, woo: 2) 9730} 9731", 9732 find_position_of("wobble").to_selection() 9733 ); 9734} 9735 9736#[test] 9737fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole_2() { 9738 assert_code_action!( 9739 CONVERT_TO_PIPE, 9740 " 9741pub fn main() { 9742 wibble(wobble: 1, woo: 2) 9743} 9744", 9745 find_position_of("woo").to_selection() 9746 ); 9747} 9748 9749#[test] 9750fn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole() { 9751 assert_code_action!( 9752 CONVERT_TO_PIPE, 9753 " 9754pub fn main() { 9755 wibble(wobble:, woo:) 9756} 9757", 9758 find_position_of("wobble").to_selection() 9759 ); 9760} 9761 9762#[test] 9763fn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole_2() { 9764 assert_code_action!( 9765 CONVERT_TO_PIPE, 9766 " 9767pub fn main() { 9768 wibble(wobble:, woo:) 9769} 9770", 9771 find_position_of("woo").to_selection() 9772 ); 9773} 9774 9775#[test] 9776fn convert_to_pipe_on_first_step_of_pipeline() { 9777 assert_code_action!( 9778 CONVERT_TO_PIPE, 9779 " 9780pub fn main() { 9781 wibble(wobble, woo) |> wobble 9782} 9783", 9784 find_position_of("wibble").to_selection() 9785 ); 9786} 9787 9788#[test] 9789fn convert_to_pipe_not_allowed_on_other_pipeline_steps() { 9790 assert_no_code_actions!( 9791 CONVERT_TO_PIPE, 9792 " 9793pub fn main() { 9794 wibble(wobble) |> wobble(woo) 9795} 9796", 9797 find_position_of("woo").to_selection() 9798 ); 9799} 9800 9801#[test] 9802fn convert_to_pipe_with_function_returning_other_function() { 9803 assert_code_action!( 9804 CONVERT_TO_PIPE, 9805 " 9806pub fn main() { 9807 wibble(wobble)(woo) 9808} 9809", 9810 find_position_of("woo").to_selection() 9811 ); 9812} 9813 9814#[test] 9815fn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use() { 9816 assert_no_code_actions!( 9817 CONVERT_TO_PIPE, 9818 " 9819pub fn main() { 9820 use <- wibble(wobble) 9821 todo 9822} 9823", 9824 find_position_of("wibble").to_selection() 9825 ); 9826} 9827 9828#[test] 9829fn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use_2() { 9830 assert_no_code_actions!( 9831 CONVERT_TO_PIPE, 9832 " 9833pub fn main() { 9834 use <- wibble(wobble) 9835 todo 9836} 9837", 9838 find_position_of("todo").to_selection() 9839 ); 9840} 9841 9842#[test] 9843fn convert_to_pipe_does_not_work_on_function_with_capture() { 9844 assert_no_code_actions!( 9845 CONVERT_TO_PIPE, 9846 "import gleam/int 9847 9848pub fn main() { 9849 let sum = int.add(1, _) 9850 sum 9851} 9852", 9853 find_position_of("1").to_selection() 9854 ); 9855} 9856 9857#[test] 9858fn convert_to_pipe_does_not_work_on_record_with_capture() { 9859 assert_no_code_actions!( 9860 CONVERT_TO_PIPE, 9861 "pub fn main() { 9862 Ok(_) 9863} 9864", 9865 find_position_of("O").to_selection() 9866 ); 9867} 9868 9869#[test] 9870fn convert_to_pipe_works_inside_body_of_use() { 9871 assert_code_action!( 9872 CONVERT_TO_PIPE, 9873 " 9874pub fn main() { 9875 use <- wibble(wobble) 9876 woo(123) 9877} 9878", 9879 find_position_of("woo").to_selection() 9880 ); 9881} 9882 9883#[test] 9884fn convert_to_pipe_pipes_the_outermost_argument() { 9885 assert_code_action!( 9886 CONVERT_TO_PIPE, 9887 " 9888pub fn main() { 9889 wibble(wobble(woo)) 9890} 9891", 9892 find_position_of("wobble").to_selection() 9893 ); 9894} 9895 9896#[test] 9897fn convert_to_pipe_when_first_arg_is_a_pipe_itself() { 9898 assert_code_action!( 9899 CONVERT_TO_PIPE, 9900 " 9901pub fn main() { 9902 wibble(wobble |> woo, waa) 9903} 9904", 9905 find_position_of("wibble").to_selection() 9906 ); 9907} 9908 9909#[test] 9910fn convert_to_pipe_with_string_concat_adds_braces() { 9911 assert_code_action!( 9912 CONVERT_TO_PIPE, 9913 " 9914pub fn main() { 9915 wibble(wobble <> woo, waa) 9916} 9917", 9918 find_position_of("wibble").to_selection() 9919 ); 9920} 9921 9922#[test] 9923fn convert_to_pipe_with_bool_operator_adds_braces() { 9924 assert_code_action!( 9925 CONVERT_TO_PIPE, 9926 " 9927pub fn main() { 9928 wibble(wobble != woo, waa) 9929} 9930", 9931 find_position_of("wibble").to_selection() 9932 ); 9933} 9934 9935#[test] 9936fn convert_to_pipe_with_sum_adds_no_braces() { 9937 assert_code_action!( 9938 CONVERT_TO_PIPE, 9939 " 9940pub fn main() { 9941 wibble(1 + 1, waa) 9942} 9943", 9944 find_position_of("wibble").to_selection() 9945 ); 9946} 9947 9948#[test] 9949fn convert_to_pipe_with_comparison_adds_braces() { 9950 assert_code_action!( 9951 CONVERT_TO_PIPE, 9952 " 9953pub fn main() { 9954 wibble(1.0 >=. 0.0, waa) 9955} 9956", 9957 find_position_of("wibble").to_selection() 9958 ); 9959} 9960 9961#[test] 9962fn convert_to_pipe_with_complex_binop_adds_braces() { 9963 assert_code_action!( 9964 CONVERT_TO_PIPE, 9965 " 9966fn bug() { 9967 bool.guard(1 == 2 || 2 == 3, Nil, fn() { Nil }) 9968} 9969", 9970 find_position_of("||").to_selection() 9971 ); 9972} 9973 9974#[test] 9975fn convert_to_pipe_with_nested_calls_picks_the_innermost_one() { 9976 assert_code_action!( 9977 CONVERT_TO_PIPE, 9978 " 9979fn bug() { 9980 wibble(Wobble( 9981 field: woo(other_call(last)) 9982 )) 9983} 9984", 9985 find_position_of("woo").to_selection() 9986 ); 9987} 9988 9989// https://github.com/gleam-lang/gleam/issues/4342 9990#[test] 9991fn inline_variable_in_record_update() { 9992 assert_code_action!( 9993 INLINE_VARIABLE, 9994 " 9995type Couple { 9996 Couple(l: Int, r: Int) 9997} 9998 9999pub fn main() { 10000 let c1 = Couple(l: 1, r: 1) 10001 let c2 = Couple(..c1, r: 1) 10002} 10003", 10004 find_position_of("c1,").to_selection() 10005 ); 10006} 10007 10008// https://github.com/gleam-lang/gleam/issues/4430 10009#[test] 10010fn inline_variable_with_record_field() { 10011 assert_code_action!( 10012 INLINE_VARIABLE, 10013 " 10014type Couple { 10015 Couple(l: Int, r: Int) 10016} 10017 10018pub fn main() { 10019 let c1 = Couple(l: 1, r: 1) 10020 let c2 = c1.l 10021 echo c2 10022} 10023", 10024 find_position_of("c2").nth_occurrence(2).to_selection() 10025 ); 10026} 10027 10028#[test] 10029fn wrap_case_clause_in_block() { 10030 assert_code_action!( 10031 WRAP_IN_BLOCK, 10032 " 10033pub fn f(option) { 10034 case option { 10035 Some(content) -> content 10036 None -> panic 10037 } 10038}", 10039 find_position_of("content").nth_occurrence(2).to_selection() 10040 ); 10041} 10042 10043#[test] 10044fn wrap_nested_case_clause_in_block() { 10045 assert_code_action!( 10046 WRAP_IN_BLOCK, 10047 " 10048pub fn f(result) { 10049 case result { 10050 Ok(reresult) -> { 10051 case reresult { 10052 Ok(w) -> w 10053 Error(_) -> panic 10054 } 10055 } 10056 Error(_) -> panic 10057 } 10058}", 10059 find_position_of("w").nth_occurrence(2).to_selection() 10060 ); 10061} 10062 10063#[test] 10064fn wrap_case_clause_with_guard_in_block() { 10065 assert_code_action!( 10066 WRAP_IN_BLOCK, 10067 " 10068pub fn f(option) { 10069 case option { 10070 Some(integer) if integer > 0 -> integer 10071 Some(integer) -> 0 10072 None -> panic 10073 } 10074}", 10075 find_position_of("integer").nth_occurrence(3).to_selection() 10076 ); 10077} 10078 10079#[test] 10080fn wrap_case_clause_with_multiple_patterns_in_block() { 10081 assert_code_action!( 10082 WRAP_IN_BLOCK, 10083 "pub type PokemonType { 10084 Air 10085 Water 10086 Fire 10087} 10088 10089 pub fn f(pokemon_type: PokemonType) { 10090 case pokemon_type { 10091 Water | Air -> soak() 10092 Fire -> burn() 10093 } 10094 }", 10095 find_position_of("soak").to_selection() 10096 ); 10097} 10098 10099#[test] 10100fn wrap_case_clause_inside_assignment_in_block() { 10101 assert_code_action!( 10102 WRAP_IN_BLOCK, 10103 r#"pub type PokemonType { 10104 Air 10105 Water 10106 Fire 10107} 10108 10109 pub fn f(pokemon_type: PokemonType) { 10110 let damage = case pokemon_type { 10111 Water -> soak() 10112 Fire -> burn() 10113 } 10114 10115 "Pokemon did " <> damage 10116 }"#, 10117 find_position_of("burn").to_selection() 10118 ); 10119} 10120 10121#[test] 10122fn wrap_case_assignment_of_record_access_in_block() { 10123 assert_code_action!( 10124 WRAP_IN_BLOCK, 10125 r#" 10126pub type Record { 10127 R(left: Int, right: Int) 10128} 10129 10130pub fn main() { 10131 let r = R(1, 2) 10132 let l = r.left 10133 l 10134} 10135"#, 10136 find_position_of("left").nth_occurrence(2).to_selection() 10137 ); 10138} 10139 10140#[test] 10141fn do_not_wrap_case_clause_in_block_1() { 10142 assert_no_code_actions!( 10143 WRAP_IN_BLOCK, 10144 " 10145pub fn f(option) { 10146 case option { 10147 Some(content) -> { 10148 content 10149 } 10150 None -> panic 10151 } 10152}", 10153 find_position_of("content").nth_occurrence(2).to_selection() 10154 ); 10155} 10156 10157#[test] 10158fn do_not_wrap_case_clause_in_block_2() { 10159 assert_no_code_actions!( 10160 WRAP_IN_BLOCK, 10161 " 10162pub fn f(result) { 10163 case result { 10164 Ok(reresult) -> { 10165 case reresult { 10166 Ok(w) -> { 10167 w 10168 } 10169 Error(_) -> panic 10170 } 10171 } 10172 Error(_) -> panic 10173 } 10174}", 10175 find_position_of("w").nth_occurrence(2).to_selection() 10176 ); 10177} 10178 10179#[test] 10180fn do_not_wrap_case_clause_in_block_3() { 10181 assert_no_code_actions!( 10182 WRAP_IN_BLOCK, 10183 " 10184pub fn f(option) { 10185 case option { 10186 Some(content) -> content 10187 None -> panic 10188 } 10189}", 10190 find_position_of("Some(content)").to_selection() 10191 ); 10192} 10193 10194#[test] 10195fn wrap_assignment_value_in_block() { 10196 assert_code_action!( 10197 WRAP_IN_BLOCK, 10198 r#"pub fn main() { 10199 let var = "value" 10200}"#, 10201 find_position_of("value").select_until(find_position_of("e").nth_occurrence(2)) 10202 ); 10203} 10204 10205#[test] 10206fn do_not_wrap_assignment_value_in_block() { 10207 assert_no_code_actions!( 10208 WRAP_IN_BLOCK, 10209 r#"pub fn main() { 10210 let var = "value" 10211}"#, 10212 find_position_of("var").to_selection() 10213 ); 10214} 10215 10216// https://github.com/gleam-lang/gleam/issues/4427 10217#[test] 10218fn extract_constant_function() { 10219 assert_no_code_actions!( 10220 EXTRACT_CONSTANT, 10221 r#" 10222fn print(x) { 10223 Nil 10224} 10225 10226pub fn main() { 10227 print("Hello") 10228} 10229"#, 10230 find_position_of("print").nth_occurrence(2).to_selection() 10231 ); 10232} 10233 10234#[test] 10235fn fix_float_operator_on_ints() { 10236 let name = "Use `>=`"; 10237 assert_code_action!( 10238 name, 10239 r#" 10240pub fn main() { 10241 1 >=. 2 10242} 10243"#, 10244 find_position_of("1").to_selection() 10245 ); 10246} 10247 10248#[test] 10249fn fix_float_operator_on_ints_2() { 10250 let name = "Use `-`"; 10251 assert_code_action!( 10252 name, 10253 r#" 10254pub fn main() { 10255 1 -. 2 10256} 10257"#, 10258 find_position_of("1").select_until(find_position_of("2")) 10259 ); 10260} 10261 10262#[test] 10263fn fix_float_operator_on_ints_3() { 10264 let name = "Use `*`"; 10265 assert_code_action!( 10266 name, 10267 r#" 10268pub fn main() { 10269 1 *. wobble() 10270} 10271 10272fn wobble() { 3 } 10273"#, 10274 find_position_of("*.").to_selection() 10275 ); 10276} 10277 10278#[test] 10279fn fix_int_operator_on_floats() { 10280 let name = "Use `>=.`"; 10281 assert_code_action!( 10282 name, 10283 r#" 10284pub fn main() { 10285 1.0 >= 2.3 10286} 10287"#, 10288 find_position_of("1").to_selection() 10289 ); 10290} 10291 10292#[test] 10293fn fix_int_operator_on_floats_2() { 10294 let name = "Use `-.`"; 10295 assert_code_action!( 10296 name, 10297 r#" 10298pub fn main() { 10299 1.12 - 2.0 10300} 10301"#, 10302 find_position_of("1").select_until(find_position_of("2.0")) 10303 ); 10304} 10305 10306#[test] 10307fn fix_int_operator_on_floats_3() { 10308 let name = "Use `*.`"; 10309 assert_code_action!( 10310 name, 10311 r#" 10312pub fn main() { 10313 1.3 * wobble() 10314} 10315 10316fn wobble() { 3.2 } 10317"#, 10318 find_position_of("*").to_selection() 10319 ); 10320} 10321 10322#[test] 10323fn fix_plus_operator_on_strings() { 10324 let name = "Use `<>`"; 10325 assert_code_action!( 10326 name, 10327 r#" 10328pub fn main() { 10329 "hello, " + name() 10330} 10331 10332fn name() { "Jak" } 10333"#, 10334 find_position_of("hello").select_until(find_position_of("name()")) 10335 ); 10336} 10337 10338#[test] 10339fn fix_float_operator_on_ints_in_guards() { 10340 let name = "Use `>=`"; 10341 assert_code_action!( 10342 name, 10343 r#" 10344pub fn main() { 10345 case todo { 10346 _ if 1 >=. 2 -> todo 10347 } 10348} 10349"#, 10350 find_position_of("1").to_selection() 10351 ); 10352} 10353 10354#[test] 10355fn fix_float_operator_on_ints_in_guards_2() { 10356 let name = "Use `-`"; 10357 assert_code_action!( 10358 name, 10359 r#" 10360pub fn main() { 10361 case todo { 10362 _ if 1 -. 2 -> todo 10363 } 10364} 10365"#, 10366 find_position_of("1").select_until(find_position_of("2")) 10367 ); 10368} 10369 10370#[test] 10371fn fix_float_operator_on_ints_in_guards_3() { 10372 let name = "Use `*`"; 10373 assert_code_action!( 10374 name, 10375 r#" 10376pub fn main() { 10377 let wobble = 3 10378 case todo { 10379 _ if 1 *. wobble -> todo 10380 } 10381} 10382"#, 10383 find_position_of("*.").to_selection() 10384 ); 10385} 10386 10387#[test] 10388fn fix_int_operator_on_floats_in_guards() { 10389 let name = "Use `>=.`"; 10390 assert_code_action!( 10391 name, 10392 r#" 10393pub fn main() { 10394 case todo { 10395 _ if 1.0 >= 2.3 -> todo 10396 } 10397} 10398"#, 10399 find_position_of("1").to_selection() 10400 ); 10401} 10402 10403#[test] 10404fn fix_int_operator_on_floats_in_guards_2() { 10405 let name = "Use `-.`"; 10406 assert_code_action!( 10407 name, 10408 r#" 10409pub fn main() { 10410 case todo { 10411 _ if 1.12 - 2.0 -> todo 10412 } 10413} 10414"#, 10415 find_position_of("1").select_until(find_position_of("2.0")) 10416 ); 10417} 10418 10419#[test] 10420fn fix_int_operator_on_floats_in_guards_3() { 10421 let name = "Use `*.`"; 10422 assert_code_action!( 10423 name, 10424 r#" 10425pub fn main() { 10426 let wobble = 3.2 10427 case todo { 10428 _ if 1.3 * wobble -> todo 10429 } 10430} 10431"#, 10432 find_position_of("*").to_selection() 10433 ); 10434} 10435 10436#[test] 10437fn fix_plus_operator_on_strings_in_guards() { 10438 let name = "Use `<>`"; 10439 assert_code_action!( 10440 name, 10441 r#" 10442pub fn main() { 10443 let name = "jak" 10444 case todo { 10445 _ if "hello, " + name -> todo 10446 } 10447} 10448"#, 10449 find_position_of("hello").select_until(find_position_of("name ->")) 10450 ); 10451} 10452 10453// https://github.com/gleam-lang/gleam/issues/4454 10454#[test] 10455fn unqualify_already_imported_type() { 10456 let src = " 10457import wibble.{type Wibble} 10458 10459pub fn main() -> wibble.Wibble { 10460 todo 10461} 10462"; 10463 10464 assert_code_action!( 10465 "Unqualify wibble.Wibble", 10466 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble"), 10467 find_position_of("wibble.Wibble").to_selection(), 10468 ); 10469} 10470 10471#[test] 10472fn fill_labels_pattern_constructor() { 10473 assert_code_action!( 10474 FILL_LABELS, 10475 " 10476pub type Wibble { 10477 Wibble(a: Int, b: Float, c: String) 10478 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil))) 10479} 10480 10481pub fn main(w: Wibble) { 10482 case w { 10483 Wibble(..) -> todo 10484 Wobble() -> todo 10485 } 10486} 10487", 10488 find_position_of("Wobble()").to_selection(), 10489 ); 10490} 10491 10492#[test] 10493fn fill_labels_pattern_constructor_let_assignment() { 10494 assert_code_action!( 10495 FILL_LABELS, 10496 " 10497pub type Wibble { 10498 Wibble(a: Int, b: Float, c: String) 10499} 10500 10501pub fn main() { 10502 let Wibble() = todo 10503} 10504", 10505 find_position_of("Wibble()").to_selection(), 10506 ); 10507} 10508 10509#[test] 10510fn fill_labels_pattern_constructor_with_some_labels() { 10511 assert_code_action!( 10512 FILL_LABELS, 10513 " 10514pub type Wibble { 10515 Wibble(a: Int, b: Float, c: String) 10516 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil))) 10517} 10518 10519pub fn main(w: Wibble) { 10520 case w { 10521 Wobble(e: <<>>) -> todo 10522 _ -> todo 10523 } 10524} 10525", 10526 find_position_of("Wobble(e").to_selection(), 10527 ); 10528} 10529 10530#[test] 10531fn fill_labels_nested_pattern_constructor() { 10532 assert_code_action!( 10533 FILL_LABELS, 10534 " 10535pub type Wibble { 10536 Wibble(a: Int, b: Float, c: String) 10537 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil))) 10538} 10539 10540pub fn main() { 10541 case todo { 10542 #([Wobble()], 2, 3) -> todo 10543 _ -> todo 10544 } 10545} 10546", 10547 find_position_of("Wobble()").to_selection(), 10548 ); 10549} 10550 10551#[test] 10552// https://github.com/gleam-lang/gleam/issues/4499 10553fn fill_labels_with_function_with_unlabelled_arguments() { 10554 assert_no_code_actions!( 10555 FILL_LABELS, 10556 " 10557pub fn main() { 10558 fold(0, over: [], with: fn(acc, item) { acc + item }) 10559} 10560 10561pub fn fold(over list, from initial, with fun) { todo }", 10562 find_position_of("fold").to_selection(), 10563 ); 10564} 10565 10566#[test] 10567fn add_missing_patterns_with_labels() { 10568 assert_code_action!( 10569 ADD_MISSING_PATTERNS, 10570 " 10571pub type Wibble { 10572 Wibble(integer: Int, float: Float) 10573 Wobble(string: String, bool: Bool) 10574} 10575 10576pub fn main(w: Wibble) { 10577 case w {} 10578} 10579", 10580 find_position_of("case w").select_until(find_position_of("{}")), 10581 ); 10582} 10583 10584// https://github.com/gleam-lang/gleam/issues/3628#issuecomment-2543342212 10585#[test] 10586fn add_missing_patterns_multibyte_grapheme() { 10587 assert_code_action!( 10588 ADD_MISSING_PATTERNS, 10589 r#" 10590// ä 10591fn wibble() { 10592 case True {} 10593} 10594"#, 10595 find_position_of("case").select_until(find_position_of("True {")) 10596 ); 10597} 10598 10599#[test] 10600fn add_missing_patterns_needs_to_be_within_the_inexhaustive_case_expression() { 10601 assert_no_code_actions!( 10602 ADD_MISSING_PATTERNS, 10603 r#" 10604fn wibble() { 10605 case True {} 10606} 10607"#, 10608 find_position_of("fn").select_until(find_position_of("}")) 10609 ); 10610} 10611 10612#[test] 10613fn add_missing_patterns_fires_for_second_inexhaustive_case_when_first_does_not_contain_cursor() { 10614 assert_code_action!( 10615 ADD_MISSING_PATTERNS, 10616 r#" 10617pub fn wibble(a: Bool, b: Bool) { 10618 case a {} 10619 case b {} 10620} 10621"#, 10622 find_position_of("case") 10623 .nth_occurrence(2) 10624 .select_until(find_position_of("b {")) 10625 ); 10626} 10627 10628// https://github.com/gleam-lang/gleam/issues/4626 10629#[test] 10630fn add_missing_patterns_opaque_type() { 10631 let src = " 10632import mod 10633 10634pub fn main(w: mod.Wibble) { 10635 case w {} 10636} 10637"; 10638 10639 assert_code_action!( 10640 ADD_MISSING_PATTERNS, 10641 TestProject::for_source(src).add_hex_module( 10642 "mod", 10643 "pub opaque type Wibble { Wibble(Int) Wobble(String) }" 10644 ), 10645 find_position_of("{}").to_selection(), 10646 ); 10647} 10648 10649#[test] 10650fn pattern_match_on_variable_does_not_add_patterns_for_internal_type() { 10651 let src = " 10652import wibble 10653 10654pub type Type { 10655 Type(wibble: wibble.Wibble, list: List(Int)) 10656} 10657 10658pub fn main(thing: Type) { 10659 case thing { 10660 Type(wibble:, ..) -> todo 10661 } 10662} 10663"; 10664 10665 assert_no_code_actions!( 10666 PATTERN_MATCH_ON_VARIABLE, 10667 TestProject::for_source(src).add_module( 10668 "wibble", 10669 "@internal pub type Wibble { Wibble(Int) Wobble(String) }" 10670 ), 10671 find_position_of("wibble").nth_occurrence(3).to_selection(), 10672 ); 10673} 10674 10675#[test] 10676fn pattern_match_on_argument_does_not_add_patterns_for_internal_type() { 10677 let src = " 10678import wibble 10679 10680pub fn main(thing: wibble.Wibble) {} 10681"; 10682 10683 assert_no_code_actions!( 10684 PATTERN_MATCH_ON_ARGUMENT, 10685 TestProject::for_source(src).add_module( 10686 "wibble", 10687 "@internal pub type Wibble { Wibble(Int) Wobble(String) }" 10688 ), 10689 find_position_of("thing").to_selection(), 10690 ); 10691} 10692 10693#[test] 10694fn pattern_match_on_argument_adds_patterns_for_internal_type_inside_module_where_it_is_defined() { 10695 let src = " 10696@internal 10697pub type Wibble { 10698 Wibble(Int) 10699 Wobble(String) 10700} 10701 10702pub fn main(thing: Wibble) {} 10703"; 10704 10705 assert_code_action!( 10706 PATTERN_MATCH_ON_ARGUMENT, 10707 TestProject::for_source(src), 10708 find_position_of("thing").to_selection(), 10709 ); 10710} 10711 10712#[test] 10713fn add_missing_patterns_adds_a_discard_for_opaque_type() { 10714 let src = " 10715import wibble 10716 10717pub fn main(w: wibble.Wibble) { 10718 case w {} 10719} 10720"; 10721 10722 assert_code_action!( 10723 ADD_MISSING_PATTERNS, 10724 TestProject::for_source(src).add_module( 10725 "wibble", 10726 "@internal pub type Wibble { Wibble(Int) Wobble(String) }" 10727 ), 10728 find_position_of("{}").to_selection(), 10729 ); 10730} 10731 10732#[test] 10733fn add_missing_patterns_adds_a_discard_for_opaque_type_1() { 10734 let src = " 10735import wibble 10736 10737pub type Type { 10738 Type(wibble: wibble.Wibble, list: List(Int)) 10739} 10740 10741pub fn main(thing: Type) { 10742 case thing {} 10743} 10744"; 10745 10746 assert_code_action!( 10747 ADD_MISSING_PATTERNS, 10748 TestProject::for_source(src).add_module( 10749 "wibble", 10750 "@internal pub type Wibble { Wibble(Int) Wobble(String) }" 10751 ), 10752 find_position_of("{}").to_selection(), 10753 ); 10754} 10755 10756#[test] 10757fn add_missing_patterns_adds_a_discard_for_opaque_type_2() { 10758 let src = " 10759import wibble 10760 10761pub type Type { 10762 Type(wibble.Wibble) 10763} 10764 10765pub fn main(thing: Type) { 10766 case thing {} 10767} 10768"; 10769 10770 assert_code_action!( 10771 ADD_MISSING_PATTERNS, 10772 TestProject::for_source(src).add_module( 10773 "wibble", 10774 "@internal pub type Wibble { Wibble(Int) Wobble(String) }" 10775 ), 10776 find_position_of("{}").to_selection(), 10777 ); 10778} 10779 10780#[test] 10781fn add_missing_patterns_adds_patterns_for_internal_type_inside_same_module_where_it_is_defined() { 10782 let src = " 10783@internal 10784pub type Wibble { 10785 Wibble(Int) 10786 Wobble(String) 10787} 10788 10789pub fn main(thing: Wibble) { 10790 case thing {} 10791} 10792"; 10793 10794 assert_code_action!( 10795 ADD_MISSING_PATTERNS, 10796 TestProject::for_source(src), 10797 find_position_of("thing").nth_occurrence(2).to_selection(), 10798 ); 10799} 10800 10801// https://github.com/gleam-lang/gleam/issues/4653 10802#[test] 10803fn generate_function_capture() { 10804 assert_code_action!( 10805 GENERATE_FUNCTION, 10806 " 10807fn map(list: List(a), f: fn(a) -> b) -> List(b) { 10808 todo 10809} 10810 10811pub fn main() { 10812 map([1, 2, 3], add(_, 1)) 10813} 10814", 10815 find_position_of("add").to_selection() 10816 ); 10817} 10818 10819// https://github.com/gleam-lang/gleam/issues/4660#issuecomment-2932371619 10820#[test] 10821fn inline_variable_label_shorthand() { 10822 assert_code_action!( 10823 INLINE_VARIABLE, 10824 " 10825pub type Example { 10826 Example(sum: Int, nil: Nil) 10827} 10828 10829pub fn main() { 10830 let sum = 1 + 1 10831 10832 Example(Nil, sum:) 10833} 10834", 10835 find_position_of("sum = ").to_selection() 10836 ); 10837} 10838 10839// https://github.com/gleam-lang/gleam/issues/4660 10840#[test] 10841fn no_inline_variable_action_for_parameter() { 10842 assert_no_code_actions!( 10843 INLINE_VARIABLE, 10844 " 10845pub fn main() { 10846 let x = fn(something) { 10847 something 10848 } 10849 10850 x 10851} 10852", 10853 find_position_of("something") 10854 .nth_occurrence(2) 10855 .to_selection() 10856 ); 10857} 10858 10859#[test] 10860fn no_inline_variable_action_when_spanning_multiple_items() { 10861 assert_no_code_actions!( 10862 INLINE_VARIABLE, 10863 " 10864pub fn main(x: Int, y: Int) { 10865 let a = 1 10866 let b = 2 10867 main(a, b) 10868} 10869", 10870 find_position_of("main") 10871 .nth_occurrence(2) 10872 .select_until(find_position_of(")").nth_occurrence(2)) 10873 ); 10874} 10875 10876#[test] 10877fn no_inline_variable_action_for_use_pattern() { 10878 assert_no_code_actions!( 10879 INLINE_VARIABLE, 10880 " 10881pub fn main() { 10882 let x = { 10883 use something <- todo 10884 something 10885 } 10886 10887 x 10888} 10889", 10890 find_position_of("something").to_selection() 10891 ); 10892} 10893 10894#[test] 10895fn no_inline_variable_action_for_case_pattern() { 10896 assert_no_code_actions!( 10897 INLINE_VARIABLE, 10898 " 10899pub fn main() { 10900 let x = case todo { 10901 something -> something 10902 } 10903 10904 x 10905} 10906", 10907 find_position_of("something") 10908 .nth_occurrence(2) 10909 .to_selection() 10910 ); 10911} 10912 10913// https://github.com/gleam-lang/gleam/issues/4675 10914#[test] 10915fn extract_variable_use() { 10916 assert_no_code_actions!( 10917 EXTRACT_VARIABLE, 10918 " 10919pub fn main() { 10920 #({ 10921 use <- todo 10922 todo 10923 }) 10924} 10925 ", 10926 find_position_of("use").to_selection() 10927 ); 10928} 10929 10930#[test] 10931fn extract_variable_in_anonymous_fn_in_argument() { 10932 assert_code_action!( 10933 EXTRACT_VARIABLE, 10934 "fn map(value, fn_over_value) { todo } 10935 10936pub fn main() { 10937 1 10938 |> Ok 10939 |> map(fn(value) { value + 2 }) 10940}", 10941 find_position_of("2").to_selection() 10942 ); 10943} 10944 10945#[test] 10946fn extract_variable_starting_pipeline_steps() { 10947 assert_code_action!( 10948 EXTRACT_VARIABLE, 10949 "fn map(value, fn_over_value) { todo } 10950 10951pub fn main() { 10952 1 10953 |> Ok 10954 |> map(fn(value) { value + 2 }) 10955}", 10956 find_position_of("1").select_until(find_position_of("Ok")) 10957 ); 10958} 10959 10960#[test] 10961fn do_not_extract_top_level_variable_in_anonymous_fn_in_argument() { 10962 assert_no_code_actions!( 10963 EXTRACT_VARIABLE, 10964 "fn map(value, fn_over_value) { todo } 10965 10966pub fn main() { 10967 1 10968 |> Ok 10969 |> map(fn(value) { value + 1 }) 10970}", 10971 find_position_of("value").nth_occurrence(4).to_selection() 10972 ); 10973} 10974 10975// https://github.com/gleam-lang/gleam/issues/4739 10976#[test] 10977fn do_not_import_internal_modules() { 10978 const IMPORT_MODULE: &str = "Import `package/internal`"; 10979 let code = " 10980pub fn main() { 10981 internal.some_internal_function() 10982} 10983"; 10984 10985 assert_no_code_actions!( 10986 IMPORT_MODULE, 10987 TestProject::for_source(code).add_package_module( 10988 "package", 10989 "package/internal", 10990 "pub fn some_internal_function() { todo }" 10991 ), 10992 find_position_of("internal").to_selection() 10993 ); 10994} 10995 10996#[test] 10997fn import_internal_module_from_same_package() { 10998 let code = " 10999pub fn main() { 11000 internal.some_internal_function() 11001} 11002"; 11003 11004 assert_code_action!( 11005 "Import `app/internal`", 11006 TestProject::for_source(code).add_package_module( 11007 "app", 11008 "app/internal", 11009 "pub fn some_internal_function() { todo }" 11010 ), 11011 find_position_of("internal").to_selection() 11012 ); 11013} 11014 11015#[test] 11016fn remove_block_1() { 11017 assert_code_action!( 11018 REMOVE_BLOCK, 11019 "pub fn main() { 11020 { 1 } 11021} 11022", 11023 find_position_of("1").to_selection() 11024 ); 11025} 11026 11027#[test] 11028fn remove_block_2() { 11029 assert_code_action!( 11030 REMOVE_BLOCK, 11031 "pub fn main() { 11032 { main() <> 2 } 11033} 11034", 11035 find_position_of("}").to_selection() 11036 ); 11037} 11038 11039#[test] 11040fn remove_block_3() { 11041 assert_code_action!( 11042 REMOVE_BLOCK, 11043 "pub fn main() { 11044 case 1 { 11045 _ -> { main() <> 2 } 11046 } 11047} 11048", 11049 find_position_of("{").nth_occurrence(3).to_selection() 11050 ); 11051} 11052 11053#[test] 11054fn remove_block_triggers_on_the_innermost_selected_block() { 11055 assert_code_action!( 11056 REMOVE_BLOCK, 11057 "pub fn main(x) { 11058 { 11059 main({ 11060 1 11061 }) 11062 } 11063} 11064", 11065 find_position_of("1").to_selection() 11066 ); 11067} 11068 11069#[test] 11070fn remove_block_does_not_unwrap_a_let_assignment() { 11071 assert_no_code_actions!( 11072 REMOVE_BLOCK, 11073 "pub fn main(x) { 11074 { 11075 let a = 1 11076 } 11077} 11078", 11079 find_position_of("let").to_selection() 11080 ); 11081} 11082 11083#[test] 11084fn remove_block_unwraps_a_single_expression_in_a_binop() { 11085 assert_code_action!( 11086 REMOVE_BLOCK, 11087 "pub fn main(x) { 11088 { main(1) } * 3 11089} 11090", 11091 find_position_of("main").nth_occurrence(2).to_selection() 11092 ); 11093} 11094 11095#[test] 11096fn remove_block_does_not_unwrap_a_binop() { 11097 assert_no_code_actions!( 11098 REMOVE_BLOCK, 11099 "pub fn main(x) { 11100 { 1 * 2 } + 3 11101} 11102", 11103 find_position_of("1").to_selection() 11104 ); 11105} 11106 11107#[test] 11108fn remove_block_does_not_unwrap_a_block_with_multiple_statements() { 11109 assert_no_code_actions!( 11110 REMOVE_BLOCK, 11111 "pub fn main(x) { 11112 { 11113 main(1) 11114 main(2) 11115 } 11116} 11117", 11118 find_position_of("1").to_selection() 11119 ); 11120} 11121 11122#[test] 11123fn remove_opaque_from_private_type() { 11124 assert_code_action!( 11125 REMOVE_OPAQUE_FROM_PRIVATE_TYPE, 11126 "opaque type Wibble { 11127 Wobble 11128} 11129", 11130 find_position_of("Wibble").to_selection() 11131 ); 11132} 11133 11134#[test] 11135fn allow_further_pattern_matching_on_let_tuple_destructuring() { 11136 assert_code_action!( 11137 PATTERN_MATCH_ON_VARIABLE, 11138 "pub fn main(x) { 11139 let #(one, other) = #(Ok(1), Error(Nil)) 11140} 11141", 11142 find_position_of("one").to_selection() 11143 ); 11144} 11145 11146#[test] 11147fn allow_further_pattern_matching_on_let_record_destructuring() { 11148 assert_code_action!( 11149 PATTERN_MATCH_ON_VARIABLE, 11150 "pub fn main(x) { 11151 let Wibble(field:) = Wibble(Ok(Nil)) 11152} 11153 11154pub type Wibble { Wibble(field: Result(Nil, String)) } 11155", 11156 find_position_of("field").to_selection() 11157 ); 11158} 11159 11160#[test] 11161fn allow_further_pattern_matching_on_asserted_result() { 11162 assert_code_action!( 11163 PATTERN_MATCH_ON_VARIABLE, 11164 "pub fn main(x) { 11165 let assert Ok(one) = Ok(Error(Nil)) 11166} 11167", 11168 find_position_of("one").to_selection() 11169 ); 11170} 11171 11172#[test] 11173fn allow_further_pattern_matching_on_asserted_list() { 11174 assert_code_action!( 11175 PATTERN_MATCH_ON_VARIABLE, 11176 "pub fn main(x) { 11177 let assert [first, ..] = [Ok(Nil), ..todo] 11178 todo 11179} 11180", 11181 find_position_of("first").to_selection() 11182 ); 11183} 11184 11185#[test] 11186fn pattern_match_on_list_variable() { 11187 assert_code_action!( 11188 PATTERN_MATCH_ON_ARGUMENT, 11189 "pub fn main(a_list: List(a)) { 11190 todo 11191}", 11192 find_position_of("a_list").to_selection() 11193 ); 11194} 11195 11196#[test] 11197fn pattern_match_on_list_tail() { 11198 assert_code_action!( 11199 PATTERN_MATCH_ON_VARIABLE, 11200 "pub fn main(a_list: List(a)) { 11201 case a_list { 11202 [] -> todo 11203 [first, ..rest] -> todo 11204 } 11205}", 11206 find_position_of("rest").to_selection() 11207 ); 11208} 11209 11210#[test] 11211fn pattern_match_on_list_tail_with_strange_whitespace() { 11212 assert_code_action!( 11213 PATTERN_MATCH_ON_VARIABLE, 11214 "pub fn main(a_list: List(a)) { 11215 case a_list { 11216 [] -> todo 11217 [first, .. rest] -> todo 11218 } 11219}", 11220 find_position_of(" ").to_selection() 11221 ); 11222} 11223 11224#[test] 11225fn pattern_match_on_list_tail_used_in_a_branch() { 11226 assert_code_action!( 11227 PATTERN_MATCH_ON_VARIABLE, 11228 "pub fn main(a_list: List(a)) { 11229 case a_list { 11230 [] -> todo 11231 [first, ..rest] -> rest 11232 } 11233}", 11234 find_position_of("rest").to_selection() 11235 ); 11236} 11237 11238#[test] 11239fn pattern_match_on_list_tail_with_shadowed_name() { 11240 assert_code_action!( 11241 PATTERN_MATCH_ON_VARIABLE, 11242 "pub fn main(a_list: List(a)) { 11243 case a_list { 11244 [] -> todo 11245 [rest, ..else_] -> todo 11246 } 11247}", 11248 find_position_of("else_").to_selection() 11249 ); 11250} 11251 11252#[test] 11253fn pattern_match_on_discard_pattern_in_branch() { 11254 assert_code_action!( 11255 PATTERN_MATCH_ON_VALUE, 11256 "pub fn main(x: Result(List(a), Nil)) { 11257 case x { 11258 Error(Nil) -> todo 11259 Ok(_) -> todo 11260 } 11261}", 11262 find_position_of("_").to_selection() 11263 ); 11264} 11265 11266#[test] 11267fn cannot_pattern_match_on_discard_on_the_left_of_an_assignment() { 11268 assert_no_code_actions!( 11269 PATTERN_MATCH_ON_VALUE, 11270 "pub fn main(x: Result(List(a), Nil)) { 11271 let _ = x 11272}", 11273 find_position_of("_").to_selection() 11274 ); 11275} 11276 11277#[test] 11278fn cannot_pattern_match_on_discard_on_the_left_of_a_use() { 11279 assert_no_code_actions!( 11280 PATTERN_MATCH_ON_VALUE, 11281 "pub fn main() { 11282 use _ <- wibble() 11283} 11284 11285fn wibble(fun: fn(Result(Int, Nil)) -> Nil) { 11286 todo 11287} 11288", 11289 find_position_of("_").to_selection() 11290 ); 11291} 11292 11293#[test] 11294fn collapse_nested_case() { 11295 assert_code_action!( 11296 COLLAPSE_NESTED_CASE, 11297 "pub fn main(x) { 11298 case x { 11299 Ok(var) -> case var { 11300 1 -> 2 11301 2 -> 4 11302 _ -> -1 11303 } 11304 _ -> todo 11305 } 11306}", 11307 find_position_of("var").to_selection() 11308 ); 11309} 11310 11311#[test] 11312fn collapse_nested_case_works_with_blocks() { 11313 assert_code_action!( 11314 COLLAPSE_NESTED_CASE, 11315 "pub fn main(x) { 11316 case x { 11317 Ok(var) -> { 11318 case var { 11319 1 -> 2 11320 2 -> 4 11321 _ -> -1 11322 } 11323 } 11324 _ -> todo 11325 } 11326}", 11327 find_position_of("var").to_selection() 11328 ); 11329} 11330 11331#[test] 11332fn collapse_nested_case_works_with_patterns_defining_multiple_variables() { 11333 assert_code_action!( 11334 COLLAPSE_NESTED_CASE, 11335 "pub fn main(x) { 11336 case x { 11337 Wibble(var, var2) -> 11338 case var { 11339 1 -> 2 11340 2 -> 4 11341 _ -> -1 11342 } 11343 11344 Wobble -> todo 11345 } 11346} 11347 11348pub type Wibble { 11349 Wibble(Int, String) 11350 Wobble 11351} 11352", 11353 find_position_of("var").to_selection() 11354 ); 11355} 11356 11357#[test] 11358fn collapse_nested_case_does_not_remove_labels() { 11359 assert_code_action!( 11360 COLLAPSE_NESTED_CASE, 11361 "pub fn main(x) { 11362 case x { 11363 Wibble(field2:, field: wibble) -> 11364 case wibble { 11365 1 -> 2 11366 2 -> 4 11367 _ -> -1 11368 } 11369 11370 Wobble -> todo 11371 } 11372} 11373 11374pub type Wibble { 11375 Wibble(field: Int, field2: String) 11376 Wobble 11377} 11378", 11379 find_position_of("field").to_selection() 11380 ); 11381} 11382 11383#[test] 11384fn collapse_nested_case_does_not_remove_labels_with_shorthand_syntax() { 11385 assert_code_action!( 11386 COLLAPSE_NESTED_CASE, 11387 "pub fn main(x) { 11388 case x { 11389 Wibble(field2:, field:) -> 11390 case field { 11391 1 -> 2 11392 2 -> 4 11393 _ -> -1 11394 } 11395 11396 Wobble -> todo 11397 } 11398} 11399 11400pub type Wibble { 11401 Wibble(field: Int, field2: String) 11402 Wobble 11403} 11404", 11405 find_position_of("field").to_selection() 11406 ); 11407} 11408 11409#[test] 11410fn collapse_nested_case_works_with_alternative_patterns() { 11411 assert_code_action!( 11412 COLLAPSE_NESTED_CASE, 11413 "pub fn main(x) { 11414 case x { 11415 [first, ..rest] -> 11416 case first { 11417 1 | 2 -> True 11418 3 | 4 | 5 -> False 11419 _ -> False 11420 } 11421 11422 [] -> True 11423 } 11424} 11425", 11426 find_position_of("first").to_selection() 11427 ); 11428} 11429 11430#[test] 11431fn collapse_nested_case_aliases_variable_if_it_is_used() { 11432 assert_code_action!( 11433 COLLAPSE_NESTED_CASE, 11434 "pub fn main(x) { 11435 case x { 11436 [first, ..rest] -> 11437 case first { 11438 1 | 2 -> first 11439 3 | 4 | 5 -> 5 11440 _ -> 0 11441 } 11442 11443 [] -> -1 11444 } 11445} 11446", 11447 find_position_of("first").to_selection() 11448 ); 11449} 11450 11451#[test] 11452fn collapse_nested_case_does_not_ignore_outer_guards() { 11453 assert_code_action!( 11454 COLLAPSE_NESTED_CASE, 11455 "pub fn main(x) { 11456 case x { 11457 [first, ..rest] if True -> 11458 case first { 11459 1 -> 1.1 11460 _ -> 0.0 *. 10.0 11461 } 11462 11463 [] -> 1.1 11464 } 11465} 11466", 11467 find_position_of("first").to_selection() 11468 ); 11469} 11470 11471#[test] 11472fn collapse_nested_case_does_not_ignore_inner_guards() { 11473 assert_code_action!( 11474 COLLAPSE_NESTED_CASE, 11475 "pub fn main(x) { 11476 case x { 11477 [first, ..rest] -> 11478 case first { 11479 1 -> 1.1 11480 _ if True -> 0.0 *. 10.0 11481 _ -> 0.0 11482 } 11483 11484 [] -> 1.1 11485 } 11486} 11487", 11488 find_position_of("first").to_selection() 11489 ); 11490} 11491 11492#[test] 11493fn collapse_nested_case_combines_inner_and_outer_guards() { 11494 assert_code_action!( 11495 COLLAPSE_NESTED_CASE, 11496 "pub fn main(x) { 11497 case x { 11498 [first, ..rest] if False -> 11499 case first { 11500 1 if False -> 1.1 11501 _ if True -> 0.0 *. 10.0 11502 _ -> 0.0 11503 } 11504 11505 [] -> 1.1 11506 } 11507} 11508", 11509 find_position_of("first").to_selection() 11510 ); 11511} 11512 11513#[test] 11514fn collapse_nested_case_combines_inner_and_outer_guards_and_adds_parentheses_when_needed() { 11515 assert_code_action!( 11516 COLLAPSE_NESTED_CASE, 11517 "pub fn main(x) { 11518 case x { 11519 [first, ..rest] if False || True -> 11520 case first { 11521 1 if False && True -> 1.1 11522 _ if True || False -> 0.0 *. 10.0 11523 _ -> 0.0 11524 } 11525 11526 [] -> 1.1 11527 } 11528} 11529", 11530 find_position_of("first").to_selection() 11531 ); 11532} 11533 11534#[test] 11535fn collapse_nested_case_combines_list_with_unformatted_tail() { 11536 assert_code_action!( 11537 COLLAPSE_NESTED_CASE, 11538 r#"pub fn main(elems: List(String)) { 11539 case elems { 11540 [first, .. rest_of_list] -> 11541 case rest_of_list { 11542 [] -> 0 11543 ["first"] -> 1 11544 [_, "second"] -> 2 11545 [_, "second", "third", _] -> 4 11546 _ -> -1 11547 } 11548 _ -> -1 11549 } 11550}"#, 11551 find_position_of("rest").to_selection() 11552 ); 11553} 11554 11555#[test] 11556fn collapse_nested_case_combines_list_with_tail() { 11557 assert_code_action!( 11558 COLLAPSE_NESTED_CASE, 11559 r#"pub fn main(elems: List(List(Int))) { 11560 case elems { 11561 [] -> 0 11562 [_, ..tail] -> 11563 case tail { 11564 [] -> -1 11565 [[1]] -> 1 11566 [_, [3, 4]] -> 3 11567 [_, _, [5, 6, 7], _] -> 5 11568 tail_list -> { 11569 echo tail_list 11570 -1 11571 } 11572 } 11573 _ -> -1 11574 } 11575}"#, 11576 find_position_of("tail").to_selection() 11577 ); 11578} 11579 11580// https://github.com/gleam-lang/gleam/issues/3786 11581#[test] 11582fn type_variables_from_other_functions_do_not_change_annotations() { 11583 assert_code_action!( 11584 ADD_ANNOTATIONS, 11585 " 11586fn wibble(a: a, b: b, c: c) -> d { todo } 11587 11588fn pair(a, b) { 11589 #(a, b) 11590} 11591", 11592 find_position_of("pair").to_selection() 11593 ); 11594} 11595 11596#[test] 11597fn type_variables_from_other_functions_do_not_change_annotations_constant() { 11598 assert_code_action!( 11599 ADD_ANNOTATION, 11600 " 11601fn wibble(a: a, b: b, c: c) -> d { todo } 11602 11603const empty = [] 11604", 11605 find_position_of("empty").to_selection() 11606 ); 11607} 11608 11609#[test] 11610fn type_variables_are_not_duplicated_when_adding_annotations() { 11611 assert_code_action!( 11612 ADD_ANNOTATIONS, 11613 " 11614fn wibble(a: a, b: b, c: c) -> d { todo } 11615 11616fn many_args(a, b, c, d: d, e: a, f, g) { 11617 todo 11618} 11619", 11620 find_position_of("many_args").to_selection() 11621 ); 11622} 11623 11624#[test] 11625fn type_variables_in_let_bindings_are_considered_when_adding_annotations() { 11626 assert_code_action!( 11627 ADD_ANNOTATIONS, 11628 " 11629fn wibble(a, b, c) { 11630 let x: a = todo 11631 fn(a: b, b: c) -> d { 11632 todo 11633 } 11634} 11635", 11636 find_position_of("wibble").to_selection() 11637 ); 11638} 11639 11640#[test] 11641fn generated_function_annotations_are_not_affected_by_other_functions() { 11642 assert_code_action!( 11643 GENERATE_FUNCTION, 11644 " 11645fn wibble(a: a, b: b, c: c) -> d { todo } 11646 11647pub fn main() { 11648 let x = todo 11649 let y = todo 11650 let #(a, b) = something(x, y) 11651 b 11652} 11653", 11654 find_position_of("something").to_selection() 11655 ); 11656} 11657 11658#[test] 11659fn generate_function_in_other_module() { 11660 let src = " 11661import wibble 11662 11663pub fn main() { 11664 wibble.wibble() 11665 wibble.wobble() 11666} 11667"; 11668 11669 assert_code_action!( 11670 GENERATE_FUNCTION, 11671 TestProject::for_source(src).add_module("wibble", "pub fn wibble() {}"), 11672 find_position_of("wobble").to_selection() 11673 ); 11674} 11675 11676#[test] 11677fn generate_function_is_not_offered_for_variants() { 11678 assert_no_code_actions!( 11679 GENERATE_FUNCTION, 11680 " 11681pub type Wibble 11682 11683pub fn main() -> Wibble { 11684 Wobble(1) 11685} 11686", 11687 find_position_of("Wobble").to_selection() 11688 ); 11689} 11690 11691#[test] 11692fn generating_function_in_other_module_uses_local_names() { 11693 let src = r#" 11694import wibble 11695 11696pub fn main() -> List(Nil) { 11697 wibble.wibble(1, #(True, "Hello")) 11698} 11699"#; 11700 11701 assert_code_action!( 11702 GENERATE_FUNCTION, 11703 TestProject::for_source(src).add_module( 11704 "wibble", 11705 "import gleam.{type Int as Number, type Bool as Boolean, type String as Text, type Nil as Nothing}" 11706 ), 11707 find_position_of("wibble(").to_selection() 11708 ); 11709} 11710 11711#[test] 11712fn generating_function_in_other_module_uses_labels() { 11713 let src = r#" 11714import wibble 11715 11716pub fn main() { 11717 wibble.wibble("Unlabelled", int: 1, bool: True) 11718} 11719"#; 11720 11721 assert_code_action!( 11722 GENERATE_FUNCTION, 11723 TestProject::for_source(src).add_module("wibble", ""), 11724 find_position_of("wibble(").to_selection() 11725 ); 11726} 11727 11728#[test] 11729fn no_code_action_to_generate_existing_function_in_other_module() { 11730 let src = r#" 11731import wibble 11732 11733pub fn main() { 11734 wibble.wibble(1, 2, 3) 11735} 11736"#; 11737 11738 assert_no_code_actions!( 11739 GENERATE_FUNCTION, 11740 TestProject::for_source(src).add_module("wibble", "pub fn wibble(a, b, c) { a + b + c }"), 11741 find_position_of("wibble(").to_selection() 11742 ); 11743} 11744 11745#[test] 11746fn do_not_generate_function_in_other_package() { 11747 let src = r#" 11748import maths 11749 11750pub fn main() { 11751 maths.add(1, 2) 11752 maths.subtract(1, 2) 11753} 11754"#; 11755 11756 assert_no_code_actions!( 11757 GENERATE_FUNCTION, 11758 TestProject::for_source(src).add_dep_module("maths", "pub fn add(a, b) { a + b }"), 11759 find_position_of("subtract").to_selection() 11760 ); 11761} 11762 11763#[test] 11764fn remove_unreachable_clauses() { 11765 assert_code_action!( 11766 REMOVE_UNREACHABLE_CLAUSES, 11767 "pub fn main(x) { 11768 case x { 11769 Ok(n) -> 1 11770 Ok(_) -> 2 11771 Error(_) -> todo 11772 Ok(1) -> 3 11773 } 11774} 11775", 11776 find_position_of("Ok(1)").to_selection() 11777 ); 11778} 11779 11780#[test] 11781fn remove_unreachable_clauses_removes_alternative_patterns() { 11782 assert_code_action!( 11783 REMOVE_UNREACHABLE_CLAUSES, 11784 "pub fn main(x) { 11785 case x { 11786 Ok(n) -> 1 11787 Ok(1) -> 3 11788 Error(_) | Ok(_) -> todo 11789 } 11790} 11791", 11792 find_position_of("Ok(1)").to_selection() 11793 ); 11794} 11795 11796#[test] 11797fn remove_unreachable_clauses_removes_multiple_alternative_patterns_at_the_start_of_branch() { 11798 assert_code_action!( 11799 REMOVE_UNREACHABLE_CLAUSES, 11800 "pub fn main(x) { 11801 case x { 11802 Ok(n) -> 1 11803 Ok(1) -> 3 11804 Ok(_) | Ok(_) | Ok(_) | Error(_) -> todo 11805 } 11806} 11807", 11808 find_position_of("Ok(1)").to_selection() 11809 ); 11810} 11811 11812#[test] 11813fn remove_unreachable_clauses_removes_multiple_alternative_patterns_at_the_end_of_branch() { 11814 assert_code_action!( 11815 REMOVE_UNREACHABLE_CLAUSES, 11816 "pub fn main(x) { 11817 case x { 11818 Ok(n) -> 1 11819 Ok(1) -> 3 11820 Error(_) | Ok(_) | Ok(_) | Ok(_) -> todo 11821 } 11822} 11823", 11824 find_position_of("Ok(1)").to_selection() 11825 ); 11826} 11827 11828#[test] 11829fn remove_unreachable_clauses_removes_multiple_alternative_patterns_in_the_middle_of_branch() { 11830 assert_code_action!( 11831 REMOVE_UNREACHABLE_CLAUSES, 11832 "pub fn main(x) { 11833 case x { 11834 1 -> todo 11835 2 -> todo 11836 3 | 3 | 3 | 3 | 4 -> todo 11837 } 11838} 11839", 11840 find_position_of("3").nth_occurrence(2).to_selection() 11841 ); 11842} 11843 11844#[test] 11845fn remove_unreachable_clauses_with_mix_of_reachable_and_unreachables() { 11846 assert_code_action!( 11847 REMOVE_UNREACHABLE_CLAUSES, 11848 "pub fn main(x) { 11849 case x { 11850 1 -> todo 11851 2 -> todo 11852 3 | 3 | 3 | 4 | 3 | 5 -> todo 11853 } 11854} 11855", 11856 find_position_of("3").nth_occurrence(2).to_selection() 11857 ); 11858} 11859 11860#[test] 11861fn remove_unreachable_clauses_can_be_triggered_from_alternative_pattern() { 11862 assert_code_action!( 11863 REMOVE_UNREACHABLE_CLAUSES, 11864 "pub fn main(x) { 11865 case x { 11866 Ok(n) -> 1 11867 Error(_) | Ok(_) -> 3 11868 Ok(1) -> todo 11869 } 11870} 11871", 11872 find_position_of("Ok(_)").to_selection() 11873 ); 11874} 11875 11876#[test] 11877fn remove_unreachable_branches_does_not_pop_up_if_all_branches_are_reachable() { 11878 assert_no_code_actions!( 11879 REMOVE_UNREACHABLE_CLAUSES, 11880 "pub fn main(x) { 11881 case x { 11882 Ok(n) -> 1 11883 Error(_) -> todo 11884 } 11885 11886 case x { 11887 Ok(n) -> todo 11888 Ok(_) -> todo 11889 _ -> todo 11890 } 11891} 11892", 11893 find_position_of("Ok(n)").to_selection() 11894 ); 11895} 11896 11897#[test] 11898fn add_type_annotations_public_alias_to_internal_type_aliased_module() { 11899 let src = " 11900import package as pkg 11901 11902pub fn main() { 11903 pkg.make_wibble() 11904} 11905"; 11906 11907 assert_code_action!( 11908 ADD_ANNOTATION, 11909 TestProject::for_source(src) 11910 .add_package_module( 11911 "package", 11912 "package", 11913 " 11914import package/internal 11915 11916pub type Wibble = internal.Wibble 11917 11918pub fn make_wibble() { 11919 internal.Wibble 11920} 11921" 11922 ) 11923 .add_package_module("package", "package/internal", "pub type Wibble { Wibble }"), 11924 find_position_of("main").to_selection(), 11925 ); 11926} 11927 11928// https://github.com/gleam-lang/gleam/issues/3898 11929#[test] 11930fn add_type_annotations_public_alias_to_internal_type() { 11931 let src = " 11932import package 11933 11934pub fn main() { 11935 package.make_wibble() 11936} 11937"; 11938 11939 assert_code_action!( 11940 ADD_ANNOTATION, 11941 TestProject::for_source(src) 11942 .add_package_module( 11943 "package", 11944 "package", 11945 " 11946import package/internal 11947 11948pub type Wibble = internal.Wibble 11949 11950pub fn make_wibble() { 11951 internal.Wibble 11952} 11953" 11954 ) 11955 .add_package_module("package", "package/internal", "pub type Wibble { Wibble }"), 11956 find_position_of("main").to_selection(), 11957 ); 11958} 11959 11960#[test] 11961fn add_type_annotations_public_alias_to_internal_generic_type() { 11962 let src = " 11963import package 11964 11965pub fn main() { 11966 package.make_wibble(10) 11967} 11968"; 11969 11970 assert_code_action!( 11971 ADD_ANNOTATION, 11972 TestProject::for_source(src) 11973 .add_package_module( 11974 "package", 11975 "package", 11976 " 11977import package/internal 11978 11979pub type Wibble(a, b) = internal.Wibble(a, b) 11980 11981pub fn make_wibble(x) { 11982 internal.Wibble(x) 11983} 11984" 11985 ) 11986 .add_package_module( 11987 "package", 11988 "package/internal", 11989 "pub type Wibble(a, b) { Wibble(a) }" 11990 ), 11991 find_position_of("main").to_selection(), 11992 ); 11993} 11994 11995#[test] 11996fn add_type_annotations_uses_internal_name_for_same_package() { 11997 let src = " 11998import thepackage/internal 11999 12000pub fn main() { 12001 internal.Constructor 12002} 12003"; 12004 12005 assert_code_action!( 12006 ADD_ANNOTATION, 12007 TestProject::for_source(src) 12008 .add_module( 12009 "thepackage/internal", 12010 " 12011pub type Internal { Constructor } 12012" 12013 ) 12014 .add_module( 12015 "thepackage/external", 12016 " 12017import thepackage/internal 12018 12019pub type External = internal.Internal 12020" 12021 ), 12022 find_position_of("main").to_selection(), 12023 ); 12024} 12025 12026#[test] 12027fn add_omitted_labels_in_function_call() { 12028 assert_code_action!( 12029 ADD_OMITTED_LABELS, 12030 " 12031pub fn main() { 12032 labelled(1, 2) 12033} 12034 12035pub fn labelled(a a, b b) { todo } 12036 ", 12037 find_position_of("labelled").to_selection(), 12038 ); 12039} 12040 12041#[test] 12042fn add_omitted_labels_in_function_call_with_some_labels() { 12043 assert_code_action!( 12044 ADD_OMITTED_LABELS, 12045 " 12046pub fn main() { 12047 labelled(1, 2) 12048} 12049 12050pub fn labelled(a, b b) { todo } 12051 ", 12052 find_position_of("labelled").to_selection(), 12053 ); 12054} 12055 12056#[test] 12057fn add_omitted_labels_in_function_call_uses_shorthand_syntax() { 12058 assert_code_action!( 12059 ADD_OMITTED_LABELS, 12060 " 12061pub fn main() { 12062 let a = 1 12063 labelled(a, 2) 12064} 12065 12066pub fn labelled(a a, b b) { todo } 12067 ", 12068 find_position_of("labelled").to_selection(), 12069 ); 12070} 12071 12072#[test] 12073fn add_omitted_labels_works_with_innermost_function_call() { 12074 assert_code_action!( 12075 ADD_OMITTED_LABELS, 12076 " 12077pub fn main() { 12078 let a = 1 12079 labelled(a, labelled(1, 2)) 12080} 12081 12082pub fn labelled(a a, b b) { todo } 12083 ", 12084 find_position_of("labelled") 12085 .nth_occurrence(2) 12086 .to_selection(), 12087 ); 12088} 12089 12090#[test] 12091fn add_omitted_labels_works_with_constructors_calls() { 12092 assert_code_action!( 12093 ADD_OMITTED_LABELS, 12094 " 12095pub fn main() { 12096 Labelled(1, 2) 12097} 12098 12099pub type Labelled { 12100 Labelled(Int, b: Int) 12101} 12102 ", 12103 find_position_of("Labelled").to_selection(), 12104 ); 12105} 12106 12107#[test] 12108fn add_omitted_labels_works_with_constructors_calls_with_some_labels_1() { 12109 assert_code_action!( 12110 ADD_OMITTED_LABELS, 12111 " 12112pub fn main() { 12113 labelled(3, 1, b: 2) 12114} 12115 12116pub fn labelled(a a, b b, c c) { todo } 12117 ", 12118 find_position_of("labelled").to_selection(), 12119 ); 12120} 12121 12122#[test] 12123fn add_omitted_labels_works_with_constructors_calls_with_some_labels() { 12124 assert_code_action!( 12125 ADD_OMITTED_LABELS, 12126 " 12127pub fn main() { 12128 let a = 1 12129 labelled(a, b: 2) 12130} 12131 12132pub fn labelled(a a, b b) { todo } 12133 ", 12134 find_position_of("labelled").to_selection(), 12135 ); 12136} 12137 12138#[test] 12139fn add_omitted_labels_works_on_call_with_wrongly_placed_labels() { 12140 assert_code_action!( 12141 ADD_OMITTED_LABELS, 12142 " 12143pub fn main() { 12144 labelled(3, b: 2, 1) 12145} 12146 12147pub fn labelled(a a, b b, c c) { todo } 12148 ", 12149 find_position_of("labelled").to_selection(), 12150 ); 12151} 12152 12153#[test] 12154fn add_omitted_labels_does_not_work_on_call_with_wrong_labels_2() { 12155 assert_no_code_actions!( 12156 ADD_OMITTED_LABELS, 12157 " 12158pub fn main() { 12159 labelled(3, 1, d: 2) 12160} 12161 12162pub fn labelled(a a, b b, c c) { todo } 12163 ", 12164 find_position_of("labelled").to_selection(), 12165 ); 12166} 12167 12168#[test] 12169fn add_omitted_labels_does_not_pop_up_if_called_function_has_no_labels() { 12170 assert_no_code_actions!( 12171 ADD_OMITTED_LABELS, 12172 " 12173pub fn main() { 12174 let a = 1 12175 labelled(a, 2) 12176} 12177 12178pub fn labelled(a, b) { todo } 12179 ", 12180 find_position_of("labelled").to_selection(), 12181 ); 12182} 12183 12184#[test] 12185fn add_omitted_labels_does_not_label_piped_argument() { 12186 assert_code_action!( 12187 ADD_OMITTED_LABELS, 12188 " 12189pub fn main() { 12190 1 |> labelled(2) 12191} 12192 12193pub fn labelled(a a, b b) { todo } 12194 ", 12195 find_position_of("labelled").to_selection(), 12196 ); 12197} 12198 12199#[test] 12200fn add_omitted_labels_does_not_label_use() { 12201 assert_code_action!( 12202 ADD_OMITTED_LABELS, 12203 " 12204pub fn main() { 12205 use <- labelled(1) 12206 todo 12207} 12208 12209pub fn labelled(a a, b b) { todo } 12210 ", 12211 find_position_of("labelled").to_selection(), 12212 ); 12213} 12214 12215#[test] 12216fn extract_function() { 12217 assert_code_action!( 12218 EXTRACT_FUNCTION, 12219 " 12220pub fn do_things(a, b) { 12221 let result = { 12222 let a = 10 + a 12223 let b = 10 + b 12224 a * b 12225 } 12226 result + 3 12227} 12228", 12229 find_position_of("{") 12230 .nth_occurrence(2) 12231 .select_until(find_position_of("}")) 12232 ); 12233} 12234 12235#[test] 12236fn extract_function_with_selected_expression_in_statement() { 12237 assert_code_action!( 12238 EXTRACT_FUNCTION, 12239 " 12240pub fn do_things(a, b) { 12241 let result = call(a, []) 12242 result + 3 12243} 12244", 12245 find_position_of("call").select_until(find_position_of("[]")) 12246 ); 12247} 12248 12249#[test] 12250fn extract_function_with_selected_pipeline_expression_in_statement() { 12251 assert_code_action!( 12252 EXTRACT_FUNCTION, 12253 " 12254pub fn do_things(a, b) { 12255 let result = 12256 wibble 12257 |> wobble 12258 |> woo 12259 12260 result + 3 12261} 12262", 12263 find_position_of("wibble").select_until(find_position_of("woo")) 12264 ); 12265} 12266 12267#[test] 12268fn extract_function_with_assignment_expression_and_multiple_assignments() { 12269 assert_code_action!( 12270 EXTRACT_FUNCTION, 12271 " 12272pub fn do_things(a, b) { 12273 let result = 12274 wibble 12275 |> wobble 12276 |> woo 12277 12278 let a = result + 2 12279 12280 a + 3 12281} 12282", 12283 find_position_of("wibble").select_until(find_position_of("2")) 12284 ); 12285} 12286 12287#[test] 12288fn extract_function_inside_anonymous_function_returning_value() { 12289 assert_code_action!( 12290 EXTRACT_FUNCTION, 12291 r#" 12292fn wibble() { 12293 let wobble = fn() { 12294 let random_number = 4 12295 random_number * 42 12296 } 12297} 12298"#, 12299 find_position_of("random_number") 12300 .nth_occurrence(2) 12301 .select_until(find_position_of("42")), 12302 ); 12303} 12304 12305#[test] 12306fn extract_function_after_anonymous_function() { 12307 assert_code_action!( 12308 EXTRACT_FUNCTION, 12309 r#" 12310fn wibble() { 12311 let wobble = fn() { 12312 let random_number = 4 12313 random_number * 42 12314 } 12315 wobble() / 22 12316} 12317"#, 12318 find_position_of("wobble()").select_until(find_position_of("22").under_last_char()), 12319 ); 12320} 12321 12322#[test] 12323fn extract_function_first_statement_inside_of_use() { 12324 assert_code_action!( 12325 EXTRACT_FUNCTION, 12326 r#" 12327pub fn wibble() { 12328 use wobble <- result.map(todo) 12329 echo wobble as "1" 12330 echo wobble as "2" 12331 echo wobble as "3" 12332 echo wobble as "4" 12333} 12334"#, 12335 find_position_of("echo").select_until(find_position_of("1\"")) 12336 ); 12337} 12338 12339#[test] 12340fn extract_function_second_statement_inside_of_use() { 12341 assert_code_action!( 12342 EXTRACT_FUNCTION, 12343 r#" 12344pub fn wibble() { 12345 use wobble <- result.map(todo) 12346 echo wobble as "1" 12347 echo wobble as "2" 12348 echo wobble as "3" 12349 echo wobble as "4" 12350} 12351"#, 12352 find_position_of("echo") 12353 .nth_occurrence(2) 12354 .select_until(find_position_of("2\"")) 12355 ); 12356} 12357 12358#[test] 12359fn extract_function_last_statement_inside_of_use() { 12360 assert_code_action!( 12361 EXTRACT_FUNCTION, 12362 r#" 12363pub fn wibble() { 12364 use wobble <- result.map(todo) 12365 echo wobble as "1" 12366 echo wobble as "2" 12367 echo wobble as "3" 12368 echo wobble as "4" 12369} 12370"#, 12371 find_position_of("echo") 12372 .nth_occurrence(4) 12373 .select_until(find_position_of("4\"")) 12374 ); 12375} 12376 12377#[test] 12378fn extract_function_first_few_statements_inside_of_use() { 12379 assert_code_action!( 12380 EXTRACT_FUNCTION, 12381 r#" 12382pub fn wibble() { 12383 use wobble <- result.map(todo) 12384 echo wobble as "1" 12385 echo wobble as "2" 12386 echo wobble as "3" 12387 echo wobble as "4" 12388} 12389"#, 12390 find_position_of("echo").select_until(find_position_of("2\"")) 12391 ); 12392} 12393 12394#[test] 12395fn extract_function_middle_few_statements_inside_of_use() { 12396 assert_code_action!( 12397 EXTRACT_FUNCTION, 12398 r#" 12399pub fn wibble() { 12400 use wobble <- result.map(todo) 12401 echo wobble as "1" 12402 echo wobble as "2" 12403 echo wobble as "3" 12404 echo wobble as "4" 12405} 12406"#, 12407 find_position_of("echo") 12408 .nth_occurrence(2) 12409 .select_until(find_position_of("3\"")) 12410 ); 12411} 12412 12413#[test] 12414fn extract_function_last_few_statements_inside_of_use() { 12415 assert_code_action!( 12416 EXTRACT_FUNCTION, 12417 r#" 12418pub fn wibble() { 12419 use wobble <- result.map(todo) 12420 echo wobble as "1" 12421 echo wobble as "2" 12422 echo wobble as "3" 12423 echo wobble as "4" 12424} 12425"#, 12426 find_position_of("echo") 12427 .nth_occurrence(3) 12428 .select_until(find_position_of("4\"")) 12429 ); 12430} 12431 12432#[test] 12433fn extract_function_all_statements_inside_of_use() { 12434 assert_code_action!( 12435 EXTRACT_FUNCTION, 12436 r#" 12437pub fn wibble() { 12438 use wobble <- result.map(todo) 12439 echo wobble as "1" 12440 echo wobble as "2" 12441 echo wobble as "3" 12442 echo wobble as "4" 12443} 12444"#, 12445 find_position_of("echo").select_until(find_position_of("4\"")) 12446 ); 12447} 12448 12449#[test] 12450fn extract_function_from_statements() { 12451 assert_code_action!( 12452 EXTRACT_FUNCTION, 12453 " 12454pub fn do_things(a, b) { 12455 let a = 10 + a 12456 let b = 10 + b 12457 let result = a * b 12458 result + 3 12459} 12460", 12461 find_position_of("let").select_until(find_position_of("* b")) 12462 ); 12463} 12464 12465#[test] 12466fn extract_function_which_use_variables_defined_in_the_extracted_span() { 12467 assert_code_action!( 12468 EXTRACT_FUNCTION, 12469 " 12470pub fn do_things(a, b) { 12471 let new_a = 10 + a 12472 let new_b = 10 + b 12473 let result = new_a * new_b 12474 result + 3 12475} 12476", 12477 find_position_of("let").select_until(find_position_of("* new_b")) 12478 ); 12479} 12480 12481#[test] 12482fn extract_function_which_use_variables_shadowed_in_an_inner_scope() { 12483 assert_code_action!( 12484 EXTRACT_FUNCTION, 12485 " 12486pub fn do_things(a, b) { 12487 let first_part = { 12488 let a = a + 10 12489 let b = b + 10 12490 a * b 12491 } 12492 let result = first_part + a * b 12493 result + 3 12494} 12495", 12496 find_position_of("let").select_until(find_position_of("+ a * b")) 12497 ); 12498} 12499 12500#[test] 12501fn extract_function_which_uses_multiple_extracted_variables() { 12502 assert_code_action!( 12503 EXTRACT_FUNCTION, 12504 " 12505pub fn do_things(a, b) { 12506 let wibble = a + b 12507 let wobble = a * b 12508 wobble / wibble 12509} 12510", 12511 find_position_of("let").select_until(find_position_of("* b")) 12512 ); 12513} 12514 12515#[test] 12516fn extract_function_which_uses_no_extracted_variables() { 12517 assert_code_action!( 12518 EXTRACT_FUNCTION, 12519 " 12520pub fn do_things(a, b) { 12521 let x = a + b 12522 echo x 12523 a 12524} 12525", 12526 find_position_of("let").select_until(find_position_of("echo x")) 12527 ); 12528} 12529 12530#[test] 12531fn extract_function_which_uses_variable_in_guard() { 12532 assert_code_action!( 12533 EXTRACT_FUNCTION, 12534 " 12535pub fn do_things(a, b) { 12536 let result = case Nil { 12537 _ if a > b -> 17 12538 _ if a < b -> 12 12539 _ -> panic 12540 } 12541 12542 result % 4 12543} 12544", 12545 find_position_of("case").select_until(find_position_of("}")) 12546 ); 12547} 12548 12549#[test] 12550fn extract_function_which_uses_variable_in_bit_array_pattern() { 12551 assert_code_action!( 12552 EXTRACT_FUNCTION, 12553 " 12554pub fn main() { 12555 let bits = todo 12556 let size = todo 12557 12558 let segment = case bits { 12559 <<x:size(size), _:bits>> -> Ok(x) 12560 _ -> Error(Nil) 12561 } 12562 12563 case segment { 12564 Ok(value) -> echo value 12565 Error(_) -> panic 12566 } 12567} 12568", 12569 find_position_of("case").select_until(find_position_of("}")) 12570 ); 12571} 12572 12573#[test] 12574fn extract_function_which_uses_constant() { 12575 assert_code_action!( 12576 EXTRACT_FUNCTION, 12577 " 12578const pi = 3.14 12579 12580pub fn main() { 12581 let radius = 4.5 12582 12583 let circumference = radius *. pi *. 2.0 12584 12585 echo circumference 12586} 12587", 12588 find_position_of("radius *.").select_until(find_position_of("2.0")) 12589 ); 12590} 12591 12592#[test] 12593fn extract_function_which_uses_constant_in_guard() { 12594 assert_code_action!( 12595 EXTRACT_FUNCTION, 12596 r#" 12597const pi = 3.14 12598 12599pub fn main() { 12600 let value = 3.15 12601 12602 let string = case value { 12603 0.0 -> "Zero" 12604 1.0 -> "One" 12605 _ if value == pi -> "PI" 12606 _ -> "Something else" 12607 } 12608 12609 echo string 12610} 12611"#, 12612 find_position_of("case").select_until(find_position_of("}")) 12613 ); 12614} 12615 12616#[test] 12617fn no_extract_function_selecting_multiple_case_branches() { 12618 assert_no_code_actions!( 12619 EXTRACT_FUNCTION, 12620 r#" 12621const pi = 3.14 12622 12623pub fn main() { 12624 let value = 3.15 12625 12626 let string = case value { 12627 0.0 -> "Zero" 12628 1.0 -> "One" 12629 _ -> "Something else" 12630 } 12631 12632 echo string 12633} 12634"#, 12635 find_position_of("0.0").select_until(find_position_of("else")) 12636 ); 12637} 12638 12639#[test] 12640fn no_extract_function_selecting_case_branch_pattern() { 12641 assert_no_code_actions!( 12642 EXTRACT_FUNCTION, 12643 r#" 12644const pi = 3.14 12645 12646pub fn main() { 12647 let value = 3.15 12648 12649 let string = case value { 12650 0.0 -> "Zero" 12651 1.0 -> "One" 12652 _ -> "Something else" 12653 } 12654 12655 echo string 12656} 12657"#, 12658 find_position_of("0.0").select_until(find_position_of("Zero").under_last_char()) 12659 ); 12660} 12661 12662#[test] 12663fn no_extract_function_selecting_case_branch_guard() { 12664 assert_no_code_actions!( 12665 EXTRACT_FUNCTION, 12666 r#" 12667const pi = 3.14 12668 12669pub fn main() { 12670 let value = 3.15 12671 12672 let string = case value { 12673 0.0 if True -> "Zero" 12674 1.0 -> "One" 12675 _ -> "Something else" 12676 } 12677 12678 echo string 12679} 12680"#, 12681 find_position_of("True") 12682 .under_char('u') 12683 .select_until(find_position_of("Zero").under_last_char()) 12684 ); 12685} 12686 12687#[test] 12688fn extract_use_inside_function() { 12689 assert_code_action!( 12690 EXTRACT_FUNCTION, 12691 r#" 12692fn wibble(f) { todo } 12693 12694pub fn main() { 12695 use a <- wibble() 12696 Ok(Nil) 12697} 12698"#, 12699 find_position_of("use").select_until(find_position_of("<-")) 12700 ); 12701} 12702 12703#[test] 12704fn extract_use_inside_block() { 12705 assert_code_action!( 12706 EXTRACT_FUNCTION, 12707 r#" 12708fn wibble(f) -> Int { todo } 12709 12710pub fn main() { 12711 let wobble = { 12712 use a <- wibble() 12713 Ok(Nil) 12714 } 12715 12716 wobble 12717} 12718"#, 12719 find_position_of("use").select_until(find_position_of("Nil)")) 12720 ); 12721} 12722 12723#[test] 12724fn extract_use_with_some_statements_before() { 12725 assert_code_action!( 12726 EXTRACT_FUNCTION, 12727 r#" 12728fn wibble(f) { todo } 12729 12730pub fn main() { 12731 let a = wibble(todo) 12732 use a <- wibble() 12733 Ok(Nil) 12734} 12735"#, 12736 find_position_of("let").select_until(find_position_of("use")) 12737 ); 12738} 12739 12740#[test] 12741fn extract_use_including_some_statements_after() { 12742 assert_code_action!( 12743 EXTRACT_FUNCTION, 12744 r#" 12745fn wibble(f) { todo } 12746 12747pub fn main() { 12748 let wobble = { 12749 use a <- wibble() 12750 Ok(Nil) 12751 } 12752 wibble(panic) 12753 12754 wobble 12755} 12756"#, 12757 find_position_of("let").select_until(find_position_of("panic)")) 12758 ); 12759} 12760 12761#[test] 12762fn extract_entire_pipeline() { 12763 assert_code_action!( 12764 EXTRACT_FUNCTION, 12765 r#" 12766pub fn main() { 12767 True 12768 |> wibble 12769 |> wobble 12770} 12771 12772fn wibble(_) { 1 } 12773fn wobble(_) { 1.0 } 12774"#, 12775 find_position_of("True").select_until(find_position_of("wobble")) 12776 ); 12777} 12778 12779#[test] 12780fn extract_starting_steps_of_pipeline() { 12781 assert_code_action!( 12782 EXTRACT_FUNCTION, 12783 r#" 12784pub fn main() { 12785 True 12786 |> wibble 12787 |> wobble 12788} 12789 12790fn wibble(_) { 1 } 12791fn wobble(_) { 1.0 } 12792"#, 12793 find_position_of("True").select_until(find_position_of("wibble")) 12794 ); 12795} 12796 12797#[test] 12798fn extract_starting_steps_of_pipeline_with_argument() { 12799 assert_code_action!( 12800 EXTRACT_FUNCTION, 12801 r#" 12802pub fn main() { 12803 let something = 1 12804 12805 True 12806 |> wibble(something) 12807 |> wobble 12808} 12809 12810fn wibble(_, _) { 1 } 12811fn wobble(_) { 1.0 } 12812"#, 12813 find_position_of("True").select_until(find_position_of("wibble")) 12814 ); 12815} 12816 12817#[test] 12818fn extract_final_steps_of_pipeline() { 12819 assert_code_action!( 12820 EXTRACT_FUNCTION, 12821 r#" 12822pub fn main() { 12823 True 12824 |> wibble 12825 |> wobble 12826} 12827 12828fn wibble(_) { 1 } 12829fn wobble(_) { 1.0 } 12830"#, 12831 find_position_of("wibble").select_until(find_position_of("wobble")) 12832 ); 12833} 12834 12835#[test] 12836fn extract_final_steps_of_pipeline_with_arguments() { 12837 assert_code_action!( 12838 EXTRACT_FUNCTION, 12839 r#" 12840pub fn main() { 12841 let something = 1 12842 12843 True 12844 |> wibble 12845 |> wobble(something) 12846} 12847 12848fn wibble(_) { 1 } 12849fn wobble(_, _) { 1.0 } 12850"#, 12851 find_position_of("wibble").select_until(find_position_of("wobble")) 12852 ); 12853} 12854 12855#[test] 12856fn extract_middle_steps_of_pipeline() { 12857 assert_code_action!( 12858 EXTRACT_FUNCTION, 12859 r#" 12860pub fn main() { 12861 True 12862 |> wibble 12863 |> wobble 12864 |> woo 12865} 12866 12867fn wibble(_) { 1 } 12868fn wobble(_) { 1.0 } 12869fn woo(_) { [] } 12870"#, 12871 find_position_of("wibble").select_until(find_position_of("wobble")) 12872 ); 12873} 12874 12875#[test] 12876fn extract_middle_steps_of_pipeline_with_arguments() { 12877 assert_code_action!( 12878 EXTRACT_FUNCTION, 12879 r#" 12880pub fn main() { 12881 let something = 1 12882 12883 True 12884 |> wibble(1) 12885 |> wobble(something) 12886 |> woo 12887} 12888 12889fn wibble(_, _) { 1 } 12890fn wobble(_, _) { 1.0 } 12891fn woo(_) { [] } 12892"#, 12893 find_position_of("wibble").select_until(find_position_of("wobble")) 12894 ); 12895} 12896 12897#[test] 12898fn cannot_extract_a_single_starting_step_as_function() { 12899 assert_no_code_actions!( 12900 EXTRACT_FUNCTION, 12901 r#" 12902pub fn main() { 12903 True 12904 |> wibble 12905 |> wobble 12906 |> woo 12907} 12908 12909fn wibble(_, _) { 1 } 12910fn wobble(_, _) { 1.0 } 12911fn woo(_) { [] } 12912"#, 12913 find_position_of("True").to_selection() 12914 ); 12915} 12916 12917#[test] 12918fn cannot_extract_a_single_middle_step_as_function() { 12919 assert_no_code_actions!( 12920 EXTRACT_FUNCTION, 12921 r#" 12922pub fn main() { 12923 True 12924 |> wibble 12925 |> wobble 12926 |> woo 12927} 12928 12929fn wibble(_, _) { 1 } 12930fn wobble(_, _) { 1.0 } 12931fn woo(_) { [] } 12932"#, 12933 find_position_of("wibble").to_selection() 12934 ); 12935} 12936 12937#[test] 12938fn cannot_extract_a_single_final_step_as_function() { 12939 assert_no_code_actions!( 12940 EXTRACT_FUNCTION, 12941 r#" 12942pub fn main() { 12943 True 12944 |> wibble 12945 |> wobble 12946 |> woo 12947} 12948 12949fn wibble(_, _) { 1 } 12950fn wobble(_, _) { 1.0 } 12951fn woo(_) { [] } 12952"#, 12953 find_position_of("woo").to_selection() 12954 ); 12955} 12956 12957#[test] 12958fn no_code_action_to_extract_function_when_expression_is_not_fully_selected() { 12959 assert_no_code_actions!( 12960 EXTRACT_FUNCTION, 12961 r#" 12962fn print(text: String) { todo } 12963 12964pub fn main() { 12965 let arguments = todo 12966 12967 case arguments { 12968 ["help"] -> print("USAGE TEXT HERE") 12969 _ -> panic as "Invalid args" 12970 } 12971} 12972"#, 12973 find_position_of("print") 12974 .under_char('i') 12975 .select_until(find_position_of("TEXT")) 12976 ); 12977} 12978 12979#[test] 12980fn extract_function_when_name_already_in_scope() { 12981 assert_code_action!( 12982 EXTRACT_FUNCTION, 12983 r#" 12984fn function() { todo } 12985 12986pub fn do_things(a, b) { 12987 let result = { 12988 let a = 10 + a 12989 let b = 10 + b 12990 a * b 12991 } 12992 result + 3 12993} 12994"#, 12995 find_position_of("= {").select_until(find_position_of("}").nth_occurrence(2)) 12996 ); 12997} 12998 12999#[test] 13000fn extract_function_when_multiple_names_already_in_scope() { 13001 assert_code_action!( 13002 EXTRACT_FUNCTION, 13003 r#" 13004fn function() { todo } 13005fn function_2() { todo } 13006fn function_3() { todo } 13007fn function_4() { todo } 13008 13009pub fn do_things(a, b) { 13010 let result = { 13011 let a = 10 + a 13012 let b = 10 + b 13013 a * b 13014 } 13015 result + 3 13016} 13017"#, 13018 find_position_of("= {").select_until(find_position_of("}").nth_occurrence(5)) 13019 ); 13020} 13021 13022#[test] 13023fn extract_function_partially_selected() { 13024 assert_code_action!( 13025 EXTRACT_FUNCTION, 13026 r#" 13027pub fn main() { 13028 let a = 10 13029 let b = 20 13030 let c = a + b 13031 13032 echo c 13033} 13034"#, 13035 find_position_of("a =").select_until(find_position_of("c =")) 13036 ); 13037} 13038 13039#[test] 13040fn selected_statements_do_not_select_outer_block() { 13041 // We want to make sure only the statements within the block are extracted, 13042 // and not the block itself. 13043 assert_code_action!( 13044 EXTRACT_FUNCTION, 13045 r#" 13046pub fn main() { 13047 let c = { 13048 let a = 10 13049 let b = 20 13050 a + b 13051 } 13052 13053 echo c 13054} 13055"#, 13056 find_position_of("let a").select_until(find_position_of("+ b")) 13057 ); 13058} 13059 13060#[test] 13061fn no_code_action_to_extract_when_multiple_functions_are_selected() { 13062 assert_no_code_actions!( 13063 EXTRACT_FUNCTION, 13064 r#" 13065pub fn main() { 13066 let a = 10 13067 a + 1 13068} 13069 13070pub fn other() { 13071 let b = 20 13072 b * 2 13073} 13074"#, 13075 find_position_of("let a").select_until(find_position_of("let b")) 13076 ); 13077} 13078 13079#[test] 13080fn extract_statements_in_tail_position() { 13081 assert_code_action!( 13082 EXTRACT_FUNCTION, 13083 r#" 13084pub fn main() { 13085 let a = 1 13086 let b = 2 13087 let c = 3 13088 let d = 4 13089 a * b + c * d 13090} 13091"#, 13092 find_position_of("let c").select_until(find_position_of("* d")) 13093 ); 13094} 13095 13096#[test] 13097fn extract_use_in_tail_position() { 13098 assert_code_action!( 13099 EXTRACT_FUNCTION, 13100 r#" 13101pub fn main() { 13102 use <- wibble 13103 123 13104} 13105 13106fn wibble(f: fn() -> Int) -> Int { f() } 13107"#, 13108 find_position_of("use").select_until(find_position_of("wibble")) 13109 ); 13110} 13111 13112#[test] 13113fn extract_use_in_tail_position_2() { 13114 assert_code_action!( 13115 EXTRACT_FUNCTION, 13116 r#" 13117pub fn main() { 13118 use <- wibble 13119 use <- wobble 13120 123 13121} 13122 13123fn wibble(f: fn() -> Float) -> Float { f() } 13124fn wobble(f: fn() -> Int) -> Float { 1.1 } 13125"#, 13126 find_position_of("use") 13127 .nth_occurrence(2) 13128 .select_until(find_position_of("wobble")) 13129 ); 13130} 13131 13132#[test] 13133fn extract_block_tail_position_3() { 13134 assert_code_action!( 13135 EXTRACT_FUNCTION, 13136 r#" 13137pub fn main() { 13138 case 1 { 13139 _ -> { 13140 use <- wibble 13141 123 13142 } 13143 _ -> todo 13144 } 13145} 13146 13147fn wibble(f: fn() -> Float) -> Float { f() } 13148"#, 13149 find_position_of("{") 13150 .nth_occurrence(3) 13151 .select_until(find_position_of("}")) 13152 ); 13153} 13154 13155#[test] 13156fn extract_block_tail_position_4() { 13157 assert_code_action!( 13158 EXTRACT_FUNCTION, 13159 r#" 13160pub fn main() { 13161 case 1 { 13162 _ -> { 13163 use <- wibble 13164 use <- wibble 13165 123 13166 } 13167 _ -> todo 13168 } 13169} 13170 13171fn wibble(f: fn() -> Float) -> Float { f() } 13172"#, 13173 find_position_of("{") 13174 .nth_occurrence(3) 13175 .select_until(find_position_of("}")) 13176 ); 13177} 13178 13179// https://github.com/gleam-lang/gleam/issues/5036 13180#[test] 13181fn generate_function_in_other_module_correctly_appends() { 13182 let src = "import module_breaker/another 13183 13184pub fn main() -> Nil { 13185 another.function() 13186} 13187"; 13188 13189 assert_code_action!( 13190 GENERATE_FUNCTION, 13191 TestProject::for_source(src).add_module( 13192 "module_breaker/another", 13193 "pub fn useless() { 13194 Nil 13195} 13196" 13197 ), 13198 find_position_of("function").to_selection() 13199 ); 13200} 13201 13202// https://github.com/gleam-lang/gleam/issues/4904 13203#[test] 13204fn no_code_action_to_generate_function_on_unsupported_target() { 13205 assert_no_code_actions!( 13206 GENERATE_FUNCTION, 13207 r#" 13208pub fn main() { 13209 wibble() 13210} 13211 13212@external(javascript, "./ffi.mjs", "wibble") 13213fn wibble() -> Nil 13214"#, 13215 find_position_of("wibble").to_selection() 13216 ); 13217} 13218 13219#[test] 13220fn merge_case_branch() { 13221 assert_code_action!( 13222 MERGE_CASE_BRANCHES, 13223 r#"pub fn go(n: Int) { 13224 case n { 13225 1 -> todo 13226 2 -> todo 13227 _ -> todo 13228 } 13229 }"#, 13230 find_position_of("1").select_until(find_position_of("2")) 13231 ); 13232} 13233 13234#[test] 13235fn merge_case_branch_with_todo_keeps_the_non_todo_body() { 13236 assert_code_action!( 13237 MERGE_CASE_BRANCHES, 13238 r#"pub fn go(n: Int) { 13239 case n { 13240 1 -> todo 13241 2 -> n * 2 13242 3 -> todo 13243 _ -> todo 13244 } 13245 }"#, 13246 find_position_of("1").select_until(find_position_of("3")) 13247 ); 13248} 13249 13250#[test] 13251fn merge_case_branch_with_todo_keeps_the_non_todo_body_1() { 13252 assert_code_action!( 13253 MERGE_CASE_BRANCHES, 13254 r#"pub fn go(n: Int) { 13255 case n { 13256 1 -> todo 13257 2 -> todo 13258 3 -> n * 2 13259 _ -> todo 13260 } 13261 }"#, 13262 find_position_of("1").select_until(find_position_of("3")) 13263 ); 13264} 13265 13266#[test] 13267fn merge_case_branch_with_todo_keeps_the_non_todo_body_2() { 13268 assert_code_action!( 13269 MERGE_CASE_BRANCHES, 13270 r#"pub fn go(n: Int) { 13271 case n { 13272 1 -> n * 2 13273 2 -> todo 13274 3 -> todo 13275 _ -> todo 13276 } 13277 }"#, 13278 find_position_of("1").select_until(find_position_of("3")) 13279 ); 13280} 13281 13282#[test] 13283fn merge_case_branch_with_complex_bodies_1() { 13284 assert_code_action!( 13285 MERGE_CASE_BRANCHES, 13286 r#"pub fn go(n: Int) { 13287 case n { 13288 1 -> Ok("one or two") 13289 2 -> Ok("one or two") 13290 _ -> Error("neither one or two") 13291 } 13292 }"#, 13293 find_position_of("1").select_until(find_position_of("2")) 13294 ); 13295} 13296 13297#[test] 13298fn merge_case_branch_with_complex_bodies_2() { 13299 assert_code_action!( 13300 MERGE_CASE_BRANCHES, 13301 r#"pub fn go(n: Int) { 13302 case n { 13303 1 -> n 13304 2 -> n 13305 _ -> panic as "neither one nor two" 13306 } 13307 }"#, 13308 find_position_of("1").select_until(find_position_of("2")) 13309 ); 13310} 13311 13312#[test] 13313fn merge_case_branch_with_complex_bodies_3() { 13314 assert_code_action!( 13315 MERGE_CASE_BRANCHES, 13316 r#"pub fn go(n: Int) { 13317 case n { 13318 1 -> go(n - 1) 13319 2 -> go(n - 1) 13320 _ -> 10 13321 } 13322}"#, 13323 find_position_of("1").select_until(find_position_of("2")) 13324 ); 13325} 13326 13327#[test] 13328fn merge_case_branch_with_complex_bodies_4() { 13329 assert_code_action!( 13330 MERGE_CASE_BRANCHES, 13331 r#"pub fn go(n: Int) { 13332 case n { 13333 1 -> { 13334 let a = go(n - 1) 13335 a * 10 13336 } 13337 2 -> { 13338 let a = go(n - 1) 13339 a * 10 13340 } 13341 _ -> 10 13342 } 13343}"#, 13344 find_position_of("1").select_until(find_position_of("2")) 13345 ); 13346} 13347 13348#[test] 13349fn merge_case_branch_will_not_merge_branches_with_guards() { 13350 assert_no_code_actions!( 13351 MERGE_CASE_BRANCHES, 13352 r#"pub fn go(n: Int) { 13353 case n { 13354 1 if True -> todo 13355 2 -> todo 13356 _ -> todo 13357 } 13358 }"#, 13359 find_position_of("1").select_until(find_position_of("2")) 13360 ); 13361} 13362 13363#[test] 13364fn merge_case_branch_will_not_merge_branches_defining_different_variables() { 13365 assert_no_code_actions!( 13366 MERGE_CASE_BRANCHES, 13367 r#"pub fn go(result: Result(Int, Int)) { 13368 case result { 13369 Ok(value) -> todo 13370 Error(error) -> todo 13371 _ -> todo 13372 } 13373 }"#, 13374 find_position_of("Ok").select_until(find_position_of("error")) 13375 ); 13376} 13377 13378#[test] 13379fn merge_case_branch_can_merge_branches_defining_the_same_variables() { 13380 assert_code_action!( 13381 MERGE_CASE_BRANCHES, 13382 r#"pub fn go(result) { 13383 case result { 13384 [Ok(value), ..] -> todo 13385 [_, Error(value)] -> todo 13386 _ -> todo 13387 } 13388}"#, 13389 find_position_of("Ok").select_until(find_position_of("todo").nth_occurrence(2)) 13390 ); 13391} 13392 13393#[test] 13394fn merge_case_branch_can_merge_multiple_branches() { 13395 assert_code_action!( 13396 MERGE_CASE_BRANCHES, 13397 r#"pub fn go(result) { 13398 case result { 13399 [_] -> 1 13400 [Ok(value), ..] -> todo 13401 [_, Error(value)] -> todo 13402 [_, _, Error(value)] -> todo 13403 [_, _] -> 1 13404 _ -> 2 13405 } 13406}"#, 13407 find_position_of("todo").select_until(find_position_of("todo").nth_occurrence(3)) 13408 ); 13409} 13410 13411#[test] 13412fn merge_case_branch_does_not_pop_up_with_a_single_selected_branch() { 13413 assert_no_code_actions!( 13414 MERGE_CASE_BRANCHES, 13415 r#"pub fn go(result) { 13416 case result { 13417 [] -> todo 13418 _ -> 2 13419 } 13420}"#, 13421 find_position_of("[]").to_selection() 13422 ); 13423} 13424 13425#[test] 13426fn merge_case_branch_works_with_existing_alternative_patterns() { 13427 assert_code_action!( 13428 MERGE_CASE_BRANCHES, 13429 r#"pub fn go(result) { 13430 case result { 13431 [] | [_, _, ..]-> todo 13432 [_] -> todo 13433 _ -> 2 13434 } 13435}"#, 13436 find_position_of("[]").select_until(find_position_of("[_]")) 13437 ); 13438} 13439 13440#[test] 13441fn merge_case_branch_does_not_merge_branches_with_variables_with_same_name_and_different_types() { 13442 assert_no_code_actions!( 13443 MERGE_CASE_BRANCHES, 13444 r#"pub fn go(result: Result(Int, String)) { 13445 case result { 13446 Ok(one) -> todo 13447 Error(one) -> todo 13448 } 13449}"#, 13450 find_position_of("Ok").select_until(find_position_of("Error")) 13451 ); 13452} 13453 13454#[test] 13455fn annotate_all_top_level_definitions_dont_affect_local_vars() { 13456 assert_code_action!( 13457 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13458 r#" 13459pub const answer = 42 13460 13461pub fn add_two(thing) { 13462 thing + 2 13463} 13464 13465pub fn add_one(thing) { 13466 let result = thing + 1 13467 result 13468} 13469"#, 13470 find_position_of("fn").select_until(find_position_of("(")) 13471 ); 13472} 13473 13474#[test] 13475fn annotate_all_top_level_definitions_constant() { 13476 assert_code_action!( 13477 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13478 r#" 13479pub const answer = 42 13480 13481pub fn add_two(thing) { 13482 thing + 2 13483} 13484 13485pub fn add_one(thing) { 13486 thing + 1 13487} 13488"#, 13489 find_position_of("const").select_until(find_position_of("=")) 13490 ); 13491} 13492 13493#[test] 13494fn annotate_all_top_level_definitions_function() { 13495 assert_code_action!( 13496 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13497 r#" 13498pub fn add_two(thing) { 13499 thing + 2 13500} 13501 13502pub fn add_one(thing) { 13503 thing + 1 13504} 13505"#, 13506 find_position_of("fn").select_until(find_position_of("(")) 13507 ); 13508} 13509 13510#[test] 13511fn annotate_all_top_level_definitions_already_annotated() { 13512 assert_no_code_actions!( 13513 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13514 r#" 13515pub const answer: Int = 42 13516 13517pub fn add_two(thing: Int) -> Int { 13518 thing + 2 13519} 13520 13521pub fn add_one(thing: Int) -> Int { 13522 thing + 1 13523} 13524"#, 13525 find_position_of("fn").select_until(find_position_of("(")) 13526 ); 13527} 13528 13529#[test] 13530fn annotate_all_top_level_definitions_inside_body() { 13531 assert_no_code_actions!( 13532 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13533 r#" 13534pub fn add_one(thing) { 13535 thing + 1 13536} 13537"#, 13538 find_position_of("thing + 1").to_selection() 13539 ); 13540} 13541 13542#[test] 13543fn annotate_all_top_level_definitions_partially_annotated() { 13544 assert_code_action!( 13545 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13546 r#" 13547pub const answer: Int = 42 13548pub const another_answer = 43 13549 13550pub fn add_two(thing) -> Int { 13551 thing + 2 13552} 13553 13554pub fn add_one(thing: Int) { 13555 thing + 1 13556} 13557"#, 13558 find_position_of("fn").select_until(find_position_of("(")) 13559 ); 13560} 13561 13562#[test] 13563fn annotate_all_top_level_definitions_with_partially_annotated_generic_function() { 13564 assert_code_action!( 13565 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13566 r#" 13567pub fn wibble(a: a, b, c: c, d) { 13568 todo 13569} 13570"#, 13571 find_position_of("wibble").to_selection() 13572 ); 13573} 13574 13575#[test] 13576fn annotate_all_top_level_definitions_with_two_generic_functions() { 13577 assert_code_action!( 13578 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13579 r#" 13580fn wibble(one) { todo } 13581 13582fn wobble(other) { todo } 13583"#, 13584 find_position_of("wobble").to_selection() 13585 ); 13586} 13587 13588#[test] 13589fn annotate_all_top_level_definitions_with_constant_and_generic_functions() { 13590 assert_code_action!( 13591 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13592 r#" 13593const answer = 42 13594 13595fn wibble(one) { todo } 13596 13597fn wobble(other) { todo } 13598"#, 13599 find_position_of("wobble").to_selection() 13600 ); 13601} 13602 13603#[test] 13604fn annotate_all_top_level_definitions_not_suggested_if_annotations_present() { 13605 assert_no_code_actions!( 13606 ANNOTATE_TOP_LEVEL_DEFINITIONS, 13607 r#" 13608fn wibble(one: Int) -> Int { one } 13609 13610fn wobble(one) { wibble(one) } 13611"#, 13612 find_position_of("wibble").to_selection() 13613 ); 13614} 13615 13616// https://github.com/gleam-lang/gleam/issues/5273 13617#[test] 13618fn extract_constant_doesnt_place_constant_below_documentation() { 13619 assert_code_action!( 13620 EXTRACT_CONSTANT, 13621 r#" 13622/// Wibble does some wobbling 13623pub fn wibble() { 13624 let x = "wobble" 13625 x 13626} 13627"#, 13628 find_position_of("x").to_selection() 13629 ); 13630} 13631 13632// https://github.com/gleam-lang/gleam/issues/5273 13633#[test] 13634fn extract_constant_doesnt_place_constant_below_large_documentation() { 13635 assert_code_action!( 13636 EXTRACT_CONSTANT, 13637 r#" 13638/// Wibble does some wobbling 13639/// Note that it doesn't perform wibbling 13640pub fn wibble() { 13641 let x = "wobble" 13642 x 13643} 13644"#, 13645 find_position_of("x").to_selection() 13646 ); 13647} 13648 13649#[test] 13650fn add_missing_type_parameter_for_single_constructor() { 13651 assert_code_action!( 13652 ADD_MISSING_TYPE_PARAMETER, 13653 r#" 13654type Wibble { 13655 Wibble(field: t) 13656} 13657"#, 13658 find_position_of("t").nth_occurrence(2).to_selection() 13659 ); 13660} 13661 13662#[test] 13663fn add_missing_type_parameter_can_only_trigger_if_within_type() { 13664 assert_no_code_actions!( 13665 ADD_MISSING_TYPE_PARAMETER, 13666 r#" 13667type Wibble { 13668 Wibble(field: t) 13669} 13670 13671pub fn main() { 13672 // unrelated 13673 todo 13674} 13675"#, 13676 find_position_of("type").select_until(find_position_of("todo")) 13677 ); 13678} 13679 13680#[test] 13681fn add_missing_type_parameter_to_exising_parameter() { 13682 assert_code_action!( 13683 ADD_MISSING_TYPE_PARAMETER, 13684 r#" 13685type Wibble(t) { 13686 Wibble(field: t) 13687 Wobble(field: u) 13688} 13689"#, 13690 find_position_of("u").to_selection() 13691 ); 13692} 13693 13694#[test] 13695fn add_missing_type_parameter_preserves_comments() { 13696 assert_code_action!( 13697 ADD_MISSING_TYPE_PARAMETER, 13698 r#" 13699type Wibble( 13700 // Comment 1 13701 b, 13702 // Comment 2 13703) { 13704 Wibble(a, b, c) 13705} 13706"#, 13707 find_position_of("c").to_selection() 13708 ); 13709} 13710 13711#[test] 13712fn add_missing_type_parameter_sorted_alphabetically() { 13713 assert_code_action!( 13714 ADD_MISSING_TYPE_PARAMETER, 13715 r#" 13716type Wibble(b) { 13717 Wibble(c, b, a) 13718} 13719"#, 13720 find_position_of("a").to_selection() 13721 ); 13722} 13723 13724#[test] 13725fn add_missing_type_parameter_not_suggested_when_nothing_missing() { 13726 assert_no_code_actions!( 13727 ADD_MISSING_TYPE_PARAMETER, 13728 r#" 13729type Wibble(t) { 13730 Wibble(field: t) 13731} 13732"#, 13733 find_position_of("t").nth_occurrence(2).to_selection() 13734 ); 13735} 13736 13737#[test] 13738fn add_missing_type_parameter_not_suggested_when_no_parameters() { 13739 assert_no_code_actions!( 13740 ADD_MISSING_TYPE_PARAMETER, 13741 r#" 13742type Wibble { 13743 Wibble 13744} 13745"#, 13746 find_position_of("Wibble").nth_occurrence(2).to_selection() 13747 ); 13748} 13749 13750#[test] 13751fn add_missing_type_parameter_does_not_add_types_that_do_not_exist() { 13752 assert_no_code_actions!( 13753 ADD_MISSING_TYPE_PARAMETER, 13754 r#" 13755type Wibble { 13756 Wibble(Wobble) 13757} 13758"#, 13759 find_position_of("Wibble").nth_occurrence(2).to_selection() 13760 ); 13761} 13762 13763// https://github.com/gleam-lang/gleam/issues/5288 13764#[test] 13765fn extract_anonymous_function_without_variable_capture_1() { 13766 assert_code_action!( 13767 EXTRACT_FUNCTION, 13768 " 13769pub fn main() { 13770 let int_pow = fn(base, exp) { 13771 case exp { 13772 exp if exp < 0 -> 0 13773 0 -> base 13774 exp -> int_pow(base * exp, exp - 1) 13775 } 13776 } 13777} 13778 ", 13779 find_position_of("fn(").select_until(find_position_of("}").nth_occurrence(2)) 13780 ); 13781} 13782 13783#[test] 13784fn extract_anonymous_function_without_variable_capture_2() { 13785 let src = r#" 13786import gleam/io 13787import gleam/list 13788 13789pub fn main() { 13790 list.each(list.range(0, 10), fn(_) { io.println("wibble wobble") }) 13791} 13792 "#; 13793 13794 assert_code_action!( 13795 EXTRACT_FUNCTION, 13796 TestProject::for_source(src) 13797 .add_hex_module( 13798 "gleam/io", 13799 " 13800 pub fn println(string: String) -> Nil { todo } 13801 " 13802 ) 13803 .add_hex_module( 13804 "gleam/list", 13805 " 13806 pub fn each(list: List(a), f: fn(a) -> b) -> Nil { todo } 13807 pub fn range(from start: Int, to stop: Int) -> List(Int) { todo } 13808 " 13809 ), 13810 find_position_of("fn(").select_until(find_position_of("}")) 13811 ); 13812} 13813 13814#[test] 13815fn extract_unary_anonymous_function_with_variable_capture_1() { 13816 let src = " 13817import gleam/list 13818 13819pub fn main() { 13820 let needle = 42 13821 let haystack = [25, 81, 74, 42, 33] 13822 list.filter(haystack, fn(x) { x == needle }) 13823} 13824 "; 13825 13826 assert_code_action!( 13827 EXTRACT_FUNCTION, 13828 TestProject::for_source(src).add_hex_module( 13829 "gleam/list", 13830 " 13831 pub fn filter( 13832 list: List(a), 13833 keeping predicate: fn(a) -> Bool, 13834 ) -> List(a) { todo } 13835 " 13836 ), 13837 find_position_of("fn(").select_until(find_position_of("}")) 13838 ); 13839} 13840 13841#[test] 13842fn extract_unary_anonymous_function_with_variable_capture_2() { 13843 let src = " 13844import gleam/list 13845 13846pub fn main() { 13847 let needle = 42 13848 let haystack = [25, 81, 74, 42, 33] 13849 list.filter(haystack, fn(_) { needle == 42 }) 13850} 13851 "; 13852 13853 assert_code_action!( 13854 EXTRACT_FUNCTION, 13855 TestProject::for_source(src).add_hex_module( 13856 "gleam/list", 13857 " 13858 pub fn filter( 13859 list: List(a), 13860 keeping predicate: fn(a) -> Bool, 13861 ) -> List(a) { todo } 13862 " 13863 ), 13864 find_position_of("fn(").select_until(find_position_of("}")) 13865 ); 13866} 13867 13868#[test] 13869fn extract_anonymous_function_with_variable_capture_1() { 13870 assert_code_action!( 13871 EXTRACT_FUNCTION, 13872 " 13873pub fn main() { 13874 let outer_scope = 3 13875 let wibble = fn(a, b) { 13876 a + b + outer_scope 13877 } 13878} 13879 ", 13880 find_position_of("fn(").select_until(find_position_of("}")) 13881 ); 13882} 13883 13884#[test] 13885fn extract_anonymous_function_with_variable_capture_2() { 13886 let src = " 13887import gleam/list 13888 13889pub fn main() { 13890 let shorter = [1, 2, 3] 13891 let longer = [4, 5, 6, 7, 8] 13892 let offset = 5 13893 list.map2(shorter, longer, fn(_left, right) { right + offset }) 13894} 13895 "; 13896 13897 assert_code_action!( 13898 EXTRACT_FUNCTION, 13899 TestProject::for_source(src).add_hex_module( 13900 "gleam/list", 13901 " 13902 pub fn map2( 13903 list1: List(a), 13904 list2: List(b), 13905 with fun: fn(a, b) -> c, 13906 ) -> List(c) { todo } 13907 " 13908 ), 13909 find_position_of("fn(").select_until(find_position_of("}")) 13910 ); 13911} 13912 13913// https://github.com/gleam-lang/gleam/issues/5263 13914#[test] 13915fn interpolate_string_allows_extracting_record_access_syntax() { 13916 assert_code_action!( 13917 INTERPOLATE_STRING, 13918 r#"pub fn main() { 13919 "wibble wobble.some_field woo" 13920}"#, 13921 find_position_of("wobble").select_until(find_position_of("some_field ").under_last_char()), 13922 ); 13923} 13924 13925// https://github.com/gleam-lang/gleam/issues/5299 13926#[test] 13927fn generate_dynamic_decoder_produces_zero_values_for_prelude_and_stdlib_types() { 13928 let src = r#" 13929import gleam/option 13930import gleam/dict 13931 13932pub type Wobble { 13933 Wobble( 13934 bit_array: BitArray, 13935 int: Int, 13936 float: Float, 13937 bool: Bool, 13938 list: List(Int), 13939 string: String, 13940 nil: Nil, 13941 option: option.Option(String), 13942 dict: dict.Dict(Int, Bool), 13943 ) 13944 Dummy( 13945 a: Int, 13946 b: Int, 13947 c: Int, 13948 d: Int, 13949 e: Int, 13950 f: Int, 13951 g: Int, 13952 h: Int, 13953 i: Int, 13954 j: Int, 13955 ) 13956} 13957 "#; 13958 assert_code_action!( 13959 GENERATE_DYNAMIC_DECODER, 13960 TestProject::for_source(src) 13961 .add_hex_module("gleam/option", "pub type Option(a) { Some(a) None }") 13962 .add_hex_module("gleam/dict", "pub type Dict(key, value)"), 13963 find_position_of("pub type Wobble {").select_until(find_position_of("}")) 13964 ); 13965} 13966 13967#[test] 13968fn interpolate_string_does_not_add_empty_string_right_at_the_start() { 13969 assert_code_action!( 13970 INTERPOLATE_STRING, 13971 r#"pub fn main() { 13972 "wibble wobble woo" 13973}"#, 13974 find_position_of("wibble ").select_until(find_position_of("wibble ").under_last_char()), 13975 ); 13976} 13977 13978#[test] 13979fn generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_1() { 13980 let src = r#" 13981import wibble.{type Wibble} 13982 13983pub type Wobble { 13984 Wobble(value: Wibble) 13985 Dummy(a: Int, b: Int) 13986} 13987 "#; 13988 assert_code_action!( 13989 GENERATE_DYNAMIC_DECODER, 13990 TestProject::for_source(src).add_module("wibble", "pub type Wibble { Wibble }"), 13991 find_position_of("pub type Wobble {").select_until(find_position_of("}").nth_occurrence(2)) 13992 ); 13993} 13994 13995#[test] 13996fn interpolate_string_does_not_add_empty_string_right_at_the_end() { 13997 assert_code_action!( 13998 INTERPOLATE_STRING, 13999 r#"pub fn main() { 14000 "wibble wobble woo" 14001}"#, 14002 find_position_of("woo\"").select_until(find_position_of("woo\"").under_last_char()), 14003 ); 14004} 14005 14006#[test] 14007fn generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_2() { 14008 let src = r#" 14009import internal/wibble.{type Wibble} 14010 14011pub type Wobble { 14012 Wobble(value: Wibble) 14013 Dummy(a: Int, b: Int) 14014} 14015 "#; 14016 assert_code_action!( 14017 GENERATE_DYNAMIC_DECODER, 14018 TestProject::for_source(src) 14019 .add_module( 14020 "internal/wibble", 14021 r#" 14022import internal/nested_wibble.{type NestedWibble} 14023pub type Wibble { Wibble(value: NestedWibble) } 14024"# 14025 ) 14026 .add_module( 14027 "internal/nested_wibble", 14028 r#" 14029pub type NestedWibble { NestedWibble } 14030"# 14031 ), 14032 find_position_of("pub type Wobble {").select_until(find_position_of("}").nth_occurrence(2)) 14033 ); 14034} 14035 14036#[test] 14037fn generate_dynamic_decoder_produces_zero_values_for_user_defined_type_in_the_same_package_3() { 14038 let src = r#" 14039import wibble.{type Wibble} 14040 14041pub type Wobble { 14042 Wobble(value: Wibble) 14043 Dummy(a: Int, b: Int) 14044} 14045 "#; 14046 assert_code_action!( 14047 GENERATE_DYNAMIC_DECODER, 14048 TestProject::for_source(src) 14049 .add_module( 14050 "wibble", 14051 r#" 14052import gleam/dict.{type Dict} 14053pub type Wibble { Wibble(map: Dict(Int, Bool)) } 14054"# 14055 ) 14056 .add_hex_module( 14057 "gleam/dict", 14058 r#" 14059pub type Dict(key, value) 14060pub fn new() -> Dict(k, v) { todo } 14061"# 14062 ), 14063 find_position_of("pub type Wobble {").select_until(find_position_of("}").nth_occurrence(2)) 14064 ); 14065} 14066 14067#[test] 14068fn generate_dynamic_decoder_does_not_produce_zero_values_for_types_from_other_packages() { 14069 let src = r#" 14070import wibble.{type Wibble} 14071 14072pub type Wobble { 14073 Wobble(value: Wibble) 14074 Dummy(a: Int, b: Wibble) 14075} 14076 "#; 14077 assert_code_action!( 14078 GENERATE_DYNAMIC_DECODER, 14079 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 14080 find_position_of("pub type Wobble {").select_until(find_position_of("}").nth_occurrence(2)) 14081 ); 14082} 14083 14084#[test] 14085fn generate_dynamic_decoder_skips_over_recursive_constructors_when_generating_zero_values() { 14086 assert_code_action!( 14087 GENERATE_DYNAMIC_DECODER, 14088 r#" 14089pub type Wobble { 14090 Wobble(inside: Wobble) 14091 Dummy(a: Int, b: Int) 14092} 14093 "#, 14094 find_position_of("pub type Wobble {").select_until(find_position_of("}")) 14095 ); 14096} 14097 14098#[test] 14099fn generate_dynamic_decoder_skips_over_mutually_recursive_constructors_when_generating_zero_values() 14100{ 14101 assert_code_action!( 14102 GENERATE_DYNAMIC_DECODER, 14103 r#" 14104pub type Wobble { 14105 Wobble(inside: Wibble) 14106 DummyWobble(a: Int, b: Int) 14107} 14108 14109pub type Wibble { 14110 Wibble(inside: Wobble) 14111 DummyWibble(a: Int, b: Int) 14112} 14113 "#, 14114 find_position_of("pub type Wobble {").select_until(find_position_of("}")) 14115 ); 14116} 14117 14118#[test] 14119fn generate_dynamic_decoder_uses_smallest_possible_constructor_for_zero_value() { 14120 let src = r#" 14121import wibble.{type Wibble} 14122 14123pub type Wobble { 14124 Wobble(impossible: Wobble) 14125 WibbleWobble(nope: Wibble) 14126 Dummy(a: Int, b: #(Float, Float)) 14127} 14128 "#; 14129 assert_code_action!( 14130 GENERATE_DYNAMIC_DECODER, 14131 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 14132 find_position_of("pub type Wobble {").select_until(find_position_of("}").nth_occurrence(2)) 14133 ); 14134} 14135 14136#[test] 14137fn generate_dynamic_decoder_generates_todo_for_zero_value_when_all_constructors_fail() { 14138 assert_code_action!( 14139 GENERATE_DYNAMIC_DECODER, 14140 r#" 14141pub type Wobble { 14142 Wobble(nope: Wobble) 14143 Wibble(not: Int, again: Wobble) 14144} 14145 "#, 14146 find_position_of("pub type Wobble {").select_until(find_position_of("}")) 14147 ); 14148} 14149 14150#[test] 14151fn generate_dynamic_decoder_uses_decode_success_for_nil() { 14152 assert_code_action!( 14153 GENERATE_DYNAMIC_DECODER, 14154 r#" 14155pub type Nothing { 14156 No(val: Nil) 14157 Nope(val: #(Nil, Nil)) 14158 Nothing(val: List(Nil)) 14159} 14160 "#, 14161 find_position_of("pub type Nothing {").select_until(find_position_of("}")) 14162 ); 14163} 14164 14165#[test] 14166fn generate_to_json_function_uses_json_null_for_nil() { 14167 let src = " 14168import gleam/json 14169import gleam/dict.{type Dict} 14170 14171 14172pub type Nothing { 14173 Nope(val: Nil) 14174 Nothing(val1: List(Nil), val2: Dict(Int, Nil)) 14175} 14176"; 14177 14178 assert_code_action!( 14179 GENERATE_TO_JSON_FUNCTION, 14180 TestProject::for_source(src) 14181 .add_package_module("gleam_json", "gleam/json", "pub type Json") 14182 .add_hex_module("gleam/dict", "pub type Dict(key, value)"), 14183 find_position_of("pub type Nothing {") 14184 .select_until(find_position_of("}").nth_occurrence(2)) 14185 ); 14186} 14187 14188#[test] 14189fn generate_to_json_function_ignores_nil_and_nil_tuple_fields_with_underscore() { 14190 let src = " 14191import gleam/json 14192import gleam/dict.{type Dict} 14193 14194 14195pub type Nothing { 14196 No(val: #(Nil), another: #(Nil, #(Nil, Int))) 14197 Nope(val: List(#(Nil))) 14198} 14199"; 14200 14201 assert_code_action!( 14202 GENERATE_TO_JSON_FUNCTION, 14203 TestProject::for_source(src) 14204 .add_package_module("gleam_json", "gleam/json", "pub type Json") 14205 .add_hex_module("gleam/dict", "pub type Dict(key, value)"), 14206 find_position_of("pub type Nothing {") 14207 .select_until(find_position_of("}").nth_occurrence(2)) 14208 ); 14209} 14210 14211#[test] 14212fn replace_underscore_with_function_return_type() { 14213 assert_code_action!( 14214 REPLACE_UNDERSCORE_WITH_TYPE, 14215 r#" 14216pub fn wibble() -> _ { 14217 12 14218} 14219 "#, 14220 find_position_of("_").to_selection() 14221 ); 14222} 14223 14224#[test] 14225fn wrap_uncalled_function_in_anonymous_function() { 14226 assert_code_action!( 14227 WRAP_IN_ANONYMOUS_FUNCTION, 14228 "pub fn main() { 14229 op 14230} 14231 14232fn op(i) { 14233 todo 14234} 14235", 14236 find_position_of("op").to_selection() 14237 ); 14238} 14239 14240#[test] 14241fn wrap_function_in_anonymous_function_does_not_trigger_if_selection_is_not_within_the_function() { 14242 assert_no_code_actions!( 14243 WRAP_IN_ANONYMOUS_FUNCTION, 14244 "pub fn main() { 14245 let a = 1 14246 some_function 14247 let b = 2 14248 Nil 14249} 14250 14251fn some_function(i) { 14252 todo 14253} 14254", 14255 find_position_of("1").select_until(find_position_of("2")) 14256 ); 14257} 14258 14259#[test] 14260fn wrap_function_in_anonymous_function_does_not_trigger_on_record_update() { 14261 assert_no_code_actions!( 14262 WRAP_IN_ANONYMOUS_FUNCTION, 14263 "pub fn main() { 14264 Wibble(..todo, a: 1) 14265} 14266 14267pub type Wibble { Wibble(a: Int, b: Int) } 14268", 14269 find_position_of("Wibble").to_selection() 14270 ); 14271} 14272 14273#[test] 14274fn wrap_function_in_anonymous_function_does_not_trigger_on_invalid_record_update() { 14275 assert_no_code_actions!( 14276 WRAP_IN_ANONYMOUS_FUNCTION, 14277 "pub fn main() { 14278 Wibble(..todo, a: 1) 14279} 14280", 14281 find_position_of("Wibble").to_selection() 14282 ); 14283} 14284 14285#[test] 14286fn wrap_function_in_anonymous_function_does_not_trigger_on_record_call() { 14287 assert_no_code_actions!( 14288 WRAP_IN_ANONYMOUS_FUNCTION, 14289 "pub fn main() { 14290 Wibble(1, 2) 14291} 14292 14293pub type Wibble { Wibble(a: Int, b: Int) } 14294", 14295 find_position_of("Wibble").to_selection() 14296 ); 14297} 14298 14299#[test] 14300fn wrap_function_in_anonymous_function_does_not_trigger_on_invalid_record_call() { 14301 assert_no_code_actions!( 14302 WRAP_IN_ANONYMOUS_FUNCTION, 14303 "pub fn main() { 14304 Wibble(1) 14305} 14306", 14307 find_position_of("Wibble").to_selection() 14308 ); 14309} 14310 14311#[test] 14312fn replace_nested_underscore_with_generic_type() { 14313 assert_code_action!( 14314 REPLACE_UNDERSCORE_WITH_TYPE, 14315 r#" 14316pub fn wibble() -> Result(a, _) { 14317 Ok(todo) 14318} 14319 "#, 14320 find_position_of("_").to_selection() 14321 ); 14322} 14323 14324#[test] 14325fn wrap_uncalled_constructor_in_anonymous_function() { 14326 assert_code_action!( 14327 WRAP_IN_ANONYMOUS_FUNCTION, 14328 "pub fn main() { 14329 Record 14330} 14331 14332type Record { 14333 Record(i: Int) 14334} 14335", 14336 find_position_of("Record").to_selection() 14337 ); 14338} 14339 14340#[test] 14341fn replace_nested_underscore_with_function_return_type() { 14342 assert_code_action!( 14343 REPLACE_UNDERSCORE_WITH_TYPE, 14344 r#" 14345pub fn wibble() -> Result(Result(_, Nil), Int) { 14346 Ok(Ok("hello")) 14347} 14348 "#, 14349 find_position_of("_").to_selection() 14350 ); 14351} 14352 14353#[test] 14354fn wrap_call_arg_in_anonymous_function() { 14355 assert_code_action!( 14356 WRAP_IN_ANONYMOUS_FUNCTION, 14357 "import gleam/list 14358 14359pub fn main() { 14360 list.map([1, 2, 3], op) 14361} 14362 14363fn op(i: Int) -> Int { 14364 todo 14365} 14366", 14367 find_position_of("op").to_selection() 14368 ); 14369} 14370 14371#[test] 14372fn replace_nested_underscore_in_let_annotation() { 14373 assert_code_action!( 14374 REPLACE_UNDERSCORE_WITH_TYPE, 14375 r#" 14376pub fn wibble() { 14377 let a: Result(Result(_, Nil), Nil) = Ok(Ok("hello")) 14378} 14379 "#, 14380 find_position_of("_").to_selection() 14381 ); 14382} 14383 14384#[test] 14385fn wrap_function_in_anonymous_function_without_shadowing() { 14386 assert_code_action!( 14387 WRAP_IN_ANONYMOUS_FUNCTION, 14388 "pub fn main() { 14389 int 14390} 14391 14392fn int(i: Int) { 14393 todo 14394} 14395", 14396 find_position_of("int").to_selection() 14397 ); 14398} 14399 14400#[test] 14401fn replace_underscore_in_let_annotation() { 14402 assert_code_action!( 14403 REPLACE_UNDERSCORE_WITH_TYPE, 14404 r#" 14405pub fn wibble() { 14406 let a: _ = Ok(Ok("hello")) 14407} 14408 "#, 14409 find_position_of("_").to_selection() 14410 ); 14411} 14412 14413#[test] 14414fn replace_nested_underscore_with_tuple_type() { 14415 assert_code_action!( 14416 REPLACE_UNDERSCORE_WITH_TYPE, 14417 r#" 14418pub fn wibble() { 14419 let a: #(Int, _, Int) = #(1, "hello", 2) 14420} 14421 "#, 14422 find_position_of("_").to_selection() 14423 ); 14424} 14425 14426#[test] 14427fn replace_underscore_in_function_argument() { 14428 assert_code_action!( 14429 REPLACE_UNDERSCORE_WITH_TYPE, 14430 r#" 14431pub fn wibble(a: _) -> Int { 14432 a + 2 14433} 14434 "#, 14435 find_position_of("_").to_selection() 14436 ); 14437} 14438 14439#[test] 14440fn replace_underscore_in_fn_expr_argument() { 14441 assert_code_action!( 14442 REPLACE_UNDERSCORE_WITH_TYPE, 14443 r#" 14444pub fn wibble() { 14445 fn(a: _) { a + 2 } 14446} 14447 "#, 14448 find_position_of("_").to_selection() 14449 ); 14450} 14451 14452#[test] 14453fn wrap_assignment_in_anonymous_function() { 14454 assert_code_action!( 14455 WRAP_IN_ANONYMOUS_FUNCTION, 14456 "pub fn main() { 14457 let op = op_factory(1, 2, 3) 14458} 14459 14460fn op_factory(a: Int, b: Int, c: Int) -> fn(Int) -> Int { 14461 todo 14462} 14463", 14464 find_position_of("op_factory").to_selection() 14465 ); 14466} 14467 14468#[test] 14469fn wrap_imported_function_in_anonymous_function() { 14470 let source = "import gleam/list 14471import gleam/int 14472 14473pub fn main() { 14474 list.map([1, 2, 3], int.is_even) 14475} 14476"; 14477 14478 let int_source = "pub fn is_even(int) { int % 2 == 0 }"; 14479 14480 assert_code_action!( 14481 WRAP_IN_ANONYMOUS_FUNCTION, 14482 TestProject::for_source(source).add_module("gleam/int", int_source), 14483 find_position_of("int.is_even").to_selection() 14484 ); 14485} 14486 14487#[test] 14488fn dont_wrap_anonymous_function_in_anonymous_function() { 14489 assert_no_code_actions!( 14490 WRAP_IN_ANONYMOUS_FUNCTION, 14491 "pub fn main() { 14492 let f = fn(in) { ception(in) } 14493} 14494 14495", 14496 find_position_of("fn(in)").to_selection() 14497 ); 14498} 14499 14500#[test] 14501fn wrap_pipeline_step_in_anonymous_function() { 14502 assert_code_action!( 14503 WRAP_IN_ANONYMOUS_FUNCTION, 14504 "pub fn main() { 14505 1 |> wibble |> wobble 14506} 14507 14508fn wibble(i) { 14509 todo 14510} 14511 14512fn wobble(i) { 14513 todo 14514} 14515 14516", 14517 find_position_of("wibble").to_selection() 14518 ); 14519} 14520 14521#[test] 14522fn wrap_final_pipeline_step_in_anonymous_function() { 14523 assert_code_action!( 14524 WRAP_IN_ANONYMOUS_FUNCTION, 14525 "pub fn main() { 14526 1 |> wibble |> wobble 14527} 14528 14529fn wibble(i) { 14530 todo 14531} 14532 14533fn wobble(i) { 14534 todo 14535} 14536 14537", 14538 find_position_of("wobble").to_selection() 14539 ); 14540} 14541 14542#[test] 14543fn wrap_record_field_in_anonymous_function() { 14544 assert_code_action!( 14545 WRAP_IN_ANONYMOUS_FUNCTION, 14546 "pub fn main() { 14547 let r = Record(wibble) 14548} 14549 14550type Record { 14551 Record(wibbler: fn(Int) -> Int) 14552} 14553 14554fn wibble(v) { 14555 todo 14556} 14557 14558", 14559 find_position_of("wibble").to_selection() 14560 ); 14561} 14562 14563#[test] 14564fn dont_wrap_functions_that_are_already_being_called() { 14565 assert_no_code_actions!( 14566 WRAP_IN_ANONYMOUS_FUNCTION, 14567 "pub fn main() { 14568 wibble(1) 14569} 14570 14571fn wibble(i) { 14572 todo 14573} 14574 14575", 14576 find_position_of("wibble").to_selection() 14577 ); 14578} 14579 14580#[test] 14581fn unwrap_trivial_anonymous_function() { 14582 assert_code_action!( 14583 UNWRAP_ANONYMOUS_FUNCTION, 14584 "import gleam/list 14585 14586pub fn main() { 14587 list.map([1, 2, 3], fn(int) { op(int) }) 14588} 14589 14590fn op(i: Int) -> Int { 14591 todo 14592} 14593", 14594 find_position_of("fn(int)").to_selection() 14595 ); 14596} 14597 14598#[test] 14599fn unwrap_anonymous_function_can_only_trigger_if_cursor_is_within_the_function() { 14600 assert_no_code_actions!( 14601 UNWRAP_ANONYMOUS_FUNCTION, 14602 "import gleam/list 14603 14604pub fn main() { 14605 list.map([1, 2, 3], fn(int) { op(int) }) 14606} 14607 14608fn op(i: Int) -> Int { 14609 todo 14610} 14611", 14612 find_position_of("fn(int)").select_until(find_position_of("todo")) 14613 ); 14614} 14615 14616#[test] 14617fn unwrap_trivial_anonymous_function_with_bad_spacing() { 14618 assert_code_action!( 14619 UNWRAP_ANONYMOUS_FUNCTION, 14620 "import gleam/list 14621 14622pub fn main() { 14623 list.map([1, 2, 3], fn (int) { 14624 14625 op(int) 14626 14627 }) 14628} 14629 14630fn op(i: Int) -> Int { 14631 todo 14632} 14633", 14634 find_position_of("fn (int)").to_selection() 14635 ); 14636} 14637 14638#[test] 14639fn unwrap_nested_anonymous_function() { 14640 assert_code_action!( 14641 UNWRAP_ANONYMOUS_FUNCTION, 14642 "pub fn main() { 14643 fn(do) { fn(re){ mi(re) }(do) } 14644} 14645 14646fn mi(v) { 14647 todo 14648} 14649", 14650 find_position_of("fn(re)").to_selection() 14651 ); 14652} 14653 14654#[test] 14655fn unwrap_anonymous_function_with_labelled_args() { 14656 assert_code_action!( 14657 UNWRAP_ANONYMOUS_FUNCTION, 14658 "pub fn main() { 14659 fn(a, b) { op(first: a, second: b) } 14660} 14661 14662fn op(first a, second b) { 14663 todo 14664} 14665", 14666 find_position_of("fn(a, b)").to_selection() 14667 ); 14668} 14669 14670#[test] 14671fn unwrap_anonymous_function_with_labelled_and_unlabelled_args() { 14672 assert_code_action!( 14673 UNWRAP_ANONYMOUS_FUNCTION, 14674 "pub fn main() { 14675 fn(a, b, c) { op(a, second: b, third: c) } 14676} 14677 14678fn op(a, second b, third c) { 14679 todo 14680} 14681", 14682 find_position_of("fn(a, b, c)").to_selection() 14683 ); 14684} 14685 14686#[test] 14687fn unwrap_anonymous_function_with_labelled_args_out_of_order() { 14688 assert_code_action!( 14689 UNWRAP_ANONYMOUS_FUNCTION, 14690 "pub fn main() { 14691 fn(a, b) { op(second: b, first: a) } 14692} 14693 14694fn op(first a, second b) { 14695 todo 14696} 14697", 14698 find_position_of("fn(a, b)").to_selection() 14699 ); 14700} 14701 14702#[test] 14703fn unwrap_anonymous_function_with_comment_after() { 14704 assert_code_action!( 14705 UNWRAP_ANONYMOUS_FUNCTION, 14706 "pub fn main() { 14707 fn(a) { 14708 op(a) 14709 // look out! 14710 } 14711} 14712 14713fn op(a) { 14714 todo 14715} 14716", 14717 find_position_of("fn(a)").to_selection() 14718 ); 14719} 14720 14721#[test] 14722fn unwrap_anonymous_function_with_comment_on_line() { 14723 assert_code_action!( 14724 UNWRAP_ANONYMOUS_FUNCTION, 14725 "pub fn main() { 14726 fn(a) { 14727 op(a) // look out! 14728 } 14729} 14730 14731fn op(a) { 14732 todo 14733} 14734", 14735 find_position_of("fn(a)").to_selection() 14736 ); 14737} 14738 14739#[test] 14740fn unwrap_anonymous_function_with_comment_on_head_line() { 14741 assert_code_action!( 14742 UNWRAP_ANONYMOUS_FUNCTION, 14743 "pub fn main() { 14744 fn(a) { // look out! 14745 op(a) 14746 } 14747} 14748 14749fn op(a) { 14750 todo 14751} 14752", 14753 find_position_of("fn(a)").to_selection() 14754 ); 14755} 14756 14757#[test] 14758fn unwrap_anonymous_function_with_comments_before() { 14759 assert_code_action!( 14760 UNWRAP_ANONYMOUS_FUNCTION, 14761 "pub fn main() { 14762 fn(a) { 14763 // look out, 14764 // there's a comment! 14765 14766 // another comment! 14767 //here's one without a leading space 14768 // here's one indented wrong 14769 // here's one indented even wronger 14770 op(a) 14771 } 14772} 14773 14774fn op(a) { 14775 todo 14776} 14777", 14778 find_position_of("fn(a)").to_selection() 14779 ); 14780} 14781 14782#[test] 14783fn unwrap_anonymous_function_unavailable_when_args_discarded() { 14784 assert_no_code_actions!( 14785 UNWRAP_ANONYMOUS_FUNCTION, 14786 "import gleam/list 14787 14788pub fn main() { 14789 list.index_map([1, 2, 3], fn(_, int) { op(int) }) 14790} 14791 14792fn op(i: Int) -> Int { 14793 todo 14794} 14795", 14796 find_position_of("fn(_, int)").to_selection() 14797 ); 14798} 14799 14800#[test] 14801fn unwrap_anonymous_function_unavailable_with_different_args() { 14802 assert_no_code_actions!( 14803 UNWRAP_ANONYMOUS_FUNCTION, 14804 "import gleam/list 14805 14806const another_int = 7 14807 14808pub fn main() { 14809 list.map([1, 2, 3], fn(int) { op(another_int) }) 14810} 14811 14812fn op(i: Int) -> Int { 14813 todo 14814} 14815", 14816 find_position_of("fn(int)").to_selection() 14817 ); 14818} 14819 14820#[test] 14821fn dont_wrap_use_in_anonymous_function() { 14822 assert_no_code_actions!( 14823 WRAP_IN_ANONYMOUS_FUNCTION, 14824 "fn apply(x, k) { 14825 k(x) 14826} 14827 14828pub fn main() { 14829 use a <- apply(5) 14830 a * 1 14831} 14832", 14833 find_position_of("a * 1").to_selection() 14834 ); 14835} 14836 14837#[test] 14838fn dont_wrap_uses_in_anonymous_function() { 14839 assert_no_code_actions!( 14840 WRAP_IN_ANONYMOUS_FUNCTION, 14841 "pub fn main() { 14842 use a <- apply(1) 14843 use b <- apply(2) 14844 use c <- apply(3) 14845 a * b * c 14846} 14847 14848fn apply(x, k) { 14849 k(x) 14850}", 14851 find_position_of("a * b * c").to_selection() 14852 ); 14853} 14854 14855#[test] 14856fn create_unknown_module_under_src() { 14857 assert_code_action!( 14858 "Create src/wibble/wobble.gleam", 14859 " 14860import wibble/wobble 14861 14862pub fn main() { 14863 Nil 14864}", 14865 find_position_of("wobble").to_selection() 14866 ); 14867} 14868 14869#[test] 14870fn create_unknown_module_under_dev() { 14871 let project = TestProject::for_source( 14872 " 14873pub fn main() { 14874 Nil 14875}", 14876 ) 14877 .add_dev_module( 14878 "wibble", 14879 " 14880import wobble/woo", 14881 ); 14882 14883 assert_code_action!( 14884 "Create dev/wobble/woo.gleam", 14885 project, 14886 Origin::Dev, 14887 "wibble", 14888 find_position_of("woo").to_selection() 14889 ); 14890} 14891 14892#[test] 14893fn create_unknown_module_under_test() { 14894 let project = TestProject::for_source( 14895 " 14896pub fn main() { 14897 Nil 14898}", 14899 ) 14900 .add_test_module( 14901 "wibble", 14902 " 14903import wobble/woo", 14904 ); 14905 14906 assert_code_action!( 14907 "Create test/wobble/woo.gleam", 14908 project, 14909 Origin::Test, 14910 "wibble", 14911 find_position_of("woo").to_selection() 14912 ); 14913} 14914 14915#[test] 14916fn create_unknown_module_doesnt_trigger_when_module_exists() { 14917 let code = " 14918import wibble/wobble 14919 14920pub fn main() { 14921 Nil 14922} 14923"; 14924 14925 assert_no_code_actions!( 14926 "Create src/wibble/wobble.gleam", 14927 TestProject::for_source(code) 14928 .add_module("wibble/wobble", "pub type Wibble { Wobble(String) }"), 14929 find_position_of("wobble").to_selection() 14930 ); 14931} 14932 14933#[test] 14934fn create_unknown_module_doesnt_trigger_when_module_is_importable() { 14935 let code = " 14936pub fn main() { 14937 wibble.something() 14938} 14939"; 14940 14941 assert_no_code_actions!( 14942 "Create src/wobble/wibble.gleam", 14943 TestProject::for_source(code) 14944 .add_module("wobble/wibble", "pub type Wibble { Wobble(String) }"), 14945 find_position_of("wibble").to_selection() 14946 ); 14947} 14948 14949#[test] 14950fn create_unknown_module_doesnt_trigger_when_import_not_selected() { 14951 let code = " 14952import wibble/wobble 14953 14954pub fn main() { 14955 Nil 14956} 14957"; 14958 14959 assert_no_code_actions!( 14960 "Create src/wibble/wobble.gleam", 14961 TestProject::for_source(code), 14962 find_position_of("main").to_selection() 14963 ); 14964} 14965 14966#[test] 14967fn remove_redundant_record_update_triggered_on_the_record_spread() { 14968 assert_code_action!( 14969 REMOVE_REDUNDANT_RECORD_UPDATE, 14970 " 14971pub fn go(record: Wibble) { 14972 Wibble(..record, a: 1, b: 2) 14973} 14974 14975pub type Wibble { Wibble(a: Int, b: Int) } 14976", 14977 find_position_of("..").to_selection() 14978 ); 14979} 14980 14981#[test] 14982fn remove_redundant_record_update_triggered_on_the_record() { 14983 assert_code_action!( 14984 REMOVE_REDUNDANT_RECORD_UPDATE, 14985 " 14986pub fn go(record: Wibble) { 14987 Wibble(..record, a: 1, b: 2) 14988} 14989 14990pub type Wibble { Wibble(a: Int, b: Int) } 14991", 14992 find_position_of("record").nth_occurrence(2).to_selection() 14993 ); 14994} 14995 14996#[test] 14997fn remove_redundant_record_update_triggered_anywhere_on_the_expression() { 14998 assert_code_action!( 14999 REMOVE_REDUNDANT_RECORD_UPDATE, 15000 " 15001pub fn go(record: Wibble) { 15002 Wibble(..record, a: 1, b: 2) 15003} 15004 15005pub type Wibble { Wibble(a: Int, b: Int) } 15006", 15007 find_position_of("1").select_until(find_position_of("2")) 15008 ); 15009} 15010 15011#[test] 15012fn remove_redundant_record_update_does_not_trigger_if_update_is_not_redundant() { 15013 assert_no_code_actions!( 15014 REMOVE_REDUNDANT_RECORD_UPDATE, 15015 " 15016pub fn go(record: Wibble) { 15017 Wibble(..record, a: 1) 15018} 15019 15020pub type Wibble { Wibble(a: Int, b: Int) } 15021", 15022 find_position_of("..record").to_selection() 15023 ); 15024} 15025 15026#[test] 15027fn remove_redundant_constant_record_update_triggered_on_the_record_spread() { 15028 assert_code_action!( 15029 REMOVE_REDUNDANT_RECORD_UPDATE, 15030 " 15031pub const updated = Wibble(..base, a: 1, b: 3) 15032pub const base = Wibble(a: 1, b: 2) 15033pub type Wibble { Wibble(a: Int, b: Int) } 15034", 15035 find_position_of("..").to_selection() 15036 ); 15037} 15038 15039#[test] 15040fn remove_redundant_constant_record_update_triggered_on_the_record() { 15041 assert_code_action!( 15042 REMOVE_REDUNDANT_RECORD_UPDATE, 15043 " 15044pub const updated = Wibble(..base, a: 1, b: 3) 15045pub const base = Wibble(a: 1, b: 2) 15046pub type Wibble { Wibble(a: Int, b: Int) } 15047", 15048 find_position_of("1").select_until(find_position_of("3")) 15049 ); 15050} 15051 15052#[test] 15053fn remove_redundant_constant_record_update_does_not_trigger_if_update_i_not_redundant() { 15054 assert_no_code_actions!( 15055 REMOVE_REDUNDANT_RECORD_UPDATE, 15056 " 15057pub const updated = Wibble(..base, a: 1) 15058pub const base = Wibble(a: 1, b: 2) 15059pub type Wibble { Wibble(a: Int, b: Int) } 15060", 15061 find_position_of("base").to_selection() 15062 ); 15063}