Add more tests

- Marketplace tests for requestsForHost, and additional tests for myRequests and mySlots
- Added Utils lib with tests
- Added additional Bytes32AddressSetMap.keys expectations
This commit is contained in:
Eric Mastro 2022-11-23 00:14:39 +11:00
parent a51491a6cb
commit d70efad7bd
No known key found for this signature in database
GPG Key ID: 141E3048D95A4E63
7 changed files with 186 additions and 4 deletions

View File

@ -7,6 +7,7 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "./Collateral.sol"; import "./Collateral.sol";
import "./Proofs.sol"; import "./Proofs.sol";
import "./libs/SetMap.sol"; import "./libs/SetMap.sol";
import "./libs/Utils.sol";
contract Marketplace is Collateral, Proofs { contract Marketplace is Collateral, Proofs {
using EnumerableSet for EnumerableSet.Bytes32Set; using EnumerableSet for EnumerableSet.Bytes32Set;
@ -43,7 +44,16 @@ contract Marketplace is Collateral, Proofs {
function myRequests() public view returns (RequestId[] memory) { function myRequests() public view returns (RequestId[] memory) {
SetMap.AddressBytes32SetMapKey key = _toAddressSetMapKey(msg.sender); SetMap.AddressBytes32SetMapKey key = _toAddressSetMapKey(msg.sender);
return _toRequestIds(activeRequestsForClients.values(key)); RequestId[] memory requestIds = _toRequestIds(activeRequestsForClients.values(key));
RequestId[] memory result = new RequestId[](requestIds.length);
uint8 counter = 0;
for (uint8 i = 0; i < requestIds.length; i++) {
if (!_isCancelled(requestIds[i])) {
result[counter] = requestIds[i];
counter++;
}
}
return _toRequestIds(Utils._resize(_toBytes32s(result), counter));
} }
function requestsForHost(address host) public view returns(RequestId[] memory) { function requestsForHost(address host) public view returns(RequestId[] memory) {
@ -55,12 +65,14 @@ contract Marketplace is Collateral, Proofs {
for (uint8 i = 0; i < keyLength; i++) { for (uint8 i = 0; i < keyLength; i++) {
RequestId requestId = RequestId.wrap(keys.at(i)); RequestId requestId = RequestId.wrap(keys.at(i));
SetMap.Bytes32AddressSetMapKey key = _toBytes32AddressSetMapKey(requestId); SetMap.Bytes32AddressSetMapKey key = _toBytes32AddressSetMapKey(requestId);
if (activeRequestsForHosts.contains(key, host)) { if (activeRequestsForHosts.contains(key, host) &&
!_isCancelled(requestId))
{
result[counter] = requestId; result[counter] = requestId;
counter++; counter++;
} }
} }
return result; return _toRequestIds(Utils._resize(_toBytes32s(result), counter));
} }
function mySlots(RequestId requestId) function mySlots(RequestId requestId)
@ -442,6 +454,17 @@ contract Marketplace is Collateral, Proofs {
} }
} }
function _toBytes32s(RequestId[] memory array)
private
pure
returns (bytes32[] memory result)
{
// solhint-disable-next-line no-inline-assembly
assembly {
result := array
}
}
function _toSlotId(RequestId requestId, uint256 slotIndex) function _toSlotId(RequestId requestId, uint256 slotIndex)
internal internal
pure pure

View File

@ -315,5 +315,6 @@ library SetMap {
internal internal
{ {
map._index[key]++; map._index[key]++;
map._keys.remove(Bytes32AddressSetMapKey.unwrap(key));
} }
} }

View File

@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Utils.sol";
// exposes public functions for testing
contract TestUtils {
function resize(bytes32[] memory array,
uint8 newSize)
public
pure
returns (bytes32[] memory)
{
return Utils._resize(array, newSize);
}
}

23
contracts/libs/Utils.sol Normal file
View File

@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
library Utils {
function _resize(bytes32[] memory array, uint8 newSize)
internal
pure
returns (bytes32[] memory)
{
require(newSize <= array.length, "size out of bounds");
if (newSize == 0) {
bytes32[] memory empty;
return empty;
} else {
bytes32[] memory sized = new bytes32[](newSize);
for (uint8 i = 0; i < newSize; i++) {
sized[i] = array[i];
}
return sized;
}
}
}

View File

@ -705,6 +705,12 @@ describe("Marketplace", function () {
expect(await marketplace.myRequests()).to.deep.equal([requestId(request)]) expect(await marketplace.myRequests()).to.deep.equal([requestId(request)])
}) })
it("removes request from list when cancelled", async function () {
await marketplace.requestStorage(request)
await waitUntilCancelled(request)
expect(await marketplace.myRequests()).to.deep.equal([])
})
it("removes request from list when funds are withdrawn", async function () { it("removes request from list when funds are withdrawn", async function () {
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
await waitUntilCancelled(request) await waitUntilCancelled(request)
@ -732,6 +738,56 @@ describe("Marketplace", function () {
}) })
}) })
describe("list of active requests for host", function () {
beforeEach(async function () {
switchAccount(client)
await token.approve(marketplace.address, price(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, collateral)
await marketplace.deposit(collateral)
})
it("is empty when no slot is filled", async function () {
expect(await marketplace.requestsForHost(host.address)).to.deep.equal([])
})
it("adds request to list when filling slot", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
expect(await marketplace.requestsForHost(host.address)).to.deep.equal([
slot.request,
])
})
it("removes request from list when cancelled", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
await waitUntilCancelled(request)
expect(await marketplace.requestsForHost(host.address)).to.deep.equal([])
})
it("removes request from list when funds are withdrawn", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
await waitUntilCancelled(request)
switchAccount(client)
await marketplace.withdrawFunds(slot.request)
expect(await marketplace.requestsForHost(host.address)).to.deep.equal([])
})
it("removes request from list when request fails", async function () {
await waitUntilStarted(marketplace, request, proof)
await waitUntilFailed(marketplace, request, slot)
expect(await marketplace.requestsForHost(host.address)).to.deep.equal([])
})
it("removes request from list when request finishes", async function () {
switchAccount(host)
await waitUntilStarted(marketplace, request, proof)
await waitUntilFinished(marketplace, requestId(request))
await marketplace.payoutSlot(slot.request, slot.index)
expect(await marketplace.requestsForHost(host.address)).to.deep.equal([])
})
})
describe("list of active slots", function () { describe("list of active slots", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
@ -762,6 +818,14 @@ describe("Marketplace", function () {
]) ])
}) })
it("returns no slots when cancelled", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
let slot1 = { ...slot, index: slot.index + 1 }
await marketplace.fillSlot(slot.request, slot1.index, proof)
await waitUntilCancelled(request)
expect(await marketplace.mySlots(slot.request)).to.deep.equal([])
})
it("removes active slots for all hosts in a request when it fails", async function () { it("removes active slots for all hosts in a request when it fails", async function () {
let halfOfSlots = request.ask.slots / 2 let halfOfSlots = request.ask.slots / 2

View File

@ -151,6 +151,15 @@ describe("SetMap", function () {
hexlify(key), hexlify(key),
hexlify(key1), hexlify(key1),
]) ])
await contract.remove(key1, value)
await expect(await contract.keys()).to.deep.equal([
hexlify(key),
hexlify(key1),
])
await contract.remove(key1, value1)
await expect(await contract.keys()).to.deep.equal([hexlify(key)])
await contract.clear(key)
await expect(await contract.keys()).to.deep.equal([])
}) })
it("contains a key/value pair", async function () { it("contains a key/value pair", async function () {

45
test/Utils.test.js Normal file
View File

@ -0,0 +1,45 @@
const { ethers } = require("hardhat")
const { expect } = require("chai")
const { hexlify, randomBytes } = ethers.utils
const { exampleAddress } = require("./examples")
const { hexZeroPad } = require("ethers/lib/utils")
describe("Utils", function () {
let contract
let value1
let value2
let value3
let value4
let value5
let array
describe("resize", function () {
beforeEach(async function () {
let Utils = await ethers.getContractFactory("TestUtils")
contract = await Utils.deploy()
value1 = hexlify(randomBytes(32))
value2 = hexlify(randomBytes(32))
value3 = hexlify(randomBytes(32))
value4 = hexZeroPad(0, 32)
value5 = hexZeroPad(0, 32)
array = [value1, value2, value3, value4, value5]
})
it("resizes to zero length if new size is 0", async function () {
await expect(await contract.resize(array, 0)).to.deep.equal([])
})
it("resizes to specified length", async function () {
await expect(await contract.resize(array, 3)).to.deep.equal([
value1,
value2,
value3,
])
})
it("fails to resize to out of bounds length", async function () {
await expect(contract.resize(array, 6))
.to.be.revertedWith("size out of bounds")
})
})
})