use newt_interaction::{ControlId, ControlValue, OptionId, SecretRef};
#[test]
fn a_toggle_cannot_be_submitted_as_a_string() {
for spelling in [
r#"{"kind":"toggle","on":"TRUE"}"#,
r#"{"kind":"toggle","on":"true"}"#,
r#"{"kind":"toggle","on":"1"}"#,
r#"{"kind":"toggle","on":"yes"}"#,
r#"{"kind":"toggle","value":true}"#,
] {
assert!(
serde_json::from_str::<ControlValue>(spelling).is_err(),
"a stringly toggle must not deserialize: {spelling}"
);
}
let real = ControlValue::Toggle { on: true };
assert_eq!(
serde_json::to_value(&real).unwrap()["on"],
serde_json::Value::Bool(true),
"a toggle travels as a bool, not as text"
);
}
#[test]
fn a_choice_names_a_control_not_free_text() {
let choice = ControlValue::Choice {
option: OptionId::new("allow-once").unwrap(),
};
let wire = serde_json::to_value(&choice).unwrap();
assert_eq!(wire["kind"], "choice");
assert_eq!(wire["option"], "allow-once");
assert!(OptionId::new("not an option id").is_err());
assert!(ControlId::new("not a control id").is_err());
}
#[test]
fn no_control_value_variant_can_carry_a_secret() {
let sealed = SecretRef::new("vault-handle-9").unwrap();
let value = ControlValue::Secret {
reference: sealed.clone(),
};
match &value {
ControlValue::Text { .. } | ControlValue::Toggle { .. } | ControlValue::Choice { .. } => {}
ControlValue::Secret { reference } => {
assert_eq!(reference.as_str(), "vault-handle-9");
}
}
let wire = serde_json::to_string(&value).unwrap();
assert!(wire.contains("vault-handle-9"));
assert!(
!wire.contains("password"),
"no plaintext path exists: {wire}"
);
}
#[test]
fn a_secret_reference_must_not_be_empty() {
assert!(SecretRef::new("").is_err());
}
#[test]
fn every_variant_round_trips() {
let values = vec![
ControlValue::Choice {
option: OptionId::new("deny").unwrap(),
},
ControlValue::Text {
text: "a typed answer".to_string(),
},
ControlValue::Toggle { on: false },
ControlValue::Secret {
reference: SecretRef::new("handle").unwrap(),
},
];
for value in values {
let json = serde_json::to_string(&value).unwrap();
let back: ControlValue = serde_json::from_str(&json).unwrap();
assert_eq!(back, value, "round trip changed the value: {json}");
}
}
#[test]
fn a_control_id_and_an_option_id_are_different_types() {
let submission = newt_interaction::Submission {
control: ControlId::new("decision").unwrap(),
value: ControlValue::Choice {
option: OptionId::new("deny").unwrap(),
},
};
let wire = serde_json::to_value(&submission).unwrap();
assert_eq!(wire["control"], "decision");
assert_eq!(wire["value"]["option"], "deny");
assert!(OptionId::new("not an option").is_err());
assert!(ControlId::new("not a control").is_err());
}