use assert_cmd::Command;
use assert_fs::prelude::*;
use assert_fs::TempDir;
use chicago_tdd_tools::prelude::*;
use chicago_tdd_tools::test;
use predicates::prelude::*;
test!(test_template_generate_integration, {
let temp = TempDir::new().unwrap();
let template_file = temp.child("template.yaml");
let output_dir = temp.child("output");
template_file
.write_str(
r#"name: test-service
description: Test template
variables:
service_name:
required: true
default: my-service
nodes:
- name: "{{service_name}}"
type: directory
children:
- name: main.rs
type: file
content: |
fn main() {
println!("{{service_name}}");
}
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("ggen").unwrap();
cmd.args([
"template",
"generate",
template_file.path().to_str().unwrap(),
output_dir.path().to_str().unwrap(),
])
.assert()
.success();
let main_file = output_dir.child("my-service/main.rs");
main_file.assert(predicate::path::exists());
main_file.assert(predicate::str::contains("my-service"));
});
test!(test_marketplace_search_integration, {
let mut cmd = Command::cargo_bin("ggen").unwrap();
let output = cmd
.args(["marketplace", "search", "rust", "--limit", "5"])
.output()
.unwrap();
assert!(output.status.success() || output.status.code() == Some(0));
});
#[ignore = "project gen command not fully implemented"]
test!(test_project_gen_integration, {
let temp = TempDir::new().unwrap();
let project_dir = temp.child("my-project");
let mut cmd = Command::cargo_bin("ggen").unwrap();
let output = cmd
.args([
"project",
"gen",
"--name",
"my-project",
"--template",
"rust-cli",
"--output",
project_dir.path().to_str().unwrap(),
])
.output()
.unwrap();
assert!(output.status.success() || project_dir.path().exists());
});
#[ignore = "lifecycle run command not fully implemented"]
test!(test_lifecycle_execution_integration, {
let temp = TempDir::new().unwrap();
let make_file = temp.child("make.toml");
make_file
.write_str(
r#"[project]
name = "test-project"
version = "1.0.0"
[[phases]]
name = "init"
description = "Initialize project"
commands = ["echo 'Initializing...'"]
[[phases]]
name = "build"
description = "Build project"
depends_on = ["init"]
commands = ["echo 'Building...'"]
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("ggen").unwrap();
let output = cmd
.args([
"lifecycle",
"run",
"build",
"--manifest",
make_file.path().to_str().unwrap(),
])
.output()
.unwrap();
assert!(output.status.success());
});
test!(test_error_propagation_invalid_template, {
let temp = TempDir::new().unwrap();
let invalid_template = temp.child("invalid.yaml");
invalid_template
.write_str("invalid: yaml: content:")
.unwrap();
let mut cmd = Command::cargo_bin("ggen").unwrap();
cmd.args([
"template",
"generate",
invalid_template.path().to_str().unwrap(),
"/tmp/output",
])
.assert()
.failure();
});
test!(test_error_propagation_missing_file, {
let mut cmd = Command::cargo_bin("ggen").unwrap();
cmd.args([
"template",
"generate",
"/nonexistent/template.yaml",
"/tmp/output",
])
.assert()
.failure();
});
test!(test_error_propagation_invalid_command, {
let mut cmd = Command::cargo_bin("ggen").unwrap();
cmd.args(["invalid-command"])
.assert()
.failure()
.stderr(predicate::str::contains("error").or(predicate::str::contains("unrecognized")));
});
test!(test_error_propagation_missing_required_var, {
let temp = TempDir::new().unwrap();
let template_file = temp.child("template.yaml");
template_file
.write_str(
r#"
name: "test"
variables:
- name: required_var
required: true
nodes:
- name: "test.txt"
type: file
content: "{{required_var}}"
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("ggen").unwrap();
cmd.args([
"template",
"generate",
template_file.path().to_str().unwrap(),
"/tmp/output",
])
.assert()
.failure();
});
test!(test_json_output_marketplace_search, {
let mut cmd = Command::cargo_bin("ggen").unwrap();
let output = cmd
.args(["marketplace", "search", "rust", "--json", "--limit", "1"])
.output()
.unwrap();
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.is_empty() && stdout.trim() != "{}" && !stdout.starts_with("Error") {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&stdout) {
assert!(json.is_object() || json.is_array());
}
}
}
});
test!(test_json_output_project_info, {
let temp = TempDir::new().unwrap();
let project_file = temp.child("project.toml");
project_file
.write_str(
r#"
[project]
name = "test-project"
version = "1.0.0"
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("ggen").unwrap();
let output = cmd
.args([
"project",
"info",
"--manifest",
project_file.path().to_str().unwrap(),
"--json",
])
.output()
.unwrap();
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.is_empty() {
let json: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert!(json.is_object());
}
}
});
test!(test_workflow_template_to_lifecycle, {
let temp = TempDir::new().unwrap();
let template_file = temp.child("template.yaml");
let output_dir = temp.child("project");
template_file
.write_str(
r#"name: lifecycle-project
description: Project with lifecycle
variables:
project_name:
required: true
default: test-project
nodes:
- name: "{{project_name}}"
type: directory
children:
- name: make.toml
type: file
content: |
[project]
name = "{{project_name}}"
[[phases]]
name = "build"
commands = ["echo 'Building...'"]
"#,
)
.unwrap();
let result = Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate",
template_file.path().to_str().unwrap(),
output_dir.path().to_str().unwrap(),
])
.output()
.unwrap();
if result.status.success() {
let make_file = output_dir.child("test-project/make.toml");
if make_file.path().exists() {
Command::cargo_bin("ggen")
.unwrap()
.args([
"lifecycle",
"run",
"build",
"--manifest",
make_file.path().to_str().unwrap(),
])
.assert()
.success();
}
}
});
test!(test_workflow_marketplace_to_project, {
let mut cmd = Command::cargo_bin("ggen").unwrap();
cmd.args(["marketplace", "search", "cli-template", "--limit", "1"])
.assert()
.success();
});
test!(test_workflow_graph_operations, {
let temp = TempDir::new().unwrap();
let graph_file = temp.child("test.ttl");
graph_file
.write_str(
r#"@prefix ex: <http://example.org/> .
ex:project1 a ex:Project ;
ex:name "Test Project" ;
ex:version "1.0.0" .
"#,
)
.unwrap();
let output = Command::cargo_bin("ggen")
.unwrap()
.args([
"graph",
"import",
graph_file.path().to_str().unwrap(),
"--format",
"turtle",
])
.output()
.unwrap();
assert!(output.status.success() || output.status.code().is_some());
});
test!(test_doctor_before_operations, {
Command::cargo_bin("ggen")
.unwrap()
.args(["doctor"])
.assert()
.success()
.stdout(predicate::str::contains("Checking").or(predicate::str::is_empty()));
});
#[ignore = "shell completion command not implemented"]
test!(test_shell_completion_generation, {
let temp = TempDir::new().unwrap();
let completion_file = temp.child("ggen.bash");
let output = Command::cargo_bin("ggen")
.unwrap()
.args([
"shell",
"completion",
"bash",
"--output",
completion_file.path().to_str().unwrap(),
])
.output()
.unwrap();
assert!(output.status.success() || completion_file.path().exists());
});
#[ignore = "config file loading not fully implemented"]
test!(test_config_file_loading, {
let temp = TempDir::new().unwrap();
let config_file = temp.child("config.toml");
config_file
.write_str(
r#"[project]
name = "test"
version = "1.0.0"
[templates]
search_paths = ["./templates"]
[marketplace]
enabled = true
"#,
)
.unwrap();
let output = Command::cargo_bin("ggen")
.unwrap()
.args(["--config", config_file.path().to_str().unwrap(), "doctor"])
.output()
.unwrap();
assert!(output.status.success());
});
test!(test_manifest_path_option, {
let temp = TempDir::new().unwrap();
let manifest = temp.child("custom.toml");
manifest
.write_str(
r#"[project]
name = "custom-project"
version = "1.0.0"
"#,
)
.unwrap();
let output = Command::cargo_bin("ggen")
.unwrap()
.args([
"--manifest-path",
manifest.path().to_str().unwrap(),
"project",
"info",
])
.output()
.unwrap();
assert!(output.status.success() || output.status.code().is_some());
});
test!(test_help_command, {
Command::cargo_bin("ggen")
.unwrap()
.args(["--help"])
.assert()
.success()
.stdout(predicate::str::contains("Graph-aware code generator"));
});
test!(test_version_command, {
Command::cargo_bin("ggen")
.unwrap()
.args(["--version"])
.assert()
.success()
.stdout(predicate::str::contains("1.2.0"));
});
test!(test_progressive_help, {
Command::cargo_bin("ggen")
.unwrap()
.args(["help-me"])
.assert()
.success();
});
test!(test_subcommand_help, {
for subcommand in &["template", "marketplace", "project", "lifecycle", "graph"] {
Command::cargo_bin("ggen")
.unwrap()
.args([*subcommand, "--help"])
.assert()
.success()
.stdout(predicate::str::contains("Usage").or(predicate::str::contains("Commands")));
}
});
test!(test_v2_auto_discovery, {
let output = Command::cargo_bin("ggen")
.unwrap()
.args(["--help"])
.output()
.unwrap();
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("marketplace") || stdout.contains("market"));
assert!(stdout.contains("template"));
assert!(stdout.contains("graph") || stdout.contains("lifecycle"));
assert!(output.status.success());
});
test!(test_v2_sync_wrapper_execution, {
let output = Command::cargo_bin("ggen")
.unwrap()
.args(["doctor"])
.output()
.unwrap();
assert!(output.status.success());
});
test!(test_v2_help_me_command, {
let output = Command::cargo_bin("ggen")
.unwrap()
.args(["help-me"])
.output()
.unwrap();
assert!(output.status.success());
});
#[ignore = "frozen section feature not yet implemented"]
test!(test_v2_frozen_section_preservation, {
let temp = TempDir::new().unwrap();
let output_file = temp.child("service.rs");
output_file
.write_str(
r#"// Generated code
pub fn generated() {
println!("Generated");
}
// FROZEN-START
pub fn my_business_logic() {
println!("Custom logic");
}
// FROZEN-END
// More generated code
pub fn more_generated() {
println!("More generated");
}
"#,
)
.unwrap();
let template_file = temp.child("template.yaml");
template_file
.write_str(
r#"name: test-frozen
nodes:
- name: service.rs
type: file
content: |
// Generated code
pub fn generated() {
println!("Generated v2");
}
// FROZEN-START
// This should be preserved
// FROZEN-END
// More generated code
pub fn more_generated() {
println!("More generated v2");
}
"#,
)
.unwrap();
let result = Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate",
template_file.path().to_str().unwrap(),
temp.path().to_str().unwrap(),
])
.output()
.unwrap();
if result.status.success() {
let content = std::fs::read_to_string(output_file.path()).unwrap();
assert!(content.contains("my_business_logic"));
assert!(content.contains("Custom logic"));
}
});
#[ignore = "business logic protection not yet implemented"]
test!(test_v2_business_logic_not_overwritten, {
let temp = TempDir::new().unwrap();
let business_file = temp.child("business_logic.rs");
business_file
.write_str(
r#"// Custom business logic
pub fn important_function() {
// Critical business logic
println!("Important!");
}
"#,
)
.unwrap();
let template_file = temp.child("template.yaml");
template_file
.write_str(
r#"name: test-business
nodes:
- name: generated.rs
type: file
content: |
// Generated code only
pub fn generated() {}
"#,
)
.unwrap();
let result = Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate",
template_file.path().to_str().unwrap(),
temp.path().to_str().unwrap(),
])
.output()
.unwrap();
if result.status.success() {
let original_content = "// Custom business logic";
let current_content = std::fs::read_to_string(business_file.path()).unwrap();
assert!(current_content.contains(original_content));
}
});
test!(test_v2_marketplace_search_with_rdf, {
let output = Command::cargo_bin("ggen")
.unwrap()
.args(["marketplace", "search", "rust", "--limit", "3"])
.output()
.unwrap();
assert!(output.status.success() || output.status.code() == Some(0));
});
#[ignore = "RDF template generation not yet fully implemented"]
test!(test_v2_rdf_based_template_generation, {
let temp = TempDir::new().unwrap();
let rdf_file = temp.child("data.ttl");
let template_file = temp.child("template.hbs");
let output_dir = temp.child("output");
rdf_file
.write_str(
r#"@prefix ex: <http://example.org/> .
ex:service a ex:Service ;
ex:name "MyService" ;
ex:version "1.0.0" .
"#,
)
.unwrap();
template_file
.write_str(
r#"// Service: {{name}}
// Version: {{version}}
pub struct {{name}} {
version: &'static str,
}
impl {{name}} {
pub fn new() -> Self {
Self { version: "{{version}}" }
}
}
"#,
)
.unwrap();
let result = Command::cargo_bin("ggen")
.unwrap()
.args([
"template",
"generate",
template_file.path().to_str().unwrap(),
rdf_file.path().to_str().unwrap(),
"--output",
output_dir.path().to_str().unwrap(),
])
.output()
.unwrap();
if result.status.success() {
assert!(output_dir.path().exists());
}
});