use std::process::Command;
fn boundary_cmd() -> Command {
Command::new(env!("CARGO_BIN_EXE_boundary"))
}
fn fixture(name: &str) -> String {
format!("{}/tests/fixtures/{name}", env!("CARGO_MANIFEST_DIR"))
}
#[test]
fn discovery_no_recognizable_structure() {
let output = boundary_cmd()
.args(["analyze", &fixture("flat-go-module")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.contains("No architectural layers detected"),
"should report no layers detected: {stdout}"
);
}
#[test]
fn discovery_complete_ddd_reports_all_layers() {
let output = boundary_cmd()
.args(["analyze", &fixture("full-ddd-module")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.contains("Domain"),
"should list Domain layer components: {stdout}"
);
assert!(
stdout.contains("Application"),
"should list Application layer components: {stdout}"
);
assert!(
stdout.contains("Infrastructure"),
"should list Infrastructure layer components: {stdout}"
);
}
#[test]
fn discovery_complete_ddd_structural_presence_100() {
let output = boundary_cmd()
.args(["analyze", &fixture("full-ddd-module")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.contains("Structural Presence: 100%"),
"should report Structural Presence: 100%: {stdout}"
);
}
#[test]
fn discovery_partial_ddd_reports_classified_and_unclassified() {
let output = boundary_cmd()
.args(["analyze", &fixture("partial-ddd-module")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.contains("Domain"),
"should list Domain layer components: {stdout}"
);
assert!(
stdout.to_lowercase().contains("unclassified") && stdout.contains("services"),
"should identify 'services' as an unclassified directory: {stdout}"
);
}
#[test]
fn discovery_unclassified_directories_suggests_config() {
let output = boundary_cmd()
.args(["analyze", &fixture("partial-ddd-module")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.contains(".boundary.toml"),
"should suggest adding a .boundary.toml: {stdout}"
);
}
#[test]
fn discovery_override_assigns_directory_to_layer() {
let output = boundary_cmd()
.args(["analyze", &fixture("adapters-override")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.contains("Infrastructure"),
"should report adapters components as Infrastructure layer: {stdout}"
);
}
#[test]
fn discovery_nonexistent_path_errors() {
let path = {
let dir = tempfile::tempdir().expect("failed to create temp dir");
dir.path().to_path_buf()
};
let output = boundary_cmd()
.args(["analyze", path.to_str().unwrap()])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let combined = format!("{stdout}{stderr}");
assert!(
!output.status.success(),
"exit code should be non-zero for nonexistent path"
);
assert!(
combined.to_lowercase().contains("not found")
|| combined.to_lowercase().contains("does not exist")
|| combined.to_lowercase().contains("no such file"),
"should report the path could not be found: {combined}"
);
}
#[test]
fn discovery_no_go_files_reports_no_source_files() {
let output = boundary_cmd()
.args(["analyze", &fixture("no-go-files")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout.to_lowercase().contains("no supported source files"),
"should report no supported source files were found: {stdout}"
);
}
#[test]
fn discovery_go_files_no_exported_types_reports_no_components() {
let output = boundary_cmd()
.args(["analyze", &fixture("no-exported-types")])
.output()
.expect("failed to run boundary analyze");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success(),
"exit code should be 0: stdout={stdout}"
);
assert!(
stdout
.to_lowercase()
.contains("no components were detected"),
"should report no components were detected in the analyzed files: {stdout}"
);
}