You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
495 lines
26 KiB
495 lines
26 KiB
import { default as test} from "tape"
|
|
import * as common from '../../src/solidity-analyzer/modules/staticAnalysisCommon'
|
|
const { localCall, thisLocalCall, libCall, externalDirect, superLocal, assignment, abiNamespaceCallNodes,
|
|
inlineAssembly, unaryOperation, nowAst, blockTimestamp, stateVariableContractNode,
|
|
functionDefinition, requireCall, selfdestruct, storageVariableNodes, dynamicDeleteUnaryOp,
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
lowlevelCall, parameterFunction, parameterFunctionCall, inheritance, blockHashAccess, contractDefinition, funcDefForComplexParams } = require('./astBlocks')
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const compiledContractObj = require('./compilationDetails/CompiledContractObj.json')
|
|
function escapeRegExp (str) {
|
|
return str.replace(/[-[\]/{}()+?.\\^$|]/g, '\\$&')
|
|
}
|
|
|
|
test('staticAnalysisCommon.helpers.buildFunctionSignature', function (t) {
|
|
t.plan(11)
|
|
|
|
t.equal(common.helpers.buildFunctionSignature([common.basicTypes.UINT, common.basicTypes.ADDRESS], [common.basicTypes.BOOL], false),
|
|
'function (uint256,address) returns (bool)',
|
|
'two params and return value without payable')
|
|
|
|
t.equal(common.helpers.buildFunctionSignature([common.basicTypes.UINT, common.basicTypes.ADDRESS], [common.basicTypes.BOOL], false, 'pure'),
|
|
'function (uint256,address) pure returns (bool)',
|
|
'two params and return value without payable but pure')
|
|
|
|
t.equal(common.helpers.buildFunctionSignature([common.basicTypes.UINT, common.basicTypes.ADDRESS], [common.basicTypes.BOOL], true, 'pure'),
|
|
'function (uint256,address) payable pure returns (bool)',
|
|
'two params and return value without payable but pure')
|
|
|
|
t.equal(common.helpers.buildFunctionSignature([common.basicTypes.UINT, common.basicTypes.BYTES32, common.basicTypes.BYTES32], [], true),
|
|
'function (uint256,bytes32,bytes32) payable',
|
|
'three params and no return with payable')
|
|
|
|
t.equal(common.helpers.buildFunctionSignature([common.basicTypes.BOOL], [common.basicTypes.BYTES32, common.basicTypes.ADDRESS], true),
|
|
'function (bool) payable returns (bytes32,address)',
|
|
'one param and two return values with payable')
|
|
|
|
t.equal(common.lowLevelCallTypes.CALL.type,
|
|
'function (bytes memory) payable returns (bool,bytes memory)',
|
|
'check fixed call type')
|
|
|
|
t.equal(common.lowLevelCallTypes['CALL-0.4'].type,
|
|
'function () payable returns (bool)',
|
|
'check fixed call type for versions before 0.5.0')
|
|
|
|
t.equal(common.lowLevelCallTypes.CALLCODE.type,
|
|
'function () payable returns (bool)',
|
|
'check fixed callcode type')
|
|
|
|
t.equal(common.lowLevelCallTypes.SEND.type,
|
|
'function (uint256) returns (bool)',
|
|
'check fixed send type')
|
|
|
|
t.equal(common.lowLevelCallTypes.DELEGATECALL.type,
|
|
'function (bytes memory) returns (bool,bytes memory)',
|
|
'check fixed delegatecall type')
|
|
|
|
t.equal(common.lowLevelCallTypes['DELEGATECALL-0.4'].type,
|
|
'function () returns (bool)',
|
|
'check fixed delegatecall type for version before 0.5.0')
|
|
})
|
|
|
|
// #################### Node Identification Primitives
|
|
|
|
test('staticAnalysisCommon.helpers.name', function (t) {
|
|
t.plan(3)
|
|
const node = { name: 'now' }
|
|
const node2 = { memberName: 'call' }
|
|
|
|
t.ok(common.helpers.memName(node, 'now'), 'should work for names')
|
|
t.ok(common.helpers.memName(node2, 'call'), 'should work for memberName')
|
|
t.ok(common.helpers.memName(node2, '.all'), 'regex should work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.helpers.operator', function (t) {
|
|
t.plan(4)
|
|
const node = { operator: '++' }
|
|
const node2 = { operator: '+++' }
|
|
|
|
const escapedPP = escapeRegExp('++')
|
|
const escapedPPExact = `^${escapedPP}$`
|
|
|
|
t.ok(common.helpers.operator(node, escapedPPExact), 'should work for ++')
|
|
t.notOk(common.helpers.operator(node2, escapedPPExact), 'should not work for +++')
|
|
t.ok(common.helpers.operator(node, escapedPP), 'should work for ++')
|
|
t.ok(common.helpers.operator(node2, escapedPP), 'should work for +++')
|
|
})
|
|
|
|
test('staticAnalysisCommon.helpers.nodeType', function (t) {
|
|
t.plan(3)
|
|
const node = { nodeType: 'Identifier', name: 'now'}
|
|
const node2 = { nodeType: 'FunctionCall', memberName: 'call' }
|
|
|
|
t.ok(common.helpers.nodeType(node, common.nodeTypes.IDENTIFIER), 'should work for identifier')
|
|
t.ok(common.helpers.nodeType(node2, common.nodeTypes.FUNCTIONCALL), 'should work for function call')
|
|
t.ok(common.helpers.nodeType(node2, '^F'), 'regex should work for function call')
|
|
})
|
|
|
|
test('staticAnalysisCommon.helpers.expressionTypeDescription', function (t) {
|
|
t.plan(3)
|
|
const node = {
|
|
"expression":
|
|
{
|
|
"argumentTypes":
|
|
[
|
|
{
|
|
"typeIdentifier": "t_stringliteral_c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
"typeString": "literal_string \"\""
|
|
}
|
|
],
|
|
"expression":
|
|
{
|
|
"name": "addr",
|
|
"nodeType": "Identifier",
|
|
"src": "132:4:0",
|
|
"typeDescriptions":
|
|
{
|
|
"typeIdentifier": "t_address_payable",
|
|
"typeString": "address payable"
|
|
}
|
|
},
|
|
"memberName": "call",
|
|
"nodeType": "MemberAccess",
|
|
"typeDescriptions":
|
|
{
|
|
"typeIdentifier": "t_function_barecall_payable$_t_bytes_memory_ptr_$returns$_t_bool_$_t_bytes_memory_ptr_$",
|
|
"typeString": "function (bytes memory) payable returns (bool,bytes memory)"
|
|
}
|
|
},
|
|
"nodeType": "FunctionCall",
|
|
}
|
|
|
|
t.ok(common.helpers.expressionTypeDescription(node.expression, common.basicTypes.PAYABLE_ADDRESS), 'should work for ident')
|
|
t.ok(common.helpers.expressionTypeDescription(node, escapeRegExp(common.basicFunctionTypes.CALL)), 'should work for funcall')
|
|
t.ok(common.helpers.expressionTypeDescription(node, '^function \\('), 'regex should work')
|
|
})
|
|
|
|
// #################### Trivial Getter Test
|
|
|
|
test('staticAnalysisCommon.getType', function (t) {
|
|
t.plan(3)
|
|
const node = { "argumentTypes": null,
|
|
"id": 3,
|
|
"name": "a",
|
|
"nodeType": "Identifier",
|
|
"overloadedDeclarations": [],
|
|
"referencedDeclaration": 22,
|
|
"src": "52:1:0",
|
|
"typeDescriptions":
|
|
{
|
|
"typeIdentifier": "t_uint256",
|
|
"typeString": "uint256"
|
|
}
|
|
}
|
|
t.ok(common.getType(blockHashAccess) === 'bytes32', 'gettype should work for different nodes')
|
|
t.ok(common.getType(node) === 'uint256', 'gettype should work for different nodes')
|
|
t.ok(common.getType(assignment) === 'uint256', 'gettype should work for different nodes')
|
|
})
|
|
|
|
// #################### Complex Getter Test
|
|
|
|
test('staticAnalysisCommon.getFunctionCallType', function (t) {
|
|
t.plan(4)
|
|
t.equal(common.getFunctionCallType(libCall), 'function (struct Set.Data storage pointer,uint256) returns (bool)', 'this lib call returns correct type')
|
|
t.equal(common.getFunctionCallType(thisLocalCall), 'function () external returns (uint256,uint256)', 'this local call returns correct type')
|
|
t.equal(common.getFunctionCallType(localCall), 'function (uint256,string memory)', 'local call returns correct type')
|
|
t.equal(common.getFunctionCallType(externalDirect), 'function () external', 'external call returns correct type')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getEffectedVariableName', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getEffectedVariableName(assignment) === 'a', 'get right name for assignment')
|
|
t.throws(() => common.getEffectedVariableName(inlineAssembly), new RegExp('staticAnalysisCommon.js: wrong node type'), 'staticAnalysisCommon.js: not an effect Node or inline assembly, get from inline assembly should throw')
|
|
t.throws(() => common.getEffectedVariableName(externalDirect), new RegExp('staticAnalysisCommon.js: not an effect Node'), 'should throw on all other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getLocalCallName', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getLocalCallName(localCall) === 'e', 'getLocal call name from node')
|
|
t.throws(() => common.getLocalCallName(externalDirect), new RegExp('staticAnalysisCommon.js: not a local call Node'), 'throws for externalDirect nodes')
|
|
t.throws(() => common.getLocalCallName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not a local call Node'), 'throws for this local call nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getThisLocalCallName', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getThisLocalCallName(thisLocalCall) === 'f', 'get this Local call name from node')
|
|
t.throws(() => common.getThisLocalCallName(externalDirect), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on externalDirect nodes')
|
|
t.throws(() => common.getThisLocalCallName(localCall), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on localCall nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getSuperLocalCallName', function (t) {
|
|
t.plan(4)
|
|
t.equal(common.getSuperLocalCallName(superLocal), 'x', 'get local name from super local call')
|
|
t.throws(() => common.getSuperLocalCallName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not a super local call Node'), 'throws on other nodes')
|
|
t.throws(() => common.getSuperLocalCallName(externalDirect), new RegExp('staticAnalysisCommon.js: not a super local call Node'),' throws on other nodes')
|
|
t.throws(() => common.getSuperLocalCallName(localCall), new RegExp('staticAnalysisCommon.js: not a super local call Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getExternalDirectCallContractName', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getExternalDirectCallContractName(externalDirect) === 'c', 'external direct call contract name from node')
|
|
t.throws(() => common.getExternalDirectCallContractName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
|
|
t.throws(() => common.getExternalDirectCallContractName(localCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getThisLocalCallContractName', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getThisLocalCallContractName(thisLocalCall) === 'C', 'this local call contract name from node')
|
|
t.throws(() => common.getThisLocalCallContractName(localCall), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on other nodes')
|
|
t.throws(() => common.getThisLocalCallContractName(externalDirect), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getExternalDirectCallMemberName', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getExternalDirectCallMemberName(externalDirect) === 'f', 'external direct call name from node')
|
|
t.throws(() => common.getExternalDirectCallMemberName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
|
|
t.throws(() => common.getExternalDirectCallMemberName(localCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getContractName', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.getContractName(contractDefinition) === 'C', 'returns right contract name')
|
|
t.throws(() => common.getContractName(inheritance), new RegExp('staticAnalysisCommon.js: not a ContractDefinition Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getFunctionDefinitionName', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.getFunctionDefinitionName(functionDefinition) === 'f', 'returns right function name')
|
|
t.throws(() => common.getFunctionDefinitionName(inheritance), new RegExp('staticAnalysisCommon.js: not a FunctionDefinition Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getInheritsFromName', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.getInheritsFromName(inheritance) === 'A', 'returns right contract name')
|
|
t.throws(() => common.getInheritsFromName(functionDefinition), new RegExp('staticAnalysisCommon.js: not an InheritanceSpecifier Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getDeclaredVariableName', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.getDeclaredVariableName(storageVariableNodes.node1) === 'c', 'extract right variable name')
|
|
const node1 = JSON.parse(JSON.stringify(storageVariableNodes))
|
|
node1.node1.nodeType = 'FunctionCall'
|
|
t.throws(() => common.getDeclaredVariableName(node1) === 'x', new RegExp('staticAnalysisCommon.js: not a VariableDeclaration Node'), 'throw if wrong node')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getStateVariableDeclarationsFromContractNode', function (t) {
|
|
t.plan(3)
|
|
const res = common.getStateVariableDeclarationsFromContractNode(stateVariableContractNode).map(common.getDeclaredVariableName)
|
|
t.ok(res[0] === 'x', 'var 1 should be x')
|
|
t.ok(res[1] === 'b', 'var 2 should be b')
|
|
t.ok(res[2] === 's', 'var 3 should be s')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getFunctionOrModifierDefinitionParameterPart', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.helpers.nodeType(common.getFunctionOrModifierDefinitionParameterPart(functionDefinition), 'ParameterList'), 'should return a parameterList')
|
|
t.throws(() => common.getFunctionOrModifierDefinitionParameterPart(contractDefinition), new RegExp('staticAnalysisCommon.js: not a FunctionDefinition or ModifierDefinition Node'), 'throws on other nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getFunctionCallTypeParameterType', function (t) {
|
|
t.plan(4)
|
|
t.ok(common.getFunctionCallTypeParameterType(thisLocalCall) === '', 'this local call returns correct type')
|
|
t.ok(common.getFunctionCallTypeParameterType(externalDirect) === '', 'external direct call returns correct type')
|
|
t.ok(common.getFunctionCallTypeParameterType(localCall) === 'uint256,string memory', 'local call returns correct type')
|
|
t.throws(() => common.getFunctionCallTypeParameterType(thisLocalCall.expression), new RegExp('staticAnalysisCommon.js: cannot extract parameter types from function call'), 'throws on wrong type')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getLibraryCallContractName', function (t) {
|
|
t.plan(2)
|
|
t.equal(common.getLibraryCallContractName(libCall), 'Set', 'should return correct contract name')
|
|
t.throws(() => common.getLibraryCallContractName(contractDefinition), new RegExp('staticAnalysisCommon.js: not a library call Node'), 'should throw on wrong node')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getLibraryCallMemberName', function (t) {
|
|
t.plan(2)
|
|
t.equal(common.getLibraryCallMemberName(libCall), 'insert', 'should return correct member name')
|
|
t.throws(() => common.getLibraryCallMemberName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not a library call Node'), 'should throw on wrong node')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getFullQualifiedFunctionCallIdent', function (t) {
|
|
t.plan(4)
|
|
t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, thisLocalCall) === 'C.f()', 'this local call returns correct type')
|
|
t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, externalDirect) === 'c.f()', 'external direct call returns correct type')
|
|
t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, localCall) === 'C.e(uint256,string memory)', 'local call returns correct type')
|
|
t.throws(() => common.getFullQualifiedFunctionCallIdent(contractDefinition, assignment), new RegExp('staticAnalysisCommon.js: Can not get function name from non function call node'), 'throws on wrong type')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getFullQuallyfiedFuncDefinitionIdent', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getFullQuallyfiedFuncDefinitionIdent(contractDefinition, functionDefinition, ['uint256', 'bool']) === 'C.f(uint256,bool)', 'creates right signature')
|
|
t.throws(() => common.getFullQuallyfiedFuncDefinitionIdent(contractDefinition, parameterFunctionCall, ['uint256', 'bool']), new RegExp('staticAnalysisCommon.js: not a FunctionDefinition Node'), 'throws on wrong nodes')
|
|
t.throws(() => common.getFullQuallyfiedFuncDefinitionIdent(parameterFunctionCall, functionDefinition, ['uint256', 'bool']), new RegExp('staticAnalysisCommon.js: not a ContractDefinition Node'), 'throws on wrong nodes')
|
|
})
|
|
|
|
test('staticAnalysisCommon.getSplittedTypeDesc', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.getMethodParamsSplittedTypeDesc(funcDefForComplexParams.withoutParams, compiledContractObj).length === 0, 'no params, no params type signature')
|
|
t.ok(common.getMethodParamsSplittedTypeDesc(funcDefForComplexParams.bytesArray, compiledContractObj)[0] === 'bytes32[]', 'creates right params type signature')
|
|
t.ok(common.getMethodParamsSplittedTypeDesc(funcDefForComplexParams.nestedStruct, compiledContractObj)[0] === '(bytes32,uint256,uint256[],address,(bytes32,uint256)[])[][]', 'creates right params type signature')
|
|
})
|
|
|
|
// #################### Complex Node Identification
|
|
|
|
test('staticAnalysisCommon.isBuiltinFunctionCall', function (t) {
|
|
t.plan(1)
|
|
t.ok(common.isBuiltinFunctionCall(selfdestruct), 'selfdestruct is builtin')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isStorageVariableDeclaration', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.isStorageVariableDeclaration(storageVariableNodes.node1), 'struct storage pointer param is storage')
|
|
t.ok(common.isStorageVariableDeclaration(storageVariableNodes.node2), 'struct storage pointer mapping param is storage')
|
|
t.notOk(common.isStorageVariableDeclaration(storageVariableNodes.node3), 'bytes is not storage')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isInteraction', function (t) {
|
|
t.plan(5)
|
|
t.ok(common.isInteraction(lowlevelCall.sendAst), 'send is interaction')
|
|
t.ok(common.isInteraction(lowlevelCall.callAst), 'call is interaction')
|
|
t.ok(common.isInteraction(externalDirect), 'ExternalDirectCall is interaction')
|
|
t.notOk(common.isInteraction(lowlevelCall.delegatecallAst), 'delegatecall is not interaction')
|
|
t.notOk(common.isInteraction(localCall), 'local call is not interaction')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isEffect', function (t) {
|
|
t.plan(5)
|
|
t.ok(common.isEffect(inlineAssembly), 'inline assembly is treated as effect')
|
|
t.ok(common.isEffect(assignment), 'assignment is treated as effect')
|
|
t.ok(common.isEffect(unaryOperation), '++ is treated as effect')
|
|
const node = JSON.parse(JSON.stringify(unaryOperation))
|
|
node.operator = '--'
|
|
t.ok(common.isEffect(node), '-- is treated as effect')
|
|
t.notOk(common.isEffect(externalDirect.expression), 'MemberAccess not treated as effect')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isWriteOnStateVariable', function (t) {
|
|
t.plan(3)
|
|
const node1 = JSON.parse(JSON.stringify(storageVariableNodes.node1))
|
|
const node2 = node1
|
|
const node3 = node1
|
|
node2.name = 'y'
|
|
node3.name = 'xx'
|
|
t.ok(common.isWriteOnStateVariable(inlineAssembly, [node1, node2, node3]), 'inline Assembly is write on state')
|
|
t.notOk(common.isWriteOnStateVariable(assignment, [node1, node2, node3]), 'assignment on non state is not write on state')
|
|
node3.name = 'a' // same as assignment left hand side var name
|
|
t.ok(common.isWriteOnStateVariable(assignment, [node1, node2, node3]), 'assignment on state is write on state')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isStateVariable', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.isStateVariable('c', [storageVariableNodes.node1, storageVariableNodes.node2]), 'is contained')
|
|
t.ok(common.isStateVariable('c', [storageVariableNodes.node2, storageVariableNodes.node1, storageVariableNodes.node1]), 'is contained twice')
|
|
t.notOk(common.isStateVariable('c', [storageVariableNodes.node2, storageVariableNodes.node3]), 'not contained')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isConstantFunction', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.isConstantFunction(functionDefinition), 'should be const func definition')
|
|
functionDefinition.stateMutability = 'view'
|
|
t.ok(common.isConstantFunction(functionDefinition), 'should be const func definition')
|
|
functionDefinition.stateMutability = 'nonpayable'
|
|
t.notOk(common.isConstantFunction(functionDefinition), 'should not be const func definition')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isPlusPlusUnaryOperation', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.isPlusPlusUnaryOperation(unaryOperation), 'should be unary ++')
|
|
const node = JSON.parse(JSON.stringify(unaryOperation))
|
|
node.operator = '--'
|
|
t.notOk(common.isPlusPlusUnaryOperation(node), 'should not be unary ++')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isMinusMinusUnaryOperation', function (t) {
|
|
t.plan(2)
|
|
unaryOperation.operator = '--'
|
|
t.ok(common.isMinusMinusUnaryOperation(unaryOperation), 'should be unary --')
|
|
unaryOperation.operator = '++'
|
|
t.notOk(common.isMinusMinusUnaryOperation(unaryOperation), 'should not be unary --')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isFullyImplementedContract', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.isFullyImplementedContract(contractDefinition), 'should be fully implemented contract')
|
|
const node = JSON.parse(JSON.stringify(contractDefinition))
|
|
node.fullyImplemented = false
|
|
t.notOk(common.isFullyImplementedContract(node), 'should not be fully implemented contract')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isCallToNonConstLocalFunction', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.isCallToNonConstLocalFunction(localCall), 'should be call to non const Local func')
|
|
const node = JSON.parse(JSON.stringify(localCall))
|
|
node.expression.typeDescriptions.typeString = 'function (struct Ballot.Voter storage pointer) view payable (uint256)'
|
|
t.notok(common.isCallToNonConstLocalFunction(node), 'should no longer be call to non const Local func')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isExternalDirectCall', function (t) {
|
|
t.plan(5)
|
|
t.notOk(common.isThisLocalCall(externalDirect), 'is this.local_method() used should not work')
|
|
t.notOk(common.isBlockTimestampAccess(externalDirect), 'is block.timestamp used should not work')
|
|
t.notOk(common.isNowAccess(externalDirect), 'is now used should not work')
|
|
t.ok(common.isExternalDirectCall(externalDirect), 'c.f() should be external direct call')
|
|
t.notOk(common.isExternalDirectCall(thisLocalCall.expression), 'this local call is not an external call')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isNowAccess', function (t) {
|
|
t.plan(1)
|
|
t.ok(common.isNowAccess(nowAst), 'is now used should work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isBlockTimestampAccess', function (t) {
|
|
t.plan(3)
|
|
t.notOk(common.isThisLocalCall(blockTimestamp), 'is this.local_method() used should not work')
|
|
t.ok(common.isBlockTimestampAccess(blockTimestamp), 'is block.timestamp used should work')
|
|
t.notOk(common.isNowAccess(blockTimestamp), 'is now used should not work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isBlockBlockhashAccess', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.isBlockBlockHashAccess(blockHashAccess), 'blockhash should work')
|
|
t.notOk(common.isNowAccess(blockHashAccess.expression), 'is now used should not work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isThisLocalCall', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.isThisLocalCall(thisLocalCall.expression), 'is this.local_method() used should work')
|
|
t.notOk(common.isBlockTimestampAccess(thisLocalCall.expression), 'is block.timestamp used should not work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isSuperLocalCall', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.isSuperLocalCall(superLocal.expression), 'is super.local_method() used should work')
|
|
t.notOk(common.isThisLocalCall(superLocal.expression), 'is this.local_method() used should not work')
|
|
t.notOk(common.isBlockTimestampAccess(superLocal.expression), 'is block.timestamp used should not work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isLibraryCall', function (t) {
|
|
t.plan(4)
|
|
t.ok(common.isLibraryCall(libCall.expression), 'is lib call should not work')
|
|
t.notOk(common.isSuperLocalCall(libCall.expression), 'is super.local_method() used should not work')
|
|
t.notOk(common.isThisLocalCall(libCall.expression), 'is this.local_method() used should not work')
|
|
t.notOk(common.isBlockTimestampAccess(libCall.expression), 'is block.timestamp used should not work')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isLocalCall', function (t) {
|
|
t.plan(1)
|
|
t.ok(common.isLocalCall(localCall), 'isLocalCall')
|
|
})
|
|
|
|
test('staticAnalysisCommon.isLowLevelCall', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.isLLSend(lowlevelCall.sendAst.expression) && common.isLowLevelCall(lowlevelCall.sendAst.expression), 'send is llc should work')
|
|
t.ok(common.isLLCall(lowlevelCall.callAst.expression) && common.isLowLevelCall(lowlevelCall.callAst.expression), 'call is llc should work')
|
|
t.ok(common.isLLDelegatecall(lowlevelCall.delegatecallAst) && common.isLowLevelCall(lowlevelCall.delegatecallAst), 'delegatecall is llc should work')
|
|
})
|
|
|
|
test('staticAnalysisCommon: Call of parameter function', function (t) {
|
|
t.plan(3)
|
|
t.ok(common.isLocalCall(parameterFunction), 'is not LocalCall')
|
|
t.equals(common.getFunctionCallType(parameterFunction), 'function (uint256,uint256)', 'Extracts right type')
|
|
t.equals(common.getFunctionCallTypeParameterType(parameterFunction), 'uint256,uint256', 'Extracts param right type')
|
|
})
|
|
|
|
test('staticAnalysisCommon: function call with of function with function parameter', function (t) {
|
|
t.plan(2)
|
|
t.equals(common.getFunctionCallType(parameterFunctionCall), 'function (function (uint256) pure returns (uint256)) pure returns (uint256)', 'Extracts right type')
|
|
t.equals(common.getFunctionCallTypeParameterType(parameterFunctionCall), 'function (uint256) pure returns (uint256)', 'Extracts param right type')
|
|
})
|
|
|
|
test('staticAnalysisCommon: require call', function (t) {
|
|
t.plan(3)
|
|
t.equals(common.isRequireCall(requireCall), true)
|
|
t.equals(common.getFunctionCallType(requireCall), 'function (bool) pure', 'Extracts right type')
|
|
t.equals(common.getFunctionCallTypeParameterType(requireCall), 'bool', 'Extracts param right type')
|
|
})
|
|
|
|
test('staticAnalysisCommon: isDeleteOfDynamicArray', function (t) {
|
|
t.plan(2)
|
|
t.ok(common.isDeleteOfDynamicArray(dynamicDeleteUnaryOp), 'is dynamic array deletion')
|
|
t.ok(common.isDynamicArrayAccess(dynamicDeleteUnaryOp.subExpression), 'Extracts right type')
|
|
})
|
|
|
|
test('staticAnalysisCommon: isAbiNamespaceCall', function (t) {
|
|
t.plan(8)
|
|
t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encode), true, 'encode abi')
|
|
t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encodePacked), true, 'encodePacked abi')
|
|
t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encodeWithSelector), true, 'encodeWithSelector abi')
|
|
t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encodeWithSignature), true, 'encodeWithSignature abi')
|
|
|
|
t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encode), true, 'encode Builtin')
|
|
t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encodePacked), true, 'encodePacked Builtin')
|
|
t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encodeWithSelector), true, 'encodeWithSelector Builtin')
|
|
t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encodeWithSignature), true, 'encodeWithSignature Builtin')
|
|
})
|
|
|