use crate::{
agent::test_agent_id,
entry::{
entry_type::{test_entry_type, EntryType},
test_entry,
},
signature::{Provenance, Signature},
time::{test_iso_8601, Iso8601},
};
use holochain_persistence_api::cas::content::{Address, AddressableContent, Content};
use holochain_json_api::{
error::{JsonError, JsonResult},
json::JsonString,
};
use std::convert::TryInto;
#[derive(Clone, Debug, Serialize, Deserialize, DefaultJson)]
pub struct ChainHeader {
entry_type: EntryType,
entry_address: Address,
provenances: Vec<Provenance>,
link: Option<Address>,
link_same_type: Option<Address>,
link_update_delete: Option<Address>,
timestamp: Iso8601,
}
impl PartialEq for ChainHeader {
fn eq(&self, other: &ChainHeader) -> bool {
self.address() == other.address()
}
}
impl ChainHeader {
pub fn new(
entry_type: &EntryType,
entry_address: &Address,
provenances: &[Provenance],
link: &Option<Address>,
link_same_type: &Option<Address>,
link_update_delete: &Option<Address>,
timestamp: &Iso8601,
) -> Self {
ChainHeader {
entry_type: entry_type.to_owned(),
entry_address: entry_address.to_owned(),
provenances: provenances.to_owned(),
link: link.to_owned(),
link_same_type: link_same_type.to_owned(),
link_update_delete: link_update_delete.to_owned(),
timestamp: timestamp.to_owned(),
}
}
pub fn entry_type(&self) -> &EntryType {
&self.entry_type
}
pub fn timestamp(&self) -> &Iso8601 {
&self.timestamp
}
pub fn link(&self) -> Option<Address> {
self.link.clone()
}
pub fn entry_address(&self) -> &Address {
&self.entry_address
}
pub fn link_same_type(&self) -> Option<Address> {
self.link_same_type.clone()
}
pub fn link_update_delete(&self) -> Option<Address> {
self.link_update_delete.clone()
}
pub fn provenances(&self) -> &Vec<Provenance> {
&self.provenances
}
}
impl AddressableContent for ChainHeader {
fn content(&self) -> Content {
self.to_owned().into()
}
fn try_from_content(content: &Content) -> JsonResult<Self> {
content.to_owned().try_into()
}
}
pub fn test_chain_header() -> ChainHeader {
test_chain_header_with_sig("sig")
}
pub fn test_chain_header_with_sig(sig: &'static str) -> ChainHeader {
ChainHeader::new(
&test_entry_type(),
&test_entry().address(),
&test_provenances(sig),
&None,
&None,
&None,
&test_iso_8601(),
)
}
pub fn test_provenances(sig: &'static str) -> Vec<Provenance> {
vec![Provenance::new(
test_agent_id().address(),
Signature::from(sig),
)]
}
#[cfg(test)]
pub mod tests {
use crate::{
chain_header::{test_chain_header, test_provenances, ChainHeader},
entry::{
entry_type::{test_entry_type, test_entry_type_a, test_entry_type_b},
test_entry, test_entry_a, test_entry_b,
},
time::test_iso_8601,
};
use holochain_persistence_api::cas::content::{Address, AddressableContent};
pub fn test_chain_header_a() -> ChainHeader {
test_chain_header()
}
pub fn test_chain_header_b() -> ChainHeader {
ChainHeader::new(
&test_entry_type_b(),
&test_entry_b().address(),
&test_provenances("sig"),
&None,
&None,
&None,
&test_iso_8601(),
)
}
pub fn test_header_address() -> Address {
Address::from("Qmc1n5gbUU2QKW6is9ENTqmaTcEjYMBwNkcACCxe3bBDnd".to_string())
}
#[test]
fn eq() {
assert_eq!(test_chain_header(), test_chain_header());
assert_ne!(test_chain_header_a(), test_chain_header_b());
let entry_a = test_entry_a();
let entry_b = test_entry_b();
assert_ne!(
ChainHeader::new(
&entry_a.entry_type(),
&entry_a.address(),
&test_provenances("sig"),
&None,
&None,
&None,
&test_iso_8601(),
),
ChainHeader::new(
&entry_b.entry_type(),
&entry_a.address(),
&test_provenances("sig"),
&None,
&None,
&None,
&test_iso_8601(),
),
);
let entry = test_entry();
assert_ne!(
ChainHeader::new(
&entry.entry_type(),
&entry.address(),
&test_provenances("sig"),
&None,
&None,
&None,
&test_iso_8601(),
),
ChainHeader::new(
&entry.entry_type(),
&entry.address(),
&test_provenances("sig"),
&Some(test_chain_header().address()),
&None,
&None,
&test_iso_8601(),
),
);
}
#[test]
fn new() {
let chain_header = test_chain_header();
assert_eq!(chain_header.entry_address(), &test_entry().address());
assert_eq!(chain_header.link(), None);
assert_ne!(chain_header.address(), Address::new());
}
#[test]
fn entry_type() {
assert_eq!(test_chain_header().entry_type(), &test_entry_type());
}
#[test]
fn timestamp_test() {
assert_eq!(test_chain_header().timestamp(), &test_iso_8601());
}
#[test]
fn link_test() {
let chain_header_a = test_chain_header();
let entry_b = test_entry();
let chain_header_b = ChainHeader::new(
&entry_b.entry_type(),
&entry_b.address(),
&test_provenances("sig"),
&Some(chain_header_a.address()),
&None,
&None,
&test_iso_8601(),
);
assert_eq!(None, chain_header_a.link());
assert_eq!(Some(chain_header_a.address()), chain_header_b.link());
}
#[test]
fn entry_test() {
assert_eq!(test_chain_header().entry_address(), &test_entry().address());
}
#[test]
fn link_same_type_test() {
let chain_header_a = test_chain_header();
let entry_b = test_entry_b();
let chain_header_b = ChainHeader::new(
&entry_b.entry_type(),
&entry_b.address(),
&test_provenances("sig"),
&Some(chain_header_a.address()),
&None,
&None,
&test_iso_8601(),
);
let entry_c = test_entry_a();
let chain_header_c = ChainHeader::new(
&entry_c.entry_type(),
&entry_c.address(),
&test_provenances("sig"),
&Some(chain_header_b.address()),
&Some(chain_header_a.address()),
&None,
&test_iso_8601(),
);
assert_eq!(None, chain_header_a.link_same_type());
assert_eq!(None, chain_header_b.link_same_type());
assert_eq!(
Some(chain_header_a.address()),
chain_header_c.link_same_type()
);
}
#[test]
fn known_address() {
assert_eq!(
test_chain_header_a().address(),
test_chain_header().address()
);
}
#[test]
fn address_entry_content() {
assert_ne!(
test_chain_header_a().address(),
test_chain_header_b().address()
);
}
#[test]
fn address_entry_type() {
assert_ne!(
ChainHeader::new(
&test_entry_type_a(),
&test_entry().address(),
&test_provenances("sig"),
&None,
&None,
&None,
&test_iso_8601(),
)
.address(),
ChainHeader::new(
&test_entry_type_b(),
&test_entry().address(),
&test_provenances("sig"),
&None,
&None,
&None,
&test_iso_8601(),
)
.address(),
);
}
#[test]
fn address_chain_state() {
let entry = test_entry();
assert_ne!(
test_chain_header().address(),
ChainHeader::new(
&entry.entry_type(),
&entry.address(),
&test_provenances("sig"),
&Some(test_chain_header().address()),
&None,
&None,
&test_iso_8601(),
)
.address(),
);
}
#[test]
fn address_type_next() {
let entry = test_entry();
assert_ne!(
test_chain_header().address(),
ChainHeader::new(
&entry.entry_type(),
&entry.address(),
&test_provenances("sig"),
&None,
&Some(test_chain_header().address()),
&None,
&test_iso_8601(),
)
.address(),
);
}
}