cargo-fuzztest: Add integration tests and test fixture crate.

Add end-to-end integration test runner and dummy target crate for cargo-fuzztest.

PiperOrigin-RevId: 964278964
diff --git a/Cargo.lock b/Cargo.lock
index 01dc9bf..dbdb659 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -100,6 +100,7 @@
 dependencies = [
  "anyhow",
  "clap",
+ "fuzztest",
  "fuzztest-options",
  "googletest",
  "serde",
diff --git a/rust/cargo_fuzztest/BUILD b/rust/cargo_fuzztest/BUILD
index b7c52f1..a19e676 100644
--- a/rust/cargo_fuzztest/BUILD
+++ b/rust/cargo_fuzztest/BUILD
@@ -57,3 +57,31 @@
         ":cargo_fuzztest_bin",
     ],
 )
+
+rust_test(
+    name = "dummy_fuzz_test_bin",
+    srcs = ["test_crates/dummy_fuzz_crate/src/lib.rs"],
+    edition = "2024",
+    tags = [
+        "manual",
+        "notap",
+    ],
+    deps = [
+        "@com_google_fuzztest//rust:fuzztest",
+        "@crate_index//:googletest",
+    ],
+)
+
+rust_test(
+    name = "runner_test",
+    srcs = ["tests/runner_test.rs"],
+    data = [
+        ":dummy_fuzz_test_bin",
+    ],
+    edition = "2024",
+    deps = [
+        ":cargo_fuzztest",
+        "@crate_index//:anyhow",  # v1
+        "@crate_index//:googletest",
+    ],
+)
diff --git a/rust/cargo_fuzztest/Cargo.toml b/rust/cargo_fuzztest/Cargo.toml
index 9111901..e5727d9 100644
--- a/rust/cargo_fuzztest/Cargo.toml
+++ b/rust/cargo_fuzztest/Cargo.toml
@@ -26,3 +26,14 @@
 
 [dev-dependencies]
 googletest.workspace = true
+fuzztest = { path = ".." }
+
+# Compiled as a [[test]] target so Cargo builds it with the test harness enabled
+# (`rustc --test`) and exposes `CARGO_BIN_EXE_dummy_fuzz_test_bin` to `runner_test`.
+[[test]]
+name = "dummy_fuzz_test_bin"
+path = "test_crates/dummy_fuzz_crate/src/lib.rs"
+
+[[test]]
+name = "runner_test"
+path = "tests/runner_test.rs"
diff --git a/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/Cargo.toml b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/Cargo.toml
new file mode 100644
index 0000000..7ac26a8
--- /dev/null
+++ b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "dummy_fuzz_crate"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+fuzztest = { path = "../../.." }
diff --git a/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/src/lib.rs b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/src/lib.rs
new file mode 100644
index 0000000..0ad6df5
--- /dev/null
+++ b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/src/lib.rs
@@ -0,0 +1,7 @@
+use fuzztest::domains::arbitrary::Arbitrary;
+use fuzztest::fuzztest;
+
+#[fuzztest(data = Arbitrary::<i32>::default())]
+fn dummy_fuzztest_target(data: i32) {
+    let _ = data;
+}
diff --git a/rust/cargo_fuzztest/tests/runner_test.rs b/rust/cargo_fuzztest/tests/runner_test.rs
new file mode 100644
index 0000000..c34d630
--- /dev/null
+++ b/rust/cargo_fuzztest/tests/runner_test.rs
@@ -0,0 +1,77 @@
+use cargo_fuzztest::{CargoFuzzTestOptions, FuzztestRunner};
+use googletest::prelude::*;
+use std::env;
+use std::path::PathBuf;
+
+#[gtest]
+fn test_runner_execution() {
+    let binary_path = get_dummy_fuzz_test_bin_path();
+
+    assert!(binary_path.exists(), "Dummy fuzz binary does not exist at {}", binary_path.display());
+
+    let options = CargoFuzzTestOptions::default();
+
+    let runner = FuzztestRunner::new("sample-host-triple".to_string(), options);
+
+    let mut cmd = runner.build_run_command(&binary_path);
+
+    let status = cmd.status().expect("Failed to execute test binary command");
+
+    expect_true!(status.success());
+}
+
+#[gtest]
+fn test_runner_list_command() {
+    let binary_path = get_dummy_fuzz_test_bin_path();
+
+    assert!(binary_path.exists(), "Dummy fuzz binary does not exist at {}", binary_path.display());
+
+    let options = CargoFuzzTestOptions { list: true };
+
+    let runner = FuzztestRunner::new("sample-host-triple".to_string(), options);
+
+    let cmd = runner.build_run_command(&binary_path);
+
+    let args: Vec<String> = cmd.get_args().map(|a| a.to_string_lossy().to_string()).collect();
+    expect_eq!(args, &["__fuzztest_mod__", "--list"]);
+}
+
+fn get_dummy_fuzz_test_bin_path() -> PathBuf {
+    // 1. Cargo test: Check if CARGO_BIN_EXE_<name> is set
+    if let Ok(cargo_bin) = env::var("CARGO_BIN_EXE_dummy_fuzz_test_bin") {
+        return PathBuf::from(cargo_bin);
+    }
+
+    // 2. Bazel/Blaze test: Fall back to TEST_SRCDIR and TEST_WORKSPACE
+    if let Ok(src_dir) = env::var("TEST_SRCDIR") {
+        let test_workspace = env::var("TEST_WORKSPACE").unwrap_or_else(|_| {
+            "_main".to_string()
+        });
+
+        const RELATIVE_BINARY_PATH: &str =
+        "rust/cargo_fuzztest/dummy_fuzz_test_bin";
+
+        let blaze_path = PathBuf::from(src_dir).join(test_workspace).join(RELATIVE_BINARY_PATH);
+        if blaze_path.exists() {
+            return blaze_path;
+        }
+    }
+
+    // 2. Cargo test fallback: Query compiled test executable path via Cargo JSON compiler messages
+    if env::var("CARGO_MANIFEST_DIR").is_ok() {
+        let cargo_bin = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
+        let output = std::process::Command::new(cargo_bin)
+            .args(["test", "--no-run", "--message-format=json", "--test", "dummy_fuzz_test_bin"])
+            .output()
+            .expect("Failed to execute `cargo test --no-run --message-format=json` to locate test binary");
+
+        if output.status.success() {
+            let json_stdout = String::from_utf8_lossy(&output.stdout);
+            if let Ok(exe) = FuzztestRunner::parse_compiler_messages(&json_stdout) {
+                return exe;
+            }
+        }
+    }
+
+    panic!("Could not locate dummy_fuzz_test_bin via CARGO_BIN_EXE, TEST_SRCDIR, or Cargo compiler messages");
+}