Conditionally compile tests based on CFG_RELEASE_CHANNEL env var

Adds the ``nightly_only_test`` and ``stable_only_test`` attribute macros
that prevent or allow certain tests to compile on nightly and stable
respectively. This is achieved through conditionally outputting the
tests TokenStream.

If CFG_RELEASE_CHANNEL is not set, it's assumed that we're running in a
nightly environment.

To mark a test as nightly only:

    #[nightly_only_test]
    #[test]
    fn only_run_on_nightly() {
        ...
    }

To mark a test a stable only:

    #[stable_only_test]
    #[test]
    fn only_run_on_stable() {
        ...
    }
This commit is contained in:
Yacin Tmimi 2021-11-27 17:14:15 -05:00 committed by Caleb Cartwright
parent 67fd9ec300
commit a21f1b6c2a
4 changed files with 86 additions and 66 deletions

View File

@ -8,6 +8,8 @@
mod item_struct;
mod utils;
use std::str::FromStr;
use proc_macro::TokenStream;
use syn::parse_macro_input;
@ -23,3 +25,43 @@ pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream {
TokenStream::from(output)
}
/// Used to conditionally output the TokenStream for tests that need to be run on nightly only.
///
/// ```rust
/// #[nightly_only_test]
/// #[test]
/// fn test_needs_nightly_rustfmt() {
/// assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
// if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true
if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") {
input
} else {
// output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev"
TokenStream::from_str("").unwrap()
}
}
/// Used to conditionally output the TokenStream for tests that need to be run on stable only.
///
/// ```rust
/// #[stable_only_test]
/// #[test]
/// fn test_needs_stable_rustfmt() {
/// assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
// if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false
if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") {
input
} else {
// output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable'
TokenStream::from_str("").unwrap()
}
}

View File

@ -405,6 +405,8 @@ mod test {
use super::*;
use std::str;
use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
#[allow(dead_code)]
mod mock {
use super::super::*;
@ -525,21 +527,17 @@ fn test_empty_string_license_template_path() {
assert!(config.license_template.is_none());
}
#[nightly_only_test]
#[test]
fn test_valid_license_template_path() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
}
#[nightly_only_test]
#[test]
fn test_override_existing_license_with_no_license() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let mut config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
@ -634,48 +632,42 @@ fn test_dump_default_config() {
assert_eq!(&toml, &default_config);
}
// FIXME(#2183): these tests cannot be run in parallel because they use env vars.
// #[test]
// fn test_as_not_nightly_channel() {
// let mut config = Config::default();
// assert_eq!(config.was_set().unstable_features(), false);
// config.set().unstable_features(true);
// assert_eq!(config.was_set().unstable_features(), false);
// }
#[stable_only_test]
#[test]
fn test_as_not_nightly_channel() {
let mut config = Config::default();
assert_eq!(config.was_set().unstable_features(), false);
config.set().unstable_features(true);
assert_eq!(config.was_set().unstable_features(), false);
}
// #[test]
// fn test_as_nightly_channel() {
// let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
// ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
// let mut config = Config::default();
// config.set().unstable_features(true);
// assert_eq!(config.was_set().unstable_features(), false);
// config.set().unstable_features(true);
// assert_eq!(config.unstable_features(), true);
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
// }
#[nightly_only_test]
#[test]
fn test_as_nightly_channel() {
let mut config = Config::default();
config.set().unstable_features(true);
// When we don't set the config from toml or command line options it
// doesn't get marked as set by the user.
assert_eq!(config.was_set().unstable_features(), false);
config.set().unstable_features(true);
assert_eq!(config.unstable_features(), true);
}
// #[test]
// fn test_unstable_from_toml() {
// let mut config = Config::from_toml("unstable_features = true").unwrap();
// assert_eq!(config.was_set().unstable_features(), false);
// let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
// ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
// config = Config::from_toml("unstable_features = true").unwrap();
// assert_eq!(config.was_set().unstable_features(), true);
// assert_eq!(config.unstable_features(), true);
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
// }
#[nightly_only_test]
#[test]
fn test_unstable_from_toml() {
let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap();
assert_eq!(config.was_set().unstable_features(), true);
assert_eq!(config.unstable_features(), true);
}
#[cfg(test)]
mod deprecated_option_merge_imports {
use super::*;
#[nightly_only_test]
#[test]
fn test_old_option_set() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
merge_imports = true
@ -684,11 +676,9 @@ fn test_old_option_set() {
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}
#[nightly_only_test]
#[test]
fn test_both_set() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
merge_imports = true
@ -698,11 +688,9 @@ fn test_both_set() {
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
#[nightly_only_test]
#[test]
fn test_new_overridden() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
merge_imports = true
@ -712,11 +700,9 @@ fn test_new_overridden() {
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
#[nightly_only_test]
#[test]
fn test_old_overridden() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
imports_granularity = "Module"

View File

@ -286,10 +286,11 @@ fn lookup_line_range(&self, span: Span) -> LineRange {
mod tests {
use super::*;
use rustfmt_config_proc_macro::nightly_only_test;
mod emitter {
use super::*;
use crate::config::IgnoreList;
use crate::is_nightly_channel;
use crate::utils::mk_sp;
use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP};
use std::path::PathBuf;
@ -371,11 +372,9 @@ fn handles_fatal_parse_error_in_ignored_file() {
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
#[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_ignored_file() {
if !is_nightly_channel!() {
return;
}
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
@ -398,11 +397,9 @@ fn handles_recoverable_parse_error_in_ignored_file() {
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
}
#[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_non_ignored_file() {
if !is_nightly_channel!() {
return;
}
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
@ -424,11 +421,9 @@ fn handles_recoverable_parse_error_in_non_ignored_file() {
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
#[nightly_only_test]
#[test]
fn handles_mix_of_recoverable_parse_error() {
if !is_nightly_channel!() {
return;
}
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));

View File

@ -15,6 +15,8 @@
use crate::source_file;
use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
use rustfmt_config_proc_macro::nightly_only_test;
mod configuration_snippet;
mod mod_resolver;
mod parser;
@ -307,14 +309,11 @@ fn assert_output(source: &Path, expected_filename: &Path) {
// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
#[nightly_only_test]
#[test]
fn idempotence_tests() {
init_log();
run_test_with(&TestSetting::default(), || {
// these tests require nightly
if !is_nightly_channel!() {
return;
}
// Get all files in the tests/target directory.
let files = get_test_files(Path::new("tests/target"), true);
let (_reports, count, fails) = check_files(files, &None);
@ -332,13 +331,11 @@ fn idempotence_tests() {
// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
// Issue-3443: these tests require nightly
#[nightly_only_test]
#[test]
fn self_tests() {
init_log();
// Issue-3443: these tests require nightly
if !is_nightly_channel!() {
return;
}
let mut files = get_test_files(Path::new("tests"), false);
let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"];
for dir in bin_directories {