diff --git a/Cargo.toml b/Cargo.toml index 8d248db68..cd30ed328 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -264,7 +264,9 @@ name = "window" resolver = "2" members = [ "dpi", + "it/common-tests", "it/gui-test", + "it/gui-test-runner", "run-wasm", ] @@ -279,3 +281,4 @@ async-io = "2.3.1" gui-test = { path = "it/gui-test" } mint = "0.5.6" serde = { version = "1", features = ["serde_derive"] } +winit = { path = "." } diff --git a/it/common-tests/Cargo.toml b/it/common-tests/Cargo.toml new file mode 100644 index 000000000..5cf9a765d --- /dev/null +++ b/it/common-tests/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "common-tests" +version = "0.1.0" +rust-version.workspace = true +repository.workspace = true +license.workspace = true +edition.workspace = true + +[dependencies] +gui-test.workspace = true +macro_rules_attribute = "0.2.0" +winit.workspace = true diff --git a/it/common-tests/src/main.rs b/it/common-tests/src/main.rs new file mode 100644 index 000000000..c3dab0e5d --- /dev/null +++ b/it/common-tests/src/main.rs @@ -0,0 +1,21 @@ +//! Run the test. + +use gui_test::{test, Harness}; +use macro_rules_attribute::apply; + +use winit::event_loop::EventLoop; + +#[apply(test)] +fn initialize(harness: &mut Harness) { + let _test = harness.test("startup/shutdown"); + + let evl = EventLoop::new().unwrap(); + evl.run(|_event, elwt| { + elwt.exit(); + }) + .unwrap(); +} + +gui_test::main! { + gui_test::remote::handler() +} diff --git a/it/gui-test-runner/Cargo.toml b/it/gui-test-runner/Cargo.toml new file mode 100644 index 000000000..2eeb4dbe4 --- /dev/null +++ b/it/gui-test-runner/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "gui-test-runner" +version = "0.1.0" +rust-version.workspace = true +repository.workspace = true +license.workspace = true +edition.workspace = true + +[dependencies] diff --git a/it/gui-test-runner/src/main.rs b/it/gui-test-runner/src/main.rs new file mode 100644 index 000000000..48cdb199f --- /dev/null +++ b/it/gui-test-runner/src/main.rs @@ -0,0 +1,59 @@ +//! Runner for the `gui-test` system. + +use std::env; +use std::process::{Command, Stdio}; + +fn main() { + let mut args = env::args(); + + // Get the test crate name. + let test_crate = args.nth(1).unwrap(); + + // Get the target. + let target_tag = args.next().unwrap(); + + // Split the target into the target and the tag. + let (target, tag) = { + let mut split = target_tag.splitn(1, ':'); + let target = split.next().unwrap(); + let tag = split.next(); + (target, tag) + }; + + // Get the current target. + let current_target = current_target(); + + // For now, we only support building for the current target. + assert_eq!(target, current_target); + assert!(tag.is_none()); + + // Just run the crate. + if !Command::new("cargo") + .args(["run", "-p", &test_crate]) + .output() + .unwrap() + .status + .success() + { + panic!("test failed"); + } +} + +/// Get the current target. +fn current_target() -> String { + let output = Command::new("rustc") + .arg("-vV") + .stdout(Stdio::piped()) + .output() + .unwrap(); + + // Look for the line that starts with "host". + let stdout = String::from_utf8(output.stdout).unwrap(); + for line in stdout.lines() { + if let Some(host) = line.strip_prefix("host: ") { + return host.to_string(); + } + } + + panic!("failed to find host: line in rustc output") +} diff --git a/it/gui-test/src/lib.rs b/it/gui-test/src/lib.rs index 880b98354..6a4e75b80 100644 --- a/it/gui-test/src/lib.rs +++ b/it/gui-test/src/lib.rs @@ -1,7 +1,7 @@ //! A testing framework that can be run remotely. -pub mod stream; pub mod remote; +pub mod stream; pub mod user; use serde::{Deserialize, Serialize}; @@ -23,7 +23,7 @@ pub use inventory as __inventory; macro_rules! main { ($handler:expr) => { fn main() { - $crate::__entry($harness) + $crate::__entry($handler) } }; } @@ -62,7 +62,7 @@ pub struct __TestStart { impl __TestStart { /// Create a new test start. #[doc(hidden)] - pub fn __new(name: &'static str, func: fn(&mut Harness)) -> Self { + pub const fn __new(name: &'static str, func: fn(&mut Harness)) -> Self { Self { name, func } } } @@ -290,6 +290,12 @@ pub trait TestHandler { fn handle_test(&mut self, event: TestEvent); } +impl TestHandler for Box { + fn handle_test(&mut self, event: TestEvent) { + (**self).handle_test(event) + } +} + /// An event produced by the test harness. #[derive(Debug, Serialize, Deserialize)] pub struct TestEvent { diff --git a/it/gui-test/src/remote.rs b/it/gui-test/src/remote.rs index 37154ce55..3316ef3f7 100644 --- a/it/gui-test/src/remote.rs +++ b/it/gui-test/src/remote.rs @@ -1,8 +1,8 @@ //! Create a test handler that can be run remotely. -use crate::TestHandler; use crate::stream::WriteHandler; use crate::user::UserHandler; +use crate::TestHandler; use std::env; use std::net::TcpStream; @@ -11,16 +11,17 @@ use std::net::TcpStream; pub fn handler() -> Box { // If GUI_TEST_UNIX_STREAM is enabled, use that as a Unix stream. #[cfg(unix)] - if let Some(stream_path) = env::var_os("GUI_TEST_UNIX_STREAM") - .filter(|s| !s.is_empty()) { - let stream = std::os::unix::net::UnixStream::connect(stream_path).expect("unable to connect to gui-test handler"); + if let Some(stream_path) = env::var_os("GUI_TEST_UNIX_STREAM").filter(|s| !s.is_empty()) { + let stream = std::os::unix::net::UnixStream::connect(stream_path) + .expect("unable to connect to gui-test handler"); return Box::new(WriteHandler::new(stream)); } // If GUI_TEST_TCP_STREAM is enabled, use that as a TCP stream. if let Some(tcp_ip) = env::var("GUI_TEST_TCP_STREAM") .ok() - .filter(|s| !s.is_empty()) { + .filter(|s| !s.is_empty()) + { let stream = TcpStream::connect(tcp_ip).unwrap(); return Box::new(WriteHandler::new(stream)); } diff --git a/it/gui-test/src/stream.rs b/it/gui-test/src/stream.rs index 18bf64d3f..f8fbeaa00 100644 --- a/it/gui-test/src/stream.rs +++ b/it/gui-test/src/stream.rs @@ -1,5 +1,5 @@ //! Write events to an output stream. -//! +//! //! The format is as follows: //! - First 8 bytes: big-endian length of payload. //! - Next {len} bytes: JSON payload to deserialize from. @@ -16,9 +16,7 @@ pub struct WriteHandler { impl WriteHandler { /// Create a new write handler. pub fn new(writer: W) -> Self { - Self { - writer - } + Self { writer } } }