1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial |
3 | |
4 | use std::io::{BufWriter, Write}; |
5 | use std::path::Path; |
6 | |
7 | fn main() -> std::io::Result<()> { |
8 | let mut generated_file = BufWriter::new(std::fs::File::create( |
9 | Path::new(&std::env::var_os("OUT_DIR" ).unwrap()).join("generated.rs" ), |
10 | )?); |
11 | |
12 | for testcase in test_driver_lib::collect_test_cases("cases" )? { |
13 | println!("cargo:rerun-if-changed= {}" , testcase.absolute_path.display()); |
14 | let mut module_name = testcase.identifier(); |
15 | if module_name.starts_with(|c: char| !c.is_ascii_alphabetic()) { |
16 | module_name.insert(0, '_' ); |
17 | } |
18 | if let Some(style) = testcase.requested_style { |
19 | module_name.push('_' ); |
20 | module_name.push_str(style); |
21 | } |
22 | writeln!(generated_file, "#[path= \"{0}.rs \"] mod r# {0};" , module_name)?; |
23 | let source = std::fs::read_to_string(&testcase.absolute_path)?; |
24 | let ignored = testcase.is_ignored("rust" ); |
25 | |
26 | let mut output = BufWriter::new(std::fs::File::create( |
27 | Path::new(&std::env::var_os("OUT_DIR" ).unwrap()).join(format!(" {}.rs" , module_name)), |
28 | )?); |
29 | |
30 | #[cfg (not(feature = "build-time" ))] |
31 | if !generate_macro(&source, &mut output, testcase)? { |
32 | continue; |
33 | } |
34 | #[cfg (feature = "build-time" )] |
35 | generate_source(&source, &mut output, testcase)?; |
36 | |
37 | for (i, x) in test_driver_lib::extract_test_functions(&source) |
38 | .filter(|x| x.language_id == "rust" ) |
39 | .enumerate() |
40 | { |
41 | write!( |
42 | output, |
43 | r" |
44 | #[test] {} fn t_ {}() -> std::result::Result<(), std::boxed::Box<dyn std::error::Error>> {{ |
45 | use i_slint_backend_testing as slint_testing; |
46 | slint_testing::init(); |
47 | {} |
48 | Ok(()) |
49 | }}" , |
50 | if ignored { "#[ignore]" } else { "" }, |
51 | i, |
52 | x.source.replace(' \n' , " \n " ) |
53 | )?; |
54 | } |
55 | } |
56 | |
57 | // By default resources are embedded. The WASM example builds provide test coverage for that. This switch |
58 | // provides test coverage for the non-embedding case, compiling tests without embedding the images. |
59 | println!("cargo:rustc-env=SLINT_EMBED_RESOURCES=false" ); |
60 | |
61 | //Make sure to use a consistent style |
62 | println!("cargo:rustc-env=SLINT_STYLE=fluent" ); |
63 | println!("cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1" ); |
64 | Ok(()) |
65 | } |
66 | |
67 | #[cfg (not(feature = "build-time" ))] |
68 | fn generate_macro( |
69 | source: &str, |
70 | output: &mut dyn Write, |
71 | testcase: test_driver_lib::TestCase, |
72 | ) -> Result<bool, std::io::Error> { |
73 | if source.contains(" \\{" ) { |
74 | // Unfortunately, \{ is not valid in a rust string so it cannot be used in a slint! macro |
75 | output.write_all(b"#[test] #[ignore] fn ignored_because_string_template() {{}}" )?; |
76 | return Ok(false); |
77 | } |
78 | // to silence all the warnings in .slint files that would be turned into errors |
79 | output.write_all(b"#![allow(deprecated)]" )?; |
80 | let include_paths = test_driver_lib::extract_include_paths(source); |
81 | let library_paths = test_driver_lib::extract_library_paths(source); |
82 | output.write_all(b"slint::slint!{" )?; |
83 | for path in include_paths { |
84 | let mut abs_path = testcase.absolute_path.clone(); |
85 | abs_path.pop(); |
86 | abs_path.push(path); |
87 | |
88 | output.write_all(b"#[include_path=r# \"" )?; |
89 | output.write_all(abs_path.to_string_lossy().as_bytes())?; |
90 | output.write_all(b" \"#] \n" )?; |
91 | |
92 | println!("cargo:rerun-if-changed= {}" , abs_path.to_string_lossy()); |
93 | } |
94 | for (lib, path) in library_paths { |
95 | let mut abs_path = testcase.absolute_path.clone(); |
96 | abs_path.pop(); |
97 | abs_path.push(path); |
98 | |
99 | output.write_all(b"#[library_path(" )?; |
100 | output.write_all(lib.as_bytes())?; |
101 | output.write_all(b")=r# \"" )?; |
102 | output.write_all(abs_path.to_string_lossy().as_bytes())?; |
103 | output.write_all(b" \"#] \n" )?; |
104 | |
105 | println!("cargo:rerun-if-changed= {}" , abs_path.to_string_lossy()); |
106 | } |
107 | |
108 | if let Some(style) = testcase.requested_style { |
109 | output.write_all(b"#[style= \"" )?; |
110 | output.write_all(style.as_bytes())?; |
111 | output.write_all(b" \"#] \n" )?; |
112 | } |
113 | |
114 | let mut abs_path = testcase.absolute_path; |
115 | abs_path.pop(); |
116 | output.write_all(b"#[include_path=r# \"" )?; |
117 | output.write_all(abs_path.to_string_lossy().as_bytes())?; |
118 | output.write_all(b" \"#] \n" )?; |
119 | output.write_all(source.as_bytes())?; |
120 | output.write_all(b"} \n" )?; |
121 | Ok(true) |
122 | } |
123 | |
124 | #[cfg (feature = "build-time" )] |
125 | fn generate_source( |
126 | source: &str, |
127 | output: &mut impl Write, |
128 | testcase: test_driver_lib::TestCase, |
129 | ) -> Result<(), std::io::Error> { |
130 | use i_slint_compiler::{diagnostics::BuildDiagnostics, *}; |
131 | |
132 | let include_paths = test_driver_lib::extract_include_paths(source) |
133 | .map(std::path::PathBuf::from) |
134 | .collect::<Vec<_>>(); |
135 | let library_paths = test_driver_lib::extract_library_paths(source) |
136 | .map(|(k, v)| (k.to_string(), std::path::PathBuf::from(v))) |
137 | .collect::<std::collections::HashMap<_, _>>(); |
138 | |
139 | let mut diag = BuildDiagnostics::default(); |
140 | let syntax_node = |
141 | parser::parse(source.to_owned(), Some(&testcase.absolute_path), None, &mut diag); |
142 | let mut compiler_config = CompilerConfiguration::new(generator::OutputFormat::Rust); |
143 | compiler_config.enable_component_containers = true; |
144 | compiler_config.include_paths = include_paths; |
145 | compiler_config.library_paths = library_paths; |
146 | compiler_config.style = Some(testcase.requested_style.unwrap_or("fluent" ).to_string()); |
147 | let (root_component, diag, _) = |
148 | spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config)); |
149 | |
150 | if diag.has_error() { |
151 | diag.print_warnings_and_exit_on_error(); |
152 | return Err(std::io::Error::new( |
153 | std::io::ErrorKind::Other, |
154 | format!("build error in {:?}" , testcase.absolute_path), |
155 | )); |
156 | } else { |
157 | diag.print(); |
158 | } |
159 | |
160 | generator::generate(generator::OutputFormat::Rust, output, &root_component)?; |
161 | Ok(()) |
162 | } |
163 | |