use std::fs;
use std::path::PathBuf;
fn get_crate_version() -> String
{
let manifest_path = PathBuf::from( env!( "CARGO_MANIFEST_DIR" ) ).join( "Cargo.toml" );
let manifest_content = fs::read_to_string( manifest_path )
.expect( "Failed to read Cargo.toml" );
for line in manifest_content.lines()
{
if line.starts_with( "version" )
{
let version = line.split( '=' ).nth( 1 )
.expect( "Invalid version line in Cargo.toml" )
.trim()
.trim_matches( '"' );
return version.to_string();
}
}
panic!( "Version not found in Cargo.toml" );
}
fn get_command_versions() -> Vec< ( String, String ) >
{
let yaml_path = PathBuf::from( env!( "CARGO_MANIFEST_DIR" ) ).join( "unilang.commands.yaml" );
let yaml_content = fs::read_to_string( yaml_path )
.expect( "Failed to read unilang.commands.yaml" );
let mut commands = Vec::new();
let mut current_name = None;
for line in yaml_content.lines()
{
let trimmed = line.trim();
if trimmed.starts_with( "- name:" )
{
current_name = Some(
trimmed.split( ':' ).nth( 1 )
.expect( "Invalid name line" )
.trim()
.trim_matches( '"' )
.to_string()
);
}
else if trimmed.starts_with( "version:" )
{
if let Some( name ) = current_name.take()
{
let version = trimmed.split( ':' ).nth( 1 )
.expect( "Invalid version line" )
.trim()
.trim_matches( '"' )
.to_string();
commands.push( ( name, version ) );
}
}
}
commands
}
#[test]
fn test_command_version_consistency()
{
let crate_version = get_crate_version();
let commands = get_command_versions();
println!( "\n=== Command Version Consistency Report ===" );
println!( "Crate version: {crate_version}" );
println!( "\nCommands:" );
for ( name, version ) in &commands
{
println!( " {name} → v{version}" );
}
for ( name, version ) in &commands
{
assert!(
version <= &crate_version,
"Command '{name}' version ({version}) exceeds crate version ({crate_version})"
);
}
for ( name, version ) in &commands
{
let parts: Vec< &str > = version.split( '.' ).collect();
assert!(
parts.len() >= 2,
"Command '{name}' version '{version}' is not a valid semantic version (must have at least major.minor)"
);
for part in parts
{
assert!(
part.parse::< u32 >().is_ok(),
"Command '{name}' version '{version}' contains non-numeric component '{part}'"
);
}
}
println!( "\n✅ All command versions are consistent" );
}
#[test]
fn test_v1_3_0_release_versions()
{
let crate_version = get_crate_version();
if crate_version == "1.3.0"
{
let commands = get_command_versions();
let show_cmd = commands.iter().find( |( n, _ )| n == ".show" )
.expect( ".show command exists" );
assert_eq!(
show_cmd.1, "1.3.0",
".show command must be v1.3.0 (breaking change in REQ-011)"
);
println!( "\n✅ v1.3.0 release: .show correctly versioned" );
}
else
{
println!( "\nℹ️ Skipping v1.3.0-specific validation (current version: {crate_version})" );
}
}