blob: 0762ded6cabf945931b1179a25319a75c495afc4 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! This file contains "golden" tests, which compare the output of known sample
//! `Cargo.toml` files with known fixed reference output files.
use {
anyhow::Context,
argh::FromArgs,
// Without this, the test diffs are impractical to debug.
pretty_assertions::assert_eq,
std::path::{Path, PathBuf},
tempfile,
};
#[derive(FromArgs, Debug)]
/// Paths to use in test. All paths are relative to where this test is executed.
///
/// These paths have to be relative when passed to this test on infra bots, so they are mapped
/// correctly, otherwise they won't be available at test runtime. It is safe to convert these to
/// absolute paths later in the test.
struct Paths {
/// path to the directory where golden tests are placed.
#[argh(option)]
test_base_dir: String,
/// path to `rustc` binary to use in test.
#[argh(option)]
rustc_binary_path: String,
/// path to `gn` binary to use in test.
#[argh(option)]
gn_binary_path: String,
/// path to `cargo` binary to use in test.
#[argh(option)]
cargo_binary_path: String,
/// path to shared libraries directory to use in test.
#[argh(option)]
lib_path: String,
}
fn main() {
let paths: Paths = argh::from_env();
eprintln!("paths: {:?}", &paths);
// Shared library setup for Linux and Mac. Systems will ignore the settings
// that don't apply to them.
//
// These values need to be absolute so they work regardless of the current working directory.
std::env::set_var("LD_LIBRARY_PATH", Path::new(&paths.lib_path).canonicalize().unwrap());
std::env::set_var("DYLD_LIBRARY_PATH", Path::new(&paths.lib_path).canonicalize().unwrap());
// Cargo internally invokes rustc; but we must tell it to use the one from
// our sandbox, and this is configured using the env variable "RUSTC".
//
// This value needs to be absolute so it works regardless of the current working directory.
//
// See:
// https://doc.rust-lang.org/cargo/reference/environment-variables.html
std::env::set_var("RUSTC", Path::new(&paths.rustc_binary_path).canonicalize().unwrap());
#[derive(Debug)]
struct TestCase {
/// Manifest file path (`Cargo.toml`); relative to the base test directory.
manifest_path: Vec<&'static str>,
/// Expected file (`BUILD.gn`); relative to the base test directory.
golden_expected_filename: Vec<&'static str>,
/// If set, the flag `--skip-root` is added to `cargo_gnaw` invocation.
skip_root: bool,
}
let tests = vec![
TestCase {
manifest_path: vec!["simple", "Cargo.toml"],
golden_expected_filename: vec!["simple", "BUILD.gn"],
skip_root: false,
},
TestCase {
manifest_path: vec!["simple_deps", "Cargo.toml"],
golden_expected_filename: vec!["simple_deps", "BUILD.gn"],
skip_root: false,
},
TestCase {
manifest_path: vec!["simple_deps", "Cargo.toml"],
golden_expected_filename: vec!["simple_deps", "BUILD_WITH_NO_ROOT.gn"],
skip_root: true,
},
TestCase {
manifest_path: vec!["platform_deps", "Cargo.toml"],
golden_expected_filename: vec!["platform_deps", "BUILD.gn"],
skip_root: true,
},
TestCase {
manifest_path: vec!["binary", "Cargo.toml"],
golden_expected_filename: vec!["binary", "BUILD.gn"],
skip_root: false,
},
];
for test in tests {
let test_dir = tempfile::TempDir::new().unwrap();
let manifest_path: PathBuf =
test_dir.path().join(test.manifest_path.iter().collect::<PathBuf>());
let output = test_dir.path().join("BUILD.gn");
// we need the emitted file to be under the same path as the gn targets it references
let test_base_dir = PathBuf::from(&paths.test_base_dir);
copy_contents(&test_base_dir, test_dir.path());
let project_root = test_dir.path().to_str().unwrap().to_owned();
// Note: argh does not support "--flag=value" or "--bool-flag false".
let absolute_cargo_binary_path =
Path::new(&paths.cargo_binary_path).canonicalize().unwrap();
let mut args: Vec<&str> = vec![
// args[0] is not used in arg parsing, so this can be any string.
"fake_binary_name",
"--manifest-path",
manifest_path.to_str().unwrap(),
"--project-root",
&project_root,
"--output",
output.to_str().unwrap(),
"--gn-bin",
&paths.gn_binary_path,
"--cargo",
// Cargo is not executed in another working directory by gnaw_lib, so an absolute path
// is necessary here.
absolute_cargo_binary_path.to_str().unwrap(),
];
if test.skip_root {
args.push("--skip-root");
}
gnaw_lib::run(&args)
.with_context(|| format!("\n\targs were: {:?}\n\ttest was: {:?}", &args, &test))
.expect("gnaw_lib::run should succeed");
let output = std::fs::read_to_string(&output)
.with_context(|| format!("while reading tempfile: {}", output.display()))
.expect("tempfile read success");
let expected_path: PathBuf =
test_base_dir.join(test.golden_expected_filename.iter().collect::<PathBuf>());
let expected = std::fs::read_to_string(expected_path.to_string_lossy().to_string())
.with_context(|| {
format!("while reading expected: {:?}", &test.golden_expected_filename)
})
.expect("expected file read success");
assert_eq!(expected, output, "left: expected; right: actual: {:?}", &test);
}
}
fn copy_contents(original_test_dir: &Path, test_dir_path: &Path) {
// copy the contents of original test dir to test_dir
for entry in walkdir::WalkDir::new(&original_test_dir) {
let entry = entry.expect("walking original test directory to copy files to /tmp");
if !entry.file_type().is_file() {
continue;
}
let to_copy = entry.path();
let destination = test_dir_path.join(to_copy.strip_prefix(&original_test_dir).unwrap());
std::fs::create_dir_all(destination.parent().unwrap())
.expect("making parent of file to copy");
std::fs::copy(to_copy, destination).expect("copying file");
}
println!("done copying files");
}