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()?)
.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<MAXNAMELEN>; /* data creator */
case EXEC:
string interpretor<MAXNAMELEN>; /* program interpretor */
};
/*
* A complete file:
*/
struct file {
string filename<MAXNAMELEN>; /* name of file */
filetype type; /* info about file */
string owner<MAXUSERNAME>; /* owner of file */
opaque data<MAXFILELEN>; /* 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);
}
}