aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src/tests.rs')
-rw-r--r--crates/mbe/src/tests.rs296
1 files changed, 210 insertions, 86 deletions
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index bd2977ebd..5c641ebf2 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -6,7 +6,7 @@ use syntax::{
6 SyntaxKind::{ERROR, IDENT}, 6 SyntaxKind::{ERROR, IDENT},
7 SyntaxNode, WalkEvent, T, 7 SyntaxNode, WalkEvent, T,
8}; 8};
9use test_utils::assert_eq_text; 9use test_utils::{assert_eq_text, mark};
10 10
11use super::*; 11use super::*;
12 12
@@ -33,19 +33,18 @@ mod rule_parsing {
33 33
34 #[test] 34 #[test]
35 fn test_invalid_arms() { 35 fn test_invalid_arms() {
36 fn check(macro_body: &str, err: &str) { 36 fn check(macro_body: &str, err: ParseError) {
37 let m = parse_macro_arm(macro_body); 37 let m = parse_macro_arm(macro_body);
38 assert_eq!(m, Err(ParseError::Expected(String::from(err)))); 38 assert_eq!(m, Err(err.into()));
39 } 39 }
40 check("invalid", ParseError::Expected("expected subtree".into()));
40 41
41 check("invalid", "expected subtree"); 42 check("$i:ident => ()", ParseError::Expected("expected subtree".into()));
43 check("($i:ident) ()", ParseError::Expected("expected `=`".into()));
44 check("($($i:ident)_) => ()", ParseError::InvalidRepeat);
42 45
43 check("$i:ident => ()", "expected subtree"); 46 check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
44 check("($i:ident) ()", "expected `=`"); 47 check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
45 check("($($i:ident)_) => ()", "invalid repeat");
46
47 check("($i) => ($i)", "invalid macro definition");
48 check("($i:) => ($i)", "invalid macro definition");
49 } 48 }
50 49
51 fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> { 50 fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {
@@ -458,6 +457,17 @@ fn test_match_group_with_multichar_sep() {
458} 457}
459 458
460#[test] 459#[test]
460fn test_match_group_with_multichar_sep2() {
461 parse_macro(
462 r#"
463 macro_rules! foo {
464 (fn $name:ident {$($i:literal)&&*} ) => ( fn $name() -> bool { $($i)&&*} );
465 }"#,
466 )
467 .assert_expand_items("foo! (fn baz {true && true} );", "fn baz () -> bool {true &&true}");
468}
469
470#[test]
461fn test_match_group_zero_match() { 471fn test_match_group_zero_match() {
462 parse_macro( 472 parse_macro(
463 r#" 473 r#"
@@ -675,6 +685,36 @@ fn test_match_literal() {
675 .assert_expand_items("foo! ['('];", "fn foo () {}"); 685 .assert_expand_items("foo! ['('];", "fn foo () {}");
676} 686}
677 687
688#[test]
689fn test_parse_macro_def_simple() {
690 mark::check!(parse_macro_def_simple);
691
692 parse_macro2(
693 r#"
694macro foo($id:ident) {
695 fn $id() {}
696}
697"#,
698 )
699 .assert_expand_items("foo!(bar);", "fn bar () {}");
700}
701
702#[test]
703fn test_parse_macro_def_rules() {
704 mark::check!(parse_macro_def_rules);
705
706 parse_macro2(
707 r#"
708macro foo {
709 ($id:ident) => {
710 fn $id() {}
711 }
712}
713"#,
714 )
715 .assert_expand_items("foo!(bar);", "fn bar () {}");
716}
717
678// The following tests are port from intellij-rust directly 718// The following tests are port from intellij-rust directly
679// https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt 719// https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
680 720
@@ -941,6 +981,29 @@ fn test_meta_doc_comments() {
941} 981}
942 982
943#[test] 983#[test]
984fn test_meta_doc_comments_non_latin() {
985 parse_macro(
986 r#"
987 macro_rules! foo {
988 ($(#[$ i:meta])+) => (
989 $(#[$ i])+
990 fn bar() {}
991 )
992 }
993"#,
994 ).
995 assert_expand_items(
996 r#"foo! {
997 /// 錦瑟無端五十弦,一弦一柱思華年。
998 /**
999 莊生曉夢迷蝴蝶,望帝春心託杜鵑。
1000 */
1001 }"#,
1002 "# [doc = \" 錦瑟無端五十弦,一弦一柱思華年。\"] # [doc = \"\\\\n 莊生曉夢迷蝴蝶,望帝春心託杜鵑。\\\\n \"] fn bar () {}",
1003 );
1004}
1005
1006#[test]
944fn test_tt_block() { 1007fn test_tt_block() {
945 parse_macro( 1008 parse_macro(
946 r#" 1009 r#"
@@ -1215,6 +1278,18 @@ macro_rules! m {
1215 .is_some()); 1278 .is_some());
1216} 1279}
1217 1280
1281#[test]
1282fn test_match_is_not_greedy() {
1283 parse_macro(
1284 r#"
1285macro_rules! foo {
1286 ($($i:ident $(,)*),*) => {};
1287}
1288"#,
1289 )
1290 .assert_expand_items(r#"foo!(a,b);"#, r#""#);
1291}
1292
1218// The following tests are based on real world situations 1293// The following tests are based on real world situations
1219#[test] 1294#[test]
1220fn test_vec() { 1295fn test_vec() {
@@ -1699,95 +1774,122 @@ pub(crate) struct MacroFixture {
1699 rules: MacroRules, 1774 rules: MacroRules,
1700} 1775}
1701 1776
1702impl MacroFixture { 1777pub(crate) struct MacroFixture2 {
1703 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { 1778 rules: MacroDef,
1704 self.try_expand_tt(invocation).unwrap() 1779}
1705 }
1706
1707 fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> {
1708 let source_file = ast::SourceFile::parse(invocation).tree();
1709 let macro_invocation =
1710 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1711
1712 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap())
1713 .ok_or_else(|| ExpandError::ConversionError)?;
1714 1780
1715 self.rules.expand(&invocation_tt).result() 1781macro_rules! impl_fixture {
1716 } 1782 ($name:ident) => {
1783 impl $name {
1784 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
1785 self.try_expand_tt(invocation).unwrap()
1786 }
1717 1787
1718 fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { 1788 fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> {
1719 assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err)); 1789 let source_file = ast::SourceFile::parse(invocation).tree();
1720 } 1790 let macro_invocation =
1791 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1721 1792
1722 fn expand_items(&self, invocation: &str) -> SyntaxNode { 1793 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap())
1723 let expanded = self.expand_tt(invocation); 1794 .ok_or_else(|| ExpandError::ConversionError)?;
1724 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node()
1725 }
1726 1795
1727 fn expand_statements(&self, invocation: &str) -> SyntaxNode { 1796 self.rules.expand(&invocation_tt).result()
1728 let expanded = self.expand_tt(invocation); 1797 }
1729 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node()
1730 }
1731 1798
1732 fn expand_expr(&self, invocation: &str) -> SyntaxNode { 1799 #[allow(unused)]
1733 let expanded = self.expand_tt(invocation); 1800 fn assert_expand_err(&self, invocation: &str, err: &ExpandError) {
1734 token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node() 1801 assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err));
1735 } 1802 }
1736 1803
1737 fn assert_expand_tt(&self, invocation: &str, expected: &str) { 1804 #[allow(unused)]
1738 let expansion = self.expand_tt(invocation); 1805 fn expand_items(&self, invocation: &str) -> SyntaxNode {
1739 assert_eq!(expansion.to_string(), expected); 1806 let expanded = self.expand_tt(invocation);
1740 } 1807 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node()
1808 }
1741 1809
1742 fn assert_expand(&self, invocation: &str, expected: &str) { 1810 #[allow(unused)]
1743 let expansion = self.expand_tt(invocation); 1811 fn expand_statements(&self, invocation: &str) -> SyntaxNode {
1744 let actual = format!("{:?}", expansion); 1812 let expanded = self.expand_tt(invocation);
1745 test_utils::assert_eq_text!(&expected.trim(), &actual.trim()); 1813 token_tree_to_syntax_node(&expanded, FragmentKind::Statements)
1746 } 1814 .unwrap()
1815 .0
1816 .syntax_node()
1817 }
1747 1818
1748 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { 1819 #[allow(unused)]
1749 self.assert_expansion(FragmentKind::Items, invocation, expected); 1820 fn expand_expr(&self, invocation: &str) -> SyntaxNode {
1750 self 1821 let expanded = self.expand_tt(invocation);
1751 } 1822 token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node()
1823 }
1752 1824
1753 fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &MacroFixture { 1825 #[allow(unused)]
1754 self.assert_expansion(FragmentKind::Statements, invocation, expected); 1826 fn assert_expand_tt(&self, invocation: &str, expected: &str) {
1755 self 1827 let expansion = self.expand_tt(invocation);
1756 } 1828 assert_eq!(expansion.to_string(), expected);
1829 }
1757 1830
1758 fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) { 1831 #[allow(unused)]
1759 let expanded = self.expand_tt(invocation); 1832 fn assert_expand(&self, invocation: &str, expected: &str) {
1760 assert_eq!(expanded.to_string(), expected); 1833 let expansion = self.expand_tt(invocation);
1761 1834 let actual = format!("{:?}", expansion);
1762 let expected = expected.replace("$crate", "C_C__C"); 1835 test_utils::assert_eq_text!(&expected.trim(), &actual.trim());
1763 1836 }
1764 // wrap the given text to a macro call
1765 let expected = {
1766 let wrapped = format!("wrap_macro!( {} )", expected);
1767 let wrapped = ast::SourceFile::parse(&wrapped);
1768 let wrapped =
1769 wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1770 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1771 wrapped.delimiter = None;
1772 wrapped
1773 };
1774 1837
1775 let expanded_tree = token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node(); 1838 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &$name {
1776 let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string(); 1839 self.assert_expansion(FragmentKind::Items, invocation, expected);
1840 self
1841 }
1777 1842
1778 let expected_tree = token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node(); 1843 #[allow(unused)]
1779 let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string(); 1844 fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &$name {
1845 self.assert_expansion(FragmentKind::Statements, invocation, expected);
1846 self
1847 }
1780 1848
1781 let expected_tree = expected_tree.replace("C_C__C", "$crate"); 1849 fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) {
1782 assert_eq!( 1850 let expanded = self.expand_tt(invocation);
1783 expanded_tree, expected_tree, 1851 assert_eq!(expanded.to_string(), expected);
1784 "\nleft:\n{}\nright:\n{}", 1852
1785 expanded_tree, expected_tree, 1853 let expected = expected.replace("$crate", "C_C__C");
1786 ); 1854
1787 } 1855 // wrap the given text to a macro call
1856 let expected = {
1857 let wrapped = format!("wrap_macro!( {} )", expected);
1858 let wrapped = ast::SourceFile::parse(&wrapped);
1859 let wrapped = wrapped
1860 .tree()
1861 .syntax()
1862 .descendants()
1863 .find_map(ast::TokenTree::cast)
1864 .unwrap();
1865 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1866 wrapped.delimiter = None;
1867 wrapped
1868 };
1869
1870 let expanded_tree =
1871 token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node();
1872 let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string();
1873
1874 let expected_tree =
1875 token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node();
1876 let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string();
1877
1878 let expected_tree = expected_tree.replace("C_C__C", "$crate");
1879 assert_eq!(
1880 expanded_tree, expected_tree,
1881 "\nleft:\n{}\nright:\n{}",
1882 expanded_tree, expected_tree,
1883 );
1884 }
1885 }
1886 };
1788} 1887}
1789 1888
1790fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree { 1889impl_fixture!(MacroFixture);
1890impl_fixture!(MacroFixture2);
1891
1892fn parse_macro_rules_to_tt(ra_fixture: &str) -> tt::Subtree {
1791 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); 1893 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
1792 let macro_definition = 1894 let macro_definition =
1793 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap(); 1895 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
@@ -1804,14 +1906,36 @@ fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree {
1804 definition_tt 1906 definition_tt
1805} 1907}
1806 1908
1909fn parse_macro_def_to_tt(ra_fixture: &str) -> tt::Subtree {
1910 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
1911 let macro_definition =
1912 source_file.syntax().descendants().find_map(ast::MacroDef::cast).unwrap();
1913
1914 let (definition_tt, _) = ast_to_token_tree(&macro_definition.body().unwrap()).unwrap();
1915
1916 let parsed =
1917 parse_to_token_tree(&ra_fixture[macro_definition.body().unwrap().syntax().text_range()])
1918 .unwrap()
1919 .0;
1920 assert_eq!(definition_tt, parsed);
1921
1922 definition_tt
1923}
1924
1807pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { 1925pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
1808 let definition_tt = parse_macro_to_tt(ra_fixture); 1926 let definition_tt = parse_macro_rules_to_tt(ra_fixture);
1809 let rules = MacroRules::parse(&definition_tt).unwrap(); 1927 let rules = MacroRules::parse(&definition_tt).unwrap();
1810 MacroFixture { rules } 1928 MacroFixture { rules }
1811} 1929}
1812 1930
1931pub(crate) fn parse_macro2(ra_fixture: &str) -> MacroFixture2 {
1932 let definition_tt = parse_macro_def_to_tt(ra_fixture);
1933 let rules = MacroDef::parse(&definition_tt).unwrap();
1934 MacroFixture2 { rules }
1935}
1936
1813pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError { 1937pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
1814 let definition_tt = parse_macro_to_tt(ra_fixture); 1938 let definition_tt = parse_macro_rules_to_tt(ra_fixture);
1815 1939
1816 match MacroRules::parse(&definition_tt) { 1940 match MacroRules::parse(&definition_tt) {
1817 Ok(_) => panic!("Expect error"), 1941 Ok(_) => panic!("Expect error"),