From c70eb69ed6f1f8cbb670705a796a3c33dcccb466 Mon Sep 17 00:00:00 2001
From: Tom Alexander <tom@fizz.buzz>
Date: Sat, 7 Oct 2023 01:24:32 -0400
Subject: [PATCH] Compare radio target properties.

---
 src/compare/diff.rs      | 28 +++++++++++++++++++++++-----
 src/parser/radio_link.rs | 18 ++++++++++++------
 src/types/object.rs      |  1 +
 3 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/src/compare/diff.rs b/src/compare/diff.rs
index 426f42e..c08e559 100644
--- a/src/compare/diff.rs
+++ b/src/compare/diff.rs
@@ -1,5 +1,6 @@
 use std::borrow::Cow;
-// TODO: Add a check for unexpected keys in the properties
+// TODO: Update all to use the macro to assert there are no unexpected keys.
+// TODO: Check all compare funtions for whether they correctly iterate children.
 use std::collections::BTreeSet;
 use std::collections::HashSet;
 
@@ -2893,14 +2894,31 @@ fn compare_radio_link<'b, 's>(
 }
 
 fn compare_radio_target<'b, 's>(
-    _source: &'s str,
+    source: &'s str,
     emacs: &'b Token<'s>,
     rust: &'b RadioTarget<'s>,
 ) -> Result<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
-    let this_status = DiffStatus::Good;
-    let message = None;
+    let children = emacs.as_list()?;
+    let mut this_status = DiffStatus::Good;
+    let mut child_status = Vec::new();
+    let mut message = None;
 
-    // TODO: Compare :value
+    if let Some((new_status, new_message)) = compare_properties!(
+        emacs,
+        rust,
+        (
+            EmacsField::Required(":value"),
+            |r| Some(r.value),
+            compare_property_quoted_string
+        )
+    )? {
+        this_status = new_status;
+        message = new_message;
+    }
+
+    for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) {
+        child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?);
+    }
 
     Ok(DiffResult {
         status: this_status,
diff --git a/src/parser/radio_link.rs b/src/parser/radio_link.rs
index c5a4ac4..5edd8b6 100644
--- a/src/parser/radio_link.rs
+++ b/src/parser/radio_link.rs
@@ -2,6 +2,8 @@ use nom::branch::alt;
 use nom::bytes::complete::tag;
 use nom::character::complete::line_ending;
 use nom::character::complete::space0;
+use nom::combinator::consumed;
+use nom::combinator::map;
 use nom::combinator::verify;
 use nom::multi::many_till;
 
@@ -108,13 +110,16 @@ pub(crate) fn radio_target<'b, 'g, 'r, 's>(
     });
     let parser_context = context.with_additional_node(&parser_context);
 
-    let (remaining, (children, _exit_contents)) = verify(
-        many_till(
-            parser_with_context!(minimal_set_object)(&parser_context),
-            parser_with_context!(exit_matcher_parser)(&parser_context),
+    let (remaining, (raw_value, children)) = consumed(verify(
+        map(
+            many_till(
+                parser_with_context!(minimal_set_object)(&parser_context),
+                parser_with_context!(exit_matcher_parser)(&parser_context),
+            ),
+            |(children, _)| children,
         ),
-        |(children, _exit_contents)| !children.is_empty(),
-    )(remaining)?;
+        |children: &Vec<_>| !children.is_empty(),
+    ))(remaining)?;
 
     let (remaining, _closing) = tag(">>>")(remaining)?;
     let (remaining, _trailing_whitespace) =
@@ -124,6 +129,7 @@ pub(crate) fn radio_target<'b, 'g, 'r, 's>(
         remaining,
         RadioTarget {
             source: source.into(),
+            value: raw_value.into(),
             children,
         },
     ))
diff --git a/src/types/object.rs b/src/types/object.rs
index a177d41..8a76234 100644
--- a/src/types/object.rs
+++ b/src/types/object.rs
@@ -90,6 +90,7 @@ pub struct RegularLink<'s> {
 #[derive(Debug, PartialEq)]
 pub struct RadioTarget<'s> {
     pub source: &'s str,
+    pub value: &'s str,
     pub children: Vec<Object<'s>>,
 }