diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/windows-implement/src/tests.rs | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/windows-implement/src/tests.rs')
| -rw-r--r-- | vendor/windows-implement/src/tests.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/vendor/windows-implement/src/tests.rs b/vendor/windows-implement/src/tests.rs new file mode 100644 index 00000000..3f5c3493 --- /dev/null +++ b/vendor/windows-implement/src/tests.rs @@ -0,0 +1,135 @@ +//! These tests are just a way to quickly run the `#[implement]` macro and see its output. +//! They don't check the output in any way. +//! +//! This exists because of some difficulties of running `cargo expand` against the `#[implement]` +//! macro. It's also just really convenient. You can see the output by using `--nocapture` and +//! you'll probably want to restrict the output to a single thread: +//! +//! ```text +//! cargo test -p windows-implement --lib -- --nocapture --test-threads=1 +//! ``` + +use std::io::{Read, Write}; +use std::process::{Command, Stdio}; + +use proc_macro2::TokenStream; +use quote::quote; + +fn implement(attributes: TokenStream, item_tokens: TokenStream) -> String { + let out_tokens = crate::implement_core(attributes, item_tokens); + let tokens_string = out_tokens.to_string(); + + let out_string = rustfmt(&tokens_string); + println!("// output of #[implement] :"); + println!(); + println!("{}", out_string); + out_string +} + +fn rustfmt(input: &str) -> String { + let mut rustfmt = Command::new("rustfmt"); + + rustfmt.stdin(Stdio::piped()); + rustfmt.stdout(Stdio::piped()); + rustfmt.stderr(Stdio::inherit()); + + let mut child = match rustfmt.spawn() { + Ok(c) => c, + Err(e) => { + eprintln!("failed to spawn rustfmt: {e:?}"); + return input.to_string(); + } + }; + + let mut stdout = child.stdout.take().unwrap(); + + // spawn thread to read stdout + let stdout_thread = std::thread::spawn(move || { + let mut buf = String::new(); + stdout.read_to_string(&mut buf).unwrap(); + buf + }); + + // write unformatted into stdin + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(input.as_bytes()).unwrap(); + drop(stdin); + + let stdout_string: String = stdout_thread.join().unwrap(); + + let exit = child.wait().unwrap(); + if !exit.success() { + eprintln!("rustfmt terminated with failure status code"); + return input.to_string(); + } + + stdout_string +} + +#[test] +fn simple_type() { + implement( + quote!(IFoo), + quote! { + struct Foo { + x: u32, + } + }, + ); +} + +#[test] +fn zero_sized_type() { + implement( + quote!(IFoo), + quote! { + struct Foo; + }, + ); +} + +#[test] +fn no_interfaces() { + implement( + quote!(), + quote! { + struct Foo {} + }, + ); +} + +#[test] +fn generic_no_lifetime() { + implement( + quote!(IAsyncOperationWithProgress<T, P>, IAsyncInfo), + quote! { + struct OperationWithProgress<T, P>(SyncState<IAsyncOperationWithProgress<T, P>>) + where + T: RuntimeType + 'static, + P: RuntimeType + 'static; + + }, + ); +} + +#[test] +fn generic_with_lifetime() { + implement( + quote!(), + quote! { + pub struct Foo<'a> { + pub x: &'a [u8], + } + }, + ); +} + +#[test] +fn tuple_type() { + implement( + quote!(IFoo), + quote! { + struct Foo(pub i32); + }, + ); +} |
