From 0a72b2664688a1f7ef3688947d8de0658003c3fd Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Fri, 17 Jan 2020 23:19:16 -0500 Subject: [PATCH] Add proptest encoding round-trip test --- toolchain/Cargo.lock | 47 ++++++++++++++++ toolchain/Cargo.toml | 1 + toolchain/proptest-regressions/inst/test.txt | 7 +++ toolchain/src/inst.rs | 57 ++++++++++++++------ toolchain/src/inst/decode.rs | 8 ++- toolchain/src/inst/encode.rs | 7 +++ toolchain/src/inst/test.rs | 16 ++++++ toolchain/src/lib.rs | 2 +- 8 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 toolchain/proptest-regressions/inst/test.txt create mode 100644 toolchain/src/inst/test.rs diff --git a/toolchain/Cargo.lock b/toolchain/Cargo.lock index d7d2e0b..3df833b 100644 --- a/toolchain/Cargo.lock +++ b/toolchain/Cargo.lock @@ -113,6 +113,15 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + [[package]] name = "proptest" version = "0.9.4" @@ -133,12 +142,32 @@ dependencies = [ "tempfile", ] +[[package]] +name = "proptest-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d31edb17edac73aeacc947bd61462dda15220584268896a58e12f053d767f15b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.6.5" @@ -328,6 +357,17 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.1.0" @@ -347,8 +387,15 @@ name = "toolchain" version = "0.1.0" dependencies = [ "proptest", + "proptest-derive", ] +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/toolchain/Cargo.toml b/toolchain/Cargo.toml index 976c29c..fd9a1be 100644 --- a/toolchain/Cargo.toml +++ b/toolchain/Cargo.toml @@ -10,3 +10,4 @@ edition = "2018" [dev-dependencies] proptest = "0.9.4" +proptest-derive = "0.1.0" diff --git a/toolchain/proptest-regressions/inst/test.txt b/toolchain/proptest-regressions/inst/test.txt new file mode 100644 index 0000000..ddfe16f --- /dev/null +++ b/toolchain/proptest-regressions/inst/test.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc bd1463681b9efb78a1ecf699478179a28e5228c837d2b2ee06b2b8418f24419f # shrinks to inst = Nope diff --git a/toolchain/src/inst.rs b/toolchain/src/inst.rs index ff0788b..07ffded 100644 --- a/toolchain/src/inst.rs +++ b/toolchain/src/inst.rs @@ -1,9 +1,17 @@ -mod decode; -mod encode; +pub mod decode; +pub mod encode; +#[cfg(test)] +mod test; +#[cfg(test)] +use proptest_derive::Arbitrary; + +pub use self::{decode::Decode, encode::Encode}; use std::cmp::PartialEq; #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] +#[repr(u8)] pub enum Reg { R0, R1, @@ -12,6 +20,7 @@ pub enum Reg { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum LdSt { Ld, @@ -19,6 +28,8 @@ pub enum LdSt { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] +#[repr(u8)] pub enum Op1 { Inc, Dec, @@ -27,6 +38,7 @@ pub enum Op1 { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub enum OpI { Add(I8), Lsl(U4), @@ -36,32 +48,38 @@ pub enum OpI { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] +#[repr(u8)] pub enum Op2 { - Add, + Add = 2, Sub, + AddPc, And, Or, Xor, - // These are preliminary - Lsl, - Rol, - Bic, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct U4(i8); +#[cfg_attr(test, derive(Arbitrary))] +pub struct U4(#[cfg_attr(test, proptest(strategy = "0..=16u8"))]u8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct I5(i8); +#[cfg_attr(test, derive(Arbitrary))] +pub struct I5(#[cfg_attr(test, proptest(strategy = "-16..=15i8"))]i8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct I7(i8); +#[cfg_attr(test, derive(Arbitrary))] +pub struct I7(#[cfg_attr(test, proptest(strategy = "-64..=63i8"))] i8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct U7(u8); +#[cfg_attr(test, derive(Arbitrary))] +pub struct U7(#[cfg_attr(test, proptest(strategy = "0..=128u8"))]u8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub struct U8(u8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub struct I8(i8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum Size { Byte, @@ -69,6 +87,7 @@ pub enum Size { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum Half { Low, @@ -76,10 +95,11 @@ pub enum Half { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub enum Addr { Fixed(U7), Reg(Reg), - Extended{ + Extended { base: Reg, offset: I5, stack: bool, @@ -88,16 +108,19 @@ pub enum Addr { } #[derive(Clone, Copy, Debug, Eq)] +#[cfg_attr(test, derive(Arbitrary))] +#[cfg_attr(test, proptest(no_params))] pub enum Cond { - Eq(Reg, Reg), - Ne(Reg, Reg), - Test(Reg ,Reg), + Eql(Reg, Reg), + Neq(Reg, Reg), + Test(Reg, Reg), TestNot(Reg, Reg), Lt(Reg, Reg), Ult(Reg, Reg), } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub enum Inst { Halt, Nope, @@ -116,8 +139,8 @@ impl PartialEq for Cond { fn eq(&self, other: &Cond) -> bool { use Cond::*; match (self, other) { - (Eq(a1, b1), Eq(a2, b2)) => (a1, b1) == (a2, b2) || (a1, b1) == (b2, a2), - (Ne(a1, b1), Ne(a2, b2)) => (a1, b1) == (a2, b2) || (a1, b1) == (b2, a2), + (Eql(a1, b1), Eql(a2, b2)) => (a1, b1) == (a2, b2) || (a1, b1) == (b2, a2), + (Neq(a1, b1), Neq(a2, b2)) => (a1, b1) == (a2, b2) || (a1, b1) == (b2, a2), (Test(a1, b1), Test(a2, b2)) => (a1, b1) == (a2, b2) || (a1, b1) == (b2, a2), (TestNot(a1, b1), TestNot(a2, b2)) => (a1, b1) == (a2, b2) || (a1, b1) == (b2, a2), (Lt(a1, b1), Lt(a2, b2)) => (a1, b1) == (a2, b2), diff --git a/toolchain/src/inst/decode.rs b/toolchain/src/inst/decode.rs index eb07ff4..66dc13f 100644 --- a/toolchain/src/inst/decode.rs +++ b/toolchain/src/inst/decode.rs @@ -2,5 +2,11 @@ use crate::inst::Inst; use std::io::{self, Read}; pub trait Decode { - fn decode(code: &mut impl Read) -> io::Result>; + fn decode(code: &mut impl Read) -> io::Result; +} + +impl Decode for Inst { + fn decode(code: &mut impl Read) -> io::Result { + Ok(Inst::Halt) + } } diff --git a/toolchain/src/inst/encode.rs b/toolchain/src/inst/encode.rs index ae7b0e9..e4832e2 100644 --- a/toolchain/src/inst/encode.rs +++ b/toolchain/src/inst/encode.rs @@ -4,3 +4,10 @@ use std::io::{self, Write}; pub trait Encode { fn encode(&self, out: &mut impl Write) -> io::Result<()>; } + +impl Encode for Inst { + fn encode(&self, out: &mut impl Write) -> io::Result<()> { + out.write_all(&[0x00])?; + Ok(()) + } +} diff --git a/toolchain/src/inst/test.rs b/toolchain/src/inst/test.rs new file mode 100644 index 0000000..e62a444 --- /dev/null +++ b/toolchain/src/inst/test.rs @@ -0,0 +1,16 @@ +use super::{Decode, Encode, Inst}; +use proptest::prelude::*; +use std::io::Cursor; + +proptest! { + #[test] + fn encoding_roundtrip(inst: Inst) { + let mut buffer = [0, 0]; + let mut cursor = Cursor::new(&mut buffer[..]); + inst.encode(&mut cursor).expect("Should encode instruction"); + cursor.set_position(0); + let out_inst = Inst::decode(&mut cursor) + .expect(&format!("Should decode instruction bytes {:?}", cursor.get_ref())); + prop_assert_eq!(inst, out_inst, "inst should round-trip the same"); + } +} diff --git a/toolchain/src/lib.rs b/toolchain/src/lib.rs index dda0093..83dc91c 100644 --- a/toolchain/src/lib.rs +++ b/toolchain/src/lib.rs @@ -1,2 +1,2 @@ -pub mod inst; pub mod cpu; +pub mod inst; -- 2.47.0