225 lines
8.3 KiB
Rust
225 lines
8.3 KiB
Rust
use crate::case_result::CaseResult;
|
|
use crate::cases::*;
|
|
use crate::doc_header::DocHeader;
|
|
use crate::error::Error;
|
|
use crate::yaml_decode::{yaml_split_header_and_cases, YamlDecode};
|
|
use crate::EfTest;
|
|
use serde_derive::Deserialize;
|
|
use std::{fs::File, io::prelude::*, path::PathBuf};
|
|
use types::{MainnetEthSpec, MinimalEthSpec};
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct Doc {
|
|
pub header_yaml: String,
|
|
pub cases_yaml: String,
|
|
pub path: PathBuf,
|
|
}
|
|
|
|
impl Doc {
|
|
fn from_path(path: PathBuf) -> Self {
|
|
let mut file = File::open(path.clone()).unwrap();
|
|
|
|
let mut yaml = String::new();
|
|
file.read_to_string(&mut yaml).unwrap();
|
|
|
|
let (header_yaml, cases_yaml) = yaml_split_header_and_cases(yaml.clone());
|
|
|
|
Self {
|
|
header_yaml,
|
|
cases_yaml,
|
|
path,
|
|
}
|
|
}
|
|
|
|
pub fn test_results(&self) -> Vec<CaseResult> {
|
|
let header: DocHeader = serde_yaml::from_str(&self.header_yaml.as_str()).unwrap();
|
|
|
|
match (
|
|
header.runner.as_ref(),
|
|
header.handler.as_ref(),
|
|
header.config.as_ref(),
|
|
) {
|
|
("ssz", "uint", _) => run_test::<SszGeneric>(self),
|
|
("ssz", "static", "minimal") => run_test::<SszStatic<MinimalEthSpec>>(self),
|
|
("ssz", "static", "mainnet") => run_test::<SszStatic<MainnetEthSpec>>(self),
|
|
("sanity", "slots", "minimal") => run_test::<SanitySlots<MinimalEthSpec>>(self),
|
|
("sanity", "slots", "mainnet") => run_test::<SanitySlots<MainnetEthSpec>>(self),
|
|
("sanity", "blocks", "minimal") => run_test::<SanityBlocks<MinimalEthSpec>>(self),
|
|
("sanity", "blocks", "mainnet") => run_test::<SanityBlocks<MainnetEthSpec>>(self),
|
|
("shuffling", "core", "minimal") => run_test::<Shuffling<MinimalEthSpec>>(self),
|
|
("shuffling", "core", "mainnet") => run_test::<Shuffling<MainnetEthSpec>>(self),
|
|
("bls", "aggregate_pubkeys", "mainnet") => run_test::<BlsAggregatePubkeys>(self),
|
|
("bls", "aggregate_sigs", "mainnet") => run_test::<BlsAggregateSigs>(self),
|
|
("bls", "msg_hash_compressed", "mainnet") => run_test::<BlsG2Compressed>(self),
|
|
// Note this test fails due to a difference in our internal representations. It does
|
|
// not effect verification or external representation.
|
|
//
|
|
// It is skipped.
|
|
("bls", "msg_hash_uncompressed", "mainnet") => vec![],
|
|
("bls", "priv_to_pub", "mainnet") => run_test::<BlsPrivToPub>(self),
|
|
("bls", "sign_msg", "mainnet") => run_test::<BlsSign>(self),
|
|
("operations", "deposit", "mainnet") => {
|
|
run_test::<OperationsDeposit<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "deposit", "minimal") => {
|
|
run_test::<OperationsDeposit<MinimalEthSpec>>(self)
|
|
}
|
|
("operations", "transfer", "mainnet") => {
|
|
run_test::<OperationsTransfer<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "transfer", "minimal") => {
|
|
run_test::<OperationsTransfer<MinimalEthSpec>>(self)
|
|
}
|
|
("operations", "voluntary_exit", "mainnet") => {
|
|
run_test::<OperationsExit<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "voluntary_exit", "minimal") => {
|
|
run_test::<OperationsExit<MinimalEthSpec>>(self)
|
|
}
|
|
("operations", "proposer_slashing", "mainnet") => {
|
|
run_test::<OperationsProposerSlashing<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "proposer_slashing", "minimal") => {
|
|
run_test::<OperationsProposerSlashing<MinimalEthSpec>>(self)
|
|
}
|
|
("operations", "attester_slashing", "mainnet") => {
|
|
run_test::<OperationsAttesterSlashing<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "attester_slashing", "minimal") => {
|
|
run_test::<OperationsAttesterSlashing<MinimalEthSpec>>(self)
|
|
}
|
|
("operations", "attestation", "mainnet") => {
|
|
run_test::<OperationsAttestation<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "attestation", "minimal") => {
|
|
run_test::<OperationsAttestation<MinimalEthSpec>>(self)
|
|
}
|
|
("operations", "block_header", "mainnet") => {
|
|
run_test::<OperationsBlockHeader<MainnetEthSpec>>(self)
|
|
}
|
|
("operations", "block_header", "minimal") => {
|
|
run_test::<OperationsBlockHeader<MinimalEthSpec>>(self)
|
|
}
|
|
("epoch_processing", "crosslinks", "minimal") => {
|
|
run_test::<EpochProcessingCrosslinks<MinimalEthSpec>>(self)
|
|
}
|
|
("epoch_processing", "crosslinks", "mainnet") => {
|
|
run_test::<EpochProcessingCrosslinks<MainnetEthSpec>>(self)
|
|
}
|
|
("epoch_processing", "registry_updates", "minimal") => {
|
|
run_test::<EpochProcessingRegistryUpdates<MinimalEthSpec>>(self)
|
|
}
|
|
("epoch_processing", "registry_updates", "mainnet") => {
|
|
run_test::<EpochProcessingRegistryUpdates<MainnetEthSpec>>(self)
|
|
}
|
|
(runner, handler, config) => panic!(
|
|
"No implementation for runner: \"{}\", handler: \"{}\", config: \"{}\"",
|
|
runner, handler, config
|
|
),
|
|
}
|
|
}
|
|
|
|
pub fn assert_tests_pass(path: PathBuf) {
|
|
let doc = Self::from_path(path);
|
|
let results = doc.test_results();
|
|
|
|
let (failed, skipped_bls, skipped_known_failures) = categorize_results(&results);
|
|
|
|
if failed.len() + skipped_known_failures.len() > 0 {
|
|
print_results(
|
|
&doc,
|
|
&failed,
|
|
&skipped_bls,
|
|
&skipped_known_failures,
|
|
&results,
|
|
);
|
|
if !failed.is_empty() {
|
|
panic!("Tests failed (see above)");
|
|
}
|
|
} else {
|
|
println!("Passed {} tests in {:?}", results.len(), doc.path);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn run_test<T>(doc: &Doc) -> Vec<CaseResult>
|
|
where
|
|
Cases<T>: EfTest + YamlDecode,
|
|
{
|
|
// Pass only the "test_cases" YAML string to `yaml_decode`.
|
|
let test_cases: Cases<T> = Cases::yaml_decode(&doc.cases_yaml).unwrap();
|
|
|
|
test_cases.test_results()
|
|
}
|
|
|
|
pub fn categorize_results(
|
|
results: &[CaseResult],
|
|
) -> (Vec<&CaseResult>, Vec<&CaseResult>, Vec<&CaseResult>) {
|
|
let mut failed = vec![];
|
|
let mut skipped_bls = vec![];
|
|
let mut skipped_known_failures = vec![];
|
|
|
|
for case in results {
|
|
match case.result.as_ref().err() {
|
|
Some(Error::SkippedBls) => skipped_bls.push(case),
|
|
Some(Error::SkippedKnownFailure) => skipped_known_failures.push(case),
|
|
Some(_) => failed.push(case),
|
|
None => (),
|
|
}
|
|
}
|
|
|
|
(failed, skipped_bls, skipped_known_failures)
|
|
}
|
|
|
|
pub fn print_results(
|
|
doc: &Doc,
|
|
failed: &[&CaseResult],
|
|
skipped_bls: &[&CaseResult],
|
|
skipped_known_failures: &[&CaseResult],
|
|
results: &[CaseResult],
|
|
) {
|
|
let header: DocHeader = serde_yaml::from_str(&doc.header_yaml).unwrap();
|
|
println!("--------------------------------------------------");
|
|
println!(
|
|
"Test {}",
|
|
if failed.is_empty() {
|
|
"Result"
|
|
} else {
|
|
"Failure"
|
|
}
|
|
);
|
|
println!("Title: {}", header.title);
|
|
println!("File: {:?}", doc.path);
|
|
println!();
|
|
println!(
|
|
"{} tests, {} failed, {} skipped (known failure), {} skipped (bls), {} passed.",
|
|
results.len(),
|
|
failed.len(),
|
|
skipped_known_failures.len(),
|
|
skipped_bls.len(),
|
|
results.len() - skipped_bls.len() - skipped_known_failures.len() - failed.len()
|
|
);
|
|
println!();
|
|
|
|
for case in skipped_known_failures {
|
|
println!("-------");
|
|
println!(
|
|
"case[{}] ({}) skipped because it's a known failure",
|
|
case.case_index, case.desc,
|
|
);
|
|
}
|
|
for failure in failed {
|
|
let error = failure.result.clone().unwrap_err();
|
|
|
|
println!("-------");
|
|
println!(
|
|
"case[{}] ({}) failed with {}:",
|
|
failure.case_index,
|
|
failure.desc,
|
|
error.name()
|
|
);
|
|
println!("{}", error.message());
|
|
}
|
|
println!();
|
|
}
|