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