Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macro compilation tests. #57

Merged
merged 25 commits into from
Feb 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3ef8ca9
Define macro for creating trybuild tests.
Anders429 Feb 16, 2022
91f4173
Trybuild tests for entities macro.
Anders429 Feb 16, 2022
a14efb8
Trybuild test and fix for incorrect stages commands.
Anders429 Feb 16, 2022
3e04a58
Trybuild tests for more unexpected command variations.
Anders429 Feb 16, 2022
9a71c8d
Trybuild tests for stages macro, with rewritten macro to pass these t…
Anders429 Feb 16, 2022
9d6c783
Formatting.
Anders429 Feb 16, 2022
39f8f56
more trybuild tests for unexpected tokens in stages macro.
Anders429 Feb 16, 2022
2fb479d
Merge branch 'master' of https://github.com/Anders429/brood into tryb…
Anders429 Feb 16, 2022
6ccf37b
More trybuild tests for entities macro.
Anders429 Feb 17, 2022
a73da88
trybuild tests for entity macro.
Anders429 Feb 17, 2022
774ff48
trybuild tests for registry macro.
Anders429 Feb 17, 2022
ac2c576
trybuild tests for views macro.
Anders429 Feb 18, 2022
92c597e
Actually write the trybuild tests.
Anders429 Feb 18, 2022
fe82b70
trybuild tests for result macro.
Anders429 Feb 18, 2022
9b37dde
Install valgrind from source.
Anders429 Feb 18, 2022
fc71248
Add missing command.
Anders429 Feb 18, 2022
ed72fee
Run configure binary.
Anders429 Feb 18, 2022
880db4c
Run from root directory.
Anders429 Feb 18, 2022
062d0ad
Specify working directory for make commands.
Anders429 Feb 18, 2022
006e5fd
Fix typo in command.
Anders429 Feb 18, 2022
72edffb
Install 32-bit libc6-dbg.
Anders429 Feb 18, 2022
f06f241
Install as root.
Anders429 Feb 18, 2022
4ac1117
Install 64-bit libc6-dbg.
Anders429 Feb 18, 2022
635e2ae
Ignore trybuild tests in valgrind and miri workflow jobs.
Anders429 Feb 20, 2022
1e8dcfa
Fix environment variable typo.
Anders429 Feb 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,21 @@ jobs:
args: miri test --feature-powerset --optional-deps
env:
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-ignore-leaks
RUSTFLAGS: --cfg skip_trybuild

valgrind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt-get install valgrind
- run: wget https://sourceware.org/pub/valgrind/valgrind-3.18.1.tar.bz2
- run: tar xvf valgrind-3.18.1.tar.bz2
- run: ./configure
working-directory: ./valgrind-3.18.1
- run: make
working-directory: ./valgrind-3.18.1
- run: sudo make install
working-directory: ./valgrind-3.18.1
- run: sudo apt-get install libc6-dbg
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
Expand All @@ -156,6 +165,8 @@ jobs:
with:
command: hack
args: valgrind test --feature-powerset --optional-deps
env:
RUSTFLAGS: --cfg skip_trybuild

codecov:
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ rayon = {version = "1.5.1", optional = true}
serde = {version = "1.0.133", default-features = false, features = ["alloc"], optional = true}

[dev-dependencies]
rustversion = "1.0.6"
serde_test = "1.0.133"
trybuild = "1.0.56"

[features]
# TODO: Rename this to "rayon" when namespaced dependencies are stabilized in 1.60.0.
Expand Down
7 changes: 5 additions & 2 deletions src/entities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@ macro_rules! entities {
)
}
};
($(($($components:expr),*)),* $(,)?) => {
($(($($components:expr),*)),+ $(,)?) => {
unsafe {
$crate::entities::Batch::new_unchecked(
$crate::entities!(@transpose [] $(($($components),*)),*)
$crate::entities!(@transpose [] $(($($components),*)),+)
)
}
};
Expand All @@ -244,18 +244,21 @@ macro_rules! entities {
$crate::entities::Batch::new_unchecked($crate::entities::Null)
}
};

(@cloned ($component:expr $(,$components:expr)* $(,)?); $n:expr) => {
($crate::reexports::vec![$component; $n], $crate::entities!(@cloned ($($components),*); $n))
};
(@cloned (); $n:expr) => {
$crate::entities::Null
};

(@transpose [$([$($column:expr),*])*] $(($component:expr $(,$components:expr)* $(,)?)),*) => {
$crate::entities!(@transpose [$([$($column),*])* [$($component),*]] $(($($components),*)),*)
};
(@transpose [$([$($column:expr),*])*] $(()),*) => {
$crate::entities!(@as_vec ($(($($column),*)),*))
};

(@as_vec (($($column:expr),*) $(,($($columns:expr),*))* $(,)?)) => {
($crate::reexports::vec![$($column),*], $crate::entities!(@as_vec ($(($($columns),*)),*)))
};
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod archetype;
mod archetypes;
mod doc;
mod hlist;
mod r#macro;

#[doc(inline)]
pub use world::World;
16 changes: 16 additions & 0 deletions src/macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Helper macros specifically for use by other macros within this crate.
//!
//! Although the macros here are exported publicly, it is only for use by other macros within this
//! crate. These should not be depended upon by any external code, and are not considered a part of
//! the public API.

/// Indicate that the given tokens were unexpected.
///
/// Calling this macro with any tokens will return an error pointing to those tokens within the
/// original macro. This allows more precise error messages from macros when input is not formatted
/// correctly.
#[macro_export]
#[doc(hidden)]
macro_rules! unexpected {
() => {};
}
167 changes: 153 additions & 14 deletions src/system/schedule/stage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,159 @@ doc::non_root_macro! {
/// [`schedule::Builder`]: crate::system::schedule::Builder
/// [`System`]: crate::system::System
macro_rules! stages {
($($idents:tt $(: $systems:tt)?),* $(,)?) => (
stages!(internal @ $crate::system::schedule::stage::Null; $($idents $(: $systems)?,)*)
);
(internal @ $processed:ty; system: $system:ty, $($idents:tt $(: $systems:tt)?),* $(,)?) => (
stages!(internal @ ($crate::system::schedule::stage::Stage<$system, $crate::system::Null>, $processed); $($idents $(: $systems)?,)*)
);
(internal @ $processed:ty; par_system: $par_system:ty, $($idents:tt $(: $systems:tt)?),* $(,)?) => (
stages!(internal @ ($crate::system::schedule::stage::Stage<$crate::system::Null, $par_system>, $processed); $($idents $(: $systems)?,)*)
);
(internal @ $processed:ty; flush, $($idents:tt $(: $systems:tt)?),* $(,)?) => (
stages!(internal @ ($crate::system::schedule::stage::Stage<$crate::system::Null, $crate::system::Null>, $processed); $($idents $(: $systems)?,)*)
);
(internal @ $processed:ty; $($idents:tt $(: $systems:tt)?),* $(,)?) => (
$processed
// Entry point for the macro.
//
// This just calls into the internal macro with all of the correct parameters.
($($tt:tt)*) => (
$crate::stages_internal!(@task $crate::system::schedule::stage::Null; ($($tt)*) ($($tt)*))
);
}
}

#[doc(hidden)]
#[macro_export]
macro_rules! stages_internal {
///////////////////////////////////////////////////////////////////////////////////////////////
// Generic task macro.
//
// These patterns are for matching and processing generic tasks listed in the token tree. When
// each of the valid task types (system, par_system, and flush) are encountered, the tokens are
// passed to the appropriate patterns (@system, @par_system, and @flush) to be consumed.
//
// Note that we require two copies of the input token tree here. The first is matched on, and
// the second is used to trigger errors.
//
// Invoked as:
// $crate::stages_internal!(@task $crate::system::schedule::stage::Null; ($($tt)*) ($($tt)*))
///////////////////////////////////////////////////////////////////////////////////////////////

// Match a system task.
(@task $processed:ty; (system $($rest:tt)*) $copy:tt) => (
$crate::stages_internal!(@system $processed; ($($rest)*) ($($rest)*))
);

// Match a par_system task.
(@task $processed:ty; (par_system $($rest:tt)*) $copy:tt) => (
$crate::stages_internal!(@par_system $processed; ($($rest)*) ($($rest)*))
);

// Match a flush task.
(@task $processed:ty; (flush $($rest:tt)*) $copy:tt) => (
$crate::stages_internal!(@flush $processed; ($($rest)*) ($($rest)*))
);

// End case. We return the processed result.
(@task $processed:ty; () ()) => (
$processed
);

// Match any other unexpected input. This will output an error.
(@task $processed:ty; ($($rest:tt)*) $copy:tt) => (
$crate::unexpected!($($rest)*)
);

///////////////////////////////////////////////////////////////////////////////////////////////
// System task macro.
//
// These patterns match the remainder of a system task entry. This will match a colon followed
// by a system type. Trailing commas are also matched here.
//
// Note that we require two copies of the input token tree here. The first is matched on, and
// the second is used to trigger errors.
///////////////////////////////////////////////////////////////////////////////////////////////

// Match a system type without a trailing comma. This will only match at the end of the token
// tree.
(@system $processed:ty; (: $system:ty) $copy:tt) => {
$crate::stages_internal(@task ($crate::system::schedule::stage::Stage<$system, $crate::system::Null>, $processed); () ())
};

// Match a system type with a trailing comma.
(@system $processed:ty; (: $system:ty, $($rest:tt)*) $copy:tt) => (
$crate::stages_internal!(@task ($crate::system::schedule::stage::Stage<$system, $crate::system::Null>, $processed); ($($rest)*) ($($rest)*))
);

// Match a system type with no trailing comma not at the end of the token tree. This will
// output an error.
(@system $processed:ty; (: $system:tt $($rest:tt)*) $copy:tt) => {
$crate::unexpected!($($rest)*)
};

// Match a comma with no system type provided. This will output an error.
(@system $processed:ty; (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => (
$crate::unexpected!($comma)
);

// Match any other unexpected input. This will output an error.
(@system $processed:ty; ($($rest:tt)*) $copy:tt) => (
$crate::unexpected!($($rest)*)
);

///////////////////////////////////////////////////////////////////////////////////////////////
// Parallel system task macro.
//
// These patterns match the remainder of a par_system task entry. This will match a colon
// followed by a parallel system type. Trailing commas are also matched here.
//
// Note that we require two copies of the input token tree here. The first is matched on, and
// the second is used to trigger errors.
///////////////////////////////////////////////////////////////////////////////////////////////

// Match a parallel system type without a trailing comma. This will only match at the end of
// the token tree.
(@par_system $processed:ty; (: $par_system:ty) $copy:tt) => (
$crate::stages_internal!(@task ($crate::system::schedule::stage::Stage<$crate::system::Null, $par_system>, $processed); () ())
);

// Match a parallel system type with a trailing comma.
(@par_system $processed:ty; (: $par_system:ty, $($rest:tt)*) $copy:tt) => (
$crate::stages_internal!(@task ($crate::system::schedule::stage::Stage<$crate::system::Null, $par_system>, $processed); ($($rest)*) ($($rest)*))
);

// Match a parallel system type with no trailing comma not at the end of the token tree. This
// will output an error.
(@par_system $processed:ty; (: $par_system:tt $($rest:tt)*) $copy:tt) => {
$crate::unexpected!($($rest)*)
};

// Match a comma with no parallel system type provided. This will output an error.
(@par_system $processed:ty; (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => (
$crate::unexpected!($comma)
);

// Match any other unexpected input. This will output an error.
(@par_system $processed:ty; ($($rest:tt)*) $copy:tt) => (
$crate::unexpected!($($rest)*)
);

///////////////////////////////////////////////////////////////////////////////////////////////
// Flush task macro.
//
// These patterns match the remainder of a flush task entry, which is only either a comma or
// nothing.
//
// Note that we require two copies of the input token tree here. The first is matched on, and
// the second is used to trigger errors.
///////////////////////////////////////////////////////////////////////////////////////////////

// Match a comma.
(@flush $processed:ty; (, $($rest:tt)*) $copy:tt) => (
$crate::stages_internal!(@task ($crate::system::schedule::stage::Stage<$crate::system::Null, $crate::system::Null>, $processed); ($($rest)*) ($($rest)*))
);

// Match a colon. This is invalid and will output an error.
(@flush $processed:ty; (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => (
$crate::unexpected!($colon)
);

// Match nothing. This will only occur at the end of the input token tree, which is the only
// time when a trailing comma is not required.
(@flush $processed:ty; () ()) => (
$crate::stages_internal!(@task ($crate::system::schedule::stage::Stage<$crate::system::Null, $crate::system::Null>, $processed); () ())
);

// Match any other unexpected input. This will output an error.
(@flush $processed:ty; ($($rest:tt)*) $copy:tt) => (
$crate::unexpected!($($rest)*)
);
}
23 changes: 23 additions & 0 deletions tests/trybuild.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#![cfg(not(skip_trybuild))]

macro_rules! trybuild_test {
($test_name:ident) => {
#[test]
#[rustversion::attr(not(nightly), ignore)]
fn $test_name() {
trybuild::TestCases::new().compile_fail(concat!(
"tests/trybuild/",
stringify!($test_name),
"/*.rs"
));
}
};
}

trybuild_test!(entities);
trybuild_test!(entity);
trybuild_test!(registry);
trybuild_test!(result);
#[cfg(feature = "parallel")]
trybuild_test!(stages);
trybuild_test!(views);
5 changes: 5 additions & 0 deletions tests/trybuild/entities/comma_alone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use brood::entities;

fn main () {
let entities = entities!(,);
}
5 changes: 5 additions & 0 deletions tests/trybuild/entities/comma_alone.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: no rules expected the token `,`
--> tests/trybuild/entities/comma_alone.rs:4:30
|
4 | let entities = entities!(,);
| ^ no rules expected this token in macro call
9 changes: 9 additions & 0 deletions tests/trybuild/entities/component_order.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use brood::entities;

// Define components.
struct A;
struct B;

fn main () {
let entities = entities!((A, B), (B, A));
}
11 changes: 11 additions & 0 deletions tests/trybuild/entities/component_order.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> tests/trybuild/entities/component_order.rs:8:39
|
8 | let entities = entities!((A, B), (B, A));
| ^ expected struct `A`, found struct `B`

error[E0308]: mismatched types
--> tests/trybuild/entities/component_order.rs:8:42
|
8 | let entities = entities!((A, B), (B, A));
| ^ expected struct `B`, found struct `A`
9 changes: 9 additions & 0 deletions tests/trybuild/entities/double_comma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use brood::entities;

// Define components.
struct A;
struct B;

fn main () {
let entities = entities!((A, B),, (A, B));
}
5 changes: 5 additions & 0 deletions tests/trybuild/entities/double_comma.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: no rules expected the token `,`
--> tests/trybuild/entities/double_comma.rs:8:37
|
8 | let entities = entities!((A, B),, (A, B));
| ^ no rules expected this token in macro call
11 changes: 11 additions & 0 deletions tests/trybuild/entities/length_not_integer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use brood::entities;

// Define components.
#[derive(Clone)]
struct A;
#[derive(Clone)]
struct B;

fn main () {
let entities = entities!((A, B); 1.5);
}
5 changes: 5 additions & 0 deletions tests/trybuild/entities/length_not_integer.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error[E0308]: mismatched types
--> tests/trybuild/entities/length_not_integer.rs:10:38
|
10 | let entities = entities!((A, B); 1.5);
| ^^^ expected `usize`, found floating-point number
10 changes: 10 additions & 0 deletions tests/trybuild/entities/same_components.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use brood::entities;

// Define components.
struct A;
struct B;
struct C;

fn main () {
let entities = entities!((A, B), (A, C));
}
5 changes: 5 additions & 0 deletions tests/trybuild/entities/same_components.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error[E0308]: mismatched types
--> tests/trybuild/entities/same_components.rs:9:42
|
9 | let entities = entities!((A, B), (A, C));
| ^ expected struct `B`, found struct `C`
11 changes: 11 additions & 0 deletions tests/trybuild/entities/semicolon_separated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use brood::entities;

// Define components.
#[derive(Clone)]
struct A;
#[derive(Clone)]
struct B;

fn main () {
let entities = entities!((A, B); (A, B); (A, B));
}
Loading