tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1077HTML 1008Markdown 12TOML 83209 Sutichaykuna

⎇ 076aca1b7e6f8d292ac3a13f1565ac94aaf1f5bd scripts/gentest/src/main.rs Rust · 364 siq'ikuna · 12.6 KB Ñawpa willay Pi imata llamkarqan ch'uya

Basic test generation working 076aca1b7 · Emil Sjölander ·

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