use crate::reflection::RegistryBuilder;
use crate::reflection::format::{ContainerFormat, Format, VariantFormat};
#[cfg(test)]
mod tests {
use std::collections::{BTreeMap, BTreeSet, HashSet};
use crate::{
error::Error,
reflect,
reflection::format::{Doc, Namespace, QualifiedTypeName},
};
use super::*;
use facet::Facet;
#[test]
fn test_set_types_work() {
#[derive(Facet)]
struct WithSets {
btree_set: BTreeSet<String>,
hash_set: HashSet<u32>,
}
#[derive(Facet)]
#[repr(u8)]
#[allow(unused)]
enum EnumWithSet {
SetVariant(BTreeSet<i64>),
Regular(u32),
}
let registry = reflect!(WithSets, EnumWithSet).unwrap();
assert!(!registry.is_empty());
}
#[test]
fn test_complex_nested_sets() {
#[derive(Facet)]
struct NestedSets {
sets_in_vec: Vec<BTreeSet<String>>,
optional_set: Option<HashSet<u64>>,
}
let registry = reflect!(NestedSets).unwrap();
assert!(!registry.is_empty());
}
#[test]
fn test_normal_variable_resolution() {
#[derive(Facet)]
struct SimpleStruct {
field: u32,
}
let registry = reflect!(SimpleStruct).unwrap();
assert!(!registry.is_empty());
let type_name = QualifiedTypeName {
namespace: Namespace::Root,
name: "SimpleStruct".to_string(),
};
assert!(registry.contains_key(&type_name));
}
#[test]
#[should_panic(expected = "UnknownFormat")]
fn test_variable_visit_mechanism() {
use crate::reflection::format::{FormatHolder, Variable};
let variable: Variable<Format> = Variable::new(None);
let result = variable.visit(&mut |_| Ok(()));
result.unwrap();
}
#[test]
fn test_temp_container_resolution() {
#[derive(Facet)]
#[repr(u8)]
#[allow(unused)]
enum WithNewtypeVariant {
Variant(BTreeSet<String>),
}
let registry = reflect!(WithNewtypeVariant).unwrap();
assert!(!registry.is_empty());
}
#[test]
fn test_comprehensive_previously_problematic_types() {
use std::collections::{BTreeSet, HashMap, HashSet};
#[derive(Facet)]
struct Complex {
btree_set: BTreeSet<String>,
hash_set: HashSet<u32>,
nested: Vec<BTreeSet<i32>>,
mapped: HashMap<String, HashSet<u64>>,
maybe_set: Option<HashSet<i32>>,
}
#[derive(Facet)]
#[repr(u8)]
#[allow(unused)]
enum ComplexEnum {
SetVariant(BTreeSet<String>),
NestedVariant(Vec<HashSet<u32>>),
OptionalVariant(Option<HashSet<i64>>),
Regular(u32),
}
let registry = reflect!(Complex, ComplexEnum).unwrap();
assert!(!registry.is_empty());
let mut found_types = 0;
for key in registry.keys() {
if key.name.contains("Complex") {
found_types += 1;
}
}
assert!(found_types >= 2, "Should have processed both Complex types");
}
#[test]
fn test_build_catches_unresolved_variables() {
let mut builder = RegistryBuilder::new();
let type_name = QualifiedTypeName {
namespace: Namespace::Named("test".to_string()),
name: "UnresolvedType".to_string(),
};
let unresolved_container = ContainerFormat::NewTypeStruct(Box::default(), Doc::new());
builder
.registry
.insert(type_name.clone(), unresolved_container);
assert_eq!(
builder.build(),
Err(Error::ReflectionError {
type_name: type_name.to_string(),
message: "incomplete reflection detected".to_string()
})
);
}
#[test]
fn test_enum_with_unresolved_variant_caught() {
let mut builder = RegistryBuilder::new();
let mut variants = BTreeMap::new();
variants.insert(
0,
crate::reflection::format::Named {
name: "UnresolvedVariant".to_string(),
doc: Doc::new(),
value: VariantFormat::unknown(), },
);
let enum_container = ContainerFormat::Enum(variants, Doc::new());
let type_name = QualifiedTypeName {
namespace: Namespace::Named("test".to_string()),
name: "EnumWithUnresolvedVariant".to_string(),
};
builder.registry.insert(type_name.clone(), enum_container);
assert_eq!(
builder.build(),
Err(Error::ReflectionError {
type_name: type_name.to_string(),
message: "incomplete reflection detected".to_string()
})
);
}
#[test]
fn test_struct_with_unresolved_field_caught() {
let mut builder = RegistryBuilder::new();
let fields = vec![crate::reflection::format::Named {
name: "unresolved_field".to_string(),
doc: Doc::new(),
value: Format::unknown(), }];
let struct_container = ContainerFormat::Struct(fields, Doc::new());
let type_name = QualifiedTypeName {
namespace: Namespace::Named("test".to_string()),
name: "StructWithUnresolvedField".to_string(),
};
builder.registry.insert(type_name.clone(), struct_container);
assert_eq!(
builder.build(),
Err(Error::ReflectionError {
type_name: type_name.to_string(),
message: "incomplete reflection detected".to_string()
})
);
}
#[test]
fn test_original_set_of_string_pattern_works() {
use std::collections::BTreeSet;
#[derive(Facet)]
#[repr(u8)]
#[allow(unused)]
enum MyEnum {
Set(BTreeSet<String>),
Other(u32),
}
let registry = reflect!(MyEnum).unwrap();
assert!(!registry.is_empty());
let type_name = QualifiedTypeName {
namespace: Namespace::Root,
name: "MyEnum".to_string(),
};
assert!(registry.contains_key(&type_name));
}
#[test]
fn test_enum_with_anon_struct_variants_with_result_of_t() {
use thiserror::Error;
#[derive(Facet, Clone, PartialEq, Eq, Error, Debug)]
#[error("AnotherError")]
struct AnotherError;
#[derive(Facet, Clone, PartialEq, Eq, Error, Debug)]
#[repr(C)]
#[allow(unused)]
pub enum MyError {
#[error("disconnected")]
Disconnect(#[from] AnotherError),
#[error("the data for key `{0}` is not available")]
Redaction(String),
#[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader { expected: String, found: String },
#[error("unknown data store error")]
Unknown,
}
#[derive(Facet, Debug, Clone, PartialEq, Eq)]
#[repr(C)]
#[allow(unused)]
pub enum MyResult<T> {
Ok(T),
Err(MyError),
}
#[derive(Facet)]
#[repr(C)]
#[allow(unused)]
enum MyEnum {
Variant1 { result: MyResult<String> },
Variant2 { result: MyResult<i32> },
}
let err = reflect!(MyEnum).unwrap_err();
insta::assert_snapshot!(
err.root_cause(),
@"failed to add type MyEnum: unsupported generic type: MyResult<i32>, the type may have already been used with different parameters"
);
}
}