chore: remove BMAD framework files and IDE configuration artifacts
Clean up unused BMAD workflow, agent, and command files across all IDE configurations (.agent, .clinerules, .cursor, .gemini, .github, .kilocode, .opencode) and internal module files (_bmad/bmb, _bmad/bmm). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
//! Tests for batch execution.
|
||||
|
||||
use entropyk_cli::batch::{discover_config_files, BatchSummary};
|
||||
use entropyk_cli::batch::{discover_config_files, BatchAggregator, BatchSummary, OutputFormat};
|
||||
use entropyk_cli::run::{SimulationResult, SimulationStatus};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
@@ -128,3 +129,167 @@ fn test_simulation_result_statuses() {
|
||||
assert_eq!(error_count, 1);
|
||||
assert_eq!(timeout_count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_aggregator_csv_output() {
|
||||
let results = vec![
|
||||
SimulationResult {
|
||||
input: "scenario1.json".to_string(),
|
||||
status: SimulationStatus::Converged,
|
||||
convergence: Some(entropyk_cli::run::ConvergenceInfo {
|
||||
final_residual: 1e-8,
|
||||
tolerance: 1e-6,
|
||||
}),
|
||||
iterations: Some(25),
|
||||
state: None,
|
||||
performance: None,
|
||||
error: None,
|
||||
elapsed_ms: 150,
|
||||
},
|
||||
SimulationResult {
|
||||
input: "scenario2.json".to_string(),
|
||||
status: SimulationStatus::Converged,
|
||||
convergence: Some(entropyk_cli::run::ConvergenceInfo {
|
||||
final_residual: 5e-7,
|
||||
tolerance: 1e-6,
|
||||
}),
|
||||
iterations: Some(30),
|
||||
state: None,
|
||||
performance: None,
|
||||
error: None,
|
||||
elapsed_ms: 200,
|
||||
},
|
||||
SimulationResult {
|
||||
input: "scenario3.json".to_string(),
|
||||
status: SimulationStatus::Error,
|
||||
convergence: None,
|
||||
iterations: None,
|
||||
state: None,
|
||||
performance: None,
|
||||
error: Some("Solver failed".to_string()),
|
||||
elapsed_ms: 0,
|
||||
},
|
||||
];
|
||||
|
||||
let aggregator = BatchAggregator::new(results);
|
||||
let csv = aggregator.to_csv();
|
||||
let lines: Vec<&str> = csv.lines().collect();
|
||||
|
||||
// Header + 3 data lines
|
||||
assert_eq!(lines.len(), 4);
|
||||
assert!(lines[0].contains("input,status,iterations,converged"));
|
||||
assert!(lines[1].contains("scenario1.json"));
|
||||
assert!(lines[1].contains("converged"));
|
||||
assert!(lines[1].contains("true"));
|
||||
assert!(lines[3].contains("error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_aggregator_json_summary() {
|
||||
let results = vec![
|
||||
SimulationResult {
|
||||
input: "test1.json".to_string(),
|
||||
status: SimulationStatus::Converged,
|
||||
convergence: None,
|
||||
iterations: Some(10),
|
||||
state: None,
|
||||
performance: None,
|
||||
error: None,
|
||||
elapsed_ms: 50,
|
||||
},
|
||||
SimulationResult {
|
||||
input: "test2.json".to_string(),
|
||||
status: SimulationStatus::Converged,
|
||||
convergence: None,
|
||||
iterations: Some(15),
|
||||
state: None,
|
||||
performance: None,
|
||||
error: None,
|
||||
elapsed_ms: 75,
|
||||
},
|
||||
SimulationResult {
|
||||
input: "test3.json".to_string(),
|
||||
status: SimulationStatus::Timeout,
|
||||
convergence: None,
|
||||
iterations: Some(100),
|
||||
state: None,
|
||||
performance: None,
|
||||
error: None,
|
||||
elapsed_ms: 5000,
|
||||
},
|
||||
];
|
||||
|
||||
let aggregator = BatchAggregator::new(results);
|
||||
let summary = aggregator.summary();
|
||||
|
||||
assert_eq!(summary.total, 3);
|
||||
assert_eq!(summary.succeeded, 2);
|
||||
assert_eq!(summary.failed, 0);
|
||||
assert_eq!(summary.non_converged, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_format_parsing() {
|
||||
assert_eq!(OutputFormat::from_str("json").unwrap(), OutputFormat::Json);
|
||||
assert_eq!(OutputFormat::from_str("JSON").unwrap(), OutputFormat::Json);
|
||||
assert_eq!(OutputFormat::from_str("csv").unwrap(), OutputFormat::Csv);
|
||||
assert_eq!(OutputFormat::from_str("CSV").unwrap(), OutputFormat::Csv);
|
||||
assert!(OutputFormat::from_str("xml").is_err());
|
||||
assert!(OutputFormat::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_summary_json_serialization_roundtrip() {
|
||||
let summary = BatchSummary {
|
||||
total: 20,
|
||||
succeeded: 18,
|
||||
failed: 1,
|
||||
non_converged: 1,
|
||||
total_elapsed_ms: 5000,
|
||||
avg_elapsed_ms: 250.0,
|
||||
results: vec![],
|
||||
};
|
||||
|
||||
let json = summary.to_json().unwrap();
|
||||
let deserialized: BatchSummary = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(deserialized.total, 20);
|
||||
assert_eq!(deserialized.succeeded, 18);
|
||||
assert_eq!(deserialized.failed, 1);
|
||||
assert_eq!(deserialized.non_converged, 1);
|
||||
assert_eq!(deserialized.total_elapsed_ms, 5000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_summary_csv_with_convergence() {
|
||||
let results = vec![SimulationResult {
|
||||
input: "config1.json".to_string(),
|
||||
status: SimulationStatus::Converged,
|
||||
convergence: Some(entropyk_cli::run::ConvergenceInfo {
|
||||
final_residual: 1e-9,
|
||||
tolerance: 1e-6,
|
||||
}),
|
||||
iterations: Some(42),
|
||||
state: None,
|
||||
performance: None,
|
||||
error: None,
|
||||
elapsed_ms: 300,
|
||||
}];
|
||||
|
||||
let summary = BatchSummary {
|
||||
total: 1,
|
||||
succeeded: 1,
|
||||
failed: 0,
|
||||
non_converged: 0,
|
||||
total_elapsed_ms: 300,
|
||||
avg_elapsed_ms: 300.0,
|
||||
results,
|
||||
};
|
||||
|
||||
let csv = summary.to_csv();
|
||||
assert!(csv.contains("config1.json"));
|
||||
assert!(csv.contains("converged"));
|
||||
assert!(csv.contains("42"));
|
||||
assert!(csv.contains("1.00e-9"));
|
||||
assert!(csv.contains("300"));
|
||||
}
|
||||
|
||||
@@ -652,3 +652,112 @@ fn test_fan_control_bounded_does_not_error() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Integration test for story 15-3: CLI uses real Pump<Connected> (2 equations), not stub.
|
||||
/// A config with two Pumps in a loop must not fail with "State dimension does not match equation count".
|
||||
#[test]
|
||||
fn test_pump_real_component_used() {
|
||||
use entropyk_cli::run::run_simulation;
|
||||
|
||||
let dir = tempdir().unwrap();
|
||||
let config_path = dir.path().join("water_loop.json");
|
||||
|
||||
let json = r#"
|
||||
{
|
||||
"name": "Water loop two pumps",
|
||||
"fluid": "Water",
|
||||
"circuits": [{
|
||||
"id": 0,
|
||||
"name": "Water",
|
||||
"components": [
|
||||
{ "type": "Pump", "name": "pump1" },
|
||||
{ "type": "Pump", "name": "pump2" }
|
||||
],
|
||||
"edges": [
|
||||
{ "from": "pump1:outlet", "to": "pump2:inlet" },
|
||||
{ "from": "pump2:outlet", "to": "pump1:inlet" }
|
||||
]
|
||||
}],
|
||||
"solver": { "strategy": "newton", "max_iterations": 50, "tolerance": 1e-6 }
|
||||
}
|
||||
"#;
|
||||
std::fs::write(&config_path, json).unwrap();
|
||||
|
||||
let result = run_simulation(&config_path, None, false).unwrap();
|
||||
|
||||
// Real Pump has 2 equations each -> 4 equations, 2 edges -> 4 state. No dimension mismatch.
|
||||
if let Some(ref err) = result.error {
|
||||
assert!(
|
||||
!err.contains("State dimension") || !err.contains("equation count"),
|
||||
"Real Pump must be used (no stub); dimension mismatch indicates stub: {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Story 15-4: BphxEvaporator and BphxCondenser are accepted by create_component (config parsing).
|
||||
/// Asserts that a config with both types does not yield "Unknown component type".
|
||||
#[test]
|
||||
fn test_bphx_evaporator_and_condenser_config_parsing() {
|
||||
use entropyk_cli::run::run_simulation;
|
||||
|
||||
let dir = tempdir().unwrap();
|
||||
let config_path = dir.path().join("bphx_parsing.json");
|
||||
|
||||
let json = r#"
|
||||
{
|
||||
"name": "BPHX parsing test",
|
||||
"fluid": "R410A",
|
||||
"circuits": [
|
||||
{
|
||||
"id": 0,
|
||||
"components": [
|
||||
{
|
||||
"type": "BphxEvaporator",
|
||||
"name": "evap",
|
||||
"refrigerant": "R410A",
|
||||
"secondary_fluid": "Water",
|
||||
"dh_m": 0.003,
|
||||
"area_m2": 0.5,
|
||||
"n_plates": 20
|
||||
},
|
||||
{
|
||||
"type": "BphxCondenser",
|
||||
"name": "cond",
|
||||
"refrigerant": "R410A",
|
||||
"secondary_fluid": "Water",
|
||||
"target_subcooling_k": 3.0,
|
||||
"dh_m": 0.003,
|
||||
"area_m2": 0.5,
|
||||
"n_plates": 20
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
}
|
||||
],
|
||||
"solver": { "strategy": "newton", "max_iterations": 10, "tolerance": 1e-6 }
|
||||
}
|
||||
"#;
|
||||
std::fs::write(&config_path, json).unwrap();
|
||||
|
||||
let result = run_simulation(&config_path, None, false).unwrap();
|
||||
|
||||
// create_component must accept both types (no "Unknown component type").
|
||||
if let Some(ref err) = result.error {
|
||||
assert!(
|
||||
!err.contains("Unknown component type"),
|
||||
"BphxEvaporator and BphxCondenser must be supported: {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
// We expect Error or NonConverged (edges empty -> topology/finalization failure), not config parse failure.
|
||||
match result.status {
|
||||
SimulationStatus::Error => {
|
||||
// Failure is expected (e.g. isolated nodes); config parsing succeeded.
|
||||
}
|
||||
SimulationStatus::NonConverged | SimulationStatus::Converged | SimulationStatus::Timeout => {
|
||||
// Also acceptable if we get to solver stage.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user