Implement tokensByIndex extension

- Remove restrictions from mock mint and burn calls
This commit is contained in:
Santiago Palladino
2018-03-09 12:58:16 -03:00
parent d726c79e5f
commit 54a1d2eacc
8 changed files with 184 additions and 60 deletions

View File

@ -138,13 +138,13 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
});
it('adjusts owners tokens by index', async function () {
if (!this.token.tokensOfOwnerByIndex) return;
if (!this.token.tokenOfOwnerByIndex) return;
const newOwnerToken = await this.tokensOfOwnerByIndex(this.to, 0);
newOwnerToken.should.be.equal(tokenId);
const newOwnerToken = await this.token.tokenOfOwnerByIndex(this.to, 0);
newOwnerToken.toNumber().should.be.equal(tokenId);
const previousOwnerToken = await this.tokensOfOwnerByIndex(owner, 0);
previousOwnerToken.should.not.be.equal(tokenId);
const previousOwnerToken = await this.token.tokenOfOwnerByIndex(owner, 0);
previousOwnerToken.toNumber().should.not.be.equal(tokenId);
});
};

View File

@ -40,13 +40,6 @@ export default function shouldMintAndBurnERC721Token (accounts) {
balance.should.be.bignumber.equal(1);
});
it('adjusts owner tokens by index', async function () {
if (!this.token.tokensOfOwnerByIndex) return;
const token = await this.tokensOfOwnerByIndex(to, 0);
token.should.be.equal(tokenId);
});
it('emits a transfer event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Transfer');
@ -86,13 +79,6 @@ export default function shouldMintAndBurnERC721Token (accounts) {
balance.should.be.bignumber.equal(1);
});
it('removes that token from the token list of the owner', async function () {
if (!this.token.tokensOfOwnerByIndex) return;
const token = await this.tokensOfOwnerByIndex(sender, 0);
token.should.not.be.equal(tokenId);
});
it('emits a burn event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Transfer');
@ -126,12 +112,6 @@ export default function shouldMintAndBurnERC721Token (accounts) {
});
});
describe('when the msg.sender does not own given token', function () {
it('reverts', async function () {
await assertRevert(this.token.burn(tokenId, { from: accounts[1] }));
});
});
describe('when the given token ID was not tracked by this contract', function () {
it('reverts', async function () {
await assertRevert(this.token.burn(unknownTokenId, { from: creator }));

View File

@ -1,6 +1,7 @@
import assertRevert from '../../helpers/assertRevert';
import shouldBehaveLikeERC721BasicToken from './ERC721BasicToken.behaviour';
import shouldMintAndBurnERC721Token from './ERC721MintBurn.behaviour';
import _ from 'lodash';
const BigNumber = web3.BigNumber;
const ERC721Token = artifacts.require('ERC721TokenMock.sol');
@ -13,8 +14,8 @@ require('chai')
contract('ERC721Token', function (accounts) {
const name = 'Non Fungible Token';
const symbol = 'NFT';
const firstTokenId = 1;
const secondTokenId = 2;
const firstTokenId = 100;
const secondTokenId = 200;
const creator = accounts[0];
beforeEach(async function () {
@ -30,6 +31,51 @@ contract('ERC721Token', function (accounts) {
await this.token.mint(creator, secondTokenId, { from: creator });
});
describe('mint', function () {
const to = accounts[1];
const tokenId = 3;
beforeEach(async function () {
await this.token.mint(to, tokenId);
});
it('adjusts owner tokens by index', async function () {
const token = await this.token.tokenOfOwnerByIndex(to, 0);
token.toNumber().should.be.equal(tokenId);
});
it('adjusts all tokens list', async function () {
const newToken = await this.token.tokenByIndex(2);
newToken.toNumber().should.be.equal(tokenId);
});
});
describe('burn', function () {
const tokenId = firstTokenId;
const sender = creator;
beforeEach(async function () {
await this.token.burn(tokenId, { from: sender });
});
it('removes that token from the token list of the owner', async function () {
const token = await this.token.tokenOfOwnerByIndex(sender, 0);
token.toNumber().should.be.equal(secondTokenId);
});
it('adjusts all tokens list', async function () {
const token = await this.token.tokenByIndex(0);
token.toNumber().should.be.equal(secondTokenId);
});
it('burns all tokens', async function () {
await this.token.burn(secondTokenId, { from: sender });
const total = await this.token.totalSupply();
total.toNumber().should.be.equal(0);
await assertRevert(this.token.tokenByIndex(0));
});
});
describe('metadata', function () {
it('has a name', async function () {
const name = await this.token.name();
@ -56,34 +102,80 @@ contract('ERC721Token', function (accounts) {
});
describe('tokenOfOwnerByIndex', function () {
describe('when the given address owns some tokens', function () {
const owner = creator;
describe('when the given index is lower than the amount of tokens owned by the given address', function () {
const index = 0;
it('returns the token ID placed at the given index', async function () {
const tokenId = await this.token.tokenOfOwnerByIndex(owner, index);
tokenId.should.be.bignumber.equal(firstTokenId);
});
const owner = creator;
const another = accounts[1];
describe('when the given index is lower than the amount of tokens owned by the given address', function () {
it('returns the token ID placed at the given index', async function () {
const tokenId = await this.token.tokenOfOwnerByIndex(owner, 0);
tokenId.should.be.bignumber.equal(firstTokenId);
});
});
describe('when the index is greater than or equal to the total tokens owned by the given address', function () {
const index = 2;
it('reverts', async function () {
await assertRevert(this.token.tokenOfOwnerByIndex(owner, index));
});
describe('when the index is greater than or equal to the total tokens owned by the given address', function () {
it('reverts', async function () {
await assertRevert(this.token.tokenOfOwnerByIndex(owner, 2));
});
});
describe('when the given address does not own any token', function () {
const owner = accounts[1];
it('reverts', async function () {
await assertRevert(this.token.tokenOfOwnerByIndex(another, 0));
});
});
describe('after transferring all tokens to another user', function () {
beforeEach(async function () {
await this.token.transferFrom(owner, another, firstTokenId, { from: owner });
await this.token.transferFrom(owner, another, secondTokenId, { from: owner });
});
it('returns correct token IDs for target', async function () {
const count = await this.token.balanceOf(another);
count.toNumber().should.be.equal(2);
const tokensListed = await Promise.all(_.range(2).map(i => this.token.tokenOfOwnerByIndex(another, i)));
tokensListed.map(t => t.toNumber()).should.have.members([firstTokenId, secondTokenId]);
});
it('returns empty collection for original owner', async function () {
const count = await this.token.balanceOf(owner);
count.toNumber().should.be.equal(0);
await assertRevert(this.token.tokenOfOwnerByIndex(owner, 0));
});
});
});
describe('tokenByIndex', function () {
it('should return all tokens', async function () {
const tokensListed = await Promise.all(_.range(2).map(i => this.token.tokenByIndex(i)));
tokensListed.map(t => t.toNumber()).should.have.members([firstTokenId, secondTokenId]);
});
it('should revert if index is greater than supply', async function () {
await assertRevert(this.token.tokenByIndex(2));
});
[firstTokenId, secondTokenId].forEach(function (tokenId) {
it(`should return all tokens after burning token ${tokenId} and minting new tokens`, async function () {
const owner = accounts[0];
const newTokenId = 300;
const anotherNewTokenId = 400;
await this.token.burn(tokenId, { from: owner });
await this.token.mint(owner, newTokenId, { from: owner });
await this.token.mint(owner, anotherNewTokenId, { from: owner });
const count = await this.token.totalSupply();
count.toNumber().should.be.equal(3);
const tokensListed = await Promise.all(_.range(3).map(i => this.token.tokenByIndex(i)));
const expectedTokens = _.filter(
[firstTokenId, secondTokenId, newTokenId, anotherNewTokenId],
x => (x !== tokenId)
);
tokensListed.map(t => t.toNumber()).should.have.members(expectedTokens);
});
});
});
});
});