mod common;
use common::{
assertions::*,
create_temp_dir, fixture_path,
fixtures::{
MonorepoFixtureBuilder, PackageJsonBuilder, create_basic_monorepo_fixture,
create_single_package_fixture,
},
fixtures_dir,
generators::*,
mocks::{filesystem::MockFileSystem, git::MockGitRepository, registry::MockRegistry},
};
use proptest::prelude::*;
#[test]
fn test_fixtures_directory_exists() {
let dir = fixtures_dir();
assert_path_exists(&dir);
assert_is_dir(&dir);
}
#[test]
fn test_fixture_paths() {
let monorepo_path = fixture_path("monorepo");
assert_path_exists(&monorepo_path);
assert_is_dir(&monorepo_path);
let single_path = fixture_path("single-package");
assert_path_exists(&single_path);
assert_is_dir(&single_path);
}
#[test]
fn test_temp_dir_creation() {
let temp = create_temp_dir().unwrap();
assert_path_exists(temp.path());
assert_is_dir(temp.path());
}
#[tokio::test]
async fn test_mock_filesystem_operations() {
let fs = MockFileSystem::new();
let path = std::path::Path::new("/test/file.txt");
fs.write_file_string(path, "test content").await.unwrap();
let content = fs.read_file_string(path).await.unwrap();
assert_eq!(content, "test content");
assert!(fs.exists(path).await);
assert!(fs.is_file(path));
let dir = std::path::Path::new("/test");
assert!(fs.is_dir(dir));
}
#[tokio::test]
async fn test_mock_filesystem_with_package_json() {
let fs = MockFileSystem::new();
let package_json = PackageJsonBuilder::new("test-package")
.version("1.2.3")
.description("Test package for infrastructure")
.add_dependency("react", "^18.0.0")
.add_dev_dependency("jest", "^29.0.0")
.build();
let path = std::path::Path::new("/package.json");
fs.write_file_string(path, &package_json).await.unwrap();
let content = fs.read_file_string(path).await.unwrap();
assert_contains(&content, r#""name": "test-package""#);
assert_contains(&content, r#""version": "1.2.3""#);
assert_json_field(&content, "name", "test-package");
assert_json_field(&content, "version", "1.2.3");
}
#[test]
fn test_mock_git_repository() {
let repo = MockGitRepository::new("/repo");
repo.add_commit(
"abc123",
"feat: add new feature",
vec![std::path::PathBuf::from("/src/feature.js")],
);
repo.add_commit("def456", "fix: fix bug", vec![std::path::PathBuf::from("/src/bug.js")]);
let commits = repo.get_commits();
assert_eq!(commits.len(), 2);
assert_eq!(commits[0].hash, "abc123");
assert_eq!(commits[1].hash, "def456");
repo.add_branch("develop", "def456");
let branches = repo.get_branches();
assert!(branches.contains_key("develop"));
repo.add_tag("v1.0.0", "def456");
let tags = repo.get_tags();
assert_eq!(tags.get("v1.0.0"), Some(&"def456".to_string()));
}
#[test]
fn test_mock_git_commit_builder() {
use common::mocks::git::MockCommit;
let commit = MockCommit::builder("abc123")
.message("feat(api): add new endpoint")
.author("John Doe")
.author_email("john@example.com")
.add_file("/src/api/endpoint.js")
.add_file("/src/api/types.ts")
.lines_added(50)
.lines_deleted(10)
.build();
assert_eq!(commit.hash, "abc123");
assert_eq!(commit.message, "feat(api): add new endpoint");
assert_eq!(commit.author, "John Doe");
assert_eq!(commit.files_changed.len(), 2);
assert_eq!(commit.lines_added, 50);
assert_eq!(commit.lines_deleted, 10);
}
#[test]
fn test_mock_registry() {
let registry = MockRegistry::new();
registry.add_package("react", vec!["18.0.0", "18.1.0", "18.2.0"]);
registry.add_package("vue", vec!["3.0.0", "3.1.0", "3.2.0"]);
let react = registry.get_package("react");
assert!(react.is_some());
let react_metadata = react.unwrap();
assert_eq!(react_metadata.name, "react");
assert_eq!(react_metadata.versions.len(), 3);
let latest = registry.get_latest_version("react");
assert_eq!(latest, Some("18.2.0".to_string()));
assert_eq!(registry.package_count(), 2);
}
#[test]
fn test_mock_registry_deprecation() {
let registry = MockRegistry::new();
registry.add_package("old-package", vec!["1.0.0", "2.0.0"]);
registry.deprecate_package("old-package", "Use new-package instead");
let metadata = registry.get_package("old-package").unwrap();
assert!(metadata.deprecated.is_some());
assert_contains(&metadata.deprecated.unwrap(), "new-package");
registry.deprecate_version("old-package", "1.0.0", "Use 2.0.0");
let metadata = registry.get_package("old-package").unwrap();
let version_metadata = metadata.versions.get("1.0.0").unwrap();
assert!(version_metadata.deprecated.is_some());
}
#[test]
fn test_package_json_builder() {
let json = PackageJsonBuilder::new("my-package")
.version("2.3.4")
.description("A test package")
.add_dependency("lodash", "^4.17.21")
.add_dependency("axios", "^1.4.0")
.add_dev_dependency("jest", "^29.0.0")
.add_script("test", "jest")
.add_script("build", "tsc")
.build();
assert_json_field(&json, "name", "my-package");
assert_json_field(&json, "version", "2.3.4");
assert_contains(&json, "lodash");
assert_contains(&json, "jest");
assert_contains(&json, r#""scripts""#);
}
#[test]
fn test_monorepo_fixture_builder() {
let fixture = MonorepoFixtureBuilder::new("test-monorepo")
.workspace_patterns(vec!["packages/*".to_string()])
.add_package("packages/pkg1", "pkg1", "1.0.0")
.add_package("packages/pkg2", "pkg2", "2.0.0")
.build();
assert_eq!(fixture.root_name, "test-monorepo");
assert_eq!(fixture.packages.len(), 2);
let files = fixture.generate_files();
assert!(files.contains_key(&std::path::PathBuf::from("package.json")));
assert!(files.contains_key(&std::path::PathBuf::from("packages/pkg1/package.json")));
assert!(files.contains_key(&std::path::PathBuf::from("packages/pkg2/package.json")));
}
#[test]
fn test_create_basic_monorepo_fixture() {
let fixture = create_basic_monorepo_fixture();
assert_eq!(fixture.packages.len(), 2);
let files = fixture.generate_files();
assert_not_empty(&files.keys().collect::<Vec<_>>());
}
#[test]
fn test_create_single_package_fixture() {
let files = create_single_package_fixture("test-pkg", "1.0.0");
assert_len(&files.keys().collect::<Vec<_>>(), 2);
assert!(files.contains_key(&std::path::PathBuf::from("package.json")));
assert!(files.contains_key(&std::path::PathBuf::from("index.js")));
}
#[test]
fn test_version_assertions() {
assert_version_eq("1.2.3", "1.2.3");
assert_version_gt("1.2.3", "1.2.2");
assert_version_gte("1.2.3", "1.2.3");
assert_version_gte("1.2.3", "1.2.2");
}
#[test]
fn test_string_assertions() {
let text = "Hello, world!";
assert_contains(text, "world");
assert_not_contains(text, "goodbye");
}
#[test]
fn test_collection_assertions() {
let vec = vec![1, 2, 3];
assert_len(&vec, 3);
assert_not_empty(&vec);
let empty_vec: Vec<i32> = vec![];
assert_empty(&empty_vec);
}
proptest! {
#[test]
fn prop_test_semver_generation(version in semver_strategy()) {
let result = semver::Version::parse(&version);
prop_assert!(result.is_ok(), "Generated invalid version: {}", version);
}
#[test]
fn prop_test_package_names(name in package_name_strategy()) {
prop_assert!(!name.is_empty());
prop_assert!(name.len() >= 3);
prop_assert_eq!(name.to_lowercase(), name);
}
#[test]
fn prop_test_conventional_commits(message in conventional_commit_strategy()) {
prop_assert!(message.contains(':'));
let types = ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert"];
let starts_with_type = types.iter().any(|t| message.starts_with(t));
prop_assert!(starts_with_type, "Invalid commit type in: {}", message);
}
#[test]
fn prop_test_commit_hashes(hash in commit_hash_strategy()) {
prop_assert_eq!(hash.len(), 40);
prop_assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
}
#[test]
fn prop_test_version_specs(spec in version_spec_strategy()) {
let prefixes = ["^", "~", ">=", "<=", "="];
let has_prefix = prefixes.iter().any(|p| spec.starts_with(p));
prop_assert!(has_prefix, "Invalid version spec: {}", spec);
}
#[test]
fn prop_test_author_emails(email in author_email_strategy()) {
prop_assert!(email.contains('@'));
prop_assert!(email.contains('.'));
let parts: Vec<&str> = email.split('@').collect();
prop_assert_eq!(parts.len(), 2);
}
}
#[tokio::test]
async fn test_integration_mocks() {
let fs = MockFileSystem::new();
let package_json = PackageJsonBuilder::new("integration-test")
.version("1.0.0")
.add_dependency("react", "^18.0.0")
.build();
fs.write_file_string(std::path::Path::new("/package.json"), &package_json).await.unwrap();
let repo = MockGitRepository::new("/repo");
repo.add_commit("abc123", "feat: initial commit", vec![]);
repo.add_commit("def456", "fix: bug fix", vec![]);
let registry = MockRegistry::new();
registry.add_package("react", vec!["18.0.0", "18.2.0"]);
assert!(fs.exists(std::path::Path::new("/package.json")).await);
assert_eq!(repo.commit_count(), 2);
assert_eq!(registry.package_count(), 1);
let latest_react = registry.get_latest_version("react");
assert_eq!(latest_react, Some("18.2.0".to_string()));
}
#[test]
fn test_fixture_write_to_temp() {
let temp = create_temp_dir().unwrap();
let fixture = create_basic_monorepo_fixture();
fixture.write_to_dir(temp.path()).unwrap();
let root_package = temp.path().join("package.json");
assert_path_exists(&root_package);
assert_is_file(&root_package);
let pkg1 = temp.path().join("packages/pkg-a/package.json");
assert_path_exists(&pkg1);
assert_is_file(&pkg1);
}
#[tokio::test]
async fn test_mock_filesystem_with_files() {
use std::collections::HashMap;
use std::path::PathBuf;
let mut files = HashMap::new();
files.insert(PathBuf::from("/test1.txt"), "content1".to_string());
files.insert(PathBuf::from("/test2.txt"), "content2".to_string());
files.insert(PathBuf::from("/dir/test3.txt"), "content3".to_string());
let fs = MockFileSystem::with_files(files);
assert_eq!(fs.list_files().len(), 3);
let content1 = fs.read_file_string(std::path::Path::new("/test1.txt")).await.unwrap();
assert_eq!(content1, "content1");
}