summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorD. Scott Boggs <scott@tams.tech>2023-02-12 12:30:11 -0500
committerD. Scott Boggs <scott@tams.tech>2024-04-08 08:56:16 -0400
commitaa94354c0f1b88455cf6d7ee3de79cecfbc30ade (patch)
tree247a3dd7620441e079eec7c6aaab96d180fb604c
parentbf359f5e7edf58c14746debea4753e0c2a321121 (diff)
Add Admin::Measure example test
-rw-r--r--entities/src/admin/measure.rs70
-rw-r--r--entities/src/conversion.rs53
2 files changed, 120 insertions, 3 deletions
diff --git a/entities/src/admin/measure.rs b/entities/src/admin/measure.rs
index 7d93d6c..08a39bc 100644
--- a/entities/src/admin/measure.rs
+++ b/entities/src/admin/measure.rs
@@ -14,13 +14,14 @@ pub struct Measure {
#[serde(with = "conversion::string_to_u64")]
pub total: u64,
/// A human-readable formatted value for this data item.
- pub human_value: String,
+ #[serde(default)]
+ pub human_value: Option<String>,
/// The numeric total associated with the requested measure, in the previous
/// period. Previous period is calculated by subtracting the start_at and
/// end_at dates, then offsetting both start and end dates backwards by the
/// length of the time period.
- #[serde(with = "conversion::string_to_u64")]
- pub previous_total: u64,
+ #[serde(with = "conversion::string_to_u64::option")]
+ pub previous_total: Option<u64>,
/// The data available for the requested measure, split into daily buckets.
pub data: Vec<Data>,
}
@@ -35,3 +36,66 @@ pub struct Data {
#[serde(with = "conversion::string_to_u64")]
pub value: u64,
}
+
+#[cfg(test)]
+mod tests {
+ use time::Month;
+
+ use super::*;
+
+ #[test]
+ fn test_measure_example() {
+ let example = r#"{
+ "key": "active_users",
+ "unit": null,
+ "total": "2",
+ "previous_total": "0",
+ "data": [
+ {
+ "date": "2022-09-14T00:00:00Z",
+ "value": "0"
+ },
+ {
+ "date": "2022-09-15T00:00:00Z",
+ "value": "0"
+ },
+ {
+ "date": "2022-09-16T00:00:00Z",
+ "value": "0"
+ },
+ {
+ "date": "2022-09-17T00:00:00Z",
+ "value": "1"
+ },
+ {
+ "date": "2022-09-18T00:00:00Z",
+ "value": "1"
+ },
+ {
+ "date": "2022-09-19T00:00:00Z",
+ "value": "1"
+ },
+ {
+ "date": "2022-09-20T00:00:00Z",
+ "value": "2"
+ },
+ {
+ "date": "2022-09-21T00:00:00Z",
+ "value": "1"
+ }
+ ]
+ }"#;
+ let subject: Measure = serde_json::from_str(example).unwrap();
+ assert_eq!(subject.key, MeasureKey::new("active_users"));
+ assert!(subject.unit.is_none());
+ assert_eq!(subject.total, 2);
+ assert_eq!(subject.previous_total, Some(0));
+ assert!(subject.human_value.is_none());
+ let data = &subject.data[0];
+ assert_eq!(data.value, 0);
+ let date = data.date.date();
+ assert_eq!(date.year(), 2022);
+ assert_eq!(date.month(), Month::September);
+ assert_eq!(date.day(), 14);
+ }
+} \ No newline at end of file
diff --git a/entities/src/conversion.rs b/entities/src/conversion.rs
index 04ae3b9..ccfaa81 100644
--- a/entities/src/conversion.rs
+++ b/entities/src/conversion.rs
@@ -36,6 +36,59 @@ pub(crate) mod string_to_u64 {
deserializer.deserialize_str(StringToIntVisitor)
}
+
+ pub(crate) mod option {
+ use serde::{
+ de::{self, Visitor},
+ Deserializer, Serializer,
+ };
+
+ pub(crate) fn serialize<S>(value: &Option<u64>, ser: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ if let Some(value) = value {
+ ser.serialize_str(&value.to_string())
+ } else {
+ ser.serialize_none()
+ }
+ }
+
+ pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct StringToIntVisitor;
+
+ impl<'v> Visitor<'v> for StringToIntVisitor {
+ type Value = Option<u64>;
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ formatter,
+ "a string which can be parsed as an unsigned, 64-bit integer"
+ )
+ }
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ let v: u64 = v
+ .parse()
+ .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &self))?;
+ Ok(Some(v))
+ }
+
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(None)
+ }
+ }
+
+ deserializer.deserialize_any(StringToIntVisitor)
+ }
+ }
}
pub(crate) mod maybe_empty_url {