From 1aec62e90663f444f30c5ecc5603859bb381805d Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Tue, 16 Sep 2025 16:17:34 -0300 Subject: [PATCH 1/4] feat: foundry-no-block-time-number rule --- conf/rulesets/solhint-all.js | 1 + .../foundry-no-block-time-number.js | 102 +++++++++ lib/rules/miscellaneous/index.js | 2 + .../naming/foundry-test-function-naming.js | 4 +- lib/rules/naming/index.js | 4 +- test/common/config-validator.js | 137 ++++++++++++ .../foundry-no-block-time-number.js | 202 ++++++++++++++++++ test/rules/miscellaneous/import-path-check.js | 2 +- 8 files changed, 449 insertions(+), 5 deletions(-) create mode 100644 lib/rules/miscellaneous/foundry-no-block-time-number.js create mode 100644 test/rules/miscellaneous/foundry-no-block-time-number.js diff --git a/conf/rulesets/solhint-all.js b/conf/rulesets/solhint-all.js index 35178955..d7807645 100644 --- a/conf/rulesets/solhint-all.js +++ b/conf/rulesets/solhint-all.js @@ -67,6 +67,7 @@ module.exports = Object.freeze({ 'gas-struct-packing': 'warn', 'comprehensive-interface': 'warn', 'duplicated-imports': 'warn', + 'foundry-no-block-time-number': ['warn', ['test', 'tests']], 'import-path-check': ['warn', ['[~dependenciesPath]']], quotes: ['error', 'double'], 'const-name-snakecase': 'warn', diff --git a/lib/rules/miscellaneous/foundry-no-block-time-number.js b/lib/rules/miscellaneous/foundry-no-block-time-number.js new file mode 100644 index 00000000..e3e4eb4f --- /dev/null +++ b/lib/rules/miscellaneous/foundry-no-block-time-number.js @@ -0,0 +1,102 @@ +const path = require('path') +const BaseChecker = require('../base-checker') +const { severityDescription } = require('../../doc/utils') + +const ruleId = 'foundry-no-block-time-number' + +const DEFAULT_SEVERITY = 'warn' +const DEFAULT_TEST_DIRS = ['test', 'tests'] // default folders considered as Foundry test roots + +const meta = { + type: 'miscellaneous', + + docs: { + description: + 'Warn on the use of block.timestamp / block.number inside Foundry test files; recommend vm.getBlockTimestamp() / vm.getBlockNumber().', + category: 'Miscellaneous', + options: [ + { + description: severityDescription, + default: DEFAULT_SEVERITY, + }, + { + description: + 'Array of folder names for solhint to execute (defaults to ["test","tests"], case-insensitive).', + default: JSON.stringify(DEFAULT_TEST_DIRS), + }, + ], + notes: [ + { + note: 'This rule only runs for files located under the configured test directories (e.g., test/** or tests/**).', + }, + ], + }, + + fixable: false, + recommended: false, + // defaultSetup: [severity, testDirs[]] + defaultSetup: [DEFAULT_SEVERITY, DEFAULT_TEST_DIRS], + + schema: { + type: 'array', + description: 'Array of folder names for solhint to execute the rule (case-insensitive).', + items: { type: 'string', errorMessage: 'Each item must be a string' }, + }, +} + +class FoundryNoBlockTimeNumberChecker extends BaseChecker { + constructor(reporter, config, fileName) { + super(reporter, ruleId, meta) + + // Read array of folders from config. If invalid/empty, fallback to defaults. + const arr = config ? config.getArray(ruleId) : [] + this.testDirs = Array.isArray(arr) && arr.length > 0 ? arr.slice() : DEFAULT_TEST_DIRS.slice() + + this.fileName = fileName + this.enabledForThisFile = this.isInAnyTestDir(fileName, this.testDirs) + } + + // Only evaluate the AST if the current file is inside a configured test directory. + MemberAccess(node) { + if (!this.enabledForThisFile) return + + // Detect `block.timestamp` / `block.number` + if (node && node.type === 'MemberAccess') { + const expr = node.expression + const member = node.memberName + + if (expr && expr.type === 'Identifier' && expr.name === 'block') { + if (member === 'timestamp') { + this.error( + node, + 'Avoid `block.timestamp` in Foundry tests. Use `vm.getBlockTimestamp()` instead.' + ) + } else if (member === 'number') { + this.error( + node, + 'Avoid `block.number` in Foundry tests. Use `vm.getBlockNumber()` instead.' + ) + } + } + } + } + + // ---------- helpers ---------- + isInAnyTestDir(fileName, testDirs) { + try { + // Make the path relative to the project root to compare path segments + const rel = path.relative(process.cwd(), fileName) + const norm = path.normalize(rel) // normalize separators for Win/Linux + const segments = norm.split(path.sep).map((s) => s.toLowerCase()) + + // Match by exact directory segment (case-insensitive) + const wanted = new Set(testDirs.map((d) => String(d).toLowerCase())) + return segments.some((seg) => wanted.has(seg)) + } catch (_) { + // Fail-safe: if anything goes wrong, do not enable the rule for this file. + return false + } + } +} + +module.exports = FoundryNoBlockTimeNumberChecker diff --git a/lib/rules/miscellaneous/index.js b/lib/rules/miscellaneous/index.js index 90926bed..694c9a7c 100644 --- a/lib/rules/miscellaneous/index.js +++ b/lib/rules/miscellaneous/index.js @@ -2,6 +2,7 @@ const QuotesChecker = require('./quotes') const ComprehensiveInterfaceChecker = require('./comprehensive-interface') const DuplicatedImportsChecker = require('./duplicated-imports') const ImportPathChecker = require('./import-path-check') +const FoundryNoBlockTimeNumberChecker = require('./foundry-no-block-time-number') module.exports = function checkers(reporter, config, tokens, fileName) { return [ @@ -9,5 +10,6 @@ module.exports = function checkers(reporter, config, tokens, fileName) { new ComprehensiveInterfaceChecker(reporter, config, tokens), new DuplicatedImportsChecker(reporter), new ImportPathChecker(reporter, config, fileName), + new FoundryNoBlockTimeNumberChecker(reporter, config, fileName), ] } diff --git a/lib/rules/naming/foundry-test-function-naming.js b/lib/rules/naming/foundry-test-function-naming.js index e7a995aa..669b9768 100644 --- a/lib/rules/naming/foundry-test-function-naming.js +++ b/lib/rules/naming/foundry-test-function-naming.js @@ -71,7 +71,7 @@ const meta = { }, } -class FoundryTestFunctionNaming extends BaseChecker { +class FoundryTestFunctionNamingChecker extends BaseChecker { constructor(reporter, config) { super(reporter, ruleId, meta) this.skippedFunctions = config @@ -97,4 +97,4 @@ class FoundryTestFunctionNaming extends BaseChecker { } } -module.exports = FoundryTestFunctionNaming +module.exports = FoundryTestFunctionNamingChecker diff --git a/lib/rules/naming/index.js b/lib/rules/naming/index.js index 9d2bb79c..f2971701 100644 --- a/lib/rules/naming/index.js +++ b/lib/rules/naming/index.js @@ -14,7 +14,7 @@ const FunctionNamedParametersChecker = require('./func-named-parameters') // 👇 old (alias with deprecation) const FoundryTestFunctionsChecker = require('./foundry-test-functions') // 👇 new name -const FoundryTestFunctionNaming = require('./foundry-test-function-naming') +const FoundryTestFunctionNamingChecker = require('./foundry-test-function-naming') module.exports = function checkers(reporter, config) { return [ @@ -33,6 +33,6 @@ module.exports = function checkers(reporter, config) { // 👇 call both new FoundryTestFunctionsChecker(reporter, config), - new FoundryTestFunctionNaming(reporter, config), + new FoundryTestFunctionNamingChecker(reporter, config), ] } diff --git a/test/common/config-validator.js b/test/common/config-validator.js index 710e5811..2a212c20 100644 --- a/test/common/config-validator.js +++ b/test/common/config-validator.js @@ -580,4 +580,141 @@ describe('Better errors addition + rule disable on error', () => { assert.ok(logged.includes("invalid configuration for rule 'use-natspec'")) assert.ok(warnSpy.called) }) + + // + // ---- foundry-no-block-time-number: CONFIG VALIDATOR TESTS ---- + // + + it('Valid CFG - accept: foundry-no-block-time-number with only severity (uses DEFAULT test dirs)', () => { + const report = linter.processStr(dummyCode, { + rules: { 'foundry-no-block-time-number': 'warn' }, + }) + + // Not asserting execution here (rule is directory-gated and dummy file path may not match), + // we only assert the config is accepted and no reporter was used. + assert.equal(report.errorCount, 0) + assert.equal(report.warningCount, 0) + assert.deepEqual(report.messages, []) + + // No config warning should be printed + sinon.assert.notCalled(warnSpy) + sinon.assert.notCalled(reportErrorSpy) + sinon.assert.notCalled(reportWarnSpy) + }) + + it('Valid CFG - accept: foundry-no-block-time-number with custom test dirs array', () => { + const report = linter.processStr(dummyCode, { + rules: { 'foundry-no-block-time-number': ['warn', ['tests', 'e2e', 'it']] }, + }) + + // Only checking config acceptance (no execution guarantees here). + assert.equal(report.errorCount, 0) + assert.equal(report.warningCount, 0) + assert.deepEqual(report.messages, []) + + // No schema warning expected + sinon.assert.notCalled(warnSpy) + sinon.assert.notCalled(reportErrorSpy) + sinon.assert.notCalled(reportWarnSpy) + }) + + it('Invalid CFG - not execute: foundry-no-block-time-number when wrong value type in array is provided', () => { + // Second arg must be an array of strings; here it's [1] (invalid element type) + const report = linter.processStr(dummyCode, { + rules: { 'foundry-no-block-time-number': ['error', [1]] }, + }) + + assert.equal(report.errorCount, 0) + assert.equal(report.warningCount, 0) + assert.deepEqual(report.messages, []) + + const logged = warnSpy + .getCalls() + .map((c) => c.args[0]) + .join('\n') + + assert.ok( + logged.includes("invalid configuration for rule 'foundry-no-block-time-number'"), + `Expected a warning for foundry-no-block-time-number but got:\n${logged}` + ) + + assert.ok(warnSpy.called, 'console.warn should have been called') + sinon.assert.notCalled(reportErrorSpy) + sinon.assert.notCalled(reportWarnSpy) + }) + + it('Invalid CFG - not execute: foundry-no-block-time-number when wrong option type is provided (string)', () => { + // Second arg must be an array; here it's a string (invalid) + const report = linter.processStr(dummyCode, { + rules: { 'foundry-no-block-time-number': ['error', 'wrong'] }, + }) + + assert.equal(report.errorCount, 0) + assert.equal(report.warningCount, 0) + assert.deepEqual(report.messages, []) + + const logged = warnSpy + .getCalls() + .map((c) => c.args[0]) + .join('\n') + + assert.ok( + logged.includes("invalid configuration for rule 'foundry-no-block-time-number'"), + `Expected a warning for foundry-no-block-time-number but got:\n${logged}` + ) + + assert.ok(warnSpy.called, 'console.warn should have been called') + sinon.assert.notCalled(reportErrorSpy) + sinon.assert.notCalled(reportWarnSpy) + }) + + it('Invalid CFG - not execute: foundry-no-block-time-number when empty object is provided', () => { + // Second arg must be an array; here it's an object (invalid) + const report = linter.processStr(dummyCode, { + rules: { 'foundry-no-block-time-number': ['error', {}] }, + }) + + assert.equal(report.errorCount, 0) + assert.equal(report.warningCount, 0) + assert.deepEqual(report.messages, []) + + const logged = warnSpy + .getCalls() + .map((c) => c.args[0]) + .join('\n') + + assert.ok( + logged.includes("invalid configuration for rule 'foundry-no-block-time-number'"), + `Expected a warning for foundry-no-block-time-number but got:\n${logged}` + ) + + assert.ok(warnSpy.called, 'console.warn should have been called') + sinon.assert.notCalled(reportErrorSpy) + sinon.assert.notCalled(reportWarnSpy) + }) + + it('Invalid CFG - not execute: foundry-no-block-time-number when array items are not strings (mixed types)', () => { + // Mixed invalid item types + const report = linter.processStr(dummyCode, { + rules: { 'foundry-no-block-time-number': ['warn', ['tests', 123, null]] }, + }) + + assert.equal(report.errorCount, 0) + assert.equal(report.warningCount, 0) + assert.deepEqual(report.messages, []) + + const logged = warnSpy + .getCalls() + .map((c) => c.args[0]) + .join('\n') + + assert.ok( + logged.includes("invalid configuration for rule 'foundry-no-block-time-number'"), + `Expected a warning for foundry-no-block-time-number but got:\n${logged}` + ) + + assert.ok(warnSpy.called, 'console.warn should have been called') + sinon.assert.notCalled(reportErrorSpy) + sinon.assert.notCalled(reportWarnSpy) + }) }) diff --git a/test/rules/miscellaneous/foundry-no-block-time-number.js b/test/rules/miscellaneous/foundry-no-block-time-number.js new file mode 100644 index 00000000..58ea2e33 --- /dev/null +++ b/test/rules/miscellaneous/foundry-no-block-time-number.js @@ -0,0 +1,202 @@ +const assert = require('assert') +const linter = require('../../../lib/index') +const { assertNoErrors, assertErrorCount } = require('../../common/asserts') +const { multiLine } = require('../../common/contract-builder') + +describe('Linter - foundry-no-block-time-number (functional)', () => { + it('Should report when using block.timestamp inside tests/ dir', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_timestamp() public {', + ' uint256 x = block.timestamp;', + ' x;', + ' }', + '}' + ) + + const fileName = '/project/tests/T.sol' + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertErrorCount(report, 1) + assert.ok( + report.reports[0].message.includes( + 'Avoid `block.timestamp` in Foundry tests. Use `vm.getBlockTimestamp()` instead.' + ), + `Unexpected message: ${report.reports[0] && report.reports[0].message}` + ) + }) + + it('Should report when using block.number inside test/ dir', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_number() public {', + ' uint256 n = block.number;', + ' n;', + ' }', + '}' + ) + + const fileName = '/project/test/T.sol' + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertErrorCount(report, 1) + assert.ok( + report.reports[0].message.includes( + 'Avoid `block.number` in Foundry tests. Use `vm.getBlockNumber()` instead.' + ), + `Unexpected message: ${report.reports[0] && report.reports[0].message}` + ) + }) + + it('Should report twice when both block.timestamp and block.number are used', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_both() public {', + ' uint256 a = block.timestamp;', + ' uint256 b = block.number;', + ' (a); (b);', + ' }', + '}' + ) + + const fileName = '/repo/tests/helpers/T.sol' + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertErrorCount(report, 2) + + // Accept any order; check that both messages are present + const messages = report.reports.map((r) => r.message) + assert.ok( + messages.some((m) => m.includes('Avoid `block.timestamp`')), + `Messages: ${messages}` + ) + assert.ok( + messages.some((m) => m.includes('Avoid `block.number`')), + `Messages: ${messages}` + ) + }) + + it('Should NOT report outside configured test directories', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract Prod {', + ' function f() public view returns (uint256) {', + ' return block.timestamp + block.number;', + ' }', + '}' + ) + + const fileName = '/project/contracts/Prod.sol' // not under test/tests + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertNoErrors(report) + }) + + it('Should respect custom testDirs config (e.g., ["spec","integration"])', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_custom_dir() public {', + ' uint256 a = block.number;', + ' a;', + ' }', + '}' + ) + + const fileName = '/project/spec/T.sol' + const config = { + rules: { + 'foundry-no-block-time-number': ['error', ['spec', 'integration']], + }, + } + + const report = linter.processStr(code, config, fileName) + + assertErrorCount(report, 1) + assert.ok( + report.reports[0].message.includes( + 'Avoid `block.number` in Foundry tests. Use `vm.getBlockNumber()` instead.' + ), + `Unexpected message: ${report.reports[0] && report.reports[0].message}` + ) + }) + + it('Should match directory names case-insensitively', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_case_insensitive() public {', + ' uint256 a = block.timestamp;', + ' a;', + ' }', + '}' + ) + + const fileName = '/project/TeStS/T.sol' // mixed case + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertErrorCount(report, 1) + assert.ok( + report.reports[0].message.includes( + 'Avoid `block.timestamp` in Foundry tests. Use `vm.getBlockTimestamp()` instead.' + ), + `Unexpected message: ${report.reports[0] && report.reports[0].message}` + ) + }) + + it('Should NOT report if no block.timestamp/number usage exists (even under tests/)', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_ok() public {', + ' uint256 x = 1;', + ' (x);', + ' }', + '}' + ) + + const fileName = '/project/tests/T.sol' + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertNoErrors(report) + }) +}) diff --git a/test/rules/miscellaneous/import-path-check.js b/test/rules/miscellaneous/import-path-check.js index f8c4034b..11460e06 100644 --- a/test/rules/miscellaneous/import-path-check.js +++ b/test/rules/miscellaneous/import-path-check.js @@ -6,7 +6,7 @@ const { assertNoErrors, assertErrorCount, assertWarnsCount } = require('../../co const { multiLine } = require('../../common/contract-builder') const { successCases, errorCases } = require('../../fixtures/miscellaneous/import-path-check') -describe('import-path-check (mocked fs)', () => { +describe('Linter - import-path-check (mocked fs)', () => { let existsStub let currentFakeFileSystem = new Set() From 8eea3411a37059b3c0e60029238d5a8e4ec9fd56 Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Tue, 16 Sep 2025 16:17:53 -0300 Subject: [PATCH 2/4] feat: foundry-no-block-time-number rule --- docs/rules.md | 11 ++-- .../foundry-no-block-time-number.md | 50 +++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 docs/rules/miscellaneous/foundry-no-block-time-number.md diff --git a/docs/rules.md b/docs/rules.md index fb8a9158..859b91a5 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -69,11 +69,12 @@ title: "Rule Index of Solhint" ## Miscellaneous -| Rule Id | Error | Recommended | Deprecated | -| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ---------- | -| [comprehensive-interface](./rules/miscellaneous/comprehensive-interface.md) | Check that all public or external functions are overridden. This is useful to make sure that the whole API is extracted in an interface. | | | -| [import-path-check](./rules/miscellaneous/import-path-check.md) | Check if an import file exits in target path | $~~~~~~~~$✔️ | | -| [quotes](./rules/miscellaneous/quotes.md) | Enforces the use of double or simple quotes as configured for string literals. Values must be 'single' or 'double'. | $~~~~~~~~$✔️ | | +| Rule Id | Error | Recommended | Deprecated | +| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ---------- | +| [comprehensive-interface](./rules/miscellaneous/comprehensive-interface.md) | Check that all public or external functions are overridden. This is useful to make sure that the whole API is extracted in an interface. | | | +| [foundry-no-block-time-number](./rules/miscellaneous/foundry-no-block-time-number.md) | Warn on the use of block.timestamp / block.number inside Foundry test files; recommend vm.getBlockTimestamp() / vm.getBlockNumber(). | | | +| [import-path-check](./rules/miscellaneous/import-path-check.md) | Check if an import file exits in target path | $~~~~~~~~$✔️ | | +| [quotes](./rules/miscellaneous/quotes.md) | Enforces the use of double or simple quotes as configured for string literals. Values must be 'single' or 'double'. | $~~~~~~~~$✔️ | | ## Security Rules diff --git a/docs/rules/miscellaneous/foundry-no-block-time-number.md b/docs/rules/miscellaneous/foundry-no-block-time-number.md new file mode 100644 index 00000000..b503a874 --- /dev/null +++ b/docs/rules/miscellaneous/foundry-no-block-time-number.md @@ -0,0 +1,50 @@ +--- +warning: "This is a dynamically generated file. Do not edit manually." +layout: "default" +title: "foundry-no-block-time-number | Solhint" +--- + +# foundry-no-block-time-number +![Category Badge](https://img.shields.io/badge/-Miscellaneous-informational) +![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow) + +## Description +Warn on the use of block.timestamp / block.number inside Foundry test files; recommend vm.getBlockTimestamp() / vm.getBlockNumber(). + +## Options +This rule accepts an array of options: + +| Index | Description | Default Value | +| ----- | ---------------------------------------------------------------------------------------------- | ---------------- | +| 0 | Rule severity. Must be one of "error", "warn", "off". | warn | +| 1 | Array of folder names for solhint to execute (defaults to ["test","tests"], case-insensitive). | ["test","tests"] | + + +### Example Config +```json +{ + "rules": { + "foundry-no-block-time-number": [ + "warn", + [ + "test", + "tests" + ] + ] + } +} +``` + +### Notes +- This rule only runs for files located under the configured test directories (e.g., test/** or tests/**). + +## Examples +This rule does not have examples. + +## Version +This rule was introduced in the latest version. + +## Resources +- [Rule source](https://github.com/protofire/solhint/blob/master/lib/rules/miscellaneous/foundry-no-block-time-number.js) +- [Document source](https://github.com/protofire/solhint/blob/master/docs/rules/miscellaneous/foundry-no-block-time-number.md) +- [Test cases](https://github.com/protofire/solhint/blob/master/test/rules/miscellaneous/foundry-no-block-time-number.js) From a3946686ebfc8316a112f207a9a945ffdfadf38b Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Tue, 16 Sep 2025 16:24:49 -0300 Subject: [PATCH 3/4] feat: foundry-no-block-time-number rule --- .../foundry-no-block-time-number.js | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/rules/miscellaneous/foundry-no-block-time-number.js b/test/rules/miscellaneous/foundry-no-block-time-number.js index 58ea2e33..5ff9e96f 100644 --- a/test/rules/miscellaneous/foundry-no-block-time-number.js +++ b/test/rules/miscellaneous/foundry-no-block-time-number.js @@ -62,6 +62,35 @@ describe('Linter - foundry-no-block-time-number (functional)', () => { ) }) + it('Should report when using block.number inside test/ dir', () => { + const code = multiLine( + 'pragma solidity ^0.8.24;', + 'contract T {', + ' function test_number() public {', + ' uint256 n = block.number;', + ' n;', + ' }', + '}' + ) + + const fileName = '/project/test/folder1/folder2/T.sol' + const config = { + rules: { + 'foundry-no-block-time-number': 'error', + }, + } + + const report = linter.processStr(code, config, fileName) + + assertErrorCount(report, 1) + assert.ok( + report.reports[0].message.includes( + 'Avoid `block.number` in Foundry tests. Use `vm.getBlockNumber()` instead.' + ), + `Unexpected message: ${report.reports[0] && report.reports[0].message}` + ) + }) + it('Should report twice when both block.timestamp and block.number are used', () => { const code = multiLine( 'pragma solidity ^0.8.24;', From 6047f1bf05b1cc5806fb7b8d158a5e57ddab2721 Mon Sep 17 00:00:00 2001 From: dbale-altoros Date: Tue, 16 Sep 2025 16:25:09 -0300 Subject: [PATCH 4/4] feat: foundry-no-block-time-number rule --- test/rules/miscellaneous/foundry-no-block-time-number.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rules/miscellaneous/foundry-no-block-time-number.js b/test/rules/miscellaneous/foundry-no-block-time-number.js index 5ff9e96f..a2267228 100644 --- a/test/rules/miscellaneous/foundry-no-block-time-number.js +++ b/test/rules/miscellaneous/foundry-no-block-time-number.js @@ -62,7 +62,7 @@ describe('Linter - foundry-no-block-time-number (functional)', () => { ) }) - it('Should report when using block.number inside test/ dir', () => { + it('Should report when using block.number inside test/folder1/folder2 dir', () => { const code = multiLine( 'pragma solidity ^0.8.24;', 'contract T {',