difftreelog
CORE-410 Adapt collection properties tests for ReFungible collections
in: master
4 files changed
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -833,7 +833,7 @@
),
);
<T as Config>::Currency::settle(
- &owner.as_sub(),
+ owner.as_sub(),
imbalance,
WithdrawReasons::TRANSFER,
ExistenceRequirement::KeepAlive,
tests/src/nesting/properties.test.tsdiffbeforeafterboth--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -2,6 +2,7 @@
import usingApi, {executeTransaction} from '../substrate/substrate-api';
import {
addCollectionAdminExpectSuccess,
+ CollectionMode,
createCollectionExpectSuccess,
setCollectionPermissionsExpectSuccess,
createItemExpectSuccess,
@@ -23,9 +24,9 @@
});
});
- it('Makes sure collectionById supplies required fields', async () => {
+ async function testMakeSureSuppliesRequired(mode: CollectionMode) {
await usingApi(async api => {
- const collectionId = await createCollectionExpectSuccess();
+ const collectionId = await createCollectionExpectSuccess({mode: mode});
const collectionOption = await api.rpc.unique.collectionById(collectionId);
expect(collectionOption.isSome).to.be.true;
@@ -57,6 +58,14 @@
expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);
expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);
});
+ }
+
+ it('Makes sure collectionById supplies required fields for NFT', async () => {
+ await testMakeSureSuppliesRequired({type: 'NFT'});
+ });
+
+ it('Makes sure collectionById supplies required fields for ReFungible', async () => {
+ await testMakeSureSuppliesRequired({type: 'ReFungible'});
});
});
@@ -79,9 +88,10 @@
});
});
- it('Sets properties for a collection', async () => {
+
+ async function testSetsPropertiesForCollection(mode: string) {
await usingApi(async api => {
- const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));
+ const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));
const {collectionId} = getCreateCollectionResult(events);
// As owner
@@ -106,48 +116,54 @@
{key: 'black_hole', value: ''},
]);
});
+ }
+ it('Sets properties for a NFT collection', async () => {
+ await testSetsPropertiesForCollection('NFT');
});
+ it('Sets properties for a ReFungible collection', async () => {
+ await testSetsPropertiesForCollection('ReFungible');
+ });
- it('Check valid names for collection properties keys', async () => {
+ async function testCheckValidNames(mode: string) {
await usingApi(async api => {
- const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));
+ const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));
const {collectionId} = getCreateCollectionResult(events);
-
+
// alpha symbols
await expect(executeTransaction(
api,
bob,
api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]),
)).to.not.be.rejected;
-
+
// numeric symbols
await expect(executeTransaction(
api,
bob,
api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]),
)).to.not.be.rejected;
-
+
// underscore symbol
await expect(executeTransaction(
api,
bob,
api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]),
)).to.not.be.rejected;
-
+
// dash symbol
await expect(executeTransaction(
api,
bob,
api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]),
)).to.not.be.rejected;
-
+
// underscore symbol
await expect(executeTransaction(
api,
bob,
api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]),
)).to.not.be.rejected;
-
+
const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];
const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();
expect(properties).to.be.deep.equal([
@@ -158,54 +174,72 @@
{key: 'build.rs', value: ''},
]);
});
+ }
+ it('Check valid names for NFT collection properties keys', async () => {
+ await testCheckValidNames('NFT');
});
+ it('Check valid names for ReFungible collection properties keys', async () => {
+ await testCheckValidNames('ReFungible');
+ });
- it('Changes properties of a collection', async () => {
+ async function testChangesProperties(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]),
)).to.not.be.rejected;
-
+
// Mutate the properties
await expect(executeTransaction(
api,
alice,
api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]),
)).to.not.be.rejected;
-
+
const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();
expect(properties).to.be.deep.equal([
{key: 'electron', value: 'bonded'},
{key: 'black_hole', value: 'LIGO'},
]);
});
+ }
+ it('Changes properties of a NFT collection', async () => {
+ await testChangesProperties({type: 'NFT'});
});
+ it('Changes properties of a ReFungible collection', async () => {
+ await testChangesProperties({type: 'ReFungible'});
+ });
- it('Deletes properties of a collection', async () => {
+ async function testDeleteProperties(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]),
)).to.not.be.rejected;
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.deleteCollectionProperties(collection, ['electron']),
)).to.not.be.rejected;
-
+
const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();
expect(properties).to.be.deep.equal([
{key: 'black_hole', value: 'LIGO'},
]);
- });
+ });
+ }
+ it('Deletes properties of a NFT collection', async () => {
+ await testDeleteProperties({type: 'NFT'});
+ });
+ it('Deletes properties of a ReFungible collection', async () => {
+ await testDeleteProperties({type: 'ReFungible'});
});
});
@@ -217,10 +251,10 @@
});
});
- it('Fails to set properties in a collection if not its onwer/administrator', async () => {
+ async function testFailsSetPropertiesIfNotOwnerOrAdmin(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
bob,
@@ -230,14 +264,20 @@
const properties = (await api.query.common.collectionProperties(collection)).toJSON();
expect(properties.map).to.be.empty;
expect(properties.consumedSpace).to.equal(0);
- });
+ });
+ }
+ it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {
+ await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});
+ });
+ it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {
+ await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});
});
- it('Fails to set properties that exceed the limits', async () => {
+ async function testFailsSetPropertiesThatExeedLimits(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
+ const collection = await createCollectionExpectSuccess({mode: mode});
const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number;
-
+
// Mute the general tx parsing error, too many bytes to process
{
console.error = () => {};
@@ -247,10 +287,10 @@
api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]),
)).to.be.rejected;
}
-
+
let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();
expect(properties).to.be.empty;
-
+
await expect(executeTransaction(
api,
alice,
@@ -259,16 +299,22 @@
{key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))},
]),
)).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
+
properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();
expect(properties).to.be.empty;
- });
+ });
+ }
+ it('Fails to set properties that exceed the limits (NFT)', async () => {
+ await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});
+ });
+ it('Fails to set properties that exceed the limits (ReFungible)', async () => {
+ await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});
});
- it('Fails to set more properties than it is allowed', async () => {
+ async function testFailsSetMorePropertiesThanAllowed(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
const propertiesToBeSet = [];
for (let i = 0; i < 65; i++) {
propertiesToBeSet.push({
@@ -276,29 +322,35 @@
value: Math.random() > 0.5 ? 'high' : 'low',
});
}
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setCollectionProperties(collection, propertiesToBeSet),
)).to.be.rejectedWith(/common\.PropertyLimitReached/);
-
+
const properties = (await api.query.common.collectionProperties(collection)).toJSON();
expect(properties.map).to.be.empty;
expect(properties.consumedSpace).to.equal(0);
- });
+ });
+ }
+ it('Fails to set more properties than it is allowed (NFT)', async () => {
+ await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});
+ });
+ it('Fails to set more properties than it is allowed (ReFungible)', async () => {
+ await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});
});
-
- it('Fails to set properties with invalid names', async () => {
+
+ async function testFailsSetPropertiesWithInvalidNames(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
const invalidProperties = [
[{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
[{key: 'Mr/Sandman', value: 'Bring me a gene'}],
[{key: 'déjà vu', value: 'hmm...'}],
];
-
+
for (let i = 0; i < invalidProperties.length; i++) {
await expect(executeTransaction(
api,
@@ -306,13 +358,13 @@
api.tx.unique.setCollectionProperties(collection, invalidProperties[i]),
), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
}
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]),
), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
+
await expect(executeTransaction(
api,
alice,
@@ -320,14 +372,14 @@
{key: 'CRISPR-Cas9', value: 'rewriting nature!'},
]),
), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;
-
+
const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');
-
+
const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();
expect(properties).to.be.deep.equal([
{key: 'CRISPR-Cas9', value: 'rewriting nature!'},
]);
-
+
for (let i = 0; i < invalidProperties.length; i++) {
await expect(executeTransaction(
api,
@@ -336,7 +388,13 @@
), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
}
});
+ }
+ it('Fails to set properties with invalid names (NFT)', async () => {
+ await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});
});
+ it('Fails to set properties with invalid names (ReFungible)', async () => {
+ await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});
+ });
});
// ---------- ACCESS RIGHTS
@@ -357,53 +415,65 @@
});
});
- it('Sets access rights to properties of a collection', async () => {
+ async function testSetsAccessRightsToProperties(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]),
)).to.not.be.rejected;
-
+
await addCollectionAdminExpectSuccess(alice, collection, bob.address);
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]),
)).to.not.be.rejected;
-
+
const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();
expect(propertyRights).to.be.deep.equal([
{key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},
{key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},
]);
- });
+ });
+ }
+ it('Sets access rights to properties of a collection (NFT)', async () => {
+ await testSetsAccessRightsToProperties({type: 'NFT'});
});
+ it('Sets access rights to properties of a collection (ReFungible)', async () => {
+ await testSetsAccessRightsToProperties({type: 'ReFungible'});
+ });
- it('Changes access rights to properties of a collection', async () => {
+ async function testChangesAccessRightsToProperty(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]),
)).to.not.be.rejected;
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]),
)).to.not.be.rejected;
-
+
const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();
expect(propertyRights).to.be.deep.equal([
{key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
]);
});
+ }
+ it('Changes access rights to properties of a NFT collection', async () => {
+ await testChangesAccessRightsToProperty({type: 'NFT'});
+ });
+ it('Changes access rights to properties of a ReFungible collection', async () => {
+ await testChangesAccessRightsToProperty({type: 'ReFungible'});
});
});
@@ -415,25 +485,31 @@
});
});
- it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {
+ async function testPreventsFromSettingAccessRightsNotAdminOrOwner(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
bob,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]),
)).to.be.rejectedWith(/common\.NoPermission/);
-
+
const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();
expect(propertyRights).to.be.empty;
});
+ }
+ it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {
+ await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});
});
+ it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {
+ await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});
+ });
- it('Prevents from adding too many possible properties', async () => {
+ async function testPreventFromAddingTooManyPossibleProperties(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
const constitution = [];
for (let i = 0; i < 65; i++) {
constitution.push({
@@ -441,51 +517,63 @@
permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
});
}
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, constitution),
)).to.be.rejectedWith(/common\.PropertyLimitReached/);
-
+
const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();
expect(propertyRights).to.be.empty;
- });
+ });
+ }
+ it('Prevents from adding too many possible properties (NFT)', async () => {
+ await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});
+ });
+ it('Prevents from adding too many possible properties (ReFungible)', async () => {
+ await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});
});
- it('Prevents access rights to be modified if constant', async () => {
+ async function testPreventAccessRightsModifiedIfConstant(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]),
)).to.not.be.rejected;
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]),
)).to.be.rejectedWith(/common\.NoPermission/);
-
+
const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();
expect(propertyRights).to.deep.equal([
{key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
]);
- });
+ });
+ }
+ it('Prevents access rights to be modified if constant (NFT)', async () => {
+ await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});
});
+ it('Prevents access rights to be modified if constant (ReFungible)', async () => {
+ await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});
+ });
- it('Prevents adding properties with invalid names', async () => {
+ async function testPreventsAddingPropertiesWithInvalidNames(mode: CollectionMode) {
await usingApi(async api => {
- const collection = await createCollectionExpectSuccess();
-
+ const collection = await createCollectionExpectSuccess({mode: mode});
+
const invalidProperties = [
[{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
[{key: 'G#4', permission: {tokenOwner: true}}],
[{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],
];
-
+
for (let i = 0; i < invalidProperties.length; i++) {
await expect(executeTransaction(
api,
@@ -493,13 +581,13 @@
api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]),
), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
}
-
+
await expect(executeTransaction(
api,
alice,
api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]),
), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
+
const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string
await expect(executeTransaction(
api,
@@ -508,14 +596,20 @@
{key: correctKey, permission: {collectionAdmin: true}},
]),
), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;
-
+
const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');
-
+
const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();
expect(propertyRights).to.be.deep.equal([
{key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
]);
});
+ }
+ it('Prevents adding properties with invalid names (NFT)', async () => {
+ await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});
+ });
+ it('Prevents adding properties with invalid names (ReFungible)', async () => {
+ await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});
});
});
tests/src/refungible.test.tsdiffbeforeafterboth--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -211,35 +211,4 @@
expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);
});
});
-
- it('Set properties for exist collection', async () => {
- await usingApi(async api => {
- const collectionId = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'ReFungible'},
- });
-
- const properties = [
- {key: 'key1', value: 'val1'},
- {key: 'key2', value: 'val2'},
- ];
- await expect(executeTransaction(
- api,
- alice,
- api.tx.unique.setCollectionProperties(collectionId, properties),
- )).to.not.be.rejected;
-
- const propertyPermissions = [
- {key: 'key1', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},
- {key: 'key2', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}},
- ];
- await expect(executeTransaction(
- api,
- alice,
- api.tx.unique.setTokenPropertyPermissions(collectionId, propertyPermissions),
- )).to.not.be.rejected;
-
- const collection = (await getDetailedCollectionInfo(api, collectionId))!;
- expect(collection.properties.toHuman()).to.be.deep.equal(properties);
- expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);
- });
- });
});
tests/src/util/helpers.tsdiffbeforeafterboth284 type: 'ReFungible';284 type: 'ReFungible';285}285}286286287type CollectionMode = Nft | Fungible | ReFungible;287export type CollectionMode = Nft | Fungible | ReFungible;288288289export type Property = {289export type Property = {290 key: any,290 key: any,