use crate::{Multibase, Version, parameters::Parameters, witness::Witnesses};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Parameters1_0 {
#[serde(skip)]
pub pre_rotation_active: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scid: Option<Arc<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub update_keys: Option<Arc<Vec<Multibase>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub portable: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_key_hashes: Option<Arc<Vec<Multibase>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub witness: Option<Arc<Witnesses>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub watchers: Option<Arc<Vec<String>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deactivated: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ttl: Option<u32>,
}
impl Default for Parameters1_0 {
fn default() -> Self {
Parameters1_0 {
pre_rotation_active: false,
method: Some("did:webvh:1.0".to_string()),
scid: None,
update_keys: None,
portable: None,
next_key_hashes: None,
witness: None,
watchers: None,
deactivated: None,
ttl: Some(3600),
}
}
}
impl From<Parameters> for Parameters1_0 {
fn from(value: Parameters) -> Self {
Parameters1_0 {
deactivated: value.deactivated,
pre_rotation_active: value.pre_rotation_active,
method: value.method.map(|_| Version::V1_0.to_string()),
next_key_hashes: value.next_key_hashes.clone(),
scid: value.scid.clone(),
ttl: value.ttl,
update_keys: value.update_keys.clone(),
portable: value.portable,
witness: value.witness.clone(),
watchers: value.watchers.clone(),
}
}
}
impl From<Parameters1_0> for Parameters {
fn from(value: Parameters1_0) -> Parameters {
Parameters {
deactivated: value.deactivated,
pre_rotation_active: value.pre_rotation_active,
method: value.method.map(|_| Version::V1_0),
next_key_hashes: value.next_key_hashes.clone(),
scid: value.scid.clone(),
ttl: value.ttl,
update_keys: value.update_keys.clone(),
portable: value.portable,
witness: value.witness.clone(),
watchers: value.watchers.clone(),
active_update_keys: Arc::new(Vec::new()), active_witness: None, }
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::{
Multibase, SCID_HOLDER,
test_utils::TEST_UPDATE_KEY,
witness::{Witness, Witnesses},
};
use super::Parameters;
#[test]
fn watchers_absent_serialize() {
let parameters = Parameters {
watchers: None,
..Default::default()
};
let values = serde_json::to_value(parameters).unwrap();
assert!(values.get("watchers").is_none())
}
#[test]
fn diff_no_changes_full() {
let old_params = Parameters {
method: Some(crate::Version::V1_0),
scid: Some(Arc::new("scid123".to_string())),
update_keys: Some(Arc::new(vec![
Multibase::new(TEST_UPDATE_KEY),
Multibase::new("z6MkqUa1LbqZ7EpevqrFC7XHAWM8CE49AKFWVjyu543NfVAp"),
])),
portable: Some(true),
next_key_hashes: Some(Arc::new(vec![
Multibase::new("zQmS6fKbreQixpa6JueaSuDiL2VQAGosC45TDQdKHf5E155"),
Multibase::new("zQmctZhRGCKrE2R58K9rkfA1aUL74mecrrJRvicz42resii"),
])),
witness: Some(Arc::new(Witnesses::Value {
threshold: 2,
witnesses: vec![
Witness {
id: Multibase::new("witness1"),
},
Witness {
id: Multibase::new("witness2"),
},
],
})),
watchers: Some(Arc::new(vec!["watcher1".to_string()])),
deactivated: Some(false),
ttl: Some(3600),
..Default::default()
};
let new_params = old_params.clone();
let result = old_params.diff(&new_params).expect("Diff failed");
assert_eq!(serde_json::to_string(&result).unwrap(), "{}");
}
#[test]
fn diff_no_changes_empty() {
let old_params = Parameters {
method: Some(crate::Version::V1_0),
..Default::default()
};
let new_params = old_params.clone();
let result = old_params.diff(&new_params).expect("Diff failed");
assert_eq!(serde_json::to_string(&result).unwrap(), "{}");
}
#[test]
fn diff_no_changes_method() {
let old_params = Parameters::default();
let new_params = Parameters {
method: Some(crate::Version::V1_0),
..Default::default()
};
let result = old_params.diff(&new_params).expect("Diff failed");
assert_eq!(serde_json::to_string(&result).unwrap(), "{}");
}
#[test]
fn pre_rotation_active() {
let first_params = Parameters {
update_keys: Some(Arc::new(vec![Multibase::new(TEST_UPDATE_KEY)])),
next_key_hashes: Some(Arc::new(vec![Multibase::new(
"zQmS6fKbreQixpa6JueaSuDiL2VQAGosC45TDQdKHf5E155",
)])),
scid: Some(Arc::new(SCID_HOLDER.to_string())),
..Default::default()
};
let validated = first_params
.validate(None)
.expect("First Log Entry should be valid");
assert!(validated.pre_rotation_active);
}
#[test]
fn diff_tri_state_absent() {
let diff = Parameters::diff_tri_state::<String>(&None, &None, "test");
assert!(diff.is_ok_and(|a| a.is_none()));
}
#[test]
fn diff_tri_state_empty() {
let diff = Parameters::diff_tri_state::<String>(&None, &Some(Arc::new(Vec::new())), "test")
.expect("Parameters::diff_update_keys() error");
assert!(diff.is_some_and(|a| a.is_empty()));
let diff = Parameters::diff_tri_state::<String>(
&Some(Arc::new(vec!["test".to_string()])),
&Some(Arc::new(Vec::new())),
"test",
)
.expect("Parameters::diff_update_keys() error");
assert!(diff.is_some_and(|a| a.is_empty()));
}
#[test]
fn diff_tri_state_double_empty() {
let diff = Parameters::diff_tri_state::<String>(
&Some(Arc::new(Vec::new())),
&Some(Arc::new(Vec::new())),
"test",
)
.expect("Both empty should not error");
assert!(diff.is_none());
}
#[test]
fn diff_tri_state_value() {
let test = Some(Arc::new(vec!["test".to_string()]));
let diff = Parameters::diff_tri_state::<String>(&None, &test.clone(), "test")
.expect("Parameters::diff_update_keys error");
assert!(diff == test);
}
#[test]
fn diff_tri_state_same_value() {
let diff = Parameters::diff_tri_state::<String>(
&Some(Arc::new(vec!["test".to_string()])),
&Some(Arc::new(vec!["test".to_string()])),
"test",
)
.expect("Parameters::diff_update_keys error");
assert!(diff.is_none());
}
#[test]
fn diff_tri_state_different_value() {
let diff = Parameters::diff_tri_state::<String>(
&Some(Arc::new(vec!["old".to_string()])),
&Some(Arc::new(vec!["new".to_string()])),
"test",
)
.expect("Parameters::diff_update_keys error");
assert!(diff.is_some_and(|a| a.first().unwrap().as_str() == "new"));
}
fn first_entry_params() -> Parameters {
Parameters {
scid: Some(Arc::new(SCID_HOLDER.to_string())),
update_keys: Some(Arc::new(vec![Multibase::new(TEST_UPDATE_KEY)])),
..Default::default()
}
}
fn subsequent_entry_params() -> Parameters {
Parameters {
update_keys: Some(Arc::new(vec![Multibase::new(TEST_UPDATE_KEY)])),
..Default::default()
}
}
fn sample_witnesses() -> Arc<Witnesses> {
Arc::new(Witnesses::Value {
threshold: 1,
witnesses: vec![Witness {
id: Multibase::new("z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7lL8N8AC4Pp6"),
}],
})
}
fn sample_witnesses_2() -> Arc<Witnesses> {
Arc::new(Witnesses::Value {
threshold: 2,
witnesses: vec![
Witness {
id: Multibase::new("z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7lL8N8AC4Pp6"),
},
Witness {
id: Multibase::new("z6MkqUa1LbqZ7EpevqrFC7XHAWM8CE49AKFWVjyu543NfVAp"),
},
],
})
}
#[test]
fn validate_first_entry_witness_none() {
let params = first_entry_params();
let validated = params.validate(None).expect("Should succeed");
assert!(validated.witness.is_none());
assert!(validated.active_witness.is_none());
}
#[test]
fn validate_first_entry_witness_empty_object() {
let params = Parameters {
witness: Some(Arc::new(Witnesses::Empty {})),
..first_entry_params()
};
let validated = params
.validate(None)
.expect("witness: {} on first entry should succeed");
assert!(validated.witness.is_none());
assert!(validated.active_witness.is_none());
}
#[test]
fn validate_first_entry_witness_with_values() {
let params = Parameters {
witness: Some(sample_witnesses()),
..first_entry_params()
};
let validated = params.validate(None).expect("Should succeed");
assert!(validated.witness.is_some());
assert!(validated.active_witness.is_some());
assert!(!validated.witness.as_ref().unwrap().is_empty());
}
#[test]
fn validate_first_entry_witness_invalid_threshold() {
let params = Parameters {
witness: Some(Arc::new(Witnesses::Value {
threshold: 0,
witnesses: vec![Witness {
id: Multibase::new("z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7lL8N8AC4Pp6"),
}],
})),
..first_entry_params()
};
assert!(params.validate(None).is_err());
}
#[test]
fn validate_first_entry_witness_threshold_exceeds_count() {
let params = Parameters {
witness: Some(Arc::new(Witnesses::Value {
threshold: 3,
witnesses: vec![Witness {
id: Multibase::new("z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7lL8N8AC4Pp6"),
}],
})),
..first_entry_params()
};
assert!(params.validate(None).is_err());
}
#[test]
fn validate_subsequent_witness_absent_inherits_none() {
let previous = Parameters {
witness: None,
active_witness: None,
..first_entry_params()
};
let current = Parameters {
witness: None,
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert!(validated.witness.is_none());
assert!(validated.active_witness.is_none());
}
#[test]
fn validate_subsequent_witness_absent_inherits_value() {
let previous = Parameters {
witness: Some(sample_witnesses()),
active_witness: Some(sample_witnesses()),
..first_entry_params()
};
let current = Parameters {
witness: None,
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert!(validated.witness.is_some());
assert!(validated.active_witness.is_some());
}
#[test]
fn validate_subsequent_witness_empty_deactivates() {
let previous = Parameters {
witness: Some(sample_witnesses()),
active_witness: Some(sample_witnesses()),
..first_entry_params()
};
let current = Parameters {
witness: Some(Arc::new(Witnesses::Empty {})),
..subsequent_entry_params()
};
let validated = current
.validate(Some(&previous))
.expect("Deactivating witnesses should succeed");
assert!(validated.witness.is_none());
assert!(validated.active_witness.is_some());
}
#[test]
fn validate_subsequent_witness_new_value() {
let previous = Parameters {
witness: Some(sample_witnesses()),
active_witness: Some(sample_witnesses()),
..first_entry_params()
};
let current = Parameters {
witness: Some(sample_witnesses_2()),
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert_eq!(validated.witness, Some(sample_witnesses_2()));
assert_eq!(validated.active_witness, Some(sample_witnesses()));
}
#[test]
fn validate_subsequent_witness_activate_from_none() {
let previous = Parameters {
witness: None,
active_witness: None,
..first_entry_params()
};
let current = Parameters {
witness: Some(sample_witnesses()),
..subsequent_entry_params()
};
let validated = current
.validate(Some(&previous))
.expect("Activating witnesses should succeed");
assert_eq!(validated.witness, Some(sample_witnesses()));
assert!(validated.active_witness.is_none());
}
#[test]
fn diff_witness_both_absent() {
let diff = Parameters::diff_witness(&None, &None).expect("Should succeed");
assert!(diff.is_none());
}
#[test]
fn diff_witness_current_absent() {
let diff =
Parameters::diff_witness(&Some(sample_witnesses()), &None).expect("Should succeed");
assert!(diff.is_none());
}
#[test]
fn diff_witness_previous_absent_current_empty() {
let diff = Parameters::diff_witness(&None, &Some(Arc::new(Witnesses::Empty {})))
.expect("Should succeed");
assert!(diff.is_some());
assert!(diff.unwrap().is_empty());
}
#[test]
fn diff_witness_previous_value_current_empty() {
let diff = Parameters::diff_witness(
&Some(sample_witnesses()),
&Some(Arc::new(Witnesses::Empty {})),
)
.expect("Should succeed");
assert!(diff.is_some());
assert!(diff.unwrap().is_empty());
}
#[test]
fn diff_witness_both_empty() {
let diff = Parameters::diff_witness(
&Some(Arc::new(Witnesses::Empty {})),
&Some(Arc::new(Witnesses::Empty {})),
)
.expect("Both empty should not error");
assert!(diff.is_none());
}
#[test]
fn diff_witness_same_value() {
let diff = Parameters::diff_witness(&Some(sample_witnesses()), &Some(sample_witnesses()))
.expect("Should succeed");
assert!(diff.is_none());
}
#[test]
fn diff_witness_different_value() {
let diff = Parameters::diff_witness(&Some(sample_witnesses()), &Some(sample_witnesses_2()))
.expect("Should succeed");
assert_eq!(diff, Some(sample_witnesses_2()));
}
#[test]
fn diff_witness_absent_to_value() {
let diff =
Parameters::diff_witness(&None, &Some(sample_witnesses())).expect("Should succeed");
assert_eq!(diff, Some(sample_witnesses()));
}
#[test]
fn diff_witness_empty_to_value() {
let diff = Parameters::diff_witness(
&Some(Arc::new(Witnesses::Empty {})),
&Some(sample_witnesses()),
)
.expect("Should succeed");
assert_eq!(diff, Some(sample_witnesses()));
}
#[test]
fn witness_empty_serializes_to_empty_object() {
let w = Witnesses::Empty {};
let json = serde_json::to_string(&w).unwrap();
assert_eq!(json, "{}");
}
#[test]
fn witness_empty_deserializes_from_empty_object() {
let w: Witnesses = serde_json::from_str("{}").unwrap();
assert!(w.is_empty());
}
#[test]
fn witness_value_roundtrips() {
let w = Witnesses::Value {
threshold: 2,
witnesses: vec![
Witness {
id: Multibase::new("witness1"),
},
Witness {
id: Multibase::new("witness2"),
},
],
};
let json = serde_json::to_string(&w).unwrap();
let w2: Witnesses = serde_json::from_str(&json).unwrap();
assert_eq!(w, w2);
}
#[test]
fn parameters_with_witness_empty_serializes_without_witness() {
let params = Parameters {
witness: Some(Arc::new(Witnesses::Empty {})),
..first_entry_params()
};
let validated = params.validate(None).unwrap();
let json = serde_json::to_value(&validated).unwrap();
assert!(json.get("witness").is_none());
}
#[test]
fn validate_first_entry_watchers_none() {
let params = first_entry_params();
let validated = params.validate(None).expect("Should succeed");
assert!(validated.watchers.is_none());
}
#[test]
fn validate_first_entry_watchers_empty_array() {
let params = Parameters {
watchers: Some(Arc::new(Vec::new())),
..first_entry_params()
};
let validated = params
.validate(None)
.expect("watchers: [] on first entry should succeed");
assert!(validated.watchers.is_none());
}
#[test]
fn validate_first_entry_watchers_with_values() {
let params = Parameters {
watchers: Some(Arc::new(vec!["https://watcher.example.com".to_string()])),
..first_entry_params()
};
let validated = params.validate(None).expect("Should succeed");
assert!(validated.watchers.is_some());
assert_eq!(validated.watchers.as_ref().unwrap().len(), 1);
}
#[test]
fn validate_subsequent_watchers_absent_inherits_none() {
let previous = Parameters {
watchers: None,
..first_entry_params()
};
let current = Parameters {
watchers: None,
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert!(validated.watchers.is_none());
}
#[test]
fn validate_subsequent_watchers_absent_inherits_value() {
let previous = Parameters {
watchers: Some(Arc::new(vec!["https://watcher.example.com".to_string()])),
..first_entry_params()
};
let current = Parameters {
watchers: None,
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert_eq!(
validated.watchers,
Some(Arc::new(vec!["https://watcher.example.com".to_string()]))
);
}
#[test]
fn validate_subsequent_watchers_empty_deactivates() {
let previous = Parameters {
watchers: Some(Arc::new(vec!["https://watcher.example.com".to_string()])),
..first_entry_params()
};
let current = Parameters {
watchers: Some(Arc::new(Vec::new())),
..subsequent_entry_params()
};
let validated = current
.validate(Some(&previous))
.expect("Deactivating watchers should succeed");
assert!(validated.watchers.is_none());
}
#[test]
fn validate_subsequent_watchers_new_value() {
let previous = Parameters {
watchers: Some(Arc::new(vec!["https://old.example.com".to_string()])),
..first_entry_params()
};
let current = Parameters {
watchers: Some(Arc::new(vec!["https://new.example.com".to_string()])),
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert_eq!(
validated.watchers,
Some(Arc::new(vec!["https://new.example.com".to_string()]))
);
}
#[test]
fn validate_subsequent_watchers_activate_from_none() {
let previous = Parameters {
watchers: None,
..first_entry_params()
};
let current = Parameters {
watchers: Some(Arc::new(vec!["https://watcher.example.com".to_string()])),
..subsequent_entry_params()
};
let validated = current.validate(Some(&previous)).expect("Should succeed");
assert!(validated.watchers.is_some());
}
#[test]
fn diff_watchers_both_empty() {
let diff = Parameters::diff_tri_state::<String>(
&Some(Arc::new(Vec::new())),
&Some(Arc::new(Vec::new())),
"watchers",
)
.expect("Both empty watchers should not error");
assert!(diff.is_none());
}
#[test]
fn diff_watchers_value_to_empty() {
let diff = Parameters::diff_tri_state::<String>(
&Some(Arc::new(vec!["https://watcher.example.com".to_string()])),
&Some(Arc::new(Vec::new())),
"watchers",
)
.expect("Should succeed");
assert!(diff.is_some_and(|a| a.is_empty()));
}
#[test]
fn diff_watchers_absent_to_empty() {
let diff =
Parameters::diff_tri_state::<String>(&None, &Some(Arc::new(Vec::new())), "watchers")
.expect("Should succeed");
assert!(diff.is_some_and(|a| a.is_empty()));
}
#[test]
fn parameters_with_watchers_empty_serializes_without_watchers() {
let params = Parameters {
watchers: Some(Arc::new(Vec::new())),
..first_entry_params()
};
let validated = params.validate(None).unwrap();
let json = serde_json::to_value(&validated).unwrap();
assert!(json.get("watchers").is_none());
}
#[test]
fn diff_update_keys_pre_rotation_empty() {
let previous = Parameters {
pre_rotation_active: true,
..Default::default()
};
let current = Parameters {
update_keys: Some(Arc::new(Vec::new())),
..Default::default()
};
assert!(previous.diff(¤t).is_err());
}
#[test]
fn diff_update_keys_pre_rotation_none() {
let previous = Parameters {
pre_rotation_active: true,
..Default::default()
};
let current = Parameters {
update_keys: None,
..Default::default()
};
assert!(previous.diff(¤t).is_err());
}
use super::Parameters1_0;
fn assert_params_roundtrip(json: serde_json::Value) {
let params: Parameters1_0 =
serde_json::from_value(json.clone()).expect("Parameters1_0 deserialization failed");
let re_serialized =
serde_json::to_value(¶ms).expect("Parameters1_0 re-serialization failed");
assert_eq!(
json, re_serialized,
"Parameters1_0 round-trip must be lossless"
);
}
fn assert_field_absent_roundtrip(field: &str) {
let json = serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test-scid",
"updateKeys": ["z6Mkiq4dQWqVEbtpmFButES3mBQ87y61jihJ7Wsh1x3iA9yT"]
});
let params: Parameters1_0 = serde_json::from_value(json).unwrap();
let re_serialized = serde_json::to_value(¶ms).unwrap();
assert!(
re_serialized.get(field).is_none(),
"{field} must be absent when not in source JSON"
);
}
#[test]
fn roundtrip_all_empty_values() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "QmRYeabNZ8KSFrLXxWAK1VB5vx4XmU4w389T5xhp5qwVGS",
"updateKeys": ["z6Mkiq4dQWqVEbtpmFButES3mBQ87y61jihJ7Wsh1x3iA9yT"],
"portable": false,
"nextKeyHashes": [],
"watchers": [],
"witness": {},
"deactivated": false
}));
}
#[test]
fn roundtrip_all_actual_values() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "QmRYeabNZ8KSFrLXxWAK1VB5vx4XmU4w389T5xhp5qwVGS",
"updateKeys": ["z6Mkiq4dQWqVEbtpmFButES3mBQ87y61jihJ7Wsh1x3iA9yT"],
"portable": true,
"nextKeyHashes": ["zQmS6fKbreQixpa6JueaSuDiL2VQAGosC45TDQdKHf5E155"],
"watchers": ["https://watcher.example.com"],
"witness": {
"threshold": 1,
"witnesses": [{"id": "z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7lL8N8AC4Pp6"}]
},
"deactivated": false,
"ttl": 7200
}));
}
#[test]
fn roundtrip_minimal() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "QmRYeabNZ8KSFrLXxWAK1VB5vx4XmU4w389T5xhp5qwVGS",
"updateKeys": ["z6Mkiq4dQWqVEbtpmFButES3mBQ87y61jihJ7Wsh1x3iA9yT"]
}));
}
#[test]
fn roundtrip_method_absent() {
let json = serde_json::json!({
"scid": "test",
"updateKeys": ["key1"]
});
let params: Parameters1_0 = serde_json::from_value(json.clone()).unwrap();
let re_serialized = serde_json::to_value(¶ms).unwrap();
assert!(re_serialized.get("method").is_none());
assert_eq!(json, re_serialized);
}
#[test]
fn roundtrip_method_present() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"]
}));
}
#[test]
fn roundtrip_scid_absent() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"updateKeys": ["key1"]
}));
}
#[test]
fn roundtrip_scid_present() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "QmRYeabNZ8KSFrLXxWAK1VB5vx4XmU4w389T5xhp5qwVGS",
"updateKeys": ["key1"]
}));
}
#[test]
fn roundtrip_update_keys_absent() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test"
}));
}
#[test]
fn roundtrip_update_keys_empty() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": []
}));
}
#[test]
fn roundtrip_update_keys_with_values() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["z6Mkiq4dQWqVEbtpmFButES3mBQ87y61jihJ7Wsh1x3iA9yT", "z6MkqUa1LbqZ7EpevqrFC7XHAWM8CE49AKFWVjyu543NfVAp"]
}));
}
#[test]
fn roundtrip_portable_absent() {
assert_field_absent_roundtrip("portable");
}
#[test]
fn roundtrip_portable_false() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"portable": false
}));
}
#[test]
fn roundtrip_portable_true() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"portable": true
}));
}
#[test]
fn roundtrip_next_key_hashes_absent() {
assert_field_absent_roundtrip("nextKeyHashes");
}
#[test]
fn roundtrip_next_key_hashes_empty() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"nextKeyHashes": []
}));
}
#[test]
fn roundtrip_next_key_hashes_with_values() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"nextKeyHashes": ["zQmS6fKbreQixpa6JueaSuDiL2VQAGosC45TDQdKHf5E155", "zQmctZhRGCKrE2R58K9rkfA1aUL74mecrrJRvicz42resii"]
}));
}
#[test]
fn roundtrip_witness_absent() {
assert_field_absent_roundtrip("witness");
}
#[test]
fn roundtrip_witness_empty_object() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"witness": {}
}));
}
#[test]
fn roundtrip_witness_with_values() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"witness": {
"threshold": 2,
"witnesses": [
{"id": "z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7lL8N8AC4Pp6"},
{"id": "z6MkqUa1LbqZ7EpevqrFC7XHAWM8CE49AKFWVjyu543NfVAp"}
]
}
}));
}
#[test]
fn roundtrip_watchers_absent() {
assert_field_absent_roundtrip("watchers");
}
#[test]
fn roundtrip_watchers_empty() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"watchers": []
}));
}
#[test]
fn roundtrip_watchers_with_values() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"watchers": ["https://watcher1.example.com", "https://watcher2.example.com"]
}));
}
#[test]
fn roundtrip_deactivated_absent() {
assert_field_absent_roundtrip("deactivated");
}
#[test]
fn roundtrip_deactivated_false() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"deactivated": false
}));
}
#[test]
fn roundtrip_deactivated_true() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": [],
"deactivated": true
}));
}
#[test]
fn roundtrip_ttl_absent() {
assert_field_absent_roundtrip("ttl");
}
#[test]
fn roundtrip_ttl_zero() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"ttl": 0
}));
}
#[test]
fn roundtrip_ttl_default() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"ttl": 3600
}));
}
#[test]
fn roundtrip_ttl_custom() {
assert_params_roundtrip(serde_json::json!({
"method": "did:webvh:1.0",
"scid": "test",
"updateKeys": ["key1"],
"ttl": 86400
}));
}
}