extern crate xdrgen; extern crate xdr_codec; extern crate tempdir; #[macro_use] extern crate error_chain; use std::fs::{File, create_dir_all}; use std::io::{Cursor, Write}; use std::process::Command; use xdrgen::generate; use xdr_codec::Result; fn build_test(name: &str, xdr_spec: &str) -> Result<()> { let tempdir = tempdir::TempDir::new("build").expect("Failed to make tempdir"); let dir = tempdir.path(); println!("tempdir {:?}", dir); let _ = create_dir_all(&dir); let mainfile = dir.join(format!("{}.rs", name)); let testfile = dir.join(format!("{}_xdr.rs", name)); let cargohome = dir.join(".cargo"); let cargotoml = dir.join("Cargo.toml"); let toml = format!( r#" [package] name = "test" version = "0.0.0" publish = false [lib] name = "test" path = "{}" [dependencies] xdr-codec = {{ path = "{}" }} "#, mainfile.as_os_str().to_string_lossy(), std::env::current_dir()? .join("../xdr-codec") .as_os_str() .to_string_lossy() ); let template = format!( r#" #![allow(dead_code, non_camel_case_types, unused_assignments, unused_imports)] extern crate xdr_codec; mod test {{ use xdr_codec; include!("{}"); }} fn main() {{}} "#, testfile.as_os_str().to_string_lossy() ); { let mut main = File::create(&mainfile)?; main.write_all(template.as_bytes())?; } { let mut cargo = File::create(&cargotoml)?; cargo.write_all(toml.as_bytes())?; } let _ = create_dir_all(&cargohome); { let test = File::create(&testfile)?; generate(name, Cursor::new(xdr_spec.as_bytes()), test)?; } let compile = { let mut cmd = Command::new("cargo"); let cmd = cmd .current_dir(std::env::current_dir()?) //.env("CARGO_HOME", cargohome) .arg("test") .arg("--manifest-path").arg(cargotoml); println!("CWD: {:?} Command: {:?}", std::env::current_dir(), cmd); cmd.output()? }; println!( "stdout: {}\n, stderr: {}", String::from_utf8_lossy(&compile.stdout), String::from_utf8_lossy(&compile.stderr) ); if compile.status.success() { Ok(()) } else { bail!("couldn't compile") } } #[test] fn typedef_arrays() { let name = "typedef_arrays"; let spec = r#" typedef opaque buf1<20>; typedef opaque buf2[10]; typedef opaque buf3<>; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn recursive_type() { let name = "recursive_type"; let spec = r#" struct list { list *next; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn union_with_default() { let name = "union_with_default"; let spec = r#" union foo switch (int bar) { case 1: int val; default: void; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn union_default_nonempty() { let name = "union_default_nonempty"; let spec = r#" union foo switch (int bar) { case 1: int val; default: opaque buf<>; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn simple() { let name = "simple"; let specs = vec![ "struct foo { int bar; unsigned int blat; hyper foo; unsigned hyper hyperfoo; };", "const blop = 123;", "typedef opaque Ioaddr<>;", ]; for (i, spec) in specs.into_iter().enumerate() { let name = format!("{}_{}", name, i); if let Err(e) = build_test(&name, spec) { panic!("test {} failed: {}", name, e); } } } #[test] fn rfc4506() { let name = "rfc4506"; let spec = r#" const MAXUSERNAME = 32; /* max length of a user name */ const MAXFILELEN = 65535; /* max length of a file */ const MAXNAMELEN = 255; /* max length of a file name */ /* * Types of files: */ enum filekind { TEXT = 0, /* ascii data */ DATA = 1, /* raw data */ EXEC = 2 /* executable */ }; /* * File information, per kind of file: */ union filetype switch (filekind kind) { case TEXT: void; /* no extra information */ case DATA: string creator; /* data creator */ case EXEC: string interpretor; /* program interpretor */ }; /* * A complete file: */ struct file { string filename; /* name of file */ filetype type; /* info about file */ string owner; /* owner of file */ opaque data; /* file data */ }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn enums() { let name = "enums"; let spec = r#" enum Foo { A = 0, B = -1 }; struct Bar { Foo x; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn unions() { let name = "unions"; let spec = r#" enum Foo { A = 0, B = -1 }; union foo switch (Foo bar) { case A: int val; case B: void; default: int other; }; union foo2 switch (Foo bar) { case A: void; case B: int a; default: int other; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn consts() { let name = "consts"; let spec = r#" const FOO = 1; const BAR = -1; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn arrays() { let name = "arrays"; let spec = r#" struct a { opaque data[15]; }; struct b { int things[10]; }; struct c { string decitweet[14]; }; struct d { c tweetses[10]; }; struct big { c tweetses[100]; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn flex() { let name = "flex"; let spec = r#" struct a { opaque data<>; opaque limdata<15>; }; struct b { string s<>; string limstr<32>; }; struct c { a athing<>; a alim<10>; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } } #[test] fn derive_float() { let name = "derive_float"; let spec = r#" struct a { float a; double b; }; "#; if let Err(e) = build_test(name, spec) { panic!("test {} failed: {}", name, e); } }