use std::ffi::CStr;
use noesis_runtime::ffi::noesis_unbox_string;
use noesis_runtime::resources::{
ResourceDictionary, application_resources_contains, application_resources_present,
set_application_resources,
};
const MERGED_XAML: &str = r##"<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="Merged.Greeting">from-merged</sys:String>
</ResourceDictionary>"##;
const PARSED_XAML: &str = r##"<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="Parsed.Title">parsed-value</sys:String>
</ResourceDictionary>"##;
fn unbox(ptr: *mut std::ffi::c_void) -> Option<String> {
let s = unsafe { noesis_unbox_string(ptr) };
if s.is_null() {
return None;
}
Some(unsafe { CStr::from_ptr(s) }.to_string_lossy().into_owned())
}
#[test]
fn resource_dictionary_roundtrips() {
if let (Ok(name), Ok(key)) = (
std::env::var("NOESIS_LICENSE_NAME"),
std::env::var("NOESIS_LICENSE_KEY"),
) {
noesis_runtime::set_license(&name, &key);
}
noesis_runtime::init();
{
let mut dict = ResourceDictionary::new();
assert!(dict.is_empty(), "fresh dictionary should be empty");
assert!(dict.add_string("K", "hello"), "add_string should succeed");
assert_eq!(dict.len(), 1, "one base-dictionary entry after add");
let hit = dict
.find("K")
.expect("find(\"K\") should be Some after add");
assert_eq!(
unbox(hit.as_ptr()).as_deref(),
Some("hello"),
"looked-up value must unbox to the stored string"
);
assert!(dict.contains("K"), "contains(\"K\") true");
assert!(dict.find("nope").is_none(), "missing key -> None");
assert!(!dict.contains("nope"), "missing key -> contains false");
let merged = ResourceDictionary::parse(MERGED_XAML)
.expect("parse of <ResourceDictionary> should succeed");
assert!(
merged.contains("Merged.Greeting"),
"merged dict should contain its own key"
);
assert!(
!dict.contains("Merged.Greeting"),
"parent must NOT see the merged key before merging"
);
assert!(dict.add_merged(&merged), "add_merged should succeed");
assert!(
dict.contains("Merged.Greeting"),
"parent should resolve the merged key after add_merged"
);
let parsed = ResourceDictionary::parse(PARSED_XAML).expect("parse should succeed");
let parsed_hit = parsed
.find("Parsed.Title")
.expect("parsed dict should contain Parsed.Title");
assert_eq!(
unbox(parsed_hit.as_ptr()).as_deref(),
Some("parsed-value"),
"parsed value must round-trip"
);
assert!(
ResourceDictionary::parse(
"<Grid xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"/>"
)
.is_none(),
"parsing a non-ResourceDictionary root must be None"
);
assert!(
!application_resources_contains("K"),
"K must not resolve through app resources before install"
);
set_application_resources(&dict);
assert!(
application_resources_present(),
"GetApplicationResources non-null after SetApplicationResources"
);
assert!(
application_resources_contains("K"),
"installed app resources should contain K"
);
assert!(
application_resources_contains("Merged.Greeting"),
"installed app resources should resolve the merged key too"
);
assert!(
!application_resources_contains("absent-key"),
"absent key -> false through app resources"
);
unsafe { noesis_runtime::ffi::noesis_gui_set_application_resources(std::ptr::null_mut()) };
}
noesis_runtime::shutdown();
}