156 lines
6.9 KiB
TypeScript

import { blockchainTests, constants, expect, hexSlice } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import { BlockParam, CallData } from 'ethereum-types';
import * as ethUtil from 'ethereumjs-util';
import { artifacts, TestFrameworkContract } from '../../src';
import { GetterCache } from '../utils/cache';
blockchainTests.resets('Cache Tests', env => {
let exampleContract: TestFrameworkContract;
before(async () => {
exampleContract = await TestFrameworkContract.deployFrom0xArtifactAsync(
artifacts.TestFramework,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('callAsync', () => {
describe('() => uint', () => {
let cache: GetterCache;
beforeEach(async () => {
cache = new GetterCache(exampleContract.numberSideEffect);
});
it('should return 0 when "counter" == 0', async () => {
expect(await cache.callAsync()).bignumber.to.be.eq(constants.ZERO_AMOUNT);
});
it('should return 1 when "counter" == 1', async () => {
// Update the counter to 1.
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
// Ensure that the returned value is the updated counter.
expect(await cache.callAsync()).bignumber.to.be.eq(new BigNumber(1));
});
it('should return the cached counter', async () => {
// Cache a value.
expect(await cache.callAsync()).bignumber.to.be.eq(constants.ZERO_AMOUNT);
// Update the counter to 1.
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
// This should return "0" because a value was cached by the first call to "callAsync"
expect(await cache.callAsync()).bignumber.to.be.eq(constants.ZERO_AMOUNT);
});
});
describe('uint => boolean', () => {
let cache: GetterCache;
beforeEach(async () => {
cache = new GetterCache(exampleContract.equalsSideEffect);
});
it('should return true when "possiblyZero" == 0 && "counter" == 0', async () => {
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
});
it('should return false when "possiblyZero" == 0 && "counter" != 0', async () => {
// Update "counter" to "1", which will cause all calls to return false.
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.false();
});
it('should return the cached value', async () => {
// Cache a "true" value when "possiblyZero" == 0 && "counter" == 0
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
// Update "counter" to "1", which will cause all calls of "isZeroOrFalse" to return "false".
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
// This should return "true" because a value was by the first call to "callAsync"
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
});
});
describe('(uint, bytes32) => bytes32', () => {
let cache: GetterCache;
beforeEach(async () => {
cache = new GetterCache(exampleContract.hashSideEffect);
});
it('should return correct hash when counter == 0', async () => {
// Get the calldata for the function call, which includes the abi-encoded data to hash.
const hashData = exampleContract.hashSideEffect.getABIEncodedTransactionData(
new BigNumber(1),
ethUtil.bufferToHex(ethUtil.sha3(0)),
);
// Ensure that the correct hash was returned from the cache.
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(
ethUtil.bufferToHex(ethUtil.sha3(hexSlice(hashData, 4))),
);
});
it('should return the null hash when counter != 0', async () => {
// Update "counter" to "1", which will cause all calls to return the null hash.
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
// Ensure that the cache returns the correct value.
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(
ethUtil.bufferToHex(ethUtil.sha3('0x')),
);
});
it('should return the cached hash', async () => {
// Get the calldata for the function call, which includes the abi-encoded data to hash.
const hashData = exampleContract.hashSideEffect.getABIEncodedTransactionData(
new BigNumber(1),
ethUtil.bufferToHex(ethUtil.sha3(0)),
);
const hash = ethUtil.bufferToHex(ethUtil.sha3(hexSlice(hashData, 4)));
// Ensure that the cache returns the correct value.
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(hash);
// Update "counter" to "1", which will cause all calls to return the null hash.
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
// The cache should return the same value as the first call to `callAsync` since a value was cached.
expect(await cache.callAsync(new BigNumber(1), ethUtil.bufferToHex(ethUtil.sha3(0)))).to.be.eq(hash);
});
});
});
describe('flush', () => {
describe('uint => boolean', () => {
let cache: GetterCache;
beforeEach(async () => {
cache = new GetterCache(exampleContract.equalsSideEffect);
});
it('should return false when the cache was flushed && "possiblyZero" == 0 && "counter" != 0', async () => {
// Cache a "true" value when "possiblyZero" == 0 && "counter" == 0
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.true();
// Update "counter" to "1", which will cause all calls of "isZeroOrFalse" to return "false".
await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1));
// Flush the entire cache.
cache.flush();
// This should return "false" because the value was flushed.
expect(await cache.callAsync(constants.ZERO_AMOUNT)).to.be.false();
});
});
});
});