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