diff options
Diffstat (limited to 'quote/tests')
-rw-r--r-- | quote/tests/compiletest.rs | 6 | ||||
-rw-r--r-- | quote/tests/test.rs | 429 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter-interpolated-dup.rs | 9 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter-interpolated-dup.stderr | 11 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter-interpolated.rs | 9 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter-interpolated.stderr | 11 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter-separated.rs | 5 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter-separated.stderr | 11 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter.rs | 5 | ||||
-rw-r--r-- | quote/tests/ui/does-not-have-iter.stderr | 11 | ||||
-rw-r--r-- | quote/tests/ui/not-quotable.rs | 7 | ||||
-rw-r--r-- | quote/tests/ui/not-quotable.stderr | 10 | ||||
-rw-r--r-- | quote/tests/ui/not-repeatable.rs | 7 | ||||
-rw-r--r-- | quote/tests/ui/not-repeatable.stderr | 14 | ||||
-rw-r--r-- | quote/tests/ui/wrong-type-span.rs | 7 | ||||
-rw-r--r-- | quote/tests/ui/wrong-type-span.stderr | 10 |
16 files changed, 562 insertions, 0 deletions
diff --git a/quote/tests/compiletest.rs b/quote/tests/compiletest.rs new file mode 100644 index 0000000..f9aea23 --- /dev/null +++ b/quote/tests/compiletest.rs @@ -0,0 +1,6 @@ +#[rustversion::attr(not(nightly), ignore)] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/quote/tests/test.rs b/quote/tests/test.rs new file mode 100644 index 0000000..957d470 --- /dev/null +++ b/quote/tests/test.rs @@ -0,0 +1,429 @@ +#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))] + +use std::borrow::Cow; +use std::collections::BTreeSet; + +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{format_ident, quote, TokenStreamExt}; + +struct X; + +impl quote::ToTokens for X { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Ident::new("X", Span::call_site())); + } +} + +#[test] +fn test_quote_impl() { + let tokens = quote! { + impl<'a, T: ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } + } + }; + + let expected = concat!( + "impl < 'a , T : ToTokens > ToTokens for & 'a T { ", + "fn to_tokens ( & self , tokens : & mut TokenStream ) { ", + "( * * self ) . to_tokens ( tokens ) ", + "} ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_substitution() { + let x = X; + let tokens = quote!(#x <#x> (#x) [#x] {#x}); + + let expected = "X < X > ( X ) [ X ] { X }"; + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_iter() { + let primes = &[X, X, X, X]; + + assert_eq!("X X X X", quote!(#(#primes)*).to_string()); + + assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).to_string()); + + assert_eq!("X , X , X , X", quote!(#(#primes),*).to_string()); +} + +#[test] +fn test_advanced() { + let generics = quote!( <'a, T> ); + + let where_clause = quote!( where T: Serialize ); + + let field_ty = quote!(String); + + let item_ty = quote!(Cow<'a, str>); + + let path = quote!(SomeTrait::serialize_with); + + let value = quote!(self.x); + + let tokens = quote! { + struct SerializeWith #generics #where_clause { + value: &'a #field_ty, + phantom: ::std::marker::PhantomData<#item_ty>, + } + + impl #generics ::serde::Serialize for SerializeWith #generics #where_clause { + fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer + { + #path(self.value, s) + } + } + + SerializeWith { + value: #value, + phantom: ::std::marker::PhantomData::<#item_ty>, + } + }; + + let expected = concat!( + "struct SerializeWith < 'a , T > where T : Serialize { ", + "value : & 'a String , ", + "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ", + "} ", + "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ", + "fn serialize < S > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > ", + "where S : :: serde :: Serializer ", + "{ ", + "SomeTrait :: serialize_with ( self . value , s ) ", + "} ", + "} ", + "SerializeWith { ", + "value : self . x , ", + "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_integer() { + let ii8 = -1i8; + let ii16 = -1i16; + let ii32 = -1i32; + let ii64 = -1i64; + let ii128 = -1i128; + let iisize = -1isize; + let uu8 = 1u8; + let uu16 = 1u16; + let uu32 = 1u32; + let uu64 = 1u64; + let uu128 = 1u128; + let uusize = 1usize; + + let tokens = quote! { + #ii8 #ii16 #ii32 #ii64 #ii128 #iisize + #uu8 #uu16 #uu32 #uu64 #uu128 #uusize + }; + let expected = "-1i8 -1i16 -1i32 -1i64 -1i128 -1isize 1u8 1u16 1u32 1u64 1u128 1usize"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_floating() { + let e32 = 2.345f32; + + let e64 = 2.345f64; + + let tokens = quote! { + #e32 + #e64 + }; + let expected = concat!("2.345f32 2.345f64"); + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_char() { + let zero = '\0'; + let pound = '#'; + let quote = '"'; + let apost = '\''; + let newline = '\n'; + let heart = '\u{2764}'; + + let tokens = quote! { + #zero #pound #quote #apost #newline #heart + }; + let expected = "'\\u{0}' '#' '\"' '\\'' '\\n' '\\u{2764}'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_str() { + let s = "\0 a 'b \" c"; + let tokens = quote!(#s); + let expected = "\"\\u{0} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_string() { + let s = "\0 a 'b \" c".to_string(); + let tokens = quote!(#s); + let expected = "\"\\u{0} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_ident() { + let foo = Ident::new("Foo", Span::call_site()); + let bar = Ident::new(&format!("Bar{}", 7), Span::call_site()); + let tokens = quote!(struct #foo; enum #bar {}); + let expected = "struct Foo ; enum Bar7 { }"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate() { + let ch = 'x'; + + let tokens = quote!(#ch #ch); + + let expected = "'x' 'x'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_fancy_repetition() { + let foo = vec!["a", "b"]; + let bar = vec![true, false]; + + let tokens = quote! { + #(#foo: #bar),* + }; + + let expected = r#""a" : true , "b" : false"#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_nested_fancy_repetition() { + let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']]; + + let tokens = quote! { + #( + #(#nested)* + ),* + }; + + let expected = "'a' 'b' 'c' , 'x' 'y' 'z'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate_name_repetition() { + let foo = &["a", "b"]; + + let tokens = quote! { + #(#foo: #foo),* + #(#foo: #foo),* + }; + + let expected = r#""a" : "a" , "b" : "b" "a" : "a" , "b" : "b""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate_name_repetition_no_copy() { + let foo = vec!["a".to_owned(), "b".to_owned()]; + + let tokens = quote! { + #(#foo: #foo),* + }; + + let expected = r#""a" : "a" , "b" : "b""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_btreeset_repetition() { + let mut set = BTreeSet::new(); + set.insert("a".to_owned()); + set.insert("b".to_owned()); + + let tokens = quote! { + #(#set: #set),* + }; + + let expected = r#""a" : "a" , "b" : "b""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_variable_name_conflict() { + // The implementation of `#(...),*` uses the variable `_i` but it should be + // fine, if a little confusing when debugging. + let _i = vec!['a', 'b']; + let tokens = quote! { #(#_i),* }; + let expected = "'a' , 'b'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_nonrep_in_repetition() { + let rep = vec!["a", "b"]; + let nonrep = "c"; + + let tokens = quote! { + #(#rep #rep : #nonrep #nonrep),* + }; + + let expected = r#""a" "a" : "c" "c" , "b" "b" : "c" "c""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_empty_quote() { + let tokens = quote!(); + assert_eq!("", tokens.to_string()); +} + +#[test] +fn test_box_str() { + let b = "str".to_owned().into_boxed_str(); + let tokens = quote! { #b }; + assert_eq!("\"str\"", tokens.to_string()); +} + +#[test] +fn test_cow() { + let owned: Cow<Ident> = Cow::Owned(Ident::new("owned", Span::call_site())); + + let ident = Ident::new("borrowed", Span::call_site()); + let borrowed = Cow::Borrowed(&ident); + + let tokens = quote! { #owned #borrowed }; + assert_eq!("owned borrowed", tokens.to_string()); +} + +#[test] +fn test_closure() { + fn field_i(i: usize) -> Ident { + format_ident!("__field{}", i) + } + + let fields = (0usize..3) + .map(field_i as fn(_) -> _) + .map(|var| quote! { #var }); + + let tokens = quote! { #(#fields)* }; + assert_eq!("__field0 __field1 __field2", tokens.to_string()); +} + +#[test] +fn test_append_tokens() { + let mut a = quote!(a); + let b = quote!(b); + a.append_all(b); + assert_eq!("a b", a.to_string()); +} + +#[test] +fn test_format_ident() { + let id0 = format_ident!("Aa"); + let id1 = format_ident!("Hello{x}", x = id0); + let id2 = format_ident!("Hello{x}", x = 5usize); + let id3 = format_ident!("Hello{}_{x}", id0, x = 10usize); + let id4 = format_ident!("Aa", span = Span::call_site()); + + assert_eq!(id0, "Aa"); + assert_eq!(id1, "HelloAa"); + assert_eq!(id2, "Hello5"); + assert_eq!(id3, "HelloAa_10"); + assert_eq!(id4, "Aa"); +} + +#[test] +fn test_format_ident_strip_raw() { + let id = format_ident!("r#struct"); + let my_id = format_ident!("MyId{}", id); + let raw_my_id = format_ident!("r#MyId{}", id); + + assert_eq!(id, "r#struct"); + assert_eq!(my_id, "MyIdstruct"); + assert_eq!(raw_my_id, "r#MyIdstruct"); +} + +#[test] +fn test_outer_line_comment() { + let tokens = quote! { + /// doc + }; + let expected = "# [ doc = r\" doc\" ]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_inner_line_comment() { + let tokens = quote! { + //! doc + }; + let expected = "# ! [ doc = r\" doc\" ]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_outer_block_comment() { + let tokens = quote! { + /** doc */ + }; + let expected = "# [ doc = r\" doc \" ]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_inner_block_comment() { + let tokens = quote! { + /*! doc */ + }; + let expected = "# ! [ doc = r\" doc \" ]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_outer_attr() { + let tokens = quote! { + #[inline] + }; + let expected = "# [ inline ]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_inner_attr() { + let tokens = quote! { + #![no_std] + }; + let expected = "# ! [ no_std ]"; + assert_eq!(expected, tokens.to_string()); +} + +// https://github.com/dtolnay/quote/issues/130 +#[test] +fn test_star_after_repetition() { + let c = vec!['0', '1']; + let tokens = quote! { + #( + f(#c); + )* + *out = None; + }; + let expected = "f ( '0' ) ; f ( '1' ) ; * out = None ;"; + assert_eq!(expected, tokens.to_string()); +} diff --git a/quote/tests/ui/does-not-have-iter-interpolated-dup.rs b/quote/tests/ui/does-not-have-iter-interpolated-dup.rs new file mode 100644 index 0000000..0a39f41 --- /dev/null +++ b/quote/tests/ui/does-not-have-iter-interpolated-dup.rs @@ -0,0 +1,9 @@ +use quote::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!(#(#nonrep #nonrep)*); +} diff --git a/quote/tests/ui/does-not-have-iter-interpolated-dup.stderr b/quote/tests/ui/does-not-have-iter-interpolated-dup.stderr new file mode 100644 index 0000000..6ee6fdf --- /dev/null +++ b/quote/tests/ui/does-not-have-iter-interpolated-dup.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/does-not-have-iter-interpolated-dup.rs:8:5 + | +8 | quote!(#(#nonrep #nonrep)*); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition` + | + = note: expected type `quote::__rt::HasIterator` + found type `quote::__rt::ThereIsNoIteratorInRepetition` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +For more information about this error, try `rustc --explain E0308`. diff --git a/quote/tests/ui/does-not-have-iter-interpolated.rs b/quote/tests/ui/does-not-have-iter-interpolated.rs new file mode 100644 index 0000000..2c740cc --- /dev/null +++ b/quote/tests/ui/does-not-have-iter-interpolated.rs @@ -0,0 +1,9 @@ +use quote::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!(#(#nonrep)*); +} diff --git a/quote/tests/ui/does-not-have-iter-interpolated.stderr b/quote/tests/ui/does-not-have-iter-interpolated.stderr new file mode 100644 index 0000000..8d6c990 --- /dev/null +++ b/quote/tests/ui/does-not-have-iter-interpolated.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/does-not-have-iter-interpolated.rs:8:5 + | +8 | quote!(#(#nonrep)*); + | ^^^^^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition` + | + = note: expected type `quote::__rt::HasIterator` + found type `quote::__rt::ThereIsNoIteratorInRepetition` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +For more information about this error, try `rustc --explain E0308`. diff --git a/quote/tests/ui/does-not-have-iter-separated.rs b/quote/tests/ui/does-not-have-iter-separated.rs new file mode 100644 index 0000000..c027243 --- /dev/null +++ b/quote/tests/ui/does-not-have-iter-separated.rs @@ -0,0 +1,5 @@ +use quote::quote; + +fn main() { + quote!(#(a b),*); +} diff --git a/quote/tests/ui/does-not-have-iter-separated.stderr b/quote/tests/ui/does-not-have-iter-separated.stderr new file mode 100644 index 0000000..c1fd0ad --- /dev/null +++ b/quote/tests/ui/does-not-have-iter-separated.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/does-not-have-iter-separated.rs:4:5 + | +4 | quote!(#(a b),*); + | ^^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition` + | + = note: expected type `quote::__rt::HasIterator` + found type `quote::__rt::ThereIsNoIteratorInRepetition` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +For more information about this error, try `rustc --explain E0308`. diff --git a/quote/tests/ui/does-not-have-iter.rs b/quote/tests/ui/does-not-have-iter.rs new file mode 100644 index 0000000..8908353 --- /dev/null +++ b/quote/tests/ui/does-not-have-iter.rs @@ -0,0 +1,5 @@ +use quote::quote; + +fn main() { + quote!(#(a b)*); +} diff --git a/quote/tests/ui/does-not-have-iter.stderr b/quote/tests/ui/does-not-have-iter.stderr new file mode 100644 index 0000000..3b87705 --- /dev/null +++ b/quote/tests/ui/does-not-have-iter.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/does-not-have-iter.rs:4:5 + | +4 | quote!(#(a b)*); + | ^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition` + | + = note: expected type `quote::__rt::HasIterator` + found type `quote::__rt::ThereIsNoIteratorInRepetition` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +For more information about this error, try `rustc --explain E0308`. diff --git a/quote/tests/ui/not-quotable.rs b/quote/tests/ui/not-quotable.rs new file mode 100644 index 0000000..f991c18 --- /dev/null +++ b/quote/tests/ui/not-quotable.rs @@ -0,0 +1,7 @@ +use quote::quote; +use std::net::Ipv4Addr; + +fn main() { + let ip = Ipv4Addr::LOCALHOST; + let _ = quote! { #ip }; +} diff --git a/quote/tests/ui/not-quotable.stderr b/quote/tests/ui/not-quotable.stderr new file mode 100644 index 0000000..f51f85f --- /dev/null +++ b/quote/tests/ui/not-quotable.stderr @@ -0,0 +1,10 @@ +error[E0277]: the trait bound `std::net::Ipv4Addr: quote::to_tokens::ToTokens` is not satisfied + --> $DIR/not-quotable.rs:6:13 + | +6 | let _ = quote! { #ip }; + | ^^^^^^^^^^^^^^ the trait `quote::to_tokens::ToTokens` is not implemented for `std::net::Ipv4Addr` + | + = note: required by `quote::to_tokens::ToTokens::to_tokens` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +For more information about this error, try `rustc --explain E0277`. diff --git a/quote/tests/ui/not-repeatable.rs b/quote/tests/ui/not-repeatable.rs new file mode 100644 index 0000000..ff18060 --- /dev/null +++ b/quote/tests/ui/not-repeatable.rs @@ -0,0 +1,7 @@ +use quote::quote; +use std::net::Ipv4Addr; + +fn main() { + let ip = Ipv4Addr::LOCALHOST; + let _ = quote! { #(#ip)* }; +} diff --git a/quote/tests/ui/not-repeatable.stderr b/quote/tests/ui/not-repeatable.stderr new file mode 100644 index 0000000..ddcac05 --- /dev/null +++ b/quote/tests/ui/not-repeatable.stderr @@ -0,0 +1,14 @@ +error[E0599]: no method named `quote_into_iter` found for type `std::net::Ipv4Addr` in the current scope + --> $DIR/not-repeatable.rs:6:13 + | +6 | let _ = quote! { #(#ip)* }; + | ^^^^^^^^^^^^^^^^^^ + | + = note: the method `quote_into_iter` exists but the following trait bounds were not satisfied: + `&mut std::net::Ipv4Addr : quote::__rt::ext::RepIteratorExt` + `&std::net::Ipv4Addr : quote::__rt::ext::RepIteratorExt` + `std::net::Ipv4Addr : quote::__rt::ext::RepIteratorExt` + `std::net::Ipv4Addr : quote::__rt::ext::RepToTokensExt` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +For more information about this error, try `rustc --explain E0599`. diff --git a/quote/tests/ui/wrong-type-span.rs b/quote/tests/ui/wrong-type-span.rs new file mode 100644 index 0000000..1ce391c --- /dev/null +++ b/quote/tests/ui/wrong-type-span.rs @@ -0,0 +1,7 @@ +use quote::quote_spanned; + +fn main() { + let span = ""; + let x = 0; + quote_spanned!(span=> #x); +} diff --git a/quote/tests/ui/wrong-type-span.stderr b/quote/tests/ui/wrong-type-span.stderr new file mode 100644 index 0000000..a6ae8ef --- /dev/null +++ b/quote/tests/ui/wrong-type-span.stderr @@ -0,0 +1,10 @@ +error[E0308]: mismatched types + --> $DIR/wrong-type-span.rs:6:20 + | +6 | quote_spanned!(span=> #x); + | ^^^^ expected struct `proc_macro2::Span`, found &str + | + = note: expected type `proc_macro2::Span` + found type `&str` + +For more information about this error, try `rustc --explain E0308`. |