Explorar o código

Prepare code for mutation testing

This commit adds the optional with_mutagen feature, which brings in the in-development version of mutagen. It adds the attribute to all the DNS parsers, opting them in to mutation testing.

The mutagen tool itself recommends using the Git master version; however, it currently lacks the --package option which I added in my branch.
Benjamin Sago %!s(int64=4) %!d(string=hai) anos
pai
achega
3db46ddc3b

+ 159 - 8
Cargo.lock

@@ -1,5 +1,20 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+[[package]]
+name = "addr2line"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
+
 [[package]]
 name = "ansi_term"
 version = "0.11.0"
@@ -46,6 +61,20 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
+[[package]]
+name = "backtrace"
+version = "0.3.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707b586e0e2f247cbde68cdd2c3ce69ea7b7be43e1c5b426e37c9319c4b9838e"
+dependencies = [
+ "addr2line",
+ "cfg-if 1.0.0",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
 [[package]]
 name = "bitflags"
 version = "1.2.1"
@@ -76,6 +105,12 @@ version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
 [[package]]
 name = "core-foundation"
 version = "0.7.0"
@@ -136,6 +171,7 @@ version = "0.1.0"
 dependencies = [
  "byteorder",
  "log",
+ "mutagen",
 ]
 
 [[package]]
@@ -171,6 +207,28 @@ dependencies = [
  "serde_json",
 ]
 
+[[package]]
+name = "failure"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
+dependencies = [
+ "backtrace",
+ "failure_derive",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -262,11 +320,17 @@ version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
+
 [[package]]
 name = "h2"
 version = "0.2.6"
@@ -396,6 +460,12 @@ version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
 
+[[package]]
+name = "json"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
+
 [[package]]
 name = "kernel32-sys"
 version = "0.2.2"
@@ -424,7 +494,7 @@ version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
@@ -433,13 +503,23 @@ version = "2.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
 
+[[package]]
+name = "miniz_oxide"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
 [[package]]
 name = "mio"
 version = "0.6.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "fuchsia-zircon",
  "fuchsia-zircon-sys",
  "iovec",
@@ -464,6 +544,39 @@ dependencies = [
  "ws2_32-sys",
 ]
 
+[[package]]
+name = "mutagen"
+version = "0.2.0"
+source = "git+https://github.com/llogiq/mutagen#a33213be69f3df987c057d2667d0a3399bc7f625"
+dependencies = [
+ "mutagen-core",
+ "mutagen-transform",
+]
+
+[[package]]
+name = "mutagen-core"
+version = "0.2.0"
+source = "git+https://github.com/llogiq/mutagen#a33213be69f3df987c057d2667d0a3399bc7f625"
+dependencies = [
+ "failure",
+ "json",
+ "lazy_static",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn",
+]
+
+[[package]]
+name = "mutagen-transform"
+version = "0.2.0"
+source = "git+https://github.com/llogiq/mutagen#a33213be69f3df987c057d2667d0a3399bc7f625"
+dependencies = [
+ "mutagen-core",
+ "proc-macro2",
+]
+
 [[package]]
 name = "native-tls"
 version = "0.2.4"
@@ -488,11 +601,17 @@ version = "0.2.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "object"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693"
+
 [[package]]
 name = "openssl"
 version = "0.10.30"
@@ -500,7 +619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "foreign-types",
  "lazy_static",
  "libc",
@@ -680,6 +799,12 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "rustc-demangle"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
+
 [[package]]
 name = "ryu"
 version = "1.0.5"
@@ -724,6 +849,20 @@ name = "serde"
 version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
 
 [[package]]
 name = "serde_json"
@@ -748,7 +887,7 @@ version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "redox_syscall",
  "winapi 0.3.9",
@@ -765,13 +904,25 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "synstructure"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unicode-xid",
+]
+
 [[package]]
 name = "tempfile"
 version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "rand",
  "redox_syscall",
@@ -832,7 +983,7 @@ version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "log",
  "pin-project-lite",
  "tracing-core",

+ 6 - 1
Justfile

@@ -16,12 +16,17 @@ export DOG_DEBUG := ""
 
 # runs unit tests
 @test:
-    cargo test --all -- --quiet
+    cargo test --workspace -- --quiet
 
 # runs unit tests (in release mode)
 @test-release:
     cargo test --release --all --verbose
 
+# runs mutation tests
+@test-mutation:
+    cargo +nightly test    --package dns --features=dns/with_mutagen -- --quiet
+    cargo +nightly mutagen --package dns --features=dns/with_mutagen
+
 
 # runs extended tests
 @xtests:

+ 7 - 0
dns/Cargo.toml

@@ -12,3 +12,10 @@ log = "0.4"
 
 # protocol parsing
 byteorder = "1.3"
+
+# testing
+mutagen = { git = "https://github.com/llogiq/mutagen", optional = true }
+
+
+[features]
+with_mutagen = ["mutagen"]  # needs nightly

+ 1 - 0
dns/src/record/a.rs

@@ -19,6 +19,7 @@ impl Wire for A {
     const NAME: &'static str = "A";
     const RR_TYPE: u16 = 1;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let mut buf = Vec::new();
         for _ in 0 .. len {

+ 1 - 0
dns/src/record/aaaa.rs

@@ -19,6 +19,7 @@ impl Wire for AAAA {
     const NAME: &'static str = "AAAA";
     const RR_TYPE: u16 = 28;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let mut buf = Vec::new();
         for _ in 0 .. len {

+ 1 - 0
dns/src/record/caa.rs

@@ -24,6 +24,7 @@ impl Wire for CAA {
     const NAME: &'static str = "CAA";
     const RR_TYPE: u16 = 257;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let flags = c.read_u8()?;
         let tag_length = c.read_u8()?;

+ 1 - 0
dns/src/record/cname.rs

@@ -18,6 +18,7 @@ impl Wire for CNAME {
     const NAME: &'static str = "CNAME";
     const RR_TYPE: u16 = 5;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(_len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let domain = c.read_labels()?;
         Ok(CNAME { domain })

+ 1 - 0
dns/src/record/mx.rs

@@ -25,6 +25,7 @@ impl Wire for MX {
     const NAME: &'static str = "MX";
     const RR_TYPE: u16 = 15;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let preference = c.read_u16::<BigEndian>()?;
         let exchange = c.read_labels()?;

+ 1 - 0
dns/src/record/ns.rs

@@ -21,6 +21,7 @@ impl Wire for NS {
     const NAME: &'static str = "NS";
     const RR_TYPE: u16 = 2;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let nameserver = c.read_labels()?;
 

+ 1 - 0
dns/src/record/opt.rs

@@ -58,6 +58,7 @@ impl OPT {
     /// See §6.1.3 of the RFC, “OPT Record TTL Field Use”.
     ///
     /// Unlike the `Wire::read` function, this does not require a length.
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     pub fn read(c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let udp_payload_size = c.read_u16::<BigEndian>()?;  // replaces the class field
         let higher_bits = c.read_u8()?;                     // replaces the ttl field...

+ 1 - 0
dns/src/record/ptr.rs

@@ -24,6 +24,7 @@ impl Wire for PTR {
     const NAME: &'static str = "PTR";
     const RR_TYPE: u16 = 12;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(_len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let cname = c.read_labels()?;
         Ok(PTR { cname })

+ 1 - 0
dns/src/record/soa.rs

@@ -45,6 +45,7 @@ impl Wire for SOA {
     const NAME: &'static str = "SOA";
     const RR_TYPE: u16 = 6;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let mname = c.read_labels()?;
         let rname = c.read_labels()?;

+ 1 - 0
dns/src/record/srv.rs

@@ -32,6 +32,7 @@ impl Wire for SRV {
     const NAME: &'static str = "SRV";
     const RR_TYPE: u16 = 33;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let priority = c.read_u16::<BigEndian>()?;
         let weight   = c.read_u16::<BigEndian>()?;

+ 1 - 0
dns/src/record/txt.rs

@@ -24,6 +24,7 @@ impl Wire for TXT {
     const NAME: &'static str = "TXT";
     const RR_TYPE: u16 = 16;
 
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let mut buf = Vec::new();
         let mut total_len = 0_usize;

+ 1 - 0
dns/src/strings.rs

@@ -57,6 +57,7 @@ impl<W: Write> WriteLabels for W {
 
 const RECURSION_LIMIT: usize = 8;
 
+#[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
 fn read_string_recursive(name_buf: &mut Vec<u8>, c: &mut Cursor<&[u8]>, recursions: &mut Vec<u16>) -> Result<(), WireError> {
     loop {
         let byte = c.read_u8()?;

+ 4 - 0
dns/src/wire.rs

@@ -56,6 +56,7 @@ impl Request {
 impl Response {
 
     /// Reads bytes off of the given slice, parsing them into a response.
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     pub fn from_bytes(bytes: &[u8]) -> Result<Self, WireError> {
         debug!("Parsing bytes -> {:?}", bytes);
 
@@ -106,6 +107,7 @@ impl Query {
 
     /// Reads bytes from the given cursor, and parses them into a query with
     /// the given domain name.
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn from_bytes(qname: String, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let qtype = c.read_u16::<BigEndian>()?;
         let qclass = QClass::from_u16(c.read_u16::<BigEndian>()?);
@@ -119,6 +121,7 @@ impl Answer {
 
     /// Reads bytes from the given cursor, and parses them into an answer with
     /// the given domain name.
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn from_bytes(qname: String, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
         let qtype = c.read_u16::<BigEndian>()?;
         if qtype == OPT::RR_TYPE {
@@ -143,6 +146,7 @@ impl Record {
 
     /// Reads at most `len` bytes from the given curser, and parses them into
     /// a record structure depending on the type number, which has already been read.
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
     fn from_bytes(qtype: TypeInt, len: u16, c: &mut Cursor<&[u8]>) -> Result<Record, WireError> {
         use crate::record::*;