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 / hover.rs
43 kB 2308 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2023 The Gleam contributors 3 4use lsp_types::{Contents, Hover, HoverParams, MarkedString, Position, Range}; 5 6use super::*; 7 8fn hover(tester: TestProject<'_>, position: Position) -> Option<Hover> { 9 tester.at(position, |engine, param, _| { 10 let params = HoverParams { 11 text_document_position_params: param, 12 work_done_progress_params: Default::default(), 13 }; 14 let response = engine.hover(params); 15 16 response.result.unwrap() 17 }) 18} 19 20pub fn show_hover(code: &str, range: Range, position: Position) -> String { 21 let Range { start, end } = range; 22 23 // When we display the over range the end character is always excluded! 24 let end = Position::new(end.line, end.character); 25 26 let mut buffer: String = "".into(); 27 for (line_number, line) in code.lines().enumerate() { 28 let mut underline: String = "".into(); 29 let mut underline_empty = true; 30 31 for (column_number, _) in line.chars().enumerate() { 32 let current_position = Position::new(line_number as u32, column_number as u32); 33 if current_position == position { 34 underline_empty = false; 35 underline.push('↑'); 36 } else if start <= current_position && current_position < end { 37 underline_empty = false; 38 underline.push('▔'); 39 } else { 40 underline.push(' '); 41 } 42 } 43 44 buffer.push_str(line); 45 if !underline_empty { 46 buffer.push('\n'); 47 buffer.push_str(&underline); 48 } 49 buffer.push('\n'); 50 } 51 52 buffer 53} 54 55fn pretty_hover_contents(contents: Contents) -> String { 56 let (kind, content) = match contents { 57 Contents::MarkedString(marked_string) => ("markdown", pretty_marked_string(marked_string)), 58 Contents::MarkedStringList(marked_strings) => ( 59 "markdown array", 60 marked_strings 61 .into_iter() 62 .map(pretty_marked_string) 63 .join("\n\n"), 64 ), 65 Contents::MarkupContent(lsp_types::MarkupContent { kind, value }) => match kind { 66 lsp_types::MarkupKind::PlainText => ("plaintext", value), 67 lsp_types::MarkupKind::Markdown => ("markdown", value), 68 }, 69 }; 70 format!("----- Hover content ({kind}) -----\n{content}") 71} 72 73fn pretty_marked_string(marked_string: MarkedString) -> String { 74 match marked_string { 75 MarkedString::String(string) => string, 76 #[allow(deprecated)] 77 MarkedString::MarkedStringWithLanguage(lsp_types::MarkedStringWithLanguage { 78 language, 79 value, 80 }) => { 81 format!("```{language}\n{value}\n```") 82 } 83 } 84} 85 86#[macro_export] 87macro_rules! assert_hover { 88 ($code:literal, $position:expr $(,)?) => { 89 let project = TestProject::for_source($code); 90 assert_hover!(project, $position); 91 }; 92 93 ($project:expr, $position:expr $(,)?) => { 94 let src = $project.src; 95 let position = $position.find_position(src); 96 let result = hover($project, position).expect("no hover produced"); 97 let pretty_hover = show_hover(src, result.range.expect("hover with no range"), position); 98 let output = format!( 99 "{}\n\n{}", 100 pretty_hover, 101 pretty_hover_contents(result.contents) 102 ); 103 insta::assert_snapshot!(insta::internals::AutoName, output, src); 104 }; 105} 106 107#[test] 108fn hover_function_definition() { 109 assert_hover!( 110 " 111fn add_2(x) { 112 x + 2 113} 114", 115 find_position_of("add_2") 116 ); 117} 118 119#[test] 120fn hover_local_function() { 121 assert_hover!( 122 " 123fn my_fn() { 124 Nil 125} 126 127fn main() { 128 my_fn 129} 130", 131 find_position_of("my_fn").under_char('y').nth_occurrence(2) 132 ); 133} 134 135// https://github.com/gleam-lang/gleam/issues/2654 136#[test] 137fn hover_local_function_in_pipe() { 138 assert_hover!( 139 " 140fn add1(num: Int) -> Int { 141 num + 1 142} 143 144pub fn main() { 145 add1(1) 146 147 1 148 |> add1 149 |> add1 150 |> add1 151} 152", 153 find_position_of("add1") 154 .with_char_offset(1) 155 .nth_occurrence(2) 156 ); 157} 158 159// https://github.com/gleam-lang/gleam/issues/2654 160#[test] 161fn hover_local_function_in_pipe_1() { 162 assert_hover!( 163 " 164fn add1(num: Int) -> Int { 165 num + 1 166} 167 168pub fn main() { 169 add1(1) 170 171 1 172 |> add1 173 |> add1 174 |> add1 175} 176", 177 find_position_of("add1") 178 .with_char_offset(2) 179 .nth_occurrence(3) 180 ); 181} 182 183// https://github.com/gleam-lang/gleam/issues/2654 184#[test] 185fn hover_local_function_in_pipe_2() { 186 assert_hover!( 187 " 188fn add1(num: Int) -> Int { 189 num + 1 190} 191 192pub fn main() { 193 add1(1) 194 195 1 196 |> add1 197 |> add1 198 |> add1 199} 200", 201 find_position_of("add1") 202 .with_char_offset(2) 203 .nth_occurrence(4) 204 ); 205} 206 207// https://github.com/gleam-lang/gleam/issues/2654 208#[test] 209fn hover_local_function_in_pipe_3() { 210 assert_hover!( 211 " 212fn add1(num: Int) -> Int { 213 num + 1 214} 215 216pub fn main() { 217 add1(1) 218 219 1 220 |> add1 221 |> add1 222 |> add1 223} 224", 225 find_position_of("add1") 226 .with_char_offset(2) 227 .nth_occurrence(5) 228 ); 229} 230 231#[test] 232fn hover_imported_function() { 233 let code = " 234import example_module 235fn main() { 236 example_module.my_fn 237} 238"; 239 240 assert_hover!( 241 TestProject::for_source(code).add_module("example_module", "pub fn my_fn() { Nil }"), 242 find_position_of("my_fn").under_char('_'), 243 ); 244} 245 246#[test] 247fn hover_external_imported_function() { 248 let code = " 249import example_module 250fn main() { 251 example_module.my_fn 252} 253"; 254 255 assert_hover!( 256 TestProject::for_source(code).add_hex_module("example_module", "pub fn my_fn() { Nil }"), 257 find_position_of("my_fn").under_char('_'), 258 ); 259} 260 261#[test] 262fn hover_external_imported_unqualified_function() { 263 let code = " 264import example_module.{my_fn} 265fn main() { 266 my_fn 267} 268"; 269 270 assert_hover!( 271 TestProject::for_source(code).add_hex_module("example_module", "pub fn my_fn() { Nil }"), 272 find_position_of("my_fn").under_char('f').nth_occurrence(2), 273 ); 274} 275 276#[test] 277fn hover_external_imported_function_renamed_module() { 278 let code = " 279import example_module as renamed_module 280fn main() { 281 renamed_module.my_fn 282} 283"; 284 285 assert_hover!( 286 TestProject::for_source(code).add_hex_module("example_module", "pub fn my_fn() { Nil }"), 287 find_position_of("my_fn").under_char('f'), 288 ); 289} 290 291#[test] 292fn hover_external_unqualified_imported_function_renamed_module() { 293 let code = " 294import example_module.{my_fn} as renamed_module 295fn main() { 296 my_fn 297} 298"; 299 300 assert_hover!( 301 TestProject::for_source(code).add_hex_module("example_module", "pub fn my_fn() { Nil }"), 302 find_position_of("my_fn").under_char('_').nth_occurrence(2), 303 ); 304} 305 306#[test] 307fn hover_external_imported_function_nested_module() { 308 // Example of HexDocs link with nested modules: https://lustre.hexdocs.pm/lustre/element/svg.html 309 let code = " 310import my/nested/example_module 311fn main() { 312 example_module.my_fn 313} 314"; 315 316 assert_hover!( 317 TestProject::for_source(code) 318 .add_hex_module("my/nested/example_module", "pub fn my_fn() { Nil }"), 319 find_position_of("my_fn").under_char('f'), 320 ); 321} 322 323#[test] 324fn hover_external_imported_ffi_renamed_function() { 325 let code = r#" 326import example_module 327fn main() { 328 example_module.my_fn 329} 330"#; 331 332 let hex_module = r#" 333@external(erlang, "my_mod_ffi", "renamed_fn") 334pub fn my_fn() -> Nil 335"#; 336 337 assert_hover!( 338 TestProject::for_source(code).add_hex_module("example_module", hex_module,), 339 find_position_of("my_fn").under_char('f'), 340 ); 341} 342 343#[test] 344fn hover_external_imported_constants() { 345 let code = " 346import example_module 347fn main() { 348 example_module.my_const 349} 350"; 351 352 assert_hover!( 353 TestProject::for_source(code).add_hex_module("example_module", "pub const my_const = 42"), 354 find_position_of("my_const").under_char('_'), 355 ); 356} 357 358#[test] 359fn hover_external_imported_unqualified_constants() { 360 let code = " 361import example_module.{my_const} 362fn main() { 363 my_const 364} 365"; 366 367 assert_hover!( 368 TestProject::for_source(code).add_hex_module("example_module", "pub const my_const = 42"), 369 find_position_of("my_const") 370 .under_char('c') 371 .nth_occurrence(2), 372 ); 373} 374 375#[test] 376fn hover_external_value_with_two_modules_same_name() { 377 let code = " 378import a/example_module as _ 379import b/example_module 380fn main() { 381 example_module.my_const 382} 383"; 384 385 assert_hover!( 386 TestProject::for_source(code) 387 .add_hex_module("a/example_module", "pub const my_const = 42") 388 .add_hex_module("b/example_module", "pub const my_const = 42"), 389 find_position_of("my_const").under_char('c'), 390 ); 391} 392 393#[test] 394fn hover_external_function_with_another_value_same_name() { 395 let code = " 396import a/example_module.{my_const as discarded} 397import b/example_module.{my_const} as _ 398fn main() { 399 my_const 400} 401"; 402 403 assert_hover!( 404 TestProject::for_source(code) 405 .add_hex_module("a/example_module", "pub const my_const = 42") 406 .add_hex_module("b/example_module", "pub const my_const = 42"), 407 find_position_of("my_const") 408 .under_char('o') 409 .nth_occurrence(3), 410 ); 411} 412 413#[test] 414fn hover_function_definition_with_docs() { 415 assert_hover!( 416 " 417/// Exciting documentation 418/// Maybe even multiple lines 419fn append(x, y) { 420 x <> y 421} 422", 423 find_position_of("append") 424 ); 425} 426 427#[test] 428fn hover_function_argument() { 429 assert_hover!( 430 " 431/// Exciting documentation 432/// Maybe even multiple lines 433fn append(x, y) { 434 x <> y 435} 436", 437 find_position_of("append(x, y)").under_char('x') 438 ); 439} 440 441#[test] 442fn hover_function_body() { 443 let code = " 444/// Exciting documentation 445/// Maybe even multiple lines 446fn append(x, y) { 447 x <> y 448} 449"; 450 451 assert_eq!( 452 hover(TestProject::for_source(code), Position::new(4, 1)), 453 None 454 ); 455} 456 457#[test] 458fn hover_expressions_in_function_body() { 459 assert_hover!( 460 " 461fn append(x, y) { 462 x <> y 463} 464", 465 find_position_of("x").nth_occurrence(2) 466 ); 467} 468 469#[test] 470fn hover_module_constant() { 471 assert_hover!( 472 " 473/// Exciting documentation 474/// Maybe even multiple lines 475const one = 1 476", 477 find_position_of("one") 478 ); 479} 480 481#[test] 482fn hover_variable_in_use_expression() { 483 assert_hover!( 484 " 485fn b(fun: fn(Int) -> String) { 486 fun(42) 487} 488 489fn do_stuff() { 490 let c = \"done\" 491 492 use a <- b 493 c 494} 495", 496 find_position_of("use a").under_last_char() 497 ); 498} 499 500#[test] 501fn hover_variable_in_use_expression_1() { 502 assert_hover!( 503 " 504fn b(fun: fn(Int) -> String) { 505 fun(42) 506} 507 508fn do_stuff() { 509 let c = \"done\" 510 511 use a <- b 512 c 513} 514", 515 find_position_of("b").nth_occurrence(2) 516 ); 517} 518 519#[test] 520fn hover_variable_in_use_expression_2() { 521 assert_hover!( 522 " 523fn b(fun: fn(Int) -> String) { 524 fun(42) 525} 526 527fn do_stuff() { 528 let c = \"done\" 529 530 use a <- b 531 c 532} 533", 534 find_position_of("c").nth_occurrence(2) 535 ); 536} 537 538#[test] 539fn hover_function_arg_annotation_2() { 540 assert_hover!( 541 " 542/// Exciting documentation 543/// Maybe even multiple lines 544fn append(x: String, y: String) -> String { 545 x <> y 546} 547", 548 find_position_of("String").under_char('n') 549 ); 550} 551 552#[test] 553fn hover_function_return_annotation() { 554 assert_hover!( 555 " 556/// Exciting documentation 557/// Maybe even multiple lines 558fn append(x: String, y: String) -> String { 559 x <> y 560} 561", 562 find_position_of("String").under_char('n').nth_occurrence(3) 563 ); 564} 565 566#[test] 567fn hover_function_return_annotation_with_tuple() { 568 assert_hover!( 569 " 570/// Exciting documentation 571/// Maybe even multiple lines 572fn append(x: String, y: String) -> #(String, String) { 573 #(x, y) 574} 575", 576 find_position_of("String").under_char('r').nth_occurrence(3) 577 ); 578} 579 580#[test] 581fn hover_module_constant_annotation() { 582 assert_hover!( 583 " 584/// Exciting documentation 585/// Maybe even multiple lines 586const one: Int = 1 587", 588 find_position_of("Int").under_last_char() 589 ); 590} 591 592#[test] 593fn hover_type_constructor_annotation() { 594 assert_hover!( 595 " 596type Wibble { 597 Wibble(arg: String) 598} 599", 600 find_position_of("String").under_char('n') 601 ); 602} 603 604#[test] 605fn hover_type_alias_annotation() { 606 assert_hover!("type Wibble = Int", find_position_of("Int").under_char('n')); 607} 608 609#[test] 610fn hover_assignment_annotation() { 611 assert_hover!( 612 " 613fn wibble() { 614 let wobble: Int = 7 615 wobble 616} 617", 618 find_position_of("Int").under_last_char() 619 ); 620} 621 622#[test] 623fn hover_function_arg_annotation_with_documentation() { 624 assert_hover!( 625 " 626/// Exciting documentation 627/// Maybe even multiple lines 628type Wibble { 629 Wibble(arg: String) 630} 631 632fn identity(x: Wibble) -> Wibble { 633 x 634} 635", 636 find_position_of("Wibble") 637 .under_last_char() 638 .nth_occurrence(3) 639 ); 640} 641 642#[test] 643fn hover_import_unqualified_value() { 644 let code = " 645import example_module.{my_num} 646fn main() { 647 my_num 648} 649"; 650 651 assert_hover!( 652 TestProject::for_source(code).add_module( 653 "example_module", 654 " 655/// Exciting documentation 656/// Maybe even multiple lines 657pub const my_num = 1" 658 ), 659 find_position_of("my_num").under_char('n') 660 ); 661} 662 663#[test] 664fn hover_import_unqualified_value_from_hex() { 665 let code = " 666import example_module.{my_num} 667fn main() { 668 my_num 669} 670"; 671 672 assert_hover!( 673 TestProject::for_source(code).add_hex_module( 674 "example_module", 675 " 676/// Exciting documentation 677/// Maybe even multiple lines 678pub const my_num = 1" 679 ), 680 find_position_of("my_num").under_char('n') 681 ); 682} 683 684#[test] 685fn hover_import_unqualified_type() { 686 let code = " 687import example_module.{type MyType, MyType} 688fn main() -> MyType { 689 MyType 690} 691"; 692 693 assert_hover!( 694 TestProject::for_source(code).add_module( 695 "example_module", 696 " 697/// Exciting documentation 698/// Maybe even multiple lines 699pub type MyType { 700 MyType 701}" 702 ), 703 find_position_of("MyType").under_last_char() 704 ); 705} 706 707#[test] 708fn hover_works_even_for_invalid_code() { 709 assert_hover!( 710 " 711fn invalid() { 1 + Nil } 712fn valid() { Nil } 713", 714 find_position_of("fn valid").under_char('v') 715 ); 716} 717 718#[test] 719fn hover_for_pattern_spread_ignoring_all_fields() { 720 assert_hover!( 721 " 722pub type Model { 723 Model( 724 Int, 725 Float, 726 label1: Int, 727 label2: String, 728 ) 729} 730 731pub fn main() { 732 case todo { 733 Model(..) -> todo 734 } 735} 736", 737 find_position_of("..") 738 ); 739} 740 741#[test] 742fn hover_for_pattern_spread_ignoring_some_fields() { 743 assert_hover!( 744 " 745pub type Model { 746 Model( 747 Int, 748 Float, 749 label1: Int, 750 label2: String, 751 ) 752} 753 754pub fn main() { 755 case todo { 756 Model(_, label1: _, ..) -> todo 757 } 758} 759", 760 find_position_of("..").under_last_char() 761 ); 762} 763 764#[test] 765fn hover_for_pattern_spread_ignoring_all_positional_fields() { 766 assert_hover!( 767 " 768pub type Model { 769 Model( 770 Int, 771 Float, 772 label1: Int, 773 label2: String, 774 ) 775} 776 777pub fn main() { 778 case todo { 779 Model(_, _, _, ..) -> todo 780 } 781} 782", 783 find_position_of("..") 784 ); 785} 786 787#[test] 788fn hover_label_shorthand_in_call_arg() { 789 assert_hover!( 790 " 791fn wibble(arg1 arg1: Int, arg2 arg2: Bool) { Nil } 792 793fn main() { 794 let arg1 = 1 795 let arg2 = True 796 wibble(arg2:, arg1:) 797} 798", 799 find_position_of("arg2:").nth_occurrence(2) 800 ); 801} 802 803#[test] 804fn hover_label_shorthand_in_pattern_call_arg() { 805 assert_hover!( 806 " 807pub type Wibble { Wibble(arg1: Int, arg2: Bool) } 808 809pub fn main() { 810 case todo { 811 Wibble(arg2:, ..) -> todo 812 } 813} 814", 815 find_position_of("arg2:") 816 .nth_occurrence(2) 817 .under_last_char() 818 ); 819} 820 821#[test] 822fn hover_label_shorthand_in_pattern_call_arg_2() { 823 assert_hover!( 824 " 825pub type Wibble { Wibble(arg1: Int, arg2: Bool) } 826 827pub fn main() { 828 let Wibble(arg2:, ..) = todo 829} 830", 831 find_position_of("arg2:").nth_occurrence(2).under_char('r') 832 ); 833} 834 835#[test] 836fn hover_contextual_type() { 837 let code = " 838import wibble/wobble 839const value = wobble.Wobble 840"; 841 842 assert_hover!( 843 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 844 find_position_of("value").under_char('v') 845 ); 846} 847 848#[test] 849fn hover_contextual_type_aliased_module() { 850 let code = " 851import wibble/wobble as wubble 852const value = wubble.Wobble 853"; 854 855 assert_hover!( 856 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 857 find_position_of("value").under_char('v') 858 ); 859} 860 861#[test] 862fn hover_contextual_type_unqualified() { 863 let code = " 864import wibble/wobble.{type Wibble} 865const value = wobble.Wobble 866"; 867 868 assert_hover!( 869 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 870 find_position_of("value").under_char('v') 871 ); 872} 873 874#[test] 875fn hover_contextual_type_unqualified_aliased() { 876 let code = " 877import wibble/wobble.{type Wibble as Wobble} 878const value = wobble.Wobble 879"; 880 881 assert_hover!( 882 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 883 find_position_of("value").under_char('v') 884 ); 885} 886 887#[test] 888fn hover_contextual_type_aliased() { 889 let code = " 890import wibble/wobble 891type Local = wobble.Wibble 892const value = wobble.Wobble 893"; 894 895 assert_hover!( 896 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 897 find_position_of("value").under_char('v') 898 ); 899} 900 901#[test] 902fn hover_contextual_type_function() { 903 let code = " 904import wibble/wobble 905type MyInt = Int 906fn func(value: wobble.Wibble) -> MyInt { 1 } 907"; 908 909 assert_hover!( 910 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 911 find_position_of("func").under_char('f') 912 ); 913} 914 915#[test] 916fn hover_contextual_type_unqualified_import() { 917 let code = " 918import wibble/wobble.{type Wibble as Wobble, Wobble} 919"; 920 921 assert_hover!( 922 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wobble }"), 923 find_position_of("Wobble}").under_char('W') 924 ); 925} 926 927#[test] 928fn hover_contextual_type_pattern() { 929 let code = " 930import wibble/wobble.{Wibble, Wobble, Wubble} 931 932pub fn cycle(wibble: wobble.Wibble) { 933 case wibble { 934 Wibble -> Wobble 935 Wobble -> Wubble 936 Wubble -> Wibble 937 } 938} 939"; 940 941 assert_hover!( 942 TestProject::for_source(code) 943 .add_hex_module("wibble/wobble", "pub type Wibble { Wibble Wobble Wubble }"), 944 find_position_of("Wubble ->").under_char('u') 945 ); 946} 947 948#[test] 949fn hover_contextual_type_pattern_spread() { 950 let code = " 951import wibble/wobble.{type Wibble as Wobble} 952 953type Thing { 954 Thing(id: Int, value: Wobble) 955} 956 957pub fn main(thing: Thing) { 958 case thing { 959 Thing(id: 0, ..) -> 12 960 _ -> 14 961 } 962} 963"; 964 965 assert_hover!( 966 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 967 find_position_of("..").under_char('.') 968 ); 969} 970 971#[test] 972fn hover_contextual_type_expression() { 973 let code = " 974import wibble/wobble 975 976pub fn main() { 977 let wibble = wobble.Wibble 978} 979"; 980 981 assert_hover!( 982 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 983 find_position_of(".Wibble").under_char('l') 984 ); 985} 986 987#[test] 988fn hover_contextual_type_arg() { 989 let code = " 990import wibble/wobble 991 992fn do_things(wibble: wobble.Wibble) { wibble } 993"; 994 995 assert_hover!( 996 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 997 find_position_of("wibble:").under_char('w') 998 ); 999} 1000 1001#[test] 1002fn hover_print_type_variable_names() { 1003 let code = " 1004fn main(value: Result(ok, error)) { 1005 let v = value 1006 v 1007} 1008"; 1009 1010 assert_hover!( 1011 TestProject::for_source(code), 1012 find_position_of("let v").under_char('v') 1013 ); 1014} 1015 1016#[test] 1017fn hover_print_unbound_type_variable_names() { 1018 let code = " 1019fn make_ok(value: some_type) { 1020 let result = Ok(value) 1021 result 1022} 1023"; 1024 1025 assert_hover!( 1026 TestProject::for_source(code), 1027 find_position_of("result =").under_char('s') 1028 ); 1029} 1030 1031#[test] 1032fn hover_print_unbound_type_variable_name_without_conflicts() { 1033 let code = " 1034fn make_ok(value: a) { 1035 let result = Ok(value) 1036 result 1037} 1038"; 1039 1040 assert_hover!( 1041 TestProject::for_source(code), 1042 find_position_of("result =").under_char('s') 1043 ); 1044} 1045 1046#[test] 1047fn hover_print_imported_alias() { 1048 let code = " 1049import aliases.{type Aliased} 1050const thing: Aliased = 10 1051"; 1052 1053 assert_hover!( 1054 TestProject::for_source(code).add_hex_module("aliases", "pub type Aliased = Int"), 1055 find_position_of("thing").under_char('g') 1056 ); 1057} 1058 1059#[test] 1060fn hover_prelude_type() { 1061 let code = " 1062const number = 100 1063"; 1064 1065 assert_hover!( 1066 TestProject::for_source(code), 1067 find_position_of("number").under_char('b') 1068 ); 1069} 1070 1071#[test] 1072fn hover_shadowed_prelude_type() { 1073 let code = " 1074type Int { Int } 1075const number = 100 1076"; 1077 1078 assert_hover!( 1079 TestProject::for_source(code), 1080 find_position_of("number").under_char('b') 1081 ); 1082} 1083 1084#[test] 1085fn hover_shadowed_prelude_type_imported() { 1086 let code = " 1087import numbers.{type Int} 1088const number = 100 1089"; 1090 1091 assert_hover!( 1092 TestProject::for_source(code).add_hex_module("numbers", "pub type Int"), 1093 find_position_of("number =").under_char('b') 1094 ); 1095} 1096 1097#[test] 1098fn hover_contextual_type_annotation() { 1099 let code = " 1100import wibble/wobble 1101 1102fn make_wibble() -> wobble.Wibble { wobble.Wibble } 1103"; 1104 1105 assert_hover!( 1106 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 1107 find_position_of("-> wobble.Wibble").under_char('i') 1108 ); 1109} 1110 1111#[test] 1112fn hover_contextual_type_annotation_prelude() { 1113 let code = " 1114fn add_one(a: Int) -> Int { 1115 a + 1 1116} 1117"; 1118 1119 assert_hover!( 1120 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 1121 find_position_of("-> Int").under_char('I') 1122 ); 1123} 1124 1125#[test] 1126fn hover_contextual_type_annotation_unqualified() { 1127 let code = " 1128import wibble/wobble.{type Wibble} 1129 1130fn main(wibble: Wibble) { 1131 wibble 1132} 1133"; 1134 1135 assert_hover!( 1136 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 1137 find_position_of(": Wibble").under_char('W') 1138 ); 1139} 1140 1141#[test] 1142fn hover_contextual_type_annotation_unqualified_aliased() { 1143 let code = " 1144import wibble/wobble.{type Wibble as Wubble} 1145 1146fn main(wibble: Wubble) { 1147 wibble 1148} 1149"; 1150 1151 assert_hover!( 1152 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 1153 find_position_of(": Wubble").under_char('W') 1154 ); 1155} 1156 1157#[test] 1158fn hover_contextual_type_annotation_aliased_module() { 1159 let code = " 1160import wibble/wobble as wubble 1161 1162fn main(wibble: wubble.Wibble) { 1163 wibble 1164} 1165"; 1166 1167 assert_hover!( 1168 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 1169 find_position_of(": wubble.Wibble").under_char('W') 1170 ); 1171} 1172 1173#[test] 1174fn hover_contextual_type_annotation_aliased() { 1175 let code = " 1176import wibble/wobble 1177 1178type Wubble = wobble.Wibble 1179 1180fn main(wibble: Wubble) { 1181 wibble 1182} 1183"; 1184 1185 assert_hover!( 1186 TestProject::for_source(code).add_hex_module("wibble/wobble", "pub type Wibble { Wibble }"), 1187 find_position_of(": Wubble").under_char('e') 1188 ); 1189} 1190 1191#[test] 1192fn hover_print_underlying_for_alias_with_parameters() { 1193 let code = " 1194type LocalResult = Result(String, Int) 1195 1196fn do_thing() -> LocalResult { 1197 Error(1) 1198} 1199"; 1200 1201 assert_hover!( 1202 TestProject::for_source(code), 1203 find_position_of("do_thing").under_char('d') 1204 ); 1205} 1206 1207#[test] 1208fn hover_print_alias_when_parameters_match() { 1209 let code = " 1210type MyResult(a, b) = Result(a, b) 1211 1212fn do_thing() -> MyResult(Int, Int) { 1213 Error(1) 1214} 1215"; 1216 1217 assert_hover!( 1218 TestProject::for_source(code), 1219 find_position_of("do_thing").under_char('d') 1220 ); 1221} 1222 1223#[test] 1224fn hover_print_underlying_for_imported_alias() { 1225 let code = " 1226import alias.{type A} 1227 1228fn wibble() -> Result(Int, String) { 1229 todo 1230} 1231"; 1232 1233 assert_hover!( 1234 TestProject::for_source(code).add_hex_module("alias", "pub type A = Result(Int, String)"), 1235 find_position_of("wibble").under_char('l') 1236 ); 1237} 1238 1239#[test] 1240fn hover_print_aliased_imported_generic_type() { 1241 let code = " 1242import gleam/option.{type Option as Maybe} 1243 1244const none: Maybe(Int) = option.None 1245"; 1246 1247 assert_hover!( 1248 TestProject::for_source(code) 1249 .add_hex_module("gleam/option", "pub type Option(a) { None Some(a) }"), 1250 find_position_of("none").under_char('e') 1251 ); 1252} 1253 1254#[test] 1255fn hover_print_qualified_prelude_type_when_shadowed_by_alias() { 1256 let code = " 1257type Result = #(Bool, String) 1258const ok = Ok(10) 1259"; 1260 1261 assert_hover!( 1262 TestProject::for_source(code), 1263 find_position_of("ok").under_char('k') 1264 ); 1265} 1266 1267#[test] 1268fn hover_print_qualified_prelude_type_when_shadowed_by_imported_alias() { 1269 let code = " 1270import alias.{type Bool} 1271const value = True 1272"; 1273 1274 assert_hover!( 1275 TestProject::for_source(code).add_hex_module("alias", "pub type Bool = #(Int, Int)"), 1276 find_position_of("value").under_char('v') 1277 ); 1278} 1279 1280// https://github.com/gleam-lang/gleam/issues/3761 1281#[test] 1282fn hover_over_block_in_list_spread() { 1283 let code = " 1284pub fn main() { 1285 [1, 2, ..{ 1286 let x = 1 1287 [x] 1288 }] 1289} 1290"; 1291 1292 assert_hover!(TestProject::for_source(code), find_position_of("x")); 1293} 1294 1295// https://github.com/gleam-lang/gleam/issues/3758 1296#[test] 1297fn hover_for_anonymous_function_annotation() { 1298 let code = " 1299/// An example type. 1300pub type Wibble 1301 1302pub fn main() { 1303 fn(w: Wibble) { todo } 1304} 1305"; 1306 1307 assert_hover!( 1308 TestProject::for_source(code), 1309 find_position_of("w: Wibble").under_char('b') 1310 ); 1311} 1312 1313#[test] 1314fn hover_for_label_in_pattern() { 1315 let code = " 1316type Wibble { 1317 Wibble(wibble: Int, wobble: Int) 1318} 1319 1320pub fn main() { 1321 let Wibble(wibble: _, wobble: _) = todo 1322 todo 1323} 1324"; 1325 1326 assert_hover!( 1327 TestProject::for_source(code), 1328 find_position_of("wibble: _").under_char('l') 1329 ); 1330} 1331 1332#[test] 1333fn hover_for_label_in_expression() { 1334 let code = " 1335fn add(wibble a, wobble b) { 1336 a + b 1337} 1338 1339pub fn main() { 1340 add(wibble: 1, wobble: 2) 1341} 1342"; 1343 1344 assert_hover!( 1345 TestProject::for_source(code), 1346 find_position_of("wibble:").under_char('i') 1347 ); 1348} 1349 1350#[test] 1351fn hover_for_pattern_in_use() { 1352 let code = " 1353type Wibble { 1354 Wibble(Int, Float) 1355} 1356 1357pub fn main() { 1358 use Wibble(int, float) <- todo 1359 todo 1360} 1361"; 1362 1363 assert_hover!( 1364 TestProject::for_source(code), 1365 find_position_of("int").under_char('i') 1366 ); 1367} 1368 1369#[test] 1370fn hover_for_annotation_in_use() { 1371 let code = " 1372pub fn main() { 1373 use something: Int <- todo 1374 todo 1375} 1376"; 1377 1378 assert_hover!( 1379 TestProject::for_source(code), 1380 find_position_of("Int").under_char('n') 1381 ); 1382} 1383 1384#[test] 1385fn hover_on_pipe_with_invalid_step() { 1386 assert_hover!( 1387 " 1388pub fn main() { 1389 [1, 2, 3] 1390 |> map(wibble) 1391 |> filter(fn(value) { value }) 1392} 1393 1394fn map(list: List(a), fun: fn(a) -> b) -> List(b) {} 1395fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {} 1396", 1397 find_position_of("[") 1398 ); 1399} 1400 1401#[test] 1402fn hover_on_pipe_with_invalid_step_1() { 1403 assert_hover!( 1404 " 1405pub fn main() { 1406 [1, 2, 3] 1407 |> map(wibble) 1408 |> filter(fn(value) { value }) 1409} 1410 1411fn map(list: List(a), fun: fn(a) -> b) -> List(b) {} 1412fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {} 1413", 1414 find_position_of("1") 1415 ); 1416} 1417 1418#[test] 1419fn hover_on_pipe_with_invalid_step_2() { 1420 assert_hover!( 1421 " 1422pub fn main() { 1423 [1, 2, 3] 1424 |> map(wibble) 1425 |> filter(fn(value) { value }) 1426} 1427 1428fn map(list: List(a), fun: fn(a) -> b) -> List(b) {} 1429fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {} 1430", 1431 find_position_of("map") 1432 ); 1433} 1434 1435#[test] 1436fn hover_on_pipe_with_invalid_step_3() { 1437 assert_hover!( 1438 " 1439pub fn main() { 1440 [1, 2, 3] 1441 |> map(wibble) 1442 |> filter(fn(value) { value }) 1443} 1444 1445fn map(list: List(a), fun: fn(a) -> b) -> List(b) {} 1446fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {} 1447", 1448 find_position_of("wibble") 1449 ); 1450} 1451 1452#[test] 1453fn hover_on_pipe_with_invalid_step_4() { 1454 assert_hover!( 1455 " 1456pub fn main() { 1457 [1, 2, 3] 1458 |> map(wibble) 1459 |> filter(fn(value) { value }) 1460} 1461 1462fn map(list: List(a), fun: fn(a) -> b) -> List(b) {} 1463fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) {} 1464", 1465 find_position_of("filter") 1466 ); 1467} 1468 1469#[test] 1470fn hover_on_pipe_with_invalid_step_5() { 1471 assert_hover!( 1472 " 1473pub fn main() { 1474 [1, 2, 3] 1475 |> map(wibble) 1476 |> filter(fn(value) { value }) 1477} 1478 1479fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo } 1480fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo } 1481", 1482 find_position_of("fn(value)") 1483 ); 1484} 1485 1486#[test] 1487fn hover_on_pipe_with_invalid_step_6() { 1488 assert_hover!( 1489 " 1490pub fn main() { 1491 [1, 2, 3] 1492 |> wibble 1493 |> filter(fn(value) { value }) 1494} 1495 1496fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo } 1497", 1498 find_position_of("wibble") 1499 ); 1500} 1501 1502#[test] 1503fn hover_on_pipe_with_invalid_step_8() { 1504 assert_hover!( 1505 " 1506pub fn main() { 1507 [1, 2, 3] 1508 |> wibble 1509 |> filter(fn(value) { value }) 1510} 1511 1512fn filter(list: List(a), fun: fn(a) -> Bool) -> List(a) { todo } 1513", 1514 find_position_of("fn(value)") 1515 ); 1516} 1517 1518#[test] 1519fn hover_over_module_name() { 1520 let src = " 1521import wibble 1522 1523pub fn main() { 1524 wibble.wibble() 1525} 1526"; 1527 assert_hover!( 1528 TestProject::for_source(src).add_hex_module( 1529 "wibble", 1530 " 1531//// This is the wibble module. 1532//// Here is some documentation about it. 1533//// This module does stuff 1534 1535pub fn wibble() { 1536 todo 1537} 1538" 1539 ), 1540 find_position_of("wibble.") 1541 ); 1542} 1543 1544#[test] 1545fn hover_over_module_with_path() { 1546 let src = " 1547import wibble/wobble 1548 1549pub fn main() { 1550 wobble.wibble() 1551} 1552"; 1553 assert_hover!( 1554 TestProject::for_source(src).add_hex_module( 1555 "wibble/wobble", 1556 " 1557//// The module documentation 1558 1559pub fn wibble() { 1560 todo 1561} 1562" 1563 ), 1564 find_position_of("wobble.") 1565 ); 1566} 1567 1568#[test] 1569fn hover_over_module_name_in_annotation() { 1570 let src = " 1571import wibble 1572 1573pub fn main(w: wibble.Wibble) { 1574 todo 1575} 1576"; 1577 assert_hover!( 1578 TestProject::for_source(src).add_hex_module( 1579 "wibble", 1580 " 1581//// This is the wibble module. 1582//// Here is some documentation about it. 1583//// This module does stuff 1584 1585pub type Wibble 1586" 1587 ), 1588 find_position_of("wibble.") 1589 ); 1590} 1591 1592#[test] 1593fn hover_over_imported_module() { 1594 let src = " 1595import wibble 1596"; 1597 assert_hover!( 1598 TestProject::for_source(src).add_hex_module( 1599 "wibble", 1600 " 1601//// This is the wibble module. 1602//// Here is some documentation about it. 1603//// This module does stuff 1604" 1605 ), 1606 find_position_of("wibble") 1607 ); 1608} 1609 1610#[test] 1611fn no_hexdocs_link_when_hovering_over_local_module() { 1612 let src = " 1613import wibble 1614"; 1615 assert_hover!( 1616 TestProject::for_source(src).add_module( 1617 "wibble", 1618 " 1619//// This is the wibble module. 1620//// Here is some documentation about it. 1621//// This module does stuff 1622" 1623 ), 1624 find_position_of("wibble") 1625 ); 1626} 1627 1628#[test] 1629fn hover_for_constant_int() { 1630 assert_hover!( 1631 " 1632const ten = 10 1633", 1634 find_position_of("10") 1635 ); 1636} 1637 1638#[test] 1639fn hover_for_constant_float() { 1640 assert_hover!( 1641 " 1642const pi = 3.14 1643", 1644 find_position_of("3.14") 1645 ); 1646} 1647#[test] 1648fn hover_for_constant_string() { 1649 assert_hover!( 1650 r#" 1651const message = "Hello!" 1652"#, 1653 find_position_of("!") 1654 ); 1655} 1656 1657#[test] 1658fn hover_for_constant_other_constant() { 1659 assert_hover!( 1660 " 1661const constant1 = 10 1662const constant2 = constant1 1663", 1664 find_position_of("= constant1").under_char('s') 1665 ); 1666} 1667 1668#[test] 1669fn hover_for_constant_record() { 1670 assert_hover!( 1671 " 1672type Wibble { 1673 Wibble(Int) 1674} 1675 1676const w = Wibble(10) 1677", 1678 find_position_of("Wibble(10)").under_char('i') 1679 ); 1680} 1681 1682#[test] 1683fn hover_for_constant_tuple() { 1684 assert_hover!( 1685 " 1686const tuple = #(1, 3.5, False) 1687", 1688 find_position_of("#(") 1689 ); 1690} 1691 1692#[test] 1693fn hover_for_constant_tuple_element() { 1694 assert_hover!( 1695 " 1696const tuple = #(1, 3.5, False) 1697", 1698 find_position_of("False") 1699 ); 1700} 1701 1702#[test] 1703fn hover_for_constant_list() { 1704 assert_hover!( 1705 " 1706const numbers = [2, 4, 6, 8] 1707", 1708 find_position_of("[") 1709 ); 1710} 1711 1712#[test] 1713fn hover_for_constant_list_element() { 1714 assert_hover!( 1715 " 1716const numbers = [2, 4, 6, 8] 1717", 1718 find_position_of("4") 1719 ); 1720} 1721 1722#[test] 1723fn hover_for_constant_string_concatenation() { 1724 assert_hover!( 1725 r#" 1726const name = "Bob" 1727const message = "Hello " <> name 1728"#, 1729 find_position_of("<>") 1730 ); 1731} 1732 1733#[test] 1734fn hover_for_constant_string_concatenation_side() { 1735 assert_hover!( 1736 r#" 1737const name = "Bob" 1738const message = "Hello " <> name 1739"#, 1740 find_position_of("<> name").under_char('n') 1741 ); 1742} 1743 1744#[test] 1745fn hover_for_constant_bit_array() { 1746 assert_hover!( 1747 " 1748const bits = <<1:2, 3:4>> 1749", 1750 find_position_of(",") 1751 ); 1752} 1753 1754#[test] 1755fn hover_for_constant_bit_array_segment() { 1756 assert_hover!( 1757 " 1758const bits = <<1:2, 3:4>> 1759", 1760 find_position_of("1") 1761 ); 1762} 1763 1764#[test] 1765fn hover_for_constant_bit_array_segment_option() { 1766 assert_hover!( 1767 " 1768const bits = <<1:size(2), 3:4>> 1769", 1770 find_position_of("2") 1771 ); 1772} 1773 1774#[test] 1775fn hover_for_nested_constant() { 1776 assert_hover!( 1777 " 1778type Wibble { 1779 Wibble 1780 Wobble(BitArray) 1781} 1782 1783const value = #(1, 2, [Wibble, Wobble(<<1, 2, 3>>), Wibble]) 1784", 1785 find_position_of("3") 1786 ); 1787} 1788 1789#[test] 1790fn record_field_documentation() { 1791 assert_hover!( 1792 " 1793pub type Wibble { 1794 Wibble( 1795 /// This is some documentation about the wibble field. 1796 wibble: Int 1797 ) 1798} 1799 1800pub fn wibble(w: Wibble) { 1801 w.wibble 1802} 1803", 1804 find_position_of("w.wibble").under_char('l') 1805 ); 1806} 1807 1808#[test] 1809fn no_documentation_for_shared_record_field() { 1810 assert_hover!( 1811 " 1812pub type Wibble { 1813 Wibble( 1814 /// This is some documentation about the wibble field. 1815 wibble: Int 1816 ) 1817 Wobble( 1818 /// Here's some documentation explaining a field of Wobble 1819 wibble: Int 1820 ) 1821} 1822 1823pub fn wibble(w: Wibble) { 1824 w.wibble 1825} 1826", 1827 find_position_of("w.wibble").under_char('l') 1828 ); 1829} 1830 1831#[test] 1832fn documentation_for_shared_record_field_when_variant_is_known() { 1833 assert_hover!( 1834 " 1835pub type Wibble { 1836 Wibble( 1837 /// This is some documentation about the wibble field. 1838 wibble: Int 1839 ) 1840 Wobble( 1841 /// This won't show up because it's a Wibble variant 1842 wibble: Int 1843 ) 1844} 1845 1846pub fn wibble(w: Wibble) { 1847 let assert Wibble(..) = w 1848 w.wibble 1849} 1850", 1851 find_position_of("w.wibble").under_char('l') 1852 ); 1853} 1854 1855#[test] 1856fn hover_for_string_prefix_pattern() { 1857 assert_hover!( 1858 " 1859pub fn main() { 1860 case \"wibble\" { 1861 \"wib\" as alias <> suffix -> alias <> suffix 1862 other -> other 1863 } 1864} 1865", 1866 find_position_of("<>") 1867 ); 1868} 1869 1870#[test] 1871fn hover_for_string_prefix_pattern_prefix_alias() { 1872 assert_hover!( 1873 " 1874pub fn main() { 1875 case \"wibble\" { 1876 \"wib\" as alias <> suffix -> alias <> suffix 1877 other -> other 1878 } 1879} 1880", 1881 find_position_of("alias").nth_occurrence(1) 1882 ); 1883} 1884 1885#[test] 1886fn hover_for_string_prefix_pattern_suffix_variable() { 1887 assert_hover!( 1888 " 1889pub fn main() { 1890 case \"wibble\" { 1891 \"wib\" as alias <> suffix -> alias <> suffix 1892 other -> other 1893 } 1894} 1895", 1896 find_position_of("suffix").nth_occurrence(1) 1897 ); 1898} 1899 1900#[test] 1901fn hover_for_string_prefix_pattern_prefix_alias_alternative_definition() { 1902 assert_hover!( 1903 " 1904pub fn main() { 1905 case \"wibble\" { 1906 \"wib\" as prefix <> rest | \"wob\" as prefix <> rest -> prefix <> rest 1907 other -> other 1908 } 1909} 1910", 1911 find_position_of("prefix").nth_occurrence(2) 1912 ); 1913} 1914 1915#[test] 1916fn hover_for_string_prefix_pattern_suffix_variable_alternative_definition() { 1917 assert_hover!( 1918 " 1919pub fn main() { 1920 case \"wibble\" { 1921 \"wib\" <> rest | \"wob\" <> rest -> rest 1922 other -> other 1923 } 1924} 1925", 1926 find_position_of("rest").nth_occurrence(2) 1927 ); 1928} 1929 1930#[test] 1931fn hover_for_string_prefix_pattern_suffix_variable_discard() { 1932 assert_hover!( 1933 " 1934pub fn main() { 1935 case \"wibble\" { 1936 \"wib\" <> _discard -> Nil 1937 other -> Nil 1938 } 1939} 1940", 1941 find_position_of("_discard") 1942 ); 1943} 1944 1945#[test] 1946fn hover_for_custom_type() { 1947 assert_hover!( 1948 "/// Exciting documentation 1949/// Maybe even multiple lines 1950type Wibble { 1951 /// Some more exciting documentation 1952 Wibble(String) 1953 /// The most exciting documentation 1954 Wobble(arg: Int) 1955}", 1956 find_position_of("Wibble") 1957 ); 1958} 1959 1960#[test] 1961fn hover_type_constructor_with_no_fields() { 1962 assert_hover!( 1963 " 1964/// Exciting documentation 1965/// Maybe even multiple lines 1966type Wibble { 1967 /// Some more exciting documentation 1968 Wibble 1969} 1970", 1971 find_position_of("Wibble").nth_occurrence(2) 1972 ); 1973} 1974 1975#[test] 1976fn hover_type_constructor_with_label() { 1977 assert_hover!( 1978 " 1979/// Exciting documentation 1980/// Maybe even multiple lines 1981type Wibble { 1982 /// Some more exciting documentation 1983 Wibble(arg: String) 1984 /// The most exciting documentation 1985 Wobble(Int) 1986} 1987", 1988 find_position_of("Wibble").nth_occurrence(2) 1989 ); 1990} 1991 1992#[test] 1993fn hover_type_constructor_with_no_label() { 1994 assert_hover!( 1995 " 1996/// Exciting documentation 1997/// Maybe even multiple lines 1998type Wibble { 1999 /// Some more exciting documentation 2000 Wibble(arg: String) 2001 /// The most exciting documentation 2002 Wobble(Int) 2003} 2004", 2005 find_position_of("Wobble") 2006 ); 2007} 2008 2009#[test] 2010fn hover_for_local_variable_from_guard() { 2011 assert_hover!( 2012 " 2013pub fn main() { 2014 let wibble = True 2015 let wobble = False 2016 case wibble { 2017 True if wobble -> !wibble 2018 False if !wobble -> wibble 2019 _ -> wobble 2020 } 2021} 2022", 2023 find_position_of("wobble").nth_occurrence(2).under_char('o') 2024 ); 2025} 2026 2027#[test] 2028fn hover_for_record_from_guard() { 2029 assert_hover!( 2030 " 2031type Wibble { 2032 Wibble 2033 Wobble 2034} 2035 2036pub fn main() { 2037 let wibble = True 2038 let wobble = Wibble 2039 case wibble { 2040 True if wobble == Wibble -> !wibble 2041 False if wobble == Wobble -> wibble 2042 _ -> Wibble 2043 } 2044} 2045", 2046 find_position_of("== Wibble").under_char('l') 2047 ); 2048} 2049 2050#[test] 2051fn hover_for_module_select_from_guard() { 2052 let src = " 2053import mod 2054 2055pub fn main() { 2056 let wibble = True 2057 case wibble { 2058 True if mod.wibble < 5 -> !wibble 2059 False if mod.wibble != 10 -> wibble 2060 _ -> mod.wibble + 1 2061 } 2062} 2063"; 2064 assert_hover!( 2065 TestProject::for_source(src).add_module("mod", "pub const wibble = 10"), 2066 find_position_of("mod.wibble").under_char('w') 2067 ); 2068} 2069 2070#[test] 2071fn hover_for_record_module_select_from_guard() { 2072 let src = " 2073import mod 2074 2075pub fn main() { 2076 let wibble = True 2077 let wobble = mod.Wibble 2078 case wibble { 2079 True if wobble == mod.Wobble -> !wibble 2080 False if wobble == mod.Wibble -> wibble 2081 _ -> mod.Wibble 2082 } 2083} 2084"; 2085 assert_hover!( 2086 TestProject::for_source(src).add_module("mod", "pub type Wobble { Wibble Wobble }"), 2087 find_position_of("== mod.Wibble").under_char('i') 2088 ); 2089} 2090 2091#[test] 2092fn hover_for_module_select_pattern() { 2093 let src = " 2094import mod 2095pub fn go(x: mod.Wibble) { 2096 case x { 2097 mod.Wibble -> 1 2098 } 2099} 2100"; 2101 assert_hover!( 2102 TestProject::for_source(src).add_module("mod", "pub type Wibble { Wibble }"), 2103 find_position_of("mod.Wibble") 2104 .under_char('W') 2105 .nth_occurrence(2) 2106 ); 2107} 2108 2109#[test] 2110fn hover_on_record_dot_of_record_update_shows_ignored_fields() { 2111 assert_hover!( 2112 " 2113type Wibble { 2114 Wibble(a: Int, b: Bool) 2115} 2116 2117pub fn go(wibble: Wibble) { 2118 Wibble(..wibble, a: 1) 2119} 2120", 2121 find_position_of("..") 2122 ); 2123} 2124 2125#[test] 2126fn hover_on_record_being_updated_shows_ignored_fields() { 2127 assert_hover!( 2128 " 2129type Wibble { 2130 Wibble(a: Int, b: Bool) 2131} 2132 2133pub fn go(wibble: Wibble) { 2134 Wibble(..wibble, a: 1) 2135} 2136", 2137 find_position_of("..wibble").under_last_char() 2138 ); 2139} 2140 2141#[test] 2142fn hover_for_invalid_record_update_1() { 2143 assert_hover!( 2144 " 2145type Wibble { 2146 Wibble(a: Int, b: Bool) 2147} 2148 2149pub fn go(wibble: Wibble) { 2150 Wibble(..wibble, a: True, b: 1) 2151} 2152", 2153 find_position_of("True") 2154 ); 2155} 2156 2157#[test] 2158fn hover_for_invalid_record_update_2() { 2159 assert_hover!( 2160 " 2161type Wibble { 2162 Wibble(a: Int, b: Bool) 2163} 2164 2165pub fn go(wibble: Wibble) { 2166 Wibble(..wibble, a: True, b: 1) 2167} 2168", 2169 find_position_of("1") 2170 ); 2171} 2172 2173#[test] 2174fn hover_for_invalid_record_update_3() { 2175 assert_hover!( 2176 " 2177type Wibble { 2178 Wibble(a: Int, b: Bool) 2179} 2180 2181pub fn go(wibble: Wibble) { 2182 Wibble(..wibble, a: True, b: 1) 2183} 2184", 2185 find_position_of("Wibble").nth_occurrence(4) 2186 ); 2187} 2188 2189#[test] 2190fn hover_on_constant_todo() { 2191 assert_hover!( 2192 " 2193const wibble = todo 2194", 2195 find_position_of("wibble") 2196 ); 2197} 2198 2199#[test] 2200fn hover_on_constant_todo_1() { 2201 assert_hover!( 2202 " 2203const wibble = todo 2204", 2205 find_position_of("todo") 2206 ); 2207} 2208 2209#[test] 2210fn hover_on_constant_todo_in_list() { 2211 assert_hover!( 2212 " 2213const wibble = [todo, 1] 2214", 2215 find_position_of("wibble") 2216 ); 2217} 2218 2219#[test] 2220fn hover_on_constant_todo_in_list_2() { 2221 assert_hover!( 2222 " 2223const wibble = [todo, 1] 2224", 2225 find_position_of("todo") 2226 ); 2227} 2228 2229#[test] 2230fn hover_on_constant_todo_in_bit_array() { 2231 assert_hover!( 2232 " 2233const wibble = <<todo:utf8>> 2234", 2235 find_position_of("todo") 2236 ); 2237} 2238 2239#[test] 2240fn hover_on_constant_todo_in_bit_array_2() { 2241 assert_hover!( 2242 " 2243const wibble = <<todo>> 2244", 2245 find_position_of("todo") 2246 ); 2247} 2248 2249#[test] 2250fn hover_on_constant_todo_in_constructor() { 2251 assert_hover!( 2252 " 2253const wibble = Ok(todo) 2254", 2255 find_position_of("wibble") 2256 ); 2257} 2258 2259#[test] 2260fn hover_on_constant_todo_in_annotated_constructor() { 2261 assert_hover!( 2262 " 2263const wibble: Result(String, Int) = Ok(todo) 2264", 2265 find_position_of("todo") 2266 ); 2267} 2268 2269#[test] 2270fn hover_on_constant_todo_in_constructor_2() { 2271 assert_hover!( 2272 " 2273const wibble = Ok(todo) 2274", 2275 find_position_of("todo") 2276 ); 2277} 2278 2279#[test] 2280fn hover_on_constant_annotated_todo() { 2281 assert_hover!( 2282 " 2283const wibble: String = todo 2284", 2285 find_position_of("todo") 2286 ); 2287} 2288 2289#[test] 2290fn hover_on_constant_todo_message() { 2291 assert_hover!( 2292 r#" 2293const wibble = todo as "wobble" 2294"#, 2295 find_position_of("wobble") 2296 ); 2297} 2298 2299#[test] 2300fn hover_on_constant_todo_invalid_message_still_works() { 2301 assert_hover!( 2302 r#" 2303const wobble = 1 2304const wibble = todo as [wobble] 2305"#, 2306 find_position_of("wobble").nth_occurrence(2) 2307 ); 2308}