diff --git a/crates/ty_ide/src/docstring.rs b/crates/ty_ide/src/docstring.rs index e16cf09e32803..328081a0a3a42 100644 --- a/crates/ty_ide/src/docstring.rs +++ b/crates/ty_ide/src/docstring.rs @@ -835,13 +835,24 @@ fn extract_rest_style_params(docstring: &str) -> HashMap { #[cfg(test)] mod tests { + use insta::Settings; use insta::assert_snapshot; use super::*; + fn bind_docstring_snapshot_filters() -> impl Drop { + let mut settings = Settings::clone_current(); + // Markdown hard breaks are encoded as trailing spaces (`" \n"`), but many editors + // trim trailing whitespace in string literals. Replace them with `` in snapshots + // so tests are stable and the expected output stays readable. + settings.add_filter(" \n", "\n"); + settings.bind_to_scope() + } + // A nice doctest that is surrounded by prose #[test] fn dunder_escape() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Here _this_ and ___that__ should be escaped Here *this* and **that** should be untouched @@ -867,24 +878,24 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r" - Here \_this\_ and \_\_\_that\_\_ should be escaped - Here *this* and **that** should be untouched - Here `this` and ``that`` should be untouched - - Here `_this_` and ``__that__`` should be untouched - Here `_this_` ``__that__`` should be untouched - `_this_too_should_be_untouched_` - - Here `_this_```__that__`` should be untouched but this\_is\_escaped - Here ``_this_```__that__` should be untouched but this\_is\_escaped - - Here `_this_ and _that_ should be escaped (but isn't) - Here \_this\_ and \_that\_` should be escaped - `Here _this_ and _that_ should be escaped (but isn't) - Here \_this\_ and \_that\_ should be escaped` - - Here ```_is_``__a__`_balanced_``_mess_``` - Here ```_is_`````__a__``\_random\_````_mess__```` + Here \_this\_ and \_\_\_that\_\_ should be escaped + Here *this* and **that** should be untouched + Here `this` and ``that`` should be untouched + + Here `_this_` and ``__that__`` should be untouched + Here `_this_` ``__that__`` should be untouched + `_this_too_should_be_untouched_` + + Here `_this_```__that__`` should be untouched but this\_is\_escaped + Here ``_this_```__that__` should be untouched but this\_is\_escaped + + Here `_this_ and _that_ should be escaped (but isn't) + Here \_this\_ and \_that\_` should be escaped + `Here _this_ and _that_ should be escaped (but isn't) + Here \_this\_ and \_that\_ should be escaped` + + Here ```_is_``__a__`_balanced_``_mess_``` + Here ```_is_`````__a__``\_random\_````_mess__```` ```_is_`````__a__``\_random\_````_mess__```` "); } @@ -893,6 +904,7 @@ mod tests { // and should become `:` #[test] fn literal_colon() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Check out this great example code:: @@ -911,7 +923,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Check out this great example code: + Check out this great example code: ```````````python x_y = "hello" @@ -931,6 +943,7 @@ mod tests { // and should be erased #[test] fn literal_space() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Check out this great example code :: @@ -949,7 +962,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Check out this great example code + Check out this great example code ```````````python x_y = "hello" @@ -969,6 +982,7 @@ mod tests { // and the whole line should be deleted #[test] fn literal_own_line() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Check out this great example code :: @@ -988,8 +1002,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Check out this great example code -      + Check out this great example code +      ```````````python x_y = "hello" @@ -1009,6 +1023,7 @@ mod tests { // and I have no idea what Should happen but let's record what Does #[test] fn literal_squeezed() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Check out this great example code:: x_y = "hello" @@ -1025,7 +1040,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Check out this great example code: + Check out this great example code: ```````````python x_y = "hello" @@ -1044,6 +1059,7 @@ mod tests { // and we should tidy up #[test] fn literal_flush() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Check out this great example code:: @@ -1059,7 +1075,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Check out this great example code: + Check out this great example code: ```````````python x_y = "hello" @@ -1077,6 +1093,7 @@ mod tests { // still be shown as text and not ```code```. #[test] fn warning_block() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" The thing you need to understand is that computers are hard. @@ -1096,18 +1113,18 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - The thing you need to understand is that computers are hard. - - **Warning:** -     Now listen here buckaroo you might have seen me say computers are hard, -     and though "yeah I know computers are hard but NO you DON'T KNOW. - -     Listen: - -     - Computers -     - Are -     - Hard - + The thing you need to understand is that computers are hard. + + **Warning:** +     Now listen here buckaroo you might have seen me say computers are hard, +     and though "yeah I know computers are hard but NO you DON'T KNOW. + +     Listen: + +     - Computers +     - Are +     - Hard +     Ok!?!?!? "#); } @@ -1116,6 +1133,7 @@ mod tests { // still be shown as text and not ```code```. #[test] fn version_blocks() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Some much-updated docs @@ -1135,18 +1153,18 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - Some much-updated docs - - **Added in version 3.0:** -    Function added - - **Changed in version 4.0:** -    The `spam` argument was added - **Changed in version 4.1:** -    The `spam` argument is considered evil now. - -    You really shouldnt use it - + Some much-updated docs + + **Added in version 3.0:** +    Function added + + **Changed in version 4.0:** +    The `spam` argument was added + **Changed in version 4.1:** +    The `spam` argument is considered evil now. + +    You really shouldnt use it + And that's the docs "); } @@ -1155,6 +1173,7 @@ mod tests { // `..deprecated ::` #[test] fn deprecated_prefix_gunk() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" wow this is some changes .. deprecated:: 1.2.3 x = 2 @@ -1163,7 +1182,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - **wow this is some changes Deprecated since version 1.2.3:** + **wow this is some changes Deprecated since version 1.2.3:**     x = 2 "); } @@ -1171,6 +1190,7 @@ mod tests { // We should not parse the contents of a markdown codefence #[test] fn explicit_markdown_block_with_ps1_contents() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1185,8 +1205,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + ```python >>> thing.do_thing() wow it did the thing @@ -1199,6 +1219,7 @@ mod tests { // We should not parse the contents of a markdown codefence #[test] fn explicit_markdown_block_with_underscore_contents_tick() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1212,8 +1233,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + `````python x_y = thing_do(); ``` # this should't close the fence! @@ -1225,6 +1246,7 @@ mod tests { // `~~~` also starts a markdown codefence #[test] fn explicit_markdown_block_with_underscore_contents_tilde() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1238,8 +1260,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + ~~~~~python x_y = thing_do(); ~~~ # this should't close the fence! @@ -1253,6 +1275,7 @@ mod tests { // but it's nice if we handle it anyway because it makes visual sense). #[test] fn explicit_markdown_block_with_indent_tick() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func... @@ -1269,15 +1292,15 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func... - - Returns: -     Some details + My cool func... + + Returns: +     Some details `````python x_y = thing_do(); ``` # this should't close the fence! a_b = other_thing(); - ````` + `````     And so on. "); } @@ -1287,6 +1310,7 @@ mod tests { // but it's nice if we handle it anyway because it makes visual sense). #[test] fn explicit_markdown_block_with_indent_tilde() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func... @@ -1303,15 +1327,15 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func... - - Returns: -     Some details + My cool func... + + Returns: +     Some details ~~~~~~python x_y = thing_do(); ~~~ # this should't close the fence! a_b = other_thing(); - ~~~~~~ + ~~~~~~     And so on. "); } @@ -1319,6 +1343,7 @@ mod tests { // What do we do when we hit the end of the docstring with an unclosed markdown block? #[test] fn explicit_markdown_block_with_unclosed_fence_tick() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1329,8 +1354,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + ````python x_y = thing_do(); ```` @@ -1340,6 +1365,7 @@ mod tests { // What do we do when we hit the end of the docstring with an unclosed markdown block? #[test] fn explicit_markdown_block_with_unclosed_fence_tilde() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1350,8 +1376,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + ~~~~~python x_y = thing_do(); ~~~~~ @@ -1362,6 +1388,7 @@ mod tests { // It's fine to break this test, it's not particularly intentional behaviour. #[test] fn explicit_markdown_block_messy_corners_tick() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1373,8 +1400,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + ``````we still think this is a codefence``` x_y = thing_do(); ```````````` and are sloppy as heck with indentation and closing shrugggg @@ -1385,6 +1412,7 @@ mod tests { // It's fine to break this test, it's not particularly intentional behaviour. #[test] fn explicit_markdown_block_messy_corners_tilde() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" My cool func: @@ -1396,8 +1424,8 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - My cool func: - + My cool func: + ~~~~~~we still think this is a codefence~~~ x_y = thing_do(); ~~~~~~~~~~~~~ and are sloppy as heck with indentation and closing shrugggg @@ -1407,6 +1435,7 @@ mod tests { // `.. code::` is a literal block and the `.. code::` should be deleted #[test] fn code_block() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Here's some code! @@ -1419,9 +1448,9 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Here's some code! - - + Here's some code! + + ```````````python def main() { print("hello world!") @@ -1433,6 +1462,7 @@ mod tests { // `.. code:: rust` is a literal block with rust syntax highlighting #[test] fn code_block_lang() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Here's some Rust code! @@ -1445,9 +1475,9 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Here's some Rust code! - - + Here's some Rust code! + + ```````````rust fn main() { println!("hello world!"); @@ -1459,6 +1489,7 @@ mod tests { // I don't know if this is valid syntax but we preserve stuff before `..code ::` #[test] fn code_block_prefix_gunk() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" wow this is some code.. code:: abc x = 2 @@ -1467,7 +1498,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - wow this is some code + wow this is some code ```````````abc x = 2 ``````````` @@ -1477,6 +1508,7 @@ mod tests { // `.. asdgfhjkl-unknown::` is treated the same as `.. code::` #[test] fn unknown_block() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Here's some code! @@ -1489,9 +1521,9 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Here's some code! - - + Here's some code! + + ```````````python fn main() { println!("hello world!"); @@ -1503,6 +1535,7 @@ mod tests { // `.. asdgfhjkl-unknown:: rust` is treated the same as `.. code:: rust` #[test] fn unknown_block_lang() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" Here's some Rust code! @@ -1515,9 +1548,9 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @r#" - Here's some Rust code! - - + Here's some Rust code! + + ```````````rust fn main() { print("hello world!") @@ -1529,6 +1562,7 @@ mod tests { // A nice doctest that is surrounded by prose #[test] fn doctest_simple() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description @@ -1543,14 +1577,14 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - This is a function description - + This is a function description + ```````````python >>> thing.do_thing() wow it did the thing >>> thing.do_other_thing() it sure did the thing - ``````````` + ``````````` As you can see it did the thing! "); } @@ -1558,6 +1592,7 @@ mod tests { // A nice doctest that is surrounded by prose with an indent #[test] fn doctest_simple_indent() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description @@ -1572,14 +1607,14 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - This is a function description - + This is a function description + ```````````python >>> thing.do_thing() wow it did the thing >>> thing.do_other_thing() it sure did the thing - ``````````` + ``````````` As you can see it did the thing! "); } @@ -1587,6 +1622,7 @@ mod tests { // A doctest that has nothing around it #[test] fn doctest_flush() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#">>> thing.do_thing() wow it did the thing >>> thing.do_other_thing() @@ -1607,6 +1643,7 @@ mod tests { // A doctest embedded in a literal block (it's just a literal block) #[test] fn literal_doctest() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description:: @@ -1621,7 +1658,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - This is a function description: + This is a function description: ```````````python >>> thing.do_thing() wow it did the thing @@ -1635,6 +1672,7 @@ mod tests { #[test] fn doctest_indent_flush() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" And so you can see that >>> thing.do_thing() @@ -1645,7 +1683,7 @@ mod tests { let docstring = Docstring::new(docstring.to_owned()); assert_snapshot!(docstring.render_markdown(), @" - And so you can see that + And so you can see that ```````````python >>> thing.do_thing() wow it did the thing @@ -1657,6 +1695,7 @@ mod tests { #[test] fn test_google_style_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description. @@ -1695,21 +1734,22 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - Args: -     param1 (str): The first parameter description -     param2 (int): The second parameter description -         This is a continuation of param2 description. -     param3: A parameter without type annotation - - Returns: + This is a function description. + + Args: +     param1 (str): The first parameter description +     param2 (int): The second parameter description +         This is a continuation of param2 description. +     param3: A parameter without type annotation + + Returns:     str: The return value description "); } #[test] fn test_numpy_style_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description. @@ -1766,27 +1806,28 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - Parameters - ---------- - param1 : str -     The first parameter description - param2 : int -     The second parameter description -     This is a continuation of param2 description. - param3 -     A parameter without type annotation - - Returns - ------- - str + This is a function description. + + Parameters + ---------- + param1 : str +     The first parameter description + param2 : int +     The second parameter description +     This is a continuation of param2 description. + param3 +     A parameter without type annotation + + Returns + ------- + str     The return value description "); } #[test] fn test_pep257_style_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#"Insert an entry into the list of warnings filters (at the front). 'param1' -- The first parameter description @@ -1823,13 +1864,13 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @r" - Insert an entry into the list of warnings filters (at the front). - - 'param1' -- The first parameter description - 'param2' -- The second parameter description -             This is a continuation of param2 description. - 'param3' -- A parameter without type annotation - + Insert an entry into the list of warnings filters (at the front). + + 'param1' -- The first parameter description + 'param2' -- The second parameter description +             This is a continuation of param2 description. + 'param3' -- A parameter without type annotation + ```````````python >>> print repr(foo.__doc__) '\n This is the second line of the docstring.\n ' @@ -1843,6 +1884,7 @@ mod tests { #[test] fn test_no_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a simple function description without parameter documentation. "#; @@ -1858,6 +1900,7 @@ mod tests { #[test] fn test_mixed_style_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description. @@ -1902,21 +1945,22 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - Args: -     param1 (str): Google-style parameter -     param2 (int): Another Google-style parameter - - Parameters - ---------- - param3 : bool + This is a function description. + + Args: +     param1 (str): Google-style parameter +     param2 (int): Another Google-style parameter + + Parameters + ---------- + param3 : bool     NumPy-style parameter "); } #[test] fn test_rest_style_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description. @@ -1957,19 +2001,20 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - :param str param1: The first parameter description - :param int param2: The second parameter description -     This is a continuation of param2 description. - :param param3: A parameter without type annotation - :returns: The return value description + This is a function description. + + :param str param1: The first parameter description + :param int param2: The second parameter description +     This is a continuation of param2 description. + :param param3: A parameter without type annotation + :returns: The return value description :rtype: str "); } #[test] fn test_mixed_style_with_rest_parameter_documentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description. @@ -2022,23 +2067,24 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - Args: -     param1 (str): Google-style parameter - - :param int param2: reST-style parameter - :param param3: Another reST-style parameter - - Parameters - ---------- - param4 : bool + This is a function description. + + Args: +     param1 (str): Google-style parameter + + :param int param2: reST-style parameter + :param param3: Another reST-style parameter + + Parameters + ---------- + param4 : bool     NumPy-style parameter "); } #[test] fn test_numpy_style_with_different_indentation() { + let _snap = bind_docstring_snapshot_filters(); let docstring = r#" This is a function description. @@ -2095,27 +2141,28 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - Parameters - ---------- - param1 : str -     The first parameter description - param2 : int -     The second parameter description -     This is a continuation of param2 description. - param3 -     A parameter without type annotation - - Returns - ------- - str + This is a function description. + + Parameters + ---------- + param1 : str +     The first parameter description + param2 : int +     The second parameter description +     This is a continuation of param2 description. + param3 +     A parameter without type annotation + + Returns + ------- + str     The return value description "); } #[test] fn test_numpy_style_with_tabs_and_mixed_indentation() { + let _snap = bind_docstring_snapshot_filters(); // Using raw strings to avoid tab/space conversion issues in the test let docstring = " This is a function description. @@ -2163,22 +2210,23 @@ mod tests { "); assert_snapshot!(docstring.render_markdown(), @" - This is a function description. - - Parameters - ---------- - param1 : str -         The first parameter description - param2 : int -         The second parameter description -         This is a continuation of param2 description. - param3 + This is a function description. + + Parameters + ---------- + param1 : str +         The first parameter description + param2 : int +         The second parameter description +         This is a continuation of param2 description. + param3         A parameter without type annotation "); } #[test] fn test_universal_newlines() { + let _snap = bind_docstring_snapshot_filters(); // Test with Windows-style line endings (\r\n) let docstring_windows = "This is a function description.\r\n\r\nArgs:\r\n param1 (str): The first parameter\r\n param2 (int): The second parameter\r\n"; @@ -2223,10 +2271,10 @@ mod tests { "); assert_snapshot!(docstring_windows.render_markdown(), @" - This is a function description. - - Args: -     param1 (str): The first parameter + This is a function description. + + Args: +     param1 (str): The first parameter     param2 (int): The second parameter "); @@ -2239,10 +2287,10 @@ mod tests { "); assert_snapshot!(docstring_mac.render_markdown(), @" - This is a function description. - - Args: -     param1 (str): The first parameter + This is a function description. + + Args: +     param1 (str): The first parameter     param2 (int): The second parameter "); @@ -2255,10 +2303,10 @@ mod tests { "); assert_snapshot!(docstring_unix.render_markdown(), @" - This is a function description. - - Args: -     param1 (str): The first parameter + This is a function description. + + Args: +     param1 (str): The first parameter     param2 (int): The second parameter "); } @@ -2269,6 +2317,7 @@ mod tests { // See: https://github.com/astral-sh/ty/issues/2497 #[test] fn doctest_then_literal_block_with_blank_lines() { + let _snap = bind_docstring_snapshot_filters(); let docstring = Docstring::new( "\ Example: @@ -2292,13 +2341,13 @@ Done. // The blank line between foo() and bar() should be preserved inside the code block, // NOT cause the code block to end early with bar() rendered as regular text. assert_snapshot!(docstring.render_markdown(), @r#" - Example: - + Example: + ```````````python >>> print("hello") hello - ``````````` - Code example: + ``````````` + Code example: ```````````python def foo(): pass diff --git a/crates/ty_ide/src/hover.rs b/crates/ty_ide/src/hover.rs index 1485ed0bba7d4..814e1b756c7ef 100644 --- a/crates/ty_ide/src/hover.rs +++ b/crates/ty_ide/src/hover.rs @@ -232,7 +232,7 @@ impl fmt::Display for DisplayHoverContent<'_, '_> { #[cfg(test)] mod tests { - use crate::tests::{CursorTest, cursor_test}; + use crate::tests::CursorTest; use crate::{MarkupKind, hover}; use std::fmt::Write as _; @@ -243,9 +243,18 @@ mod tests { }; use ruff_text_size::{Ranged, TextRange}; + fn hover_test(source: &str) -> CursorTest { + // Hover snapshots include markdown-rendered docstrings. Normalize markdown hard breaks + // so snapshot literals remain stable even if an editor trims trailing whitespace. + CursorTest::builder() + .snapshot_filter(" \n", "\n") + .source("main.py", source) + .build() + } + #[test] fn hover_basic() { - let test = cursor_test( + let test = hover_test( r#" a = 10 """This is the docs for this value @@ -269,8 +278,8 @@ mod tests { Literal[10] ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -288,7 +297,7 @@ mod tests { #[test] fn hover_function() { - let test = cursor_test( + let test = hover_test( r#" def my_func(a, b): '''This is such a great func!! @@ -323,10 +332,10 @@ mod tests { ) -> Unknown ``` --- - This is such a great func!! - - Args: -     a: first for a reason + This is such a great func!! + + Args: +     a: first for a reason     b: coming for `a`'s title --------------------------------------------- info[hover]: Hovered content is @@ -345,7 +354,7 @@ mod tests { #[test] fn hover_function_def() { - let test = cursor_test( + let test = hover_test( r#" def my_func(a, b): '''This is such a great func!! @@ -378,10 +387,10 @@ mod tests { ) -> Unknown ``` --- - This is such a great func!! - - Args: -     a: first for a reason + This is such a great func!! + + Args: +     a: first for a reason     b: coming for `a`'s title --------------------------------------------- info[hover]: Hovered content is @@ -399,7 +408,7 @@ mod tests { #[test] fn hover_class() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: ''' @@ -441,10 +450,10 @@ mod tests { ``` --- - This is such a great class!! - -     Don't you know? - + This is such a great class!! + +     Don't you know? + Everyone loves my class!! --------------------------------------------- info[hover]: Hovered content is @@ -463,7 +472,7 @@ mod tests { #[test] fn hover_class_def() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: ''' @@ -503,10 +512,10 @@ mod tests { ``` --- - This is such a great class!! - -     Don't you know? - + This is such a great class!! + +     Don't you know? + Everyone loves my class!! --------------------------------------------- info[hover]: Hovered content is @@ -525,7 +534,7 @@ mod tests { #[test] fn hover_class_init() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: ''' @@ -637,7 +646,7 @@ mod tests { #[test] fn hover_class_init_no_init_docs() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: ''' @@ -678,10 +687,10 @@ mod tests { class MyClass(val) ``` --- - This is such a great class!! - -     Don't you know? - + This is such a great class!! + +     Don't you know? + Everyone loves my class!! --------------------------------------------- info[hover]: Hovered content is @@ -700,7 +709,7 @@ mod tests { #[test] fn hover_class_typed_init() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: def __init__(self, a: int, b: str): @@ -740,7 +749,7 @@ mod tests { #[test] fn hover_dataclass_class_init() { - let test = cursor_test( + let test = hover_test( r#" from dataclasses import dataclass @@ -790,7 +799,7 @@ mod tests { #[test] fn hover_class_no_init() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: pass @@ -822,7 +831,7 @@ mod tests { #[test] fn hover_class_with_new() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: def __new__(cls, a: int, b: str) -> "MyClass": @@ -862,7 +871,7 @@ mod tests { #[test] fn hover_class_init_overload_no_match() { - let test = cursor_test( + let test = hover_test( r#" from typing import overload @@ -912,7 +921,7 @@ mod tests { #[test] fn hover_class_init_overload_match() { - let test = cursor_test( + let test = hover_test( r#" from typing import overload @@ -960,7 +969,7 @@ mod tests { #[test] fn hover_class_init_and_new_invalid() { - let test = cursor_test( + let test = hover_test( r#" class S: def __init__(self, a: int): @@ -1012,7 +1021,7 @@ mod tests { #[test] fn hover_class_init_and_new_valid() { - let test = cursor_test( + let test = hover_test( r#" class S: def __init__(self, a: int): @@ -1056,7 +1065,7 @@ mod tests { #[test] fn hover_class_init_with_callable_param() { - let test = cursor_test( + let test = hover_test( r#" from typing import Callable @@ -1093,7 +1102,7 @@ mod tests { // https://github.com/astral-sh/ruff/pull/24257#issuecomment-4164472728 #[test] fn hover_enum_constructor() { - let test = cursor_test( + let test = hover_test( r#" from enum import Enum @@ -1144,29 +1153,29 @@ mod tests { ) ``` --- - Either returns an existing member, or creates a new enum class. - - This method is used both when an enum class is given a value to match - to an enumeration member (i.e. Color(3)) and for the functional API - (i.e. Color = Enum('Color', names='RED GREEN BLUE')). - - The value lookup branch is chosen if the enum is final. - - When used for the functional API: - - `value` will be the name of the new class. - - `names` should be either a string of white-space/comma delimited names - (values will start at `start`), or an iterator/mapping of name, value pairs. - - `module` should be set to the module this class is being created in; - if it is not set, an attempt to find that module will be made, but if - it fails the class will not be picklable. - - `qualname` should be set to the actual location this class can be found - at in its module; by default it is set to the global scope. If this is - not correct, unpickling will fail in some circumstances. - + Either returns an existing member, or creates a new enum class. + + This method is used both when an enum class is given a value to match + to an enumeration member (i.e. Color(3)) and for the functional API + (i.e. Color = Enum('Color', names='RED GREEN BLUE')). + + The value lookup branch is chosen if the enum is final. + + When used for the functional API: + + `value` will be the name of the new class. + + `names` should be either a string of white-space/comma delimited names + (values will start at `start`), or an iterator/mapping of name, value pairs. + + `module` should be set to the module this class is being created in; + if it is not set, an attempt to find that module will be made, but if + it fails the class will not be picklable. + + `qualname` should be set to the actual location this class can be found + at in its module; by default it is set to the global scope. If this is + not correct, unpickling will fail in some circumstances. + `type`, if set, will be mixed in as the first base class. --------------------------------------------- info[hover]: Hovered content is @@ -1187,7 +1196,7 @@ mod tests { // https://github.com/astral-sh/ruff/pull/24257#issuecomment-4164472728 #[test] fn hover_typeddict_constructor() { - let test = cursor_test( + let test = hover_test( r#" from typing import TypedDict @@ -1222,7 +1231,7 @@ mod tests { #[test] fn hover_class_method() { - let test = cursor_test( + let test = hover_test( r#" class MyClass: ''' @@ -1271,10 +1280,10 @@ mod tests { ) -> Unknown ``` --- - This is such a great func!! - - Args: -     a: first for a reason + This is such a great func!! + + Args: +     a: first for a reason     b: coming for `a`'s title --------------------------------------------- info[hover]: Hovered content is @@ -1292,7 +1301,7 @@ mod tests { #[test] fn hover_member() { - let test = cursor_test( + let test = hover_test( r#" class Foo: a: int = 10 @@ -1332,7 +1341,7 @@ mod tests { #[test] fn hover_function_typed_variable() { - let test = cursor_test( + let test = hover_test( r#" def foo(a, b): ... @@ -1368,7 +1377,7 @@ mod tests { #[test] fn hover_binary_expression() { - let test = cursor_test( + let test = hover_test( r#" def foo(a: int, b: int, c: int): a + b == c @@ -1397,7 +1406,7 @@ mod tests { #[test] fn hover_keyword_parameter() { - let test = cursor_test( + let test = hover_test( r#" def test(ab: int): """my cool test @@ -1435,7 +1444,7 @@ mod tests { #[test] fn hover_keyword_parameter_def() { - let test = cursor_test( + let test = hover_test( r#" def test(ab: int): """my cool test @@ -1469,7 +1478,7 @@ mod tests { #[test] fn hover_union() { - let test = cursor_test( + let test = hover_test( r#" def foo(a, b): @@ -1511,7 +1520,7 @@ mod tests { #[test] fn hover_string_annotation1() { - let test = cursor_test( + let test = hover_test( r#" a: "MyClass" = 1 @@ -1548,7 +1557,7 @@ mod tests { #[test] fn hover_string_annotation2() { - let test = cursor_test( + let test = hover_test( r#" a: "None | MyClass" = 1 @@ -1585,7 +1594,7 @@ mod tests { #[test] fn hover_string_annotation3() { - let test = cursor_test( + let test = hover_test( r#" a: "None | MyClass" = 1 @@ -1599,7 +1608,7 @@ mod tests { #[test] fn hover_string_annotation4() { - let test = cursor_test( + let test = hover_test( r#" a: "None | MyClass" = 1 @@ -1635,7 +1644,7 @@ mod tests { #[test] fn hover_string_annotation5() { - let test = cursor_test( + let test = hover_test( r#" a: "None | MyClass" = 1 @@ -1649,7 +1658,7 @@ mod tests { #[test] fn hover_string_annotation_dangling1() { - let test = cursor_test( + let test = hover_test( r#" a: "MyClass |" = 1 @@ -1663,7 +1672,7 @@ mod tests { #[test] fn hover_string_annotation_dangling2() { - let test = cursor_test( + let test = hover_test( r#" a: "MyClass | No" = 1 @@ -1700,7 +1709,7 @@ mod tests { #[test] fn hover_string_annotation_dangling3() { - let test = cursor_test( + let test = hover_test( r#" a: "MyClass | No" = 1 @@ -1732,7 +1741,7 @@ mod tests { #[test] fn hover_string_annotation_recursive() { - let test = cursor_test( + let test = hover_test( r#" ab: "ab" "#, @@ -1759,7 +1768,7 @@ mod tests { #[test] fn hover_string_annotation_unknown() { - let test = cursor_test( + let test = hover_test( r#" x: "foobar" "#, @@ -1786,7 +1795,7 @@ mod tests { #[test] fn goto_type_string_annotation_nested1() { - let test = cursor_test( + let test = hover_test( r#" x: "list['MyClass | int'] | None" @@ -1823,7 +1832,7 @@ mod tests { #[test] fn goto_type_string_annotation_nested2() { - let test = cursor_test( + let test = hover_test( r#" x: "list['int | MyClass'] | None" @@ -1860,7 +1869,7 @@ mod tests { #[test] fn goto_type_string_annotation_nested3() { - let test = cursor_test( + let test = hover_test( r#" x: "list['int | None'] | MyClass" @@ -1897,7 +1906,7 @@ mod tests { #[test] fn goto_type_string_annotation_nested4() { - let test = cursor_test( + let test = hover_test( r#" x: "list['int' | 'MyClass'] | None" @@ -1934,7 +1943,7 @@ mod tests { #[test] fn goto_type_string_annotation_nested5() { - let test = cursor_test( + let test = hover_test( r#" x: "list['MyClass' | 'str'] | None" @@ -1971,7 +1980,7 @@ mod tests { #[test] fn goto_type_string_annotation_too_nested1() { - let test = cursor_test( + let test = hover_test( r#" x: """'list["MyClass" | "str"]' | None""" @@ -2003,7 +2012,7 @@ mod tests { #[test] fn goto_type_string_annotation_too_nested2() { - let test = cursor_test( + let test = hover_test( r#" x: """'list["int" | "str"]' | MyClass""" @@ -2430,7 +2439,7 @@ def ab(a: int, *, c: int): #[test] fn hover_overload_ambiguous() { - let test = cursor_test( + let test = hover_test( r#" from typing import overload @@ -2494,7 +2503,7 @@ def ab(a: int, *, c: int): #[test] fn hover_overload_ambiguous_compact() { - let test = cursor_test( + let test = hover_test( r#" from typing import overload @@ -2546,7 +2555,7 @@ def ab(a: int, *, c: int): #[test] fn hover_module() { - let mut test = cursor_test( + let mut test = hover_test( r#" import lib @@ -2579,8 +2588,8 @@ def ab(a: int, *, c: int): ``` --- - The cool lib/_py module! - + The cool lib/_py module! + Wow this module rocks. --------------------------------------------- info[hover]: Hovered content is @@ -2599,7 +2608,7 @@ def ab(a: int, *, c: int): #[test] fn hover_nonlocal_binding() { - let test = cursor_test( + let test = hover_test( r#" def outer(): x = "outer_value" @@ -2638,7 +2647,7 @@ def outer(): #[test] fn hover_nonlocal_stmt() { - let test = cursor_test( + let test = hover_test( r#" def outer(): xy = "outer_value" @@ -2658,7 +2667,7 @@ def outer(): #[test] fn hover_global_binding() { - let test = cursor_test( + let test = hover_test( r#" global_var = "global_value" @@ -2693,7 +2702,7 @@ def function(): #[test] fn hover_global_stmt() { - let test = cursor_test( + let test = hover_test( r#" global_var = "global_value" @@ -2710,7 +2719,7 @@ def function(): #[test] fn hover_match_name_stmt() { - let test = cursor_test( + let test = hover_test( r#" def my_func(command: str): match command.split(): @@ -2724,7 +2733,7 @@ def function(): #[test] fn hover_match_name_binding() { - let test = cursor_test( + let test = hover_test( r#" def my_func(command: str): match command.split(): @@ -2756,7 +2765,7 @@ def function(): #[test] fn hover_match_rest_stmt() { - let test = cursor_test( + let test = hover_test( r#" def my_func(command: str): match command.split(): @@ -2770,7 +2779,7 @@ def function(): #[test] fn hover_match_rest_binding() { - let test = cursor_test( + let test = hover_test( r#" def my_func(command: str): match command.split(): @@ -2802,7 +2811,7 @@ def function(): #[test] fn hover_match_as_stmt() { - let test = cursor_test( + let test = hover_test( r#" def my_func(command: str): match command.split(): @@ -2816,7 +2825,7 @@ def function(): #[test] fn hover_match_as_binding() { - let test = cursor_test( + let test = hover_test( r#" def my_func(command: str): match command.split(): @@ -2848,7 +2857,7 @@ def function(): #[test] fn hover_match_keyword_stmt() { - let test = cursor_test( + let test = hover_test( r#" class Click: __match_args__ = ("position", "button") @@ -2868,7 +2877,7 @@ def function(): #[test] fn hover_match_keyword_binding() { - let test = cursor_test( + let test = hover_test( r#" class Click: __match_args__ = ("position", "button") @@ -2906,7 +2915,7 @@ def function(): #[test] fn hover_match_class_name() { - let test = cursor_test( + let test = hover_test( r#" class Click: __match_args__ = ("position", "button") @@ -2945,7 +2954,7 @@ def function(): #[test] fn hover_match_class_field_name() { - let test = cursor_test( + let test = hover_test( r#" class Click: __match_args__ = ("position", "button") @@ -2965,7 +2974,7 @@ def function(): #[test] fn hover_typevar_name_stmt() { - let test = cursor_test( + let test = hover_test( r#" type Alias1[AB: int = bool] = tuple[AB, list[AB]] "#, @@ -2992,7 +3001,7 @@ def function(): #[test] fn hover_typevar_name_binding() { - let test = cursor_test( + let test = hover_test( r#" type Alias1[AB: int = bool] = tuple[AB, list[AB]] "#, @@ -3019,7 +3028,7 @@ def function(): #[test] fn hover_typevar_spec_stmt() { - let test = cursor_test( + let test = hover_test( r#" from typing import Callable type Alias2[**AB = [int, str]] = Callable[AB, tuple[AB]] @@ -3031,7 +3040,7 @@ def function(): #[test] fn hover_typevar_spec_binding() { - let test = cursor_test( + let test = hover_test( r#" from typing import Callable type Alias2[**AB = [int, str]] = Callable[AB, tuple[AB]] @@ -3062,7 +3071,7 @@ def function(): #[test] fn hover_typevar_tuple_stmt() { - let test = cursor_test( + let test = hover_test( r#" type Alias3[*AB = ()] = tuple[tuple[*AB], tuple[*AB]] "#, @@ -3073,7 +3082,7 @@ def function(): #[test] fn hover_typevar_tuple_binding() { - let test = cursor_test( + let test = hover_test( r#" type Alias3[*AB = ()] = tuple[tuple[*AB], tuple[*AB]] "#, @@ -3100,7 +3109,7 @@ def function(): #[test] fn hover_module_import() { - let mut test = cursor_test( + let mut test = hover_test( r#" import lib @@ -3133,8 +3142,8 @@ def function(): ``` --- - The cool lib/_py module! - + The cool lib/_py module! + Wow this module rocks. --------------------------------------------- info[hover]: Hovered content is @@ -3153,7 +3162,7 @@ def function(): #[test] fn hover_type_of_expression_with_type_var_type() { - let test = cursor_test( + let test = hover_test( r#" type Alias[T: int = bool] = list[T] "#, @@ -3179,7 +3188,7 @@ def function(): #[test] fn hover_type_of_expression_with_type_param_spec() { - let test = cursor_test( + let test = hover_test( r#" type Alias[**P = [int, str]] = Callable[P, int] "#, @@ -3206,7 +3215,7 @@ def function(): #[test] fn hover_type_of_expression_with_type_var_tuple() { - let test = cursor_test( + let test = hover_test( r#" type Alias[*Ts = ()] = tuple[*Ts] "#, @@ -3232,7 +3241,7 @@ def function(): #[test] fn hover_variable_assignment() { - let test = cursor_test( + let test = hover_test( r#" value = 1 """This is the docs for this value @@ -3254,8 +3263,8 @@ def function(): Literal[1] ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3272,7 +3281,7 @@ def function(): #[test] fn hover_augmented_assignment() { - let test = cursor_test( + let test = hover_test( r#" value = 1 """This is the docs for this value @@ -3303,8 +3312,8 @@ def function(): Literal[1] ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3323,7 +3332,7 @@ def function(): #[test] fn hover_attribute_assignment() { - let test = cursor_test( + let test = hover_test( r#" class C: attr: int = 1 @@ -3352,8 +3361,8 @@ def function(): Literal[2] ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3372,7 +3381,7 @@ def function(): #[test] fn hover_augmented_attribute_assignment() { - let test = cursor_test( + let test = hover_test( r#" class C: attr = 1 @@ -3403,8 +3412,8 @@ def function(): Unknown | Literal[1] ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3423,7 +3432,7 @@ def function(): #[test] fn hover_annotated_assignment() { - let test = cursor_test( + let test = hover_test( r#" class Foo: a: int @@ -3446,8 +3455,8 @@ def function(): int ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3465,7 +3474,7 @@ def function(): #[test] fn hover_annotated_assignment_with_rhs() { - let test = cursor_test( + let test = hover_test( r#" class Foo: a: int = 1 @@ -3488,8 +3497,8 @@ def function(): Literal[1] ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3507,7 +3516,7 @@ def function(): #[test] fn hover_annotated_assignment_with_rhs_use() { - let test = cursor_test( + let test = hover_test( r#" class Foo: a: int = 1 @@ -3533,8 +3542,8 @@ def function(): int ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3551,7 +3560,7 @@ def function(): #[test] fn hover_annotated_attribute_assignment() { - let test = cursor_test( + let test = hover_test( r#" class Foo: def __init__(self, a: int): @@ -3575,8 +3584,8 @@ def function(): int ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3595,7 +3604,7 @@ def function(): #[test] fn hover_annotated_attribute_assignment_use() { - let test = cursor_test( + let test = hover_test( r#" class Foo: def __init__(self, a: int): @@ -3622,8 +3631,8 @@ def function(): int ``` --- - This is the docs for this value - + This is the docs for this value + Wow these are good docs! --------------------------------------------- info[hover]: Hovered content is @@ -3640,7 +3649,7 @@ def function(): #[test] fn hover_bare_final_attribute_assignment() { - let test = cursor_test( + let test = hover_test( r#" from typing import Final @@ -3672,7 +3681,7 @@ def function(): #[test] fn hover_final_variable() { - let test = cursor_test( + let test = hover_test( r#" from typing import Final @@ -3702,7 +3711,7 @@ def function(): #[test] fn hover_final_variable_use() { - let test = cursor_test( + let test = hover_test( r#" from typing import Final @@ -3732,7 +3741,7 @@ def function(): #[test] fn hover_classvar_attribute() { - let test = cursor_test( + let test = hover_test( r#" from typing import ClassVar @@ -3765,7 +3774,7 @@ def function(): #[test] fn hover_final_global_use() { - let test = cursor_test( + let test = hover_test( r#" from typing import Final @@ -3799,7 +3808,7 @@ def function(): #[test] fn hover_type_narrowing() { - let test = cursor_test( + let test = hover_test( r#" def foo(a: str | None, b): ''' @@ -3835,7 +3844,7 @@ def function(): #[test] fn hover_whitespace() { - let test = cursor_test( + let test = hover_test( r#" class C: @@ -3848,7 +3857,7 @@ def function(): #[test] fn hover_literal_int() { - let test = cursor_test( + let test = hover_test( r#" print( 0 + 1 @@ -3861,7 +3870,7 @@ def function(): #[test] fn hover_literal_ellipsis() { - let test = cursor_test( + let test = hover_test( r#" print( ... @@ -3874,7 +3883,7 @@ def function(): #[test] fn hover_subscript_literal_index() { - let test = cursor_test( + let test = hover_test( r#" values: list[str] = ["a", "b"] print(values[0]) @@ -3944,7 +3953,7 @@ def function(): let mut output = String::new(); for (index, case) in cases.iter().enumerate() { - let test = cursor_test(case); + let test = hover_test(case); let hover = test.hover(); write!(output, "case {index}:\n{hover}\n\n").unwrap(); } @@ -3953,7 +3962,7 @@ def function(): #[test] fn hover_subscript_non_literal_index() { - let test = cursor_test( + let test = hover_test( r#" values: list[str] = ["a", "b"] def get_index() -> int: ... @@ -3996,7 +4005,7 @@ def function(): let mut output = String::new(); for (index, case) in list_cases.iter().enumerate() { - let test = cursor_test(case); + let test = hover_test(case); let hover = test.hover(); write!(output, "list case {index}:\n{hover}\n\n").unwrap(); } @@ -4022,7 +4031,7 @@ def function(): let mut output = String::new(); for (index, case) in string_cases.iter().enumerate() { - let test = cursor_test(case); + let test = hover_test(case); let hover = test.hover(); write!(output, "string case {index}:\n{hover}\n\n").unwrap(); } @@ -4031,7 +4040,7 @@ def function(): #[test] fn hover_typed_dict_key_literal() { - let test = cursor_test( + let test = hover_test( r#" from typing import TypedDict @@ -4073,7 +4082,7 @@ def function(): #[test] fn hover_complex_type1() { - let test = cursor_test( + let test = hover_test( r#" from typing import Callable, Any, List def ab(x: int, y: Callable[[int, int], Any], z: List[int]) -> int: ... @@ -4113,7 +4122,7 @@ def function(): #[test] fn hover_complex_type2() { - let test = cursor_test( + let test = hover_test( r#" from typing import Callable, Tuple, Any ab: Tuple[Any, int, Callable[[int, int], Any]] = ... @@ -4145,7 +4154,7 @@ def function(): #[test] fn hover_complex_type3() { - let test = cursor_test( + let test = hover_test( r#" from typing import Callable, Any ab: Callable[[int, int], Any] | None = ... @@ -4177,7 +4186,7 @@ def function(): #[test] fn hover_docstring() { - let test = cursor_test( + let test = hover_test( r#" def f(): """Lorem ipsum dolor sit amet.""" @@ -4189,7 +4198,7 @@ def function(): #[test] fn hover_func_with_concat_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): """wow cool docs""" """and docs""" @@ -4225,7 +4234,7 @@ def function(): #[test] fn hover_func_with_plus_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): """wow cool docs""" + """and docs""" @@ -4256,7 +4265,7 @@ def function(): #[test] fn hover_func_with_slash_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): """wow cool docs""" \ @@ -4293,7 +4302,7 @@ def function(): #[test] fn hover_func_with_sameline_commented_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): """wow cool docs""" # and a comment @@ -4330,7 +4339,7 @@ def function(): #[test] fn hover_func_with_nextline_commented_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): """wow cool docs""" @@ -4368,7 +4377,7 @@ def function(): #[test] fn hover_func_with_parens_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): ( @@ -4407,7 +4416,7 @@ def function(): #[test] fn hover_func_with_nextline_commented_parens_docstring() { - let test = cursor_test( + let test = hover_test( r#" def ab(): ( @@ -4447,7 +4456,7 @@ def function(): #[test] fn hover_attribute_docstring_spill() { - let test = cursor_test( + let test = hover_test( r#" if True: ab = 1 @@ -4478,7 +4487,7 @@ def function(): #[test] fn hover_class_typevar_variance() { - let test = cursor_test( + let test = hover_test( r#" class Covariant[T]: def get(self) -> T: @@ -4505,7 +4514,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" class Covariant[T]: def get(self) -> T: @@ -4532,7 +4541,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" class Contravariant[T]: def set(self, x: T): @@ -4559,7 +4568,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" class Contravariant[T]: def set(self, x: T): @@ -4589,7 +4598,7 @@ def function(): #[test] fn hover_function_typevar_variance() { - let test = cursor_test( + let test = hover_test( r#" def covariant[T]() -> T: raise ValueError @@ -4614,7 +4623,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" def covariant[T]() -> T: raise ValueError @@ -4639,7 +4648,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" def contravariant[T](x: T): pass @@ -4664,7 +4673,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" def contravariant[T](x: T): pass @@ -4692,7 +4701,7 @@ def function(): #[test] fn hover_type_alias_typevar_variance() { - let test = cursor_test( + let test = hover_test( r#" type List[T] = list[T] "#, @@ -4715,7 +4724,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" type List[T] = list[T] "#, @@ -4738,7 +4747,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" type Tuple[T] = tuple[T] "#, @@ -4761,7 +4770,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" type Tuple[T] = tuple[T] "#, @@ -4787,7 +4796,7 @@ def function(): #[test] fn hover_legacy_typevar_variance() { - let test = cursor_test( + let test = hover_test( r#" from typing import TypeVar @@ -4819,7 +4828,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" from typing import TypeVar @@ -4850,7 +4859,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" from typing import TypeVar @@ -4882,7 +4891,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" from typing import TypeVar @@ -4916,7 +4925,7 @@ def function(): #[test] fn hover_binary_operator_literal() { - let test = cursor_test( + let test = hover_test( r#" result = 5 + 3 "#, @@ -4948,7 +4957,7 @@ def function(): #[test] fn hover_binary_operator_overload() { - let test = cursor_test( + let test = hover_test( r#" from __future__ import annotations from typing import overload @@ -4994,7 +5003,7 @@ def function(): #[test] fn hover_binary_operator_union() { - let test = cursor_test( + let test = hover_test( r#" from __future__ import annotations @@ -5032,7 +5041,7 @@ def function(): #[test] fn hover_float_annotation() { - let test = cursor_test( + let test = hover_test( r#" a: float = 3.14 "#, @@ -5063,7 +5072,7 @@ def function(): #[test] fn hover_comprehension_type_context() { - let test = cursor_test( + let test = hover_test( r#" a = [[n] for n in [1, 2, 3]] "#, @@ -5086,7 +5095,7 @@ def function(): | "###); - let test = cursor_test( + let test = hover_test( r#" a: list[list[int | str]] = [[n] for n in [1, 2, 3]] "#, @@ -5112,7 +5121,7 @@ def function(): #[test] fn hover_multi_inference() { - let test = cursor_test( + let test = hover_test( r#" def list1[T](x: T) -> list[T]: return [x] @@ -5140,7 +5149,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" def f(x: int, y: int) -> list[int] | list[str]: return [x + y] @@ -5165,7 +5174,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" def list1[T](x: T) -> list[T]: return [x] @@ -5193,7 +5202,7 @@ def function(): | "); - let test = cursor_test( + let test = hover_test( r#" def f(x: int, y: int) -> list[int] | list[str]: return (_ := [x + y]) @@ -5557,7 +5566,7 @@ def function(): #[test] fn hover_dunder_file() { - let test = cursor_test( + let test = hover_test( r#" __file__ "#, @@ -5586,7 +5595,7 @@ def function(): // Ref: https://github.com/astral-sh/ty/issues/2401 #[test] fn hover_incomplete_except_handler() { - let test = cursor_test( + let test = hover_test( "\ try: print() diff --git a/crates/ty_ide/src/lib.rs b/crates/ty_ide/src/lib.rs index 6250a020f88f0..41a92078ef4b2 100644 --- a/crates/ty_ide/src/lib.rs +++ b/crates/ty_ide/src/lib.rs @@ -453,6 +453,7 @@ mod tests { /// A list of source files, corresponding to the /// file's path and its contents. sources: Vec, + snapshot_filters: Vec<(String, String)>, } impl CursorTestBuilder { @@ -515,6 +516,9 @@ mod tests { insta_settings.add_filter(r#"\\(\w\w|\.|")"#, "/$1"); // Filter out TODO types because they are different between debug and release builds. insta_settings.add_filter(r"@Todo\(.+\)", "@Todo"); + for (pattern, replacement) in &self.snapshot_filters { + insta_settings.add_filter(pattern, replacement); + } let insta_settings_guard = insta_settings.bind_to_scope(); @@ -534,6 +538,16 @@ mod tests { self } + pub(super) fn snapshot_filter( + &mut self, + pattern: impl Into, + replacement: impl Into, + ) -> &mut CursorTestBuilder { + self.snapshot_filters + .push((pattern.into(), replacement.into())); + self + } + /// Convert to a builder that supports site-packages (third-party dependencies). pub(super) fn with_site_packages(self) -> SitePackagesCursorTestBuilder { SitePackagesCursorTestBuilder {