From 866fb0142752ba04552b717341eeb42c6d9bf008 Mon Sep 17 00:00:00 2001 From: Fomegne Brady Date: Thu, 29 Jun 2023 19:49:29 +0100 Subject: [PATCH] test(clafrica): implement a test sandbox (#47) --- .github/workflows/coverage.yml | 8 +- .github/workflows/rust.yml | 6 +- Cargo.lock | 24 +++++- clafrica/Cargo.toml | 3 + clafrica/data/test.toml | 18 +++++ clafrica/src/lib.rs | 129 ++++++++++++++++++++++++++++++++- 6 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 clafrica/data/test.toml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 421bf20..8c8a6c8 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -13,6 +13,8 @@ env: jobs: coverage: runs-on: ubuntu-latest + env: + DISPLAY: ':99' steps: - uses: actions/checkout@v3 - uses: awalsh128/cache-apt-pkgs-action@latest @@ -20,6 +22,10 @@ jobs: packages: libxtst-dev libevdev-dev libxdo-dev version: 1.0 + - name: Setup headless environment + run: | + Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + - name: Dependencies run: | sudo apt-get install libxtst-dev libevdev-dev libxdo-dev --assume-yes @@ -57,7 +63,7 @@ jobs: --branch \ --ignore-not-existing \ --ignore "/*" \ - --ignore "clafrica/src/{lib,main}.rs" \ + --ignore "clafrica/src/{main}.rs" \ --excl-line "#\\[derive\\(" \ -o ./coverage/lcov.info diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 775265b..43e27cc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,6 +22,8 @@ jobs: include: - os: ubuntu-latest headless: Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + - os: macos-latest + extra: -- --skip test_simple steps: - uses: actions/checkout@v3 @@ -51,5 +53,5 @@ jobs: - name: Run tests run: | - cargo test --all-features --lib --bins --tests --verbose - cargo test --benches + cargo test --all-features --lib --bins --tests --verbose ${{matrix.extra}} + cargo test --benches ${{matrix.extra}} diff --git a/Cargo.lock b/Cargo.lock index 062aea5..c6e1f86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,18 +22,19 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "clafrica" -version = "0.2.2" +version = "0.3.0" dependencies = [ "clafrica-lib", "enigo", "rdev", + "rstk", "serde", "toml", ] [[package]] name = "clafrica-lib" -version = "0.2.0" +version = "0.3.0" [[package]] name = "cocoa" @@ -183,9 +184,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "malloc_buf" @@ -211,6 +212,12 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + [[package]] name = "pkg-config" version = "0.3.26" @@ -251,6 +258,15 @@ dependencies = [ "x11", ] +[[package]] +name = "rstk" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f01d34f6758044cb899a4ecfd766df0fceb544ecff346d18f84523ee71e07442" +dependencies = [ + "once_cell", +] + [[package]] name = "serde" version = "1.0.163" diff --git a/clafrica/Cargo.toml b/clafrica/Cargo.toml index 0a7684e..3443fc4 100644 --- a/clafrica/Cargo.toml +++ b/clafrica/Cargo.toml @@ -17,3 +17,6 @@ enigo = "0.1.2" rdev = "0.5.2" serde = { version = "1.0.163", features = ["serde_derive"] } toml = "0.7.3" + +[dev-dependencies] +rstk = "0.1.0" diff --git a/clafrica/data/test.toml b/clafrica/data/test.toml new file mode 100644 index 0000000..cef2007 --- /dev/null +++ b/clafrica/data/test.toml @@ -0,0 +1,18 @@ +# Test file + +[info] +name = "Test code" +description = "Test code for testing purpose." + +[core] +buffer_size = 128 + +[data] +af = "ɑ" +af3 = "ɑ̄" +aff = "ɑɑ" +aff3 = "ɑ̄ɑ̄" +cc = { value = "ç", alias = ["ccced"]} +uu = "ʉ" +uu3 = "ʉ̄" +uuaf3 = "ʉ̄ɑ̄" diff --git a/clafrica/src/lib.rs b/clafrica/src/lib.rs index fe562b5..912b473 100644 --- a/clafrica/src/lib.rs +++ b/clafrica/src/lib.rs @@ -141,4 +141,131 @@ pub fn run(config: config::Config, mut frontend: impl Frontend) -> Result<(), io } #[cfg(test)] -mod tests {} +mod tests { + use crate::{api, config::Config, run}; + use rdev::{self, Button, EventType::*, Key::*}; + use rstk::{self, TkPackLayout}; + use std::{thread, time::Duration}; + + macro_rules! input { + ( $( $key:expr )*, $delay:expr ) => ( + $( + thread::sleep($delay); + rdev::simulate(&KeyPress($key)).unwrap(); + thread::sleep($delay); + rdev::simulate(&KeyRelease($key)).unwrap(); + )* + ); + } + + macro_rules! output { + ( $textfield: expr, $expected: expr ) => { + // A loop to be sure to got something stable + loop { + let a = $textfield.get_to_end((1, 0)); + let b = $textfield.get_to_end((1, 0)); + + if (a == b) { + let content = a.chars().filter(|c| *c != '\0').collect::(); + let content = content.trim(); + + assert_eq!(content, $expected); + break; + } + } + }; + } + + fn start_clafrica() { + use std::path::Path; + + let test_config = Config::from_file(Path::new("./data/test.toml")).unwrap(); + + thread::spawn(move || { + run(test_config, api::Console).unwrap(); + }); + } + + fn start_sandbox() -> rstk::TkText { + let root = rstk::trace_with("wish").unwrap(); + root.title("Clafrica Test Environment"); + let input_field = rstk::make_text(&root); + input_field.width(50); + input_field.height(12); + input_field.pack().layout(); + root.geometry(200, 200, 0, 0); + rstk::tell_wish( + r#" + bind . { destroy . }; + chan configure stdout -encoding utf-8; + "#, + ); + thread::sleep(Duration::from_secs(1)); + input_field + } + + #[test] + fn test_simple() { + let typing_speed_ms = Duration::from_millis(300); + + // To detect excessive backspace + const LIMIT: &str = "bbb"; + + // Start the clafrica + start_clafrica(); + + // Start the sandbox + let textfield = start_sandbox(); + + rdev::simulate(&MouseMove { x: 100.0, y: 100.0 }).unwrap(); + thread::sleep(typing_speed_ms); + rdev::simulate(&ButtonPress(Button::Left)).unwrap(); + thread::sleep(typing_speed_ms); + rdev::simulate(&ButtonRelease(Button::Left)).unwrap(); + thread::sleep(typing_speed_ms); + + input!(KeyB KeyB KeyB Escape, typing_speed_ms); + + input!(KeyU Backspace KeyU KeyU Backspace KeyU, typing_speed_ms); + + input!(KeyC KeyC KeyC KeyE KeyD, typing_speed_ms); + input!(KeyU KeyU KeyA KeyF, typing_speed_ms); + + input!(CapsLock, typing_speed_ms); + input!(Num3, typing_speed_ms); + input!(CapsLock, typing_speed_ms); + + input!(KeyA KeyF KeyA KeyF, typing_speed_ms); + input!(KeyA KeyF KeyF, typing_speed_ms); + + input!(CapsLock, typing_speed_ms); + input!(Num3, typing_speed_ms); + input!(CapsLock, typing_speed_ms); + + input!(KeyU KeyU, typing_speed_ms); + + input!(CapsLock, typing_speed_ms); + input!(Num3, typing_speed_ms); + input!(CapsLock, typing_speed_ms); + + output!(textfield, format!("{LIMIT}uçʉ̄ɑ̄ɑɑɑ̄ɑ̄ʉ̄")); + + // To verify that the undo (backspace) work as expected + (0..12).for_each(|_| { + input!(Backspace, typing_speed_ms); + }); + + output!(textfield, LIMIT); + + input!(Escape, typing_speed_ms); + + input!(ControlLeft ControlLeft, typing_speed_ms); + input!(KeyA KeyF, typing_speed_ms); + input!(ControlLeft ControlLeft, typing_speed_ms); + input!(KeyA KeyF, typing_speed_ms); + + output!(textfield, format!("{LIMIT}afɑ")); + + rstk::end_wish(); + } +}