//! The real tools, when the machine has them. //! //! Everything else in `tests/` drives stubs, because checkpatch's output moves //! with the kernel version and a test cannot assert on that. These tests are the //! other half: they run the host's own scripts so a kernel-version change to a //! summary line, an argument, or an exit code shows up here rather than in //! someone's patch workflow. //! //! They are ignored by default and need both variables: //! //! ```console //! $ SPECTRAL_REAL_CHECKPATCH=1 SPECTRAL_REAL_TREE=/usr/src/linux \ //! cargo test --locked -- --ignored real_ //! ``` mod common; use common::Fixture; /// A change checkpatch has opinions about, whatever kernel it comes from. const BAD: &str = "static int foo(int a) {\n\tint b = a + 1;\n\tif (a>0)\n\t\tb += 2;\n\treturn b;\n}\n"; #[test] #[ignore = "needs SPECTRAL_REAL_CHECKPATCH=1 and SPECTRAL_REAL_TREE=/path/to/linux"] fn real_checkpatch_reads_all_three_kinds_of_target() { let fixture = real_fixture(); fixture.write("drivers/foo/bar.c", BAD); // The working tree goes in on stdin, because `--git` with no revision // dies with "no git commits after extraction". let working_tree = fixture.cli(&["patch", "check"]); let stdout = String::from_utf8_lossy(&working_tree.stdout).into_owned(); assert_eq!(working_tree.status.code(), Some(1), "{stdout}"); assert!(stdout.contains("total:"), "{stdout}"); assert!(stdout.contains("ERROR"), "{stdout}"); // A revision goes through --git, and checkpatch names the commit it read. let by_rev = fixture.cli(&["patch", "check", "--rev", "HEAD"]); let stdout = String::from_utf8_lossy(&by_rev.stdout).into_owned(); assert!(stdout.contains("fixture: add bar"), "{stdout}"); // A patch file goes through --file. let patch = fixture.home().join("bad.patch"); std::fs::write(&patch, format!("{}\n", fixture.git(&["diff"]))).expect("write the patch"); let by_file = fixture.cli(&["patch", "check", patch.to_str().expect("the patch path")]); let stdout = String::from_utf8_lossy(&by_file.stdout).into_owned(); assert_eq!(by_file.status.code(), Some(1), "{stdout}"); assert!(stdout.contains("ERROR"), "{stdout}"); } /// A fixture whose checkpatch is the host's, copied in. fn real_fixture() -> Fixture { assert_eq!( std::env::var("SPECTRAL_REAL_CHECKPATCH").as_deref(), Ok("1"), "run this with SPECTRAL_REAL_CHECKPATCH=1" ); let tree = std::env::var("SPECTRAL_REAL_TREE") .expect("set SPECTRAL_REAL_TREE to a kernel tree holding scripts/checkpatch.pl"); let fixture = Fixture::kernel_tree(); let script = std::path::Path::new(&tree).join("scripts/checkpatch.pl"); let body = std::fs::read_to_string(&script) .unwrap_or_else(|error| panic!("read {}: {error}", script.display())); fixture.write_script("scripts/checkpatch.pl", &body); fixture } #[test] #[ignore = "needs SPECTRAL_REAL_GETMAINTAINER=1 and SPECTRAL_REAL_TREE=/path/to/linux"] fn real_get_maintainer_fills_the_to_and_cc_lines() { assert_eq!( std::env::var("SPECTRAL_REAL_GETMAINTAINER").as_deref(), Ok("1"), "run this with SPECTRAL_REAL_GETMAINTAINER=1" ); let tree = std::env::var("SPECTRAL_REAL_TREE") .expect("set SPECTRAL_REAL_TREE to a kernel tree holding scripts/get_maintainer.pl"); let fixture = Fixture::kernel_tree(); let script = std::path::Path::new(&tree).join("scripts/get_maintainer.pl"); let body = std::fs::read_to_string(&script) .unwrap_or_else(|error| panic!("read {}: {error}", script.display())); fixture.write_script("scripts/get_maintainer.pl", &body); fixture.commit_all("fixture: use the real get_maintainer"); fixture.work_on_a_branch(); fixture.write("drivers/foo/bar.c", common::EDITED); fixture.commit_all("foo: return a + 1"); let created = fixture.cli(&["patch", "create", "000-foo"]); assert!( created.status.success(), "{}", String::from_utf8_lossy(&created.stderr) ); let patch = fixture.home().join(".spectral/patches/000-foo.patch"); let output = fixture.cli(&[ "patch", "submit", patch.to_str().expect("the patch path"), "--dry-run", ]); assert!( output.status.success(), "{}", String::from_utf8_lossy(&output.stderr) ); let stdout = String::from_utf8_lossy(&output.stdout); // The script's own words decide the split, so the assertion is about the // shape rather than about which kernel's MAINTAINERS matched. assert!( stdout.contains("To: Fixture Maintainer "), "{stdout}" ); assert!( stdout.lines().any(|line| line.starts_with("Cc: ")), "a reviewer and a second list belong on the Cc line: {stdout}" ); assert!(stdout.contains("Dry-OK"), "{stdout}"); }