mirror of
https://github.com/danbulant/cushy
synced 2026-07-06 11:40:37 +00:00
Trying to make Mac CI fail gracefully
This message may be repeated multiple times as I work on the CI configuration. Refs #129
This commit is contained in:
parent
5556d2ea6d
commit
d7fde0815f
5 changed files with 96 additions and 33 deletions
9
.github/workflows/rust.yml
vendored
9
.github/workflows/rust.yml
vendored
|
|
@ -45,4 +45,11 @@ jobs:
|
||||||
# fixed purely by updating the rust version.
|
# fixed purely by updating the rust version.
|
||||||
if: matrix.version == 'stable'
|
if: matrix.version == 'stable'
|
||||||
run: |
|
run: |
|
||||||
cargo test --all-features --all-targets
|
cargo test --all-features --all-targets -- --nocapture
|
||||||
|
env:
|
||||||
|
# When running on Mac OS CI, it's pretty common to not get an adapter
|
||||||
|
# returned. We don't want errors specifically caused by not being able
|
||||||
|
# to create a wgpu Adapter to cause unit test failures on CI. Long
|
||||||
|
# term it would be nice to have a reliable way to run Mac CI with a
|
||||||
|
# GPU adapter available.
|
||||||
|
NO_ADAPTER: ${{ matris.os == "macos-stable" && "github-ci" || "" }}
|
||||||
|
|
@ -2,35 +2,33 @@ use std::time::Duration;
|
||||||
|
|
||||||
use cushy::animation::easings::EaseInOutSine;
|
use cushy::animation::easings::EaseInOutSine;
|
||||||
use cushy::widget::MakeWidget;
|
use cushy::widget::MakeWidget;
|
||||||
|
use cushy::window::VirtualRecorderError;
|
||||||
use figures::units::Px;
|
use figures::units::Px;
|
||||||
use figures::{Point, Size};
|
use figures::{Point, Size};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod shared;
|
||||||
|
|
||||||
fn ui() -> impl MakeWidget {
|
fn ui() -> impl MakeWidget {
|
||||||
"Hello World".into_button().centered()
|
"Hello World".into_button().centered()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), VirtualRecorderError> {
|
||||||
let mut recorder = ui()
|
let mut recorder = ui().build_recorder().size(Size::new(320, 240)).finish()?;
|
||||||
.build_recorder()
|
|
||||||
.size(Size::new(320, 240))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let initial_point = Point::new(Px::new(140), Px::new(150));
|
let initial_point = Point::new(Px::new(140), Px::new(150));
|
||||||
recorder.set_cursor_position(initial_point);
|
recorder.set_cursor_position(initial_point);
|
||||||
recorder.set_cursor_visible(true);
|
recorder.set_cursor_visible(true);
|
||||||
recorder.refresh().unwrap();
|
recorder.refresh()?;
|
||||||
let mut animation = recorder.record_animated_png(60);
|
let mut animation = recorder.record_animated_png(60);
|
||||||
animation
|
animation.animate_cursor_to(
|
||||||
.animate_cursor_to(
|
Point::new(Px::new(160), Px::new(120)),
|
||||||
Point::new(Px::new(160), Px::new(120)),
|
Duration::from_millis(250),
|
||||||
Duration::from_millis(250),
|
EaseInOutSine,
|
||||||
EaseInOutSine,
|
)?;
|
||||||
)
|
animation.wait_for(Duration::from_millis(500))?;
|
||||||
.unwrap();
|
animation.animate_cursor_to(initial_point, Duration::from_millis(250), EaseInOutSine)?;
|
||||||
animation.wait_for(Duration::from_millis(500)).unwrap();
|
animation.wait_for(Duration::from_millis(500))?;
|
||||||
animation
|
animation.write_to("examples/offscreen-apng.png")
|
||||||
.animate_cursor_to(initial_point, Duration::from_millis(250), EaseInOutSine)
|
|
||||||
.unwrap();
|
|
||||||
animation.wait_for(Duration::from_millis(500)).unwrap();
|
|
||||||
animation.write_to("examples/offscreen-apng.png").unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adapter_required_test!(main);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use cushy::widget::MakeWidget;
|
use cushy::widget::MakeWidget;
|
||||||
|
use cushy::window::VirtualRecorderError;
|
||||||
use figures::Size;
|
use figures::Size;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod shared;
|
||||||
|
|
||||||
fn ui() -> impl MakeWidget {
|
fn ui() -> impl MakeWidget {
|
||||||
"Hello World".into_button().centered()
|
"Hello World".into_button().centered()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), VirtualRecorderError> {
|
||||||
// The default recorder generated solid, rgb images.
|
// The default recorder generated solid, rgb images.
|
||||||
let recorder = ui()
|
let recorder = ui().build_recorder().size(Size::new(320, 240)).finish()?;
|
||||||
.build_recorder()
|
|
||||||
.size(Size::new(320, 240))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
recorder.image().save("examples/offscreen.png").unwrap();
|
recorder.image().save("examples/offscreen.png").unwrap();
|
||||||
|
|
||||||
// Creating a recorder with alpha makes the virtual window transparent.
|
// Creating a recorder with alpha makes the virtual window transparent.
|
||||||
|
|
@ -19,12 +19,9 @@ fn main() {
|
||||||
.build_recorder()
|
.build_recorder()
|
||||||
.with_alpha()
|
.with_alpha()
|
||||||
.size(Size::new(320, 240))
|
.size(Size::new(320, 240))
|
||||||
.finish()
|
.finish()?;
|
||||||
.unwrap();
|
|
||||||
recorder.image().save("examples/offscreen.png").unwrap();
|
recorder.image().save("examples/offscreen.png").unwrap();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
adapter_required_test!(main);
|
||||||
fn runs() {
|
|
||||||
main();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
39
examples/shared/mod.rs
Normal file
39
examples/shared/mod.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
/// This macro creates a unit test that calls the named function, and
|
||||||
|
/// potentially ignores a `NoAdapter` error.
|
||||||
|
///
|
||||||
|
/// # Background
|
||||||
|
///
|
||||||
|
/// On GitHub CI, it seems fairly common for the MacOS runners to be configured
|
||||||
|
/// in such a way that wgpu returns no adapters from a request with the default
|
||||||
|
/// settings. The default settings appear to imply as high of flexibility as
|
||||||
|
/// possible, and sometimes the runners succeed in returning an adapter.
|
||||||
|
///
|
||||||
|
/// Because of these spurious failures, this macro checks for the environment
|
||||||
|
/// variable `NO_ADAPTER`. If it is set to a value, a warning will be printed
|
||||||
|
/// instead of panicking.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! adapter_required_test {
|
||||||
|
($name:ident) => {
|
||||||
|
#[test]
|
||||||
|
fn runs() {
|
||||||
|
let no_adapter_setting = std::env::var("NO_ADAPTER");
|
||||||
|
match ($name(), no_adapter_setting) {
|
||||||
|
(Ok(()), _) => {}
|
||||||
|
(Err(cushy::window::VirtualRecorderError::NoAdapter), Ok(no_adapter))
|
||||||
|
if !no_adapter.is_empty() =>
|
||||||
|
{
|
||||||
|
let prefix = match no_adapter.as_ref() {
|
||||||
|
"github-ci" => "::warning::",
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
|
println!(
|
||||||
|
"{prefix}Ignoring {}:{}: no graphics adapters available",
|
||||||
|
file!(),
|
||||||
|
stringify!($name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(Err(err), _) => unreachable!("Error testing example: {err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -3607,6 +3607,28 @@ impl From<io::Error> for VirtualRecorderError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for VirtualRecorderError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
VirtualRecorderError::NoAdapter => {
|
||||||
|
f.write_str("no compatible graphics adapters were found")
|
||||||
|
}
|
||||||
|
VirtualRecorderError::RequestDevice(err) => {
|
||||||
|
write!(f, "error requesting graphics device: {err}")
|
||||||
|
}
|
||||||
|
VirtualRecorderError::TooLarge => {
|
||||||
|
f.write_str("the rendered surface is too large for this cpu architecture")
|
||||||
|
}
|
||||||
|
VirtualRecorderError::MapBuffer(err) => {
|
||||||
|
write!(f, "error reading rendered graphics data: {err}")
|
||||||
|
}
|
||||||
|
VirtualRecorderError::PngEncode(err) => write!(f, "error encoding png: {err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for VirtualRecorderError {}
|
||||||
|
|
||||||
/// A unique identifier of an input device.
|
/// A unique identifier of an input device.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum DeviceId {
|
pub enum DeviceId {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue