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 use gdk_pixbuf_sys::*;
6 use std::env;
7 use std::error::Error;
8 use std::ffi::OsString;
9 use std::mem::{align_of, size_of};
10 use std::path::Path;
11 use std::process::Command;
12 use std::str;
13 use tempfile::Builder;
14 
15 static PACKAGES: &[&str] = &["gdk-pixbuf-2.0"];
16 
17 #[derive(Clone, Debug)]
18 struct Compiler {
19     pub args: Vec<String>,
20 }
21 
22 impl Compiler {
new() -> Result<Self, Box<dyn Error>>23     pub fn new() -> Result<Self, Box<dyn Error>> {
24         let mut args = get_var("CC", "cc")?;
25         args.push("-Wno-deprecated-declarations".to_owned());
26         // For _Generic
27         args.push("-std=c11".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(Self { args })
34     }
35 
compile(&self, src: &Path, out: &Path) -> Result<(), Box<dyn Error>>36     pub fn compile(&self, src: &Path, out: &Path) -> Result<(), Box<dyn Error>> {
37         let mut cmd = self.to_command();
38         cmd.arg(src);
39         cmd.arg("-o");
40         cmd.arg(out);
41         let status = cmd.spawn()?.wait()?;
42         if !status.success() {
43             return Err(format!("compilation command {:?} failed, {}", &cmd, status).into());
44         }
45         Ok(())
46     }
47 
to_command(&self) -> Command48     fn to_command(&self) -> Command {
49         let mut cmd = Command::new(&self.args[0]);
50         cmd.args(&self.args[1..]);
51         cmd
52     }
53 }
54 
get_var(name: &str, default: &str) -> Result<Vec<String>, Box<dyn Error>>55 fn get_var(name: &str, default: &str) -> Result<Vec<String>, Box<dyn Error>> {
56     match env::var(name) {
57         Ok(value) => Ok(shell_words::split(&value)?),
58         Err(env::VarError::NotPresent) => Ok(shell_words::split(default)?),
59         Err(err) => Err(format!("{} {}", name, err).into()),
60     }
61 }
62 
pkg_config_cflags(packages: &[&str]) -> Result<Vec<String>, Box<dyn Error>>63 fn pkg_config_cflags(packages: &[&str]) -> Result<Vec<String>, Box<dyn Error>> {
64     if packages.is_empty() {
65         return Ok(Vec::new());
66     }
67     let pkg_config = env::var_os("PKG_CONFIG").unwrap_or_else(|| OsString::from("pkg-config"));
68     let mut cmd = Command::new(pkg_config);
69     cmd.arg("--cflags");
70     cmd.args(packages);
71     let out = cmd.output()?;
72     if !out.status.success() {
73         return Err(format!("command {:?} returned {}", &cmd, out.status).into());
74     }
75     let stdout = str::from_utf8(&out.stdout)?;
76     Ok(shell_words::split(stdout.trim())?)
77 }
78 
79 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
80 struct Layout {
81     size: usize,
82     alignment: usize,
83 }
84 
85 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
86 struct Results {
87     /// Number of successfully completed tests.
88     passed: usize,
89     /// Total number of failed tests (including those that failed to compile).
90     failed: usize,
91 }
92 
93 impl Results {
record_passed(&mut self)94     fn record_passed(&mut self) {
95         self.passed += 1;
96     }
record_failed(&mut self)97     fn record_failed(&mut self) {
98         self.failed += 1;
99     }
summary(&self) -> String100     fn summary(&self) -> String {
101         format!("{} passed; {} failed", self.passed, self.failed)
102     }
expect_total_success(&self)103     fn expect_total_success(&self) {
104         if self.failed == 0 {
105             println!("OK: {}", self.summary());
106         } else {
107             panic!("FAILED: {}", self.summary());
108         };
109     }
110 }
111 
112 #[test]
cross_validate_constants_with_c()113 fn cross_validate_constants_with_c() {
114     let mut c_constants: Vec<(String, String)> = Vec::new();
115 
116     for l in get_c_output("constant").unwrap().lines() {
117         let mut words = l.trim().split(';');
118         let name = words.next().expect("Failed to parse name").to_owned();
119         let value = words
120             .next()
121             .and_then(|s| s.parse().ok())
122             .expect("Failed to parse value");
123         c_constants.push((name, value));
124     }
125 
126     let mut results = Results::default();
127 
128     for ((rust_name, rust_value), (c_name, c_value)) in
129         RUST_CONSTANTS.iter().zip(c_constants.iter())
130     {
131         if rust_name != c_name {
132             results.record_failed();
133             eprintln!("Name mismatch:\nRust: {:?}\nC:    {:?}", rust_name, c_name,);
134             continue;
135         }
136 
137         if rust_value != c_value {
138             results.record_failed();
139             eprintln!(
140                 "Constant value mismatch for {}\nRust: {:?}\nC:    {:?}",
141                 rust_name, rust_value, &c_value
142             );
143             continue;
144         }
145 
146         results.record_passed();
147     }
148 
149     results.expect_total_success();
150 }
151 
152 #[test]
cross_validate_layout_with_c()153 fn cross_validate_layout_with_c() {
154     let mut c_layouts = Vec::new();
155 
156     for l in get_c_output("layout").unwrap().lines() {
157         let mut words = l.trim().split(';');
158         let name = words.next().expect("Failed to parse name").to_owned();
159         let size = words
160             .next()
161             .and_then(|s| s.parse().ok())
162             .expect("Failed to parse size");
163         let alignment = words
164             .next()
165             .and_then(|s| s.parse().ok())
166             .expect("Failed to parse alignment");
167         c_layouts.push((name, Layout { size, alignment }));
168     }
169 
170     let mut results = Results::default();
171 
172     for ((rust_name, rust_layout), (c_name, c_layout)) in RUST_LAYOUTS.iter().zip(c_layouts.iter())
173     {
174         if rust_name != c_name {
175             results.record_failed();
176             eprintln!("Name mismatch:\nRust: {:?}\nC:    {:?}", rust_name, c_name,);
177             continue;
178         }
179 
180         if rust_layout != c_layout {
181             results.record_failed();
182             eprintln!(
183                 "Layout mismatch for {}\nRust: {:?}\nC:    {:?}",
184                 rust_name, rust_layout, &c_layout
185             );
186             continue;
187         }
188 
189         results.record_passed();
190     }
191 
192     results.expect_total_success();
193 }
194 
get_c_output(name: &str) -> Result<String, Box<dyn Error>>195 fn get_c_output(name: &str) -> Result<String, Box<dyn Error>> {
196     let tmpdir = Builder::new().prefix("abi").tempdir()?;
197     let exe = tmpdir.path().join(name);
198     let c_file = Path::new("tests").join(name).with_extension("c");
199 
200     let cc = Compiler::new().expect("configured compiler");
201     cc.compile(&c_file, &exe)?;
202 
203     let mut abi_cmd = Command::new(exe);
204     let output = abi_cmd.output()?;
205     if !output.status.success() {
206         return Err(format!("command {:?} failed, {:?}", &abi_cmd, &output).into());
207     }
208 
209     Ok(String::from_utf8(output.stdout)?)
210 }
211 
212 const RUST_LAYOUTS: &[(&str, Layout)] = &[
213     (
214         "GdkColorspace",
215         Layout {
216             size: size_of::<GdkColorspace>(),
217             alignment: align_of::<GdkColorspace>(),
218         },
219     ),
220     (
221         "GdkInterpType",
222         Layout {
223             size: size_of::<GdkInterpType>(),
224             alignment: align_of::<GdkInterpType>(),
225         },
226     ),
227     (
228         "GdkPixbufAlphaMode",
229         Layout {
230             size: size_of::<GdkPixbufAlphaMode>(),
231             alignment: align_of::<GdkPixbufAlphaMode>(),
232         },
233     ),
234     (
235         "GdkPixbufAnimation",
236         Layout {
237             size: size_of::<GdkPixbufAnimation>(),
238             alignment: align_of::<GdkPixbufAnimation>(),
239         },
240     ),
241     (
242         "GdkPixbufAnimationClass",
243         Layout {
244             size: size_of::<GdkPixbufAnimationClass>(),
245             alignment: align_of::<GdkPixbufAnimationClass>(),
246         },
247     ),
248     (
249         "GdkPixbufAnimationIter",
250         Layout {
251             size: size_of::<GdkPixbufAnimationIter>(),
252             alignment: align_of::<GdkPixbufAnimationIter>(),
253         },
254     ),
255     (
256         "GdkPixbufAnimationIterClass",
257         Layout {
258             size: size_of::<GdkPixbufAnimationIterClass>(),
259             alignment: align_of::<GdkPixbufAnimationIterClass>(),
260         },
261     ),
262     (
263         "GdkPixbufError",
264         Layout {
265             size: size_of::<GdkPixbufError>(),
266             alignment: align_of::<GdkPixbufError>(),
267         },
268     ),
269     (
270         "GdkPixbufFormat",
271         Layout {
272             size: size_of::<GdkPixbufFormat>(),
273             alignment: align_of::<GdkPixbufFormat>(),
274         },
275     ),
276     (
277         "GdkPixbufFormatFlags",
278         Layout {
279             size: size_of::<GdkPixbufFormatFlags>(),
280             alignment: align_of::<GdkPixbufFormatFlags>(),
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         "GdkPixbufModule",
299         Layout {
300             size: size_of::<GdkPixbufModule>(),
301             alignment: align_of::<GdkPixbufModule>(),
302         },
303     ),
304     (
305         "GdkPixbufModulePattern",
306         Layout {
307             size: size_of::<GdkPixbufModulePattern>(),
308             alignment: align_of::<GdkPixbufModulePattern>(),
309         },
310     ),
311     (
312         "GdkPixbufRotation",
313         Layout {
314             size: size_of::<GdkPixbufRotation>(),
315             alignment: align_of::<GdkPixbufRotation>(),
316         },
317     ),
318 ];
319 
320 const RUST_CONSTANTS: &[(&str, &str)] = &[
321     ("(gint) GDK_COLORSPACE_RGB", "0"),
322     ("(gint) GDK_INTERP_BILINEAR", "2"),
323     ("(gint) GDK_INTERP_HYPER", "3"),
324     ("(gint) GDK_INTERP_NEAREST", "0"),
325     ("(gint) GDK_INTERP_TILES", "1"),
326     ("(gint) GDK_PIXBUF_ALPHA_BILEVEL", "0"),
327     ("(gint) GDK_PIXBUF_ALPHA_FULL", "1"),
328     ("(gint) GDK_PIXBUF_ERROR_BAD_OPTION", "2"),
329     ("(gint) GDK_PIXBUF_ERROR_CORRUPT_IMAGE", "0"),
330     ("(gint) GDK_PIXBUF_ERROR_FAILED", "5"),
331     ("(gint) GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION", "6"),
332     ("(gint) GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY", "1"),
333     ("(gint) GDK_PIXBUF_ERROR_UNKNOWN_TYPE", "3"),
334     ("(gint) GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION", "4"),
335     ("(guint) GDK_PIXBUF_FORMAT_SCALABLE", "2"),
336     ("(guint) GDK_PIXBUF_FORMAT_THREADSAFE", "4"),
337     ("(guint) GDK_PIXBUF_FORMAT_WRITABLE", "1"),
338     ("(gint) GDK_PIXBUF_ROTATE_CLOCKWISE", "270"),
339     ("(gint) GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE", "90"),
340     ("(gint) GDK_PIXBUF_ROTATE_NONE", "0"),
341     ("(gint) GDK_PIXBUF_ROTATE_UPSIDEDOWN", "180"),
342 ];
343