UNPKG

solhint-community

Version:
178 lines (160 loc) 6.99 kB
const linter = require('../../../lib/index') const { configGetter } = require('../../../lib/config/config-file') const { assertNoWarnings, assertWarnsCount, assertErrorMessage } = require('../../common/asserts') const { contractWith, multiLine, funcWith } = require('../../common/contract-builder') describe('Linter - named-parameters-function', () => { describe('GIVEN default rule settings', function () { const config = { rules: { 'named-parameters-function': 'warn' }, } it('WHEN calling with two positional arguments THEN it does NOT report', () => { const code = contractWith( multiLine('function foo(uint a, uint b) {}', `function bar (){foo(1,2);}`) ) assertNoWarnings(linter.processStr(code, config)) }) it('WHEN calling with four positional arguments THEN it reports', () => { const code = contractWith( multiLine( 'function foo(uint a, uint b, uint c, uint d) {}', `function bar (){foo(1,2,3,4);}` ) ) const report = linter.processStr(code, config) assertWarnsCount(report, 1) assertErrorMessage( report, 'Call to function with arity > 3 is using positional arguments. Use named arguments instead.' ) }) it('WHEN calling with four named arguments THEN it does NOT report', () => { const code = contractWith( multiLine( 'function foo(uint a, uint b, uint c, uint d) {}', `function bar (){foo({a: 1, b: 2, c:3, d:4});}` ) ) assertNoWarnings(linter.processStr(code, config)) }) }) describe('GIVEN a setting of one maximum positional argument', function () { const config = { rules: { 'named-parameters-function': ['warn', 1] }, } describe('builitin functions with named parameters', function () { it('WHEN calling require with a positional error message THEN it reports', function () { const code = funcWith('require(false, "this is an error");') assertWarnsCount(linter.processStr(code, config), 1) }) it('WHEN calling require with a named error message THEN it does NOT report', function () { const code = funcWith('require({condition: false, message: "this is an error"});') assertNoWarnings(linter.processStr(code, config)) }) it('WHEN calling require without an error message THEN it does NOT report', function () { const code = funcWith('require(false);') assertNoWarnings(linter.processStr(code, config)) }) it('WHEN calling builtin function mulmod with named parameters THEN it does NOT report', function () { const code = funcWith('uint r = mulmod({x: 100, y: 7, k: 4});') assertNoWarnings(linter.processStr(code, config)) }) it('WHEN calling builtin function ecrecover with named parameters THEN it does NOT report', function () { const code = funcWith('uint r = ecrecover({hash: foo, v: bar, r: baz, s: moo});') assertNoWarnings(linter.processStr(code, config)) }) it('WHEN calling builtin function ecrecover with positional parameters THEN it reports', function () { const code = funcWith('uint r = ecrecover(foo, bar, baz, moo);') assertWarnsCount(linter.processStr(code, config), 1) }) }) describe('builtin variadic functions', function () { it('WHEN calling abi.decode with positional arguments, THEN it does NOT report', function () { const code = funcWith('(uint a, uint b, uint c) = abi.decode(data, (uint, uint, uint));') assertNoWarnings(linter.processStr(code, config)) }) ;['encode', 'encodePacked', 'encodeWithSelector', 'encodeWithSignature'].forEach((method) => { it(`WHEN calling abi.${method} with positional arguments, THEN it does NOT report`, function () { const code = funcWith(`bytes foo = abi.${method}(foo, bar, baz);`) assertNoWarnings(linter.processStr(code, config)) }) }) }) }) describe('GIVEN an invalid setting of zero', function () { const config = { rules: { 'named-parameters-function': ['warn', 0] }, } it('WHEN calling no arguments THEN it does NOT report', () => { const code = contractWith(multiLine('function foo() {}', `function bar (){foo();}`)) assertNoWarnings(linter.processStr(code, config)) }) it('WHEN calling with one positional argument THEN it does NOT report', () => { const code = contractWith(multiLine('function foo(uint a) {}', `function bar (){foo(3);}`)) assertNoWarnings(linter.processStr(code, config)) }) it('WHEN doing a cast to a user defined type, THEN it should NOT report an error', function () { const code = ` contract A {} contract B { address public a; function setA(address addr) external { a = A(addr); } } ` assertNoWarnings(linter.processStr(code, config)) }) ;[ ['uint', 'uint256', 'int', 'int256', 'uint8', 'int128'], ['ufixed', 'ufixed128x18', 'fixed', 'fixed128x18'], ['bytes1', 'bytes32', 'bytes', 'bytes12'], ['address', 'payable', 'address payable'], ] .flat() .forEach((i) => { it(`WHEN doing a cast to native type ${i} THEN it does NOT report an error`, function () { const code = contractWith(`function bar (){${i}(3);}`) assertNoWarnings(linter.processStr(code, config)) }) }) }) it('GIVEN a setting of 4, THEN it does NOT warn on calls with four positional arguments', () => { const code = contractWith( multiLine('function foo(uint a, uint b, uint c, uint d) {}', `function bar (){foo(1,2,3,4);}`) ) const report = linter.processStr(code, { rules: { 'named-parameters-function': ['warn', 4] }, }) assertNoWarnings(report) }) it('GIVEN a recommended solhint config, THEN the rule is disabled and no errors are reported', () => { const code = contractWith( multiLine( 'function foo(uint256 a, uint256 b, uint256 c, uint256 d) public {}', `function bar () public {foo(1,2,3,4);}` ) ) const report = linter.processStr(code, { rules: { ...configGetter('solhint:recommended').rules, 'compiler-version': 'off', 'no-unused-vars': 'off', 'no-empty-blocks': 'off', }, }) assertNoWarnings(report) }) it('GIVEN a setting of 2, THEN it warns on calls with 3 positional argument', () => { const code = contractWith( multiLine('function foo(uint a, uint b, uint c) {}', `function bar (){foo(1,2,3);}`) ) const report = linter.processStr(code, { rules: { 'named-parameters-function': ['warn', 2] }, }) assertWarnsCount(report, 1) assertErrorMessage( report, 'Call to function with arity > 2 is using positional arguments. Use named arguments instead.' ) }) })