tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1114HTML 1040Markdown 12TOML 94698 Definitions

⎇ c3eff87967f17e831fe09488d3206b363e4e9efa scripts/gentest/src/main.rs Rust · 385 lines · 13.1 KB History Who touched what raw

Add error handling to custom measure functions c3eff8796 · Emil Sjölander ·

1use selenium_rs::element::Element;
2use selenium_rs::webdriver::{Browser, Selector, WebDriver};
3
4use std::process::Command;
5use std::path::Path;
6use std::fs;
7use std::{thread, time};
8
9use json;
10
11fn main() {
12    // std::env::current_exe should be <path/to/repo>/scripts/gentest/target/debug/gentest
13    // move up five times to get to repo root
14    let root_dir = std::env::current_exe().unwrap();
15    let repo_root = root_dir.parent()
16        .and_then(Path::parent)
17        .and_then(Path::parent)
18        .and_then(Path::parent)
19        .and_then(Path::parent)
20        .unwrap();
21
22    let fixtures_root = repo_root.join("test_fixtures");
23
24    let mut selenium = Command::new("java")
25        .arg("-jar")
26        .arg("selenium.jar")
27        .current_dir(&format!("{}/scripts/gentest", repo_root.display()))
28        .spawn()
29        .expect("failed to execute selenium, most likely missing java");
30
31    // Wait for a bit until selenium is up and running...
32    let ten_millis = time::Duration::from_millis(2000);
33    thread::sleep(ten_millis);
34
35    let mut driver = WebDriver::new(Browser::Chrome);
36    driver.start_session();
37
38    let mut src = String::new();
39    src.push_str("#[cfg(test)]\n");
40    src.push_str("mod generated {\n");
41
42    let fixtures = fs::read_dir(fixtures_root).unwrap();
43    for fixture in fixtures {
44        let fixture_path = fixture.unwrap().path();
45        if fixture_path.is_file() {
46            let name = fixture_path.file_stem().unwrap().to_str().unwrap();
47
48            driver.navigate(&format!("file://{}", fixture_path.display()));
49            let root_element = driver.query_element(Selector::CSS, "#test-root").unwrap();
50            src.push_str(&format!("{}\n", generate_test(&name, root_element)));
51        }
52    }
53    
54    src.push_str("}\n");
55    fs::write(repo_root.join("tests").join("generated.rs"), src);
56
57    Command::new("cargo")
58        .arg("fmt")
59        .current_dir(repo_root)
60        .status();
61
62    driver.delete_session();
63    selenium.kill();
64}
65
66fn generate_test(name: &str, root: Element) -> String {
67    let description_string = root.get_property("__stretch_description__").unwrap();
68    let description = json::parse(&description_string).unwrap();
69
70    let mut src = String::new();
71    src.push_str("#[test]\n");
72    src.push_str(&format!("fn {}() {{\n", name));
73    
74    src.push_str("let layout = stretch::compute(\n");
75    src.push_str(&format!("&{}", &generate_node(&description)));
76    src.push_str(", stretch::geometry::Size::undefined()).unwrap();\n\n");
77
78    src.push_str(&generate_assertions("layout".to_string(), &description));
79    src.push_str("}\n");
80    src
81}
82
83fn generate_assertions(prefix: String, node: &json::JsonValue) -> String {
84    let layout = &node["layout"];
85    let mut src = String::new();
86
87    src.push_str(&format!("assert_eq!({}.size.width, {:.4});\n", prefix, layout["width"].as_f32().unwrap()));
88    src.push_str(&format!("assert_eq!({}.size.height, {:.4});\n", prefix, layout["height"].as_f32().unwrap()));
89    src.push_str(&format!("assert_eq!({}.location.x, {:.4});\n", prefix, layout["x"].as_f32().unwrap()));
90    src.push_str(&format!("assert_eq!({}.location.y, {:.4});\n\n", prefix, layout["y"].as_f32().unwrap()));
91
92    match node["children"] {
93        json::JsonValue::Array(ref value) => {
94            for i in 0..value.len() {
95                let child = &value[i];
96                src.push_str(&generate_assertions(format!("{}.children[{}]", prefix, i), child));
97            }
98        },
99        _ => (),
100    };
101    src
102}
103
104fn generate_node(node: &json::JsonValue) -> String {
105    let mut src = String::new();
106    src.push_str("stretch::style::Node {\n");
107
108    let style = &node["style"];
109
110    match style["display"] {
111        json::JsonValue::Short(ref value) => {
112            match value.as_ref() {
113                "none" => src.push_str("display: stretch::style::Display::None,\n"),
114                _ => (),
115            };
116        },
117        _ => (),
118    };
119
120    match style["position_type"] {
121        json::JsonValue::Short(ref value) => {
122            match value.as_ref() {
123                "absolute" => src.push_str("position_type: stretch::style::PositionType::Absolute,\n"),
124                _ => (),
125            };
126        },
127        _ => (),
128    };
129
130    match style["direction"] {
131        json::JsonValue::Short(ref value) => {
132            match value.as_ref() {
133                "rtl" => src.push_str("direction: stretch::style::Direction::RTL,\n"),
134                "ltr" => src.push_str("direction: stretch::style::Direction::LTR,\n"),
135                _ => (),
136            };
137        },
138        _ => (),
139    };
140
141    match style["flexDirection"] {
142        json::JsonValue::Short(ref value) => {
143            match value.as_ref() {
144                "row-reverse" => src.push_str("flex_direction: stretch::style::FlexDirection::RowReverse,\n"),
145                "column" => src.push_str("flex_direction: stretch::style::FlexDirection::Column,\n"),
146                "column-reverse" => src.push_str("flex_direction: stretch::style::FlexDirection::ColumnReverse,\n"),
147                _ => (),
148            };
149        },
150        _ => (),
151    };
152
153    match style["flexWrap"] {
154        json::JsonValue::Short(ref value) => {
155            match value.as_ref() {
156                "wrap" => src.push_str("flex_wrap: stretch::style::FlexWrap::Wrap,\n"),
157                "wrap-reverse" => src.push_str("flex_wrap: stretch::style::FlexWrap::WrapReverse,\n"),
158                _ => (),
159            };
160        },
161        _ => (),
162    };
163
164    match style["overflow"] {
165        json::JsonValue::Short(ref value) => {
166            match value.as_ref() {
167                "hidden" => src.push_str("overflow: stretch::style::Overflow::Hidden,\n"),
168                "scroll" => src.push_str("overflow: stretch::style::Overflow::Scroll,\n"),
169                _ => (),
170            };
171        },
172        _ => (),
173    };
174
175    match style["alignItems"] {
176        json::JsonValue::Short(ref value) => {
177            match value.as_ref() {
178                "flex-start" => src.push_str("align_items: stretch::style::AlignItems::FlexStart,\n"),
179                "flex-end" => src.push_str("align_items: stretch::style::AlignItems::FlexEnd,\n"),
180                "center" => src.push_str("align_items: stretch::style::AlignItems::Center,\n"),
181                "baseline" => src.push_str("align_items: stretch::style::AlignItems::Baseline,\n"),
182                _ => (),
183            };
184        },
185        _ => (),
186    };
187
188    match style["alignSelf"] {
189        json::JsonValue::Short(ref value) => {
190            match value.as_ref() {
191                "flex-start" => src.push_str("align_self: stretch::style::AlignSelf::FlexStart,\n"),
192                "flex-end" => src.push_str("align_self: stretch::style::AlignSelf::FlexEnd,\n"),
193                "center" => src.push_str("align_self: stretch::style::AlignSelf::Center,\n"),
194                "baseline" => src.push_str("align_self: stretch::style::AlignSelf::Baseline,\n"),
195                "stretch" => src.push_str("align_self: stretch::style::AlignSelf::Stretch,\n"),
196                _ => (),
197            };
198        },
199        _ => (),
200    };
201
202    match style["alignContent"] {
203        json::JsonValue::Short(ref value) => {
204            match value.as_ref() {
205                "flex-start" => src.push_str("align_content: stretch::style::AlignContent::FlexStart,\n"),
206                "flex-end" => src.push_str("align_content: stretch::style::AlignContent::FlexEnd,\n"),
207                "center" => src.push_str("align_content: stretch::style::AlignContent::Center,\n"),
208                "space-between" => src.push_str("align_content: stretch::style::AlignContent::SpaceBetween,\n"),
209                "space-around" => src.push_str("align_content: stretch::style::AlignContent::SpaceAround,\n"),
210                _ => (),
211            };
212        },
213        _ => (),
214    };
215
216    match style["justifyContent"] {
217        json::JsonValue::Short(ref value) => {
218            match value.as_ref() {
219                "flex-end" => src.push_str("justify_content: stretch::style::JustifyContent::FlexEnd,\n"),
220                "center" => src.push_str("justify_content: stretch::style::JustifyContent::Center,\n"),
221                "space-between" => src.push_str("justify_content: stretch::style::JustifyContent::SpaceBetween,\n"),
222                "space-around" => src.push_str("justify_content: stretch::style::JustifyContent::SpaceAround,\n"),
223                "space-evenly" => src.push_str("justify_content: stretch::style::JustifyContent::SpaceEvenly,\n"),
224                _ => (),
225            };
226        },
227        _ => (),
228    };
229
230    match style["flexGrow"] {
231        json::JsonValue::Number(value) => {
232            let value: f32 = value.into();
233            src.push_str(&format!("flex_grow: {:.4},\n", value))
234        },
235        _ => (),
236    };
237
238    match style["flexShrink"] {
239        json::JsonValue::Number(value) => {
240            let value: f32 = value.into();
241            src.push_str(&format!("flex_shrink: {:.4},\n", value))
242        },
243        _ => (),
244    };
245
246    match style["flexBasis"] {
247        json::JsonValue::Object(ref value) => src.push_str(&format!("flex_basis: {},\n", generate_dimension(value))),
248        _ => (),
249    };
250
251    match style["size"] {
252        json::JsonValue::Object(ref value) => src.push_str(&format!("size: {},\n", generate_size(value))),
253        _ => (),
254    };
255
256    match style["min_size"] {
257        json::JsonValue::Object(ref value) => src.push_str(&format!("min_size: {},\n", generate_size(value))),
258        _ => (),
259    };
260
261    match style["max_size"] {
262        json::JsonValue::Object(ref value) => src.push_str(&format!("max_size: {},\n", generate_size(value))),
263        _ => (),
264    };
265
266    match style["margin"] {
267        json::JsonValue::Object(ref value) => src.push_str(&format!("margin: {},\n", generate_edges(value))),
268        _ => (),
269    };
270
271    match style["padding"] {
272        json::JsonValue::Object(ref value) => src.push_str(&format!("padding: {},\n", generate_edges(value))),
273        _ => (),
274    };
275
276    match style["position"] {
277        json::JsonValue::Object(ref value) => src.push_str(&format!("position: {},\n", generate_edges(value))),
278        _ => (),
279    };
280
281    match style["border"] {
282        json::JsonValue::Object(ref value) => src.push_str(&format!("border: {},\n", generate_edges(value))),
283        _ => (),
284    };
285
286    match node["children"] {
287        json::JsonValue::Array(ref value) => {
288            if value.len() > 0 {
289                src.push_str("children: vec![\n");
290                value.iter().for_each(|child| {
291                    src.push_str(&format!("{},\n", generate_node(child)));
292                });
293                src.push_str("],\n");
294            }
295        },
296        _ => (),
297    };
298
299    src.push_str("..Default::default()\n");
300    src.push_str("}\n");
301    src
302}
303
304fn generate_size(size: &json::object::Object) -> String {
305    let mut src = String::new();
306    src.push_str("stretch::geometry::Size {\n");
307
308    match size.get("width") {
309        Some(value) => match value {
310            json::JsonValue::Object(ref value) => src.push_str(&format!("width: {},\n", generate_dimension(value))),
311            _ => (),
312        },
313        None => (),
314    };
315
316    match size.get("height") {
317        Some(value) => match value {
318            json::JsonValue::Object(ref value) => src.push_str(&format!("height: {},\n", generate_dimension(value))),
319            _ => (),
320        },
321        None => (),
322    };
323
324    src.push_str("..Default::default()\n");
325    src.push_str("}\n");
326    src
327}
328
329fn generate_dimension(dimen: &json::object::Object) -> String {
330    let unit = dimen.get("unit").unwrap();
331    let value = || dimen.get("value").unwrap().as_f32().unwrap();
332
333    match unit {
334        json::JsonValue::Short(ref unit) => {
335            match unit.as_ref() {
336                "auto" => format!("stretch::style::Dimension::Auto"),
337                "points" => format!("stretch::style::Dimension::Points({:.4})", value()),
338                "percent" => format!("stretch::style::Dimension::Percent({:.4})", value()),
339                _ => panic!(),
340            }
341        },
342        _ => panic!(),
343    }
344}
345
346fn generate_edges(dimen: &json::object::Object) -> String {
347    let mut src = String::new();
348    src.push_str("stretch::geometry::Rect {\n");
349
350    match dimen.get("start") {
351        Some(value) => match value {
352            json::JsonValue::Object(ref value) => src.push_str(&format!("start: {},\n", generate_dimension(value))),
353            _ => (),
354        },
355        None => (),
356    };
357
358    match dimen.get("end") {
359        Some(value) => match value {
360            json::JsonValue::Object(ref value) => src.push_str(&format!("end: {},\n", generate_dimension(value))),
361            _ => (),
362        },
363        None => (),
364    };
365
366    match dimen.get("top") {
367        Some(value) => match value {
368            json::JsonValue::Object(ref value) => src.push_str(&format!("top: {},\n", generate_dimension(value))),
369            _ => (),
370        },
371        None => (),
372    };
373
374    match dimen.get("bottom") {
375        Some(value) => match value {
376            json::JsonValue::Object(ref value) => src.push_str(&format!("bottom: {},\n", generate_dimension(value))),
377            _ => (),
378        },
379        None => (),
380    };
381
382    src.push_str("..Default::default()\n");
383    src.push_str("}\n");
384    src
385}