use std::{ process::Command, fs, path::Path };
#[ test ]
fn test_all_examples_registered()
{
let examples_dir = Path::new( "examples" );
let cargo_toml = fs::read_to_string( "Cargo.toml" )
.expect( "Failed to read Cargo.toml" );
let mut example_files = Vec::new();
for entry in fs::read_dir( examples_dir ).expect( "Failed to read examples directory" )
{
let entry = entry.expect( "Failed to read directory entry" );
let path = entry.path();
if path.extension().and_then( | s | s.to_str() ) == Some( "rs" )
{
let filename = path.file_name().expect( "[test_all_examples_compile] Path should have filename component - check examples directory structure" ).to_str().expect( "[test_all_examples_compile] Filename should be valid UTF-8 - check filesystem encoding" );
example_files.push( ( filename.to_string(), path ) );
}
}
let mut unregistered = Vec::new();
for ( filename, _path ) in &example_files
{
let expected_path = format!( "examples/{filename}" );
if !cargo_toml.contains( &expected_path )
{
unregistered.push( filename.clone() );
}
}
assert!(
unregistered.is_empty(),
"Found {} unregistered examples in Cargo.toml:\n{}\n\n\
These examples exist but cannot be run. Add [[example]] entries for them.",
unregistered.len(),
unregistered.join( "\n" )
);
}
#[ test ]
fn test_cargo_toml_examples_exist()
{
let cargo_toml = fs::read_to_string( "Cargo.toml" )
.expect( "Failed to read Cargo.toml" );
let mut missing = Vec::new();
for line in cargo_toml.lines()
{
if line.trim().starts_with( "path = \"examples/" )
{
if let Some( start ) = line.find( "\"examples/" )
{
if let Some( end ) = line[ start + 1.. ].find( '"' )
{
let path_str = &line[ start + 1..start + 1 + end ];
let path = Path::new( path_str );
if !path.exists()
{
missing.push( path_str.to_string() );
}
}
}
}
}
assert!(
missing.is_empty(),
"Found {} Cargo.toml entries for non-existent examples:\n{}",
missing.len(),
missing.join( "\n" )
);
}
#[ test ]
fn test_expected_example_count()
{
let examples_dir = Path::new( "examples" );
let count = fs::read_dir( examples_dir )
.expect( "Failed to read examples directory" )
.filter_map( core::result::Result::ok )
.filter( | entry | {
entry.path().extension().and_then( | s | s.to_str() ) == Some( "rs" )
} )
.count();
assert!(
count >= 14,
"Expected at least 14 examples, found {count}. Examples may have been deleted."
);
}
#[ test ]
fn test_examples_compile_all_features()
{
let output = Command::new( "cargo" )
.args( [ "build", "--examples", "--all-features" ] )
.env( "RUSTFLAGS", "-D warnings" )
.output()
.expect( "Failed to run cargo build" );
if !output.status.success()
{
let stderr = String::from_utf8_lossy( &output.stderr );
panic!(
"Examples failed to compile with --all-features:\n{stderr}"
);
}
}
#[ test ]
fn test_example_naming_convention()
{
let cargo_toml = fs::read_to_string( "Cargo.toml" )
.expect( "Failed to read Cargo.toml" );
let mut violations = Vec::new();
for line in cargo_toml.lines()
{
if line.trim().starts_with( "name = \"" )
{
if let Some( start ) = line.find( '"' )
{
if let Some( end ) = line[ start + 1.. ].find( '"' )
{
let name = &line[ start + 1..start + 1 + end ];
if name.chars().any( | c | c.is_uppercase() || c == '-' )
{
violations.push( format!(
"{name}: Example names should use snake_case, not kebab-case or camelCase"
) );
}
}
}
}
}
assert!(
violations.is_empty(),
"Found example naming convention violations:\n{}",
violations.join( "\n" )
);
}