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

[Merged by Bors] - Make Time::update_with_instant public for use in tests #4469

Closed
wants to merge 6 commits into from
Closed

[Merged by Bors] - Make Time::update_with_instant public for use in tests #4469

wants to merge 6 commits into from

Conversation

mdickopp
Copy link
Contributor

Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock Time. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to #2549 by @ostwilkens and based on his work.

Solution

To mock Time, one needs to be able to manually update the Time resource with an Instant defined by the developer. This can be achieved by making the existing Time::update_with_instant method public for use in tests.

Changelog

  • Make Time::update_with_instant public
  • Add doc to Time::update_with_instant clarifying that the method should not be called outside of tests.
  • Add doc test to Time demonstrating how to use update_with_instant in tests.

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Apr 13, 2022
@alice-i-cecile alice-i-cecile added A-Core C-Usability A targeted quality-of-life change that makes Bevy easier to use and removed S-Needs-Triage This issue needs to be labelled labels Apr 13, 2022
@alice-i-cecile alice-i-cecile self-requested a review April 13, 2022 19:30
Comment on lines 82 to 87
/// Update time with a specified [`Instant`]
///
/// This method is for use in tests, and should generally not be called on the [`Time`] resource
/// as part of your app. Doing so will conflict with the `time_system` called by
/// [`CorePlugin`](crate::CorePlugin), and result in inaccurate performance measurements.
pub fn update_with_instant(&mut self, instant: Instant) {
Copy link
Member

@mockersf mockersf Apr 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Update time with a specified [`Instant`]
///
/// This method is for use in tests, and should generally not be called on the [`Time`] resource
/// as part of your app. Doing so will conflict with the `time_system` called by
/// [`CorePlugin`](crate::CorePlugin), and result in inaccurate performance measurements.
pub fn update_with_instant(&mut self, instant: Instant) {
/// Update time with a specified [`Instant`]
///
/// This method is for use in tests, and should generally not be called on the [`Time`] resource
/// as part of your app. Doing so will conflict with the `time_system` called by
/// [`CorePlugin`](crate::CorePlugin), and result in inaccurate performance measurements.
#[cfg(test)]
pub fn manual_update_with_instant(&mut self, instant: Instant) {
self.update_with_instant(instant);
}
pub(crate) fn update_with_instant(&mut self, instant: Instant) {

not sure this is a good idea, but it would make it impossible to mess with time. Doc comment above would need to be updated too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I don't think this actually adds much more safety. I think that aggressive doc warnings should be sufficient here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[cfg(test)] hides the method from the new doctest. And #[cfg(doctest)] does not work here due to a bug in cargo (rust-lang/rust#67295). Any ideas how this could be solved?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mockersf, I agree with @alice-i-cecile. Is it acceptable to you to leave the patch unchanged?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[cfg(test)] only applies when testing the current crate, not when testing a dependent crate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's acceptable, even more with Bjorn3 remark! (we already had this discussion on another place, and I keep forgetting that...).

It's not something I wanted to block on anyway

@mdickopp
Copy link
Contributor Author

I see two options, either leave the patch unchanged, or add the #[cfg(test)] attribute and remove the doctest. Please let me know what you prefer.

Instead of removing the code in the doctest entirely, I would transform it into an example.

@alice-i-cecile
Copy link
Member

My preference is for the former: I don't think the API is so dangerous that we need to hide it.

@mdickopp mdickopp changed the title Make Time::update_with_instant public for use in tests Make Time::update_with_instant public for use in tests Apr 17, 2022
@mdickopp
Copy link
Contributor Author

@mockersf, do you require code changes?

@alice-i-cecile
Copy link
Member

@maniwani are you on board with merging this? I saw you mention it on Discord, and want your opinion.

Copy link
Contributor

@maniwani maniwani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maniwani are you on board with merging this?

Yeah, I'm cool with making this method pub. Nothing was stopping someone from calling Time::update before.

A couple tiny nits. Also you should probably have the note saying the CorePlugin is usually in charge on the update doc as well.

Comment on lines 84 to 86
/// This method is for use in tests, and should generally not be called on the [`Time`] resource
/// as part of your app. Doing so will conflict with the `time_system` called by
/// [`CorePlugin`](crate::CorePlugin), and result in inaccurate performance measurements.
Copy link
Contributor

@maniwani maniwani Apr 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// This method is for use in tests, and should generally not be called on the [`Time`] resource
/// as part of your app. Doing so will conflict with the `time_system` called by
/// [`CorePlugin`](crate::CorePlugin), and result in inaccurate performance measurements.
/// This method is provided for use in tests. Calling this method on the [`Time`] resource as part of your app
/// will most likely result in inaccurate timekeeping, as the resource is ordinarily managed by the [`CorePlugin`](crate::CorePlugin).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion! I updated the documentation accordingly.

Copy link
Contributor

@maniwani maniwani Apr 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the second sentence ("Calling this...") as a disclaimer to Time::update as well?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, agreed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Done!

Comment on lines 8 to 50
/// ```
/// # use bevy_core::prelude::*;
/// # use bevy_ecs::prelude::*;
/// # use bevy_utils::Duration;
/// # fn main () {
/// # test_health_system();
/// # }
/// struct Health {
/// // Health value between 0.0 and 1.0
/// health_value: f32,
/// }
///
/// fn health_system(time: Res<Time>, mut health: ResMut<Health>) {
/// // Increase health value by 0.1 per second, independent of frame rate,
/// // but not beyond 1.0
/// health.health_value = (health.health_value + 0.1 * time.delta_seconds()).min(1.0);
/// }
///
/// // Mock time in tests
/// fn test_health_system() {
/// let mut world = World::default();
/// let mut time = Time::default();
/// time.update();
/// world.insert_resource(time);
/// world.insert_resource(Health { health_value: 0.2 });
///
/// let mut update_stage = SystemStage::single_threaded();
/// update_stage.add_system(health_system);
///
/// // Simulate that 30 ms have passed
/// let mut time = world.get_resource_mut::<Time>().unwrap();
/// let last_update = time.last_update().unwrap();
/// time.update_with_instant(last_update + Duration::from_millis(30));
///
/// // Run system
/// update_stage.run(&mut world);
///
/// // Check that 0.003 has been added to the health value
/// let expected_health_value = 0.2 + 0.1 * 0.03;
/// let actual_health_value = world.get_resource::<Health>().unwrap().health_value;
/// assert_eq!(expected_health_value, actual_health_value);
/// }
/// ```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest moving this doc test to update_with_instant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the doc test,and I also replaced world.get_resource_mut::<Time>().unwrap() with the simpler world.resource_mut::<Time>().

@mdickopp
Copy link
Contributor Author

I'm confused by the CI failure, as I didn't change any markdown documents. Any advice would be appreciated.

@alice-i-cecile
Copy link
Member

This is just a flaky CI failure @mdickopp, don't worry about it.

@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Apr 24, 2022
# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to #2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
@bors
Copy link
Contributor

bors bot commented Apr 24, 2022

Build failed:

@alice-i-cecile
Copy link
Member

bors retry

bors bot pushed a commit that referenced this pull request Apr 24, 2022
# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to #2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
@bors
Copy link
Contributor

bors bot commented Apr 24, 2022

Build failed:

@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Apr 24, 2022
# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to #2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
@bors
Copy link
Contributor

bors bot commented Apr 24, 2022

Build failed:

@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Apr 24, 2022
# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to #2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
@bors
Copy link
Contributor

bors bot commented Apr 24, 2022

Timed out.

@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Apr 24, 2022
# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to #2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
@bors bors bot changed the title Make Time::update_with_instant public for use in tests [Merged by Bors] - Make Time::update_with_instant public for use in tests Apr 24, 2022
@bors bors bot closed this Apr 24, 2022
@mdickopp
Copy link
Contributor Author

Thanks!

@mdickopp mdickopp deleted the pub_update_with_instant branch April 25, 2022 07:47
exjam pushed a commit to exjam/bevy that referenced this pull request May 22, 2022
…4469)

# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to bevyengine#2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
tgecho pushed a commit to tgecho/bevy that referenced this pull request Jun 16, 2022
…4469)

# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to bevyengine#2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests.

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.

Co-authored-by: Martin Dickopp <[email protected]>
(cherry picked from commit 93cee3b)
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
…4469)

# Objective

To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent.

This is a follow-up PR to bevyengine#2549 by @ostwilkens and based on his work.

## Solution

To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. 

## Changelog

- Make `Time::update_with_instant` public
- Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests.
- Add doc test to `Time` demonstrating how to use `update_with_instant` in tests.


Co-authored-by: Martin Dickopp <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-Usability A targeted quality-of-life change that makes Bevy easier to use
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants