mod common;
use common::*;
use std::fs;
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn test_full_package_workflow() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let package_dir = temp_dir.path().join("my-package");
fs::create_dir_all(&package_dir).unwrap();
create_test_package(&package_dir, "my-package", "1.0.0");
assert_file_exists(&package_dir.join("typst.toml"));
assert_file_exists(&package_dir.join("main.typ"));
let linked_path = temp_dir
.path()
.join("data/typst/packages/local/my-package/1.0.0");
utpm::utils::copy_dir_all(&package_dir, &linked_path).unwrap();
assert_dir_exists(&linked_path);
assert_file_exists(&linked_path.join("typst.toml"));
assert_file_exists(&linked_path.join("main.typ"));
fs::remove_dir_all(&linked_path).unwrap();
assert_not_exists(&linked_path);
cleanup_test_env();
}
#[test]
fn test_package_with_dependencies() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let manifest_content = r#"[package]
name = "dependent-pkg"
version = "1.0.0"
entrypoint = "main.typ"
authors = ["Test"]
license = "MIT"
description = "Package with dependencies"
[tool.utpm]
namespace = "local"
dependencies = [
"https://github.com/example/dep1.git",
"https://github.com/example/dep2.git"
]
"#;
let package_dir = temp_dir.path().join("package");
fs::create_dir_all(&package_dir).unwrap();
create_custom_manifest(&package_dir, manifest_content);
create_test_entrypoint(&package_dir);
let content = read_file_string(&package_dir.join("typst.toml"));
assert!(content.contains("dependencies"));
assert!(content.contains("dep1.git"));
assert!(content.contains("dep2.git"));
cleanup_test_env();
}
#[test]
fn test_version_bumping_workflow() {
let temp_dir = setup_temp_dir();
let package_dir = temp_dir.path().join("package");
fs::create_dir_all(&package_dir).unwrap();
create_test_manifest(&package_dir, "test-pkg", "1.0.0");
let manifest_path = package_dir.join("typst.toml");
let content = read_file_string(&manifest_path);
assert!(content.contains("version = \"1.0.0\""));
let new_content = content.replace("version = \"1.0.0\"", "version = \"1.0.1\"");
fs::write(&manifest_path, new_content).unwrap();
let updated = read_file_string(&manifest_path);
assert!(updated.contains("version = \"1.0.1\""));
assert!(!updated.contains("version = \"1.0.0\""));
}
#[test]
fn test_sync_updates_imports() {
let temp_dir = setup_temp_dir();
let typ_file = temp_dir.path().join("document.typ");
let content = r#"#import "@preview/example:1.0.0": *
#import "@preview/another:2.0.0"
#show: example.template
Some document content
"#;
fs::write(&typ_file, content).unwrap();
let file_content = read_file_string(&typ_file);
assert!(file_content.contains("@preview/example:1.0.0"));
assert!(file_content.contains("@preview/another:2.0.0"));
let updated_content = file_content
.replace("example:1.0.0", "example:1.1.0")
.replace("another:2.0.0", "another:2.1.0");
fs::write(&typ_file, updated_content).unwrap();
let synced = read_file_string(&typ_file);
assert!(synced.contains("@preview/example:1.1.0"));
assert!(synced.contains("@preview/another:2.1.0"));
}
#[test]
fn test_exclude_patterns_in_linking() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let package_dir = temp_dir.path().join("package");
fs::create_dir_all(&package_dir).unwrap();
let manifest_content = r#"[package]
name = "test"
version = "1.0.0"
entrypoint = "main.typ"
authors = ["Test"]
license = "MIT"
description = "Test"
[tool.utpm]
namespace = "local"
exclude = [
".git",
".github",
"*.md",
"tests/",
"*.log"
]
"#;
create_custom_manifest(&package_dir, manifest_content);
fs::write(package_dir.join("main.typ"), "main").unwrap();
fs::write(package_dir.join("README.md"), "readme").unwrap();
fs::write(package_dir.join("debug.log"), "log").unwrap();
fs::create_dir_all(package_dir.join("tests")).unwrap();
fs::write(package_dir.join("tests/test.typ"), "test").unwrap();
fs::create_dir_all(package_dir.join(".git")).unwrap();
fs::write(package_dir.join(".git/config"), "git").unwrap();
assert_file_exists(&package_dir.join("main.typ"));
assert_file_exists(&package_dir.join("README.md"));
assert_file_exists(&package_dir.join("debug.log"));
cleanup_test_env();
}
#[test]
fn test_multiple_namespaces() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let data_dir = temp_dir.path().join("data/typst/packages");
let cache_dir = temp_dir.path().join("cache/typst/packages");
let local_path = data_dir.join("local/pkg1/1.0.0");
fs::create_dir_all(&local_path).unwrap();
let preview_path = cache_dir.join("preview/pkg2/1.0.0");
fs::create_dir_all(&preview_path).unwrap();
assert_dir_exists(&local_path);
assert_dir_exists(&preview_path);
cleanup_test_env();
}
#[test]
fn test_package_validation() {
let temp_dir = setup_temp_dir();
let valid_manifest = r#"[package]
name = "valid-pkg"
version = "1.0.0"
entrypoint = "main.typ"
authors = ["Author"]
license = "MIT"
description = "Valid package"
"#;
create_custom_manifest(temp_dir.path(), valid_manifest);
let content = read_file_string(&temp_dir.path().join("typst.toml"));
assert!(content.contains("name"));
assert!(content.contains("version"));
assert!(content.contains("entrypoint"));
}
#[test]
fn test_dry_run_mode() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let package_dir = temp_dir.path().join("package");
fs::create_dir_all(&package_dir).unwrap();
create_test_package(&package_dir, "test", "1.0.0");
let data_dir = temp_dir.path().join("data/typst/packages/local/test/1.0.0");
assert_not_exists(&data_dir);
cleanup_test_env();
}
}
#[cfg(test)]
mod error_handling_tests {
use super::*;
#[test]
fn test_missing_manifest_error() {
let temp_dir = setup_temp_dir();
let manifest_path = temp_dir.path().join("typst.toml");
assert_not_exists(&manifest_path);
}
#[test]
fn test_invalid_version_format() {
let temp_dir = setup_temp_dir();
let invalid_manifest = r#"[package]
name = "test"
version = "invalid"
entrypoint = "main.typ"
"#;
let manifest_path = temp_dir.path().join("typst.toml");
fs::write(&manifest_path, invalid_manifest).unwrap();
}
#[test]
fn test_package_already_exists() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let existing = temp_dir
.path()
.join("data/typst/packages/local/existing/1.0.0");
fs::create_dir_all(&existing).unwrap();
fs::write(existing.join("typst.toml"), "test").unwrap();
assert_dir_exists(&existing);
cleanup_test_env();
}
#[test]
fn test_invalid_package_format() {
use utpm::regex_package;
let invalid_formats = vec![
"preview/package:1.0.0", "@preview/package", "@preview/package:v1.0", "package:1.0.0", "@/package:1.0.0", "@preview/:1.0.0", "@preview/package:1.0", "@preview/package-:1.0.0", ];
let re = regex_package();
for format in invalid_formats {
assert!(
!re.is_match(format),
"Format should be invalid but matched regex: {}",
format
);
}
}
}
#[cfg(test)]
mod performance_tests {
use super::*;
#[test]
fn test_list_many_packages() {
let temp_dir = setup_temp_dir();
setup_test_env(temp_dir.path());
let data_dir = temp_dir.path().join("data/typst/packages/local");
for i in 0..100 {
let pkg_path = data_dir.join(format!("package-{}/1.0.0", i));
fs::create_dir_all(&pkg_path).unwrap();
}
let count = fs::read_dir(&data_dir)
.unwrap()
.filter_map(|e| e.ok())
.count();
assert_eq!(count, 100);
cleanup_test_env();
}
#[test]
fn test_large_file_filtering() {
let temp_dir = setup_temp_dir();
for i in 0..1000 {
fs::write(temp_dir.path().join(format!("file-{}.typ", i)), "content").unwrap();
}
let count = fs::read_dir(temp_dir.path())
.unwrap()
.filter_map(|e| e.ok())
.count();
assert_eq!(count, 1000);
}
}