fix(arg_enum!): Invalid expansions of some trailing-comma patterns

In particular, fix macros that take an enum of one of the the following forms:

 - `#[...] enum { ... , }`
 - `pub enum { ... , }`
 - `enum { ... , }`

Previously, these expansions would result in an error message like "error: no
rules expected the token `:`".

Add extensive tests for each pattern.  Only two of the patterns had tests
before, so these errors did not surface automatically.
This commit is contained in:
Bence Kalmar 2018-04-07 13:30:58 +02:00 committed by Pavan Kumar Sunkara
parent 0f3bdc439e
commit 4bf3f97d28
2 changed files with 123 additions and 27 deletions

View file

@ -371,10 +371,11 @@ macro_rules! arg_enum {
);
};
($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!($(#[$($m:meta),+])+
enum $e:ident {
$($v:ident $(=$val:expr)*),+
}
$crate::arg_enum!(@impls
($(#[$($m),+])+
enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
@ -386,9 +387,11 @@ macro_rules! arg_enum {
);
};
(pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!(pub enum $e:ident {
$($v:ident $(=$val:expr)*),+
});
$crate::arg_enum!(@impls
(pub enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
(pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
$crate::arg_enum!(@impls
@ -398,9 +401,11 @@ macro_rules! arg_enum {
);
};
(enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
$crate::arg_enum!(enum $e:ident {
$($v:ident $(=$val:expr)*),+
});
$crate::arg_enum!(@impls
(enum $e {
$($v$(=$val)*),+
}) -> ($e, $($v),+)
);
};
(enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
$crate::arg_enum!(@impls

125
tests/macros.rs Normal file → Executable file
View file

@ -286,24 +286,115 @@ fn group_macro_set_not_required() {
#[test]
fn arg_enum() {
arg_enum! {
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Greek {
Alpha,
Bravo
}
// Helper macros to avoid repetition
macro_rules! test_greek {
($arg_enum:item, $tests:block) => {{
$arg_enum
// FromStr implementation
assert!("Charlie".parse::<Greek>().is_err());
// Display implementation
assert_eq!(format!("{}", Greek::Alpha), "Alpha");
assert_eq!(format!("{}", Greek::Bravo), "Bravo");
// fn variants()
assert_eq!(Greek::variants(), ["Alpha", "Bravo"]);
// rest of tests
$tests
}};
}
macro_rules! test_greek_no_meta {
{$arg_enum:item} => {
test_greek!($arg_enum, {
// FromStr implementation
assert!("Alpha".parse::<Greek>().is_ok());
assert!("Bravo".parse::<Greek>().is_ok());
})
};
}
macro_rules! test_greek_meta {
{$arg_enum:item} => {
test_greek!($arg_enum, {
// FromStr implementation
assert_eq!("Alpha".parse::<Greek>(), Ok(Greek::Alpha));
assert_eq!("Bravo".parse::<Greek>(), Ok(Greek::Bravo));
})
};
}
assert_eq!("Alpha".parse::<Greek>(), Ok(Greek::Alpha));
}
#[test]
fn arg_enum_trailing_comma() {
arg_enum! {
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Greek {
Alpha,
Bravo,
// Tests for each pattern
// meta NO, pub NO, trailing comma NO
test_greek_no_meta! {
arg_enum!{
enum Greek {
Alpha,
Bravo
}
}
}
assert_eq!("Alpha".parse::<Greek>(), Ok(Greek::Alpha));
};
// meta NO, pub NO, trailing comma YES
test_greek_no_meta! {
arg_enum!{
enum Greek {
Alpha,
Bravo,
}
}
};
// meta NO, pub YES, trailing comma NO
test_greek_no_meta! {
arg_enum!{
pub enum Greek {
Alpha,
Bravo
}
}
};
// meta NO, pub YES, trailing comma YES
test_greek_no_meta! {
arg_enum!{
pub enum Greek {
Alpha,
Bravo,
}
}
};
// meta YES, pub NO, trailing comma NO
test_greek_meta! {
arg_enum!{
#[derive(Debug, PartialEq, Copy, Clone)]
enum Greek {
Alpha,
Bravo
}
}
};
// meta YES, pub NO, trailing comma YES
test_greek_meta! {
arg_enum!{
#[derive(Debug, PartialEq, Copy, Clone)]
enum Greek {
Alpha,
Bravo,
}
}
};
// meta YES, pub YES, trailing comma NO
test_greek_meta! {
arg_enum!{
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Greek {
Alpha,
Bravo
}
}
};
// meta YES, pub YES, trailing comma YES
test_greek_meta! {
arg_enum!{
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Greek {
Alpha,
Bravo,
}
}
};
}