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