Replace false coverage exclusions with unreachable!() and tests
Two cov-excl markers hid invariant violations rather than genuinely
untestable code: the else branch of an all_maps loop and the Seq/Map
arm of to_kdl_value (only called on primitives). Both now panic via
unreachable!() and grcov excludes the unreachable! pattern automatically.

The Null branch of to_kdl_value was wrongly excluded — it fires when
serializing Vec<Option<T>> with None elements (Null is primitive, so
it reaches to_kdl_value through the all_primitive sequence path). Added
tests for both this path and the mixed-sequence Null path through
value_to_nodes.

Assisted-by: Claude Opus 4.6 via pi
change mmurooyuyytxvymskquopvmomnqlrryu
commit dcb9438e484381340f961da8847dcc15719e64ed
author Alpha Chen <alpha@kejadlen.dev>
date
parent qvwyozzn
diff --git a/justfile b/justfile
index cfcff33..de8afe8 100644
--- a/justfile
+++ b/justfile
@@ -23,7 +23,7 @@ coverage:
         -t covdir \
         --ignore-not-existing \
         --keep-only 'src/**' \
-        --excl-line 'cov-excl-line' \
+        --excl-line 'cov-excl-line|unreachable!' \
         --excl-start 'cov-excl-start' \
         --excl-stop 'cov-excl-stop')
     echo "$REPORT" | jq -r '
diff --git a/src/ser.rs b/src/ser.rs
index 0e61b12..b69159e 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -63,12 +63,12 @@ impl Value {
 
     fn to_kdl_value(&self) -> Option<KdlValue> {
         match self {
-            Value::Null => Some(KdlValue::Null), // cov-excl-line — Null is skipped by SerializeStruct/SerializeMap
+            Value::Null => Some(KdlValue::Null),
             Value::Bool(b) => Some(KdlValue::Bool(*b)),
             Value::Integer(i) => Some(KdlValue::Integer(*i)),
             Value::Float(f) => Some(KdlValue::Float(*f)),
             Value::String(s) => Some(KdlValue::String(s.clone())),
-            _ => None, // cov-excl-line — Seq/Map elements never reach to_kdl_value
+            _ => unreachable!("to_kdl_value is only called on primitive values"),
         }
     }
 }
@@ -96,15 +96,13 @@ fn value_to_doc(value: Value) -> Result<KdlDocument> {
 /// Convert a key-value pair to one or more KDL nodes.
 fn value_to_nodes(name: &str, value: Value) -> Result<Vec<KdlNode>> {
     match value {
-        // cov-excl-start — Null values are filtered out by SerializeStruct
-        // and SerializeMap (representing Option::None), so they never reach
-        // value_to_nodes as a standalone field.
+        // Null reaches value_to_nodes through the mixed-sequence `-`
+        // children path (e.g., Vec<Option<Vec<T>>> with a None element).
         Value::Null => {
             let mut node = KdlNode::new(name);
             node.push(KdlEntry::new(KdlValue::Null));
             Ok(vec![node])
         }
-        // cov-excl-stop
         Value::Bool(b) => {
             let mut node = KdlNode::new(name);
             node.push(KdlEntry::new(KdlValue::Bool(b)));
@@ -158,7 +156,9 @@ fn value_to_nodes(name: &str, value: Value) -> Result<Vec<KdlNode>> {
                         let children_doc = map_entries_to_doc(entries)?;
                         node.set_children(children_doc);
                         nodes.push(node);
-                    } // cov-excl-line — else is unreachable: all_maps was true
+                    } else {
+                        unreachable!("all_maps was true but element is not Map");
+                    }
                 }
                 Ok(nodes)
             } else {
diff --git a/tests/integration.rs b/tests/integration.rs
index 4a94365..8effdc6 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -2642,6 +2642,38 @@ fn serialize_vec_bools() {
     assert_eq!(val, roundtrip);
 }
 
+#[test]
+fn serialize_vec_option_with_nulls() {
+    // Exercises to_kdl_value Null branch: None serializes as Value::Null,
+    // is_primitive() is true for Null, so it reaches to_kdl_value.
+    #[derive(Serialize, Debug, PartialEq)]
+    struct S {
+        vals: Vec<Option<i32>>,
+    }
+    let val = S {
+        vals: vec![Some(1), None, Some(3)],
+    };
+    let output = serde_kdl::to_string(&val).unwrap();
+    assert!(output.contains("vals"));
+    assert!(output.contains("#null"));
+}
+
+#[test]
+fn serialize_mixed_seq_with_null() {
+    // Exercises value_to_nodes Null branch: a mixed sequence containing
+    // None alongside nested Vecs hits the `-` children path, which calls
+    // value_to_nodes("-", Value::Null).
+    #[derive(Serialize, Debug)]
+    struct S {
+        items: Vec<Option<Vec<i32>>>,
+    }
+    let val = S {
+        items: vec![Some(vec![1, 2]), None, Some(vec![3])],
+    };
+    let output = serde_kdl::to_string(&val).unwrap();
+    assert!(output.contains("#null"));
+}
+
 // ════════════════════════════════════════════════════════════════════════
 // Remaining coverage: ValueDeserializer::deserialize_any Integer/Float
 // ════════════════════════════════════════════════════════════════════════