use ::parser::ParserEntryPoint;
use syntax::{SyntaxKind::IDENT, T};
use super::*;
// Good first issue (although a slightly challenging one):
//
// * Pick a random test from here
// https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
// * Port the test to rust and add it to this module
// * Make it pass :-)
#[test]
fn test_token_id_shift() {
let expansion = parse_macro(
r#"
macro_rules! foobar {
($e:ident) => { foo bar $e }
}
"#,
)
.expand_tt("foobar!(baz);");
fn get_id(t: &tt::TokenTree) -> Option<u32> {
if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
return Some(ident.id.0);
}
None
}
assert_eq!(expansion.token_trees.len(), 3);
// {($e:ident) => { foo bar $e }}
// 012345 67 8 9 T 12
assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
// The input args of macro call include parentheses:
// (baz)
// So baz should be 12+1+1
assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
}
#[test]
fn test_token_map() {
let expanded = parse_macro(
r#"
macro_rules! foobar {
($e:ident) => { fn $e() {} }
}
"#,
)
.expand_tt("foobar!(baz);");
let (node, token_map) = token_tree_to_syntax_node(&expanded, ParserEntryPoint::Items).unwrap();
let content = node.syntax_node().to_string();
let get_text = |id, kind| -> String {
content[token_map.first_range_by_token(id, kind).unwrap()].to_string()
};
assert_eq!(expanded.token_trees.len(), 4);
// {($e:ident) => { fn $e() {} }}
// 012345 67 8 9 T12 3
assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
}
fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
if let tt::TokenTree::Subtree(subtree) = tt {
return subtree;
}
unreachable!("It is not a subtree");
}
fn to_punct(tt: &tt::TokenTree) -> &tt::Punct {
if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt {
return lit;
}
unreachable!("It is not a Punct");
}
#[test]
fn test_attr_to_token_tree() {
let expansion = parse_to_token_tree_by_syntax(
r#"
#[derive(Copy)]
struct Foo;
"#,
);
assert_eq!(to_punct(&expansion.token_trees[0]).char, '#');
assert_eq!(
to_subtree(&expansion.token_trees[1]).delimiter_kind(),
Some(tt::DelimiterKind::Bracket)
);
}
#[test]
fn test_expand_bad_literal() {
parse_macro(
r#"
macro_rules! foo { ($i:literal) => {}; }
"#,
)
.assert_expand_err(r#"foo!(&k");"#, &ExpandError::BindingError("".into()));
}
#[test]
fn test_empty_comments() {
parse_macro(
r#"
macro_rules! one_arg_macro { ($fmt:expr) => (); }
"#,
)
.assert_expand_err(
r#"one_arg_macro!(/**/)"#,
&ExpandError::BindingError("expected Expr".into()),
);
}