Skip to content

Commit

Permalink
Add UI tests for existing lints (#128)
Browse files Browse the repository at this point in the history
Part of #31.

This is a continuation of #125 that actually adds UI tests for all of
the current lints. It was split off to make #125 easier to review.

To test this, run:

```bash
cargo test -p bevy_lint --test ui
```

To bless changes, run:

```bash
cargo test -p bevy_lint --test ui -- --bless
```

There are a few additional options available if you replace `--bless`
with `--help`, too.
  • Loading branch information
BD103 authored Oct 13, 2024
1 parent f969f96 commit 603a7c6
Show file tree
Hide file tree
Showing 29 changed files with 708 additions and 6 deletions.
5 changes: 5 additions & 0 deletions bevy_lint/src/lints/main_return_without_appexit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
//! it from `main()` will set the exit code, which allows external processes to detect whether there
//! was an error.
//!
//! # Known issues
//!
//! If you wish to silence this lint, you must add `#[allow(bevy::main_return_without_appexit)]` to
//! `fn main()`, not the line that calls `App::run()`.
//!
//! # Example
//!
//! ```
Expand Down
22 changes: 22 additions & 0 deletions bevy_lint/tests/ui/insert_event_resource/bug_94.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! This test tracks the bug reported in [#94]. When this starts failing, the bug has been fixed.
//!
//! [#94]: https://github.com/TheBevyFlock/bevy_cli/issues/94
//@check-pass

#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::insert_event_resource)]

use bevy::prelude::*;

#[derive(Event)]
struct Foo;

fn main() {
let mut app = App::new();

// These both should error, but currently do not.
App::init_resource::<Events<Foo>>(&mut app);
App::insert_resource::<Events<Foo>>(&mut app, Default::default());
}
26 changes: 26 additions & 0 deletions bevy_lint/tests/ui/insert_event_resource/main.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::insert_event_resource)]

use bevy::prelude::*;

#[derive(Event)]
struct Foo;

fn main() {
App::new().add_event::<Foo>();
//~^ ERROR: called `App::init_resource::<Events<T>>()` instead of `App::add_event::<T>()`

App::new().add_event::<Foo>();
//~^ ERROR: called `App::insert_resource(Events<T>)` instead of `App::add_event::<T>()`

// Make sure the correct type is detected, even when not explicitly passed to
// `insert_resource()`.
let implied_event: Events<Foo> = Default::default();
App::new().add_event::<Foo>();
//~^ ERROR: called `App::insert_resource(Events<T>)` instead of `App::add_event::<T>()`

// Ensure the lint can be muted by annotating the expression.
#[allow(bevy::insert_event_resource)]
App::new().init_resource::<Events<Foo>>();
}
26 changes: 26 additions & 0 deletions bevy_lint/tests/ui/insert_event_resource/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::insert_event_resource)]

use bevy::prelude::*;

#[derive(Event)]
struct Foo;

fn main() {
App::new().init_resource::<Events<Foo>>();
//~^ ERROR: called `App::init_resource::<Events<T>>()` instead of `App::add_event::<T>()`

App::new().insert_resource::<Events<Foo>>(Default::default());
//~^ ERROR: called `App::insert_resource(Events<T>)` instead of `App::add_event::<T>()`

// Make sure the correct type is detected, even when not explicitly passed to
// `insert_resource()`.
let implied_event: Events<Foo> = Default::default();
App::new().insert_resource(implied_event);
//~^ ERROR: called `App::insert_resource(Events<T>)` instead of `App::add_event::<T>()`

// Ensure the lint can be muted by annotating the expression.
#[allow(bevy::insert_event_resource)]
App::new().init_resource::<Events<Foo>>();
}
40 changes: 40 additions & 0 deletions bevy_lint/tests/ui/insert_event_resource/main.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error: called `App::init_resource::<Events<T>>()` instead of `App::add_event::<T>()`
--> tests/ui/insert_event_resource/main.rs:11:16
|
11 | App::new().init_resource::<Events<Foo>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> tests/ui/insert_event_resource/main.rs:3:9
|
3 | #![deny(bevy::insert_event_resource)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: inserting an `Events` resource does not fully setup that event
|
11 | App::new().add_event::<Foo>();
| ~~~~~~~~~~~~~~~~~~

error: called `App::insert_resource(Events<T>)` instead of `App::add_event::<T>()`
--> tests/ui/insert_event_resource/main.rs:14:16
|
14 | App::new().insert_resource::<Events<Foo>>(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: inserting an `Events` resource does not fully setup that event
|
14 | App::new().add_event::<Foo>();
| ~~~~~~~~~~~~~~~~~~

error: called `App::insert_resource(Events<T>)` instead of `App::add_event::<T>()`
--> tests/ui/insert_event_resource/main.rs:20:16
|
20 | App::new().insert_resource(implied_event);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: inserting an `Events` resource does not fully setup that event
|
20 | App::new().add_event::<Foo>();
| ~~~~~~~~~~~~~~~~~~

error: aborting due to 3 previous errors

20 changes: 20 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/bug_132.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! A version of `main.rs` where the lint is muted on the expression. Since this lint is run on
//! functions, it will still error.
//!
//! This test tracks the bug reported in [#132]. When this starts failing, the bug has been fixed.
//!
//! [#132]: https://github.com/TheBevyFlock/bevy_cli/issues/132
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

fn main() {
//~^ HELP: try

#[allow(bevy::main_return_without_appexit)]
App::new().run();
//~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit`
}
18 changes: 18 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/bug_132.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: an entrypoint that calls `App::run()` does not return `AppExit`
--> tests/ui/main_return_without_appexit/bug_132.rs:18:16
|
14 | fn main() {
| - help: try: `-> AppExit`
...
18 | App::new().run();
| ^^^^^
|
= note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not
note: the lint level is defined here
--> tests/ui/main_return_without_appexit/bug_132.rs:10:9
|
10 | #![deny(bevy::main_return_without_appexit)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

17 changes: 17 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/bug_87.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! This test tracks the bug reported in [#87]. When this starts failing, the bug has been fixed.
//!
//! [#87]: https://github.com/TheBevyFlock/bevy_cli/issues/87
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

fn main() {
// This should not raise an error, since `AppExit` is not ignored.
let app_exit = App::new().run();
//~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit`

println!("{app_exit:?}");
}
18 changes: 18 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/bug_87.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: an entrypoint that calls `App::run()` does not return `AppExit`
--> tests/ui/main_return_without_appexit/bug_87.rs:13:31
|
11 | fn main() {
| - help: try: `-> AppExit`
12 | // This should not raise an error, since `AppExit` is not ignored.
13 | let app_exit = App::new().run();
| ^^^^^
|
= note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not
note: the lint level is defined here
--> tests/ui/main_return_without_appexit/bug_87.rs:7:9
|
7 | #![deny(bevy::main_return_without_appexit)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

18 changes: 18 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/bug_94.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! This test tracks the bug reported in [#94]. When this starts failing, the bug has been fixed.
//!
//! [#94]: https://github.com/TheBevyFlock/bevy_cli/issues/94
//@check-pass

#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

fn main() {
let mut app = App::new();

// This should error because the `AppExit` is not handled, but it does not.
App::run(&mut app);
}
13 changes: 13 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! Tests the most basic version: where `main()` returns nothing and `AppExit` is not handled.
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

fn main() {
//~^ HELP: try
App::new().run();
//~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit`
}
18 changes: 18 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/main.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: an entrypoint that calls `App::run()` does not return `AppExit`
--> tests/ui/main_return_without_appexit/main.rs:11:16
|
9 | fn main() {
| - help: try: `-> AppExit`
10 |
11 | App::new().run();
| ^^^^^
|
= note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not
note: the lint level is defined here
--> tests/ui/main_return_without_appexit/main.rs:5:9
|
5 | #![deny(bevy::main_return_without_appexit)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

15 changes: 15 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/muted_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! A version of `main.rs` where the lint is muted on the function. This should pass without any
//! errors.
//@check-pass

#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

#[allow(bevy::main_return_without_appexit)]
fn main() {
App::new().run();
}
14 changes: 14 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/return_appexit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Tests when `main()` returns `AppExit`, meaning the user has fixed the lint. No diagnostics
//! should be emitted in this case.
//@check-pass

#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

fn main() -> AppExit {
App::new().run()
}
16 changes: 16 additions & 0 deletions bevy_lint/tests/ui/main_return_without_appexit/return_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Tests when `main()` returns a type other than the unit `()`. When this is done no lint is
//! emitted, since we assume the user knows what they're doing.
//@check-pass

#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::main_return_without_appexit)]

use bevy::prelude::*;

fn main() -> Result<(), ()> {
App::new().run();

Ok(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

use bevy::prelude::*;

fn main() {
fn main() -> () {
//~^ HELP: try
App::new().run();
//~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit`
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
error: an entrypoint that calls `App::run()` does not return `AppExit`
--> tests/ui/main_return_without_appexit.rs:8:16
--> tests/ui/main_return_without_appexit/return_unit.rs:9:16
|
7 | fn main() {
| - help: try: `-> AppExit`
8 | App::new().run();
7 | fn main() -> () {
| -- help: try: `AppExit`
8 |
9 | App::new().run();
| ^^^^^
|
= note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not
note: the lint level is defined here
--> tests/ui/main_return_without_appexit.rs:3:9
--> tests/ui/main_return_without_appexit/return_unit.rs:3:9
|
3 | #![deny(bevy::main_return_without_appexit)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
34 changes: 34 additions & 0 deletions bevy_lint/tests/ui/panicking_methods/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! This tests the `panicking_query_methods` lint, specifically when triggered on the `Query` type.
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::panicking_query_methods)]

use bevy::prelude::*;

#[derive(Component)]
struct Foo;

fn main() {
App::new().add_systems(Startup, my_system);
}

fn my_system(mut query: Query<&mut Foo>) {
query.single();
//~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists
//~| HELP: use `query.get_single()`

query.single_mut();
//~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists
//~| HELP: use `query.get_single_mut()`

let entities = [Entity::PLACEHOLDER; 3];

let [_, _, _] = query.many(entities);
//~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists
//~| HELP: use `query.get_many(entities)`

query.many_mut([]);
//~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists
//~| HELP: use `query.get_many_mut([])`
}
Loading

0 comments on commit 603a7c6

Please sign in to comment.