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