diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4324d28b..8e06af5e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,6 +33,31 @@ jobs: command: test args: --all + test_miri: + name: Miri Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + components: miri + - run: cargo miri test + + test_miri_big_endian: + name: Miri Test Big Endian + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + components: miri + target: mips64-unknown-linux-gnuabi64 + - run: cargo miri test --target mips64-unknown-linux-gnuabi64 + examples: name: Examples runs-on: ubuntu-latest diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 6b7906ea..06465ed0 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -528,7 +528,7 @@ fn emit_field_read( if (!(#v)) { // assertion is false, raise error return Err(::#crate_::DekuError::Assertion(format!( - "field '{}' failed assertion: {}", + "field {} failed assertion: {}", #field_ident_str, stringify!(#v) ))); @@ -543,7 +543,7 @@ fn emit_field_read( if (!(#internal_field_ident == (#v))) { // assertion is false, raise error return Err(::#crate_::DekuError::Assertion(format!( - "field '{}' failed assertion: {}", + "field {} failed assertion: {}", #field_ident_str, stringify!(#field_ident == #v) ))); diff --git a/deku-derive/src/macros/deku_write.rs b/deku-derive/src/macros/deku_write.rs index 600add87..c83c491e 100644 --- a/deku-derive/src/macros/deku_write.rs +++ b/deku-derive/src/macros/deku_write.rs @@ -492,7 +492,7 @@ fn emit_field_write( if (!(#v)) { // assertion is false, raise error return Err(::#crate_::DekuError::Assertion(format!( - "field '{}' failed assertion: {}", + "field {} failed assertion: {}", #field_ident_str, stringify!(#v) ))); @@ -507,7 +507,7 @@ fn emit_field_write( if (!(*(#field_ident) == (#v))) { // assertion is false, raise error return Err(::#crate_::DekuError::Assertion(format!( - "field '{}' failed assertion: {}", + "field {} failed assertion: {}", #field_ident_str, stringify!(#field_ident == #v) ))); diff --git a/src/attributes.rs b/src/attributes.rs index 003c1b10..a8db3ecb 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -187,7 +187,7 @@ let data: Vec = vec![0x00, 0x01, 0x02]; let value = DekuTest::try_from(data.as_ref()); assert_eq!( - Err(DekuError::Assertion("field 'data' failed assertion: * data >= 8".into())), + Err(DekuError::Assertion("field data failed assertion: * data >= 8".into())), value ); ``` @@ -220,7 +220,7 @@ value.data = 0x02; let value: Result, DekuError> = value.try_into(); assert_eq!( - Err(DekuError::Assertion("field 'data' failed assertion: data == 0x01".into())), + Err(DekuError::Assertion("field data failed assertion: data == 0x01".into())), value ); ``` diff --git a/src/impls/boxed.rs b/src/impls/boxed.rs index 708c03c2..a499a4ac 100644 --- a/src/impls/boxed.rs +++ b/src/impls/boxed.rs @@ -69,12 +69,13 @@ where mod tests { use super::*; use crate::ctx::*; + use crate::native_endian; use rstest::rstest; #[rstest(input, expected, expected_rest, case( &[0xEF, 0xBE], - Box::new(0xBEEF), + Box::new(native_endian!(0xBEEF_u16)), bits![Msb0, u8;] ), )] diff --git a/src/impls/cow.rs b/src/impls/cow.rs index cfea3f2f..b50605ef 100644 --- a/src/impls/cow.rs +++ b/src/impls/cow.rs @@ -34,12 +34,13 @@ where #[cfg(test)] mod tests { use super::*; + use crate::native_endian; use rstest::rstest; #[rstest(input, expected, expected_rest, case( &[0xEF, 0xBE], - Cow::Owned(0xBEEF), + Cow::Owned(native_endian!(0xBEEF_u16)), bits![Msb0, u8;] ), )] diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index fb58dade..537c168a 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -223,6 +223,7 @@ ImplDekuTraits!(f64); #[cfg(test)] mod tests { use super::*; + use crate::native_endian; use rstest::rstest; static ENDIAN: Endian = Endian::new(); @@ -244,13 +245,23 @@ mod tests { } TestPrimitive!(test_u8, u8, vec![0xAAu8], 0xAAu8); - TestPrimitive!(test_u16, u16, vec![0xABu8, 0xCD], 0xCDAB); - TestPrimitive!(test_u32, u32, vec![0xABu8, 0xCD, 0xEF, 0xBE], 0xBEEFCDAB); + TestPrimitive!( + test_u16, + u16, + vec![0xABu8, 0xCD], + native_endian!(0xCDAB_u16) + ); + TestPrimitive!( + test_u32, + u32, + vec![0xABu8, 0xCD, 0xEF, 0xBE], + native_endian!(0xBEEFCDAB_u32) + ); TestPrimitive!( test_u64, u64, vec![0xABu8, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0], - 0xC0FECDABBEEFCDAB + native_endian!(0xC0FECDABBEEFCDAB_u64) ); TestPrimitive!( test_u128, @@ -259,26 +270,31 @@ mod tests { 0xABu8, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0, 0xAB, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0 ], - 0xC0FECDABBEEFCDABC0FECDABBEEFCDAB + native_endian!(0xC0FECDABBEEFCDABC0FECDABBEEFCDAB_u128) ); TestPrimitive!( test_usize, usize, vec![0xABu8, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0], if core::mem::size_of::() == 8 { - 0xC0FECDABBEEFCDAB + native_endian!(0xC0FECDABBEEFCDAB_usize) } else { - 0xBEEFCDAB + native_endian!(0xBEEFCDAB_usize) } ); TestPrimitive!(test_i8, i8, vec![0xFBu8], -5); - TestPrimitive!(test_i16, i16, vec![0xFDu8, 0xFE], -259); - TestPrimitive!(test_i32, i32, vec![0x02u8, 0x3F, 0x01, 0xEF], -0x10FEC0FE); + TestPrimitive!(test_i16, i16, vec![0xFDu8, 0xFE], native_endian!(-259_i16)); + TestPrimitive!( + test_i32, + i32, + vec![0x02u8, 0x3F, 0x01, 0xEF], + native_endian!(-0x10FEC0FE_i32) + ); TestPrimitive!( test_i64, i64, vec![0x02u8, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF], - -0x10FEC0FE10FEC0FE + native_endian!(-0x10FEC0FE10FEC0FE_i64) ); TestPrimitive!( test_i128, @@ -287,24 +303,29 @@ mod tests { 0x02u8, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF ], - -0x10FEC0FE10FEC0FE10FEC0FE10FEC0FE + native_endian!(-0x10FEC0FE10FEC0FE10FEC0FE10FEC0FE_i128) ); TestPrimitive!( test_isize, isize, vec![0x02u8, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF], if core::mem::size_of::() == 8 { - -0x10FEC0FE10FEC0FE + native_endian!(-0x10FEC0FE10FEC0FE_isize) } else { - -0x10FEC0FE + native_endian!(-0x10FEC0FE_isize) } ); - TestPrimitive!(test_f32, f32, vec![0xA6u8, 0x9B, 0xC4, 0xBB], -0.006); + TestPrimitive!( + test_f32, + f32, + vec![0xA6u8, 0x9B, 0xC4, 0xBB], + native_endian!(-0.006_f32) + ); TestPrimitive!( test_f64, f64, vec![0xFAu8, 0x7E, 0x6A, 0xBC, 0x74, 0x93, 0x78, 0xBF], - -0.006 + native_endian!(-0.006_f64) ); #[rstest(input, endian, bit_size, expected, expected_rest, diff --git a/src/impls/tuple.rs b/src/impls/tuple.rs index 6aba9363..202abd58 100644 --- a/src/impls/tuple.rs +++ b/src/impls/tuple.rs @@ -83,15 +83,16 @@ ImplDekuTupleTraits! { A, B, C, D, E, F, G, H, I, J, K, } #[cfg(test)] mod tests { use super::*; + use crate::native_endian; use core::fmt::Debug; use rstest::rstest; #[rstest(input, expected, expected_rest, - case::length_1([0xef, 0xbe, 0xad, 0xde].as_ref(), (0xdeadbeefu32,), bits![Msb0, u8;]), - case::length_2([1, 0x24, 0x98, 0x82, 0].as_ref(), (true, 0x829824u32), bits![Msb0, u8;]), + case::length_1([0xef, 0xbe, 0xad, 0xde].as_ref(), (native_endian!(0xdeadbeef_u32),), bits![Msb0, u8;]), + case::length_2([1, 0x24, 0x98, 0x82, 0].as_ref(), (true, native_endian!(0x829824_u32)), bits![Msb0, u8;]), case::length_11([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].as_ref(), (0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8), bits![Msb0, u8;]), - case::extra_rest([1, 0x24, 0x98, 0x82, 0, 0].as_ref(), (true, 0x829824u32), bits![Msb0, u8; 0, 0, 0, 0, 0, 0, 0, 0]), + case::extra_rest([1, 0x24, 0x98, 0x82, 0, 0].as_ref(), (true, native_endian!(0x829824_u32)), bits![Msb0, u8; 0, 0, 0, 0, 0, 0, 0, 0]), )] fn test_tuple_read<'a, T>(input: &'a [u8], expected: T, expected_rest: &BitSlice) where @@ -104,8 +105,8 @@ mod tests { } #[rstest(input, expected, - case::length_1((0xdeadbeefu32,), vec![0xef, 0xbe, 0xad, 0xde]), - case::length_2((true, 0x829824u32), vec![1, 0x24, 0x98, 0x82, 0]), + case::length_1((native_endian!(0xdeadbeef_u32),), vec![0xef, 0xbe, 0xad, 0xde]), + case::length_2((true, native_endian!(0x829824_u32)), vec![1, 0x24, 0x98, 0x82, 0]), case::length_11((0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8), vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) )] fn test_tuple_write(input: T, expected: Vec) diff --git a/src/lib.rs b/src/lib.rs index 2965f335..ee28e227 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -363,3 +363,7 @@ where Ok(()) } } + +#[cfg(test)] +#[path = "../tests/test_common/mod.rs"] +pub mod test_common; diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs index c0d3ec16..a3014abd 100644 --- a/tests/test_alloc.rs +++ b/tests/test_alloc.rs @@ -43,6 +43,7 @@ mod tests { use std::convert::TryFrom; #[test] + #[cfg_attr(miri, ignore)] fn test_simple() { let input = hex!("aabbbbcc0102ddffffffaa"); diff --git a/tests/test_attributes/test_assert.rs b/tests/test_attributes/test_assert.rs index 5a306d74..d0796291 100644 --- a/tests/test_attributes/test_assert.rs +++ b/tests/test_attributes/test_assert.rs @@ -16,7 +16,7 @@ struct TestStruct { field_b: 0x02, }), - #[should_panic(expected = r#"Assertion("field \'field_b\' failed assertion: * field_a + * field_b >= 3")"#)] + #[should_panic(expected = r#"Assertion("field field_b failed assertion: * field_a + * field_b >= 3")"#)] case(&hex!("0101"), TestStruct::default()) )] fn test_assert_read(input: &[u8], expected: TestStruct) { @@ -30,7 +30,7 @@ fn test_assert_read(input: &[u8], expected: TestStruct) { field_b: 0x02, }, hex!("0102").to_vec()), - #[should_panic(expected = r#"Assertion("field \'field_b\' failed assertion: * field_a + * field_b >= 3")"#)] + #[should_panic(expected = r#"Assertion("field field_b failed assertion: * field_a + * field_b >= 3")"#)] case(TestStruct { field_a: 0x01, field_b: 0x01, diff --git a/tests/test_attributes/test_assert_eq.rs b/tests/test_attributes/test_assert_eq.rs index 2c356ae5..abddeaa3 100644 --- a/tests/test_attributes/test_assert_eq.rs +++ b/tests/test_attributes/test_assert_eq.rs @@ -16,7 +16,7 @@ struct TestStruct { field_b: 0x01, }), - #[should_panic(expected = r#"Assertion("field \'field_b\' failed assertion: field_b == * field_a")"#)] + #[should_panic(expected = r#"Assertion("field field_b failed assertion: field_b == * field_a")"#)] case(&hex!("0102"), TestStruct::default()) )] fn test_assert_eq_read(input: &[u8], expected: TestStruct) { @@ -30,7 +30,7 @@ fn test_assert_eq_read(input: &[u8], expected: TestStruct) { field_b: 0x01, }, hex!("0101").to_vec()), - #[should_panic(expected = r#"Assertion("field \'field_b\' failed assertion: field_b == * field_a")"#)] + #[should_panic(expected = r#"Assertion("field field_b failed assertion: field_b == * field_a")"#)] case(TestStruct { field_a: 0x01, field_b: 0x02, diff --git a/tests/test_common/mod.rs b/tests/test_common/mod.rs new file mode 100644 index 00000000..5d9eef4c --- /dev/null +++ b/tests/test_common/mod.rs @@ -0,0 +1,41 @@ +pub trait FromBeBytes: Sized { + type Bytes; + fn from_be_bytes(_: Self::Bytes) -> Self; +} + +macro_rules! implFromBeBytes {( + $($T:ident),* $(,)?) => ($( + impl FromBeBytes for $T { + type Bytes = [u8; ::core::mem::size_of::<$T>()]; + fn from_be_bytes (bytes: Self::Bytes) -> Self { + #![deny(unconditional_recursion)] + Self::from_be_bytes(bytes) + } + } + )* +)} + +implFromBeBytes![u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128, f32, f64,]; + +/// Converts value to native endian +/// +/// Input is assumed to be little endian and the result is swapped if +/// target is big endian. +#[macro_export] +macro_rules! native_endian { + ($num:expr) => {{ + #[cfg(target_endian = "little")] + let res = $num; + + #[cfg(target_endian = "big")] + let res = { + let mut val = $num; + let bytes = val.to_le_bytes(); + val = $crate::test_common::FromBeBytes::from_be_bytes(bytes); + + val + }; + + res + }}; +} diff --git a/tests/test_compile/mod.rs b/tests/test_compile/mod.rs index 2f6276dc..92a37681 100644 --- a/tests/test_compile/mod.rs +++ b/tests/test_compile/mod.rs @@ -1,5 +1,6 @@ #[test] #[cfg(not(tarpaulin))] +#[cfg_attr(miri, ignore)] fn test_compile() { let t = trybuild::TestCases::new(); t.compile_fail("tests/test_compile/cases/*.rs"); diff --git a/tests/test_struct.rs b/tests/test_struct.rs index 77ef8e24..5fdfca14 100644 --- a/tests/test_struct.rs +++ b/tests/test_struct.rs @@ -1,6 +1,8 @@ use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +mod test_common; + /// General smoke tests for structs /// TODO: These should be divided into smaller tests @@ -71,12 +73,14 @@ fn test_unnamed_struct() { 0xFF, 0b0000_0010, 0b0001_0110, - 0xBBAA, - 0xCCDD, + native_endian!(0xBBAAu16), + 0xCCDDu16, NestedDeku { nest_a: 0b00_100101, nest_b: 0b10, - inner: DoubleNestedDeku { data: 0xDDCC } + inner: DoubleNestedDeku { + data: native_endian!(0xDDCCu16) + } }, 0x02, vec![0xBE, 0xEF], @@ -132,12 +136,14 @@ fn test_named_struct() { field_a: 0xFF, field_b: 0b0000_0010, field_c: 0b0001_0110, - field_d: 0xBBAA, - field_e: 0xCCDD, + field_d: native_endian!(0xBBAAu16), + field_e: 0xCCDDu16, field_f: NestedDeku { nest_a: 0b00_100101, nest_b: 0b10, - inner: DoubleNestedDeku { data: 0xDDCC } + inner: DoubleNestedDeku { + data: native_endian!(0xDDCCu16) + } }, vec_len: 0x02, vec_data: vec![0xBE, 0xEF]