Skip to content

Commit

Permalink
wip: UI testing
Browse files Browse the repository at this point in the history
  • Loading branch information
usadson committed Feb 16, 2024
1 parent 4cf20a7 commit e77d39c
Show file tree
Hide file tree
Showing 13 changed files with 432 additions and 0 deletions.
143 changes: 143 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cargo-finestra/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ license.workspace = true
description.workspace = true

[dependencies]
clap = { version = "4.5.0", features = ["derive"] }
1 change: 1 addition & 0 deletions finestra/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ euclid = "0.22"
cacao = { version = "0.3", features = ["appkit"] }
objc_id = "0.1.1"
block = "0.1.6"
objc_exception = "0.1.2"

[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.52", features = [
Expand Down
15 changes: 15 additions & 0 deletions finestra/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (C) 2024 Tristan Gerritsen <tristan@thewoosh.org>
// All Rights Reserved.

fn main() {
#[cfg(all(target_os = "macos", test))]
configure_xctest();
}

#[cfg(all(target_os = "macos", test))]
fn configure_xctest() {
println!("cargo:rustc-link-lib=framework=XCTest");
println!("cargo:rustc-link-search=framework=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks/");

println!("cargo:rustc-env=DYLD_FRAMEWORK_PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks/");
}
3 changes: 3 additions & 0 deletions finestra/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ mod state;
mod views;
mod window;

#[cfg(test)]
pub mod test;

pub use self::app::*;
pub(crate) use self::layout::*;
pub use self::property::*;
Expand Down
4 changes: 4 additions & 0 deletions finestra/src/platform/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod extensions;
mod resources;
pub(crate) mod state;
mod window;
mod xctest;

pub(crate) use self::app::MacOSDelegate;
pub(crate) use self::appkit::*;
Expand All @@ -18,6 +19,9 @@ pub(crate) use self::resources::ToCacao;
pub(crate) use self::dynamic_wrapper::DynamicViewWrapper;
pub(crate) use self::dynamic_wrapper::LayoutExt;

#[cfg(test)]
pub(crate) use self::xctest::*;

use cacao::appkit::App as CacaoApp;

use crate::{App, AppDelegate};
Expand Down
60 changes: 60 additions & 0 deletions finestra/src/platform/macos/xctest/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2024 Tristan Gerritsen <tristan@thewoosh.org>
// All Rights Reserved.

mod xcuiapplication;
mod xcuiapplicationstate;

use std::{io::{stdout, Write}, sync::Once};

use cacao::{foundation::NSString, objc::runtime::Class};

pub(crate) use self::{
xcuiapplication::XCUIApplication,
xcuiapplicationstate::XCUIApplicationState,
};

const BUNDLE_LOAD: Once = Once::new();

pub(crate) fn load_xc_test_into_bundle() {
println!("LOADBUNDLE");

use cacao::objc::{class, msg_send, sel, sel_impl};
use cacao::objc::runtime::Object;
BUNDLE_LOAD.call_once(|| {
let result = unsafe {
objc_exception::r#try(|| {
let path = NSString::new("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework");
let xctest_framework: *const Object = msg_send![class!(NSBundle), bundleWithPath: &*path.objc];
let _: () = msg_send![xctest_framework, load];
})
};

if let Err(e) = result {
panic!("Failed to load bundle: {e:p}");
}
});

for class in Class::classes().into_iter() {
if !class.name().starts_with("XCTestConfiguration") { continue }
eprintln!("\n\nClass: {}", class.name());

for protocol in class.adopted_protocols().iter() {
eprintln!(" Protocol: {}", protocol.name());
}

for variable in class.instance_variables().iter() {
eprintln!(" Variable: {}", variable.name());
}

for method in class.instance_methods().iter() {
eprintln!(" Method: {}", method.name().name());
eprintln!(" Return Type: {}", method.return_type().as_str());
eprintln!(" Arguments: {}", method.arguments_count());
for i in 0..method.arguments_count() {
eprintln!(" * Argument {i}: {:?}", method.argument_type(i).map(|x| x.as_str().to_owned()).unwrap_or_default());
}
}
}

println!("done load");
}
57 changes: 57 additions & 0 deletions finestra/src/platform/macos/xctest/xcuiapplication.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (C) 2024 Tristan Gerritsen <tristan@thewoosh.org>
// All Rights Reserved.

use cacao::{foundation::{id, NSString, NSUInteger, NSURL}, objc::{class, msg_send, runtime::Class, sel, sel_impl}, utils::properties::ObjcProperty};

use super::XCUIApplicationState;

pub(crate) struct XCUIApplication {
objc: ObjcProperty,
}

impl XCUIApplication {
/// <https://developer.apple.com/documentation/xctest/xcuiapplication/2879413-initwithurl?language=objc>
pub fn init_with_url(uurl: &str) -> Self {
super::load_xc_test_into_bundle();

let url = NSString::new(uurl);
let obj: id = unsafe {
let url: id = msg_send![class!(NSURL), URLWithString:&*url];
println!("URL: {url:p} from \"{uurl}\"");

// let obj: id = msg_send![class!(XCUIApplication), new];
// let obj: id = msg_send![obj, initWithURL:url];
let obj: id = msg_send![class!(XCUIApplication), alloc];
let obj: id = msg_send![obj, initWithURL:url];
obj
};

Self {
objc: ObjcProperty::retain(obj),
}
}

pub fn activate(&self) {
let _: () = self.objc.get(|objc| unsafe {
msg_send![objc, activate]
});
}

pub fn state(&self) -> XCUIApplicationState {
let id: NSUInteger = self.objc.get(|objc| unsafe {
msg_send![
objc, state
]
});

id.into()
}
}

impl Drop for XCUIApplication {
fn drop(&mut self) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, terminate];
})
}
}
Loading

0 comments on commit e77d39c

Please sign in to comment.