Skip to content

Commit

Permalink
ensure that substate_id to_string and from_str impls are correct (test)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Sep 5, 2024
1 parent 6863eb7 commit 8dd22e6
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 41 deletions.
37 changes: 24 additions & 13 deletions dan_layer/engine_types/src/substate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,17 +362,9 @@ impl FromStr for SubstateId {
},
Some(("nftindex", rest)) => {
// nftindex_{resource_id}_{index}
let (resource, idx) = rest
.split_once('_')
.ok_or_else(|| InvalidSubstateIdFormat(s.to_string()))?;
let resource_addr =
ResourceAddress::from_hex(resource).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
let index = u64::from_str(idx).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;

Ok(SubstateId::NonFungibleIndex(NonFungibleIndexAddress::new(
resource_addr,
index,
)))
let addr =
NonFungibleIndexAddress::from_str(rest).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Ok(SubstateId::NonFungibleIndex(addr))
},
Some(("vault", addr)) => {
let id = VaultId::from_hex(addr).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Expand Down Expand Up @@ -723,11 +715,11 @@ impl SubstateDiff {
mod tests {
use super::*;

mod substate_address_parse {
mod substate_id_parse {
use super::*;

#[test]
fn it_parses_valid_substate_addresses() {
fn it_parses_valid_substate_ids() {
SubstateId::from_str("component_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff")
.unwrap()
.as_component_address()
Expand Down Expand Up @@ -755,5 +747,24 @@ mod tests {
.as_non_fungible_index_address()
.unwrap();
}

#[test]
fn it_parses_a_display_string() {
fn check(s: &str) {
let id = SubstateId::from_str(s).unwrap();
assert_eq!(id.to_string(), s);
}
check("component_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("vault_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("nft_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_str_SpecialNft");
check(
"nft_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fffffffff_uuid_7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
);
check("nftindex_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_0");
check("feeclaim_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("txreceipt_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("commitment_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
}
}
}
46 changes: 28 additions & 18 deletions dan_layer/template_lib/src/models/non_fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ use crate::{
Hash,
};

const DELIM: char = ':';

/// The unique identification of a non-fungible token inside it's parent resource
#[serde_as]
#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, Hash)]
Expand Down Expand Up @@ -74,7 +72,7 @@ impl NonFungibleId {
let type_name = self.type_name();
let mut s = String::with_capacity(type_name.len() + 1 + self.str_repr_len());
s.push_str(self.type_name());
s.push(DELIM);
s.push('_');

match self {
NonFungibleId::U256(uuid) => {
Expand Down Expand Up @@ -193,10 +191,10 @@ fn validate_nft_id_str(s: &str) -> Result<(), ParseNonFungibleIdError> {
impl Display for NonFungibleId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NonFungibleId::U256(v) => write!(f, "uuid:{}", Hash::from(*v)),
NonFungibleId::String(s) => write!(f, "str:{}", s),
NonFungibleId::Uint32(v) => write!(f, "u32:{}", v),
NonFungibleId::Uint64(v) => write!(f, "u64:{}", v),
NonFungibleId::U256(v) => write!(f, "uuid_{}", Hash::from(*v)),
NonFungibleId::String(s) => write!(f, "str_{}", s),
NonFungibleId::Uint32(v) => write!(f, "u32_{}", v),
NonFungibleId::Uint64(v) => write!(f, "u64_{}", v),
}
}
}
Expand Down Expand Up @@ -287,7 +285,11 @@ impl From<NonFungibleAddressContents> for NonFungibleAddress {

impl Display for NonFungibleAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} nft_{}", self.0.resource_address, self.0.id)
write!(f, "nft_")?;
for byte in self.resource_address().as_bytes() {
write!(f, "{:02x}", byte)?;
}
write!(f, "_{}", self.id())
}
}

Expand Down Expand Up @@ -437,21 +439,21 @@ mod tests {
#[test]
fn it_generates_correct_canonical_string() {
// u32
assert_eq!(NonFungibleId::from_u32(0).to_canonical_string(), "u32:0");
assert_eq!(NonFungibleId::from_u32(100000).to_canonical_string(), "u32:100000");
assert_eq!(NonFungibleId::from_u32(0).to_canonical_string(), "u32_0");
assert_eq!(NonFungibleId::from_u32(100000).to_canonical_string(), "u32_100000");
assert_eq!(
NonFungibleId::from_u32(u32::MAX).to_canonical_string(),
format!("u32:{}", u32::MAX)
format!("u32_{}", u32::MAX)
);

// u64
assert_eq!(NonFungibleId::from_u64(0).to_canonical_string(), "u64:0");
assert_eq!(NonFungibleId::from_u64(1).to_canonical_string(), "u64:1");
assert_eq!(NonFungibleId::from_u64(10).to_canonical_string(), "u64:10");
assert_eq!(NonFungibleId::from_u64(100).to_canonical_string(), "u64:100");
assert_eq!(NonFungibleId::from_u64(0).to_canonical_string(), "u64_0");
assert_eq!(NonFungibleId::from_u64(1).to_canonical_string(), "u64_1");
assert_eq!(NonFungibleId::from_u64(10).to_canonical_string(), "u64_10");
assert_eq!(NonFungibleId::from_u64(100).to_canonical_string(), "u64_100");
assert_eq!(
NonFungibleId::from_u64(u64::MAX).to_canonical_string(),
format!("u64:{}", u64::MAX)
format!("u64_{}", u64::MAX)
);

// uuid
Expand All @@ -462,17 +464,25 @@ mod tests {
.into_array()
)
.to_canonical_string(),
"uuid:736bab0c3af393a0423c578ddcf7e19b81086f6ecbbc148713e95da75ef8171d"
"uuid_736bab0c3af393a0423c578ddcf7e19b81086f6ecbbc148713e95da75ef8171d"
);

// string
assert_eq!(
NonFungibleId::try_from_string("hello_world")
.unwrap()
.to_canonical_string(),
"str:hello_world"
"str_hello_world"
);
}

#[test]
fn it_parses_a_display_string() {
let id = NonFungibleId::from_u32(123);
let s = id.to_string();
let id2 = NonFungibleId::try_from_canonical_string(&s).unwrap();
assert_eq!(id, id2);
}
}

mod serde_deser {
Expand Down
28 changes: 24 additions & 4 deletions dan_layer/template_lib/src/models/non_fungible_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,23 @@ impl NonFungibleIndexAddress {

impl Display for NonFungibleIndexAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} index_{}", self.resource_address, self.index)
write!(f, "nftindex_")?;
for byte in self.resource_address.as_bytes() {
write!(f, "{:02x}", byte)?;
}
write!(f, "_{}", self.index)
}
}

impl FromStr for NonFungibleIndexAddress {
type Err = NonFungibleIndexAddressParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let (resource, index) = s.split_once(" index_").ok_or(NonFungibleIndexAddressParseError)?;

// nftindex_{resource_id}_{index}
let s = s.strip_prefix("nftindex_").unwrap_or(s);
let (resource, index) = s.split_once('_').ok_or(NonFungibleIndexAddressParseError)?;
let resource_address = resource.parse().map_err(|_| NonFungibleIndexAddressParseError)?;
let index = index.parse().map_err(|_| NonFungibleIndexAddressParseError)?;

Ok(Self::new(resource_address, index))
}
}
Expand All @@ -84,3 +88,19 @@ impl Display for NonFungibleIndexAddressParseError {
write!(f, "Invalid non-fungible index address string")
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_parses_a_display_string() {
let address = NonFungibleIndexAddress::new(
ResourceAddress::from_hex("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaA").unwrap(),
123,
);
let display = address.to_string();
let parsed = NonFungibleIndexAddress::from_str(&display).unwrap();
assert_eq!(address, parsed);
}
}
4 changes: 2 additions & 2 deletions dan_layer/template_lib/src/resource/builder/confidential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl ConfidentialResourceBuilder {
/// ## Examples
///
/// Building a resource with a hook from within a component
/// ```rust
/// ```ignore
/// # use tari_template_lib::{caller_context::CallerContext, prelude::ResourceBuilder};
/// ResourceBuilder::confidential()
/// .with_authorization_hook(CallerContext::current_component_address(), "my_hook")
Expand All @@ -127,7 +127,7 @@ impl ConfidentialResourceBuilder {
///
/// Building a resource with a hook in a static template function. The address is allocated beforehand.
///
/// ```rust
/// ```ignore
/// # use tari_template_lib::{caller_context::CallerContext, prelude::ResourceBuilder};
/// let alloc = CallerContext::allocate_component_address();
/// ResourceBuilder::confidential()
Expand Down
4 changes: 2 additions & 2 deletions dan_layer/template_lib/src/resource/builder/fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl FungibleResourceBuilder {
/// ## Examples
///
/// Building a resource with a hook from within a component
/// ```rust
/// ```ignore
/// use tari_template_lib::{caller_context::CallerContext, prelude::ResourceBuilder};
/// ResourceBuilder::fungible()
/// .with_authorization_hook(CallerContext::current_component_address(), "my_hook")
Expand All @@ -115,7 +115,7 @@ impl FungibleResourceBuilder {
///
/// Building a resource with a hook in a static template function. The address is allocated beforehand.
///
/// ```rust
/// ```ignore
/// use tari_template_lib::{caller_context::CallerContext, prelude::ResourceBuilder};
/// let alloc = CallerContext::allocate_component_address();
/// ResourceBuilder::fungible()
Expand Down
4 changes: 2 additions & 2 deletions dan_layer/template_lib/src/resource/builder/non_fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl NonFungibleResourceBuilder {
/// ## Examples
///
/// Building a resource with a hook from within a component
/// ```rust
/// ```ignore
/// use tari_template_lib::{caller_context::CallerContext, prelude::ResourceBuilder};
/// ResourceBuilder::non_fungible()
/// .with_authorization_hook(CallerContext::current_component_address(), "my_hook")
Expand All @@ -124,7 +124,7 @@ impl NonFungibleResourceBuilder {
///
/// Building a resource with a hook in a static template function. The address is allocated beforehand.
///
/// ```rust
/// ```ignore
/// use tari_template_lib::{caller_context::CallerContext, prelude::ResourceBuilder};
/// let alloc = CallerContext::allocate_component_address();
/// ResourceBuilder::non_fungible()
Expand Down

0 comments on commit 8dd22e6

Please sign in to comment.