#![allow(dead_code)]
use {
super::{mock, registry_client::MockRegistryClient},
crate::{catalogs::CatalogsByName, cli::UpdateTarget, context::Context, registry_client::RegistryClient, visit_packages::visit_packages},
serde_json::{json, Value},
std::sync::Arc,
};
pub struct TestBuilder {
catalogs: Option<Value>,
config: Value,
dependency_groups: Vec<Value>,
packages: Vec<Value>,
registry_updates: Option<Value>,
semver_groups: Vec<Value>,
strict: Option<bool>,
update_target: Option<UpdateTarget>,
version_groups: Vec<Value>,
}
impl TestBuilder {
pub fn new() -> Self {
Self {
catalogs: None,
config: json!({}),
dependency_groups: vec![],
packages: vec![],
registry_updates: None,
semver_groups: vec![],
strict: None,
update_target: None,
version_groups: vec![],
}
}
pub fn with_catalogs(mut self, catalogs: Value) -> Self {
self.catalogs = Some(catalogs);
self
}
pub fn with_package(mut self, package: Value) -> Self {
self.packages.push(package);
self
}
pub fn with_packages(mut self, packages: Vec<Value>) -> Self {
self.packages.extend(packages);
self
}
pub fn with_version_group(mut self, group: Value) -> Self {
self.version_groups.push(group);
self
}
pub fn with_version_groups(mut self, groups: Vec<Value>) -> Self {
self.version_groups.extend(groups);
self
}
pub fn with_semver_group(mut self, group: Value) -> Self {
self.semver_groups.push(group);
self
}
pub fn with_strict(mut self, strict: bool) -> Self {
self.strict = Some(strict);
self
}
pub fn with_update_target(mut self, target: UpdateTarget) -> Self {
self.update_target = Some(target);
self
}
pub fn with_registry_updates(mut self, updates: Value) -> Self {
self.registry_updates = Some(updates);
self
}
pub fn with_config(mut self, config: Value) -> Self {
self.config = config;
self
}
fn build_config(&self) -> Value {
let mut config = self.config.clone();
if !self.version_groups.is_empty() {
config["versionGroups"] = Value::Array(self.version_groups.clone());
}
if !self.semver_groups.is_empty() {
config["semverGroups"] = Value::Array(self.semver_groups.clone());
}
if !self.dependency_groups.is_empty() {
config["dependencyGroups"] = Value::Array(self.dependency_groups.clone());
}
if let Some(strict) = self.strict {
config["strict"] = Value::Bool(strict);
}
config
}
pub fn build(self) -> Context {
let mut config = mock::config_from_mock(self.build_config());
let registry_client = self.create_registry_client();
let catalogs = self.create_catalogs();
let packages = mock::packages_from_mocks(self.packages);
if let Some(target) = self.update_target {
match target {
UpdateTarget::Latest => config.cli.target = UpdateTarget::Latest,
UpdateTarget::Minor => config.cli.target = UpdateTarget::Minor,
UpdateTarget::Patch => config.cli.target = UpdateTarget::Patch,
}
}
Context::create(config, packages, registry_client, catalogs)
}
pub fn build_and_visit_packages(self) -> Context {
let ctx = self.build();
visit_packages(ctx)
}
pub async fn build_with_registry_and_visit(self) -> Context {
let mut config = mock::config_from_mock(self.build_config());
let catalogs = self.create_catalogs();
let packages = mock::packages_from_mocks(self.packages);
if let Some(target) = self.update_target {
match target {
UpdateTarget::Latest => config.cli.target = UpdateTarget::Latest,
UpdateTarget::Minor => config.cli.target = UpdateTarget::Minor,
UpdateTarget::Patch => config.cli.target = UpdateTarget::Patch,
}
}
let ctx = if let Some(updates) = self.registry_updates {
mock::context_with_registry_updates(config, packages, updates, catalogs).await
} else {
let registry_client = None;
Context::create(config, packages, registry_client, catalogs)
};
visit_packages(ctx)
}
fn create_registry_client(&self) -> Option<Arc<dyn RegistryClient>> {
self
.registry_updates
.as_ref()
.map(|updates| Arc::new(MockRegistryClient::from_json(updates.clone())) as Arc<dyn RegistryClient>)
}
fn create_catalogs(&self) -> Option<CatalogsByName> {
self.catalogs.as_ref().map(|catalogs| mock::catalogs_from_mocks(catalogs.clone()))
}
}
impl Default for TestBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::{
instance_state::{InstanceState, ValidInstance::*},
test::expect::{expect, ExpectedInstance},
},
};
#[test]
fn test_builder_basic_usage() {
let ctx = TestBuilder::new()
.with_package(json!({
"name": "package-a",
"version": "1.0.0"
}))
.build_and_visit_packages();
expect(&ctx).to_have_instances(vec![ExpectedInstance {
state: InstanceState::valid(IsLocalAndValid),
dependency_name: "package-a",
id: "package-a in /version of package-a",
actual: "1.0.0",
expected: Some("1.0.0"),
overridden: None,
}]);
}
#[test]
fn test_builder_with_version_group() {
let ctx = TestBuilder::new()
.with_package(json!({
"name": "package-a",
"version": "1.0.0",
"dependencies": {"foo": "1.0.0"}
}))
.with_version_group(json!({
"dependencies": ["foo"],
"pinVersion": "2.0.0"
}))
.build_and_visit_packages();
assert!(ctx.instances.len() > 1);
}
#[test]
fn test_builder_with_multiple_packages() {
let ctx = TestBuilder::new()
.with_packages(vec![
json!({"name": "package-a", "version": "1.0.0"}),
json!({"name": "package-b", "version": "2.0.0"}),
])
.build_and_visit_packages();
assert_eq!(ctx.instances.len(), 2);
}
#[test]
fn test_builder_with_strict_mode() {
let ctx = TestBuilder::new()
.with_package(json!({
"name": "package-a",
"version": "1.0.0",
"dependencies": {"package-a": "workspace:*"}
}))
.with_strict(true)
.build_and_visit_packages();
assert!(ctx.instances.iter().any(|i| i.state.borrow().is_invalid()));
}
#[tokio::test]
async fn test_builder_with_registry_updates() {
let ctx = TestBuilder::new()
.with_package(json!({
"name": "package-a",
"dependencies": {"foo": "1.0.0"}
}))
.with_registry_updates(json!({"foo": ["1.0.0", "2.0.0"]}))
.build_with_registry_and_visit()
.await;
assert!(ctx.instances.iter().any(|i| i.state.borrow().is_outdated()));
}
#[tokio::test]
async fn test_builder_with_update_target() {
use crate::cli::UpdateTarget;
let ctx = TestBuilder::new()
.with_package(json!({
"name": "package-a",
"dependencies": {"foo": "1.0.0"}
}))
.with_update_target(UpdateTarget::Minor)
.with_registry_updates(json!({"foo": ["1.0.0", "1.1.0", "2.0.0"]}))
.build_with_registry_and_visit()
.await;
let foo_instance = ctx.instances.iter().find(|i| i.descriptor.internal_name == "foo").unwrap();
assert_eq!(foo_instance.expected_specifier.borrow().as_ref().unwrap().get_raw(), "1.1.0");
}
}