Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions packages/rs-dpp/src/data_contract/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,4 +583,124 @@ mod tests {
}
}
}

mod bincode_roundtrip {
use super::*;
use bincode::config;

#[test]
fn v0_bincode_roundtrip_preserves_fields() {
let cfg = config::standard();
let original = DataContractConfig::V0(DataContractConfigV0 {
can_be_deleted: true,
readonly: true,
keeps_history: true,
documents_keep_history_contract_default: true,
documents_mutable_contract_default: false,
documents_can_be_deleted_contract_default: false,
requires_identity_encryption_bounded_key: Some(StorageKeyRequirements::Unique),
requires_identity_decryption_bounded_key: None,
});
let bytes = bincode::encode_to_vec(original, cfg).expect("encode");
let (decoded, _): (DataContractConfig, _) =
bincode::decode_from_slice(&bytes, cfg).expect("decode");
assert_eq!(decoded, original);
}

#[test]
fn v1_bincode_roundtrip_preserves_sized_integer_types() {
let cfg = config::standard();
let original = DataContractConfig::V1(DataContractConfigV1 {
can_be_deleted: false,
readonly: false,
keeps_history: false,
documents_keep_history_contract_default: false,
documents_mutable_contract_default: true,
documents_can_be_deleted_contract_default: true,
requires_identity_encryption_bounded_key: None,
requires_identity_decryption_bounded_key: None,
sized_integer_types: false,
});
let bytes = bincode::encode_to_vec(original, cfg).expect("encode");
let (decoded, _): (DataContractConfig, _) =
bincode::decode_from_slice(&bytes, cfg).expect("decode");
assert_eq!(decoded, original);
// And sized_integer_types is correctly false on the decoded copy
assert!(!decoded.sized_integer_types());
}
}

mod from_value_tests {
use super::*;
use platform_value::platform_value;

#[test]
fn from_value_yields_default_for_empty_object() {
// Empty object -> defaults; succeeds on the latest platform version
let value = platform_value!({});
let platform_version = PlatformVersion::latest();
let cfg = DataContractConfig::from_value(value, platform_version)
.expect("empty object should deserialize to defaults");
// All booleans should match defaults
assert_eq!(cfg.can_be_deleted(), DEFAULT_CONTRACT_CAN_BE_DELETED);
}
}

mod get_contract_configuration_properties_tests {
use super::*;
use platform_value::Value;
use std::collections::BTreeMap;

fn make_contract_map(can_be_deleted: bool, readonly: bool) -> BTreeMap<String, Value> {
let mut m = BTreeMap::new();
m.insert(
property::CAN_BE_DELETED.to_string(),
Value::Bool(can_be_deleted),
);
m.insert(property::READONLY.to_string(), Value::Bool(readonly));
m
}

#[test]
fn reads_booleans_from_map() {
let platform_version = PlatformVersion::latest();
// Use distinct values for both fields so a key mix-up (reading
// one field from the other's key) would fail the assertion.
for (can_be_deleted, readonly) in [(true, false), (false, true)] {
let contract = make_contract_map(can_be_deleted, readonly);
let cfg = DataContractConfig::get_contract_configuration_properties(
&contract,
platform_version,
)
.expect("should parse config from map");
assert_eq!(cfg.can_be_deleted(), can_be_deleted);
assert_eq!(cfg.readonly(), readonly);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[test]
fn missing_keys_fall_back_to_defaults() {
let platform_version = PlatformVersion::latest();
let empty: BTreeMap<String, Value> = BTreeMap::new();
let cfg =
DataContractConfig::get_contract_configuration_properties(&empty, platform_version)
.expect("should parse empty contract map");
// Defaults preserved
assert_eq!(cfg.can_be_deleted(), DEFAULT_CONTRACT_CAN_BE_DELETED);
assert_eq!(cfg.keeps_history(), DEFAULT_CONTRACT_KEEPS_HISTORY);
}

#[test]
fn non_bool_value_errors() {
let platform_version = PlatformVersion::latest();
let mut m: BTreeMap<String, Value> = BTreeMap::new();
m.insert(
property::CAN_BE_DELETED.to_string(),
Value::Text("not-a-bool".to_string()),
);
let result =
DataContractConfig::get_contract_configuration_properties(&m, platform_version);
assert!(result.is_err());
}
}
}
159 changes: 159 additions & 0 deletions packages/rs-dpp/src/voting/contender_structs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,162 @@ impl TryFrom<ContenderWithSerializedDocument> for FinalizedContenderWithSerializ
})
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::voting::contender_structs::contender::v0::ContenderWithSerializedDocumentV0;
use platform_value::Identifier;

mod finalized_resource_vote_choices_display {
use super::*;

#[test]
fn display_with_no_voters() {
let item = FinalizedResourceVoteChoicesWithVoterInfo {
resource_vote_choice: ResourceVoteChoice::Abstain,
voters: vec![],
};
let s = item.to_string();
assert!(s.contains("resource_vote_choice"));
assert!(s.contains("voters: []"));
}

#[test]
fn display_with_multiple_voters() {
let id1 = Identifier::new([1u8; 32]);
let id2 = Identifier::new([2u8; 32]);
let item = FinalizedResourceVoteChoicesWithVoterInfo {
resource_vote_choice: ResourceVoteChoice::Lock,
voters: vec![(id1, 1), (id2, 4)],
};
let s = item.to_string();
// Each voter rendered as id:strength and comma separated
assert!(s.contains(&format!("{}:1", id1)));
assert!(s.contains(&format!("{}:4", id2)));
assert!(s.contains(", "));
}
}

mod finalized_resource_vote_choices_encoding {
use super::*;
use bincode::config;

#[test]
fn roundtrip_preserves_data() {
let id = Identifier::new([7u8; 32]);
let original = FinalizedResourceVoteChoicesWithVoterInfo {
resource_vote_choice: ResourceVoteChoice::TowardsIdentity(id),
voters: vec![(id, 3)],
};
let cfg = config::standard();
let bytes = bincode::encode_to_vec(&original, cfg).expect("encode");
let (decoded, _): (FinalizedResourceVoteChoicesWithVoterInfo, _) =
bincode::decode_from_slice(&bytes, cfg).expect("decode");
assert_eq!(decoded, original);
}
}

mod finalized_contender_with_serialized_document_default {
use super::*;

#[test]
fn default_has_zero_fields() {
let fc = FinalizedContenderWithSerializedDocument::default();
assert_eq!(fc.identity_id, Identifier::default());
assert!(fc.serialized_document.is_empty());
assert_eq!(fc.final_vote_tally, 0);
}
}

mod try_from_contender_with_serialized_document {
use super::*;

#[test]
fn err_when_serialized_document_missing() {
let csd = ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
identity_id: Identifier::new([1u8; 32]),
serialized_document: None,
vote_tally: Some(10),
});
let result = FinalizedContenderWithSerializedDocument::try_from(csd);
match result {
Err(ProtocolError::CorruptedCodeExecution(msg)) => {
assert!(msg.contains("expected serialized document"));
}
_ => panic!("expected CorruptedCodeExecution error for missing document"),
}
}

#[test]
fn err_when_vote_tally_missing() {
let csd = ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
identity_id: Identifier::new([1u8; 32]),
serialized_document: Some(vec![1, 2, 3]),
vote_tally: None,
});
let result = FinalizedContenderWithSerializedDocument::try_from(csd);
match result {
Err(ProtocolError::CorruptedCodeExecution(msg)) => {
assert!(msg.contains("expected vote tally"));
}
_ => panic!("expected CorruptedCodeExecution error for missing vote tally"),
}
}

#[test]
fn ok_when_all_fields_present() {
let id = Identifier::new([9u8; 32]);
let doc = vec![0xAA, 0xBB, 0xCC];
let csd = ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
identity_id: id,
serialized_document: Some(doc.clone()),
vote_tally: Some(42),
});
let finalized =
FinalizedContenderWithSerializedDocument::try_from(csd).expect("should succeed");
assert_eq!(finalized.identity_id, id);
assert_eq!(finalized.serialized_document, doc);
assert_eq!(finalized.final_vote_tally, 42);
}
}

mod finalized_contender_with_serialized_document_equality {
use super::*;

#[test]
fn equal_structs_compare_equal() {
let id = Identifier::new([3u8; 32]);
let a = FinalizedContenderWithSerializedDocument {
identity_id: id,
serialized_document: vec![1, 2, 3],
final_vote_tally: 100,
};
let b = FinalizedContenderWithSerializedDocument {
identity_id: id,
serialized_document: vec![1, 2, 3],
final_vote_tally: 100,
};
assert_eq!(a, b);
// Clone preserves fields
let c = a.clone();
assert_eq!(a, c);
}

#[test]
fn different_tally_not_equal() {
let id = Identifier::new([3u8; 32]);
let a = FinalizedContenderWithSerializedDocument {
identity_id: id,
serialized_document: vec![1, 2, 3],
final_vote_tally: 100,
};
let b = FinalizedContenderWithSerializedDocument {
identity_id: id,
serialized_document: vec![1, 2, 3],
final_vote_tally: 101,
};
assert_ne!(a, b);
}
}
}
Loading
Loading