Skip to content
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

Implement doc tests #302

Merged
merged 2 commits into from
Aug 7, 2014
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
29 changes: 11 additions & 18 deletions src/bin/cargo-test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ extern crate docopt;
use std::io::process::ExitStatus;

use cargo::ops;
use cargo::{execute_main_without_stdin};
use cargo::core::{MultiShell};
use cargo::util;
use cargo::execute_main_without_stdin;
use cargo::core::MultiShell;
use cargo::util::{CliResult, CliError, CargoError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};

Expand Down Expand Up @@ -48,24 +47,18 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
target: None,
};

let test_executables = try!(ops::compile(&root,
&mut compile_opts).map_err(|err| {
let err = try!(ops::run_tests(&root, &mut compile_opts,
options.arg_args.as_slice()).map_err(|err| {
CliError::from_boxed(err, 101)
}));

let test_dir = root.dir_path().join("target").join("test");

for file in test_executables.iter() {
try!(util::process(test_dir.join(file.as_slice()))
.args(options.arg_args.as_slice())
.exec().map_err(|e| {
let exit_status = match e.exit {
match err {
None => Ok(None),
Some(err) => {
let status = match err.exit {
Some(ExitStatus(i)) => i as uint,
_ => 1,
_ => 101,
};
CliError::from_boxed(e.mark_human(), exit_status)
}));
Err(CliError::from_boxed(err.mark_human(), status))
}
}

Ok(None)
}
22 changes: 6 additions & 16 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ pub struct CompileOptions<'a> {
}

pub fn compile(manifest_path: &Path,
options: &mut CompileOptions) -> CargoResult<Vec<String>> {
options: &mut CompileOptions)
-> CargoResult<HashMap<PackageId, Vec<Path>>> {
let CompileOptions { update, env, ref mut shell, jobs, target } = *options;
let target = target.map(|s| s.to_string());

Expand Down Expand Up @@ -114,31 +115,20 @@ pub fn compile(manifest_path: &Path,
}
}).collect::<Vec<&Target>>();

{
let ret = {
let _p = profile::start("compiling");
let mut config = try!(Config::new(*shell, update, jobs, target));
try!(scrape_target_config(&mut config, &user_configs));

try!(ops::compile_targets(env.as_slice(), targets.as_slice(), &package,
&PackageSet::new(packages.as_slice()),
&resolve_with_overrides, &sources,
&mut config));
}
&mut config))
};

try!(ops::write_resolve(&package, &resolve));

let test_executables: Vec<String> = targets.iter()
.filter_map(|target| {
if target.get_profile().is_test() {
debug!("Run Target: {}", target.get_name());
Some(target.file_stem())
} else {
debug!("Skip Target: {}", target.get_name());
None
}
}).collect();

Ok(test_executables)
return Ok(ret);
}

fn source_ids_from_config(configs: &HashMap<String, config::ConfigValue>,
Expand Down
51 changes: 46 additions & 5 deletions src/cargo/ops/cargo_rustc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::collections::{HashSet, HashMap};
use std::dynamic_lib::DynamicLibrary;
use std::io::{fs, UserRWX};
use std::os;
Expand Down Expand Up @@ -41,11 +41,15 @@ fn uniq_target_dest<'a>(targets: &[&'a Target]) -> Option<&'a str> {
curr.unwrap()
}

// Returns a mapping of the root package plus its immediate dependencies to
// where the compiled libraries are all located.
pub fn compile_targets<'a>(env: &str, targets: &[&'a Target], pkg: &'a Package,
deps: &PackageSet, resolve: &'a Resolve, sources: &'a SourceMap,
config: &'a mut Config<'a>) -> CargoResult<()> {
deps: &PackageSet, resolve: &'a Resolve,
sources: &'a SourceMap,
config: &'a mut Config<'a>)
-> CargoResult<HashMap<PackageId, Vec<Path>>> {
if targets.is_empty() {
return Ok(());
return Ok(HashMap::new());
}

debug!("compile_targets; targets={}; pkg={}; deps={}", targets, pkg, deps);
Expand Down Expand Up @@ -82,8 +86,12 @@ pub fn compile_targets<'a>(env: &str, targets: &[&'a Target], pkg: &'a Package,
cx.primary();
try!(compile(targets, pkg, &mut cx, &mut queue));

let ret = build_return_map(&cx, pkg, deps);

// Now that we've figured out everything that we're going to do, do it!
queue.execute(cx.config)
try!(queue.execute(cx.config));

Ok(ret)
}

fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
Expand Down Expand Up @@ -453,3 +461,36 @@ fn pre_version_component(v: &Version) -> Option<String> {

Some(ret)
}

fn build_return_map(cx: &Context, root: &Package, deps: &PackageSet)
-> HashMap<PackageId, Vec<Path>> {
let mut ret = HashMap::new();
match cx.resolve.deps(root.get_package_id()) {
Some(mut my_deps) => {
for dep in my_deps {
let pkg = deps.iter().find(|p| p.get_package_id() == dep).unwrap();
ret.insert(dep.clone(), build_paths(cx, pkg, false));
}
}
None => {}
}
ret.insert(root.get_package_id().clone(), build_paths(cx, root, true));
return ret;

fn build_paths(cx: &Context, pkg: &Package, root: bool) -> Vec<Path> {
pkg.get_targets().iter().filter(|target| {
target.get_profile().is_compile() && target.is_lib()
}).flat_map(|target| {
let kind = if target.get_profile().is_plugin() {
KindPlugin
} else {
KindTarget
};
let layout = cx.layout(kind);
cx.target_filenames(target).move_iter().map(|filename| {
let root = if root {layout.root()} else {layout.deps()};
root.join(filename)
}).collect::<Vec<Path>>().move_iter()
}).collect()
}
}
77 changes: 77 additions & 0 deletions src/cargo/ops/cargo_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::os;

use core::Source;
use sources::PathSource;
use ops;
use util::{process, CargoResult, ProcessError};

pub fn run_tests(manifest_path: &Path,
options: &mut ops::CompileOptions,
args: &[String]) -> CargoResult<Option<ProcessError>> {
let mut source = PathSource::for_path(&manifest_path.dir_path());
try!(source.update());
let package = try!(source.get_root_package());

let compiled_libs = try!(ops::compile(manifest_path, options));

let mut exes: Vec<Path> = package.get_targets().iter().filter_map(|target| {
if !target.get_profile().is_test() { return None }
let root = package.get_root().join("target");
let root = match target.get_profile().get_dest() {
Some(dest) => root.join(dest),
None => root,
};
Some(root.join(target.file_stem()))
}).collect();
exes.sort();

let cwd = os::getcwd();
for exe in exes.iter() {
let to_display = match exe.path_relative_from(&cwd) {
Some(path) => path,
None => exe.clone(),
};
try!(options.shell.status("Running", to_display.display()));
match process(exe).args(args).exec() {
Ok(()) => {}
Err(e) => return Ok(Some(e))
}
}

let mut libs = package.get_targets().iter().filter_map(|target| {
if !target.get_profile().is_test() || !target.is_lib() {
return None
}
Some((target.get_src_path(), target.get_name()))
});

for (lib, name) in libs {
try!(options.shell.status("Doc-tests", name));
let mut p = process("rustdoc").arg("--test").arg(lib)
.arg("--crate-name").arg(name)
.arg("-L").arg("target/test")
.arg("-L").arg("target/test/deps")
.cwd(package.get_root());

// FIXME(rust-lang/rust#16272): this should just always be passed.
if args.len() > 0 {
p = p.arg("--test-args").arg(args.connect(" "));
}

for (pkg, libs) in compiled_libs.iter() {
for lib in libs.iter() {
let mut arg = pkg.get_name().as_bytes().to_vec();
arg.push(b'=');
arg.push_all(lib.as_vec());
p = p.arg("--extern").arg(arg.as_slice());
}
}

match p.exec() {
Ok(()) => {}
Err(e) => return Ok(Some(e)),
}
}

Ok(None)
}
2 changes: 2 additions & 0 deletions src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub use self::cargo_new::{new, NewOptions};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::{generate_lockfile, write_resolve};
pub use self::cargo_generate_lockfile::{update_lockfile, load_lockfile};
pub use self::cargo_test::run_tests;

mod cargo_clean;
mod cargo_compile;
Expand All @@ -16,3 +17,4 @@ mod cargo_run;
mod cargo_new;
mod cargo_doc;
mod cargo_generate_lockfile;
mod cargo_test;
2 changes: 1 addition & 1 deletion src/cargo/util/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ fn normalize(libs: &[TomlLibTarget],
|bin| format!("src/bin/{}.rs", bin.name));
},
([_, ..], []) => {
lib_targets(&mut ret, libs, test_dep, metadata);
lib_targets(&mut ret, libs, Needed, metadata);
},
([], [_, ..]) => {
bin_targets(&mut ret, bins, test_dep, metadata,
Expand Down
1 change: 1 addition & 0 deletions tests/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,3 +499,4 @@ pub static RUNNING: &'static str = " Running";
pub static COMPILING: &'static str = " Compiling";
pub static FRESH: &'static str = " Fresh";
pub static UPDATING: &'static str = " Updating";
pub static DOCTEST: &'static str = " Doc-tests";
6 changes: 0 additions & 6 deletions tests/test_cargo_freshness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ test!(modify_only_some_files {

let lib = p.root().join("src/lib.rs");
let bin = p.root().join("src/b.rs");
let test = p.root().join("tests/test.rs");

File::create(&lib).write_str("invalid rust code").assert();
lib.move_into_the_past().assert();
Expand All @@ -85,9 +84,4 @@ test!(modify_only_some_files {
{compiling} foo v0.0.1 (file:{dir})
", compiling = COMPILING, dir = p.root().display())));
assert_that(&p.bin("foo"), existing_file());

// Make sure the tests don't recompile the lib
File::create(&test).write_str("fn foo() {}").assert();
assert_that(p.process(cargo_dir().join("cargo-test")),
execs().with_status(0));
})
Loading