Skip to content

rustpkg: Implement rustpkg test #9549

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
Sep 27, 2013
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
6 changes: 5 additions & 1 deletion src/librustpkg/package_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,17 @@ impl PkgSrc {
/// Infers crates to build. Called only in the case where there
/// is no custom build logic
pub fn find_crates(&mut self) {
self.find_crates_with_filter(|_| true);
}

pub fn find_crates_with_filter(&mut self, filter: &fn(&str) -> bool) {
use conditions::missing_pkg_files::cond;

let prefix = self.start_dir.components.len();
debug!("Matching against %s", self.id.short_name);
do os::walk_dir(&self.start_dir) |pth| {
let maybe_known_crate_set = match pth.filename() {
Some(filename) => match filename {
Some(filename) if filter(filename) => match filename {
"lib.rs" => Some(&mut self.libs),
"main.rs" => Some(&mut self.mains),
"test.rs" => Some(&mut self.tests),
Expand Down
108 changes: 74 additions & 34 deletions src/librustpkg/rustpkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use extra::{getopts};
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};
Expand All @@ -44,7 +44,7 @@ use context::{Context, BuildContext,
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;
Expand Down Expand Up @@ -177,6 +177,8 @@ impl<'self> PkgScript<'self> {
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);
Expand All @@ -190,43 +192,53 @@ pub trait CtxMethods {
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 {
Expand Down Expand Up @@ -310,7 +322,17 @@ impl CtxMethods for BuildContext {
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 {
Expand Down Expand Up @@ -425,6 +447,8 @@ impl CtxMethods for BuildContext {
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,
Expand Down Expand Up @@ -592,9 +616,25 @@ impl CtxMethods for BuildContext {
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) {
Expand Down
2 changes: 2 additions & 0 deletions src/librustpkg/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub enum Target {
pub enum WhatToBuild {
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
JustOne(Path),
/// Build any test.rs files that can be recursively found in the active workspace
Tests,
/// Build everything
Everything
}
Expand Down
79 changes: 67 additions & 12 deletions src/librustpkg/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,11 +350,19 @@ fn assert_executable_exists(repo: &Path, short_name: &str) {
}

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) {
Expand Down Expand Up @@ -1045,19 +1053,8 @@ fn test_info() {
}

#[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"));
Expand Down Expand Up @@ -1800,6 +1797,64 @@ fn correct_package_name_with_rust_path_hack() {
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};
Expand Down