//! Integration tests for the `reposhape` command. use std::fs; use assert_cmd::Command; use predicates::prelude::*; use tempfile::tempdir; fn cargo_command() -> Command { Command::cargo_bin("reposhape").expect("binary") } #[test] fn detects_multiple_ecosystems_and_grouped_sections_as_json() { let temp = tempdir().expect("tempdir"); fs::create_dir_all(temp.path().join("src")).expect("src"); fs::create_dir_all(temp.path().join(".github").join("workflows")).expect("workflows"); fs::create_dir_all(temp.path().join("cmd").join("server")).expect("go cmd"); fs::create_dir_all(temp.path().join("app")).expect("app"); fs::write(temp.path().join("Cargo.toml"), "[package]\nname=\"demo\"\n").expect("cargo"); fs::write(temp.path().join("src").join("main.rs"), "fn main() {}\n").expect("main"); fs::write( temp.path().join("package.json"), "{\"scripts\":{\"build\":\"tsc\",\"test\":\"vitest\"},\"main\":\"index.js\"}", ) .expect("package"); fs::write(temp.path().join("pnpm-lock.yaml"), "lockfileVersion: '9.0'").expect("lock"); fs::write( temp.path().join("pyproject.toml"), "[project]\nname=\"demo\"\n[project.scripts]\nserve=\"demo:main\"\n", ) .expect("pyproject"); fs::write(temp.path().join("requirements.txt"), "pytest\n").expect("requirements"); fs::write( temp.path().join("go.mod"), "module example.com/demo\n\ngo 1.22\n", ) .expect("go"); fs::write( temp.path().join("cmd").join("server").join("main.go"), "package main\nfunc main(){}\n", ) .expect("go main"); fs::write( temp.path().join("CMakeLists.txt"), "cmake_minimum_required(VERSION 3.20)\n", ) .expect("cmake"); fs::write( temp.path().join("Makefile"), "build:\n\t@echo build\ntest:\n\t@echo test\n", ) .expect("make"); fs::write( temp.path().join("demo.sln"), "Microsoft Visual Studio Solution File\n", ) .expect("sln"); fs::write( temp.path().join("app").join("demo.csproj"), "\n", ) .expect("csproj"); fs::write( temp.path().join(".github").join("workflows").join("ci.yml"), "name: ci\non: [push]\n", ) .expect("workflow"); let mut command = cargo_command(); command .arg("--json") .arg(temp.path()) .assert() .success() .stdout(predicate::str::contains("\"ecosystems\"")) .stdout(predicate::str::contains("\"manifests\"")) .stdout(predicate::str::contains("\"commands\"")) .stdout(predicate::str::contains("\"entrypoints\"")) .stdout(predicate::str::contains("\"ci\"")) .stdout(predicate::str::contains("\"name\":\"cargo\"")) .stdout(predicate::str::contains("\"name\":\"pnpm\"")) .stdout(predicate::str::contains("\"name\":\"python\"")) .stdout(predicate::str::contains("\"name\":\"dotnet\"")) .stdout(predicate::str::contains("\"name\":\"go\"")) .stdout(predicate::str::contains("\"name\":\"cmake\"")) .stdout(predicate::str::contains("\"name\":\"make\"")) .stdout(predicate::str::contains("\"provider\":\"github_actions\"")); } #[test] fn help_includes_grouped_output_language() { let mut command = cargo_command(); command .arg("--help") .assert() .success() .stdout(predicate::str::contains("--max-depth")) .stdout(predicate::str::contains("ecosystems")) .stdout(predicate::str::contains("reposhape")); } #[test] fn max_depth_limits_nested_package_detection() { let temp = tempdir().expect("tempdir"); fs::create_dir_all(temp.path().join("src")).expect("src"); fs::create_dir_all(temp.path().join("deep")).expect("deep"); fs::write(temp.path().join("Cargo.toml"), "[package]\nname=\"demo\"\n").expect("cargo"); fs::write(temp.path().join("src").join("main.rs"), "fn main() {}\n").expect("main"); fs::write( temp.path().join("deep").join("package.json"), "{\"scripts\":{\"build\":\"tsc\"}}", ) .expect("package"); let mut shallow = cargo_command(); shallow .arg("--json") .arg("--max-depth") .arg("1") .arg(temp.path()) .assert() .success() .stdout(predicate::str::contains("\"name\":\"cargo\"")) .stdout(predicate::str::contains("\"kind\":\"package_json\"").not()); let mut deep = cargo_command(); deep.arg("--json") .arg("--max-depth") .arg("4") .arg(temp.path()) .assert() .success() .stdout(predicate::str::contains("\"kind\":\"package_json\"")) .stdout(predicate::str::contains("deep")); } #[test] fn hidden_flag_controls_hidden_workspace_detection() { let temp = tempdir().expect("tempdir"); fs::create_dir_all(temp.path().join("src")).expect("src"); fs::create_dir_all(temp.path().join(".hidden")).expect("hidden"); fs::write(temp.path().join("Cargo.toml"), "[package]\nname=\"demo\"\n").expect("cargo"); fs::write(temp.path().join("src").join("main.rs"), "fn main() {}\n").expect("main"); fs::write( temp.path().join(".hidden").join("package.json"), "{\"scripts\":{\"test\":\"vitest\"}}", ) .expect("package"); let mut without_hidden = cargo_command(); without_hidden .arg("--json") .arg(temp.path()) .assert() .success() .stdout(predicate::str::contains("\"kind\":\"package_json\"").not()); let mut with_hidden = cargo_command(); with_hidden .arg("--json") .arg("--hidden") .arg(temp.path()) .assert() .success() .stdout(predicate::str::contains("\"kind\":\"package_json\"")) .stdout(predicate::str::contains("hidden")); } #[test] fn cli_surfaces_invalid_depth_and_missing_path_errors() { let mut invalid_depth = cargo_command(); invalid_depth .arg("--max-depth") .arg("nope") .assert() .failure() .stderr(predicate::str::contains("invalid --max-depth value")); let temp = tempdir().expect("tempdir"); let missing = temp.path().join("does-not-exist"); let mut missing_path = cargo_command(); missing_path .arg(missing) .assert() .failure() .stderr(predicate::str::contains("repository path does not exist")); }