Skip to content

Commit 96bdcd0

Browse files
committed
rustpkg: Implement rustpkg test
Towards #7401
1 parent f210a16 commit 96bdcd0

File tree

4 files changed

+148
-47
lines changed

4 files changed

+148
-47
lines changed

src/librustpkg/package_source.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,17 @@ impl PkgSrc {
246246
/// Infers crates to build. Called only in the case where there
247247
/// is no custom build logic
248248
pub fn find_crates(&mut self) {
249+
self.find_crates_with_filter(|_| true);
250+
}
251+
252+
pub fn find_crates_with_filter(&mut self, filter: &fn(&str) -> bool) {
249253
use conditions::missing_pkg_files::cond;
250254

251255
let prefix = self.start_dir.components.len();
252256
debug!("Matching against %s", self.id.short_name);
253257
do os::walk_dir(&self.start_dir) |pth| {
254258
let maybe_known_crate_set = match pth.filename() {
255-
Some(filename) => match filename {
259+
Some(filename) if filter(filename) => match filename {
256260
"lib.rs" => Some(&mut self.libs),
257261
"main.rs" => Some(&mut self.mains),
258262
"test.rs" => Some(&mut self.tests),

src/librustpkg/rustpkg.rs

Lines changed: 74 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use extra::{getopts};
3333
use syntax::{ast, diagnostic};
3434
use util::*;
3535
use messages::{error, warn, note};
36-
use path_util::build_pkg_id_in_workspace;
36+
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
3737
use path_util::{U_RWX, in_rust_path};
3838
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
3939
use path_util::{target_executable_in_workspace, target_library_in_workspace};
@@ -44,7 +44,7 @@ use context::{Context, BuildContext,
4444
LLVMAssemble, LLVMCompileBitcode};
4545
use package_id::PkgId;
4646
use package_source::PkgSrc;
47-
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
47+
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench, Tests};
4848
// use workcache_support::{discover_outputs, digest_only_date};
4949
use workcache_support::digest_only_date;
5050
use exit_codes::COPY_FAILED_CODE;
@@ -177,6 +177,8 @@ impl<'self> PkgScript<'self> {
177177
pub trait CtxMethods {
178178
fn run(&self, cmd: &str, args: ~[~str]);
179179
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
180+
/// Returns a pair of the selected package ID, and the destination workspace
181+
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(PkgId, Path)>;
180182
/// Returns the destination workspace
181183
fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
182184
fn clean(&self, workspace: &Path, id: &PkgId);
@@ -190,43 +192,53 @@ pub trait CtxMethods {
190192
target_workspace: &Path,
191193
id: &PkgId) -> ~[~str];
192194
fn prefer(&self, _id: &str, _vers: Option<~str>);
193-
fn test(&self);
195+
fn test(&self, id: &PkgId, workspace: &Path);
194196
fn uninstall(&self, _id: &str, _vers: Option<~str>);
195197
fn unprefer(&self, _id: &str, _vers: Option<~str>);
196198
fn init(&self);
197199
}
198200

199201
impl CtxMethods for BuildContext {
202+
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(PkgId, Path)> {
203+
if args.len() < 1 {
204+
match cwd_to_workspace() {
205+
None if self.context.use_rust_path_hack => {
206+
let cwd = os::getcwd();
207+
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
208+
let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
209+
let dest_ws = self.build(&mut pkg_src, what);
210+
Some((pkg_src.id, dest_ws))
211+
}
212+
None => { usage::build(); None }
213+
Some((ws, pkgid)) => {
214+
let mut pkg_src = PkgSrc::new(ws, false, pkgid);
215+
let dest_ws = self.build(&mut pkg_src, what);
216+
Some((pkg_src.id, dest_ws))
217+
}
218+
}
219+
} else {
220+
// The package id is presumed to be the first command-line
221+
// argument
222+
let pkgid = PkgId::new(args[0].clone());
223+
let mut dest_ws = None;
224+
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
225+
debug!("found pkg %s in workspace %s, trying to build",
226+
pkgid.to_str(), workspace.to_str());
227+
let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
228+
dest_ws = Some(self.build(&mut pkg_src, what));
229+
true
230+
};
231+
assert!(dest_ws.is_some());
232+
// n.b. If this builds multiple packages, it only returns the workspace for
233+
// the last one. The whole building-multiple-packages-with-the-same-ID is weird
234+
// anyway and there are no tests for it, so maybe take it out
235+
Some((pkgid, dest_ws.unwrap()))
236+
}
237+
}
200238
fn run(&self, cmd: &str, args: ~[~str]) {
201239
match cmd {
202240
"build" => {
203-
if args.len() < 1 {
204-
match cwd_to_workspace() {
205-
None if self.context.use_rust_path_hack => {
206-
let cwd = os::getcwd();
207-
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
208-
let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
209-
self.build(&mut pkg_src, &Everything);
210-
}
211-
None => { usage::build(); return; }
212-
Some((ws, pkgid)) => {
213-
let mut pkg_src = PkgSrc::new(ws, false, pkgid);
214-
self.build(&mut pkg_src, &Everything);
215-
}
216-
}
217-
}
218-
else {
219-
// The package id is presumed to be the first command-line
220-
// argument
221-
let pkgid = PkgId::new(args[0].clone());
222-
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
223-
debug!("found pkg %s in workspace %s, trying to build",
224-
pkgid.to_str(), workspace.to_str());
225-
let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
226-
self.build(&mut pkg_src, &Everything);
227-
true
228-
};
229-
}
241+
self.build_args(args, &Everything);
230242
}
231243
"clean" => {
232244
if args.len() < 1 {
@@ -310,7 +322,17 @@ impl CtxMethods for BuildContext {
310322
self.prefer(args[0], None);
311323
}
312324
"test" => {
313-
self.test();
325+
// Build the test executable
326+
let maybe_id_and_workspace = self.build_args(args, &Tests);
327+
match maybe_id_and_workspace {
328+
Some((pkg_id, workspace)) => {
329+
// Assuming it's built, run the tests
330+
self.test(&pkg_id, &workspace);
331+
}
332+
None => {
333+
error("Testing failed because building the specified package failed.");
334+
}
335+
}
314336
}
315337
"init" => {
316338
if args.len() != 0 {
@@ -425,6 +447,8 @@ impl CtxMethods for BuildContext {
425447
match what_to_build {
426448
// Find crates inside the workspace
427449
&Everything => pkg_src.find_crates(),
450+
// Find only tests
451+
&Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path(s)) }),
428452
// Don't infer any crates -- just build the one that was requested
429453
&JustOne(ref p) => {
430454
// We expect that p is relative to the package source's start directory,
@@ -592,9 +616,25 @@ impl CtxMethods for BuildContext {
592616
fail!("prefer not yet implemented");
593617
}
594618

595-
fn test(&self) {
596-
// stub
597-
fail!("test not yet implemented");
619+
fn test(&self, pkgid: &PkgId, workspace: &Path) {
620+
match built_test_in_workspace(pkgid, workspace) {
621+
Some(test_exec) => {
622+
debug!("test: test_exec = %s", test_exec.to_str());
623+
let p_output = run::process_output(test_exec.to_str(), [~"--test"]);
624+
if p_output.status == 0 {
625+
println(str::from_utf8(p_output.output));
626+
}
627+
else {
628+
println(str::from_utf8(p_output.error));
629+
}
630+
os::set_exit_status(p_output.status);
631+
}
632+
None => {
633+
error(fmt!("Internal error: test executable for package ID %s in workspace %s \
634+
wasn't built! Please report this as a bug.",
635+
pkgid.to_str(), workspace.to_str()));
636+
}
637+
}
598638
}
599639

600640
fn init(&self) {

src/librustpkg/target.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub enum Target {
2626
pub enum WhatToBuild {
2727
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
2828
JustOne(Path),
29+
/// Build any test.rs files that can be recursively found in the active workspace
30+
Tests,
2931
/// Build everything
3032
Everything
3133
}

src/librustpkg/tests.rs

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,19 @@ fn assert_executable_exists(repo: &Path, short_name: &str) {
350350
}
351351

352352
fn executable_exists(repo: &Path, short_name: &str) -> bool {
353-
debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
353+
debug!("executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
354354
let exec = target_executable_in_workspace(&PkgId::new(short_name), repo);
355355
os::path_exists(&exec) && is_rwx(&exec)
356356
}
357357

358+
fn test_executable_exists(repo: &Path, short_name: &str) -> bool {
359+
debug!("test_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
360+
let exec = built_test_in_workspace(&PkgId::new(short_name), repo);
361+
do exec.map_default(false) |exec| {
362+
os::path_exists(exec) && is_rwx(exec)
363+
}
364+
}
365+
358366
fn remove_executable_file(p: &PkgId, workspace: &Path) {
359367
let exec = target_executable_in_workspace(&PkgId::new(p.short_name), workspace);
360368
if os::path_exists(&exec) {
@@ -1045,19 +1053,8 @@ fn test_info() {
10451053
}
10461054
10471055
#[test]
1048-
#[ignore(reason = "test not yet implemented")]
1049-
fn test_rustpkg_test() {
1050-
let expected_results = ~"1 out of 1 tests passed"; // fill in
1051-
let workspace = create_local_package_with_test(&PkgId::new("foo"));
1052-
let output = command_line_test([~"test", ~"foo"], &workspace);
1053-
assert_eq!(str::from_utf8(output.output), expected_results);
1054-
}
1055-
1056-
#[test]
1057-
#[ignore(reason = "test not yet implemented")]
10581056
fn test_uninstall() {
10591057
let workspace = create_local_package(&PkgId::new("foo"));
1060-
let _output = command_line_test([~"info", ~"foo"], &workspace);
10611058
command_line_test([~"uninstall", ~"foo"], &workspace);
10621059
let output = command_line_test([~"list"], &workspace);
10631060
assert!(!str::from_utf8(output.output).contains("foo"));
@@ -1800,6 +1797,64 @@ fn correct_package_name_with_rust_path_hack() {
18001797
assert!(!lib_exists(&foo_workspace, &foo_id.path.clone(), foo_id.version.clone()));
18011798
}
18021799
1800+
#[test]
1801+
fn test_rustpkg_test_creates_exec() {
1802+
let foo_id = PkgId::new("foo");
1803+
let foo_workspace = create_local_package(&foo_id);
1804+
writeFile(&foo_workspace.push_many(["src", "foo-0.1", "test.rs"]),
1805+
"#[test] fn f() { assert!('a' == 'a'); }");
1806+
command_line_test([~"test", ~"foo"], &foo_workspace);
1807+
assert!(test_executable_exists(&foo_workspace, "foo"));
1808+
}
1809+
1810+
#[test]
1811+
fn test_rustpkg_test_output() {
1812+
let workspace = create_local_package_with_test(&PkgId::new("foo"));
1813+
let output = command_line_test([~"test", ~"foo"], &workspace);
1814+
let output_str = str::from_utf8(output.output);
1815+
assert!(output_str.contains("test f ... ok"));
1816+
assert!(output_str.contains(
1817+
"test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured"));
1818+
}
1819+
1820+
#[test]
1821+
#[ignore(reason = "See issue #9441")]
1822+
fn test_rebuild_when_needed() {
1823+
let foo_id = PkgId::new("foo");
1824+
let foo_workspace = create_local_package(&foo_id);
1825+
let test_crate = foo_workspace.push_many(["src", "foo-0.1", "test.rs"]);
1826+
writeFile(&test_crate, "#[test] fn f() { assert!('a' == 'a'); }");
1827+
command_line_test([~"test", ~"foo"], &foo_workspace);
1828+
assert!(test_executable_exists(&foo_workspace, "foo"));
1829+
let test_executable = built_test_in_workspace(&foo_id,
1830+
&foo_workspace).expect("test_rebuild_when_needed failed");
1831+
frob_source_file(&foo_workspace, &foo_id, "test.rs");
1832+
chmod_read_only(&test_executable);
1833+
match command_line_test_partial([~"test", ~"foo"], &foo_workspace) {
1834+
Success(*) => fail!("test_rebuild_when_needed didn't rebuild"),
1835+
Fail(status) if status == 65 => (), // ok
1836+
Fail(_) => fail!("test_rebuild_when_needed failed for some other reason")
1837+
}
1838+
}
1839+
1840+
#[test]
1841+
fn test_no_rebuilding() {
1842+
let foo_id = PkgId::new("foo");
1843+
let foo_workspace = create_local_package(&foo_id);
1844+
let test_crate = foo_workspace.push_many(["src", "foo-0.1", "test.rs"]);
1845+
writeFile(&test_crate, "#[test] fn f() { assert!('a' == 'a'); }");
1846+
command_line_test([~"test", ~"foo"], &foo_workspace);
1847+
assert!(test_executable_exists(&foo_workspace, "foo"));
1848+
let test_executable = built_test_in_workspace(&foo_id,
1849+
&foo_workspace).expect("test_no_rebuilding failed");
1850+
chmod_read_only(&test_executable);
1851+
match command_line_test_partial([~"test", ~"foo"], &foo_workspace) {
1852+
Success(*) => (), // ok
1853+
Fail(status) if status == 65 => fail!("test_no_rebuilding failed: it rebuilt the tests"),
1854+
Fail(_) => fail!("test_no_rebuilding failed for some other reason")
1855+
}
1856+
}
1857+
18031858
/// Returns true if p exists and is executable
18041859
fn is_executable(p: &Path) -> bool {
18051860
use std::libc::consts::os::posix88::{S_IXUSR};

0 commit comments

Comments
 (0)