use std::fs;
use std::path::PathBuf;
use standard_version::{CustomVersionFile, update_version_files};
fn custom(path: &str, pattern: &str) -> CustomVersionFile {
CustomVersionFile {
path: PathBuf::from(path),
pattern: pattern.to_string(),
}
}
#[test]
fn bump_version_file() {
let dir = tempfile::tempdir().unwrap();
let version = dir.path().join("VERSION");
fs::write(&version, "1.0.0\n").unwrap();
let results = update_version_files(dir.path(), "2.0.0", &[]).unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, "VERSION");
assert_eq!(results[0].old_version, "1.0.0");
assert_eq!(results[0].new_version, "2.0.0");
let on_disk = fs::read_to_string(&version).unwrap();
assert_eq!(on_disk, "2.0.0\n");
}
#[test]
fn bump_custom_regex_file() {
let dir = tempfile::tempdir().unwrap();
let pom = dir.path().join("pom.xml");
fs::write(
&pom,
r#"<?xml version="1.0"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0</version>
</project>
"#,
)
.unwrap();
let custom_files = vec![custom(
"pom.xml",
r"<artifactId>my-app</artifactId>\s*<version>([^<]+)</version>",
)];
let results = update_version_files(dir.path(), "2.0.0", &custom_files).unwrap();
let pom_result = results.iter().find(|r| r.name == "pom.xml").unwrap();
assert_eq!(pom_result.old_version, "1.0.0");
assert_eq!(pom_result.new_version, "2.0.0");
let on_disk = fs::read_to_string(&pom).unwrap();
assert!(on_disk.contains("<version>2.0.0</version>"));
assert!(on_disk.contains("<modelVersion>4.0.0</modelVersion>"));
}
#[test]
fn bump_invalid_regex_no_capture_group() {
let dir = tempfile::tempdir().unwrap();
let txt = dir.path().join("version.txt");
fs::write(&txt, "version = 1.0.0\n").unwrap();
let custom_files = vec![custom("version.txt", r"version = \d+\.\d+\.\d+")];
let result = update_version_files(dir.path(), "2.0.0", &custom_files);
assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(
err.contains("capture group"),
"expected capture group error, got: {err}"
);
}
#[test]
fn bump_missing_files_skipped() {
let dir = tempfile::tempdir().unwrap();
let custom_files = vec![custom("nonexistent.xml", r"<version>([^<]+)</version>")];
let results = update_version_files(dir.path(), "2.0.0", &custom_files).unwrap();
assert!(
results.is_empty(),
"missing files should be skipped, got {} results",
results.len()
);
}
#[test]
fn bump_files_without_version_skipped() {
let dir = tempfile::tempdir().unwrap();
fs::write(
dir.path().join("package.json"),
r#"{
"name": "my-app",
"main": "index.js"
}"#,
)
.unwrap();
fs::write(
dir.path().join("Cargo.toml"),
"[dependencies]\nfoo = \"1\"\n",
)
.unwrap();
let results = update_version_files(dir.path(), "2.0.0", &[]).unwrap();
assert!(
results.is_empty(),
"files without version fields should be skipped, got {} results",
results.len()
);
}
#[test]
fn bump_all_ecosystems() {
let dir = tempfile::tempdir().unwrap();
fs::write(
dir.path().join("Cargo.toml"),
r#"[package]
name = "my-app"
version = "1.0.0"
edition = "2021"
"#,
)
.unwrap();
fs::write(
dir.path().join("package.json"),
r#"{
"name": "my-app",
"version": "1.0.0",
"main": "index.js"
}"#,
)
.unwrap();
fs::write(
dir.path().join("deno.json"),
r#"{
"version": "1.0.0",
"tasks": { "dev": "deno run main.ts" }
}"#,
)
.unwrap();
fs::write(
dir.path().join("pyproject.toml"),
r#"[project]
name = "my-app"
version = "1.0.0"
requires-python = ">=3.8"
"#,
)
.unwrap();
fs::write(
dir.path().join("pubspec.yaml"),
"name: my_app\nversion: 1.0.0\ndescription: A Flutter app\n",
)
.unwrap();
fs::write(
dir.path().join("gradle.properties"),
"VERSION_NAME=1.0.0\nVERSION_CODE=10\n",
)
.unwrap();
fs::write(dir.path().join("VERSION"), "1.0.0\n").unwrap();
fs::write(
dir.path().join("pom.xml"),
"<project>\n <version>1.0.0</version>\n</project>\n",
)
.unwrap();
let custom_files = vec![custom("pom.xml", r"<version>([^<]+)</version>")];
let results = update_version_files(dir.path(), "2.0.0", &custom_files).unwrap();
assert_eq!(
results.len(),
8,
"expected 8 updated files, got {}: {:?}",
results.len(),
results.iter().map(|r| &r.name).collect::<Vec<_>>()
);
let names: Vec<&str> = results.iter().map(|r| r.name.as_str()).collect();
assert!(names.contains(&"Cargo.toml"));
assert!(names.contains(&"pyproject.toml"));
assert!(names.contains(&"package.json"));
assert!(names.contains(&"deno.json"));
assert!(names.contains(&"pubspec.yaml"));
assert!(names.contains(&"gradle.properties"));
assert!(names.contains(&"VERSION"));
assert!(names.contains(&"pom.xml"));
let cargo_disk = fs::read_to_string(dir.path().join("Cargo.toml")).unwrap();
assert!(cargo_disk.contains(r#"version = "2.0.0""#));
let pkg_disk = fs::read_to_string(dir.path().join("package.json")).unwrap();
assert!(pkg_disk.contains(r#""version": "2.0.0""#));
let pyproject_disk = fs::read_to_string(dir.path().join("pyproject.toml")).unwrap();
assert!(pyproject_disk.contains(r#"version = "2.0.0""#));
let deno_disk = fs::read_to_string(dir.path().join("deno.json")).unwrap();
assert!(deno_disk.contains(r#""version": "2.0.0""#));
let pubspec_disk = fs::read_to_string(dir.path().join("pubspec.yaml")).unwrap();
assert!(pubspec_disk.contains("version: 2.0.0"));
let gradle_disk = fs::read_to_string(dir.path().join("gradle.properties")).unwrap();
assert!(gradle_disk.contains("VERSION_NAME=2.0.0"));
assert!(gradle_disk.contains("VERSION_CODE=11"));
let version_disk = fs::read_to_string(dir.path().join("VERSION")).unwrap();
assert_eq!(version_disk, "2.0.0\n");
let pom_disk = fs::read_to_string(dir.path().join("pom.xml")).unwrap();
assert!(pom_disk.contains("<version>2.0.0</version>"));
}