use crate::common::{ManifestBuilder, TestProject};
use anyhow::Result;
#[tokio::test]
async fn test_explicit_version_specs_prevent_conflicts() -> Result<()> {
let project = TestProject::new().await?;
let repo = project.create_source_repo("community").await?;
repo.add_resource(
"agents",
"resource-c",
r#"---
name: Resource C
---
# Resource C
This is resource C at v1.0.0.
"#,
)
.await?;
repo.add_resource(
"agents",
"resource-b",
r#"---
name: Resource B
dependencies:
agents:
- path: ./resource-c.md
version: v1.0.0
---
# Resource B
This is resource B at v1.0.0, depending on C at v1.0.0.
"#,
)
.await?;
repo.add_resource(
"agents",
"resource-d",
r#"---
name: Resource D
dependencies:
agents:
- path: ./resource-c.md
version: v1.0.0
---
# Resource D
This is resource D at v1.0.0, depending on C at v1.0.0.
"#,
)
.await?;
repo.add_resource(
"agents",
"resource-a",
r#"---
name: Resource A
dependencies:
agents:
- path: ./resource-b.md
version: v1.0.0
---
# Resource A
This is resource A at v1.0.0, depending on B at v1.0.0.
"#,
)
.await?;
repo.commit_all("Add all resources")?;
repo.tag_version("v1.0.0")?;
let repo_url = repo.bare_file_url(project.sources_path()).await?;
let manifest = ManifestBuilder::new()
.add_source("community", &repo_url)
.add_standard_agent("resource-a", "community", "agents/resource-a.md")
.add_standard_agent("resource-d", "community", "agents/resource-d.md")
.add_standard_agent("resource-c", "community", "agents/resource-c.md")
.build();
project.write_manifest(&manifest).await?;
let output = project.run_agpm(&["install"])?;
assert!(
output.success,
"Install should succeed with no conflicts. stderr: {}\nstdout: {}",
output.stderr, output.stdout
);
let lockfile = project.load_lockfile()?;
assert_eq!(lockfile.agents.len(), 4, "Should have exactly 4 agents in lockfile");
let resource_a = lockfile
.agents
.iter()
.find(|a| a.name == "agents/resource-a")
.expect("Resource A should be in lockfile");
let resource_b = lockfile
.agents
.iter()
.find(|a| a.name == "agents/resource-b")
.expect("Resource B should be in lockfile");
let resource_c = lockfile
.agents
.iter()
.find(|a| a.name == "agents/resource-c")
.expect("Resource C should be in lockfile");
let resource_d = lockfile
.agents
.iter()
.find(|a| a.name == "agents/resource-d")
.expect("Resource D should be in lockfile");
assert_eq!(resource_a.version, Some("v1.0.0".to_string()));
assert_eq!(resource_b.version, Some("v1.0.0".to_string()));
assert_eq!(resource_c.version, Some("v1.0.0".to_string()));
assert_eq!(resource_d.version, Some("v1.0.0".to_string()));
assert_eq!(
resource_c.manifest_alias,
Some("resource-c".to_string()),
"Resource C should have manifest_alias since it's a direct dependency"
);
assert_eq!(
resource_b.manifest_alias, None,
"Resource B should not have manifest_alias since it's transitive"
);
assert_eq!(
resource_a.source,
Some("community".to_string()),
"Resource A should be from community"
);
assert_eq!(
resource_b.source,
Some("community".to_string()),
"Resource B should be from community"
);
assert_eq!(
resource_c.source,
Some("community".to_string()),
"Resource C should be from community"
);
assert_eq!(
resource_d.source,
Some("community".to_string()),
"Resource D should be from community"
);
assert!(
resource_c.resolved_commit.as_ref().map(|c| !c.is_empty()).unwrap_or(false),
"Resource C should have a resolved commit"
);
assert_eq!(
resource_a.resolved_commit, resource_b.resolved_commit,
"Resources A and B should have same commit"
);
assert_eq!(
resource_b.resolved_commit, resource_c.resolved_commit,
"Resources B and C should have same commit"
);
assert_eq!(
resource_c.resolved_commit, resource_d.resolved_commit,
"Resources C and D should have same commit"
);
let c_count = lockfile.agents.iter().filter(|a| a.name == "agents/resource-c").count();
assert_eq!(c_count, 1, "Should have exactly one entry for resource C");
Ok(())
}