macro_rules! tests {
($kind: literal in mod $module: ident $($unwrap: ident)?) => {
mod $module {
use bauer::Builder;
#[derive(Builder, Debug, PartialEq)]
#[builder(kind = $kind)]
struct BasicConverter {
#[builder(adapter = |value: Vec<&str>| value.into_iter().map(|s| s.to_string()).collect())]
tags: Vec<String>,
#[builder(adapter = |value: &str| value.to_uppercase())]
name: String,
#[builder(adapter = |value: i32| value * 2)]
count: i32,
}
#[test]
fn test_basic_converter() {
let instance = BasicConverter::builder()
.tags(vec!["rust", "converter"])
.name("test")
.count(21)
.build()
$(.$unwrap())?;
assert_eq!(
instance.tags,
vec!["rust".to_string(), "converter".to_string()]
);
assert_eq!(instance.name, "TEST".to_string());
assert_eq!(instance.count, 42);
}
#[derive(Builder, Debug, PartialEq)]
#[builder(kind = $kind)]
struct GenericConverter<T>
where
T: Clone + std::fmt::Debug,
{
data: T,
#[builder(adapter = |value: Vec<&str>| value.into_iter().map(|s| s.to_string()).collect())]
labels: Vec<String>,
}
#[test]
fn test_generic_converter() {
let instance = GenericConverter::<i32>::builder()
.data(42)
.labels(vec!["label1", "label2"])
.build()
$(.$unwrap())?;
assert_eq!(instance.data, 42);
assert_eq!(
instance.labels,
vec!["label1".to_string(), "label2".to_string()]
);
}
#[derive(Builder, Debug)]
#[builder(kind = $kind)]
struct LifetimeConverter<'a> {
data: &'a str,
#[builder(adapter = |value: Vec<&str>| value.join(","))]
combined: String,
}
#[test]
fn test_lifetime_converter() {
let data = "test data";
let instance = LifetimeConverter::builder()
.data(data)
.combined(vec!["a", "b", "c"])
.build()
$(.$unwrap())?;
assert_eq!(instance.data, "test data");
assert_eq!(instance.combined, "a,b,c");
}
#[derive(Builder, Debug, PartialEq)]
#[builder(kind = $kind)]
struct ConstGenericConverter<const N: usize> {
data: [i32; N],
#[builder(adapter = |value: Vec<i32>| value.into_iter().sum())]
sum: i32,
}
#[test]
fn test_const_generic_converter() {
let instance = ConstGenericConverter::<3>::builder()
.data([1, 2, 3])
.sum(vec![10, 20, 30])
.build()
$(.$unwrap())?;
assert_eq!(instance.data, [1, 2, 3]);
assert_eq!(instance.sum, 60);
}
#[derive(Builder, Debug)]
#[builder(kind = $kind)]
struct ComplexConverter<'a, T, U, const N: usize>
where
T: Clone + std::fmt::Debug,
U: std::fmt::Display,
{
reference: &'a str,
data: T,
display_data: U,
array: [i32; N],
#[builder(adapter = |value: Vec<&str>| value.into_iter().map(|s| format!("converted_{s}")).collect())]
processed: Vec<String>,
}
#[test]
fn test_complex_converter() {
let reference = "test_ref";
let instance = ComplexConverter::<String, f64, 2>::builder()
.reference(reference)
.data("test".to_string())
.display_data(std::f64::consts::PI)
.array([1, 2])
.processed(vec!["item1", "item2"])
.build()
$(.$unwrap())?;
assert_eq!(instance.reference, "test_ref");
assert_eq!(instance.data, "test".to_string());
assert_eq!(instance.display_data, std::f64::consts::PI);
assert_eq!(instance.array, [1, 2]);
assert_eq!(
instance.processed,
vec!["converted_item1".to_string(), "converted_item2".to_string()]
);
}
#[derive(Builder, Debug, PartialEq)]
#[builder(kind = $kind)]
struct ComplexClosureConverter {
#[builder(adapter = |value: Vec<(String, i32)>| {
value.into_iter()
.filter(|(_, count)| *count > 0)
.map(|(name, count)| format!("{name}:{count}"))
.collect()
})]
items: Vec<String>,
#[builder(adapter = |value: std::collections::HashMap<String, i32>| {
value.values().sum()
})]
total: i32,
}
#[test]
fn test_complex_closure_converter() {
let mut map = std::collections::HashMap::new();
map.insert("a".to_string(), 10);
map.insert("b".to_string(), 20);
map.insert("c".to_string(), 30);
let instance = ComplexClosureConverter::builder()
.items(vec![
("valid".to_string(), 5),
("invalid".to_string(), 0),
("another".to_string(), 3),
])
.total(map)
.build()
$(.$unwrap())?;
assert_eq!(
instance.items,
vec!["valid:5".to_string(), "another:3".to_string()]
);
assert_eq!(instance.total, 60);
}
#[derive(Builder, Debug, PartialEq)]
#[builder(kind = $kind, prefix = "with_")]
struct ConverterWithAttributes {
#[builder(adapter = |value: &str| value.to_uppercase(), rename = "title")]
name: String,
#[builder(adapter = |value: Vec<i32>| value.into_iter().max().unwrap_or(0), rename = "set_max_value", skip_prefix, default)]
max_value: i32,
#[builder(adapter = |value: Option<String>| value.unwrap_or_else(|| "default".to_string()), default)]
description: String,
}
#[test]
fn test_converter_with_attributes() {
let instance = ConverterWithAttributes::builder()
.with_title("hello world")
.set_max_value(vec![1, 5, 3, 9, 2])
.with_description(Some("custom desc".to_string()))
.build()
$(.$unwrap())?;
assert_eq!(instance.name, "HELLO WORLD".to_string());
assert_eq!(instance.max_value, 9);
assert_eq!(instance.description, "custom desc".to_string());
}
#[test]
fn test_converter_with_default_fallback() {
let instance = ConverterWithAttributes::builder()
.with_title("test")
.build()
$(.$unwrap())?;
assert_eq!(instance.name, "TEST".to_string());
assert_eq!(instance.max_value, 0);
assert_eq!(instance.description, "".to_string()); }
#[derive(Builder, Debug, PartialEq)]
#[builder(kind = $kind)]
struct RegularBuilderConverter {
#[builder(adapter = |value: Vec<&str>| value.join("-"))]
joined: String,
#[builder(adapter = |value: (i32, i32)| value.0 + value.1, default)]
sum: i32,
}
#[test]
fn test_regular_builder_converter() {
let instance = RegularBuilderConverter::builder()
.joined(vec!["a", "b", "c"])
.sum((10, 20))
.build()
$(.$unwrap())?;
assert_eq!(instance.joined, "a-b-c".to_string());
assert_eq!(instance.sum, 30);
}
#[test]
fn test_regular_builder_converter_defaults() {
let instance = RegularBuilderConverter::builder()
.joined(vec!["only", "this"])
.build()
$(.$unwrap())?;
assert_eq!(instance.joined, "only-this".to_string());
assert_eq!(instance.sum, 0); }
}
};
}
tests!("borrowed" in mod borrowed unwrap);
tests!("owned" in mod owned unwrap);
tests!("type-state" in mod type_state);