diff --git a/bin/run b/bin/run index b5d1304..bdfcd07 100755 --- a/bin/run +++ b/bin/run @@ -69,6 +69,14 @@ test_metal () { shell "time cargo test -- --nocapture" } +build_watch () { + shell "cargo watch -- bin/run build" +} + +build_watch_clear () { + shell "cargo watch --clear -- bin/run build" +} + build () { run build_happ } diff --git a/zomes/hc_zome_trust_atom/src/lib.rs b/zomes/hc_zome_trust_atom/src/lib.rs index 6220612..28d2778 100644 --- a/zomes/hc_zome_trust_atom/src/lib.rs +++ b/zomes/hc_zome_trust_atom/src/lib.rs @@ -11,25 +11,32 @@ // #![warn(clippy::cargo)] use hdk::prelude::*; +use std::collections::BTreeMap; // public for sweettest; TODO can we fix this: pub mod trust_atom; pub use crate::trust_atom::*; - pub mod test_helpers; -// pub use crate::test_helpers; -entry_defs![StringTarget::entry_def()]; +entry_defs![test_helpers::StringTarget::entry_def(), Extra::entry_def()]; // INPUT TYPES +#[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)] +pub struct TrustAtomInput { + pub target: EntryHash, // TODO maybe target_entry_hash? + pub content: Option, + pub value: Option, + pub extra: Option>, +} + #[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)] pub struct QueryInput { pub source: Option, pub target: Option, pub content_full: Option, pub content_starts_with: Option, - pub min_rating: Option, + pub value_starts_with: Option, } #[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)] @@ -37,14 +44,28 @@ pub struct QueryMineInput { pub target: Option, pub content_full: Option, pub content_starts_with: Option, - pub min_rating: Option, + pub value_starts_with: Option, } // ZOME API FUNCTIONS #[hdk_extern] -pub fn create_trust_atom(input: TrustAtomInput) -> ExternResult<()> { - trust_atom::create(input.target, &input.content, &input.value, input.attributes) +pub fn create_trust_atom(input: TrustAtomInput) -> ExternResult { + let trust_atom = trust_atom::create(input.target, input.content, input.value, input.extra)?; + Ok(trust_atom) +} + +#[hdk_extern] +#[allow(clippy::needless_pass_by_value)] +pub fn get_extra(entry_hash: EntryHash) -> ExternResult { + let extra = trust_atom::get_extra(&entry_hash)?; + Ok(extra) +} + +#[hdk_extern] +pub fn calc_extra_hash(input: Extra) -> ExternResult { + let hash = trust_atom::calc_extra_hash(input)?; + Ok(hash) } #[hdk_extern] @@ -54,7 +75,7 @@ pub fn query(input: QueryInput) -> ExternResult> { input.target, input.content_full, input.content_starts_with, - input.min_rating, + input.value_starts_with, ) } @@ -64,15 +85,14 @@ pub fn query_mine(input: QueryMineInput) -> ExternResult> { input.target, input.content_full, input.content_starts_with, - input.min_rating, + input.value_starts_with, ) } - // TEST HELPERS #[hdk_extern] pub fn create_string_target(input: String) -> ExternResult { - crate::trust_atom::create_string_target(input) + crate::test_helpers::create_string_target(input) } #[hdk_extern] diff --git a/zomes/hc_zome_trust_atom/src/test_helpers.rs b/zomes/hc_zome_trust_atom/src/test_helpers.rs index 11f7259..10ace4d 100644 --- a/zomes/hc_zome_trust_atom/src/test_helpers.rs +++ b/zomes/hc_zome_trust_atom/src/test_helpers.rs @@ -2,6 +2,13 @@ use hdk::prelude::*; +#[derive(Serialize, Deserialize, Debug, SerializedBytes)] +struct StringLinkTag(String); + +#[hdk_entry(id = "restaurant", visibility = "public")] +#[derive(Clone)] +pub struct StringTarget(String); + pub fn list_links_for_base(base: EntryHash) -> ExternResult> { let links = hdk::link::get_links(base, None)?; @@ -19,8 +26,14 @@ pub fn list_links(base: EntryHash, link_tag_text: Option) -> ExternResul Ok(links) } -#[derive(Serialize, Deserialize, Debug, SerializedBytes)] -struct StringLinkTag(String); +pub fn create_string_target(input: String) -> ExternResult { + let string_target = StringTarget(input); + + create_entry(string_target.clone())?; + + let target_entry_hash = hash_entry(string_target)?; + Ok(target_entry_hash) +} fn link_tag(tag: String) -> ExternResult { let serialized_bytes: SerializedBytes = StringLinkTag(tag).try_into()?; diff --git a/zomes/hc_zome_trust_atom/src/trust_atom.rs b/zomes/hc_zome_trust_atom/src/trust_atom.rs index b5503db..5b2f001 100644 --- a/zomes/hc_zome_trust_atom/src/trust_atom.rs +++ b/zomes/hc_zome_trust_atom/src/trust_atom.rs @@ -15,95 +15,146 @@ enum LinkDirection { /// We may support JSON in the future to allow for more complex data structures @TODO #[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone, PartialEq)] pub struct TrustAtom { - pub source: String, + pub source: String, // TODO source_name pub target: String, - pub content: String, - pub value: String, pub source_entry_hash: EntryHashB64, pub target_entry_hash: EntryHashB64, - pub attributes: BTreeMap, + pub content: Option, + pub value: Option, + pub extra: Option>, } -#[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)] -pub struct TrustAtomInput { - pub target: EntryHash, - pub content: String, - pub value: String, - pub attributes: BTreeMap, -} - -#[hdk_entry(id = "restaurant", visibility = "public")] -#[derive(Clone)] -pub struct StringTarget(String); - const UNICODE_NUL_STR: &str = "\u{0}"; // Unicode NUL character -const UNICODE_NUL_BYTES: [u8; 1] = [0]; const LINK_TAG_HEADER: [u8; 2] = [197, 166]; // Unicode "Ŧ" // hex bytes: [0xC5][0xA6] const LINK_TAG_ARROW_FORWARD: [u8; 3] = [226, 134, 146]; // Unicode "→" // hex bytes: [0xE2][0x86][0x92] const LINK_TAG_ARROW_REVERSE: [u8; 3] = [226, 134, 169]; // Unicode "↩" // hex bytes: [0xE2][0x86][0xA9] -#[warn(clippy::needless_pass_by_value)] // TODO remove when `attributes` is used +#[hdk_entry(id = "extra", visibility = "public")] +#[derive(Clone)] +pub struct Extra { + pub fields: BTreeMap, // extra content +} + pub fn create( target: EntryHash, - content: &str, - value: &str, - _attributes: BTreeMap, -) -> ExternResult<()> { - let agent_info = agent_info()?; - let agent_address: EntryHash = agent_info.agent_initial_pubkey.into(); - - let normalized_value = normalize_value(value)?; + content: Option, + value: Option, + extra: Option>, +) -> ExternResult { + let agent_address: EntryHash = agent_info()?.agent_initial_pubkey.into(); let bucket = create_bucket()?; - let forward_link_tag = trust_atom_link_tag( - &LinkDirection::Forward, - vec![content, &normalized_value, bucket.as_str()], - ); - let reverse_link_tag = trust_atom_link_tag( - &LinkDirection::Reverse, - vec![content, &normalized_value, bucket.as_str()], - ); + let extra_entry_hash_string = match extra.clone() { + Some(x) => Some(create_extra(x)?), + None => None, + }; + + let chunks = [ + content.clone(), + normalize_value(value.clone())?, + Some(bucket), + extra_entry_hash_string, + ]; + let forward_link_tag = create_link_tag(&LinkDirection::Forward, &chunks); + let reverse_link_tag = create_link_tag(&LinkDirection::Reverse, &chunks); create_link(agent_address.clone(), target.clone(), forward_link_tag)?; - create_link(target, agent_address, reverse_link_tag)?; + create_link(target.clone(), agent_address.clone(), reverse_link_tag)?; + + let agent_address_entry: EntryHash = agent_address; + + let trust_atom = TrustAtom { + source: agent_address_entry.to_string(), + target: target.to_string(), + source_entry_hash: agent_address_entry.into(), + target_entry_hash: target.into(), + content, + value, + extra, + }; + Ok(trust_atom) +} - Ok(()) +fn create_bucket() -> ExternResult { + let bucket_bytes = random_bytes(9)?.into_vec(); + Ok(create_bucket_string(&bucket_bytes)) } -fn normalize_value(value_str: &str) -> ExternResult { - match Decimal::from_str(value_str) { - Ok(value_decimal) => { - match value_decimal.round_sf_with_strategy(9, RoundingStrategy::MidpointAwayFromZero) { - Some(value_decimal) => { - if value_decimal == Decimal::ONE { - Ok(".999999999".to_string()) - } else if value_decimal == Decimal::NEGATIVE_ONE { - Ok("-.999999999".to_string()) - } else if value_decimal > Decimal::NEGATIVE_ONE && value_decimal < Decimal::ONE { - let value_zero_stripped = value_decimal.to_string().replace("0.", "."); - Ok(value_zero_stripped) - } else { - Err(WasmError::Guest(format!( - "Value must be in the range -1..1, but got: `{}`", - value_str - ))) +fn create_bucket_string(bucket_bytes: &[u8]) -> String { + let mut bucket = String::new(); + for chunk in bucket_bytes { + let val = chunk; + bucket += (val % 10).to_string().as_str(); + } + bucket +} + +fn create_extra(input: BTreeMap) -> ExternResult { + let entry = Extra { fields: input }; + + create_entry(entry.clone())?; + + let entry_hash_string = calc_extra_hash(entry)?.to_string(); + Ok(entry_hash_string) +} + +pub fn calc_extra_hash(input: Extra) -> ExternResult { + let hash = hash_entry(input)?; + Ok(hash) +} + +fn normalize_value(value_str: Option) -> ExternResult> { + match value_str { + Some(value_str) => match Decimal::from_str(value_str.as_str()) { + Ok(value_decimal) => { + match value_decimal.round_sf_with_strategy(9, RoundingStrategy::MidpointAwayFromZero) { + Some(value_decimal) => { + if value_decimal == Decimal::ONE { + Ok(Some(".999999999".to_string())) + } else if value_decimal == Decimal::NEGATIVE_ONE { + Ok(Some("-.999999999".to_string())) + } else if value_decimal > Decimal::NEGATIVE_ONE && value_decimal < Decimal::ONE { + let value_zero_stripped = value_decimal.to_string().replace("0.", "."); + Ok(Some(value_zero_stripped)) + } else { + Err(WasmError::Guest(format!( + "Value must be in the range -1..1, but got: `{}`", + value_str + ))) + } } + None => Err(WasmError::Guest(format!( + "Value could not be processed: `{}`", + value_str + ))), } - None => Err(WasmError::Guest(format!( - "Value could not be processed: `{}`", - value_str - ))), + } + Err(error) => Err(WasmError::Guest(format!( + "Value could not be processed: `{}`. Error: `{}`", + value_str, error + ))), + }, + None => Ok(None), + } +} + +fn create_link_tag(link_direction: &LinkDirection, chunk_options: &[Option]) -> LinkTag { + let mut chunks: Vec = vec![]; + + for i in 0..chunk_options.len() { + if let Some(chunk) = chunk_options[i].clone() { + chunks.push(chunk); + if i < chunk_options.len() - 1 { + chunks.push(UNICODE_NUL_STR.to_string()); } } - Err(error) => Err(WasmError::Guest(format!( - "Value could not be processed: `{}`. Error: `{}`", - value_str, error - ))), } + + create_link_tag_metal(link_direction, chunks) } -fn trust_atom_link_tag(link_direction: &LinkDirection, mut chunks: Vec<&str>) -> LinkTag { +fn create_link_tag_metal(link_direction: &LinkDirection, chunks: Vec) -> LinkTag { let link_tag_arrow = match link_direction { LinkDirection::Forward => LINK_TAG_ARROW_FORWARD, LinkDirection::Reverse => LINK_TAG_ARROW_REVERSE, @@ -112,36 +163,47 @@ fn trust_atom_link_tag(link_direction: &LinkDirection, mut chunks: Vec<&str>) -> let mut link_tag_bytes = vec![]; link_tag_bytes.extend_from_slice(&LINK_TAG_HEADER); link_tag_bytes.extend_from_slice(&link_tag_arrow); - let content = chunks.remove(0); - link_tag_bytes.extend_from_slice(content.as_bytes()); for chunk in chunks { - link_tag_bytes.extend_from_slice(&UNICODE_NUL_BYTES); link_tag_bytes.extend_from_slice(chunk.as_bytes()); } + // debug!("link_tag: {:?}", String::from_utf8_lossy(&link_tag_bytes)); LinkTag(link_tag_bytes) } -fn create_bucket() -> ExternResult { - let bucket_bytes = random_bytes(9)?.into_vec(); - Ok(create_bucket_string(&bucket_bytes)) +pub fn get_extra(entry_hash: &EntryHash) -> ExternResult { + let element = get_element(entry_hash, GetOptions::default())?; + match element.entry() { + element::ElementEntry::Present(entry) => { + Extra::try_from(entry.clone()).or(Err(WasmError::Guest(format!( + "Couldn't convert Element entry {:?} into data type {}", + entry, + std::any::type_name::() + )))) + } + _ => Err(WasmError::Guest(format!( + "Element {:?} does not have an entry", + element + ))), + } } -fn create_bucket_string(bucket_bytes: &[u8]) -> String { - let mut bucket = String::new(); - for chunk in bucket_bytes { - let val = chunk; - bucket += (val % 10).to_string().as_str(); +fn get_element(entry_hash: &EntryHash, get_options: GetOptions) -> ExternResult { + match get(entry_hash.clone(), get_options)? { + Some(element) => Ok(element), + None => Err(WasmError::Guest(format!( + "There is no element at the hash {}", + entry_hash + ))), } - bucket } pub fn query_mine( target: Option, content_full: Option, content_starts_with: Option, - min_value: Option, + value_starts_with: Option, ) -> ExternResult> { let agent_address: EntryHash = agent_info()?.agent_initial_pubkey.into(); @@ -150,7 +212,7 @@ pub fn query_mine( target, content_full, content_starts_with, - min_value, + value_starts_with, )?; Ok(result) @@ -165,24 +227,8 @@ pub fn query( target: Option, content_full: Option, content_starts_with: Option, - min_value: Option, + value_starts_with: Option, ) -> ExternResult> { - let (full, starts_with, min_val) = match (content_full, content_starts_with, min_value) { - (Some(_content_full), Some(_content_starts_with), _) => { - return Err(WasmError::Guest( - "Exactly one query method must be specified, but not both".into(), - )) - } - (_, Some(_content_starts_with), Some(_min_value)) => { - return Err(WasmError::Guest( - "Must be full content to pass min value".into(), - )) - } - (Some(content_full), None, min_value) => (Some(content_full), None, min_value), - (None, Some(content_starts_with), None) => (None, Some(content_starts_with), None), - (None, None, min_value) => (None, None, min_value), - }; - let (link_direction, link_base) = match (source, target) { (Some(source), None) => (LinkDirection::Forward, source), (None, Some(target)) => (LinkDirection::Reverse, target), @@ -198,27 +244,29 @@ pub fn query( } }; - let link_tag = match (full, starts_with, link_direction.clone()) { - (Some(full), None, LinkDirection::Forward) => Some(trust_atom_link_tag( - &LinkDirection::Forward, - vec![&full, &min_val.unwrap_or("".to_string())], - )), - (Some(full), None, LinkDirection::Reverse) => Some(trust_atom_link_tag( - &LinkDirection::Reverse, - vec![&full, &min_val.unwrap_or("".to_string())], - )), - (None, Some(starts_with), LinkDirection::Forward) => Some(trust_atom_link_tag( - &LinkDirection::Forward, - vec![&starts_with], + let link_tag = match (content_full, content_starts_with, value_starts_with) { + (Some(_content_full), Some(_content_starts_with), _) => { + return Err(WasmError::Guest("Only one of `content_full` or `content_starts_with` can be used".into())) + } + (_, Some(_content_starts_with), Some(_value_starts_with)) => { + return Err(WasmError::Guest( + "Cannot use `value_starts_with` and `content_starts_with` arguments together; maybe try `content_full` instead?".into(), + )) + } + (Some(content_full), None, Some(value_starts_with)) => Some(create_link_tag( + &link_direction, + &[Some(content_full), Some(value_starts_with)], )), - (None, Some(starts_with), LinkDirection::Reverse) => Some(trust_atom_link_tag( - &LinkDirection::Reverse, - vec![&starts_with], + (Some(content_full), None, None) => { + Some(create_link_tag_metal(&link_direction, vec![content_full, UNICODE_NUL_STR.to_string()])) + } + (None, Some(content_starts_with), None) => Some(create_link_tag( + &link_direction, + &[Some(content_starts_with)], )), - (Some(_full), Some(_starts_with), _) => None, // error handled earlier - (None, None, _) => None, + (None, None, Some(value_starts_with)) => Some(create_link_tag(&link_direction, &[Some(value_starts_with)])), + (None, None, None) => None, }; - let links = get_links(link_base.clone(), link_tag)?; let trust_atoms = convert_links_to_trust_atoms(links, &link_direction, &link_base)?; @@ -269,45 +317,28 @@ fn convert_link_to_trust_atom( TrustAtom { source: link_base_b64.to_string(), target: link_target_b64.to_string(), - content, - value, source_entry_hash: link_base_b64, target_entry_hash: link_target_b64, - attributes: BTreeMap::new(), // TODO + content: Some(content), + value: Some(value), + extra: Some(BTreeMap::new()), // TODO } } LinkDirection::Reverse => { TrustAtom { - source: "".into(), // TODO - target: "".into(), // TODO - content: link_tag, // TODO - value: "999".into(), // TODO - source_entry_hash: link_target_b64, - target_entry_hash: link_base.clone().into(), - attributes: BTreeMap::new(), // TODO + source: link_target_b64.to_string(), // flipped for Reverse direction + target: link_base_b64.to_string(), // flipped for Reverse direction + source_entry_hash: link_target_b64, // flipped for Reverse direction + target_entry_hash: link_base_b64, // flipped for Reverse direction + content: Some(content), + value: Some(value), + extra: Some(BTreeMap::new()), // TODO } } }; Ok(trust_atom) } -pub fn create_string_target(input: String) -> ExternResult { - let string_target = StringTarget(input); - - create_entry(string_target.clone())?; - - let target_entry_hash = hash_entry(string_target)?; - Ok(target_entry_hash) -} - -#[derive(Serialize, Deserialize, Debug, SerializedBytes)] -struct StringLinkTag(String); - -pub fn link_tag(tag: String) -> ExternResult { - let serialized_bytes: SerializedBytes = StringLinkTag(tag).try_into()?; - Ok(LinkTag(serialized_bytes.bytes().clone())) -} - const fn tg_link_tag_header_length() -> usize { LINK_TAG_HEADER.len() + LINK_TAG_ARROW_FORWARD.len() } @@ -335,7 +366,7 @@ mod tests { ]; for value in valid_values { - normalize_value(value).unwrap(); + normalize_value(Some(value.to_string())).unwrap(); } } @@ -354,7 +385,7 @@ mod tests { for value in out_of_range_values { let expected_error_message = "Value must be in the range -1..1"; - let actual_error_message = normalize_value(value) + let actual_error_message = normalize_value(Some(value.to_string())) .expect_err(&format!("expected error for value `{}`, got", value)) .to_string(); assert!( @@ -395,7 +426,7 @@ mod tests { for value in non_numeric_values { let expected_error_message = "Value could not be processed"; - let actual_error_message = normalize_value(value) + let actual_error_message = normalize_value(Some(value.to_string())) .expect_err(&format!("expected error for value `{}`, got", value)) .to_string(); assert!( @@ -409,35 +440,36 @@ mod tests { #[test] fn test_normalize_value() { - assert_eq!(normalize_value("-.9").unwrap(), "-.900000000"); - assert_eq!(normalize_value("-.9000").unwrap(), "-.900000000"); - assert_eq!(normalize_value("-.900000000").unwrap(), "-.900000000"); - assert_eq!(normalize_value("-.9000000004").unwrap(), "-.900000000"); - assert_eq!(normalize_value("-.9000000005").unwrap(), "-.900000001"); - assert_eq!(normalize_value("-0.900000000").unwrap(), "-.900000000"); - - assert_eq!(normalize_value("0.8999999995").unwrap(), ".900000000"); - assert_eq!(normalize_value("0.7999999995").unwrap(), ".800000000"); - assert_eq!(normalize_value("-0.8999999995").unwrap(), "-.900000000"); - assert_eq!(normalize_value("-0.7999999995").unwrap(), "-.800000000"); - - assert_eq!(normalize_value("0.8999999994").unwrap(), ".899999999"); - assert_eq!(normalize_value("0.7999999994").unwrap(), ".799999999"); - assert_eq!(normalize_value("-0.8999999994").unwrap(), "-.899999999"); - assert_eq!(normalize_value("-0.7999999994").unwrap(), "-.799999999"); - - assert_eq!(normalize_value(".9").unwrap(), ".900000000"); - assert_eq!(normalize_value(".9000").unwrap(), ".900000000"); - assert_eq!(normalize_value(".900000000").unwrap(), ".900000000"); - assert_eq!(normalize_value("0.900000000").unwrap(), ".900000000"); - - // - - assert_eq!(normalize_value("1").unwrap(), ".999999999"); - assert_eq!(normalize_value("1.0").unwrap(), ".999999999"); - - assert_eq!(normalize_value("-1").unwrap(), "-.999999999"); - assert_eq!(normalize_value("-1.0").unwrap(), "-.999999999"); + let input_and_expected = [ + ["-.9", "-.900000000"], + ["-.9000", "-.900000000"], + ["-.900000000", "-.900000000"], + ["-.9000000004", "-.900000000"], + ["-.9000000005", "-.900000001"], + ["-0.900000000", "-.900000000"], + ["0.8999999995", ".900000000"], + ["0.7999999995", ".800000000"], + ["-0.8999999995", "-.900000000"], + ["-0.7999999995", "-.800000000"], + ["0.8999999994", ".899999999"], + ["0.7999999994", ".799999999"], + ["-0.8999999994", "-.899999999"], + ["-0.7999999994", "-.799999999"], + [".9", ".900000000"], + [".9000", ".900000000"], + [".900000000", ".900000000"], + ["0.900000000", ".900000000"], + // + ["1", ".999999999"], + ["1.0", ".999999999"], + ["-1", "-.999999999"], + ["-1.0", "-.999999999"], + ]; + + for [input, expected] in input_and_expected { + let normalized_value = normalize_value(Some(input.to_string())).unwrap().unwrap(); + assert_eq!(normalized_value, expected.to_string()); + } } #[test] diff --git a/zomes/hc_zome_trust_atom/tests/trust_atom_tests.rs b/zomes/hc_zome_trust_atom/tests/trust_atom_tests.rs index b730c76..648f7aa 100644 --- a/zomes/hc_zome_trust_atom/tests/trust_atom_tests.rs +++ b/zomes/hc_zome_trust_atom/tests/trust_atom_tests.rs @@ -44,7 +44,7 @@ pub async fn test_create_trust_atom() { let content: String = "sushi".into(); let value: String = ".8".into(); - let attributes: BTreeMap = BTreeMap::from([( + let extra: BTreeMap = BTreeMap::from([( "details".into(), "Excellent specials. The regular menu is so-so. Their coconut curry (special) is to die for" .into(), @@ -52,12 +52,12 @@ pub async fn test_create_trust_atom() { let trust_atom_input = TrustAtomInput { target: target_entry_hash.clone(), - content: content.clone(), - value, - attributes: attributes.clone(), + content: Some(content.clone()), + value: Some(value.clone()), + extra: Some(extra.clone()), }; - let _result: () = conductor + let _result: TrustAtom = conductor .call( &cell1.zome("trust_atom"), "create_trust_atom", @@ -88,7 +88,7 @@ pub async fn test_create_trust_atom() { let relevant_link_string = String::from_utf8(relevant_link_bytes).unwrap(); let chunks: Vec<&str> = relevant_link_string.split(unicode_nul).collect(); - assert_eq!(chunks.len(), 3); + assert_eq!(chunks.len(), 4); assert_eq!(chunks[0], "Ŧ→sushi"); assert_eq!(chunks[1], ".800000000"); @@ -97,9 +97,18 @@ pub async fn test_create_trust_atom() { assert_eq!(bucket.chars().count(), 9); assert!(bucket.chars().all(|c| c.is_digit(10))); + let expected_entry_hash = "uhCEkto76kYgGIZMzU6AbEzCx1HMRNzurwPaOdF2utJaP-33mdcdN"; let expected_link_tag_string = format!( - "{}{}{}{}{}{}{}", - "Ŧ", "→", "sushi", unicode_nul, ".800000000", unicode_nul, bucket + "{}{}{}{}{}{}{}{}{}", + "Ŧ", + "→", + "sushi", + unicode_nul, + ".800000000", + unicode_nul, + bucket, + unicode_nul, + expected_entry_hash ); assert_eq!(relevant_link_string, expected_link_tag_string); @@ -123,16 +132,25 @@ pub async fn test_create_trust_atom() { let relevant_link_bytes = link_tag_bytes.to_vec(); let relevant_link_string = String::from_utf8(relevant_link_bytes).unwrap(); let expected_link_tag_string = format!( - "{}{}{}{}{}{}{}", - "Ŧ", "↩", "sushi", unicode_nul, ".800000000", unicode_nul, bucket + "{}{}{}{}{}{}{}{}{}", + "Ŧ", + "↩", + "sushi", + unicode_nul, + ".800000000", + unicode_nul, + bucket, + unicode_nul, + expected_entry_hash ); assert_eq!(relevant_link_string, expected_link_tag_string); let chunks: Vec<&str> = relevant_link_string.split(unicode_nul).collect(); - assert_eq!(chunks.len(), 3); + assert_eq!(chunks.len(), 4); assert_eq!(chunks[0], "Ŧ↩sushi"); assert_eq!(chunks[1], ".800000000"); assert_eq!(chunks[2], bucket); + assert_eq!(chunks[3], expected_entry_hash); } #[tokio::test(flavor = "multi_thread")] @@ -151,15 +169,18 @@ pub async fn test_query_mine() { // CREATE TRUST ATOMS - let _result: () = conductor + let _result: TrustAtom = conductor .call( &cell1.zome("trust_atom"), "create_trust_atom", TrustAtomInput { target: target_entry_hash.clone(), - content: "sushi".into(), - value: "0.8".into(), - attributes: BTreeMap::new(), + content: Some("sushi".to_string()), + value: Some("0.8".to_string()), + extra: Some(BTreeMap::new()), + // extra: Some(BTreeMap::new([ + // ("creator_name".into(), "Bradley Fieldstone Jr.".into()), + // ])), }, ) .await; @@ -174,9 +195,7 @@ pub async fn test_query_mine() { target: None, content_starts_with: None, content_full: None, - min_rating: None, - // content_starts_with: Some("sushi".into()), - // min_rating: Some("0.0".into()), + value_starts_with: None, }, ) .await; @@ -192,11 +211,11 @@ pub async fn test_query_mine() { TrustAtom { source: source_entry_hash_b64.to_string(), target: target_entry_hash_b64.to_string(), - content: "sushi".to_string(), - value: ".800000000".to_string(), + content: Some("sushi".to_string()), + value: Some(".800000000".to_string()), source_entry_hash: source_entry_hash_b64, target_entry_hash: target_entry_hash_b64, - attributes: BTreeMap::new(), + extra: Some(BTreeMap::new()), } ); } @@ -220,15 +239,15 @@ pub async fn test_query_mine_with_content_starts_with() { let contents = vec!["sushi", "sushi joint", "sush"]; for content in contents { - let _result: () = conductor + let _result: TrustAtom = conductor .call( &cell1.zome("trust_atom"), "create_trust_atom", TrustAtomInput { target: target_entry_hash.clone(), - content: content.into(), - value: "0.8".into(), - attributes: BTreeMap::new(), + content: Some(content.into()), + value: Some("0.8".into()), + extra: Some(BTreeMap::new()), }, ) .await; @@ -241,10 +260,10 @@ pub async fn test_query_mine_with_content_starts_with() { "query_mine", QueryMineInput { target: None, - content_starts_with: Some("sushi".into()), content_full: None, - min_rating: None, - // min_rating: Some("0.0".into()), + content_starts_with: Some("sushi".into()), + value_starts_with: None, + // value_starts_with: Some("0.0".into()), }, ) .await; @@ -257,7 +276,10 @@ pub async fn test_query_mine_with_content_starts_with() { ]; actual.sort(); - assert_eq!(actual, ["sushi", "sushi joint"]); + assert_eq!( + actual, + [Some("sushi".to_string()), Some("sushi joint".to_string())] + ); } #[tokio::test(flavor = "multi_thread")] @@ -279,15 +301,15 @@ pub async fn test_query_mine_with_content_full() { let content_fulls = vec!["sushi", "sushi joint", "sush"]; for content_full in content_fulls { - let _result: () = conductor + let _result: TrustAtom = conductor .call( &cell1.zome("trust_atom"), "create_trust_atom", TrustAtomInput { target: target_entry_hash.clone(), - content: content_full.into(), - value: "0.8".into(), - attributes: BTreeMap::new(), + content: Some(content_full.into()), + value: Some("0.8".into()), + extra: Some(BTreeMap::new()), }, ) .await; @@ -300,10 +322,10 @@ pub async fn test_query_mine_with_content_full() { "query_mine", QueryMineInput { target: None, - content_starts_with: None, content_full: Some("sushi".into()), - min_rating: None, - // min_rating: Some("0.0".into()), + content_starts_with: None, + value_starts_with: None, + // value_starts_with: Some("0.0".into()), }, ) .await; @@ -312,7 +334,7 @@ pub async fn test_query_mine_with_content_full() { assert_eq!( trust_atoms_from_query[0].clone().content, - "sushi".to_string() + Some("sushi".to_string()) ); } @@ -353,3 +375,79 @@ pub async fn setup_conductors(n: usize) -> (SweetConductorBatch, Vec