]> git.lizzy.rs Git - rust.git/blob - src/librustpkg/tests.rs
auto merge of #8792 : adridu59/rust/master, r=catamorphism
[rust.git] / src / librustpkg / tests.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // rustpkg unit tests
12
13 use context::Ctx;
14 use std::hashmap::HashMap;
15 use std::{io, libc, os, run, str};
16 use extra::tempfile::mkdtemp;
17 use std::run::ProcessOutput;
18 use installed_packages::list_installed_packages;
19 use package_id::{PkgId};
20 use version::{ExactRevision, NoVersion, Version, Tagged};
21 use path_util::{target_executable_in_workspace, target_test_in_workspace,
22                target_bench_in_workspace, make_dir_rwx, U_RWX,
23                library_in_workspace, installed_library_in_workspace,
24                built_bench_in_workspace, built_test_in_workspace,
25                built_library_in_workspace, built_executable_in_workspace};
26 use rustc::metadata::filesearch::rust_path;
27 use rustc::driver::driver::host_triple;
28 use target::*;
29
30 /// Returns the last-modified date as an Option
31 fn datestamp(p: &Path) -> Option<libc::time_t> {
32     p.stat().map(|stat| stat.st_mtime)
33 }
34
35 fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
36     Ctx {
37         sysroot_opt: sysroot_opt,
38         json: false,
39         dep_cache: @mut HashMap::new()
40     }
41 }
42
43 fn fake_pkg() -> PkgId {
44     let sn = ~"bogus";
45     PkgId {
46         path: Path(sn),
47         short_name: sn,
48         version: NoVersion
49     }
50 }
51
52 fn git_repo_pkg() -> PkgId {
53     PkgId {
54         path: Path("mockgithub.com/catamorphism/test-pkg"),
55         short_name: ~"test-pkg",
56         version: NoVersion
57     }
58 }
59
60 fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId {
61     PkgId {
62         path: Path("mockgithub.com/catamorphism/test-pkg"),
63         short_name: ~"test-pkg",
64         version: Tagged(a_tag)
65     }
66 }
67
68 fn writeFile(file_path: &Path, contents: &str) {
69     let out = io::file_writer(file_path, [io::Create, io::Truncate]).unwrap();
70     out.write_line(contents);
71 }
72
73 fn mk_empty_workspace(short_name: &Path, version: &Version) -> Path {
74     let workspace_dir = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
75     mk_workspace(&workspace_dir, short_name, version);
76     workspace_dir
77 }
78
79 fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path {
80     // include version number in directory name
81     let package_dir = workspace.push("src").push(fmt!("%s-%s",
82                                                       short_name.to_str(), version.to_str()));
83     assert!(os::mkdir_recursive(&package_dir, U_RWX));
84     package_dir
85 }
86
87 fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
88     let package_dir = mk_empty_workspace(short_name,
89                                          version).push("src").push(fmt!("%s-%s",
90                                                             short_name.to_str(),
91                                                             version.to_str()));
92
93     debug!("Created %s and does it exist? %?", package_dir.to_str(),
94           os::path_is_dir(&package_dir));
95     // Create main, lib, test, and bench files
96     debug!("mk_workspace: creating %s", package_dir.to_str());
97     assert!(os::mkdir_recursive(&package_dir, U_RWX));
98     debug!("Created %s and does it exist? %?", package_dir.to_str(),
99           os::path_is_dir(&package_dir));
100     // Create main, lib, test, and bench files
101
102     writeFile(&package_dir.push("main.rs"),
103               "fn main() { let _x = (); }");
104     writeFile(&package_dir.push("lib.rs"),
105               "pub fn f() { let _x = (); }");
106     writeFile(&package_dir.push("test.rs"),
107               "#[test] pub fn f() { (); }");
108     writeFile(&package_dir.push("bench.rs"),
109               "#[bench] pub fn f() { (); }");
110     package_dir
111 }
112
113 fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
114     let cwd = (*cwd).clone();
115     let mut prog = run::Process::new("git", args, run::ProcessOptions {
116         env: env,
117         dir: Some(&cwd),
118         in_fd: None,
119         out_fd: None,
120         err_fd: None
121     });
122     let rslt = prog.finish_with_output();
123     if rslt.status != 0 {
124         fail!("%s [git returned %?, output = %s, error = %s]", err_msg,
125            rslt.status, str::from_bytes(rslt.output), str::from_bytes(rslt.error));
126     }
127 }
128
129 /// Should create an empty git repo in p, relative to the tmp dir, and return the new
130 /// absolute path
131 fn init_git_repo(p: &Path) -> Path {
132     assert!(!p.is_absolute());
133     let tmp = mkdtemp(&os::tmpdir(), "git_local").expect("couldn't create temp dir");
134     let work_dir = tmp.push_rel(p);
135     let work_dir_for_opts = work_dir.clone();
136     assert!(os::mkdir_recursive(&work_dir, U_RWX));
137     debug!("Running: git init in %s", work_dir.to_str());
138     let ws = work_dir.to_str();
139     run_git([~"init"], None, &work_dir_for_opts,
140         fmt!("Couldn't initialize git repository in %s", ws));
141     // Add stuff to the dir so that git tag succeeds
142     writeFile(&work_dir.push("README"), "");
143     run_git([~"add", ~"README"], None, &work_dir_for_opts, fmt!("Couldn't add in %s", ws));
144     git_commit(&work_dir_for_opts, ~"whatever");
145     tmp
146 }
147
148 fn add_all_and_commit(repo: &Path) {
149     git_add_all(repo);
150     git_commit(repo, ~"floop");
151 }
152
153 fn git_commit(repo: &Path, msg: ~str) {
154     run_git([~"commit", ~"--author=tester <test@mozilla.com>", ~"-m", msg],
155             None, repo, fmt!("Couldn't commit in %s", repo.to_str()));
156 }
157
158 fn git_add_all(repo: &Path) {
159     run_git([~"add", ~"-A"], None, repo, fmt!("Couldn't add all files in %s", repo.to_str()));
160 }
161
162 fn add_git_tag(repo: &Path, tag: ~str) {
163     assert!(repo.is_absolute());
164     git_add_all(repo);
165     git_commit(repo, ~"whatever");
166     run_git([~"tag", tag.clone()], None, repo,
167             fmt!("Couldn't add git tag %s in %s", tag, repo.to_str()));
168 }
169
170 fn is_rwx(p: &Path) -> bool {
171     use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
172
173     match p.get_mode() {
174         None => return false,
175         Some(m) =>
176             ((m & S_IRUSR as uint) == S_IRUSR as uint
177             && (m & S_IWUSR as uint) == S_IWUSR as uint
178             && (m & S_IXUSR as uint) == S_IXUSR as uint)
179     }
180 }
181
182 fn test_sysroot() -> Path {
183     // Totally gross hack but it's just for test cases.
184     // Infer the sysroot from the exe name and pray that it's right.
185     // (Did I mention it was a gross hack?)
186     let self_path = os::self_exe_path().expect("Couldn't get self_exe path");
187     self_path.pop()
188 }
189
190 // Returns the path to rustpkg
191 fn rustpkg_exec() -> Path {
192     // Ugh
193     let first_try = test_sysroot().push("lib").push("rustc")
194         .push(host_triple()).push("bin").push("rustpkg");
195     if is_executable(&first_try) {
196         first_try
197     }
198     else {
199         let second_try = test_sysroot().push("bin").push("rustpkg");
200         if is_executable(&second_try) {
201             second_try
202         }
203         else {
204             fail!("in rustpkg test, can't find an installed rustpkg");
205         }
206     }
207 }
208
209 fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
210     command_line_test_with_env(args, cwd, None)
211 }
212
213 /// Runs `rustpkg` (based on the directory that this executable was
214 /// invoked from) with the given arguments, in the given working directory.
215 /// Returns the process's output.
216 fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
217     -> ProcessOutput {
218     let cmd = rustpkg_exec().to_str();
219     debug!("cd %s; %s %s",
220            cwd.to_str(), cmd, args.connect(" "));
221     assert!(os::path_is_dir(&*cwd));
222     let cwd = (*cwd).clone();
223     let mut prog = run::Process::new(cmd, args, run::ProcessOptions {
224         env: env.map(|e| e + os::env()),
225         dir: Some(&cwd),
226         in_fd: None,
227         out_fd: None,
228         err_fd: None
229     });
230     let output = prog.finish_with_output();
231     debug!("Output from command %s with args %? was %s {%s}[%?]",
232                     cmd, args, str::from_bytes(output.output),
233                    str::from_bytes(output.error),
234                    output.status);
235 /*
236 By the way, rustpkg *won't* return a nonzero exit code if it fails --
237 see #4547
238 So tests that use this need to check the existence of a file
239 to make sure the command succeeded
240 */
241     if output.status != 0 {
242         fail!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
243               cmd, args, output.status,
244               str::from_bytes(output.output) + str::from_bytes(output.error));
245     }
246     output
247 }
248
249 fn create_local_package(pkgid: &PkgId) -> Path {
250     let parent_dir = mk_temp_workspace(&pkgid.path, &pkgid.version);
251     debug!("Created empty package dir for %s, returning %s", pkgid.to_str(), parent_dir.to_str());
252     parent_dir.pop().pop()
253 }
254
255 fn create_local_package_in(pkgid: &PkgId, pkgdir: &Path) -> Path {
256
257     let package_dir = pkgdir.push("src").push(pkgid.to_str());
258
259     // Create main, lib, test, and bench files
260     assert!(os::mkdir_recursive(&package_dir, U_RWX));
261     debug!("Created %s and does it exist? %?", package_dir.to_str(),
262           os::path_is_dir(&package_dir));
263     // Create main, lib, test, and bench files
264
265     writeFile(&package_dir.push("main.rs"),
266               "fn main() { let _x = (); }");
267     writeFile(&package_dir.push("lib.rs"),
268               "pub fn f() { let _x = (); }");
269     writeFile(&package_dir.push("test.rs"),
270               "#[test] pub fn f() { (); }");
271     writeFile(&package_dir.push("bench.rs"),
272               "#[bench] pub fn f() { (); }");
273     package_dir
274 }
275
276 fn create_local_package_with_test(pkgid: &PkgId) -> Path {
277     debug!("Dry run -- would create package %s with test");
278     create_local_package(pkgid) // Already has tests???
279 }
280
281 fn create_local_package_with_dep(pkgid: &PkgId, subord_pkgid: &PkgId) -> Path {
282     let package_dir = create_local_package(pkgid);
283     create_local_package_in(subord_pkgid, &package_dir);
284     // Write a main.rs file into pkgid that references subord_pkgid
285     writeFile(&package_dir.push("src").push(pkgid.to_str()).push("main.rs"),
286               fmt!("extern mod %s;\nfn main() {}",
287                    subord_pkgid.short_name));
288     // Write a lib.rs file into subord_pkgid that has something in it
289     writeFile(&package_dir.push("src").push(subord_pkgid.to_str()).push("lib.rs"),
290               "pub fn f() {}");
291     debug!("Dry run -- would create packages %s and %s in %s",
292            pkgid.to_str(),
293            subord_pkgid.to_str(),
294            package_dir.to_str());
295     package_dir
296 }
297
298 fn create_local_package_with_custom_build_hook(pkgid: &PkgId,
299                                                custom_build_hook: &str) -> Path {
300     debug!("Dry run -- would create package %s with custom build hook %s",
301            pkgid.to_str(), custom_build_hook);
302     create_local_package(pkgid)
303     // actually write the pkg.rs with the custom build hook
304
305 }
306
307 fn assert_lib_exists(repo: &Path, short_name: &str, _v: Version) { // ??? version?
308     debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
309     let lib = installed_library_in_workspace(short_name, repo);
310     debug!("assert_lib_exists: checking whether %? exists", lib);
311     assert!(lib.is_some());
312     let libname = lib.get_ref();
313     assert!(os::path_exists(libname));
314     assert!(is_rwx(libname));
315 }
316
317 fn assert_executable_exists(repo: &Path, short_name: &str) {
318     debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
319     let exec = target_executable_in_workspace(&PkgId::new(short_name), repo);
320     assert!(os::path_exists(&exec));
321     assert!(is_rwx(&exec));
322 }
323
324 fn assert_built_executable_exists(repo: &Path, short_name: &str) {
325     debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
326     let exec = built_executable_in_workspace(&PkgId::new(short_name),
327                                              repo).expect("assert_built_executable_exists failed");
328     assert!(os::path_exists(&exec));
329     assert!(is_rwx(&exec));
330 }
331
332 fn command_line_test_output(args: &[~str]) -> ~[~str] {
333     let mut result = ~[];
334     let p_output = command_line_test(args, &os::getcwd());
335     let test_output = str::from_bytes(p_output.output);
336     for s in test_output.split_iter('\n') {
337         result.push(s.to_owned());
338     }
339     result
340 }
341
342 fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
343     let mut result = ~[];
344     let p_output = command_line_test_with_env(args, &os::getcwd(), Some(env));
345     let test_output = str::from_bytes(p_output.output);
346     for s in test_output.split_iter('\n') {
347         result.push(s.to_owned());
348     }
349     result
350 }
351
352 // assumes short_name and path are one and the same -- I should fix
353 fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path {
354     debug!("lib_output_file_name: given %s and parent %s and short name %s",
355            workspace.to_str(), parent, short_name);
356     library_in_workspace(&Path(short_name),
357                          short_name,
358                          Build,
359                          workspace,
360                          "build",
361                          &NoVersion).expect("lib_output_file_name")
362 }
363
364 fn output_file_name(workspace: &Path, short_name: &str) -> Path {
365     workspace.push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
366 }
367
368 fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
369     use conditions::bad_path::cond;
370     let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
371     let contents = os::list_dir_path(&pkg_src_dir);
372     for p in contents.iter() {
373         if p.filetype() == Some(~".rs") {
374             // should be able to do this w/o a process
375             if run::process_output("touch", [p.to_str()]).status != 0 {
376                 let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path"));
377             }
378             break;
379         }
380     }
381 }
382
383 /// Add a blank line at the end
384 fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
385     use conditions::bad_path::cond;
386     let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
387     let contents = os::list_dir_path(&pkg_src_dir);
388     let mut maybe_p = None;
389     for p in contents.iter() {
390         if p.filetype() == Some(~".rs") {
391             maybe_p = Some(p);
392             break;
393         }
394     }
395     match maybe_p {
396         Some(p) => {
397             let w = io::file_writer(p, &[io::Append]);
398             match w {
399                 Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
400                 Ok(w)  => w.write_line("")
401             }
402         }
403         None => fail!(fmt!("frob_source_file failed to find a source file in %s",
404                            pkg_src_dir.to_str()))
405     }
406 }
407
408 #[test]
409 fn test_make_dir_rwx() {
410     let temp = &os::tmpdir();
411     let dir = temp.push("quux");
412     assert!(!os::path_exists(&dir) ||
413             os::remove_dir_recursive(&dir));
414     debug!("Trying to make %s", dir.to_str());
415     assert!(make_dir_rwx(&dir));
416     assert!(os::path_is_dir(&dir));
417     assert!(is_rwx(&dir));
418     assert!(os::remove_dir_recursive(&dir));
419 }
420
421 #[test]
422 fn test_install_valid() {
423     use path_util::installed_library_in_workspace;
424
425     let sysroot = test_sysroot();
426     debug!("sysroot = %s", sysroot.to_str());
427     let ctxt = fake_ctxt(Some(@sysroot));
428     let temp_pkg_id = fake_pkg();
429     let temp_workspace = mk_temp_workspace(&temp_pkg_id.path, &NoVersion).pop().pop();
430     debug!("temp_workspace = %s", temp_workspace.to_str());
431     // should have test, bench, lib, and main
432     ctxt.install(&temp_workspace, &temp_pkg_id);
433     // Check that all files exist
434     let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
435     debug!("exec = %s", exec.to_str());
436     assert!(os::path_exists(&exec));
437     assert!(is_rwx(&exec));
438
439     let lib = installed_library_in_workspace(temp_pkg_id.short_name, &temp_workspace);
440     debug!("lib = %?", lib);
441     assert!(lib.map_default(false, |l| os::path_exists(l)));
442     assert!(lib.map_default(false, |l| is_rwx(l)));
443
444     // And that the test and bench executables aren't installed
445     assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
446     let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
447     debug!("bench = %s", bench.to_str());
448     assert!(!os::path_exists(&bench));
449 }
450
451 #[test]
452 fn test_install_invalid() {
453     use conditions::nonexistent_package::cond;
454     use cond1 = conditions::missing_pkg_files::cond;
455
456     let ctxt = fake_ctxt(None);
457     let pkgid = fake_pkg();
458     let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
459     let mut error_occurred = false;
460     let mut error1_occurred = false;
461     do cond1.trap(|_| {
462         error1_occurred = true;
463     }).inside {
464         do cond.trap(|_| {
465             error_occurred = true;
466             temp_workspace.clone()
467         }).inside {
468             ctxt.install(&temp_workspace, &pkgid);
469         }
470     }
471     assert!(error_occurred && error1_occurred);
472 }
473
474 // Tests above should (maybe) be converted to shell out to rustpkg, too
475 #[test]
476 fn test_install_git() {
477     let sysroot = test_sysroot();
478     debug!("sysroot = %s", sysroot.to_str());
479     let temp_pkg_id = git_repo_pkg();
480     let repo = init_git_repo(&temp_pkg_id.path);
481     debug!("repo = %s", repo.to_str());
482     let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg");
483     debug!("repo_subdir = %s", repo_subdir.to_str());
484
485     writeFile(&repo_subdir.push("main.rs"),
486               "fn main() { let _x = (); }");
487     writeFile(&repo_subdir.push("lib.rs"),
488               "pub fn f() { let _x = (); }");
489     writeFile(&repo_subdir.push("test.rs"),
490               "#[test] pub fn f() { (); }");
491     writeFile(&repo_subdir.push("bench.rs"),
492               "#[bench] pub fn f() { (); }");
493     add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
494
495     debug!("test_install_git: calling rustpkg install %s in %s",
496            temp_pkg_id.path.to_str(), repo.to_str());
497     // should have test, bench, lib, and main
498     command_line_test([~"install", temp_pkg_id.path.to_str()], &repo);
499     let ws = repo.push(".rust");
500     // Check that all files exist
501     debug!("Checking for files in %s", ws.to_str());
502     let exec = target_executable_in_workspace(&temp_pkg_id, &ws);
503     debug!("exec = %s", exec.to_str());
504     assert!(os::path_exists(&exec));
505     assert!(is_rwx(&exec));
506     let _built_lib =
507         built_library_in_workspace(&temp_pkg_id,
508                                    &ws).expect("test_install_git: built lib should exist");
509     assert_lib_exists(&ws, temp_pkg_id.short_name, temp_pkg_id.version.clone());
510     let built_test = built_test_in_workspace(&temp_pkg_id,
511                          &ws).expect("test_install_git: built test should exist");
512     assert!(os::path_exists(&built_test));
513     let built_bench = built_bench_in_workspace(&temp_pkg_id,
514                           &ws).expect("test_install_git: built bench should exist");
515     assert!(os::path_exists(&built_bench));
516     // And that the test and bench executables aren't installed
517     let test = target_test_in_workspace(&temp_pkg_id, &ws);
518     assert!(!os::path_exists(&test));
519     debug!("test = %s", test.to_str());
520     let bench = target_bench_in_workspace(&temp_pkg_id, &ws);
521     debug!("bench = %s", bench.to_str());
522     assert!(!os::path_exists(&bench));
523 }
524
525 #[test]
526 fn test_package_ids_must_be_relative_path_like() {
527     use conditions::bad_pkg_id::cond;
528
529     /*
530     Okay:
531     - One identifier, with no slashes
532     - Several slash-delimited things, with no / at the root
533
534     Not okay:
535     - Empty string
536     - Absolute path (as per os::is_absolute)
537
538     */
539
540     let whatever = PkgId::new("foo");
541
542     assert_eq!(~"foo-0.1", whatever.to_str());
543     assert!("github.com/catamorphism/test-pkg-0.1" ==
544             PkgId::new("github.com/catamorphism/test-pkg").to_str());
545
546     do cond.trap(|(p, e)| {
547         assert!("" == p.to_str());
548         assert!("0-length pkgid" == e);
549         whatever.clone()
550     }).inside {
551         let x = PkgId::new("");
552         assert_eq!(~"foo-0.1", x.to_str());
553     }
554
555     do cond.trap(|(p, e)| {
556         assert_eq!(p.to_str(), os::make_absolute(&Path("foo/bar/quux")).to_str());
557         assert!("absolute pkgid" == e);
558         whatever.clone()
559     }).inside {
560         let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str());
561         assert_eq!(~"foo-0.1", z.to_str());
562     }
563
564 }
565
566 #[test]
567 fn test_package_version() {
568     let local_path = "mockgithub.com/catamorphism/test_pkg_version";
569     let repo = init_git_repo(&Path(local_path));
570     let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg_version");
571     debug!("Writing files in: %s", repo_subdir.to_str());
572     writeFile(&repo_subdir.push("main.rs"),
573               "fn main() { let _x = (); }");
574     writeFile(&repo_subdir.push("lib.rs"),
575               "pub fn f() { let _x = (); }");
576     writeFile(&repo_subdir.push("test.rs"),
577               "#[test] pub fn f() { (); }");
578     writeFile(&repo_subdir.push("bench.rs"),
579               "#[bench] pub fn f() { (); }");
580     add_git_tag(&repo_subdir, ~"0.4");
581
582     // It won't pick up the 0.4 version because the dir isn't in the RUST_PATH, but...
583     let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version");
584     // This should look at the prefix, clone into a workspace, then build.
585     command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg_version"],
586                       &repo);
587     let ws = repo.push(".rust");
588     // we can still match on the filename to make sure it contains the 0.4 version
589     assert!(match built_library_in_workspace(&temp_pkg_id,
590                                              &ws) {
591         Some(p) => p.to_str().ends_with(fmt!("0.4%s", os::consts::DLL_SUFFIX)),
592         None    => false
593     });
594     assert!(built_executable_in_workspace(&temp_pkg_id, &ws)
595             == Some(ws.push("build").
596                     push("mockgithub.com").
597                     push("catamorphism").
598                     push("test_pkg_version").
599                     push("test_pkg_version")));
600 }
601
602 #[test]
603 fn test_package_request_version() {
604     let local_path = "mockgithub.com/catamorphism/test_pkg_version";
605     let repo = init_git_repo(&Path(local_path));
606     let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg_version");
607     debug!("Writing files in: %s", repo_subdir.to_str());
608     writeFile(&repo_subdir.push("main.rs"),
609               "fn main() { let _x = (); }");
610     writeFile(&repo_subdir.push("lib.rs"),
611               "pub fn f() { let _x = (); }");
612     writeFile(&repo_subdir.push("test.rs"),
613               "#[test] pub fn f() { (); }");
614     writeFile(&repo_subdir.push("bench.rs"),
615               "#[bench] pub fn f() { (); }");
616     writeFile(&repo_subdir.push("version-0.3-file.txt"), "hi");
617     add_git_tag(&repo_subdir, ~"0.3");
618     writeFile(&repo_subdir.push("version-0.4-file.txt"), "hello");
619     add_git_tag(&repo_subdir, ~"0.4");
620
621     command_line_test([~"install", fmt!("%s#0.3", local_path)], &repo);
622
623     assert!(match installed_library_in_workspace("test_pkg_version", &repo.push(".rust")) {
624         Some(p) => {
625             debug!("installed: %s", p.to_str());
626             p.to_str().ends_with(fmt!("0.3%s", os::consts::DLL_SUFFIX))
627         }
628         None    => false
629     });
630     let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3");
631     assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust"))
632             == repo.push(".rust").push("bin").push("test_pkg_version"));
633
634     assert!(os::path_exists(&repo.push(".rust").push("src")
635                             .push("mockgithub.com").push("catamorphism")
636                             .push("test_pkg_version-0.3")
637                             .push("version-0.3-file.txt")));
638     assert!(!os::path_exists(&repo.push(".rust").push("src")
639                             .push("mockgithub.com").push("catamorphism")
640                              .push("test_pkg_version-0.3")
641                             .push("version-0.4-file.txt")));
642 }
643
644 #[test]
645 #[ignore (reason = "http-client not ported to rustpkg yet")]
646 fn rustpkg_install_url_2() {
647     let temp_dir = mkdtemp(&os::tmpdir(), "rustpkg_install_url_2").expect("rustpkg_install_url_2");
648     command_line_test([~"install", ~"github.com/mozilla-servo/rust-http-client"],
649                      &temp_dir);
650 }
651
652 #[test]
653 fn rustpkg_library_target() {
654     let foo_repo = init_git_repo(&Path("foo"));
655     let package_dir = foo_repo.push("foo");
656
657     debug!("Writing files in: %s", package_dir.to_str());
658     writeFile(&package_dir.push("main.rs"),
659               "fn main() { let _x = (); }");
660     writeFile(&package_dir.push("lib.rs"),
661               "pub fn f() { let _x = (); }");
662     writeFile(&package_dir.push("test.rs"),
663               "#[test] pub fn f() { (); }");
664     writeFile(&package_dir.push("bench.rs"),
665               "#[bench] pub fn f() { (); }");
666
667     add_git_tag(&package_dir, ~"1.0");
668     command_line_test([~"install", ~"foo"], &foo_repo);
669     assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0"));
670 }
671
672 #[test]
673 fn rustpkg_local_pkg() {
674     let dir = create_local_package(&PkgId::new("foo"));
675     command_line_test([~"install", ~"foo"], &dir);
676     assert_executable_exists(&dir, "foo");
677 }
678
679 #[test]
680 #[ignore (reason = "test makes bogus assumptions about build directory layout: issue #8690")]
681 fn package_script_with_default_build() {
682     let dir = create_local_package(&PkgId::new("fancy-lib"));
683     debug!("dir = %s", dir.to_str());
684     let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg").
685         push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
686     debug!("package_script_with_default_build: %s", source.to_str());
687     if !os::copy_file(&source,
688                       &dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
689         fail!("Couldn't copy file");
690     }
691     command_line_test([~"install", ~"fancy-lib"], &dir);
692     assert_lib_exists(&dir, "fancy-lib", NoVersion);
693     assert!(os::path_exists(&dir.push("build").push("fancy-lib").push("generated.rs")));
694 }
695
696 #[test]
697 fn rustpkg_build_no_arg() {
698     let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed");
699     let package_dir = tmp.push("src").push("foo");
700     assert!(os::mkdir_recursive(&package_dir, U_RWX));
701
702     writeFile(&package_dir.push("main.rs"),
703               "fn main() { let _x = (); }");
704     debug!("build_no_arg: dir = %s", package_dir.to_str());
705     command_line_test([~"build"], &package_dir);
706     assert_built_executable_exists(&tmp, "foo");
707 }
708
709 #[test]
710 fn rustpkg_install_no_arg() {
711     let tmp = mkdtemp(&os::tmpdir(),
712                       "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed");
713     let package_dir = tmp.push("src").push("foo");
714     assert!(os::mkdir_recursive(&package_dir, U_RWX));
715     writeFile(&package_dir.push("lib.rs"),
716               "fn main() { let _x = (); }");
717     debug!("install_no_arg: dir = %s", package_dir.to_str());
718     command_line_test([~"install"], &package_dir);
719     assert_lib_exists(&tmp, "foo", NoVersion);
720 }
721
722 #[test]
723 fn rustpkg_clean_no_arg() {
724     let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed");
725     let package_dir = tmp.push("src").push("foo");
726     assert!(os::mkdir_recursive(&package_dir, U_RWX));
727
728     writeFile(&package_dir.push("main.rs"),
729               "fn main() { let _x = (); }");
730     debug!("clean_no_arg: dir = %s", package_dir.to_str());
731     command_line_test([~"build"], &package_dir);
732     assert_built_executable_exists(&tmp, "foo");
733     command_line_test([~"clean"], &package_dir);
734     assert!(!built_executable_in_workspace(&PkgId::new("foo"),
735                 &tmp).map_default(false, |m| { os::path_exists(m) }));
736 }
737
738 #[test]
739 fn rust_path_test() {
740     let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed");
741     let dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion);
742     debug!("dir = %s", dir.to_str());
743     writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }");
744
745     let cwd = os::getcwd();
746     debug!("cwd = %s", cwd.to_str());
747                                      // use command_line_test_with_env
748     command_line_test_with_env([~"install", ~"foo"],
749                                &cwd,
750                                Some(~[(~"RUST_PATH", dir_for_path.to_str())]));
751     assert_executable_exists(&dir_for_path, "foo");
752 }
753
754 #[test]
755 fn rust_path_contents() {
756     use std::unstable::change_dir_locked;
757
758     let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed");
759     let abc = &dir.push("A").push("B").push("C");
760     assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX));
761     assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX));
762     assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX));
763     assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) {
764         let p = rust_path();
765         let cwd = os::getcwd().push(".rust");
766         let parent = cwd.pop().pop().push(".rust");
767         let grandparent = cwd.pop().pop().pop().push(".rust");
768         assert!(p.contains(&cwd));
769         assert!(p.contains(&parent));
770         assert!(p.contains(&grandparent));
771         for a_path in p.iter() {
772             assert!(!a_path.components.is_empty());
773         }
774     });
775 }
776
777 #[test]
778 fn rust_path_parse() {
779     os::setenv("RUST_PATH", "/a/b/c:/d/e/f:/g/h/i");
780     let paths = rust_path();
781     assert!(paths.contains(&Path("/g/h/i")));
782     assert!(paths.contains(&Path("/d/e/f")));
783     assert!(paths.contains(&Path("/a/b/c")));
784     os::unsetenv("RUST_PATH");
785 }
786
787 #[test]
788 fn test_list() {
789     let dir = mkdtemp(&os::tmpdir(), "test_list").expect("test_list failed");
790     let foo = PkgId::new("foo");
791     create_local_package_in(&foo, &dir);
792     let bar = PkgId::new("bar");
793     create_local_package_in(&bar, &dir);
794     let quux = PkgId::new("quux");
795     create_local_package_in(&quux, &dir);
796
797 // list doesn't output very much right now...
798     command_line_test([~"install", ~"foo"], &dir);
799     let env_arg = ~[(~"RUST_PATH", dir.to_str())];
800     debug!("RUST_PATH = %s", dir.to_str());
801     let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
802     assert!(list_output.iter().any(|x| x.starts_with("foo")));
803
804     command_line_test([~"install", ~"bar"], &dir);
805     let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
806     assert!(list_output.iter().any(|x| x.starts_with("foo")));
807     assert!(list_output.iter().any(|x| x.starts_with("bar")));
808
809     command_line_test([~"install", ~"quux"], &dir);
810     let list_output = command_line_test_output_with_env([~"list"], env_arg);
811     assert!(list_output.iter().any(|x| x.starts_with("foo")));
812     assert!(list_output.iter().any(|x| x.starts_with("bar")));
813     assert!(list_output.iter().any(|x| x.starts_with("quux")));
814 }
815
816 #[test]
817 fn install_remove() {
818     let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove");
819     let foo = PkgId::new("foo");
820     let bar = PkgId::new("bar");
821     let quux = PkgId::new("quux");
822     create_local_package_in(&foo, &dir);
823     create_local_package_in(&bar, &dir);
824     create_local_package_in(&quux, &dir);
825     let rust_path_to_use = ~[(~"RUST_PATH", dir.to_str())];
826     command_line_test([~"install", ~"foo"], &dir);
827     command_line_test([~"install", ~"bar"], &dir);
828     command_line_test([~"install", ~"quux"], &dir);
829     let list_output = command_line_test_output_with_env([~"list"], rust_path_to_use.clone());
830     assert!(list_output.iter().any(|x| x.starts_with("foo")));
831     assert!(list_output.iter().any(|x| x.starts_with("bar")));
832     assert!(list_output.iter().any(|x| x.starts_with("quux")));
833     command_line_test([~"uninstall", ~"foo"], &dir);
834     let list_output = command_line_test_output_with_env([~"list"], rust_path_to_use.clone());
835     assert!(!list_output.iter().any(|x| x.starts_with("foo")));
836     assert!(list_output.iter().any(|x| x.starts_with("bar")));
837     assert!(list_output.iter().any(|x| x.starts_with("quux")));
838 }
839
840 #[test]
841 fn install_check_duplicates() {
842     // should check that we don't install two packages with the same full name *and* version
843     // ("Is already installed -- doing nothing")
844     // check invariant that there are no dups in the pkg database
845     let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove");
846     let foo = PkgId::new("foo");
847     create_local_package_in(&foo, &dir);
848
849     command_line_test([~"install", ~"foo"], &dir);
850     command_line_test([~"install", ~"foo"], &dir);
851     let mut contents = ~[];
852     let check_dups = |p: &PkgId| {
853         if contents.contains(p) {
854             fail!("package %s appears in `list` output more than once", p.path.to_str());
855         }
856         else {
857             contents.push((*p).clone());
858         }
859         false
860     };
861     list_installed_packages(check_dups);
862 }
863
864 #[test]
865 #[ignore(reason = "Workcache not yet implemented -- see #7075")]
866 fn no_rebuilding() {
867     let p_id = PkgId::new("foo");
868     let workspace = create_local_package(&p_id);
869     command_line_test([~"build", ~"foo"], &workspace);
870     let date = datestamp(&built_library_in_workspace(&p_id,
871                                                     &workspace).expect("no_rebuilding"));
872     command_line_test([~"build", ~"foo"], &workspace);
873     let newdate = datestamp(&built_library_in_workspace(&p_id,
874                                                        &workspace).expect("no_rebuilding (2)"));
875     assert_eq!(date, newdate);
876 }
877
878 #[test]
879 #[ignore(reason = "Workcache not yet implemented -- see #7075")]
880 fn no_rebuilding_dep() {
881     let p_id = PkgId::new("foo");
882     let dep_id = PkgId::new("bar");
883     let workspace = create_local_package_with_dep(&p_id, &dep_id);
884     command_line_test([~"build", ~"foo"], &workspace);
885     let bar_date = datestamp(&lib_output_file_name(&workspace,
886                                                   ".rust",
887                                                   "bar"));
888     let foo_date = datestamp(&output_file_name(&workspace, "foo"));
889     assert!(bar_date < foo_date);
890 }
891
892 // n.b. The following two tests are ignored; they worked "accidentally" before,
893 // when the behavior was "always rebuild libraries" (now it's "never rebuild
894 // libraries if they already exist"). They can be un-ignored once #7075 is done.
895 #[test]
896 #[ignore(reason = "Workcache not yet implemented -- see #7075")]
897 fn do_rebuild_dep_dates_change() {
898     let p_id = PkgId::new("foo");
899     let dep_id = PkgId::new("bar");
900     let workspace = create_local_package_with_dep(&p_id, &dep_id);
901     command_line_test([~"build", ~"foo"], &workspace);
902     let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
903     let bar_date = datestamp(&bar_lib_name);
904     debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
905     touch_source_file(&workspace, &dep_id);
906     command_line_test([~"build", ~"foo"], &workspace);
907     let new_bar_date = datestamp(&bar_lib_name);
908     debug!("Datestamp on %s is %?", bar_lib_name.to_str(), new_bar_date);
909     assert!(new_bar_date > bar_date);
910 }
911
912 #[test]
913 #[ignore(reason = "Workcache not yet implemented -- see #7075")]
914 fn do_rebuild_dep_only_contents_change() {
915     let p_id = PkgId::new("foo");
916     let dep_id = PkgId::new("bar");
917     let workspace = create_local_package_with_dep(&p_id, &dep_id);
918     command_line_test([~"build", ~"foo"], &workspace);
919     let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
920     frob_source_file(&workspace, &dep_id);
921     // should adjust the datestamp
922     command_line_test([~"build", ~"foo"], &workspace);
923     let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
924     assert!(new_bar_date > bar_date);
925 }
926
927 #[test]
928 fn test_versions() {
929     let workspace = create_local_package(&PkgId::new("foo#0.1"));
930     create_local_package(&PkgId::new("foo#0.2"));
931     command_line_test([~"install", ~"foo#0.1"], &workspace);
932     let output = command_line_test_output([~"list"]);
933     // make sure output includes versions
934     assert!(!output.iter().any(|x| x == &~"foo#0.2"));
935 }
936
937 #[test]
938 #[ignore(reason = "do not yet implemented")]
939 fn test_build_hooks() {
940     let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo"),
941                                                                 "frob");
942     command_line_test([~"do", ~"foo", ~"frob"], &workspace);
943 }
944
945
946 #[test]
947 #[ignore(reason = "info not yet implemented")]
948 fn test_info() {
949     let expected_info = ~"package foo"; // fill in
950     let workspace = create_local_package(&PkgId::new("foo"));
951     let output = command_line_test([~"info", ~"foo"], &workspace);
952     assert_eq!(str::from_bytes(output.output), expected_info);
953 }
954
955 #[test]
956 #[ignore(reason = "test not yet implemented")]
957 fn test_rustpkg_test() {
958     let expected_results = ~"1 out of 1 tests passed"; // fill in
959     let workspace = create_local_package_with_test(&PkgId::new("foo"));
960     let output = command_line_test([~"test", ~"foo"], &workspace);
961     assert_eq!(str::from_bytes(output.output), expected_results);
962 }
963
964 #[test]
965 #[ignore(reason = "test not yet implemented")]
966 fn test_uninstall() {
967     let workspace = create_local_package(&PkgId::new("foo"));
968     let _output = command_line_test([~"info", ~"foo"], &workspace);
969     command_line_test([~"uninstall", ~"foo"], &workspace);
970     let output = command_line_test([~"list"], &workspace);
971     assert!(!str::from_bytes(output.output).contains("foo"));
972 }
973
974 #[test]
975 fn test_non_numeric_tag() {
976     let temp_pkg_id = git_repo_pkg();
977     let repo = init_git_repo(&temp_pkg_id.path);
978     let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg");
979     writeFile(&repo_subdir.push("foo"), "foo");
980     writeFile(&repo_subdir.push("lib.rs"),
981               "pub fn f() { let _x = (); }");
982     add_git_tag(&repo_subdir, ~"testbranch");
983     writeFile(&repo_subdir.push("testbranch_only"), "hello");
984     add_git_tag(&repo_subdir, ~"another_tag");
985     writeFile(&repo_subdir.push("not_on_testbranch_only"), "bye bye");
986     add_all_and_commit(&repo_subdir);
987
988     command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.path.to_str())], &repo);
989     let file1 = repo.push_many(["mockgithub.com", "catamorphism",
990                                 "test-pkg", "testbranch_only"]);
991     let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test-pkg",
992                                 "master_only"]);
993     assert!(os::path_exists(&file1));
994     assert!(!os::path_exists(&file2));
995 }
996
997 #[test]
998 fn test_extern_mod() {
999     let dir = mkdtemp(&os::tmpdir(), "test_extern_mod").expect("test_extern_mod");
1000     let main_file = dir.push("main.rs");
1001     let lib_depend_dir = mkdtemp(&os::tmpdir(), "foo").expect("test_extern_mod");
1002     let aux_dir = lib_depend_dir.push_many(["src", "mockgithub.com", "catamorphism", "test_pkg"]);
1003     assert!(os::mkdir_recursive(&aux_dir, U_RWX));
1004     let aux_pkg_file = aux_dir.push("lib.rs");
1005
1006     writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() {  assert!(true); } }\n");
1007     assert!(os::path_exists(&aux_pkg_file));
1008
1009     writeFile(&main_file,
1010               "extern mod test = \"mockgithub.com/catamorphism/test_pkg\";\nuse test::bar;\
1011                fn main() { bar::assert_true(); }\n");
1012
1013     command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg"], &lib_depend_dir);
1014
1015     let exec_file = dir.push("out");
1016     // Be sure to extend the existing environment
1017     let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env());
1018     let rustpkg_exec = rustpkg_exec();
1019     let rustc = rustpkg_exec.with_filename("rustc");
1020     debug!("RUST_PATH=%s %s %s \n --sysroot %s -o %s",
1021                      lib_depend_dir.to_str(),
1022                      rustc.to_str(),
1023                      main_file.to_str(),
1024                      test_sysroot().to_str(),
1025                      exec_file.to_str());
1026
1027     let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
1028                                                       ~"--sysroot", test_sysroot().to_str(),
1029                                                ~"-o", exec_file.to_str()],
1030                                      run::ProcessOptions {
1031         env: env,
1032         dir: Some(&dir),
1033         in_fd: None,
1034         out_fd: None,
1035         err_fd: None
1036     });
1037     let outp = prog.finish_with_output();
1038     if outp.status != 0 {
1039         fail!("output was %s, error was %s",
1040               str::from_bytes(outp.output),
1041               str::from_bytes(outp.error));
1042     }
1043     assert!(os::path_exists(&exec_file) && is_executable(&exec_file));
1044 }
1045
1046 #[test]
1047 fn test_import_rustpkg() {
1048     let p_id = PkgId::new("foo");
1049     let workspace = create_local_package(&p_id);
1050     writeFile(&workspace.push("src").push("foo-0.1").push("pkg.rs"),
1051               "extern mod rustpkg; fn main() {}");
1052     command_line_test([~"build", ~"foo"], &workspace);
1053     debug!("workspace = %s", workspace.to_str());
1054     assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s",
1055         os::EXE_SUFFIX))));
1056 }
1057
1058 #[test]
1059 fn test_macro_pkg_script() {
1060     let p_id = PkgId::new("foo");
1061     let workspace = create_local_package(&p_id);
1062     writeFile(&workspace.push("src").push("foo-0.1").push("pkg.rs"),
1063               "extern mod rustpkg; fn main() { debug!(\"Hi\"); }");
1064     command_line_test([~"build", ~"foo"], &workspace);
1065     debug!("workspace = %s", workspace.to_str());
1066     assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s",
1067         os::EXE_SUFFIX))));
1068 }
1069
1070 #[test]
1071 fn multiple_workspaces() {
1072 // Make a package foo; build/install in directory A
1073 // Copy the exact same package into directory B and install it
1074 // Set the RUST_PATH to A:B
1075 // Make a third package that uses foo, make sure we can build/install it
1076     let a_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
1077     let b_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
1078     debug!("Trying to install foo in %s", a_loc.to_str());
1079     command_line_test([~"install", ~"foo"], &a_loc);
1080     debug!("Trying to install foo in %s", b_loc.to_str());
1081     command_line_test([~"install", ~"foo"], &b_loc);
1082     let env = Some(~[(~"RUST_PATH", fmt!("%s:%s", a_loc.to_str(), b_loc.to_str()))]);
1083     let c_loc = create_local_package_with_dep(&PkgId::new("bar"), &PkgId::new("foo"));
1084     command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
1085 }
1086
1087 /// Returns true if p exists and is executable
1088 fn is_executable(p: &Path) -> bool {
1089     use std::libc::consts::os::posix88::{S_IXUSR};
1090
1091     match p.get_mode() {
1092         None => false,
1093         Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
1094     }
1095 }