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 / rename.rs
50 kB 2826 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2025 The Gleam contributors 3 4use std::collections::HashMap; 5 6use lsp_types::{ 7 Position, PrepareRenameParams, PrepareRenamePlaceholder, Range, RenameParams, 8 TextDocumentPositionParams, Uri as Url, WorkDoneProgressParams, WorkspaceEdit, 9}; 10 11use crate::url_from_path; 12 13use super::{TestProject, find_position_of, hover}; 14 15/// Returns the rename range and edit to apply if the rename is valid and can be 16/// carried out. 17/// However if the rename produces an error response from the language server, 18/// the error message is returned. 19fn rename( 20 tester: &TestProject<'_>, 21 new_name: &str, 22 position: Position, 23) -> Result<Option<(Range, WorkspaceEdit)>, String> { 24 let prepare_rename_response = tester.at(position, |engine, params, _| { 25 let params = PrepareRenameParams { 26 text_document_position_params: TextDocumentPositionParams { 27 text_document: params.text_document, 28 position, 29 }, 30 work_done_progress_params: WorkDoneProgressParams { 31 work_done_token: None, 32 }, 33 }; 34 engine.prepare_rename(params).result.unwrap() 35 }); 36 37 let range = match prepare_rename_response { 38 Some(lsp_types::PrepareRenameResult::Range(range)) => range, 39 Some(lsp_types::PrepareRenameResult::PrepareRenamePlaceholder( 40 PrepareRenamePlaceholder { range, .. }, 41 )) => range, 42 _ => return Ok(None), 43 }; 44 45 let outcome = tester.at(position, |engine, params, _| { 46 let params = RenameParams { 47 text_document_position_params: TextDocumentPositionParams { 48 text_document: params.text_document, 49 position, 50 }, 51 new_name: new_name.to_string(), 52 work_done_progress_params: WorkDoneProgressParams::default(), 53 }; 54 engine.rename(params).result.unwrap() 55 }); 56 57 match outcome { 58 Ok(Some(edit)) => Ok(Some((range, edit))), 59 Ok(None) => Ok(None), 60 Err(error) => Err(error.message), 61 } 62} 63 64fn rename_files(tester: &TestProject<'_>, renames: &[(&str, &str)]) -> HashMap<String, String> { 65 let edit = tester.run(|engine| { 66 let params = renames 67 .iter() 68 .map(|(old_name, new_name)| { 69 let old_url = 70 url_from_path(engine.path_for_module_name(old_name).as_str()).unwrap(); 71 let new_url = 72 url_from_path(engine.path_for_module_name(new_name).as_str()).unwrap(); 73 (old_url, new_url) 74 }) 75 .collect(); 76 engine.rename_files(params).result.unwrap() 77 }); 78 79 let changes = edit 80 .expect("No text edit found") 81 .changes 82 .expect("No text edit found"); 83 84 apply_code_edit(tester, changes) 85} 86 87fn apply_rename( 88 tester: &TestProject<'_>, 89 new_name: &str, 90 position: Position, 91) -> (Range, HashMap<String, String>) { 92 let (range, edit) = rename(tester, new_name, position) 93 .expect("Rename failed") 94 .expect("No rename produced"); 95 let changes = edit.changes.expect("No text edit found"); 96 (range, apply_code_edit(tester, changes)) 97} 98 99fn apply_code_edit( 100 tester: &TestProject<'_>, 101 changes: HashMap<Url, Vec<lsp_types::TextEdit>>, 102) -> HashMap<String, String> { 103 let mut modules = HashMap::new(); 104 for (uri, change) in changes { 105 let module_name = tester.module_name_from_url(&uri).expect("Valid uri"); 106 let module_code = tester.src_from_module_url(&uri).expect("Module exists"); 107 108 _ = modules.insert(module_name, super::apply_code_edit(module_code, change)); 109 } 110 111 modules 112} 113 114fn display_result( 115 project: &TestProject<'_>, 116 modules: HashMap<String, String>, 117 renamed_modules: HashMap<&str, &str>, 118 range: Option<Range>, 119) -> String { 120 let mut output = String::from("----- BEFORE RENAME\n"); 121 for (name, src) in project.root_package_modules.iter() { 122 output.push_str(&format!("-- {name}.gleam\n{src}\n\n")); 123 } 124 125 let src = project.src; 126 let app_src_before = if let Some(range) = range { 127 hover::show_hover(src, range, range.start) 128 } else { 129 src.to_string() 130 }; 131 output.push_str(&format!( 132 "-- app.gleam\n{app_src_before}\n\n----- AFTER RENAME\n", 133 )); 134 135 for &(name, src) in project.root_package_modules.iter() { 136 let used_name = if let Some(new_name) = renamed_modules.get(name) { 137 new_name 138 } else { 139 name 140 }; 141 output.push_str(&format!( 142 "-- {used_name}.gleam\n{}\n\n", 143 modules 144 .get(name) 145 .map(|string| string.as_str()) 146 .unwrap_or(src) 147 )); 148 } 149 output.push_str(&format!( 150 "-- app.gleam\n{}", 151 modules 152 .get("app") 153 .map(|string| string.as_str()) 154 .unwrap_or(src) 155 )); 156 output 157} 158 159macro_rules! assert_rename { 160 ($code:literal, $new_name:literal, $position:expr $(,)?) => { 161 assert_rename!(TestProject::for_source($code), $new_name, $position); 162 }; 163 164 (($module_name:literal, $module_src:literal), $code:literal, $new_name:literal, $position:expr $(,)?) => { 165 assert_rename!( 166 TestProject::for_source($code).add_module($module_name, $module_src), 167 $new_name, 168 $position 169 ); 170 }; 171 172 ($project:expr, $new_name:literal, $position:expr $(,)?) => { 173 let project = $project; 174 let src = project.src; 175 let position = $position.find_position(src); 176 let (range, result) = apply_rename(&project, $new_name, position); 177 178 let output = display_result(&project, result, HashMap::new(), Some(range)); 179 180 insta::assert_snapshot!(insta::internals::AutoName, output, src); 181 }; 182} 183 184macro_rules! assert_no_rename { 185 ($code:literal, $new_name:literal, $position:expr $(,)?) => { 186 let project = TestProject::for_source($code); 187 assert_no_rename!(&project, $new_name, $position); 188 }; 189 190 ($project:expr, $new_name:literal, $position:expr $(,)?) => { 191 let src = $project.src; 192 let position = $position.find_position(src); 193 let result = rename($project, $new_name, position); 194 assert_eq!(result, Ok(None)); 195 }; 196} 197 198macro_rules! assert_rename_error { 199 ($code:literal, $new_name:literal, $position:expr $(,)?) => { 200 let project = TestProject::for_source($code); 201 assert_rename_error!(&project, $new_name, $position); 202 }; 203 204 ($project:expr, $new_name:literal, $position:expr $(,)?) => { 205 let src = $project.src; 206 let position = $position.find_position(src); 207 let error = rename($project, $new_name, position).unwrap_err(); 208 let snapshot = format!("Error response message:\n\n{error}"); 209 insta::assert_snapshot!(insta::internals::AutoName, snapshot, src); 210 }; 211} 212 213macro_rules! assert_rename_files { 214 ($(($old_name:literal, $new_name:literal, $module_src:literal)),+, $code:literal, $(,)?) => { 215 let project = TestProject::for_source($code)$(.add_module($old_name, $module_src))*; 216 217 let renames = [$(($old_name, $new_name),)*]; 218 let result = rename_files(&project, &renames); 219 let output = display_result(&project, result, renames.into(), None); 220 221 insta::assert_snapshot!(insta::internals::AutoName, output, project.src); 222 }; 223} 224 225#[test] 226fn rename_local_variable() { 227 assert_rename!( 228 " 229pub fn main() { 230 let wibble = 10 231 wibble 232} 233", 234 "wobble", 235 find_position_of("wibble").nth_occurrence(2), 236 ); 237} 238 239#[test] 240fn rename_shadowed_local_variable() { 241 assert_rename!( 242 " 243pub fn main() { 244 let wibble = 10 245 let wibble = wibble / 2 246 wibble 247} 248", 249 "wobble", 250 find_position_of("wibble /"), 251 ); 252} 253 254#[test] 255fn rename_shadowing_local_variable() { 256 assert_rename!( 257 " 258pub fn main() { 259 let wibble = 10 260 let wibble = wibble / 2 261 wibble 262} 263", 264 "wobble", 265 find_position_of("wibble").nth_occurrence(4), 266 ); 267} 268 269#[test] 270fn rename_local_variable_record_access() { 271 assert_rename!( 272 " 273type Wibble { 274 Wibble(wibble: Int) 275} 276 277pub fn main() { 278 let wibble = Wibble(wibble: 1) 279 wibble.wibble 280} 281", 282 "wobble", 283 find_position_of("wibble."), 284 ); 285} 286#[test] 287fn rename_local_variable_guard_clause() { 288 assert_rename!( 289 " 290pub fn main() { 291 let wibble = True 292 case Nil { 293 Nil if wibble -> todo 294 _ -> panic 295 } 296 wibble || False 297} 298", 299 "wobble", 300 find_position_of("wibble ||"), 301 ); 302} 303 304#[test] 305fn rename_local_variable_from_definition() { 306 assert_rename!( 307 " 308pub fn main() { 309 let wibble = 10 310 let wobble = wibble + 1 311 wobble - wibble 312} 313", 314 "some_value", 315 find_position_of("wibble =") 316 ); 317} 318 319#[test] 320fn rename_local_variable_from_definition_nested_pattern() { 321 assert_rename!( 322 " 323pub fn main() { 324 let assert Ok([_, wibble, ..]) = Error(12) 325 wibble 326} 327", 328 "second_element", 329 find_position_of("wibble,") 330 ); 331} 332 333#[test] 334fn rename_local_variable_assignment_pattern() { 335 assert_rename!( 336 " 337pub fn main() { 338 let assert Error(12 as something) = Error(12) 339 something 340} 341", 342 "the_error", 343 find_position_of("something").nth_occurrence(2) 344 ); 345} 346 347#[test] 348fn rename_local_variable_from_definition_assignment_pattern() { 349 assert_rename!( 350 " 351pub fn main() { 352 let assert Error(12 as something) = Error(12) 353 something 354} 355", 356 "the_error", 357 find_position_of("something)") 358 ); 359} 360 361#[test] 362fn rename_local_variable_argument() { 363 assert_rename!( 364 " 365pub fn add(first_number: Int, x: Int) -> Int { 366 x + first_number 367} 368", 369 "second_number", 370 find_position_of("x +") 371 ); 372} 373 374#[test] 375fn rename_local_variable_argument_from_definition() { 376 assert_rename!( 377 " 378pub fn wibble(wibble: Float) { 379 wibble /. 0.3 380} 381", 382 "wobble", 383 find_position_of("wibble:") 384 ); 385} 386 387#[test] 388fn rename_local_variable_label_shorthand() { 389 assert_rename!( 390 " 391type Wibble { 392 Wibble(wibble: Int) 393} 394 395pub fn main() { 396 let Wibble(wibble:) = todo 397 wibble + 1 398} 399", 400 "wobble", 401 find_position_of("wibble +") 402 ); 403} 404 405#[test] 406fn rename_local_variable_label_shorthand_from_definition() { 407 assert_rename!( 408 " 409type Wibble { 410 Wibble(wibble: Int) 411} 412 413pub fn main() { 414 let Wibble(wibble:) = todo 415 wibble + 1 416} 417", 418 "wobble", 419 find_position_of("wibble:)") 420 ); 421} 422 423#[test] 424fn rename_local_variable_from_label_shorthand() { 425 assert_rename!( 426 " 427type Wibble { 428 Wibble(wibble: Int) 429} 430 431pub fn main() { 432 let wibble = todo 433 Wibble(wibble:) 434} 435", 436 "wobble", 437 find_position_of("wibble:)") 438 ); 439} 440 441#[test] 442fn rename_local_variable_in_bit_array_pattern() { 443 assert_rename!( 444 " 445pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { 446 let prefix_size = bit_size(prefix) 447 448 case bits { 449 <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True 450 _ -> False 451 } 452} 453", 454 "size_of_prefix", 455 find_position_of("prefix_size =") 456 ); 457} 458 459#[test] 460fn rename_local_variable_from_bit_array_pattern() { 461 assert_rename!( 462 " 463pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { 464 let prefix_size = bit_size(prefix) 465 466 case bits { 467 <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True 468 _ -> False 469 } 470} 471", 472 "size_of_prefix", 473 find_position_of("prefix_size)") 474 ); 475} 476 477#[test] 478fn no_rename_keyword() { 479 assert_no_rename!( 480 " 481pub fn main() {} 482", 483 "wibble", 484 find_position_of("fn"), 485 ); 486} 487 488#[test] 489fn no_rename_invalid_name() { 490 assert_rename_error!( 491 " 492pub fn main() { 493 let wibble = 10 494 wibble 495} 496", 497 "Not_AValid_Name", 498 find_position_of("wibble").nth_occurrence(2) 499 ); 500} 501 502#[test] 503fn rename_function_from_definition() { 504 assert_rename!( 505 ( 506 "mod", 507 " 508import app 509 510fn wibble() { 511 app.something() 512} 513" 514 ), 515 " 516pub fn something() { 517 something() 518} 519 520fn something_else() { 521 something() 522} 523", 524 "some_function", 525 find_position_of("something") 526 ); 527} 528 529#[test] 530fn rename_function_from_reference() { 531 assert_rename!( 532 ( 533 "mod", 534 " 535import app 536 537fn wibble() { 538 app.something() 539} 540" 541 ), 542 " 543pub fn something() { 544 something() 545} 546 547fn something_else() { 548 something() 549} 550", 551 "some_function", 552 find_position_of("something").nth_occurrence(2) 553 ); 554} 555 556#[test] 557fn rename_function_from_qualified_reference() { 558 assert_rename!( 559 ( 560 "mod", 561 " 562pub fn wibble() { 563 wibble() 564} 565" 566 ), 567 " 568import mod 569 570pub fn main() { 571 mod.wibble() 572} 573", 574 "some_function", 575 find_position_of("wibble") 576 ); 577} 578 579#[test] 580fn rename_function_from_unqualified_reference() { 581 assert_rename!( 582 ( 583 "mod", 584 " 585pub fn wibble() { 586 wibble() 587} 588" 589 ), 590 " 591import mod.{wibble} 592 593pub fn main() { 594 wibble() 595 mod.wibble() 596} 597", 598 "some_function", 599 find_position_of("wibble(") 600 ); 601} 602 603#[test] 604fn rename_aliased_function() { 605 assert_rename!( 606 ( 607 "mod", 608 " 609import app.{something as something_else} 610 611fn wibble() { 612 something_else() 613} 614" 615 ), 616 " 617pub fn something() { 618 something() 619} 620 621fn something_else() { 622 something() 623} 624", 625 "some_function", 626 find_position_of("something") 627 ); 628} 629 630#[test] 631fn rename_function_shadowing_module() { 632 let src = " 633import gleam/list 634 635pub fn list() { 636 [] 637} 638 639pub fn main() { 640 list.map(todo, todo) 641} 642 "; 643 644 assert_rename!( 645 TestProject::for_source(src).add_hex_module("gleam/list", "pub fn map(_, _) {}"), 646 "empty_list", 647 find_position_of("list()") 648 ); 649} 650 651#[test] 652fn rename_function_shadowed_by_field_access() { 653 assert_rename!( 654 ( 655 "mod", 656 " 657import app 658 659type App { 660 App(something: Int) 661} 662 663pub fn main() { 664 let app = App(10) 665 app.something 666} 667" 668 ), 669 " 670pub fn something() { 671 todo 672} 673", 674 "function", 675 find_position_of("something") 676 ); 677} 678 679#[test] 680fn no_rename_function_with_invalid_name() { 681 assert_rename_error!( 682 " 683pub fn main() { 684 let wibble = 10 685 wibble 686} 687", 688 "Not_AValid_Name", 689 find_position_of("main") 690 ); 691} 692 693#[test] 694fn no_rename_function_from_other_package() { 695 let src = " 696import wibble 697 698pub fn main() { 699 wibble.wobble() 700} 701"; 702 703 assert_no_rename!( 704 &TestProject::for_source(src).add_hex_module("wibble", "pub fn wobble() { todo }"), 705 "something", 706 find_position_of("wobble") 707 ); 708} 709 710#[test] 711fn rename_constant_from_definition() { 712 assert_rename!( 713 ( 714 "mod", 715 " 716import app 717 718fn wibble() { 719 app.something 720} 721" 722 ), 723 " 724pub const something = 10 725 726pub fn main() { 727 something + { 4 * something } 728} 729", 730 "ten", 731 find_position_of("something") 732 ); 733} 734 735#[test] 736fn rename_constant_from_reference() { 737 assert_rename!( 738 ( 739 "mod", 740 " 741import app 742 743fn wibble() { 744 app.something 745} 746" 747 ), 748 " 749pub const something = 10 750 751pub fn main() { 752 something + { 4 * something } 753} 754", 755 "ten", 756 find_position_of("something").nth_occurrence(2) 757 ); 758} 759 760#[test] 761fn rename_constant_from_qualified_reference() { 762 assert_rename!( 763 ( 764 "mod", 765 " 766pub const something = 10 767 768fn wibble() { 769 something 770} 771" 772 ), 773 " 774import mod 775 776pub fn main() { 777 mod.something 778} 779", 780 "ten", 781 find_position_of("something") 782 ); 783} 784 785#[test] 786fn rename_constant_from_unqualified_reference() { 787 assert_rename!( 788 ( 789 "mod", 790 " 791pub const something = 10 792 793fn wibble() { 794 something 795} 796" 797 ), 798 " 799import mod.{something} 800 801pub fn main() { 802 something + mod.something 803} 804", 805 "ten", 806 find_position_of("something +") 807 ); 808} 809 810#[test] 811fn rename_aliased_constant() { 812 assert_rename!( 813 ( 814 "mod", 815 " 816import app.{something as some_constant} 817 818fn wibble() { 819 some_constant 820} 821" 822 ), 823 " 824pub const something = 10 825 826pub fn main() { 827 something + { 4 * something } 828} 829", 830 "ten", 831 find_position_of("something") 832 ); 833} 834 835#[test] 836fn rename_constant_shadowing_module() { 837 let src = " 838import gleam/list 839 840const list = [] 841 842pub fn main() { 843 list.map(todo, todo) 844} 845 "; 846 847 assert_rename!( 848 TestProject::for_source(src).add_hex_module("gleam/list", "pub fn map(_, _) {}"), 849 "empty_list", 850 find_position_of("list =") 851 ); 852} 853 854#[test] 855fn rename_constant_shadowed_by_field_access() { 856 assert_rename!( 857 ( 858 "mod", 859 " 860import app 861 862type App { 863 App(something: Int) 864} 865 866pub fn main() { 867 let app = App(10) 868 app.something 869} 870" 871 ), 872 " 873pub const something = 10 874", 875 "constant", 876 find_position_of("something") 877 ); 878} 879 880#[test] 881fn no_rename_constant_with_invalid_name() { 882 assert_rename_error!( 883 " 884const value = 10 885", 886 "Ten", 887 find_position_of("value") 888 ); 889} 890 891#[test] 892fn no_rename_constant_from_other_package() { 893 let src = " 894import wibble 895 896pub fn main() { 897 wibble.wobble 898} 899"; 900 901 assert_no_rename!( 902 &TestProject::for_source(src).add_hex_module("wibble", "pub const wobble = 2"), 903 "something", 904 find_position_of("wobble") 905 ); 906} 907 908#[test] 909fn rename_type_variant_from_definition() { 910 assert_rename!( 911 ( 912 "mod", 913 " 914import app 915 916fn wibble() { 917 app.Constructor(4) 918} 919" 920 ), 921 " 922pub type Wibble { 923 Constructor(Int) 924} 925 926pub fn main() { 927 Constructor(10) 928} 929", 930 "Wibble", 931 find_position_of("Constructor(Int") 932 ); 933} 934 935#[test] 936fn rename_type_variant_from_reference() { 937 assert_rename!( 938 ( 939 "mod", 940 " 941import app 942 943fn wibble() { 944 app.Constructor(4) 945} 946" 947 ), 948 " 949pub type Wibble { 950 Constructor(Int) 951} 952 953pub fn main() { 954 Constructor(10) 955} 956", 957 "Wibble", 958 find_position_of("Constructor(10") 959 ); 960} 961 962#[test] 963fn rename_type_variant_from_qualified_reference() { 964 assert_rename!( 965 ( 966 "mod", 967 " 968pub type Wibble { 969 Constructor(Int) 970} 971 972fn wibble() { 973 Constructor(42) 974} 975" 976 ), 977 " 978import mod 979 980pub fn main() { 981 mod.Constructor 982} 983", 984 "Variant", 985 find_position_of("Constructor") 986 ); 987} 988 989#[test] 990fn rename_type_variant_from_unqualified_reference() { 991 assert_rename!( 992 ( 993 "mod", 994 " 995pub type Wibble { 996 Constructor(Int) 997} 998 999fn wibble() { 1000 Constructor(81) 1001} 1002" 1003 ), 1004 " 1005import mod.{Constructor} 1006 1007pub fn main() { 1008 #(Constructor(75), mod.Constructor(57)) 1009} 1010", 1011 "Number", 1012 find_position_of("Constructor(75") 1013 ); 1014} 1015 1016#[test] 1017fn rename_aliased_type_variant() { 1018 assert_rename!( 1019 ( 1020 "mod", 1021 " 1022import app.{Constructor as ValueConstructor} 1023 1024fn wibble() { 1025 ValueConstructor(172) 1026} 1027" 1028 ), 1029 " 1030pub type Wibble { 1031 Constructor(Int) 1032} 1033 1034pub fn main() { 1035 Constructor(42) 1036} 1037", 1038 "MakeAWibble", 1039 find_position_of("Constructor") 1040 ); 1041} 1042 1043#[test] 1044fn no_rename_type_variant_with_invalid_name() { 1045 assert_rename_error!( 1046 " 1047pub type Wibble { 1048 Constructor(Int) 1049} 1050", 1051 "name_in_snake_case", 1052 find_position_of("Constructor") 1053 ); 1054} 1055 1056#[test] 1057fn rename_custom_type_variant_pattern() { 1058 assert_rename!( 1059 " 1060pub type Type { 1061 X 1062 Y 1063} 1064 1065pub fn main(t) { 1066 case t { 1067 X -> 0 1068 Y -> 0 1069 } 1070} 1071", 1072 "Renamed", 1073 find_position_of("X") 1074 ); 1075} 1076 1077#[test] 1078fn rename_imported_custom_type_variant_pattern() { 1079 assert_rename!( 1080 ( 1081 "other", 1082 " 1083import app 1084 1085pub fn main(t) { 1086 case t { 1087 app.X -> 0 1088 app.Y -> 0 1089 } 1090} 1091" 1092 ), 1093 " 1094pub type Type { 1095 X 1096 Y 1097} 1098", 1099 "Renamed", 1100 find_position_of("X") 1101 ); 1102} 1103 1104#[test] 1105fn rename_imported_unqualified_custom_type_variant_pattern() { 1106 assert_rename!( 1107 ( 1108 "other", 1109 " 1110import app.{X, Y} 1111 1112pub fn main(t) { 1113 case t { 1114 X -> 0 1115 Y -> 0 1116 } 1117} 1118" 1119 ), 1120 " 1121pub type Type { 1122 X 1123 Y 1124} 1125", 1126 "Renamed", 1127 find_position_of("X") 1128 ); 1129} 1130 1131#[test] 1132fn rename_type_variant_pattern_with_arguments() { 1133 assert_rename!( 1134 " 1135pub type Wibble { 1136 Wibble(Int) 1137 Wobble(Float) 1138} 1139 1140fn wibble() { 1141 case Wibble(10) { 1142 Wibble(20) -> todo 1143 Wibble(_) -> panic 1144 } 1145} 1146", 1147 "Variant", 1148 find_position_of("Wibble(10)") 1149 ); 1150} 1151 1152#[test] 1153fn rename_type_variant_from_pattern() { 1154 assert_rename!( 1155 " 1156pub type Type { 1157 X 1158 Y 1159} 1160 1161pub fn main(t) { 1162 case t { 1163 X -> 0 1164 Y -> 0 1165 } 1166} 1167", 1168 "Renamed", 1169 find_position_of("X ->") 1170 ); 1171} 1172 1173#[test] 1174fn no_rename_type_variant_from_other_package() { 1175 let src = " 1176import wibble 1177 1178pub fn main() { 1179 wibble.Wibble(10) 1180} 1181"; 1182 1183 assert_no_rename!( 1184 &TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble(Int) }"), 1185 "Constructor", 1186 find_position_of("Wibble") 1187 ); 1188} 1189 1190#[test] 1191fn rename_value_in_nested_module() { 1192 assert_rename!( 1193 ( 1194 "sub/mod", 1195 " 1196pub fn wibble() { 1197 wibble() 1198} 1199" 1200 ), 1201 " 1202import sub/mod 1203 1204pub fn main() { 1205 mod.wibble() 1206} 1207", 1208 "some_function", 1209 find_position_of("wibble") 1210 ); 1211} 1212 1213#[test] 1214fn rename_value_in_aliased_module() { 1215 assert_rename!( 1216 ( 1217 "mod", 1218 " 1219pub fn wibble() { 1220 wibble() 1221} 1222" 1223 ), 1224 " 1225import mod as the_module 1226 1227pub fn main() { 1228 the_module.wibble() 1229} 1230", 1231 "some_function", 1232 find_position_of("wibble") 1233 ); 1234} 1235 1236#[test] 1237fn rename_aliased_value() { 1238 assert_rename!( 1239 ( 1240 "mod", 1241 " 1242import app.{Wibble as Wobble} 1243 1244fn wobble() { 1245 Wobble 1246} 1247" 1248 ), 1249 " 1250pub type Wibble { Wibble } 1251 1252pub fn main() { 1253 Wibble 1254} 1255", 1256 "Wubble", 1257 find_position_of("Wibble }") 1258 ); 1259} 1260 1261#[test] 1262fn rename_type_from_definition() { 1263 assert_rename!( 1264 ( 1265 "mod", 1266 " 1267import app 1268 1269fn wibble() -> app.Wibble { todo } 1270" 1271 ), 1272 " 1273pub type Wibble { Constructor } 1274 1275pub fn main(w: Wibble) -> Wibble { todo } 1276", 1277 "SomeType", 1278 find_position_of("Wibble") 1279 ); 1280} 1281 1282#[test] 1283fn rename_type_from_reference() { 1284 assert_rename!( 1285 ( 1286 "mod", 1287 " 1288import app 1289 1290fn wibble() -> app.Wibble { todo } 1291" 1292 ), 1293 " 1294pub type Wibble { Constructor } 1295 1296pub fn main(w: Wibble) -> Wibble { todo } 1297", 1298 "SomeType", 1299 find_position_of("Wibble").nth_occurrence(2) 1300 ); 1301} 1302 1303#[test] 1304fn rename_type_from_qualified_reference() { 1305 assert_rename!( 1306 ( 1307 "mod", 1308 " 1309pub type Wibble { Constructor } 1310 1311fn wibble(w: Wibble) -> Wibble { todo } 1312" 1313 ), 1314 " 1315import mod 1316 1317pub fn main(w: mod.Wibble) -> mod.Wibble { todo } 1318", 1319 "SomeType", 1320 find_position_of("Wibble") 1321 ); 1322} 1323 1324#[test] 1325fn rename_type_from_unqualified_reference() { 1326 assert_rename!( 1327 ( 1328 "mod", 1329 " 1330pub type Wibble { Constructor } 1331 1332fn wibble(w: Wibble) -> Wibble { todo } 1333" 1334 ), 1335 " 1336import mod.{type Wibble} 1337 1338pub fn main(w: Wibble) -> mod.Wibble { todo } 1339", 1340 "SomeType", 1341 find_position_of("Wibble)") 1342 ); 1343} 1344 1345#[test] 1346fn rename_aliased_type() { 1347 assert_rename!( 1348 ( 1349 "mod", 1350 " 1351import app.{type Wibble as Wobble} 1352 1353fn wibble() -> Wobble { todo } 1354" 1355 ), 1356 " 1357pub type Wibble { Constructor } 1358 1359pub fn main(w: Wibble) -> Wibble { todo } 1360", 1361 "SomeType", 1362 find_position_of("Wibble") 1363 ); 1364} 1365 1366#[test] 1367fn no_rename_type_with_invalid_name() { 1368 assert_rename_error!( 1369 " 1370type Wibble { Wobble } 1371", 1372 "a_type_name", 1373 find_position_of("Wibble") 1374 ); 1375} 1376 1377#[test] 1378fn no_rename_type_from_other_package() { 1379 let src = " 1380import wibble 1381 1382pub fn main() -> wibble.Wibble { todo } 1383"; 1384 1385 assert_no_rename!( 1386 &TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"), 1387 "SomeType", 1388 find_position_of("Wibble") 1389 ); 1390} 1391 1392// https://github.com/gleam-lang/gleam/issues/4372 1393#[test] 1394fn rename_type_referenced_in_variant_constructor_argument() { 1395 assert_rename!( 1396 ( 1397 "mod", 1398 " 1399import app 1400 1401pub type Wobble { 1402 Wobble(w: app.Wibble) 1403} 1404" 1405 ), 1406 " 1407pub type Wibble { 1408 Wibble 1409} 1410 1411pub fn main() { 1412 let wibble = Wibble 1413} 1414", 1415 "SomeType", 1416 find_position_of("Wibble") 1417 ); 1418} 1419 1420// https://github.com/gleam-lang/gleam/issues/4372 1421#[test] 1422fn rename_type_from_variant_constructor_argument() { 1423 assert_rename!( 1424 ( 1425 "mod", 1426 " 1427pub type Wibble { 1428 Wibble 1429} 1430 1431pub fn main() { 1432 let wibble = Wibble 1433} 1434" 1435 ), 1436 " 1437import mod 1438 1439pub type Wobble { 1440 Wobble(w: mod.Wibble) 1441} 1442", 1443 "SomeType", 1444 find_position_of("Wibble") 1445 ); 1446} 1447 1448// https://github.com/gleam-lang/gleam/issues/4553 1449#[test] 1450fn rename_local_variable_with_label_shorthand() { 1451 assert_rename!( 1452 " 1453pub type Wibble { 1454 Wibble(first: Int, second: Int) 1455} 1456 1457pub fn main() { 1458 let second = 2 1459 Wibble(first: 1, second:) 1460} 1461", 1462 "something", 1463 find_position_of("second =") 1464 ); 1465} 1466 1467// https://github.com/gleam-lang/gleam/issues/4748 1468#[test] 1469fn rename_alternative_pattern() { 1470 assert_rename!( 1471 " 1472pub fn main(x) { 1473 case x { 1474 #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) -> 1475 wibble + wobble 1476 _ -> 0 1477 } 1478} 1479", 1480 "new_name", 1481 find_position_of("wibble") 1482 ); 1483} 1484 1485// https://github.com/gleam-lang/gleam/issues/5091 1486#[test] 1487fn rename_alternative_pattern_aliases() { 1488 assert_rename!( 1489 " 1490pub fn main(x) { 1491 case x { 1492 [] as list | [_] as list -> list 1493 _ -> [] 1494 } 1495} 1496", 1497 "new_name", 1498 find_position_of("list") 1499 ); 1500} 1501 1502#[test] 1503fn rename_alternative_pattern_aliases_from_alternative() { 1504 assert_rename!( 1505 " 1506pub fn main(x) { 1507 case x { 1508 [] as list | [_] as list -> list 1509 _ -> [] 1510 } 1511} 1512", 1513 "new_name", 1514 find_position_of("list").nth_occurrence(2) 1515 ); 1516} 1517 1518#[test] 1519fn rename_alternative_pattern_aliases_from_usage() { 1520 assert_rename!( 1521 " 1522pub fn main(x) { 1523 case x { 1524 [] as list | [_] as list -> list 1525 _ -> [] 1526 } 1527} 1528", 1529 "new_name", 1530 find_position_of("list").nth_occurrence(3) 1531 ); 1532} 1533 1534#[test] 1535fn rename_alternative_pattern_alias_and_variable_1() { 1536 assert_rename!( 1537 " 1538pub fn main(x) { 1539 case x { 1540 [] as list | [_, ..list] -> list 1541 _ -> [] 1542 } 1543} 1544", 1545 "new_name", 1546 find_position_of("list").nth_occurrence(1) 1547 ); 1548} 1549 1550#[test] 1551fn rename_alternative_pattern_alias_and_variable_2() { 1552 assert_rename!( 1553 " 1554pub fn main(x) { 1555 case x { 1556 [] as list | [_, ..list] -> list 1557 _ -> [] 1558 } 1559} 1560", 1561 "new_name", 1562 find_position_of("list").nth_occurrence(2) 1563 ); 1564} 1565 1566#[test] 1567fn rename_alternative_pattern_alias_and_variable_3() { 1568 assert_rename!( 1569 " 1570pub fn main(x) { 1571 case x { 1572 [_, ..list] | [] as list -> list 1573 _ -> [] 1574 } 1575} 1576", 1577 "new_name", 1578 find_position_of("list").nth_occurrence(1) 1579 ); 1580} 1581 1582#[test] 1583fn rename_alternative_pattern_alias_and_variable_4() { 1584 assert_rename!( 1585 " 1586pub fn main(x) { 1587 case x { 1588 [_, ..list] | [] as list -> list 1589 _ -> [] 1590 } 1591} 1592", 1593 "new_name", 1594 find_position_of("list").nth_occurrence(2) 1595 ); 1596} 1597 1598#[test] 1599fn rename_alternative_pattern_from_usage() { 1600 assert_rename!( 1601 " 1602pub fn main(x) { 1603 case x { 1604 #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) -> 1605 wibble + wobble 1606 _ -> 0 1607 } 1608} 1609", 1610 "new_name", 1611 find_position_of("wibble +") 1612 ); 1613} 1614 1615// https://github.com/gleam-lang/gleam/issues/4605 1616#[test] 1617fn rename_prelude_value() { 1618 assert_rename!( 1619 " 1620pub fn main() { 1621 Ok(10) 1622} 1623", 1624 "Success", 1625 find_position_of("Ok") 1626 ); 1627} 1628#[test] 1629fn rename_prelude_type() { 1630 assert_rename!( 1631 " 1632pub fn main() -> Result(Int, Nil) { 1633 Ok(10) 1634} 1635", 1636 "SuccessOrFailure", 1637 find_position_of("Result") 1638 ); 1639} 1640 1641#[test] 1642fn rename_variable_with_alternative_pattern_with_same_name() { 1643 assert_rename!( 1644 " 1645pub fn main(x) { 1646 let some_var = 10 1647 1648 case x { 1649 #(some_var, []) | #(_, [some_var]) -> 1650 some_var 1651 _ -> 0 1652 } 1653 1654 some_var 1655} 1656", 1657 "new_name", 1658 find_position_of("some_var") 1659 ); 1660} 1661 1662#[test] 1663fn rename_prelude_value_with_prelude_already_imported() { 1664 assert_rename!( 1665 " 1666import gleam 1667 1668pub fn main() { 1669 Ok(gleam.Error(10)) 1670} 1671", 1672 "Success", 1673 find_position_of("Ok") 1674 ); 1675} 1676 1677#[test] 1678fn rename_prelude_value_with_prelude_import_with_empty_braces() { 1679 assert_rename!( 1680 " 1681import gleam.{} 1682 1683pub fn main() { 1684 Ok(gleam.Error(10)) 1685} 1686", 1687 "Success", 1688 find_position_of("Ok") 1689 ); 1690} 1691 1692#[test] 1693fn rename_prelude_value_with_other_prelude_value_imported() { 1694 assert_rename!( 1695 " 1696import gleam.{Error} 1697 1698pub fn main() { 1699 Ok(Error(10)) 1700} 1701", 1702 "Success", 1703 find_position_of("Ok") 1704 ); 1705} 1706 1707#[test] 1708fn rename_prelude_type_with_prelude_value_imported_with_trailing_comma() { 1709 assert_rename!( 1710 " 1711import gleam.{Error,} 1712 1713pub fn main() -> Result(Int, Nil) { 1714 Error(10) 1715} 1716", 1717 "OkOrError", 1718 find_position_of("Result") 1719 ); 1720} 1721 1722#[test] 1723fn rename_prelude_value_with_other_module_imported() { 1724 assert_rename!( 1725 ("something", "pub type Something"), 1726 " 1727import something 1728 1729pub fn main() { 1730 Ok(10) 1731} 1732", 1733 "Success", 1734 find_position_of("Ok") 1735 ); 1736} 1737 1738#[test] 1739fn rename_module_access_in_clause_guard() { 1740 assert_rename!( 1741 ( 1742 "wibble", 1743 " 1744import app 1745 1746pub fn main() { 1747 case app.something { 1748 thing if thing == app.something -> True 1749 _ -> False 1750 } 1751} 1752" 1753 ), 1754 " 1755pub const something = 10 1756", 1757 "new_name", 1758 find_position_of("something") 1759 ); 1760} 1761 1762#[test] 1763fn rename_variable_used_in_record_update() { 1764 assert_rename!( 1765 " 1766type Wibble { 1767 Wibble(a: Int, b: Int, c: Int) 1768} 1769 1770fn wibble(wibble: Wibble) { 1771 Wibble(..wibble, c: 1) 1772} 1773", 1774 "value", 1775 find_position_of("wibble:") 1776 ); 1777} 1778 1779//https://github.com/gleam-lang/gleam/issues/4941 1780#[test] 1781fn rename_external_function() { 1782 assert_rename!( 1783 r#" 1784pub fn main() { wibble() } 1785 1786@external(erlang, "a", "a") 1787fn wibble() -> Nil 1788"#, 1789 "new_name", 1790 find_position_of("wibble").nth_occurrence(2) 1791 ); 1792} 1793 1794#[test] 1795fn rename_external_javascript_function_with_pure_gleam_fallback() { 1796 assert_rename!( 1797 r#" 1798pub fn main() { wibble() } 1799 1800@external(javascript, "a", "a") 1801fn wibble() -> Nil { 1802 Nil 1803} 1804"#, 1805 "new_name", 1806 find_position_of("wibble").nth_occurrence(2) 1807 ); 1808} 1809 1810#[test] 1811fn rename_nested_aliased_pattern() { 1812 assert_rename!( 1813 r#" 1814pub fn go(x) { 1815 case x { 1816 [[nested, ..] as wibble, ..] -> todo 1817 _ -> todo 1818 } 1819} 1820 "#, 1821 "new_name", 1822 find_position_of("nested") 1823 ); 1824} 1825 1826#[test] 1827fn rename_module_from_import() { 1828 assert_rename!( 1829 TestProject::for_source("import option") 1830 .add_module("option", "pub type Option(a) { Some(a) None }"), 1831 "opt", 1832 find_position_of("option"), 1833 ); 1834} 1835 1836#[test] 1837fn rename_works_when_error_is_present() { 1838 assert_rename!( 1839 r#" 1840fn wibble() { 1841 "test string" 1842} 1843 1844pub fn main() { 1845 1 + "1" 1846 echo wibble() 1847} 1848 "#, 1849 "wobble", 1850 find_position_of("wibble") 1851 ); 1852} 1853 1854#[test] 1855fn rename_module_from_import_with_alias() { 1856 assert_rename!( 1857 TestProject::for_source("import option as opt") 1858 .add_module("option", "pub type Option(a) { Some(a) None }"), 1859 "o", 1860 find_position_of("opt"), 1861 ); 1862} 1863 1864#[test] 1865fn reanem_module_from_import_with_unqualified_values() { 1866 assert_rename!( 1867 TestProject::for_source("import option . { Some, None }") 1868 .add_module("option", "pub type Option(a) { Some(a) None }"), 1869 "opt", 1870 find_position_of("option"), 1871 ); 1872} 1873 1874#[test] 1875fn rename_module_from_import_with_unqualified_value_and_alias() { 1876 assert_rename!( 1877 TestProject::for_source("import option . {Some, None} as opt") 1878 .add_module("option", "pub type Option(a) { Some(a) None }"), 1879 "o", 1880 find_position_of("opt"), 1881 ); 1882} 1883 1884#[test] 1885fn rename_module_from_import_namespaced() { 1886 assert_rename!( 1887 TestProject::for_source("import std / option ") 1888 .add_module("std/option", "pub type Option(a) { Some(a) None }"), 1889 "opt", 1890 find_position_of("option"), 1891 ); 1892} 1893 1894#[test] 1895fn rename_module_from_import_namespaced_with_alias() { 1896 assert_rename!( 1897 TestProject::for_source("import std / option as opt") 1898 .add_module("std/option", "pub type Option(a) { Some(a) None }"), 1899 "o", 1900 find_position_of("opt"), 1901 ); 1902} 1903 1904#[test] 1905fn rename_module_from_import_namespaced_with_unqualified_values() { 1906 assert_rename!( 1907 TestProject::for_source("import std / option . { Some, None }") 1908 .add_module("std/option", "pub type Option(a) { Some(a) None }"), 1909 "opt", 1910 find_position_of("option"), 1911 ); 1912} 1913 1914#[test] 1915fn rename_module_from_import_namespaced_with_unqualified_value_and_alias() { 1916 assert_rename!( 1917 TestProject::for_source("import std / option . { Some, None } as opt") 1918 .add_module("std/option", "pub type Option(a) { Some(a) None }"), 1919 "o", 1920 find_position_of("opt"), 1921 ); 1922} 1923 1924#[test] 1925fn rename_module_from_import_with_alias_to_original_name() { 1926 assert_rename!( 1927 TestProject::for_source("import option as opt") 1928 .add_module("option", "pub type Option(a) { Some(a) None }"), 1929 "option", 1930 find_position_of("opt"), 1931 ); 1932} 1933 1934#[test] 1935fn rename_module_from_variant_in_expression() { 1936 let src = r#" 1937import option 1938 1939pub fn main() { 1940 echo option . None 1941} 1942"#; 1943 assert_rename!( 1944 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 1945 "opt", 1946 find_position_of("option").nth_occurrence(2) 1947 ); 1948} 1949 1950#[test] 1951fn rename_prefix_string_suffix_variable_in_case() { 1952 assert_rename!( 1953 " 1954fn main() -> String { 1955 let wibble = \"1-wibble\" 1956 case wibble { 1957 \"1\" <> rest -> rest 1958 other -> other 1959 } 1960} 1961", 1962 "new_name", 1963 find_position_of("rest").nth_occurrence(1) 1964 ); 1965} 1966 1967#[test] 1968fn rename_module_from_constant_in_expression() { 1969 let src = r#" 1970import maths 1971 1972pub fn main() { 1973 echo maths . pi 1974} 1975"#; 1976 1977 assert_rename!( 1978 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"), 1979 "m", 1980 find_position_of("maths").nth_occurrence(2), 1981 ); 1982} 1983 1984#[test] 1985fn rename_module_from_variant_in_const() { 1986 let src = r#" 1987import option 1988 1989const x = option .None 1990"#; 1991 1992 assert_rename!( 1993 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 1994 "opt", 1995 find_position_of("option").nth_occurrence(2), 1996 ); 1997} 1998 1999#[test] 2000fn rename_module_from_constant_in_const() { 2001 let src = r#" 2002import maths 2003 2004const x = maths . pi 2005"#; 2006 2007 assert_rename!( 2008 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"), 2009 "m", 2010 find_position_of("maths").nth_occurrence(2), 2011 ); 2012} 2013 2014#[test] 2015fn rename_module_from_variant_in_pattern() { 2016 let src = r#" 2017import option 2018 2019pub fn is_some(option) { 2020 case option { 2021 option. Some(_) -> True 2022 option .None -> False 2023 } 2024} 2025"#; 2026 2027 assert_rename!( 2028 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 2029 "opt", 2030 find_position_of("option").nth_occurrence(4), 2031 ); 2032} 2033 2034#[test] 2035fn rename_prefix_string_suffix_variable_in_case_triggered_from_usage() { 2036 assert_rename!( 2037 " 2038fn main() -> String { 2039 let wibble = \"1-wibble\" 2040 case wibble { 2041 \"1\" <> rest -> rest 2042 other -> other 2043 } 2044} 2045", 2046 "new_name", 2047 find_position_of("rest").nth_occurrence(2) 2048 ); 2049} 2050 2051#[test] 2052fn rename_module_from_variant_in_clause_guard() { 2053 let src = r#" 2054import option 2055 2056pub fn count_none(list) { 2057 case list { 2058 [option, ..rest] if option == option . None -> 1 + count_none(rest) 2059 [_, ..rest] -> count_none(rest) 2060 [] -> 0 2061 } 2062} 2063"#; 2064 2065 assert_rename!( 2066 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 2067 "opt", 2068 find_position_of("option").nth_occurrence(4), 2069 ); 2070} 2071 2072#[test] 2073fn rename_prefix_string_suffix_variable_with_alternative_definition_in_case() { 2074 assert_rename!( 2075 " 2076fn main() -> String { 2077 let wibble = \"1-wibble\" 2078 case wibble { 2079 \"1\" <> rest | \"2\" <> rest -> rest 2080 other -> other 2081 } 2082} 2083", 2084 "new_name", 2085 find_position_of("rest").nth_occurrence(1), 2086 ); 2087} 2088 2089#[test] 2090fn rename_module_from_constant_in_clause_guard() { 2091 let src = r#" 2092import maths 2093 2094pub fn count_pi(list) { 2095 case list { 2096 [number, ..rest] if number == maths . pi -> 1 + count_pi(rest) 2097 [_, ..rest] -> count_pi(rest) 2098 [] -> 0 2099 } 2100} 2101"#; 2102 2103 assert_rename!( 2104 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"), 2105 "m", 2106 find_position_of("maths").nth_occurrence(2), 2107 ); 2108} 2109 2110#[test] 2111fn rename_prefix_string_suffix_variable_with_alternative_definition_triggered_from_second_pattern() 2112{ 2113 assert_rename!( 2114 " 2115fn main() -> String { 2116 let wibble = \"1-wibble\" 2117 case wibble { 2118 \"1\" <> rest | \"2\" <> rest -> rest 2119 other -> other 2120 } 2121} 2122", 2123 "new_name", 2124 find_position_of("rest").nth_occurrence(2), 2125 ); 2126} 2127 2128#[test] 2129fn rename_module_from_type_in_custom_type() { 2130 let src = r#" 2131import option 2132 2133type Value(a) { 2134 Value(option.Option(a)) 2135} 2136"#; 2137 2138 assert_rename!( 2139 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 2140 "opt", 2141 find_position_of("option").nth_occurrence(2), 2142 ); 2143} 2144 2145#[test] 2146fn rename_module_from_type_in_type_alias() { 2147 let src = r#" 2148import option 2149 2150type Option(a) = 2151 option.Option(a) 2152"#; 2153 2154 assert_rename!( 2155 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 2156 "opt", 2157 find_position_of("option").nth_occurrence(2), 2158 ); 2159} 2160 2161#[test] 2162fn rename_module_from_type_in_annotation() { 2163 let src = r#" 2164import option 2165 2166const x: option.Option(Int) = option.Some(1) 2167"#; 2168 2169 assert_rename!( 2170 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"), 2171 "opt", 2172 find_position_of("option").nth_occurrence(2), 2173 ); 2174} 2175 2176#[test] 2177fn rename_module_from_function_call() { 2178 let src = r#" 2179import option 2180 2181pub fn main() { 2182 option.is_some(option.Some(1)) 2183} 2184"#; 2185 2186 let option_module = r#" 2187pub type Option(a) { 2188 Some(a) 2189 None 2190} 2191 2192pub fn is_some(option: Option(a)) -> Bool { 2193 case option { 2194 Some(_) -> True 2195 None -> False 2196 } 2197} 2198"#; 2199 2200 assert_rename!( 2201 TestProject::for_source(src).add_module("option", option_module), 2202 "opt", 2203 find_position_of("option").nth_occurrence(2), 2204 ); 2205} 2206 2207#[test] 2208fn rename_prefix_string_suffix_variable_in_let_assert() { 2209 assert_rename!( 2210 " 2211fn main() -> String { 2212 let assert \"1\" <> rest = \"1-wibble\" 2213 rest 2214} 2215", 2216 "new_name", 2217 find_position_of("rest").nth_occurrence(1) 2218 ); 2219} 2220 2221#[test] 2222fn rename_prefix_string_suffix_variable_in_let_assert_triggered_from_usage() { 2223 assert_rename!( 2224 " 2225fn main() -> String { 2226 let assert \"1\" <> rest = \"1-wibble\" 2227 rest 2228} 2229", 2230 "new_name", 2231 find_position_of("rest").nth_occurrence(2) 2232 ); 2233} 2234 2235#[test] 2236fn rename_prefix_string_alias_in_case() { 2237 assert_rename!( 2238 " 2239fn main() -> String { 2240 let wibble = \"1-wibble\" 2241 case wibble { 2242 \"1\" as digit <> rest -> digit <> rest 2243 other -> other 2244 } 2245} 2246", 2247 "new_name", 2248 find_position_of("digit").nth_occurrence(1) 2249 ); 2250} 2251 2252#[test] 2253fn rename_prefix_string_alias_in_case_triggered_from_usage() { 2254 assert_rename!( 2255 " 2256fn main() -> String { 2257 let wibble = \"1-wibble\" 2258 case wibble { 2259 \"1\" as digit <> rest -> digit <> rest 2260 other -> other 2261 } 2262} 2263", 2264 "new_name", 2265 find_position_of("digit").nth_occurrence(2) 2266 ); 2267} 2268 2269#[test] 2270fn rename_prefix_string_alias_with_alternative_definitions_in_case() { 2271 assert_rename!( 2272 " 2273fn main() -> String { 2274 let wibble = \"1-wibble\" 2275 case wibble { 2276 \"1\" as digit <> rest | \"2\" as digit <> rest -> digit <> rest 2277 other -> other 2278 } 2279} 2280", 2281 "new_name", 2282 find_position_of("digit").nth_occurrence(1) 2283 ); 2284} 2285 2286#[test] 2287fn rename_prefix_string_alias_with_alternative_definitions_triggered_from_second_pattern() { 2288 assert_rename!( 2289 " 2290fn main() -> String { 2291 let wibble = \"1-wibble\" 2292 case wibble { 2293 \"1\" as digit <> rest | \"2\" as digit <> rest -> digit <> rest 2294 other -> other 2295 } 2296} 2297", 2298 "new_name", 2299 find_position_of("digit").nth_occurrence(2) 2300 ); 2301} 2302 2303#[test] 2304fn rename_prefix_string_alias_in_let_assert() { 2305 assert_rename!( 2306 " 2307fn main() -> String { 2308 let assert \"1\" as digit <> rest = \"1-wibble\" 2309 digit 2310} 2311", 2312 "new_name", 2313 find_position_of("digit").nth_occurrence(1) 2314 ); 2315} 2316 2317#[test] 2318fn rename_prefix_string_alias_in_let_assert_triggered_from_usage() { 2319 assert_rename!( 2320 " 2321fn main() -> String { 2322 let assert \"1\" as digit <> rest = \"1-wibble\" 2323 digit 2324} 2325", 2326 "new_name", 2327 find_position_of("digit").nth_occurrence(2) 2328 ); 2329} 2330 2331#[test] 2332fn rename_prefix_string_suffix_variable_nested_in_tuple() { 2333 assert_rename!( 2334 " 2335fn main() { 2336 case #(\"1-wibble\", 0) { 2337 #(\"1\" <> rest, _) -> rest 2338 _ -> \"\" 2339 } 2340} 2341", 2342 "new_name", 2343 find_position_of("rest").nth_occurrence(1) 2344 ); 2345} 2346 2347#[test] 2348fn rename_prefix_string_alias_used_in_guard() { 2349 assert_rename!( 2350 " 2351fn main() { 2352 case \"1-wibble\" { 2353 \"1\" as digit <> _rest if digit == \"1\" -> digit 2354 _ -> \"\" 2355 } 2356} 2357", 2358 "new_name", 2359 find_position_of("digit").nth_occurrence(1) 2360 ); 2361} 2362 2363#[test] 2364fn rename_prefix_string_suffix_used_in_guard() { 2365 assert_rename!( 2366 " 2367fn main() { 2368 case \"1-wibble\" { 2369 \"1\" <> rest if rest == \"-wibble\" -> rest 2370 _ -> \"\" 2371 } 2372} 2373", 2374 "new_name", 2375 find_position_of("rest").nth_occurrence(1) 2376 ); 2377} 2378 2379#[test] 2380fn rename_prefix_string_suffix_shadowing_outer_variable() { 2381 assert_rename!( 2382 " 2383fn main() { 2384 let rest = \"outer\" 2385 case \"1-wibble\" { 2386 \"1\" <> rest -> rest 2387 _ -> rest 2388 } 2389} 2390", 2391 "new_name", 2392 find_position_of("rest").nth_occurrence(2) 2393 ); 2394} 2395 2396#[test] 2397fn rename_prefix_string_alias_and_suffix_complex_guard() { 2398 assert_rename!( 2399 " 2400fn main() { 2401 case \"1-wibble\" { 2402 \"1\" as digit <> rest if digit == \"1\" && rest == \"-wibble\" -> #(digit, rest) 2403 _ -> #(\"\", \"\") 2404 } 2405} 2406", 2407 "new_name", 2408 find_position_of("digit").nth_occurrence(1) 2409 ); 2410} 2411 2412#[test] 2413fn rename_module_from_alias_use() { 2414 let src = r#" 2415import maths as m 2416 2417pub fn main() { 2418 echo m .pi 2419} 2420"#; 2421 2422 assert_rename!( 2423 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"), 2424 "mth", 2425 find_position_of("m").nth_occurrence(5) 2426 ); 2427} 2428 2429#[test] 2430fn rename_local_variable_from_guard() { 2431 assert_rename!( 2432 " 2433pub fn main() { 2434 let wibble = True 2435 let wobble = False 2436 case wibble { 2437 True if wobble -> !wibble 2438 False if !wobble -> wibble 2439 _ -> wobble 2440 } 2441} 2442", 2443 "something_else", 2444 find_position_of("wobble").nth_occurrence(2).under_char('o') 2445 ); 2446} 2447 2448#[test] 2449fn alias_imported_module_from_guard() { 2450 assert_rename!( 2451 ("mod", "pub const wibble = 10"), 2452 " 2453import mod 2454 2455pub fn main() { 2456 let wibble = True 2457 case wibble { 2458 True if mod.wibble < 5 -> !wibble 2459 False if mod.wibble != 10 -> wibble 2460 _ -> mod.wibble + 1 2461 } 2462} 2463", 2464 "module", 2465 find_position_of("mod.wibble").under_char('m') 2466 ); 2467} 2468 2469#[test] 2470fn rename_module_select_from_guard() { 2471 assert_rename!( 2472 ("mod", "pub const wibble = 10"), 2473 " 2474import mod 2475 2476pub fn main() { 2477 let wibble = True 2478 case wibble { 2479 True if mod.wibble < 5 -> !wibble 2480 False if mod.wibble != 10 -> wibble 2481 _ -> mod.wibble + 1 2482 } 2483} 2484", 2485 "ten", 2486 find_position_of("mod.wibble").under_char('w') 2487 ); 2488} 2489 2490#[test] 2491fn rename_type_variable_in_function() { 2492 assert_rename!( 2493 " 2494pub fn first(a: wibble, b: wobble) -> wibble { 2495 a 2496} 2497", 2498 "value", 2499 find_position_of("wibble") 2500 ); 2501} 2502 2503#[test] 2504fn rename_type_variable_in_function_from_return() { 2505 assert_rename!( 2506 " 2507pub fn first(a: wibble, b: wobble) -> wibble { 2508 a 2509} 2510", 2511 "value", 2512 find_position_of("-> wibble").under_char('l') 2513 ); 2514} 2515 2516#[test] 2517fn rename_type_variable_in_function_body_not_used_in_head() { 2518 assert_rename!( 2519 " 2520pub fn something() { 2521 let x: Result(a, b) = todo 2522 let y: a = case x { 2523 Ok(a) -> a 2524 Error(_) -> panic 2525 } 2526} 2527", 2528 "ok", 2529 find_position_of(": a").under_char('a') 2530 ); 2531} 2532 2533#[test] 2534fn rename_type_variable_in_function_used_in_body() { 2535 assert_rename!( 2536 " 2537pub fn first(a: wibble, b: wobble) -> wibble { 2538 let x: wibble = a 2539 let f = fn(a: wibble) -> wibble { a } 2540 f(x) 2541} 2542", 2543 "value", 2544 find_position_of("wibble") 2545 ); 2546} 2547 2548#[test] 2549fn rename_type_variable_in_function_from_body() { 2550 assert_rename!( 2551 " 2552pub fn first(a: wibble, b: wobble) -> wibble { 2553 let x: wibble = a 2554 let f = fn(a: wibble) -> wibble { a } 2555 f(x) 2556} 2557", 2558 "value", 2559 find_position_of("x: wibble").under_char('i') 2560 ); 2561} 2562 2563#[test] 2564fn type_variable_in_separate_function_is_not_renamed() { 2565 assert_rename!( 2566 " 2567pub fn first(a: wibble, b: wobble) -> wibble { 2568 a 2569} 2570 2571pub fn an_unrelated_function(a: wibble, b: wibble) -> wibble { 2572 a 2573} 2574", 2575 "value", 2576 find_position_of("wibble") 2577 ); 2578} 2579 2580#[test] 2581fn rename_type_variable_in_constant() { 2582 assert_rename!( 2583 " 2584pub const empty: List(#(anything, anything)) = [] 2585", 2586 "a", 2587 find_position_of("anything") 2588 ); 2589} 2590 2591#[test] 2592fn rename_type_variable_in_type_alias() { 2593 assert_rename!( 2594 " 2595pub type Option(a) { 2596 Some(a) 2597 None 2598} 2599 2600pub type Maybe(some_type) = 2601 Option(some_type) 2602", 2603 "something", 2604 find_position_of("Option(some_type").under_char('_') 2605 ); 2606} 2607 2608#[test] 2609fn rename_type_variable_in_type_alias_from_head() { 2610 assert_rename!( 2611 " 2612pub type Option(a) { 2613 Some(a) 2614 None 2615} 2616 2617pub type Maybe(some_type) = 2618 Option(some_type) 2619", 2620 "something", 2621 find_position_of("some_type") 2622 ); 2623} 2624 2625#[test] 2626fn rename_type_variable_in_custom_type_from_head() { 2627 assert_rename!( 2628 " 2629pub type Option(anything) { 2630 Some(anything) 2631 None 2632} 2633", 2634 "something", 2635 find_position_of("anything") 2636 ); 2637} 2638 2639#[test] 2640fn rename_type_variable_in_custom_type_from_constructor() { 2641 assert_rename!( 2642 " 2643pub type Option(anything) { 2644 Some(anything) 2645 None 2646} 2647", 2648 "something", 2649 find_position_of("Some(anything").under_char('i') 2650 ); 2651} 2652 2653#[test] 2654fn invalid_type_variable_name() { 2655 assert_rename_error!( 2656 " 2657pub type Option(anything) { 2658 Some(anything) 2659 None 2660} 2661", 2662 "SomeType", 2663 find_position_of("anything") 2664 ); 2665} 2666#[test] 2667fn renaming_file_modifies_imports_and_references() { 2668 assert_rename_files!( 2669 ( 2670 "wibble/wobble", 2671 "wibble/wubble", 2672 " 2673pub type Wibble { 2674 Wibble 2675 Wobble 2676} 2677 2678pub const wibble = Wibble 2679" 2680 ), 2681 " 2682import wibble/wobble.{Wibble} 2683 2684pub fn main() -> wobble.Wibble { 2685 assert wobble.wibble == Wibble 2686 wobble.Wobble 2687} 2688", 2689 ); 2690} 2691 2692#[test] 2693fn change_directory_of_file() { 2694 assert_rename_files!( 2695 ( 2696 "wobble", 2697 "wibble/wobble", 2698 " 2699pub type Wibble { 2700 Wibble 2701 Wobble 2702} 2703 2704pub const wibble = Wibble 2705" 2706 ), 2707 " 2708import wobble.{Wibble} 2709 2710pub fn main() -> wobble.Wibble { 2711 assert wobble.wibble == Wibble 2712 wobble.Wobble 2713} 2714", 2715 ); 2716} 2717 2718#[test] 2719fn rename_file_does_not_modify_aliased_imports() { 2720 assert_rename_files!( 2721 ( 2722 "wibble/wobble", 2723 "wibble/wubble", 2724 " 2725pub type Wibble { 2726 Wibble 2727 Wobble 2728} 2729 2730pub const wibble = Wibble 2731" 2732 ), 2733 " 2734import wibble/wobble.{Wibble} as wibble 2735 2736pub fn main() -> wibble.Wibble { 2737 assert wibble.wibble == Wibble 2738 wibble.Wobble 2739} 2740", 2741 ); 2742} 2743 2744#[test] 2745fn rename_file_removes_unnecessary_alias() { 2746 assert_rename_files!( 2747 ( 2748 "wibble/wobble", 2749 "wibble/wibble", 2750 " 2751pub type Wibble { 2752 Wibble 2753 Wobble 2754} 2755 2756pub const wibble = Wibble 2757" 2758 ), 2759 " 2760import wibble/wobble.{Wibble} as wibble 2761 2762pub fn main() -> wibble.Wibble { 2763 assert wibble.wibble == Wibble 2764 wibble.Wobble 2765} 2766", 2767 ); 2768} 2769 2770#[test] 2771fn rename_file_changes_all_correct_ast_nodes() { 2772 assert_rename_files!( 2773 ( 2774 "wibble", 2775 "wobble", 2776 " 2777pub type Wibble { 2778 Wibble 2779 Wobble 2780} 2781 2782pub const wibble = Wibble 2783" 2784 ), 2785 " 2786import wibble 2787 2788pub const one = wibble.Wibble 2789 2790pub const two = wibble.wibble 2791 2792pub fn main() -> wibble.Wibble { 2793 case wibble.Wobble { 2794 x if x == wibble.Wibble -> x 2795 x if x == wibble.wibble -> x 2796 wibble.Wobble -> wibble.wibble 2797 } 2798} 2799", 2800 ); 2801} 2802 2803#[test] 2804fn rename_multiple_files() { 2805 assert_rename_files!( 2806 ( 2807 "wibble", 2808 "wibble/wibble", 2809 "pub type Wibble { Wibble Wobble }" 2810 ), 2811 ( 2812 "wobble", 2813 "wibble/wobble", 2814 "import wibble 2815pub const wibble = wibble.Wobble" 2816 ), 2817 " 2818import wibble 2819import wobble 2820 2821pub fn main() -> wibble.Wibble { 2822 wobble.wibble 2823} 2824", 2825 ); 2826}