= if line.contains("bindgen-flags:") {
+ line.split("bindgen-flags:").last().and_then(shlex::split)
+ } else {
+ None
+ }.unwrap_or(Vec::with_capacity(2));
+
+ // Fool builder_from_flags() into believing it has real env::args_os...
+ // - add "bindgen" as executable name 0th element
+ // - add header filename as 1st element
+ // - prepend raw lines so they're in the right order for expected output
+ // - append the test header's bindgen flags
+ let header_str = try!(header.to_str()
+ .ok_or(Error::new(ErrorKind::Other, "Invalid header file name")));
+
+ let prepend = [
+ "bindgen",
+ header_str,
+ "--raw-line", "",
+ "--raw-line", "#![allow(non_snake_case)]",
+ "--raw-line", "",
+ ];
+
+ let args = prepend.into_iter()
+ .map(ToString::to_string)
+ .chain(flags.into_iter());
+
+ 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 {""});
+ }
+}
diff --git a/tests/uses/.gitignore b/libbindgen/tests/uses/.gitignore
similarity index 100%
rename from tests/uses/.gitignore
rename to libbindgen/tests/uses/.gitignore
diff --git a/src/bin/bindgen.rs b/src/main.rs
old mode 100755
new mode 100644
similarity index 96%
rename from src/bin/bindgen.rs
rename to src/main.rs
index 14e882bccf..8cbff63bb8
--- a/src/bin/bindgen.rs
+++ b/src/main.rs
@@ -1,7 +1,4 @@
-#![crate_name = "bindgen"]
-#![crate_type = "bin"]
-
-extern crate bindgen;
+extern crate libbindgen;
extern crate env_logger;
#[macro_use]
extern crate log;
@@ -9,7 +6,7 @@ extern crate clang_sys;
extern crate clap;
extern crate rustc_serialize;
-use bindgen::clang_version;
+use libbindgen::clang_version;
use std::env;
mod options;
diff --git a/src/bin/options.rs b/src/options.rs
similarity index 99%
rename from src/bin/options.rs
rename to src/options.rs
index 9f746fd087..c3c6a1f269 100644
--- a/src/bin/options.rs
+++ b/src/options.rs
@@ -1,8 +1,5 @@
-
-
-use bindgen::{Builder, builder};
-
use clap::{App, Arg};
+use libbindgen::{Builder, builder};
use std::fs::File;
use std::io::{self, Error, ErrorKind};
diff --git a/tests/tests.rs b/tests/tests.rs
deleted file mode 100644
index 1f72fccf9d..0000000000
--- a/tests/tests.rs
+++ /dev/null
@@ -1,171 +0,0 @@
-// We add this `extern crate` here to ensure that bindgen is up-to-date and
-// rebuilt, even though we aren't using any of its types or functions here, only
-// indirectly calling the executable.
-#[allow(dead_code)]
-extern crate bindgen;
-
-use std::env;
-use std::fs;
-use std::io::Read;
-use std::path::{Path, PathBuf};
-use std::process;
-
-const TEST_BATCH_DEFAULT_SIZE: usize = 16;
-
-fn spawn_run_bindgen(run_bindgen: P,
- bindgen: Q,
- header: R)
- -> process::Child
- where P: AsRef,
- Q: AsRef,
- R: AsRef,
-{
- let run_bindgen = run_bindgen.as_ref();
- let bindgen = bindgen.as_ref();
- let header = header.as_ref();
-
- // Convert from "tests/headers/foo.hpp" to "tests/expectations/tests/foo.rs" by
- // saving the filename, popping off "headers/foo.hpp", pushing
- // "expectations/tests", pushing the saved filename, and finally modifying the
- // extension.
-
- let mut expected = PathBuf::from(header);
- let file_name = expected.file_name()
- .expect("Should have filename")
- .to_os_string();
- expected.pop();
- expected.pop();
- expected.push("expectations");
- expected.push("tests");
- expected.push(file_name);
- expected.set_extension("rs");
-
- // And the same style conversion as above, but for the dummy uses. We assume
- // that .hpp means we should generate a .cpp uses file, and .h means we
- // should generate a .c file.
-
- let mut dummy_uses = PathBuf::from(header);
- let file_name = dummy_uses.file_name()
- .expect("Should still have filename")
- .to_os_string();
- dummy_uses.pop();
- dummy_uses.pop();
- dummy_uses.push("uses");
- dummy_uses.push(file_name);
- dummy_uses.set_extension(if header.extension().and_then(|s| s.to_str()) ==
- Some("hpp") {
- "cpp"
- } else {
- "c"
- });
-
- process::Command::new(run_bindgen)
- .stdout(process::Stdio::piped())
- .stderr(process::Stdio::piped())
- .arg(bindgen)
- .arg(header)
- .arg(expected)
- .arg("--dummy-uses")
- .arg(dummy_uses)
- .spawn()
- .expect("Should be able to spawn run-bindgen.py child process")
-}
-
-#[test]
-fn run_bindgen_tests() {
- let crate_root = env::var("CARGO_MANIFEST_DIR")
- .expect("should have CARGO_MANIFEST_DIR environment variable");
-
- let mut run_bindgen = PathBuf::from(&crate_root);
- run_bindgen.push("tests");
- run_bindgen.push("tools");
- run_bindgen.push("run-bindgen.py");
-
- let mut bindgen = PathBuf::from(&crate_root);
- bindgen.push("target");
- if cfg!(debug_assertions) {
- bindgen.push("debug");
- } else {
- bindgen.push("release");
- }
- bindgen.push("bindgen");
- if !bindgen.is_file() {
- panic!("{} is not a file! Build bindgen before running tests.",
- bindgen.display());
- }
-
- let mut headers_dir = PathBuf::from(&crate_root);
- headers_dir.push("tests");
- headers_dir.push("headers");
-
- let entries = fs::read_dir(&headers_dir)
- .expect("Should read directory")
- .map(|result| result.expect("Should read directory entry"));
-
- let tests = entries.filter(|entry| {
- match entry.path().extension().and_then(|s| s.to_str()) {
- Some("h") | Some("hpp") => true,
- _ => false,
- }
- })
- .collect::>();
-
- let batch_size = env::var("BINDGEN_TEST_BATCH_SIZE")
- .ok()
- .and_then(|x| x.parse::().ok())
- .unwrap_or(TEST_BATCH_DEFAULT_SIZE);
-
- // Spawn `batch_size` children to run in parallel and wait on all of them
- // before processing the next batch. This puts a limit on the resources
- // consumed when testing, so that we don't overload the system.
-
- let children = tests.chunks(batch_size).map(|x| {
- x.iter()
- .map(|entry| {
- let child = spawn_run_bindgen(run_bindgen.clone(),
- bindgen.clone(),
- entry.path());
- (entry.path(), child)
- })
- .collect::>()
- });
-
- let failures: Vec<_> = children.flat_map(|x| {
- x.into_iter().filter_map(|(path, mut child)| {
- let passed = child.wait()
- .expect("Should wait on child process")
- .success();
-
- if passed { None } else { Some((path, child)) }
- })
- })
- .collect();
-
- let num_failures = failures.len();
-
- for (path, child) in failures {
- println!("FAIL: {}", path.display());
-
- let mut buf = String::new();
-
- child.stdout
- .expect("should have stdout piped")
- .read_to_string(&mut buf)
- .expect("should read child's stdout");
- for line in buf.lines() {
- println!("child stdout> {}", line);
- }
-
- child.stderr
- .expect("should have stderr piped")
- .read_to_string(&mut buf)
- .expect("should read child's stderr");
- for line in buf.lines() {
- println!("child stderr> {}", line);
- }
- }
-
- if num_failures > 0 {
- panic!("{} test failures!", num_failures);
- }
-}
diff --git a/tests/tools/run-bindgen.py b/tests/tools/run-bindgen.py
deleted file mode 100755
index 519e6891af..0000000000
--- a/tests/tools/run-bindgen.py
+++ /dev/null
@@ -1,175 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-
-import argparse
-import difflib
-import os
-import sys
-import subprocess
-import tempfile
-import shlex
-
-BINDGEN_FLAGS_PREFIX = "// bindgen-flags: "
-
-COMMON_PRELUDE = """
-#![allow(non_snake_case)]
-"""
-
-DESCRIPTION = """
-Run bindgen on a test header and check the generated bindings against expected
-output.
-"""
-
-def make_parser():
- """Make the commandline parser"""
- parser = argparse.ArgumentParser(description=DESCRIPTION)
- parser.add_argument("bindgen",
- metavar="BINDGEN",
- help="The path to the bindgen executable")
- parser.add_argument("header",
- metavar="HEADER",
- help="The path to the input header")
- parser.add_argument("rust_bindings",
- metavar="RUST_BINDINGS",
- help="The path to the generated rust output. If a file \
- at this path already exists, the newly generated \
- bindings will be checked against those extant \
- expected bindings.")
- parser.add_argument("--feature",
- dest="features",
- action="append",
- nargs=1,
- help="Run tests that depend on bindgen being built with \
- the given feature.")
- parser.add_argument("--dummy-uses",
- dest="dummy_uses",
- help="The path to generate dummy C/C++ uses of the \
- whitelisted types from the input header at.")
- return parser
-
-def usage_and_exit(*args):
- """Print the program usage and exit. If args are given, print them first"""
- if len(args) > 0:
- print(*args)
- make_parser().print_help()
- sys.exit(1)
-
-def parse_args():
- """Get, parse, and validate commandline arguments."""
- parser = make_parser()
- args = parser.parse_args()
-
- if args.features is None:
- args.features = []
-
- if not os.path.isfile(args.bindgen):
- usage_and_exit("error: bindgen is not a file:", args.bindgen)
-
- if not os.path.isfile(args.header):
- usage_and_exit("error: header is not a file:", args.header)
-
- return args
-
-def make_bindgen_env():
- """Build the environment to run bindgen in."""
- env = os.environ.copy()
- env["RUST_BACKTRACE"] = "1"
-
- # El Capitan likes to unset dyld variables
- # https://forums.developer.apple.com/thread/9233
- if "DYLD_LIBRARY_PATH" not in env and "LIBCLANG_PATH" in env:
- env["DYLD_LIBRARY_PATH"] = env["LIBCLANG_PATH"]
-
- return env
-
-def get_bindgen_flags(header_path):
- """
- Return the bindgen flags required for this header
- """
- flags = ["--no-unstable-rust"]
- for line in COMMON_PRELUDE.split("\n"):
- flags.append("--raw-line")
- flags.append(line)
-
- with open(header_path) as f:
- for line in f:
- if line.startswith(BINDGEN_FLAGS_PREFIX):
- flags.extend(shlex.split(line.strip().split(BINDGEN_FLAGS_PREFIX)[1]))
- break
-
- return flags
-
-def get_expected_bindings(rust_bindings_path):
- """
- Get the expected, generated rust bindings output, or None if there is no
- expected output yet.
- """
- expected_bindings = None
- if os.path.isfile(rust_bindings_path):
- with open(rust_bindings_path) as f:
- expected_bindings = f.read()
- return expected_bindings
-
-def get_actual_bindings(rust_bindings_path):
- """Get the actual generated rust bindings output."""
- assert os.path.isfile(rust_bindings_path)
- with open(rust_bindings_path) as f:
- return f.read()
-
-def run_cmd(command, **kwargs):
- """Run the given command, passing through **kwargs to subprocess.check_call"""
- print("run-bindgen.py: running", command)
- subprocess.check_call(command, **kwargs)
-
-def generate_bindings(bindgen, dummy_uses, flags, header, output):
- """Generate the rust bindings."""
- command = [bindgen, "-o", output]
- if dummy_uses:
- command.extend(["--dummy-uses", dummy_uses])
- command.extend(flags)
- command.append(header)
- run_cmd(command, cwd=os.getcwd(), env=make_bindgen_env())
-
-def check_actual_vs_expected(expected_bindings, rust_bindings_path):
- """
- Check the actual generated rust bindings versus our expected generated rust
- bindings. If they don't match up, print a diff between them and exit with a
- failure.
- """
- if expected_bindings is None:
- return
-
- actual_bindings = get_actual_bindings(rust_bindings_path)
- if actual_bindings == expected_bindings:
- return
-
- print("error: actual generated bindings do not match expected generated bindings!")
-
- def to_diffable(s):
- return map(lambda l: l + "\n", s.split("\n"))
-
- diff = difflib.unified_diff(to_diffable(expected_bindings),
- to_diffable(actual_bindings),
- fromfile="expected_bindings.rs",
- tofile="actual_bindings.rs")
- sys.stderr.writelines(diff)
- sys.stderr.write("\n")
-
- sys.exit(1)
-
-def main():
- args = parse_args()
-
- test_flags = get_bindgen_flags(args.header)
- expected_bindings = get_expected_bindings(args.rust_bindings)
- generate_bindings(args.bindgen,
- args.dummy_uses,
- test_flags,
- args.header,
- args.rust_bindings)
- check_actual_vs_expected(expected_bindings, args.rust_bindings)
- sys.exit(0)
-
-if __name__ == "__main__":
- main()