Skip to content

Commit

Permalink
Add generated test for statics
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jan 10, 2025
1 parent c76799e commit 9c07a2f
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 26 deletions.
21 changes: 21 additions & 0 deletions crates/header-translator/src/availability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,27 @@ impl Availability {
Ok(())
}))
}

// Used when testing
pub fn is_available_host(&self) -> bool {
if self.unavailable.macos {
return false;
}
if let Some(macos) = self.introduced.macos {
// Disable test if introduced later than my current OS.
// TODO: Use `available!` macro here.
if 14 < macos.x {
return false;
}
}
// Disable test if deprecated.
// Fixes `MLModelCollectionDidChangeNotification` not linking (it is
// only marked as unavailable if the deployment target is macOS 15.0).
if self.deprecated.macos.is_some() {
return false;
}
true
}
}

impl fmt::Display for Availability {
Expand Down
23 changes: 22 additions & 1 deletion crates/header-translator/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,19 @@ impl Module {
.filter_map(|stmt| stmt.encoding_test(config))
.collect();

if !encoding_tests.is_empty() {
let static_tests: Vec<_> = self
.stmts
.iter()
.filter_map(|stmt| stmt.static_test(config))
.collect();

if !encoding_tests.is_empty() || !static_tests.is_empty() {
writeln!(f)?;

writeln!(f, "use test_frameworks::*;")?;
}

if !encoding_tests.is_empty() {
writeln!(f)?;

writeln!(f, "#[test]")?;
Expand All @@ -323,6 +331,19 @@ impl Module {
writeln!(f, "}}")?;
}

if !static_tests.is_empty() {
writeln!(f)?;

writeln!(f, "#[test]")?;
writeln!(f, "fn test_statics() {{")?;

for test in static_tests {
write!(f, "{test}")?;
}

writeln!(f, "}}")?;
}

Ok(())
})
}
Expand Down
95 changes: 70 additions & 25 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use clang::{Entity, EntityKind, EntityVisitResult};

use crate::availability::Availability;
use crate::cfgs::PlatformCfg;
use crate::config::{ClassData, MethodData};
use crate::config::{ClassData, Config, LibraryConfig, MethodData};
use crate::context::Context;
use crate::display_helper::FormatterFn;
use crate::documentation::Documentation;
Expand All @@ -26,7 +26,6 @@ use crate::name_translation::split_words;
use crate::rust_type::Ty;
use crate::thread_safety::ThreadSafety;
use crate::unexposed_attr::UnexposedAttr;
use crate::Config;

#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Derives(Cow<'static, str>);
Expand Down Expand Up @@ -2932,27 +2931,6 @@ impl Stmt {
}

pub(crate) fn encoding_test<'a>(&'a self, config: &'a Config) -> Option<impl Display + 'a> {
let simple_platform_gate =
|data, required_items: &[ItemIdentifier], implied_items: &[ItemIdentifier]| {
let mut platform_cfg = PlatformCfg::from_config(data);

for item in required_items {
platform_cfg.dependency(config.library(item.library_name()));
}

for item in implied_items {
platform_cfg.implied(config.library(item.library_name()));
}

FormatterFn(move |f| {
if let Some(cfg) = platform_cfg.cfgs() {
writeln!(f, "#[cfg({cfg})]")?;
}

Ok(())
})
};

let (data, availability, cls, cls_required_items, cls_generics, methods) = match self {
Stmt::ExternMethods {
location,
Expand Down Expand Up @@ -2993,7 +2971,7 @@ impl Stmt {
write!(
f,
"{}",
simple_platform_gate(data, cls_required_items, &[],)
simple_platform_gate(data, cls_required_items, &[], config)
)?;
if let Some(check) = availability.check_is_available() {
writeln!(f, " if {check} ")?;
Expand All @@ -3014,7 +2992,12 @@ impl Stmt {
write!(
f,
"{}",
simple_platform_gate(data, &method.required_items(), cls_required_items,)
simple_platform_gate(
data,
&method.required_items(),
cls_required_items,
config
)
)?;
write!(f, "{}", method.encoding_test(false))?;
}
Expand All @@ -3024,4 +3007,66 @@ impl Stmt {
Ok(())
}))
}

pub(crate) fn static_test<'a>(&'a self, config: &'a Config) -> Option<impl Display + 'a> {
match self {
Self::VarDecl {
id,
availability,
ty,
value: None,
..
} => {
if !availability.is_available_host() {
return None;
}
Some(FormatterFn(|f| {
write!(
f,
"{}",
simple_platform_gate(
config.library(id.library_name()),
&ty.required_items(),
&[],
config,
)
)?;
let ty = ty.var().to_string();
if ty.starts_with("&'static") {
writeln!(f, " check_static_nonnull(unsafe {{ {} }});", id.path())?;
} else {
writeln!(f, " let _ = unsafe {{ {} }};", id.path())?;
}

Ok(())
}))
}
_ => None,
}
}
}

fn simple_platform_gate(
data: &LibraryConfig,
required_items: &[ItemIdentifier],
implied_items: &[ItemIdentifier],
config: &Config,
) -> impl Display {
let mut platform_cfg = PlatformCfg::from_config(data);

for item in required_items {
platform_cfg.dependency(config.library(item.library_name()));
}

for item in implied_items {
platform_cfg.implied(config.library(item.library_name()));
}

FormatterFn(move |f| {
if let Some(cfg) = platform_cfg.cfgs() {
writeln!(f, "#[cfg({cfg})]")?;
}

Ok(())
})
}
14 changes: 14 additions & 0 deletions crates/test-frameworks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub use core::ffi::{
c_ulong, c_ulonglong, c_ushort, c_void,
};
pub use core::ptr::NonNull;
#[cfg(feature = "test-frameworks")]
pub use dispatch2::ffi::*;
pub use libc;
pub use objc2::ffi::{NSInteger, NSUInteger};
pub use objc2::rc::{Allocated, Retained};
Expand All @@ -28,6 +30,10 @@ pub use objc2::runtime::{
};
pub use objc2::{available, sel, ClassType, MainThreadMarker};

// Fix kODAuthenticationTypeClearTextReadOnly linking
#[link(name = "odmodule", kind = "dylib")]
extern "C" {}

// MacTypes.h
pub type OSStatus = i32;
pub type Byte = u8;
Expand Down Expand Up @@ -73,6 +79,14 @@ pub fn check_method<Arguments: EncodeArguments, Return: EncodeReturn>(
// );
}

#[track_caller]
pub fn check_static_nonnull<T: ?Sized>(var: &T) {
let ptr: *const T = var;
if ptr.is_null() {
panic!("static was marked as NonNull, so it must not be NULL");
}
}

#[test]
fn smoke_test_encoding() {
let encoding = if cfg!(target_pointer_width = "64") {
Expand Down

0 comments on commit 9c07a2f

Please sign in to comment.