Skip to content

Commit

Permalink
Introduce trybuild to test failing compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
greyblake committed Oct 20, 2022
1 parent f73d5f2 commit 8913ec0
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rust-version = "1.63.0"
derive_arbitrary = { version = "1.1.6", path = "./derive", optional = true }

[dev-dependencies]
trybuild = { version = "1.0.71", features = ["diff"] }

[features]
# Turn this feature on to enable support for `#[derive(Arbitrary)]`.
Expand Down
48 changes: 31 additions & 17 deletions derive/src/field_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,33 @@ pub fn determine_field_constructor(field: &Field) -> FieldConstructor {
}

fn fetch_attr_from_field(field: &Field) -> Option<&Attribute> {
field.attrs.iter().find(|a| {
let path = &a.path;
let name = quote!(#path).to_string();
name == ARBITRARY_ATTRIBUTE_NAME
})
let found_attributes: Vec<_> = field
.attrs
.iter()
.filter(|a| {
let path = &a.path;
let name = quote!(#path).to_string();
name == ARBITRARY_ATTRIBUTE_NAME
})
.collect();
if found_attributes.len() > 1 {
let name = field.ident.as_ref().unwrap();
panic!(
"Multiple conflicting #[{ARBITRARY_ATTRIBUTE_NAME}] attributes found on field `{name}`"
);
}
found_attributes.into_iter().next()
}

fn parse_attribute(attr: &Attribute) -> FieldConstructor {
let group = {
let mut tokens_iter = attr.clone().tokens.into_iter();
let token = tokens_iter
.next()
.unwrap_or_else(|| panic!("{ARBITRARY_ATTRIBUTE_NAME} attribute cannot be empty."));
.unwrap_or_else(|| panic!("#[{ARBITRARY_ATTRIBUTE_NAME}] cannot be empty."));
match token {
TokenTree::Group(g) => g,
t => panic!("{ARBITRARY_ATTRIBUTE_NAME} must contain a group, got: {t})"),
t => panic!("#[{ARBITRARY_ATTRIBUTE_NAME}] must contain a group, got: {t})"),
}
};
parse_attribute_internals(group.stream())
Expand All @@ -55,31 +66,34 @@ fn parse_attribute_internals(stream: TokenStream) -> FieldConstructor {
let mut tokens_iter = stream.into_iter();
let token = tokens_iter
.next()
.unwrap_or_else(|| panic!("{ARBITRARY_ATTRIBUTE_NAME} attribute cannot be empty."));
.unwrap_or_else(|| panic!("#[{ARBITRARY_ATTRIBUTE_NAME}] cannot be empty."));
match token.to_string().as_ref() {
"default" => FieldConstructor::Default,
"with" => {
let func_path = parse_assigned_value(tokens_iter);
let func_path = parse_assigned_value("with", tokens_iter);
FieldConstructor::WithFunction(func_path)
}
"value" => {
let value = parse_assigned_value(tokens_iter);
let value = parse_assigned_value("value", tokens_iter);
FieldConstructor::Value(value)
}
_ => panic!("Unknown options for {ARBITRARY_ATTRIBUTE_NAME}: {token}"),
_ => panic!("Unknown option for #[{ARBITRARY_ATTRIBUTE_NAME}]: `{token}`"),
}
}

// Input:
// = "2 + 2"
// = 2 + 2
// Output:
// 2 + 2
fn parse_assigned_value(mut tokens_iter: impl Iterator<Item = TokenTree>) -> TokenStream {
let eq_sign = tokens_iter
.next()
.unwrap_or_else(|| panic!("Invalid syntax for {ARBITRARY_ATTRIBUTE_NAME}() attribute"));
fn parse_assigned_value(
opt_name: &str,
mut tokens_iter: impl Iterator<Item = TokenTree>,
) -> TokenStream {
let eq_sign = tokens_iter.next().unwrap_or_else(|| {
panic!("Invalid syntax for #[{ARBITRARY_ATTRIBUTE_NAME}], `{opt_name}` is missing RHS.")
});
if eq_sign.to_string() != "=" {
panic!("Invalid syntax for {ARBITRARY_ATTRIBUTE_NAME}() attribute");
panic!("Invalid syntax for #[{ARBITRARY_ATTRIBUTE_NAME}], expected `=` after `{opt_name}`, got: `{eq_sign}`");
}
tokens_iter.collect()
}
5 changes: 5 additions & 0 deletions tests/compiletest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/**/*.rs");
}
11 changes: 11 additions & 0 deletions tests/ui/multiple_arbitrary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use arbitrary::Arbitrary;

#[derive(Arbitrary)]
struct Point {
#[arbitrary(value = 2)]
#[arbitrary(value = 3)]
x: i32,
y: i32
}

fn main() { }
7 changes: 7 additions & 0 deletions tests/ui/multiple_arbitrary.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
error: proc-macro derive panicked
--> tests/ui/multiple_arbitrary.rs:3:10
|
3 | #[derive(Arbitrary)]
| ^^^^^^^^^
|
= help: message: Multiple conflicting #[arbitrary] attributes found on field `x`
10 changes: 10 additions & 0 deletions tests/ui/unknown_attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use arbitrary::Arbitrary;

#[derive(Arbitrary)]
struct Point {
#[arbitrary(unknown_attr)]
x: i32,
y: i32
}

fn main() { }
7 changes: 7 additions & 0 deletions tests/ui/unknown_attribute.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
error: proc-macro derive panicked
--> tests/ui/unknown_attribute.rs:3:10
|
3 | #[derive(Arbitrary)]
| ^^^^^^^^^
|
= help: message: Unknown option for #[arbitrary]: `unknown_attr`
10 changes: 10 additions & 0 deletions tests/ui/unknown_attribute_with_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use arbitrary::Arbitrary;

#[derive(Arbitrary)]
struct Point {
#[arbitrary(unknown_attr = 255)]
x: i32,
y: i32
}

fn main() { }
7 changes: 7 additions & 0 deletions tests/ui/unknown_attribute_with_value.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
error: proc-macro derive panicked
--> tests/ui/unknown_attribute_with_value.rs:3:10
|
3 | #[derive(Arbitrary)]
| ^^^^^^^^^
|
= help: message: Unknown option for #[arbitrary]: `unknown_attr`
10 changes: 10 additions & 0 deletions tests/ui/value_no_rhs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use arbitrary::Arbitrary;

#[derive(Arbitrary)]
struct Point {
#[arbitrary(value)]
x: i32,
y: i32
}

fn main() { }
7 changes: 7 additions & 0 deletions tests/ui/value_no_rhs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
error: proc-macro derive panicked
--> tests/ui/value_no_rhs.rs:3:10
|
3 | #[derive(Arbitrary)]
| ^^^^^^^^^
|
= help: message: Invalid syntax for #[arbitrary], `value` is missing RHS.
10 changes: 10 additions & 0 deletions tests/ui/with_no_rhs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use arbitrary::Arbitrary;

#[derive(Arbitrary)]
struct Point {
#[arbitrary(with)]
x: i32,
y: i32
}

fn main() { }
7 changes: 7 additions & 0 deletions tests/ui/with_no_rhs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
error: proc-macro derive panicked
--> tests/ui/with_no_rhs.rs:3:10
|
3 | #[derive(Arbitrary)]
| ^^^^^^^^^
|
= help: message: Invalid syntax for #[arbitrary], `with` is missing RHS.

0 comments on commit 8913ec0

Please sign in to comment.