1use boxworks::ds;
42use boxworks::lang;
43use boxworks::lang::convert::ToBoxLang;
44
45#[macro_export]
46macro_rules! assert_box_eq {
47 ($left:expr, $right:expr$(,)?) => {{
48 let lhs: boxworks_testing::Value = $left.into();
49 let rhs: boxworks_testing::Value = $right.into();
50 boxworks_testing::assert_eq(lhs, rhs);
51 }};
52}
53
54#[macro_export]
55macro_rules! is_box_eq {
56 ($left:expr, $right:expr$(,)?) => {{
57 let lhs: boxworks_testing::Value = $left.into();
58 let rhs: boxworks_testing::Value = $right.into();
59 boxworks_testing::is_eq(lhs, rhs)
60 }};
61}
62
63pub enum Value {
64 String(String),
65 Box(Vec<ds::Horizontal>),
66}
67
68impl From<&str> for Value {
69 fn from(value: &str) -> Self {
70 Value::String(value.into())
71 }
72}
73
74impl From<String> for Value {
75 fn from(value: String) -> Self {
76 Value::String(value)
77 }
78}
79
80impl From<ds::VBox> for Value {
81 fn from(value: ds::VBox) -> Self {
82 Value::Box(vec![ds::Horizontal::VBox(value)])
83 }
84}
85
86impl From<ds::HBox> for Value {
87 fn from(value: ds::HBox) -> Self {
88 Value::Box(vec![ds::Horizontal::HBox(value)])
89 }
90}
91
92impl From<Vec<ds::Horizontal>> for Value {
93 fn from(value: Vec<ds::Horizontal>) -> Self {
94 Value::Box(value)
95 }
96}
97
98pub fn is_eq(lhs: Value, rhs: Value) -> bool {
99 let (lhs_list, _) = normalize(lhs, "lhs.box");
100 let (rhs_list, _) = normalize(rhs, "rhs.box");
101 lhs_list == rhs_list
102}
103
104pub fn assert_eq(lhs: Value, rhs: Value) {
105 let (lhs_list, lhs_s) = normalize(lhs, "lhs.box");
106 let (rhs_list, rhs_s) = normalize(rhs, "rhs.box");
107 use pretty_assertions::assert_eq;
109 assert_eq!(lhs_s, rhs_s);
110 assert_eq!(rhs_list, lhs_list);
113}
114
115fn normalize(val: Value, side: &str) -> (Vec<ds::Horizontal>, String) {
116 let list = match val {
117 Value::String(s) => match lang::parse_horizontal_list(&s.clone()) {
118 Ok(v) => v,
119 Err(err) => {
120 let source = ariadne::Source::from(s);
121 let cache: (&str, _) = (side, source);
122 for err in err {
123 err.ariadne_report(side).eprint(cache.clone()).unwrap();
124 }
125 panic!("failed to parse boxlang input; errors printed above.")
126 }
127 },
128 Value::Box(v) => v,
129 };
130 let mut s = String::new();
131 for elem in &list {
132 use std::fmt::Write;
133 write!(&mut s, "{}", elem.to_box_lang()).unwrap();
134 }
135 (list, s)
136}