test(linter): add snapshot tester for cli (#8695)

Our first Snapshot 🥳
This commit is contained in:
Sysix 2025-01-24 17:19:31 +00:00
parent 741fb40a53
commit 34d3d72b64
9 changed files with 323 additions and 140 deletions

1
Cargo.lock generated
View file

@ -2219,6 +2219,7 @@ version = "0.15.8"
dependencies = [
"bpaf",
"ignore",
"insta",
"jemallocator",
"mimalloc",
"oxc-miette",

View file

@ -37,6 +37,7 @@ oxc_span = { workspace = true }
bpaf = { workspace = true, features = ["autocomplete", "bright-color", "derive"] }
ignore = { workspace = true, features = ["simd-accel"] }
insta = { workspace = true }
miette = { workspace = true }
rayon = { workspace = true }
rustc-hash = { workspace = true }

View file

@ -3,6 +3,7 @@ mod lint;
mod output_formatter;
mod result;
mod runner;
mod tester;
mod walk;
pub mod cli {

View file

@ -126,7 +126,14 @@ impl Runner for LintRunner {
if let Some(basic_config_file) = oxlintrc_for_print {
let config_file = config_builder.resolve_final_config_file(basic_config_file);
if misc_options.print_config {
return CliRunResult::PrintConfigResult { config_file };
stdout
.write_all(config_file.as_bytes())
.or_else(Self::check_for_writer_error)
.unwrap();
stdout.write_all(b"\n").or_else(Self::check_for_writer_error).unwrap();
stdout.flush().unwrap();
return CliRunResult::PrintConfigResult;
} else if basic_options.init {
let schema_relative_path = "node_modules/oxlint/configuration_schema.json";
let configuration = if self.cwd.join(schema_relative_path).is_file() {
@ -323,65 +330,18 @@ impl LintRunner {
#[cfg(test)]
mod test {
use std::{env, fs, path::MAIN_SEPARATOR_STR};
use std::fs;
use super::LintRunner;
use crate::cli::{lint_command, CliRunResult, LintResult, Runner};
fn test(args: &[&str]) -> LintResult {
let mut new_args = vec!["--silent"];
new_args.extend(args);
let options = lint_command().run_inner(new_args.as_slice()).unwrap();
let mut output = Vec::new();
match LintRunner::new(options).run(&mut output) {
CliRunResult::LintResult(lint_result) => lint_result,
other => panic!("{other:?}"),
}
}
fn test_with_cwd(cwd: &str, args: &[&str]) -> LintResult {
let mut new_args = vec!["--silent"];
new_args.extend(args);
let options = lint_command().run_inner(new_args.as_slice()).unwrap();
let mut current_cwd = env::current_dir().unwrap();
let part_cwd = if MAIN_SEPARATOR_STR == "/" {
cwd.into()
} else {
#[expect(clippy::disallowed_methods)]
cwd.replace('/', MAIN_SEPARATOR_STR)
};
current_cwd.push(part_cwd);
let mut output = Vec::new();
match LintRunner::new(options).with_cwd(current_cwd).run(&mut output) {
CliRunResult::LintResult(lint_result) => lint_result,
other => panic!("{other:?}"),
}
}
fn test_invalid_options(args: &[&str]) -> String {
let mut new_args = vec!["--quiet"];
new_args.extend(args);
let options = lint_command().run_inner(new_args.as_slice()).unwrap();
let mut output = Vec::new();
match LintRunner::new(options).run(&mut output) {
CliRunResult::InvalidOptions { message } => message,
other => {
panic!("Expected InvalidOptions, got {other:?}");
}
}
}
use crate::{
cli::{lint_command, CliRunResult, Runner},
tester::Tester,
};
#[test]
fn no_arg() {
let args = &[];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert!(result.number_of_warnings > 0);
assert_eq!(result.number_of_errors, 0);
}
@ -389,7 +349,7 @@ mod test {
#[test]
fn dir() {
let args = &["fixtures/linter"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 3);
assert_eq!(result.number_of_warnings, 3);
assert_eq!(result.number_of_errors, 0);
@ -398,7 +358,7 @@ mod test {
#[test]
fn cwd() {
let args = &["debugger.js"];
let result = test_with_cwd("fixtures/linter", args);
let result = Tester::new().with_cwd("fixtures/linter".into()).get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -407,7 +367,7 @@ mod test {
#[test]
fn file() {
let args = &["fixtures/linter/debugger.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -416,7 +376,7 @@ mod test {
#[test]
fn multi_files() {
let args = &["fixtures/linter/debugger.js", "fixtures/linter/nan.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 2);
assert_eq!(result.number_of_warnings, 2);
assert_eq!(result.number_of_errors, 0);
@ -425,7 +385,7 @@ mod test {
#[test]
fn wrong_extension() {
let args = &["foo.asdf"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 0);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -435,7 +395,7 @@ mod test {
fn ignore_pattern() {
let args =
&["--ignore-pattern", "**/*.js", "--ignore-pattern", "**/*.vue", "fixtures/linter"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 0);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -447,7 +407,7 @@ mod test {
#[test]
fn ignore_file_overrides_explicit_args() {
let args = &["--ignore-path", "fixtures/linter/.customignore", "fixtures/linter/nan.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 0);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -461,7 +421,7 @@ mod test {
"--no-ignore",
"fixtures/linter/nan.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -470,7 +430,7 @@ mod test {
#[test]
fn ignore_flow() {
let args = &["--import-plugin", "fixtures/flow/index.mjs"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -480,7 +440,7 @@ mod test {
// https://github.com/oxc-project/oxc/issues/7406
fn ignore_flow_import_plugin_directory() {
let args = &["--import-plugin", "-A all", "-D no-cycle", "fixtures/flow/"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 2);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -489,7 +449,7 @@ mod test {
#[test]
fn filter_allow_all() {
let args = &["-A", "all", "fixtures/linter"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert!(result.number_of_files > 0);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -498,7 +458,7 @@ mod test {
#[test]
fn filter_allow_one() {
let args = &["-W", "correctness", "-A", "no-debugger", "fixtures/linter/debugger.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -507,7 +467,7 @@ mod test {
#[test]
fn filter_error() {
let args = &["-D", "correctness", "fixtures/linter/debugger.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -516,7 +476,7 @@ mod test {
#[test]
fn eslintrc_error() {
let args = &["-c", "fixtures/linter/eslintrc.json", "fixtures/linter/debugger.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -525,7 +485,7 @@ mod test {
#[test]
fn eslintrc_off() {
let args = &["-c", "fixtures/eslintrc_off/eslintrc.json", "fixtures/eslintrc_off/test.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1); // triggered by no_empty_file
assert_eq!(result.number_of_errors, 0);
@ -534,7 +494,9 @@ mod test {
#[test]
fn oxlint_config_auto_detection() {
let args = &["debugger.js"];
let result = test_with_cwd("fixtures/auto_config_detection", args);
let result =
Tester::new().with_cwd("fixtures/auto_config_detection".into()).get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -549,7 +511,7 @@ mod test {
"fixtures/no_undef/eslintrc.json",
"fixtures/no_undef/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -564,7 +526,7 @@ mod test {
"fixtures/eslintrc_env/eslintrc_no_env.json",
"fixtures/eslintrc_env/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -577,7 +539,7 @@ mod test {
"fixtures/eslintrc_env/eslintrc_env_browser.json",
"fixtures/eslintrc_env/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -592,7 +554,7 @@ mod test {
"no-empty",
"fixtures/no_empty_allow_empty_catch/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -607,7 +569,7 @@ mod test {
"no-empty",
"fixtures/no_empty_disallow_empty_catch/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -617,7 +579,7 @@ mod test {
fn no_console_off() {
let args =
&["-c", "fixtures/no_console_off/eslintrc.json", "fixtures/no_console_off/test.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -630,7 +592,7 @@ mod test {
"fixtures/typescript_eslint/eslintrc.json",
"fixtures/typescript_eslint/test.ts",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 3);
assert_eq!(result.number_of_errors, 0);
@ -644,13 +606,16 @@ mod test {
"--disable-typescript-plugin",
"fixtures/typescript_eslint/test.ts",
];
test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 2);
assert_eq!(result.number_of_errors, 0);
}
#[test]
fn lint_vue_file() {
let args = &["fixtures/vue/debugger.vue"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 2);
assert_eq!(result.number_of_errors, 0);
@ -659,7 +624,7 @@ mod test {
#[test]
fn lint_empty_vue_file() {
let args = &["fixtures/vue/empty.vue"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -668,7 +633,7 @@ mod test {
#[test]
fn lint_astro_file() {
let args = &["fixtures/astro/debugger.astro"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 4);
assert_eq!(result.number_of_errors, 0);
@ -677,7 +642,7 @@ mod test {
#[test]
fn lint_svelte_file() {
let args = &["fixtures/svelte/debugger.svelte"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
@ -686,10 +651,11 @@ mod test {
#[test]
fn test_tsconfig_option() {
// passed
test(&["--tsconfig", "fixtures/tsconfig/tsconfig.json"]);
Tester::new().get_lint_result(&["--tsconfig", "fixtures/tsconfig/tsconfig.json"]);
// failed
assert!(test_invalid_options(&["--tsconfig", "oxc/tsconfig.json"])
assert!(Tester::new()
.get_invalid_option_result(&["--tsconfig", "oxc/tsconfig.json"])
.contains("oxc/tsconfig.json\" does not exist, Please provide a valid tsconfig file."));
}
@ -700,7 +666,10 @@ mod test {
"fixtures/eslintrc_vitest_replace/eslintrc.json",
"fixtures/eslintrc_vitest_replace/foo.test.js",
];
test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
}
#[test]
@ -711,7 +680,7 @@ mod test {
"fixtures/eslintrc_vitest_replace/eslintrc.json",
"fixtures/eslintrc_vitest_replace/foo.test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_errors, 1);
}
@ -719,7 +688,7 @@ mod test {
#[test]
fn test_import_plugin_enabled_in_config() {
let args = &["-c", "fixtures/import/.oxlintrc.json", "fixtures/import/test.js"];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -736,14 +705,15 @@ mod test {
assert_eq!(&content, "debugger\n");
// Apply fix to the file.
let _ = test(args);
let _ = Tester::new().get_lint_result(args);
#[expect(clippy::disallowed_methods)]
let new_content = fs::read_to_string(file).unwrap().replace("\r\n", "\n");
assert_eq!(new_content, "\n");
// File should not be modified if no fix is applied.
let modified_before = fs::metadata(file).unwrap().modified().unwrap();
let _ = test(args);
let modified_before: std::time::SystemTime =
fs::metadata(file).unwrap().modified().unwrap();
let _ = Tester::new().get_lint_result(args);
let modified_after = fs::metadata(file).unwrap().modified().unwrap();
assert_eq!(modified_before, modified_after);
@ -754,18 +724,7 @@ mod test {
#[test]
fn test_print_config_ban_all_rules() {
let args = &["-A", "all", "--print-config"];
let options = lint_command().run_inner(args).unwrap();
let mut output = Vec::new();
let ret = LintRunner::new(options).run(&mut output);
let CliRunResult::PrintConfigResult { config_file: config } = ret else {
panic!("Expected PrintConfigResult, got {ret:?}")
};
#[expect(clippy::disallowed_methods)]
let expect_json = std::fs::read_to_string("fixtures/print_config/normal/expect.json")
.unwrap()
.replace("\r\n", "\n");
assert_eq!(config, expect_json.trim());
Tester::new().test_and_snapshot(args);
}
#[test]
@ -779,19 +738,7 @@ mod test {
"eqeqeq",
"--print-config",
];
let options = lint_command().run_inner(args).unwrap();
let mut output = Vec::new();
let ret = LintRunner::new(options).run(&mut output);
let CliRunResult::PrintConfigResult { config_file: config } = ret else {
panic!("Expected PrintConfigResult, got {ret:?}")
};
#[expect(clippy::disallowed_methods)]
let expect_json = std::fs::read_to_string("fixtures/print_config/ban_rules/expect.json")
.unwrap()
.replace("\r\n", "\n");
assert_eq!(config, expect_json.trim());
Tester::new().test_and_snapshot(args);
}
#[test]
@ -809,20 +756,23 @@ mod test {
#[test]
fn test_overrides() {
let result =
test(&["-c", "fixtures/overrides/.oxlintrc.json", "fixtures/overrides/test.js"]);
let args = &["-c", "fixtures/overrides/.oxlintrc.json", "fixtures/overrides/test.js"];
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
let result =
test(&["-c", "fixtures/overrides/.oxlintrc.json", "fixtures/overrides/test.ts"]);
let args = &["-c", "fixtures/overrides/.oxlintrc.json", "fixtures/overrides/test.ts"];
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 1);
let result =
test(&["-c", "fixtures/overrides/.oxlintrc.json", "fixtures/overrides/other.jsx"]);
let args = &["-c", "fixtures/overrides/.oxlintrc.json", "fixtures/overrides/other.jsx"];
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -830,8 +780,9 @@ mod test {
#[test]
fn test_overrides_directories() {
let result =
test(&["-c", "fixtures/overrides/directories-config.json", "fixtures/overrides"]);
let args = &["-c", "fixtures/overrides/directories-config.json", "fixtures/overrides"];
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 7);
assert_eq!(result.number_of_warnings, 2);
assert_eq!(result.number_of_errors, 2);
@ -839,20 +790,22 @@ mod test {
#[test]
fn test_config_ignore_patterns_extension() {
let result = test(&[
let args = &[
"-c",
"fixtures/config_ignore_patterns/ignore_extension/eslintrc.json",
"fixtures/config_ignore_patterns/ignore_extension",
]);
];
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
}
#[test]
fn test_config_ignore_patterns_directory() {
let result = test_with_cwd(
"fixtures/config_ignore_patterns/ignore_directory",
&["-c", "eslintrc.json"],
);
let result = Tester::new()
.with_cwd("fixtures/config_ignore_patterns/ignore_directory".into())
.get_lint_result(&["-c", "eslintrc.json"]);
assert_eq!(result.number_of_files, 1);
}
@ -865,7 +818,7 @@ mod test {
"fixtures/issue_7566/tests/main.js",
"fixtures/issue_7566/tests/function/main.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 0);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
@ -878,7 +831,7 @@ mod test {
"fixtures/jest_and_vitest_alias_rules/oxlint-jest.json",
"fixtures/jest_and_vitest_alias_rules/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -888,7 +841,7 @@ mod test {
"fixtures/jest_and_vitest_alias_rules/oxlint-vitest.json",
"fixtures/jest_and_vitest_alias_rules/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -901,7 +854,7 @@ mod test {
"fixtures/eslint_and_typescript_alias_rules/oxlint-eslint.json",
"fixtures/eslint_and_typescript_alias_rules/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
@ -911,9 +864,15 @@ mod test {
"fixtures/eslint_and_typescript_alias_rules/oxlint-typescript.json",
"fixtures/eslint_and_typescript_alias_rules/test.js",
];
let result = test(args);
let result = Tester::new().get_lint_result(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
}
#[test]
fn test_print_config() {
let args = &["--print-config"];
Tester::new().test_and_snapshot(args);
}
}

View file

@ -9,7 +9,7 @@ pub enum CliRunResult {
InvalidOptions { message: String },
PathNotFound { paths: Vec<PathBuf> },
LintResult(LintResult),
PrintConfigResult { config_file: String },
PrintConfigResult,
ConfigFileInitResult { message: String },
}
@ -30,7 +30,7 @@ impl Termination for CliRunResult {
#[allow(clippy::print_stdout, clippy::print_stderr)]
fn report(self) -> ExitCode {
match self {
Self::None => ExitCode::from(0),
Self::None | Self::PrintConfigResult => ExitCode::from(0),
Self::InvalidOptions { message } => {
println!("Invalid Options: {message}");
ExitCode::from(1)
@ -45,10 +45,6 @@ impl Termination for CliRunResult {
number_of_errors: _,
exit_code,
}) => exit_code,
Self::PrintConfigResult { config_file } => {
println!("{config_file}");
ExitCode::from(0)
}
Self::ConfigFileInitResult { message } => {
println!("{message}");
ExitCode::from(0)

View file

@ -0,0 +1,142 @@
---
source: apps/oxlint/src/tester.rs
---
##########
--print-config
----------
{
"plugins": [
"react",
"unicorn",
"typescript",
"oxc"
],
"categories": {},
"rules": {
"oxc/only-used-in-recursion": "warn",
"oxc/bad-object-literal-comparison": "warn",
"react/jsx-key": "warn",
"no-control-regex": "warn",
"no-with": "warn",
"typescript/no-non-null-asserted-optional-chain": "warn",
"typescript/no-this-alias": "warn",
"oxc/double-comparisons": "warn",
"no-import-assign": "warn",
"for-direction": "warn",
"oxc/missing-throw": "warn",
"no-unsafe-negation": "warn",
"no-dupe-keys": "warn",
"no-irregular-whitespace": "warn",
"react/no-children-prop": "warn",
"typescript/no-wrapper-object-types": "warn",
"no-unused-labels": "warn",
"no-empty-character-class": "warn",
"require-yield": "warn",
"no-loss-of-precision": "warn",
"react/no-direct-mutation-state": "warn",
"unicorn/no-single-promise-in-promise-methods": "warn",
"no-cond-assign": "warn",
"no-useless-catch": "warn",
"no-empty-static-block": "warn",
"react/no-render-return-value": "warn",
"no-sparse-arrays": "warn",
"no-constant-binary-expression": "warn",
"no-useless-escape": "warn",
"use-isnan": "warn",
"oxc/number-arg-out-of-range": "warn",
"oxc/bad-min-max-func": "warn",
"no-this-before-super": "warn",
"react/jsx-no-duplicate-props": "warn",
"no-extra-boolean-cast": "warn",
"no-obj-calls": "warn",
"oxc/const-comparisons": "warn",
"unicorn/no-useless-length-check": "warn",
"no-delete-var": "warn",
"react/jsx-no-undef": "warn",
"no-global-assign": "warn",
"typescript/no-unsafe-declaration-merging": "warn",
"no-async-promise-executor": "warn",
"no-unsafe-finally": "warn",
"no-dupe-else-if": "warn",
"typescript/no-duplicate-enum-values": "warn",
"no-invalid-regexp": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"no-caller": "warn",
"no-self-assign": "warn",
"no-compare-neg-zero": "warn",
"no-unused-vars": "warn",
"no-empty-pattern": "warn",
"react/no-is-mounted": "warn",
"oxc/bad-array-method-on-arguments": "warn",
"unicorn/no-await-in-promise-methods": "warn",
"no-shadow-restricted-names": "warn",
"no-const-assign": "warn",
"unicorn/no-thenable": "warn",
"typescript/triple-slash-reference": "warn",
"react/no-string-refs": "warn",
"no-new-native-nonconstructor": "warn",
"oxc/bad-comparison-sequence": "warn",
"oxc/uninvoked-array-callback": "warn",
"unicorn/no-empty-file": "warn",
"unicorn/no-unnecessary-await": "warn",
"no-nonoctal-decimal-escape": "warn",
"oxc/bad-replace-all-arg": "warn",
"unicorn/no-invalid-remove-event-listener": "warn",
"no-debugger": "warn",
"react/jsx-no-target-blank": "warn",
"no-func-assign": "warn",
"unicorn/no-useless-fallback-in-spread": "warn",
"oxc/erasing-op": "warn",
"unicorn/prefer-set-size": "warn",
"unicorn/no-useless-spread": "warn",
"no-dupe-class-members": "warn",
"react/jsx-props-no-spread-multi": "warn",
"typescript/no-useless-empty-export": "warn",
"react/void-dom-elements-no-children": "warn",
"unicorn/no-new-array": "warn",
"no-unsafe-optional-chaining": "warn",
"no-duplicate-case": "warn",
"react/no-danger-with-children": "warn",
"typescript/prefer-as-const": "warn",
"no-class-assign": "warn",
"no-unused-private-class-members": "warn",
"typescript/no-extra-non-null-assertion": "warn",
"react/no-find-dom-node": "warn",
"no-setter-return": "warn",
"typescript/no-misused-new": "warn",
"unicorn/no-document-cookie": "warn",
"oxc/bad-char-at-comparison": "warn",
"no-constant-condition": "warn",
"no-useless-rename": "warn",
"no-ex-assign": "warn",
"valid-typeof": "warn"
},
"settings": {
"jsx-a11y": {
"polymorphicPropName": null,
"components": {}
},
"next": {
"rootDir": []
},
"react": {
"formComponents": [],
"linkComponents": []
},
"jsdoc": {
"ignorePrivate": false,
"ignoreInternal": false,
"ignoreReplacesDocs": true,
"overrideReplacesDocs": true,
"augmentsExtendsReplacesDocs": false,
"implementsReplacesDocs": false,
"exemptDestructuredRootsFromChecks": false,
"tagNamePreference": {}
}
},
"env": {
"builtin": true
},
"globals": {},
"ignorePatterns": []
}

View file

@ -1,3 +1,9 @@
---
source: apps/oxlint/src/tester.rs
---
##########
-A all --print-config
----------
{
"plugins": [
"react",

View file

@ -1,3 +1,9 @@
---
source: apps/oxlint/src/tester.rs
---
##########
-c fixtures/print_config/ban_rules/eslintrc.json -A all -D eqeqeq --print-config
----------
{
"plugins": [
"react",

71
apps/oxlint/src/tester.rs Normal file
View file

@ -0,0 +1,71 @@
#[cfg(test)]
use crate::cli::{lint_command, CliRunResult, LintResult, LintRunner};
#[cfg(test)]
use crate::runner::Runner;
#[cfg(test)]
use std::{env, path::PathBuf};
#[cfg(test)]
pub struct Tester {
cwd: PathBuf,
}
#[cfg(test)]
impl Tester {
pub fn new() -> Self {
let cwd = env::current_dir().unwrap();
Self { cwd }
}
pub fn with_cwd(mut self, cwd: PathBuf) -> Self {
self.cwd.push(cwd);
self
}
pub fn get_lint_result(&self, args: &[&str]) -> LintResult {
let mut new_args = vec!["--silent"];
new_args.extend(args);
let options = lint_command().run_inner(new_args.as_slice()).unwrap();
let mut output = Vec::new();
match LintRunner::new(options).with_cwd(self.cwd.clone()).run(&mut output) {
CliRunResult::LintResult(lint_result) => lint_result,
other => panic!("{other:?}"),
}
}
pub fn get_invalid_option_result(&self, args: &[&str]) -> String {
let mut new_args = vec!["--silent"];
new_args.extend(args);
let options = lint_command().run_inner(new_args.as_slice()).unwrap();
let mut output = Vec::new();
match LintRunner::new(options).with_cwd(self.cwd.clone()).run(&mut output) {
CliRunResult::InvalidOptions { message } => message,
other => {
panic!("Expected InvalidOptions, got {other:?}");
}
}
}
pub fn test_and_snapshot(&self, args: &[&str]) {
let mut settings = insta::Settings::clone_current();
let options = lint_command().run_inner(args).unwrap();
let mut output: Vec<u8> = Vec::new();
let args_string = args.join(" ");
output.extend_from_slice(format!("########## \n{args_string}\n----------\n").as_bytes());
let _ = LintRunner::new(options).with_cwd(self.cwd.clone()).run(&mut output);
output.push(b'\n');
settings.set_prepend_module_to_snapshot(false);
settings.set_omit_expression(true);
settings.set_snapshot_suffix("oxlint");
settings.bind(|| {
insta::assert_snapshot!(format!("{}", args_string), String::from_utf8(output).unwrap());
});
}
}