52

I'm on a project interacting with files, and I would like to use text files to test my work. However tests aren't run from the tests/ directory, and thus I cannot reliably find them when running cargo run.

Does Cargo handle this by always running test from the root directory (which seems to be the case but I didn't find anything attesting it)?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Léo Ercolanelli
  • 1,000
  • 1
  • 8
  • 11

2 Answers2

82

The environment variable CARGO_MANIFEST_DIR can give you a stable base point to reference other files. Here, we assume that there's a resources/test directory at the top level of the crate:

use std::path::PathBuf;

fn main() {
    let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    d.push("resources/test");

    println!("{}", d.display());
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Can this variable be overwritten? (for example in .env file) It doesn't seem so. – Anatoly Bugakov Aug 08 '22 at 17:21
  • 1
    @AnatolyBugakov I don't understand _why_ you'd want to do that, but no, I don't believe it can be overridden. Cargo sets the environment variable when compiling the build script. You could potentially create your own environment variable and prefer that if it's set, falling back to the Cargo-provided variable otherwise. – Shepmaster Aug 09 '22 at 14:32
  • Thanks for your responce @Shepmaster. The reason I was curious is because I work with Workspaces, and I'd like to access same tests data from different librarires. Prorbably though it's not a good practice. – Anatoly Bugakov Aug 09 '22 at 15:21
  • A better way to concat the paths would be `let d: PathBuf = [env!("CARGO_MANIFEST_DIR"), "resources", "test"].iter().collect();` – Raniz Jul 05 '23 at 08:08
4

Building on top of the answer provided by @Shepmaster, presuming you intend to read the files for testing:

macro_rules! test_case {($fname:expr) => (
  concat!(env!("CARGO_MANIFEST_DIR"), "/resources/test/", $fname) // assumes Linux ('/')!
)}

which is simply used in your unit test like:

test_case!("json_data/example.json")

More or less accomplishes same goal but at compile-time (helpful for catching missing files) and fairly minimal. If someone knows how to make this compile-time and platform indepent - please feel welcome to edit.

See the full discussion in rust-lang issue #2841

ecoe
  • 4,994
  • 7
  • 54
  • 72