1 // This file was generated by gir (https://github.com/gtk-rs/gir)
2 // from gir-files (https://github.com/gtk-rs/gir-files)
3 // DO NOT EDIT
4
5 extern crate gdk_pixbuf_sys;
6 extern crate shell_words;
7 extern crate tempfile;
8 use gdk_pixbuf_sys::*;
9 use std::env;
10 use std::error::Error;
11 use std::mem::{align_of, size_of};
12 use std::path::Path;
13 use std::process::Command;
14 use std::str;
15 use tempfile::Builder;
16
17 static PACKAGES: &[&str] = &["gdk-pixbuf-2.0"];
18
19 #[derive(Clone, Debug)]
20 struct Compiler {
21 pub args: Vec<String>,
22 }
23
24 impl Compiler {
new() -> Result<Compiler, Box<dyn Error>>25 pub fn new() -> Result<Compiler, Box<dyn Error>> {
26 let mut args = get_var("CC", "cc")?;
27 args.push("-Wno-deprecated-declarations".to_owned());
28 // For %z support in printf when using MinGW.
29 args.push("-D__USE_MINGW_ANSI_STDIO".to_owned());
30 args.extend(get_var("CFLAGS", "")?);
31 args.extend(get_var("CPPFLAGS", "")?);
32 args.extend(pkg_config_cflags(PACKAGES)?);
33 Ok(Compiler { args })
34 }
35
define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V)36 pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) {
37 let arg = match val.into() {
38 None => format!("-D{}", var),
39 Some(val) => format!("-D{}={}", var, val),
40 };
41 self.args.push(arg);
42 }
43
compile(&self, src: &Path, out: &Path) -> Result<(), Box<dyn Error>>44 pub fn compile(&self, src: &Path, out: &Path) -> Result<(), Box<dyn Error>> {
45 let mut cmd = self.to_command();
46 cmd.arg(src);
47 cmd.arg("-o");
48 cmd.arg(out);
49 let status = cmd.spawn()?.wait()?;
50 if !status.success() {
51 return Err(format!("compilation command {:?} failed, {}", &cmd, status).into());
52 }
53 Ok(())
54 }
55
to_command(&self) -> Command56 fn to_command(&self) -> Command {
57 let mut cmd = Command::new(&self.args[0]);
58 cmd.args(&self.args[1..]);
59 cmd
60 }
61 }
62
get_var(name: &str, default: &str) -> Result<Vec<String>, Box<dyn Error>>63 fn get_var(name: &str, default: &str) -> Result<Vec<String>, Box<dyn Error>> {
64 match env::var(name) {
65 Ok(value) => Ok(shell_words::split(&value)?),
66 Err(env::VarError::NotPresent) => Ok(shell_words::split(default)?),
67 Err(err) => Err(format!("{} {}", name, err).into()),
68 }
69 }
70
pkg_config_cflags(packages: &[&str]) -> Result<Vec<String>, Box<dyn Error>>71 fn pkg_config_cflags(packages: &[&str]) -> Result<Vec<String>, Box<dyn Error>> {
72 if packages.is_empty() {
73 return Ok(Vec::new());
74 }
75 let mut cmd = Command::new("pkg-config");
76 cmd.arg("--cflags");
77 cmd.args(packages);
78 let out = cmd.output()?;
79 if !out.status.success() {
80 return Err(format!("command {:?} returned {}", &cmd, out.status).into());
81 }
82 let stdout = str::from_utf8(&out.stdout)?;
83 Ok(shell_words::split(stdout.trim())?)
84 }
85
86 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
87 struct Layout {
88 size: usize,
89 alignment: usize,
90 }
91
92 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
93 struct Results {
94 /// Number of successfully completed tests.
95 passed: usize,
96 /// Total number of failed tests (including those that failed to compile).
97 failed: usize,
98 /// Number of tests that failed to compile.
99 failed_to_compile: usize,
100 }
101
102 impl Results {
record_passed(&mut self)103 fn record_passed(&mut self) {
104 self.passed += 1;
105 }
record_failed(&mut self)106 fn record_failed(&mut self) {
107 self.failed += 1;
108 }
record_failed_to_compile(&mut self)109 fn record_failed_to_compile(&mut self) {
110 self.failed += 1;
111 self.failed_to_compile += 1;
112 }
summary(&self) -> String113 fn summary(&self) -> String {
114 format!(
115 "{} passed; {} failed (compilation errors: {})",
116 self.passed, self.failed, self.failed_to_compile
117 )
118 }
expect_total_success(&self)119 fn expect_total_success(&self) {
120 if self.failed == 0 {
121 println!("OK: {}", self.summary());
122 } else {
123 panic!("FAILED: {}", self.summary());
124 };
125 }
126 }
127
128 #[test]
cross_validate_constants_with_c()129 fn cross_validate_constants_with_c() {
130 let tmpdir = Builder::new()
131 .prefix("abi")
132 .tempdir()
133 .expect("temporary directory");
134 let cc = Compiler::new().expect("configured compiler");
135
136 assert_eq!(
137 "1",
138 get_c_value(tmpdir.path(), &cc, "1").expect("C constant"),
139 "failed to obtain correct constant value for 1"
140 );
141
142 let mut results: Results = Default::default();
143 for (i, &(name, rust_value)) in RUST_CONSTANTS.iter().enumerate() {
144 match get_c_value(tmpdir.path(), &cc, name) {
145 Err(e) => {
146 results.record_failed_to_compile();
147 eprintln!("{}", e);
148 }
149 Ok(ref c_value) => {
150 if rust_value == c_value {
151 results.record_passed();
152 } else {
153 results.record_failed();
154 eprintln!(
155 "Constant value mismatch for {}\nRust: {:?}\nC: {:?}",
156 name, rust_value, c_value
157 );
158 }
159 }
160 };
161 if (i + 1) % 25 == 0 {
162 println!("constants ... {}", results.summary());
163 }
164 }
165 results.expect_total_success();
166 }
167
168 #[test]
cross_validate_layout_with_c()169 fn cross_validate_layout_with_c() {
170 let tmpdir = Builder::new()
171 .prefix("abi")
172 .tempdir()
173 .expect("temporary directory");
174 let cc = Compiler::new().expect("configured compiler");
175
176 assert_eq!(
177 Layout {
178 size: 1,
179 alignment: 1
180 },
181 get_c_layout(tmpdir.path(), &cc, "char").expect("C layout"),
182 "failed to obtain correct layout for char type"
183 );
184
185 let mut results: Results = Default::default();
186 for (i, &(name, rust_layout)) in RUST_LAYOUTS.iter().enumerate() {
187 match get_c_layout(tmpdir.path(), &cc, name) {
188 Err(e) => {
189 results.record_failed_to_compile();
190 eprintln!("{}", e);
191 }
192 Ok(c_layout) => {
193 if rust_layout == c_layout {
194 results.record_passed();
195 } else {
196 results.record_failed();
197 eprintln!(
198 "Layout mismatch for {}\nRust: {:?}\nC: {:?}",
199 name, rust_layout, &c_layout
200 );
201 }
202 }
203 };
204 if (i + 1) % 25 == 0 {
205 println!("layout ... {}", results.summary());
206 }
207 }
208 results.expect_total_success();
209 }
210
get_c_layout(dir: &Path, cc: &Compiler, name: &str) -> Result<Layout, Box<dyn Error>>211 fn get_c_layout(dir: &Path, cc: &Compiler, name: &str) -> Result<Layout, Box<dyn Error>> {
212 let exe = dir.join("layout");
213 let mut cc = cc.clone();
214 cc.define("ABI_TYPE_NAME", name);
215 cc.compile(Path::new("tests/layout.c"), &exe)?;
216
217 let mut abi_cmd = Command::new(exe);
218 let output = abi_cmd.output()?;
219 if !output.status.success() {
220 return Err(format!("command {:?} failed, {:?}", &abi_cmd, &output).into());
221 }
222
223 let stdout = str::from_utf8(&output.stdout)?;
224 let mut words = stdout.trim().split_whitespace();
225 let size = words.next().unwrap().parse().unwrap();
226 let alignment = words.next().unwrap().parse().unwrap();
227 Ok(Layout { size, alignment })
228 }
229
get_c_value(dir: &Path, cc: &Compiler, name: &str) -> Result<String, Box<dyn Error>>230 fn get_c_value(dir: &Path, cc: &Compiler, name: &str) -> Result<String, Box<dyn Error>> {
231 let exe = dir.join("constant");
232 let mut cc = cc.clone();
233 cc.define("ABI_CONSTANT_NAME", name);
234 cc.compile(Path::new("tests/constant.c"), &exe)?;
235
236 let mut abi_cmd = Command::new(exe);
237 let output = abi_cmd.output()?;
238 if !output.status.success() {
239 return Err(format!("command {:?} failed, {:?}", &abi_cmd, &output).into());
240 }
241
242 let output = str::from_utf8(&output.stdout)?.trim();
243 if !output.starts_with("###gir test###") || !output.ends_with("###gir test###") {
244 return Err(format!(
245 "command {:?} return invalid output, {:?}",
246 &abi_cmd, &output
247 )
248 .into());
249 }
250
251 Ok(String::from(&output[14..(output.len() - 14)]))
252 }
253
254 const RUST_LAYOUTS: &[(&str, Layout)] = &[
255 (
256 "GdkColorspace",
257 Layout {
258 size: size_of::<GdkColorspace>(),
259 alignment: align_of::<GdkColorspace>(),
260 },
261 ),
262 (
263 "GdkInterpType",
264 Layout {
265 size: size_of::<GdkInterpType>(),
266 alignment: align_of::<GdkInterpType>(),
267 },
268 ),
269 (
270 "GdkPixbufAlphaMode",
271 Layout {
272 size: size_of::<GdkPixbufAlphaMode>(),
273 alignment: align_of::<GdkPixbufAlphaMode>(),
274 },
275 ),
276 (
277 "GdkPixbufError",
278 Layout {
279 size: size_of::<GdkPixbufError>(),
280 alignment: align_of::<GdkPixbufError>(),
281 },
282 ),
283 (
284 "GdkPixbufLoader",
285 Layout {
286 size: size_of::<GdkPixbufLoader>(),
287 alignment: align_of::<GdkPixbufLoader>(),
288 },
289 ),
290 (
291 "GdkPixbufLoaderClass",
292 Layout {
293 size: size_of::<GdkPixbufLoaderClass>(),
294 alignment: align_of::<GdkPixbufLoaderClass>(),
295 },
296 ),
297 (
298 "GdkPixbufRotation",
299 Layout {
300 size: size_of::<GdkPixbufRotation>(),
301 alignment: align_of::<GdkPixbufRotation>(),
302 },
303 ),
304 ];
305
306 const RUST_CONSTANTS: &[(&str, &str)] = &[
307 ("(gint) GDK_COLORSPACE_RGB", "0"),
308 ("(gint) GDK_INTERP_BILINEAR", "2"),
309 ("(gint) GDK_INTERP_HYPER", "3"),
310 ("(gint) GDK_INTERP_NEAREST", "0"),
311 ("(gint) GDK_INTERP_TILES", "1"),
312 ("(gint) GDK_PIXBUF_ALPHA_BILEVEL", "0"),
313 ("(gint) GDK_PIXBUF_ALPHA_FULL", "1"),
314 ("(gint) GDK_PIXBUF_ERROR_BAD_OPTION", "2"),
315 ("(gint) GDK_PIXBUF_ERROR_CORRUPT_IMAGE", "0"),
316 ("(gint) GDK_PIXBUF_ERROR_FAILED", "5"),
317 ("(gint) GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION", "6"),
318 ("(gint) GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY", "1"),
319 ("(gint) GDK_PIXBUF_ERROR_UNKNOWN_TYPE", "3"),
320 ("(gint) GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION", "4"),
321 ("(gint) GDK_PIXBUF_ROTATE_CLOCKWISE", "270"),
322 ("(gint) GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE", "90"),
323 ("(gint) GDK_PIXBUF_ROTATE_NONE", "0"),
324 ("(gint) GDK_PIXBUF_ROTATE_UPSIDEDOWN", "180"),
325 ];
326