Coded EnumerableSet.
This commit is contained in:
72
contracts/drafts/EnumerableSet.sol
Normal file
72
contracts/drafts/EnumerableSet.sol
Normal file
@ -0,0 +1,72 @@
|
||||
pragma solidity ^0.5.10;
|
||||
|
||||
|
||||
/**
|
||||
* @title EnumerableSet
|
||||
* @dev Data structure
|
||||
* @author Alberto Cuesta Cañada
|
||||
*/
|
||||
library EnumerableSet {
|
||||
|
||||
event ValueAdded(address value);
|
||||
event ValueRemoved(address value);
|
||||
|
||||
struct Set {
|
||||
// Position of the value in the `values` array, plus 1 because index 0
|
||||
// means a value is not in the set.
|
||||
mapping (address => uint256) index;
|
||||
address[] values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add a value.
|
||||
*/
|
||||
function add(Set storage set, address value)
|
||||
internal
|
||||
{
|
||||
if (!contains(set, value)){
|
||||
set.index[value] = set.values.push(value);
|
||||
emit ValueAdded(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove a value.
|
||||
*/
|
||||
function remove(Set storage set, address value)
|
||||
internal
|
||||
{
|
||||
if (contains(set, value)) {
|
||||
set.values[set.index[value] - 1] = set.values[set.values.length - 1];
|
||||
set.values.pop();
|
||||
delete set.index[value];
|
||||
emit ValueRemoved(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set.
|
||||
*/
|
||||
function contains(Set storage set, address value)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return set.index[value] != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return an array with all values in the set.
|
||||
*/
|
||||
function enumerate(Set storage set)
|
||||
internal
|
||||
view
|
||||
returns (address[] memory)
|
||||
{
|
||||
address[] memory output = new address[](set.values.length);
|
||||
for (uint256 i; i < set.values.length; i++){
|
||||
output[i] = set.values[i];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@ -1,191 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
|
||||
/**
|
||||
* @title Enumerables
|
||||
* @dev This contract implements an enumerable address set as a doubly linked list.
|
||||
* @author Alberto Cuesta Cañada
|
||||
*/
|
||||
library Enumerables {
|
||||
|
||||
event ObjectCreated(uint256 id, address data);
|
||||
event ObjectsLinked(uint256 prev, uint256 next);
|
||||
event ObjectRemoved(uint256 id);
|
||||
event NewHead(uint256 id);
|
||||
event NewTail(uint256 id);
|
||||
|
||||
struct Object{
|
||||
uint256 id;
|
||||
uint256 next;
|
||||
uint256 prev;
|
||||
address data;
|
||||
}
|
||||
|
||||
struct Enumerable{
|
||||
uint256 head;
|
||||
uint256 tail;
|
||||
uint256 idCounter;
|
||||
mapping (uint256 => Object) objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Retrieves the Object denoted by `id`.
|
||||
*/
|
||||
function get(Enumerable storage enumerable, uint256 id)
|
||||
public
|
||||
view
|
||||
returns (uint256, uint256, uint256, address)
|
||||
{
|
||||
Object memory object = enumerable.objects[id];
|
||||
return (object.id, object.next, object.prev, object.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Insert a new Object as the new Head with `data` in the data field.
|
||||
*/
|
||||
function append(Enumerable storage enumerable, address data)
|
||||
public
|
||||
{
|
||||
uint256 objectId = _createObject(enumerable, data);
|
||||
if (enumerable.head == 0) {
|
||||
_setHead(enumerable, objectId);
|
||||
} else {
|
||||
_link(enumerable, enumerable.head, objectId);
|
||||
_setTail(enumerable, objectId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove the Object denoted by `id` from the List.
|
||||
*/
|
||||
function remove(Enumerable storage enumerable, uint256 id)
|
||||
public
|
||||
{
|
||||
Object memory removeObject = enumerable.objects[id];
|
||||
if (enumerable.head == id && enumerable.tail == id) {
|
||||
_setHead(enumerable, 0);
|
||||
_setTail(enumerable, 0);
|
||||
}
|
||||
else if (enumerable.head == id) {
|
||||
_setHead(enumerable, removeObject.next);
|
||||
enumerable.objects[removeObject.next].prev = 0;
|
||||
}
|
||||
else if (enumerable.tail == id) {
|
||||
_setTail(enumerable, removeObject.prev);
|
||||
enumerable.objects[removeObject.prev].next = 0;
|
||||
}
|
||||
else {
|
||||
_link(enumerable, removeObject.prev, removeObject.next);
|
||||
}
|
||||
delete enumerable.objects[removeObject.id];
|
||||
emit ObjectRemoved(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if at least one Object matches `data` in the data field.
|
||||
* TODO: What happens with address(0) as data?
|
||||
*/
|
||||
function contains(Enumerable storage enumerable, address data)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
Object memory object = enumerable.objects[enumerable.head];
|
||||
while (object.data != data) {
|
||||
object = enumerable.objects[object.next];
|
||||
}
|
||||
return object.data == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the length of the enumerable.
|
||||
*/
|
||||
function length(Enumerable storage enumerable)
|
||||
public
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
uint256 count = 0;
|
||||
if (enumerable.head != 0){
|
||||
count += 1;
|
||||
Object memory object = enumerable.objects[enumerable.head];
|
||||
while (object.id != enumerable.tail) {
|
||||
count += 1;
|
||||
object = enumerable.objects[object.next];
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns all the data fields in the enumerable, in an array ordered from head to tail.
|
||||
*/
|
||||
function enumerate(Enumerable storage enumerable)
|
||||
public
|
||||
view
|
||||
returns (address[] memory)
|
||||
{
|
||||
uint256 count = length(enumerable);
|
||||
address[] memory data = new address[](count);
|
||||
Object memory object = enumerable.objects[enumerable.head];
|
||||
for (uint256 i = 0; i < count; i += 1){
|
||||
data[i] = enumerable.objects[object.id].data;
|
||||
object = enumerable.objects[object.next];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to update the Head pointer.
|
||||
*/
|
||||
function _setHead(Enumerable storage enumerable, uint256 id)
|
||||
internal
|
||||
{
|
||||
enumerable.head = id;
|
||||
emit NewHead(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to update the Tail pointer.
|
||||
*/
|
||||
function _setTail(Enumerable storage enumerable, uint256 id)
|
||||
internal
|
||||
{
|
||||
enumerable.tail = id;
|
||||
emit NewTail(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to create an unlinked Object.
|
||||
*/
|
||||
function _createObject(Enumerable storage enumerable, address data)
|
||||
internal
|
||||
returns (uint256)
|
||||
{
|
||||
enumerable.idCounter += 1;
|
||||
uint256 newId = enumerable.idCounter;
|
||||
Object memory object = Object(
|
||||
newId,
|
||||
0,
|
||||
0,
|
||||
data
|
||||
);
|
||||
enumerable.objects[object.id] = object;
|
||||
emit ObjectCreated(
|
||||
object.id,
|
||||
object.data
|
||||
);
|
||||
return object.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to link an Object to another.
|
||||
*/
|
||||
function _link(Enumerable storage enumerable, uint256 prevId, uint256 nextId)
|
||||
internal
|
||||
{
|
||||
enumerable.objects[prevId].next = nextId;
|
||||
enumerable.objects[nextId].prev = prevId;
|
||||
emit ObjectsLinked(prevId, nextId);
|
||||
}
|
||||
}
|
||||
59
contracts/mocks/EnumerableSetMock.sol
Normal file
59
contracts/mocks/EnumerableSetMock.sol
Normal file
@ -0,0 +1,59 @@
|
||||
pragma solidity ^0.5.10;
|
||||
import "../drafts/EnumerableSet.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title EnumerableSetMock
|
||||
* @dev Data structure
|
||||
* @author Alberto Cuesta Cañada
|
||||
*/
|
||||
contract EnumerableSetMock{
|
||||
|
||||
using EnumerableSet for EnumerableSet.Set;
|
||||
|
||||
EnumerableSet.Set private set;
|
||||
|
||||
constructor() public {
|
||||
set = EnumerableSet.Set({values: new address[](0)});
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the value is in the set.
|
||||
*/
|
||||
function testContains(address value)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return EnumerableSet.contains(set, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Insert an value as the new tail.
|
||||
*/
|
||||
function testAdd(address value)
|
||||
public
|
||||
{
|
||||
EnumerableSet.add(set, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove an value.
|
||||
*/
|
||||
function testRemove(address remove)
|
||||
public
|
||||
{
|
||||
EnumerableSet.remove(set, remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return an array with all values in the set, from Head to Tail.
|
||||
*/
|
||||
function testEnumerate()
|
||||
public
|
||||
view
|
||||
returns (address[] memory)
|
||||
{
|
||||
return EnumerableSet.enumerate(set);
|
||||
}
|
||||
}
|
||||
@ -1,114 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
import "../drafts/Enumerables.sol";
|
||||
|
||||
|
||||
contract EnumerablesMock {
|
||||
using Enumerables for Enumerables.Enumerable;
|
||||
|
||||
Enumerables.Enumerable public enumerable;
|
||||
|
||||
constructor() public {
|
||||
enumerable = Enumerables.Enumerable(0, 0, 0); // Maybe have a factory method in the library.
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Retrieves the Object denoted by `id`.
|
||||
*/
|
||||
function testGet(uint256 id)
|
||||
public
|
||||
view
|
||||
returns (uint256, uint256, uint256, address)
|
||||
{
|
||||
return Enumerables.get(enumerable, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Insert a new Object as the new Head with `data` in the data field.
|
||||
*/
|
||||
function testAppend(address data)
|
||||
public
|
||||
{
|
||||
Enumerables.append(enumerable, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove the Object denoted by `id` from the List.
|
||||
*/
|
||||
function testRemove(uint256 id)
|
||||
public
|
||||
{
|
||||
Enumerables.remove(enumerable, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if at least one Object matches `data` in the data field.
|
||||
* TODO: What happens with address(0) as data?
|
||||
*/
|
||||
function testContains(address data)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
|
||||
return Enumerables.contains(enumerable, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the length of the enumerable.
|
||||
*/
|
||||
function testLength()
|
||||
public
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
return Enumerables.length(enumerable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns all the data fields in the enumerable, in an array ordered from head to tail.
|
||||
*/
|
||||
function enumerate()
|
||||
public
|
||||
view
|
||||
returns (address[] memory)
|
||||
{
|
||||
return Enumerables.enumerate(enumerable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to update the Head pointer.
|
||||
*/
|
||||
function testSetHead(uint256 id)
|
||||
public
|
||||
{
|
||||
Enumerables._setHead(enumerable, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to update the Tail pointer.
|
||||
*/
|
||||
function testSetTail(uint256 id)
|
||||
public
|
||||
{
|
||||
Enumerables._setTail(enumerable, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to create an unlinked Object.
|
||||
*/
|
||||
function testCreateObject(address data)
|
||||
public
|
||||
returns (uint256)
|
||||
{
|
||||
return Enumerables._createObject(enumerable, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to link an Object to another.
|
||||
*/
|
||||
function testLink(uint256 prevId, uint256 nextId)
|
||||
public
|
||||
{
|
||||
Enumerables._link(enumerable, prevId, nextId);
|
||||
}
|
||||
}
|
||||
54
test/drafts/EnumerableSet.test.js
Normal file
54
test/drafts/EnumerableSet.test.js
Normal file
@ -0,0 +1,54 @@
|
||||
const { contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const EnumerableSetMock = contract.fromArtifact('EnumerableSetMock');
|
||||
|
||||
const a = '0x0000000000000000000000000000000000000001';
|
||||
const b = '0x0000000000000000000000000000000000000002';
|
||||
const c = '0x0000000000000000000000000000000000000003';
|
||||
|
||||
/** @test {EnumerableSet} contract */
|
||||
describe('EnumerableSet', function () {
|
||||
beforeEach(async function () {
|
||||
this.enumerableSet = await EnumerableSetMock.new();
|
||||
});
|
||||
|
||||
it('contains can return false.', async function () {
|
||||
expect(await this.enumerableSet.testContains(a)).to.be.false;
|
||||
});
|
||||
|
||||
it('adds an value.', async function () {
|
||||
await this.enumerableSet.testAdd(a);
|
||||
expect(await this.enumerableSet.testContains(a)).to.be.true;
|
||||
});
|
||||
|
||||
it('adds several values.', async function () {
|
||||
await this.enumerableSet.testAdd(a);
|
||||
await this.enumerableSet.testAdd(b);
|
||||
expect(await this.enumerableSet.testContains(a)).to.be.true;
|
||||
expect(await this.enumerableSet.testContains(b)).to.be.true;
|
||||
expect(await this.enumerableSet.testContains(c)).to.be.false;
|
||||
});
|
||||
|
||||
it('removes values.', async function () {
|
||||
await this.enumerableSet.testAdd(a);
|
||||
await this.enumerableSet.testRemove(a);
|
||||
expect(await this.enumerableSet.testContains(a)).to.be.false;
|
||||
});
|
||||
|
||||
it('Retrieve an empty array', async function () {
|
||||
expect(await this.enumerableSet.testEnumerate()).to.be.empty;
|
||||
});
|
||||
|
||||
it('Retrieve an array of values', async function () {
|
||||
await this.enumerableSet.testAdd(a);
|
||||
await this.enumerableSet.testAdd(b);
|
||||
await this.enumerableSet.testAdd(c);
|
||||
const result = (await this.enumerableSet.testEnumerate());
|
||||
expect(result.length).to.be.equal(3);
|
||||
expect(result[0]).to.be.equal(a);
|
||||
expect(result[1]).to.be.equal(b);
|
||||
expect(result[2]).to.be.equal(c);
|
||||
});
|
||||
});
|
||||
@ -1,250 +0,0 @@
|
||||
const { contract } = require('@openzeppelin/test-environment');
|
||||
const { expectRevert, expectEvent } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const EnumerablesMock = contract.fromArtifact('EnumerablesMock');
|
||||
|
||||
const emptyData = '0x0000000000000000000000000000000000000000';
|
||||
const headData = '0x0000000000000000000000000000000000000001';
|
||||
const middleData = '0x0000000000000000000000000000000000000002';
|
||||
const tailData = '0x0000000000000000000000000000000000000003';
|
||||
|
||||
describe('Enumerable', function () {
|
||||
beforeEach(async function () {
|
||||
this.enumerables = await EnumerablesMock.new();
|
||||
});
|
||||
|
||||
// it('starts at zero', async function () {
|
||||
// expect(await this.counter.current()).to.be.bignumber.equal('0');
|
||||
// });
|
||||
|
||||
/**
|
||||
* Test the two describe methods
|
||||
* @test {Enumerable#set} and {Enumerable#get}
|
||||
*/
|
||||
it('Constructor variables.', async function () {
|
||||
// expect(await this.enumerables.enumerable().idCounter()).toNumber()).to.be.equal(1);
|
||||
});
|
||||
|
||||
it('get on a non existing object returns (0,0,0,0).', async function () {
|
||||
const result = (await this.enumerables.testGet(0));
|
||||
expect(result[0].toNumber()).to.be.equal(0);
|
||||
expect(result[1].toNumber()).to.be.equal(0);
|
||||
expect(result[2].toNumber()).to.be.equal(0);
|
||||
expect(result[3]).to.be.equal(emptyData);
|
||||
});
|
||||
|
||||
it('appends an object at the head - event emission.', async function () {
|
||||
const objectEvent = (
|
||||
await this.enumerables.testAppend(headData)
|
||||
).logs[0];
|
||||
expect(objectEvent.args.id.toNumber()).to.be.equal(1);
|
||||
expect(objectEvent.args.data).to.be.equal(headData);
|
||||
});
|
||||
|
||||
it('appends an object at the head - data storage.', async function () {
|
||||
const objectId = (
|
||||
await this.enumerables.testAppend(headData)
|
||||
).logs[0].args.id.toNumber();
|
||||
|
||||
const result = (await this.enumerables.testGet(objectId));
|
||||
expect(result[0].toNumber()).to.be.equal(objectId);
|
||||
expect(result[1].toNumber()).to.be.equal(0);
|
||||
expect(result[2].toNumber()).to.be.equal(0);
|
||||
expect(result[3]).to.be.equal(headData);
|
||||
});
|
||||
|
||||
it('appends two objects.', async function () {
|
||||
const objectOneId = (
|
||||
await this.enumerables.testAppend(middleData)
|
||||
).logs[0].args.id.toNumber();
|
||||
const objectTwoId = (
|
||||
await this.enumerables.testAppend(headData)
|
||||
).logs[0].args.id.toNumber();
|
||||
|
||||
const objectOne = (await this.enumerables.testGet(objectOneId));
|
||||
expect(objectOne[0].toNumber()).to.be.equal(objectOneId);
|
||||
expect(objectOne[1].toNumber()).to.be.equal(0);
|
||||
expect(objectOne[2].toNumber()).to.be.equal(objectTwoId);
|
||||
expect(objectOne[3]).to.be.equal(middleData);
|
||||
|
||||
const objectTwo = (await this.enumerables.testGet(objectTwoId));
|
||||
expect(objectTwo[0].toNumber()).to.be.equal(objectTwoId);
|
||||
expect(objectTwo[1].toNumber()).to.be.equal(objectOneId);
|
||||
expect(objectTwo[2].toNumber()).to.be.equal(0);
|
||||
expect(objectTwo[3]).to.be.equal(headData);
|
||||
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(objectTwoId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Enumerable - length', (accounts) => {
|
||||
beforeEach(async function () {
|
||||
this.this.enumerables = await EnumerablesMock.new();
|
||||
});
|
||||
|
||||
it('Retrieves the length of an empty this.enumerables.', async function () {
|
||||
const resultId = (await this.enumerables.testLength());
|
||||
expect(resultId.toNumber()).to.be.equal(0);
|
||||
});
|
||||
|
||||
it('Retrieves the length of an this.enumerables.', async function () {
|
||||
tailId = (
|
||||
await this.enumerables.testAppend(tailData)
|
||||
).logs[0].args.id.toNumber();
|
||||
middleId = (
|
||||
await this.enumerables.testAppend(middleData)
|
||||
).logs[0].args.id.toNumber();
|
||||
headId = (
|
||||
await this.enumerables.testAppend(headData)
|
||||
).logs[0].args.id.toNumber();
|
||||
const resultId = (await this.enumerables.testLength());
|
||||
expect(resultId.toNumber()).to.be.equal(3);
|
||||
});
|
||||
});
|
||||
|
||||
/** @test {Enumerable} describe */
|
||||
describe('Enumerable - contains', (accounts) => {
|
||||
beforeEach(async function () {
|
||||
this.this.enumerables = await EnumerablesMock.new();
|
||||
tailId = (
|
||||
await this.enumerables.testAppend(tailData)
|
||||
).logs[0].args.id.toNumber();
|
||||
middleId = (
|
||||
await this.enumerables.testAppend(middleData)
|
||||
).logs[0].args.id.toNumber();
|
||||
});
|
||||
|
||||
it('Returns false for empty data.', async function () {
|
||||
const resultId = (await this.enumerables.testContains(emptyData));
|
||||
expect(resultId).to.be.false;
|
||||
});
|
||||
|
||||
it('Returns true for existing data.', async function () {
|
||||
const resultId = (await this.enumerables.testContains(tailData));
|
||||
expect(resultId).to.be.true;
|
||||
});
|
||||
|
||||
it('Returns false for non existing data.', async function () {
|
||||
const resultId = (await this.enumerables.testContains(headData));
|
||||
expect(resultId).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
/** @test {Enumerable} describe */
|
||||
/* describe('Enumerable - enumerate', (accounts) => {
|
||||
|
||||
let enumerable: EnumerablesMockInstance;
|
||||
let headId: number;
|
||||
let middleId: number;
|
||||
let tailId: number;
|
||||
|
||||
beforeEach(async function () {
|
||||
enumerable = await EnumerablesMock.new();
|
||||
tailId = (
|
||||
await this.enumerables.testAppend(tailData)
|
||||
).logs[0].args.id.toNumber();
|
||||
middleId = (
|
||||
await this.enumerables.testAppend(middleData)
|
||||
).logs[0].args.id.toNumber();
|
||||
headId = (
|
||||
await this.enumerables.testAppend(headData)
|
||||
).logs[0].args.id.toNumber();
|
||||
});
|
||||
|
||||
it('finds an id for given data.', async function () {
|
||||
let resultId = (await this.enumerables.findIdForData(headData));
|
||||
expect(resultId.toNumber()).to.be.equal(headId);
|
||||
resultId = (await this.enumerables.findIdForData(middleData));
|
||||
expect(resultId.toNumber()).to.be.equal(middleId);
|
||||
resultId = (await this.enumerables.findIdForData(tailData));
|
||||
expect(resultId.toNumber()).to.be.equal(tailId);
|
||||
});
|
||||
}); */
|
||||
|
||||
/** @test {Enumerable} describe */
|
||||
describe('Enumerable - remove', (accounts) => {
|
||||
beforeEach(async function () {
|
||||
this.this.enumerables = await EnumerablesMock.new();
|
||||
tailId = (
|
||||
await this.enumerables.testAppend(tailData)
|
||||
).logs[0].args.id.toNumber();
|
||||
middleId = (
|
||||
await this.enumerables.testAppend(middleData)
|
||||
).logs[0].args.id.toNumber();
|
||||
headId = (
|
||||
await this.enumerables.testAppend(headData)
|
||||
).logs[0].args.id.toNumber();
|
||||
});
|
||||
|
||||
it('removes the head.', async function () {
|
||||
const removedId = (
|
||||
await this.enumerables.testRemove(headId)
|
||||
).logs[1].args.id.toNumber();
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(middleId);
|
||||
|
||||
const middleObject = (await this.enumerables.testGet(middleId));
|
||||
expect(middleObject[0].toNumber()).to.be.equal(middleId);
|
||||
expect(middleObject[1].toNumber()).to.be.equal(tailId);
|
||||
expect(middleObject[2].toNumber()).to.be.equal(0);
|
||||
expect(middleObject[3]).to.be.equal(middleData);
|
||||
|
||||
const tailObject = (await this.enumerables.testGet(tailId));
|
||||
expect(tailObject[0].toNumber()).to.be.equal(tailId);
|
||||
expect(tailObject[1].toNumber()).to.be.equal(0);
|
||||
expect(tailObject[2].toNumber()).to.be.equal(middleId);
|
||||
expect(tailObject[3]).to.be.equal(tailData);
|
||||
});
|
||||
|
||||
it('removes the tail.', async function () {
|
||||
const removedId = (
|
||||
await this.enumerables.testRemove(tailId)
|
||||
).logs[1].args.id.toNumber();
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(headId);
|
||||
|
||||
const headObject = (await this.enumerables.testGet(headId));
|
||||
expect(headObject[0].toNumber()).to.be.equal(headId);
|
||||
expect(headObject[1].toNumber()).to.be.equal(middleId);
|
||||
expect(headObject[2].toNumber()).to.be.equal(0);
|
||||
expect(headObject[3]).to.be.equal(headData);
|
||||
|
||||
const middleObject = (await this.enumerables.testGet(middleId));
|
||||
expect(middleObject[0].toNumber()).to.be.equal(middleId);
|
||||
expect(middleObject[1].toNumber()).to.be.equal(0);
|
||||
expect(middleObject[2].toNumber()).to.be.equal(headId);
|
||||
expect(middleObject[3]).to.be.equal(middleData);
|
||||
});
|
||||
|
||||
it('removes the middle.', async function () {
|
||||
const removedId = (
|
||||
await this.enumerables.testRemove(middleId)
|
||||
).logs[1].args.id.toNumber();
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(headId);
|
||||
|
||||
const headObject = (await this.enumerables.testGet(headId));
|
||||
expect(headObject[0].toNumber()).to.be.equal(headId);
|
||||
expect(headObject[1].toNumber()).to.be.equal(tailId);
|
||||
expect(headObject[2].toNumber()).to.be.equal(0);
|
||||
expect(headObject[3]).to.be.equal(headData);
|
||||
|
||||
const tailObject = (await this.enumerables.testGet(tailId));
|
||||
expect(tailObject[0].toNumber()).to.be.equal(tailId);
|
||||
expect(tailObject[1].toNumber()).to.be.equal(0);
|
||||
expect(tailObject[2].toNumber()).to.be.equal(headId);
|
||||
expect(tailObject[3]).to.be.equal(tailData);
|
||||
});
|
||||
|
||||
it('removes all.', async function () {
|
||||
(await this.enumerables.testRemove(headId)).logs[1].args.id.toNumber();
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(middleId);
|
||||
|
||||
(await this.enumerables.testRemove(tailId)).logs[1].args.id.toNumber();
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(middleId);
|
||||
// expect(((await this.enumerables.tail()).toNumber())).to.be.equal(middleId);
|
||||
|
||||
(await this.enumerables.testRemove(middleId)).logs[1].args.id.toNumber();
|
||||
// expect(((await this.enumerables.head()).toNumber())).to.be.equal(0);
|
||||
// expect(((await this.enumerables.tail()).toNumber())).to.be.equal(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user