Skip to content

Generate a separate test function for every header #261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions libbindgen/build.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
mod codegen {
extern crate quasi_codegen;
use std::path::Path;
use std::env;

pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let out_dir = Path::new(env!("OUT_DIR"));
let src = Path::new("src/codegen/mod.rs");
let dst = Path::new(&out_dir).join("codegen.rs");

Expand All @@ -14,6 +13,42 @@ mod codegen {
}
}

mod testgen {
use std::char;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;

pub fn main() {
let out_dir = Path::new(env!("OUT_DIR"));
let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap();

let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let headers_dir = manifest_dir.join("tests").join("headers");

let entries = fs::read_dir(headers_dir)
.expect("Couldn't read headers dir")
.map(|result| result.expect("Couldn't read header file"));

for entry in entries {
match entry.path().extension().and_then(OsStr::to_str) {
Some("h") | Some("hpp") => {
let func = entry.file_name().to_str().unwrap()
.replace(|c| !char::is_alphanumeric(c), "_")
.replace("__", "_")
.to_lowercase();
let _ = writeln!(dst, "test_header!(header_{}, {:?});",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think You need to write these in a block to avoid rust-lang/rust#35560

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The include!() is not itself in a function, so it just pulls in a bunch of test function definitions, and doesn't interact with that bug. I'm getting the same pass/fail rate as #204, only pretty. 😄

test result: FAILED. 120 passed; 1 failed; 0 ignored; 0 measured

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sounds good then :)

Do you plan to land everything here (and thus close #204), or splitting the last commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll rebase this once #204 has landed -- further comments over there. :-)

func, entry.path());
}
_ => {}
}
}
let _ = dst.flush();
}
}

fn main() {
codegen::main();
testgen::main();
}
58 changes: 14 additions & 44 deletions libbindgen/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ extern crate libbindgen;
extern crate log;
extern crate shlex;

use std::env;
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Read};
use std::path::{Path, PathBuf};
use std::path::PathBuf;

#[path="../../src/options.rs"]
mod options;
Expand Down Expand Up @@ -93,46 +92,17 @@ fn create_bindgen_builder(header: &PathBuf)
builder_from_flags(args).map(|(builder, _)| builder.no_unstable_rust())
}

#[test]
fn run_bindgen_tests() {
log::set_logger(|max_log_level| {
use env_logger::Logger;
let env_logger = Logger::new();
max_log_level.set(env_logger.filter());
Box::new(env_logger)
})
.expect("Failed to set logger.");

let manifest_env = env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR not set!");
let manifest_dir = Path::new(&manifest_env);
let headers_dir = manifest_dir.join("tests").join("headers");

let entries = fs::read_dir(&headers_dir)
.expect("Couldn't read headers dir")
.map(|result| result.expect("Couldn't read header file"));

let headers: Vec<_> = entries.filter_map(|entry| {
match entry.path().extension().and_then(|s| s.to_str()) {
Some("h") | Some("hpp") => Some(entry.path()),
_ => None,
}
})
.collect();

let failures: Vec<_> = headers.iter()
.filter_map(|header| {
create_bindgen_builder(header)
.and_then(|builder| compare_generated_header(header, builder))
.err()
})
.collect();

let num_failures = failures.len();

if num_failures > 0 {
panic!("{} test{} failed!",
num_failures,
if num_failures > 1 {"s"} else {""});
}
macro_rules! test_header {
($function:ident, $header:expr) => (
#[test]
fn $function() {
let header = PathBuf::from($header);
let _ = create_bindgen_builder(&header)
.and_then(|builder| compare_generated_header(&header, builder))
.map_err(|err| panic!(format!("{}", err)) );
}
)
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));