Skip to content

Commit aa3e1cf

Browse files
thephezclaudeQuantumExplorer
authored
test(wasm-sdk): expand data contract test coverage (#2803)
Co-authored-by: Claude <[email protected]> Co-authored-by: QuantumExplorer <[email protected]>
1 parent 2538438 commit aa3e1cf

File tree

3 files changed

+557
-10
lines changed

3 files changed

+557
-10
lines changed
Lines changed: 274 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,287 @@
11
import init, * as sdk from '../../dist/sdk.compressed.js';
2-
import contractFixture from './fixtures/data-contract-crypto-card-game.mjs';
2+
import contractFixtureV0 from './fixtures/data-contract-v0-crypto-card-game.mjs';
3+
import contractFixtureV1 from './fixtures/data-contract-v1-with-docs-tokens-groups.mjs';
34

4-
const PLATFORM_VERSION = 1;
5+
// Platform version constants
6+
const PLATFORM_VERSION_CONTRACT_V0 = 1;
7+
const PLATFORM_VERSION_CONTRACT_V1 = 9; // V1 contracts introduced in Platform v9
8+
9+
// Platform version compatibility ranges
10+
const V0_COMPATIBLE_VERSIONS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // V0 works across all versions
11+
const V1_COMPATIBLE_VERSIONS = [9, 10]; // V1 only works from version 9+
12+
const V0_ONLY_VERSIONS = [1, 2, 3, 4, 5, 6, 7, 8]; // Versions that only support V0
13+
const LATEST_KNOWN_VERSION = Math.max(...V0_COMPATIBLE_VERSIONS);
14+
15+
// Helper function for testing contract compatibility across versions
16+
const testContractAcrossVersions = (
17+
contractFixture,
18+
contractName,
19+
compatibleVersions,
20+
incompatibleVersions = [],
21+
) => {
22+
compatibleVersions.forEach((version) => {
23+
it(`should work with platform version ${version}`, () => {
24+
const contract = sdk.DataContract.fromJSON(contractFixture, version);
25+
expect(contract).to.be.ok();
26+
expect(contract.id()).to.equal(contractFixture.id);
27+
28+
const roundTripped = contract.toJSON();
29+
expect(roundTripped.id).to.equal(contractFixture.id);
30+
31+
contract.free();
32+
});
33+
});
34+
35+
incompatibleVersions.forEach((version) => {
36+
it(`should fail with platform version ${version}`, () => {
37+
expect(() => {
38+
sdk.DataContract.fromJSON(contractFixture, version);
39+
}).to.throw(/unknown version|dpp unknown version/);
40+
});
41+
});
42+
};
543

644
describe('DataContract', () => {
745
before(async () => {
846
await init();
947
});
1048

11-
it('should create a contract from JSON and expose identifiers', async () => {
12-
const contract = sdk.DataContract.fromJSON(contractFixture, PLATFORM_VERSION);
49+
describe('Contract Creation', () => {
50+
it('should create a V0 contract from JSON and expose all properties', async () => {
51+
const contract = sdk.DataContract.fromJSON(contractFixtureV0, PLATFORM_VERSION_CONTRACT_V0);
52+
53+
expect(contract).to.be.ok();
54+
expect(contract.id()).to.equal(contractFixtureV0.id);
55+
56+
const roundTripped = contract.toJSON();
57+
expect(roundTripped).to.be.an('object');
58+
expect(roundTripped.id).to.equal(contractFixtureV0.id);
59+
expect(roundTripped.ownerId).to.equal(contractFixtureV0.ownerId);
60+
expect(roundTripped.version).to.equal(contractFixtureV0.version);
61+
expect(roundTripped.$format_version).to.equal(contractFixtureV0.$format_version);
62+
expect(roundTripped.config).to.deep.equal(contractFixtureV0.config);
63+
expect(roundTripped.documentSchemas).to.deep.equal(contractFixtureV0.documentSchemas);
64+
65+
// Verify document schema structure
66+
expect(roundTripped.documentSchemas.card).to.exist();
67+
expect(roundTripped.documentSchemas.card.properties.name).to.exist();
68+
expect(roundTripped.documentSchemas.card.properties.rarity.enum)
69+
.to.deep.equal(['common', 'uncommon', 'rare', 'legendary']);
70+
expect(roundTripped.documentSchemas.card.indices).to.have.length(2);
71+
72+
contract.free();
73+
});
74+
75+
// TODO: enable test once an SDK fix to support this is merged
76+
it.skip('should create a V1 contract from JSON and expose all properties including tokens and groups', async () => {
77+
const contract = sdk.DataContract.fromJSON(contractFixtureV1, PLATFORM_VERSION_CONTRACT_V1);
78+
79+
expect(contract).to.be.ok();
80+
expect(contract.id()).to.equal(contractFixtureV1.id);
81+
82+
const roundTripped = contract.toJSON();
83+
expect(roundTripped).to.be.an('object');
84+
expect(roundTripped.id).to.equal(contractFixtureV1.id);
85+
expect(roundTripped.ownerId).to.equal(contractFixtureV1.ownerId);
86+
expect(roundTripped.version).to.equal(contractFixtureV1.version);
87+
expect(roundTripped.$format_version).to.equal(contractFixtureV1.$format_version);
88+
expect(roundTripped.config.sizedIntegerTypes).to.be.true();
89+
expect(roundTripped.documentSchemas).to.deep.equal(contractFixtureV1.documentSchemas);
90+
91+
// Verify V1-specific features
92+
expect(roundTripped.tokens).to.exist();
93+
expect(roundTripped.tokens['0']).to.exist();
94+
expect(roundTripped.tokens['0'].baseSupply).to.equal(100);
95+
expect(roundTripped.tokens['0'].conventions.decimals).to.equal(0);
96+
97+
expect(roundTripped.groups).to.exist();
98+
expect(roundTripped.groups['0']).to.exist();
99+
expect(roundTripped.groups['0'].required_power).to.equal(2);
100+
101+
expect(roundTripped.keywords).to.deep.equal(contractFixtureV1.keywords);
102+
103+
contract.free();
104+
});
105+
106+
it('should create a contract with only document schemas (no tokens)', () => {
107+
// V0 fixture already has only documents, no tokens - verify it works
108+
const contract = sdk.DataContract.fromJSON(contractFixtureV0, PLATFORM_VERSION_CONTRACT_V0);
109+
const roundTripped = contract.toJSON();
110+
111+
expect(roundTripped.documentSchemas.card).to.exist();
112+
expect(roundTripped.tokens).to.equal(undefined);
113+
114+
contract.free();
115+
});
116+
117+
it('should create a contract with only tokens (no documents)', () => {
118+
// Use V1 fixture but remove documentSchemas
119+
const contractWithOnlyTokens = {
120+
...contractFixtureV1,
121+
documentSchemas: {},
122+
};
123+
124+
const contract = sdk.DataContract.fromJSON(
125+
contractWithOnlyTokens,
126+
PLATFORM_VERSION_CONTRACT_V1,
127+
);
128+
const roundTripped = contract.toJSON();
129+
130+
expect(roundTripped.documentSchemas).to.deep.equal({});
131+
132+
contract.free();
133+
});
134+
});
135+
136+
describe('Version Compatibility', () => {
137+
it('should fail to create a V1 contract with V0 platform version', async () => {
138+
expect(() => {
139+
sdk.DataContract.fromJSON(contractFixtureV1, PLATFORM_VERSION_CONTRACT_V0);
140+
}).to.throw(/dpp unknown version.*known versions.*\[0\].*received.*1/);
141+
});
142+
});
143+
144+
describe('Validation', () => {
145+
it('should handle invalid JSON input gracefully', () => {
146+
expect(() => {
147+
sdk.DataContract.fromJSON(null, PLATFORM_VERSION_CONTRACT_V0);
148+
}).to.throw();
149+
150+
expect(() => {
151+
sdk.DataContract.fromJSON({}, PLATFORM_VERSION_CONTRACT_V0);
152+
}).to.throw();
153+
154+
expect(() => {
155+
sdk.DataContract.fromJSON({ id: 'invalid' }, PLATFORM_VERSION_CONTRACT_V0);
156+
}).to.throw();
157+
});
158+
159+
it('should reject contracts with invalid property values', () => {
160+
// Test invalid Base58 ID
161+
expect(() => {
162+
sdk.DataContract.fromJSON({
163+
...contractFixtureV0,
164+
id: 'invalid-not-base58!',
165+
}, PLATFORM_VERSION_CONTRACT_V0);
166+
}).to.throw();
167+
168+
// Test negative version number
169+
expect(() => {
170+
sdk.DataContract.fromJSON({
171+
...contractFixtureV0,
172+
version: -1,
173+
}, PLATFORM_VERSION_CONTRACT_V0);
174+
}).to.throw();
175+
176+
// Test invalid ownerId
177+
expect(() => {
178+
sdk.DataContract.fromJSON({
179+
...contractFixtureV0,
180+
ownerId: 'not-a-valid-id',
181+
}, PLATFORM_VERSION_CONTRACT_V0);
182+
}).to.throw();
183+
});
184+
185+
it('should require at least one document type or token', () => {
186+
const contractWithEmptySchemas = {
187+
$format_version: '0',
188+
id: contractFixtureV0.id,
189+
ownerId: contractFixtureV0.ownerId,
190+
version: 1,
191+
config: contractFixtureV0.config,
192+
documentSchemas: {},
193+
};
194+
195+
expect(() => {
196+
sdk.DataContract.fromJSON(contractWithEmptySchemas, PLATFORM_VERSION_CONTRACT_V0);
197+
}).to.throw(/must have at least one document type or token defined/);
198+
});
199+
});
200+
201+
describe('Data Preservation', () => {
202+
it('should preserve all data through JSON round-trip for V0 contract', async () => {
203+
const contract = sdk.DataContract.fromJSON(contractFixtureV0, PLATFORM_VERSION_CONTRACT_V0);
204+
const roundTripped = contract.toJSON();
205+
206+
// Create a new contract from the round-tripped JSON
207+
const contract2 = sdk.DataContract.fromJSON(roundTripped, PLATFORM_VERSION_CONTRACT_V0);
208+
const roundTripped2 = contract2.toJSON();
209+
210+
expect(roundTripped2).to.deep.equal(roundTripped);
211+
212+
contract.free();
213+
contract2.free();
214+
});
215+
216+
it('should preserve all data through JSON round-trip for V1 contract', async () => {
217+
const contract = sdk.DataContract.fromJSON(contractFixtureV1, PLATFORM_VERSION_CONTRACT_V1);
218+
const roundTripped = contract.toJSON();
219+
220+
// Create a new contract from the round-tripped JSON
221+
const contract2 = sdk.DataContract.fromJSON(roundTripped, PLATFORM_VERSION_CONTRACT_V1);
222+
const roundTripped2 = contract2.toJSON();
223+
224+
expect(roundTripped2).to.deep.equal(roundTripped);
225+
226+
contract.free();
227+
contract2.free();
228+
});
229+
});
230+
231+
describe('Memory Management', () => {
232+
it('should handle memory management properly with multiple contracts', async () => {
233+
const contract1 = sdk.DataContract.fromJSON(contractFixtureV0, PLATFORM_VERSION_CONTRACT_V0);
234+
const contract2 = sdk.DataContract.fromJSON(contractFixtureV1, PLATFORM_VERSION_CONTRACT_V1);
235+
236+
expect(contract1.id()).to.equal(contractFixtureV0.id);
237+
expect(contract2.id()).to.equal(contractFixtureV1.id);
238+
239+
contract1.free();
240+
contract2.free();
241+
});
242+
});
243+
244+
describe('Platform Version Compatibility Matrix', () => {
245+
describe('V0 Contract Compatibility', () => {
246+
testContractAcrossVersions(contractFixtureV0, 'V0', V0_COMPATIBLE_VERSIONS);
247+
});
248+
249+
describe('V1 Contract Compatibility', () => {
250+
testContractAcrossVersions(contractFixtureV1, 'V1', V1_COMPATIBLE_VERSIONS, V0_ONLY_VERSIONS);
251+
});
252+
253+
describe('Edge Cases', () => {
254+
it('should fail with invalid version numbers', () => {
255+
const invalidVersions = [
256+
0, // Zero version
257+
-1, // Negative version
258+
LATEST_KNOWN_VERSION + 1, // One beyond latest known
259+
LATEST_KNOWN_VERSION * 10, // Far beyond reasonable range
260+
];
261+
262+
invalidVersions.forEach((version) => {
263+
expect(() => {
264+
sdk.DataContract.fromJSON(contractFixtureV0, version);
265+
}).to.throw(/unknown version/);
266+
});
267+
});
13268

14-
expect(contract).to.be.ok();
15-
expect(contract.id()).to.equal(contractFixture.id);
269+
it('should handle version boundary correctly at V9 transition', () => {
270+
// V0 contract should work in V9 (backward compatibility)
271+
const contract = sdk.DataContract.fromJSON(contractFixtureV0, 9);
272+
expect(contract.id()).to.equal(contractFixtureV0.id);
273+
contract.free();
16274

17-
const roundTripped = contract.toJSON();
18-
expect(roundTripped).to.be.an('object');
19-
expect(roundTripped.id).to.equal(contractFixture.id);
275+
// V1 contract should work in V9 (first supported version)
276+
const contractV1 = sdk.DataContract.fromJSON(contractFixtureV1, 9);
277+
expect(contractV1.id()).to.equal(contractFixtureV1.id);
278+
contractV1.free();
20279

21-
contract.free();
280+
// V1 contract should fail in V8 (last unsupported version)
281+
expect(() => {
282+
sdk.DataContract.fromJSON(contractFixtureV1, 8);
283+
}).to.throw(/dpp unknown version/);
284+
});
285+
});
22286
});
23287
});

0 commit comments

Comments
 (0)