dpp/tests/
json_document.rs

1use crate::data_contract::accessors::v0::DataContractV0Setters;
2#[cfg(feature = "json-conversion")]
3use crate::data_contract::config::DataContractConfig;
4#[cfg(feature = "json-conversion")]
5use crate::data_contract::conversion::json::DataContractJsonConversionMethodsV0;
6#[cfg(any(feature = "state-transitions", feature = "factories"))]
7use crate::data_contract::created_data_contract::v0::CreatedDataContractV0;
8#[cfg(any(feature = "state-transitions", feature = "factories"))]
9use crate::data_contract::created_data_contract::CreatedDataContract;
10use crate::data_contract::document_type::accessors::DocumentTypeV0Getters;
11use crate::data_contract::document_type::DocumentTypeRef;
12use crate::document::{Document, DocumentV0};
13use crate::prelude::{DataContract, IdentityNonce};
14#[cfg(feature = "data-contract-cbor-conversion")]
15use crate::util::cbor_serializer::serializable_value_to_cbor;
16use crate::version::PlatformVersion;
17use crate::ProtocolError;
18use platform_value::{Identifier, ReplacementType};
19use std::fs::File;
20use std::io::BufReader;
21use std::path::Path;
22
23/// Reads a JSON file and converts it to serde_value.
24#[cfg(feature = "json-conversion")]
25pub fn json_document_to_json_value(
26    path: impl AsRef<Path>,
27) -> Result<serde_json::Value, ProtocolError> {
28    let file = File::open(path.as_ref()).map_err(|_| {
29        ProtocolError::FileNotFound(format!(
30            "file not found at path {}",
31            path.as_ref().to_str().unwrap()
32        ))
33    })?;
34
35    let reader = BufReader::new(file);
36    serde_json::from_reader(reader)
37        .map_err(|_| ProtocolError::DecodingError("error decoding value from document".to_string()))
38}
39
40/// Reads a JSON file and converts it to serde_value.
41pub fn json_document_to_platform_value(
42    path: impl AsRef<Path>,
43) -> Result<platform_value::Value, ProtocolError> {
44    let file = File::open(path.as_ref()).map_err(|_| {
45        ProtocolError::FileNotFound(format!(
46            "file not found at path {}",
47            path.as_ref().to_str().unwrap()
48        ))
49    })?;
50
51    let reader = BufReader::new(file);
52    serde_json::from_reader(reader)
53        .map_err(|_| ProtocolError::DecodingError("error decoding value from document".to_string()))
54}
55
56/// Reads a JSON file and converts it to CBOR.
57#[cfg(feature = "data-contract-cbor-conversion")]
58pub fn json_document_to_cbor(
59    path: impl AsRef<Path>,
60    protocol_version: Option<u32>,
61) -> Result<Vec<u8>, ProtocolError> {
62    let json = json_document_to_json_value(path)?;
63    serializable_value_to_cbor(&json, protocol_version)
64}
65
66/// Reads a JSON file and converts it a contract.
67#[cfg(feature = "json-conversion")]
68pub fn json_document_to_contract(
69    path: impl AsRef<Path>,
70    full_validation: bool,
71    platform_version: &PlatformVersion,
72) -> Result<DataContract, ProtocolError> {
73    let value = json_document_to_json_value(path)?;
74
75    DataContract::from_json(value, full_validation, platform_version)
76}
77
78#[cfg(all(
79    any(feature = "state-transitions", feature = "factories"),
80    feature = "json-conversion"
81))]
82/// Reads a JSON file and converts it a contract.
83pub fn json_document_to_created_contract(
84    path: impl AsRef<Path>,
85    identity_nonce: IdentityNonce,
86    full_validation: bool,
87    platform_version: &PlatformVersion,
88) -> Result<CreatedDataContract, ProtocolError> {
89    let mut data_contract = json_document_to_contract(path, full_validation, platform_version)?;
90
91    // JSON fixtures typically lack a config field, so they deserialize with V0 config default.
92    // Set config to the platform version default to match what the factory would produce,
93    // ensuring the contract passes config min_version validation during state transition processing.
94    data_contract.set_config(DataContractConfig::default_for_version(platform_version)?);
95
96    Ok(CreatedDataContractV0 {
97        data_contract,
98        identity_nonce,
99    }
100    .into())
101}
102
103/// Reads a JSON file and converts it a document.
104#[cfg(feature = "json-conversion")]
105pub fn json_document_to_contract_with_ids(
106    path: impl AsRef<Path>,
107    id: Option<Identifier>,
108    owner_id: Option<Identifier>,
109    full_validation: bool,
110    platform_version: &PlatformVersion,
111) -> Result<DataContract, ProtocolError> {
112    let value = json_document_to_json_value(path)?;
113
114    let mut contract = DataContract::from_json(value, full_validation, platform_version)?;
115
116    if let Some(id) = id {
117        contract.set_id(id);
118    }
119
120    if let Some(owner_id) = owner_id {
121        contract.set_owner_id(owner_id);
122    }
123
124    Ok(contract)
125}
126
127/// Reads a JSON file and converts it a document.
128pub fn json_document_to_document(
129    path: impl AsRef<Path>,
130    owner_id: Option<Identifier>,
131    document_type: DocumentTypeRef,
132    _platform_version: &PlatformVersion,
133) -> Result<Document, ProtocolError> {
134    let mut data = json_document_to_platform_value(path)?;
135
136    if let Some(owner_id) = owner_id {
137        data.set_value(
138            "$ownerId",
139            platform_value::Value::Identifier(owner_id.into_buffer()),
140        )?;
141    }
142
143    let mut document: DocumentV0 = DocumentV0 {
144        id: data.remove_identifier("$id")?,
145        owner_id: data.remove_identifier("$ownerId")?,
146        properties: Default::default(),
147        revision: data.remove_optional_integer("$revision")?,
148        created_at: data.remove_optional_integer("$createdAt")?,
149        updated_at: data.remove_optional_integer("$updatedAt")?,
150        transferred_at: data.remove_optional_integer("$transferredAt")?,
151        created_at_block_height: data.remove_optional_integer("$createdAtBlockHeight")?,
152        updated_at_block_height: data.remove_optional_integer("$updatedAtBlockHeight")?,
153        transferred_at_block_height: data.remove_optional_integer("$transferredAtBlockHeight")?,
154        created_at_core_block_height: data.remove_optional_integer("$createdAtCoreBlockHeight")?,
155        updated_at_core_block_height: data.remove_optional_integer("$updatedAtCoreBlockHeight")?,
156        transferred_at_core_block_height: data
157            .remove_optional_integer("$transferredAtCoreBlockHeight")?,
158        creator_id: data.remove_optional_identifier("$creatorId")?,
159    };
160
161    data.replace_at_paths(
162        document_type.identifier_paths().iter().map(|s| s.as_str()),
163        ReplacementType::Identifier,
164    )?;
165
166    data.replace_at_paths(
167        document_type.binary_paths().iter().map(|s| s.as_str()),
168        ReplacementType::BinaryBytes,
169    )?;
170
171    document.properties = data
172        .into_btree_string_map()
173        .map_err(ProtocolError::ValueError)?;
174
175    Ok(document.into())
176}