use syntax::{ast, diagnostic};
use util::*;
use messages::{error, warn, note};
-use path_util::build_pkg_id_in_workspace;
+use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
use path_util::{U_RWX, in_rust_path};
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
use path_util::{target_executable_in_workspace, target_library_in_workspace};
LLVMAssemble, LLVMCompileBitcode};
use package_id::PkgId;
use package_source::PkgSrc;
-use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
+use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench, Tests};
// use workcache_support::{discover_outputs, digest_only_date};
use workcache_support::digest_only_date;
use exit_codes::COPY_FAILED_CODE;
pub trait CtxMethods {
fn run(&self, cmd: &str, args: ~[~str]);
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
+ /// Returns a pair of the selected package ID, and the destination workspace
+ fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(PkgId, Path)>;
/// Returns the destination workspace
fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
fn clean(&self, workspace: &Path, id: &PkgId);
target_workspace: &Path,
id: &PkgId) -> ~[~str];
fn prefer(&self, _id: &str, _vers: Option<~str>);
- fn test(&self);
+ fn test(&self, id: &PkgId, workspace: &Path);
fn uninstall(&self, _id: &str, _vers: Option<~str>);
fn unprefer(&self, _id: &str, _vers: Option<~str>);
fn init(&self);
}
impl CtxMethods for BuildContext {
+ fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(PkgId, Path)> {
+ if args.len() < 1 {
+ match cwd_to_workspace() {
+ None if self.context.use_rust_path_hack => {
+ let cwd = os::getcwd();
+ let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
+ let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
+ let dest_ws = self.build(&mut pkg_src, what);
+ Some((pkg_src.id, dest_ws))
+ }
+ None => { usage::build(); None }
+ Some((ws, pkgid)) => {
+ let mut pkg_src = PkgSrc::new(ws, false, pkgid);
+ let dest_ws = self.build(&mut pkg_src, what);
+ Some((pkg_src.id, dest_ws))
+ }
+ }
+ } else {
+ // The package id is presumed to be the first command-line
+ // argument
+ let pkgid = PkgId::new(args[0].clone());
+ let mut dest_ws = None;
+ do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
+ debug!("found pkg %s in workspace %s, trying to build",
+ pkgid.to_str(), workspace.to_str());
+ let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
+ dest_ws = Some(self.build(&mut pkg_src, what));
+ true
+ };
+ assert!(dest_ws.is_some());
+ // n.b. If this builds multiple packages, it only returns the workspace for
+ // the last one. The whole building-multiple-packages-with-the-same-ID is weird
+ // anyway and there are no tests for it, so maybe take it out
+ Some((pkgid, dest_ws.unwrap()))
+ }
+ }
fn run(&self, cmd: &str, args: ~[~str]) {
match cmd {
"build" => {
- if args.len() < 1 {
- match cwd_to_workspace() {
- None if self.context.use_rust_path_hack => {
- let cwd = os::getcwd();
- let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
- let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
- self.build(&mut pkg_src, &Everything);
- }
- None => { usage::build(); return; }
- Some((ws, pkgid)) => {
- let mut pkg_src = PkgSrc::new(ws, false, pkgid);
- self.build(&mut pkg_src, &Everything);
- }
- }
- }
- else {
- // The package id is presumed to be the first command-line
- // argument
- let pkgid = PkgId::new(args[0].clone());
- do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
- debug!("found pkg %s in workspace %s, trying to build",
- pkgid.to_str(), workspace.to_str());
- let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
- self.build(&mut pkg_src, &Everything);
- true
- };
- }
+ self.build_args(args, &Everything);
}
"clean" => {
if args.len() < 1 {
self.prefer(args[0], None);
}
"test" => {
- self.test();
+ // Build the test executable
+ let maybe_id_and_workspace = self.build_args(args, &Tests);
+ match maybe_id_and_workspace {
+ Some((pkg_id, workspace)) => {
+ // Assuming it's built, run the tests
+ self.test(&pkg_id, &workspace);
+ }
+ None => {
+ error("Testing failed because building the specified package failed.");
+ }
+ }
}
"init" => {
if args.len() != 0 {
match what_to_build {
// Find crates inside the workspace
&Everything => pkg_src.find_crates(),
+ // Find only tests
+ &Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path(s)) }),
// Don't infer any crates -- just build the one that was requested
&JustOne(ref p) => {
// We expect that p is relative to the package source's start directory,
fail!("prefer not yet implemented");
}
- fn test(&self) {
- // stub
- fail!("test not yet implemented");
+ fn test(&self, pkgid: &PkgId, workspace: &Path) {
+ match built_test_in_workspace(pkgid, workspace) {
+ Some(test_exec) => {
+ debug!("test: test_exec = %s", test_exec.to_str());
+ let p_output = run::process_output(test_exec.to_str(), [~"--test"]);
+ if p_output.status == 0 {
+ println(str::from_utf8(p_output.output));
+ }
+ else {
+ println(str::from_utf8(p_output.error));
+ }
+ os::set_exit_status(p_output.status);
+ }
+ None => {
+ error(fmt!("Internal error: test executable for package ID %s in workspace %s \
+ wasn't built! Please report this as a bug.",
+ pkgid.to_str(), workspace.to_str()));
+ }
+ }
}
fn init(&self) {
}
fn executable_exists(repo: &Path, short_name: &str) -> bool {
- debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
+ debug!("executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
let exec = target_executable_in_workspace(&PkgId::new(short_name), repo);
os::path_exists(&exec) && is_rwx(&exec)
}
+fn test_executable_exists(repo: &Path, short_name: &str) -> bool {
+ debug!("test_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
+ let exec = built_test_in_workspace(&PkgId::new(short_name), repo);
+ do exec.map_default(false) |exec| {
+ os::path_exists(exec) && is_rwx(exec)
+ }
+}
+
fn remove_executable_file(p: &PkgId, workspace: &Path) {
let exec = target_executable_in_workspace(&PkgId::new(p.short_name), workspace);
if os::path_exists(&exec) {
}
#[test]
-#[ignore(reason = "test not yet implemented")]
-fn test_rustpkg_test() {
- let expected_results = ~"1 out of 1 tests passed"; // fill in
- let workspace = create_local_package_with_test(&PkgId::new("foo"));
- let output = command_line_test([~"test", ~"foo"], &workspace);
- assert_eq!(str::from_utf8(output.output), expected_results);
-}
-
-#[test]
-#[ignore(reason = "test not yet implemented")]
fn test_uninstall() {
let workspace = create_local_package(&PkgId::new("foo"));
- let _output = command_line_test([~"info", ~"foo"], &workspace);
command_line_test([~"uninstall", ~"foo"], &workspace);
let output = command_line_test([~"list"], &workspace);
assert!(!str::from_utf8(output.output).contains("foo"));
assert!(!lib_exists(&foo_workspace, &foo_id.path.clone(), foo_id.version.clone()));
}
+#[test]
+fn test_rustpkg_test_creates_exec() {
+ let foo_id = PkgId::new("foo");
+ let foo_workspace = create_local_package(&foo_id);
+ writeFile(&foo_workspace.push_many(["src", "foo-0.1", "test.rs"]),
+ "#[test] fn f() { assert!('a' == 'a'); }");
+ command_line_test([~"test", ~"foo"], &foo_workspace);
+ assert!(test_executable_exists(&foo_workspace, "foo"));
+}
+
+#[test]
+fn test_rustpkg_test_output() {
+ let workspace = create_local_package_with_test(&PkgId::new("foo"));
+ let output = command_line_test([~"test", ~"foo"], &workspace);
+ let output_str = str::from_utf8(output.output);
+ assert!(output_str.contains("test f ... ok"));
+ assert!(output_str.contains(
+ "test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured"));
+}
+
+#[test]
+#[ignore(reason = "See issue #9441")]
+fn test_rebuild_when_needed() {
+ let foo_id = PkgId::new("foo");
+ let foo_workspace = create_local_package(&foo_id);
+ let test_crate = foo_workspace.push_many(["src", "foo-0.1", "test.rs"]);
+ writeFile(&test_crate, "#[test] fn f() { assert!('a' == 'a'); }");
+ command_line_test([~"test", ~"foo"], &foo_workspace);
+ assert!(test_executable_exists(&foo_workspace, "foo"));
+ let test_executable = built_test_in_workspace(&foo_id,
+ &foo_workspace).expect("test_rebuild_when_needed failed");
+ frob_source_file(&foo_workspace, &foo_id, "test.rs");
+ chmod_read_only(&test_executable);
+ match command_line_test_partial([~"test", ~"foo"], &foo_workspace) {
+ Success(*) => fail!("test_rebuild_when_needed didn't rebuild"),
+ Fail(status) if status == 65 => (), // ok
+ Fail(_) => fail!("test_rebuild_when_needed failed for some other reason")
+ }
+}
+
+#[test]
+fn test_no_rebuilding() {
+ let foo_id = PkgId::new("foo");
+ let foo_workspace = create_local_package(&foo_id);
+ let test_crate = foo_workspace.push_many(["src", "foo-0.1", "test.rs"]);
+ writeFile(&test_crate, "#[test] fn f() { assert!('a' == 'a'); }");
+ command_line_test([~"test", ~"foo"], &foo_workspace);
+ assert!(test_executable_exists(&foo_workspace, "foo"));
+ let test_executable = built_test_in_workspace(&foo_id,
+ &foo_workspace).expect("test_no_rebuilding failed");
+ chmod_read_only(&test_executable);
+ match command_line_test_partial([~"test", ~"foo"], &foo_workspace) {
+ Success(*) => (), // ok
+ Fail(status) if status == 65 => fail!("test_no_rebuilding failed: it rebuilt the tests"),
+ Fail(_) => fail!("test_no_rebuilding failed for some other reason")
+ }
+}
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};