use serde_json::{Map, Value};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct K8sWireIdentity {
pub api_version: &'static str,
pub kind: &'static str,
}
impl K8sWireIdentity {
pub const fn new(api_version: &'static str, kind: &'static str) -> Self {
Self { api_version, kind }
}
pub fn as_json(self) -> Value {
let mut m = Map::with_capacity(2);
m.insert(
"apiVersion".to_string(),
Value::String(self.api_version.to_string()),
);
m.insert("kind".to_string(), Value::String(self.kind.to_string()));
Value::Object(m)
}
pub fn resource_json(self, extras: Value) -> Value {
let mut m = match extras {
Value::Object(m) => m,
_ => Map::new(),
};
m.insert(
"apiVersion".to_string(),
Value::String(self.api_version.to_string()),
);
m.insert("kind".to_string(), Value::String(self.kind.to_string()));
Value::Object(m)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn new_pairs_api_version_and_kind_by_position() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
assert_eq!(id.api_version, "group.io/v1");
assert_eq!(id.kind, "Widget");
}
#[test]
fn new_is_const_reachable() {
const ID: K8sWireIdentity = K8sWireIdentity::new("g/v", "K");
assert_eq!(ID.api_version, "g/v");
assert_eq!(ID.kind, "K");
}
#[test]
fn as_json_emits_two_slot_object() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
let v = id.as_json();
let obj = v.as_object().expect("as_json emits an Object");
assert_eq!(obj.len(), 2);
assert_eq!(obj["apiVersion"], "group.io/v1");
assert_eq!(obj["kind"], "Widget");
}
#[test]
fn resource_json_merges_identity_with_extras() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
let out = id.resource_json(json!({
"metadata": {"name": "foo"},
"spec": {"replicas": 3},
}));
let obj = out.as_object().expect("resource_json emits an Object");
assert_eq!(obj["apiVersion"], "group.io/v1");
assert_eq!(obj["kind"], "Widget");
assert_eq!(obj["metadata"]["name"], "foo");
assert_eq!(obj["spec"]["replicas"], 3);
}
#[test]
fn resource_json_identity_slots_win_over_extras_collision() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
let out = id.resource_json(json!({
"apiVersion": "wrong.io/v0",
"kind": "WrongKind",
"metadata": {"name": "foo"},
}));
let obj = out.as_object().unwrap();
assert_eq!(obj["apiVersion"], "group.io/v1");
assert_eq!(obj["kind"], "Widget");
assert_eq!(obj["metadata"]["name"], "foo");
}
#[test]
fn resource_json_non_object_extras_returns_pure_identity() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
let out = id.resource_json(Value::Null);
let obj = out.as_object().unwrap();
assert_eq!(obj.len(), 2);
assert_eq!(obj["apiVersion"], "group.io/v1");
assert_eq!(obj["kind"], "Widget");
let out2 = id.resource_json(Value::String("scalar-extras".into()));
let obj2 = out2.as_object().unwrap();
assert_eq!(obj2.len(), 2);
assert_eq!(obj2["apiVersion"], "group.io/v1");
}
#[test]
fn resource_json_empty_object_extras_returns_pure_identity() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
let out = id.resource_json(json!({}));
let obj = out.as_object().unwrap();
assert_eq!(obj.len(), 2);
assert_eq!(obj["apiVersion"], "group.io/v1");
assert_eq!(obj["kind"], "Widget");
}
#[test]
fn as_json_and_resource_json_agree_on_identity_slots() {
let id = K8sWireIdentity::new("group.io/v1", "Widget");
let pure = id.as_json();
let composed = id.resource_json(json!({"metadata": {"name": "foo"}}));
assert_eq!(pure["apiVersion"], composed["apiVersion"]);
assert_eq!(pure["kind"], composed["kind"]);
}
#[test]
fn struct_equality_pins_the_pair_axis() {
let a = K8sWireIdentity::new("g/v1", "K");
let b = K8sWireIdentity::new("g/v1", "K");
let c = K8sWireIdentity::new("g/v2", "K");
let d = K8sWireIdentity::new("g/v1", "L");
assert_eq!(a, b);
assert_ne!(a, c);
assert_ne!(a, d);
}
}