Improve ef_tests crate
This commit is contained in:
parent
d21c0b3963
commit
cf509bea9b
@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use ethereum_types::H256;
|
use ethereum_types::{H256, U128, U256};
|
||||||
|
|
||||||
macro_rules! impl_decodable_for_uint {
|
macro_rules! impl_decodable_for_uint {
|
||||||
($type: ident, $bit_size: expr) => {
|
($type: ident, $bit_size: expr) => {
|
||||||
@ -85,6 +85,48 @@ impl Decode for H256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Decode for U256 {
|
||||||
|
fn is_ssz_fixed_len() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssz_fixed_len() -> usize {
|
||||||
|
32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||||
|
let len = bytes.len();
|
||||||
|
let expected = <Self as Decode>::ssz_fixed_len();
|
||||||
|
|
||||||
|
if len != expected {
|
||||||
|
Err(DecodeError::InvalidByteLength { len, expected })
|
||||||
|
} else {
|
||||||
|
Ok(U256::from_little_endian(bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decode for U128 {
|
||||||
|
fn is_ssz_fixed_len() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssz_fixed_len() -> usize {
|
||||||
|
16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||||
|
let len = bytes.len();
|
||||||
|
let expected = <Self as Decode>::ssz_fixed_len();
|
||||||
|
|
||||||
|
if len != expected {
|
||||||
|
Err(DecodeError::InvalidByteLength { len, expected })
|
||||||
|
} else {
|
||||||
|
Ok(U128::from_little_endian(bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_decodable_for_u8_array {
|
macro_rules! impl_decodable_for_u8_array {
|
||||||
($len: expr) => {
|
($len: expr) => {
|
||||||
impl Decode for [u8; $len] {
|
impl Decode for [u8; $len] {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use ethereum_types::H256;
|
use ethereum_types::{H256, U128, U256};
|
||||||
|
|
||||||
macro_rules! impl_encodable_for_uint {
|
macro_rules! impl_encodable_for_uint {
|
||||||
($type: ident, $bit_size: expr) => {
|
($type: ident, $bit_size: expr) => {
|
||||||
@ -77,6 +77,42 @@ impl Encode for H256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Encode for U256 {
|
||||||
|
fn is_ssz_fixed_len() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssz_fixed_len() -> usize {
|
||||||
|
32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||||
|
let n = <Self as Encode>::ssz_fixed_len();
|
||||||
|
let s = buf.len();
|
||||||
|
|
||||||
|
buf.resize(s + n, 0);
|
||||||
|
self.to_little_endian(&mut buf[s..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encode for U128 {
|
||||||
|
fn is_ssz_fixed_len() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssz_fixed_len() -> usize {
|
||||||
|
16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||||
|
let n = <Self as Encode>::ssz_fixed_len();
|
||||||
|
let s = buf.len();
|
||||||
|
|
||||||
|
buf.resize(s + n, 0);
|
||||||
|
self.to_little_endian(&mut buf[s..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_encodable_for_u8_array {
|
macro_rules! impl_encodable_for_u8_array {
|
||||||
($len: expr) => {
|
($len: expr) => {
|
||||||
impl Encode for [u8; $len] {
|
impl Encode for [u8; $len] {
|
||||||
|
@ -5,6 +5,9 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ethereum-types = "0.5"
|
||||||
|
hex = "0.3"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
|
ssz = { path = "../../eth2/utils/ssz" }
|
||||||
|
9
tests/ef_tests/src/error.rs
Normal file
9
tests/ef_tests/src/error.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum Error {
|
||||||
|
/// The value in the test didn't match our value.
|
||||||
|
NotEqual(String),
|
||||||
|
/// The test specified a failure and we did not experience one.
|
||||||
|
DidntFail(String),
|
||||||
|
/// Failed to parse the test (internal error).
|
||||||
|
FailedToParseTest(String),
|
||||||
|
}
|
@ -1,4 +1,12 @@
|
|||||||
|
use error::Error;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
use ssz::Decode;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use ethereum_types::{U256, U128};
|
||||||
|
use test_decode::TestDecode;
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
mod test_decode;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct TestDoc<T> {
|
pub struct TestDoc<T> {
|
||||||
@ -21,6 +29,66 @@ pub struct SszGenericCase {
|
|||||||
pub ssz: Option<String>,
|
pub ssz: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Test {
|
||||||
|
fn test(&self) -> Vec<Result<(), Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test for TestDoc<SszGenericCase> {
|
||||||
|
fn test(&self) -> Vec<Result<(), Error>> {
|
||||||
|
self
|
||||||
|
.test_cases
|
||||||
|
.iter()
|
||||||
|
.map(|tc| {
|
||||||
|
if let Some(ssz) = &tc.ssz {
|
||||||
|
match tc.type_name.as_ref() {
|
||||||
|
"uint8" => compare_decoding::<u8>(tc.valid, ssz, &tc.value),
|
||||||
|
"uint16" => compare_decoding::<u16>(tc.valid, ssz, &tc.value),
|
||||||
|
"uint32" => compare_decoding::<u32>(tc.valid, ssz, &tc.value),
|
||||||
|
"uint64" => compare_decoding::<u64>(tc.valid, ssz, &tc.value),
|
||||||
|
"uint128" => compare_decoding::<U128>(tc.valid, ssz, &tc.value),
|
||||||
|
"uint256" => compare_decoding::<U256>(tc.valid, ssz, &tc.value),
|
||||||
|
_ => {
|
||||||
|
Err(Error::FailedToParseTest(format!("Unknown type: {}", tc.type_name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Skip tests that do not have an ssz field.
|
||||||
|
//
|
||||||
|
// See: https://github.com/ethereum/eth2.0-specs/issues/1079
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_decoding<T>(should_pass: bool, ssz: &String, value: &String) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: Decode + TestDecode + Debug + PartialEq<T>,
|
||||||
|
{
|
||||||
|
let ssz = hex::decode(&ssz[2..])
|
||||||
|
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
|
||||||
|
let expected = T::test_decode(value)?;
|
||||||
|
|
||||||
|
let decoded = T::from_ssz_bytes(&ssz);
|
||||||
|
|
||||||
|
if should_pass {
|
||||||
|
let decoded = decoded.map_err(|e| Error::NotEqual(format!("{:?}", e)))?;
|
||||||
|
|
||||||
|
if decoded != expected {
|
||||||
|
Err(Error::NotEqual(format!("{:?} != {:?}", decoded, expected)))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Ok(decoded) = decoded {
|
||||||
|
Err(Error::DidntFail(format!("Decoded as {:?}", decoded)))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
|
35
tests/ef_tests/src/test_decode.rs
Normal file
35
tests/ef_tests/src/test_decode.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub trait TestDecode: Sized {
|
||||||
|
fn test_decode(string: &String) -> Result<Self, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_via_parse {
|
||||||
|
($ty: ty) => {
|
||||||
|
impl TestDecode for $ty {
|
||||||
|
fn test_decode(string: &String) -> Result<Self, Error> {
|
||||||
|
string
|
||||||
|
.parse::<Self>()
|
||||||
|
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_via_parse!(u8);
|
||||||
|
impl_via_parse!(u16);
|
||||||
|
impl_via_parse!(u32);
|
||||||
|
impl_via_parse!(u64);
|
||||||
|
|
||||||
|
macro_rules! impl_via_from_dec_str {
|
||||||
|
($ty: ty) => {
|
||||||
|
impl TestDecode for $ty {
|
||||||
|
fn test_decode(string: &String) -> Result<Self, Error> {
|
||||||
|
Self::from_dec_str(string).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_via_from_dec_str!(U128);
|
||||||
|
impl_via_from_dec_str!(U256);
|
@ -21,7 +21,15 @@ fn load_test_case<T: DeserializeOwned>(test_name: &str) -> TestDoc<T> {
|
|||||||
fn ssz() {
|
fn ssz() {
|
||||||
let doc: TestDoc<SszGenericCase> = load_test_case("ssz_generic/uint/uint_bounds.yaml");
|
let doc: TestDoc<SszGenericCase> = load_test_case("ssz_generic/uint/uint_bounds.yaml");
|
||||||
|
|
||||||
dbg!(doc);
|
let results = doc.test();
|
||||||
|
|
||||||
assert!(false);
|
let failures: Vec<(usize, &Result<_, _>)> = results
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_i, r)| r.is_ok())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !failures.is_empty() {
|
||||||
|
panic!("{:?}", failures);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user