Repository: protofire/solhint
Pull request #473 (2023-08-07 17:44:49)

MERGE Develop into Master


Patch:
diff --git a/.gitignore b/.gitignore
index 77dd2e5..063bb15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,4 @@ convertLib.sol
 antlr4.jar
 /docs/.sass-cache/
 _temp/
-.solhint.json
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ecc118f..92070ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,43 @@
+## [3.6.1] - 2023-08-11
+
+### BREAKING CHANGE
+- RULE: `not-rely-on-time` was REMOVED from RECOMMENDED ruleset<br>
+This was long overdue.<br> 
+Beware!! If you are relying on this rule and it is not explicitly configured (meaning there's only `solhint:recommended` option).<br>
+You should add this rule manually:
+```json
+  {
+    "extends": "solhint:recommended",
+    "rules": { 
+        "not-rely-on-time": "warn", 
+        "compiler-version": "off" 
+    },
+  }
+```
+If not explicitly added, this rule will not be executed.
+
+### SPECIAL ATTENTION
+- RULE: `compiler-version` default was updated from ^0.5.2 to ^0.8.0
+
+### Added
+- New Rule: Enforces the use of Custom Errors over Require and Revert statements [#475](https://github.com/protofire/solhint/pull/475)
+- New Rule: Enforces the test_ prefix on a file for Foundry users [#476](https://github.com/protofire/solhint/pull/476)
+- New Rule: Enforces the naming of function return values [#478](https://github.com/protofire/solhint/pull/478)
+- `Notes` option on docs to add more information of each rule. See `foundry-test-functions`. [#476](https://github.com/protofire/solhint/pull/476)
+  
+### Fixed
+- `func-named-parameters` - false positives on builtin functions [#472](https://github.com/protofire/solhint/pull/472)
+- `ordering` - treat initializer weight same as constructor [#474](https://github.com/protofire/solhint/pull/474)
+- `check-send-result` - false positive on `erc777.send()`` function [#477](https://github.com/protofire/solhint/pull/477)
+- `explicit-types` - default value is now taking into account when no value is specified in config [#481](https://github.com/protofire/solhint/pull/481)
+- `compiler-version` - default value is now taking into account when no value is specified in config [#483](https://github.com/protofire/solhint/pull/483)
+
+### Updates
+- Rule: `check-send-result` added config clarification in the new `Notes` section [#482](https://github.com/protofire/solhint/pull/482)
+- Rule: `compiler-version` default was updated from ^0.5.2 to ^0.8.0 [#483](https://github.com/protofire/solhint/pull/483)
+
+
+
 ## [3.5.1] - 2023-08-04
 ### Updated
 - Support `ignoreConstructors` option for `no-empty-blocks` [#418](https://github.com/protofire/solhint/pull/418)
@@ -30,7 +70,6 @@
 
 
 
-<br><br>
 ## [3.4.1] - 2023-03-06
 ### Updated
 - Updated solidity parser to 0.16.0 [#420](https://github.com/protofire/solhint/pull/420)
@@ -46,10 +85,6 @@
 - Fix named-parameters-mapping to not enforce on nested mappings [#421](https://github.com/protofire/solhint/pull/421)
 
 
-
-
-
-<br><br>
 ## [3.4.0] - 2023-02-17
 ### Updated
 - Solhint dependencies to support newer versions [#380](https://github.com/protofire/solhint/pull/380)
@@ -73,10 +108,6 @@
 - False positive on no-unused-vars for payable arguments without name [#399](https://github.com/protofire/solhint/pull/399)
 
 
-
-
-
-<br><br>
 ## [3.3.8] - 2023-01-17
 ### Fixed Docs and Typos
 - [#292](https://github.com/protofire/solhint/pull/292)
diff --git a/conf/rulesets/solhint-all.js b/conf/rulesets/solhint-all.js
index 6ceced1..eab50c5 100644
--- a/conf/rulesets/solhint-all.js
+++ b/conf/rulesets/solhint-all.js
@@ -6,6 +6,7 @@
 module.exports = Object.freeze({
   rules: {
     'code-complexity': ['warn', 7],
+    'custom-errors': 'warn',
     'explicit-types': ['warn', 'explicit'],
     'function-max-lines': ['warn', 50],
     'max-line-length': ['error', 120],
@@ -28,8 +29,9 @@ module.exports = Object.freeze({
     'const-name-snakecase': 'warn',
     'contract-name-camelcase': 'warn',
     'event-name-camelcase': 'warn',
+    'foundry-test-functions': ['off', ['setUp']],
     'func-name-mixedcase': 'warn',
-    'func-named-parameters': ['warn', 2],
+    'func-named-parameters': ['warn', 4],
     'func-param-name-mixedcase': 'warn',
     'immutable-vars-naming': [
       'warn',
@@ -39,6 +41,7 @@ module.exports = Object.freeze({
     ],
     'modifier-name-mixedcase': 'warn',
     'named-parameters-mapping': 'off',
+    'named-return-values': 'warn',
     'private-vars-leading-underscore': [
       'warn',
       {
@@ -57,7 +60,7 @@ module.exports = Object.freeze({
     'avoid-throw': 'warn',
     'avoid-tx-origin': 'warn',
     'check-send-result': 'warn',
-    'compiler-version': ['error', '^0.5.8'],
+    'compiler-version': ['error', '^0.8.0'],
     'func-visibility': [
       'warn',
       {
diff --git a/conf/rulesets/solhint-recommended.js b/conf/rulesets/solhint-recommended.js
index dbd05e7..072ea68 100644
--- a/conf/rulesets/solhint-recommended.js
+++ b/conf/rulesets/solhint-recommended.js
@@ -5,6 +5,7 @@
 
 module.exports = Object.freeze({
   rules: {
+    'custom-errors': 'warn',
     'explicit-types': ['warn', 'explicit'],
     'max-states-count': ['warn', 15],
     'no-console': 'error',
@@ -24,7 +25,6 @@ module.exports = Object.freeze({
     'contract-name-camelcase': 'warn',
     'event-name-camelcase': 'warn',
     'func-name-mixedcase': 'warn',
-    'func-named-parameters': ['warn', 2],
     'immutable-vars-naming': [
       'warn',
       {
@@ -42,7 +42,7 @@ module.exports = Object.freeze({
     'avoid-throw': 'warn',
     'avoid-tx-origin': 'warn',
     'check-send-result': 'warn',
-    'compiler-version': ['error', '^0.5.8'],
+    'compiler-version': ['error', '^0.8.0'],
     'func-visibility': [
       'warn',
       {
@@ -53,7 +53,6 @@ module.exports = Object.freeze({
     'no-complex-fallback': 'warn',
     'no-inline-assembly': 'warn',
     'not-rely-on-block-hash': 'warn',
-    'not-rely-on-time': 'warn',
     reentrancy: 'warn',
     'state-visibility': 'warn',
   },
diff --git a/docs/rules.md b/docs/rules.md
index 24d799a..00b344b 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -9,6 +9,7 @@ title:       "Rule Index of Solhint"
 | Rule Id                                                            | Error                                                                                                                 | Recommended  | Deprecated |
 | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | ------------ | ---------- |
 | [code-complexity](./rules/best-practises/code-complexity.md)       | Function has cyclomatic complexity "current" but allowed no more than maxcompl.                                       |              |            |
+| [custom-errors](./rules/best-practises/custom-errors.md)           | Enforces the use of Custom Errors over Require and Revert statements                                                  | $~~~~~~~~$✔️ |            |
 | [explicit-types](./rules/best-practises/explicit-types.md)         | Forbid or enforce explicit types (like uint256) that have an alias (like uint).                                       | $~~~~~~~~$✔️ |            |
 | [function-max-lines](./rules/best-practises/function-max-lines.md) | Function body contains "count" lines but allowed no more than maxlines.                                               |              |            |
 | [max-line-length](./rules/best-practises/max-line-length.md)       | Line length must be no more than maxlen.                                                                              |              |            |
@@ -33,24 +34,26 @@ title:       "Rule Index of Solhint"
 
 ## Style Guide Rules
 
-| Rule Id                                                                              | Error                                                                                                   | Recommended  | Deprecated  |
-| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | ------------ | ----------- |
-| [const-name-snakecase](./rules/naming/const-name-snakecase.md)                       | Constant name must be in capitalized SNAKE_CASE. (Does not check IMMUTABLES, use immutable-vars-naming) | $~~~~~~~~$✔️ |             |
-| [contract-name-camelcase](./rules/naming/contract-name-camelcase.md)                 | Contract name must be in CamelCase.                                                                     | $~~~~~~~~$✔️ |             |
-| [event-name-camelcase](./rules/naming/event-name-camelcase.md)                       | Event name must be in CamelCase.                                                                        | $~~~~~~~~$✔️ |             |
-| [func-name-mixedcase](./rules/naming/func-name-mixedcase.md)                         | Function name must be in mixedCase.                                                                     | $~~~~~~~~$✔️ |             |
-| [func-named-parameters](./rules/naming/func-named-parameters.md)                     | Enforce function calls with Named Parameters when containing more than the configured qty               | $~~~~~~~~$✔️ |             |
-| [func-param-name-mixedcase](./rules/naming/func-param-name-mixedcase.md)             | Function param name must be in mixedCase.                                                               |              |             |
-| [immutable-vars-naming](./rules/naming/immutable-vars-naming.md)                     | Check Immutable variables. Capitalized SNAKE_CASE or mixedCase depending on configuration.              | $~~~~~~~~$✔️ |             |
-| [modifier-name-mixedcase](./rules/naming/modifier-name-mixedcase.md)                 | Modifier name must be in mixedCase.                                                                     |              |             |
-| [named-parameters-mapping](./rules/naming/named-parameters-mapping.md)               | Solidity v0.8.18 introduced named parameters on the mappings definition.                                |              |             |
-| [private-vars-leading-underscore](./rules/naming/private-vars-leading-underscore.md) | Private and internal names must start with a single underscore.                                         |              |             |
-| [use-forbidden-name](./rules/naming/use-forbidden-name.md)                           | Avoid to use letters 'I', 'l', 'O' as identifiers.                                                      | $~~~~~~~~$✔️ |             |
-| [var-name-mixedcase](./rules/naming/var-name-mixedcase.md)                           | Variable name must be in mixedCase. (Does not check IMMUTABLES, use immutable-vars-naming)              | $~~~~~~~~$✔️ |             |
-| [func-order](./rules/order/func-order.md)                                            | Function order is incorrect.                                                                            |              | $~~~~~~~$✔️ |
-| [imports-on-top](./rules/order/imports-on-top.md)                                    | Import statements must be on top.                                                                       | $~~~~~~~~$✔️ |             |
-| [ordering](./rules/order/ordering.md)                                                | Check order of elements in file and inside each contract, according to the style guide.                 |              |             |
-| [visibility-modifier-order](./rules/order/visibility-modifier-order.md)              | Visibility modifier must be first in list of modifiers.                                                 | $~~~~~~~~$✔️ |             |
+| Rule Id                                                                              | Error                                                                                                         | Recommended  | Deprecated  |
+| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | ------------ | ----------- |
+| [const-name-snakecase](./rules/naming/const-name-snakecase.md)                       | Constant name must be in capitalized SNAKE_CASE. (Does not check IMMUTABLES, use immutable-vars-naming)       | $~~~~~~~~$✔️ |             |
+| [contract-name-camelcase](./rules/naming/contract-name-camelcase.md)                 | Contract name must be in CamelCase.                                                                           | $~~~~~~~~$✔️ |             |
+| [event-name-camelcase](./rules/naming/event-name-camelcase.md)                       | Event name must be in CamelCase.                                                                              | $~~~~~~~~$✔️ |             |
+| [foundry-test-functions](./rules/naming/foundry-test-functions.md)                   | Enforce naming convention on functions for Foundry test cases                                                 |              |             |
+| [func-name-mixedcase](./rules/naming/func-name-mixedcase.md)                         | Function name must be in mixedCase.                                                                           | $~~~~~~~~$✔️ |             |
+| [func-named-parameters](./rules/naming/func-named-parameters.md)                     | Enforce named parameters for function calls with 4 or more arguments. This rule may have some false positives |              |             |
+| [func-param-name-mixedcase](./rules/naming/func-param-name-mixedcase.md)             | Function param name must be in mixedCase.                                                                     |              |             |
+| [immutable-vars-naming](./rules/naming/immutable-vars-naming.md)                     | Check Immutable variables. Capitalized SNAKE_CASE or mixedCase depending on configuration.                    | $~~~~~~~~$✔️ |             |
+| [modifier-name-mixedcase](./rules/naming/modifier-name-mixedcase.md)                 | Modifier name must be in mixedCase.                                                                           |              |             |
+| [named-parameters-mapping](./rules/naming/named-parameters-mapping.md)               | Solidity v0.8.18 introduced named parameters on the mappings definition.                                      |              |             |
+| [named-return-values](./rules/naming/named-return-values.md)                         | Enforce the return values of a function to be named                                                           |              |             |
+| [private-vars-leading-underscore](./rules/naming/private-vars-leading-underscore.md) | Private and internal names must start with a single underscore.                                               |              |             |
+| [use-forbidden-name](./rules/naming/use-forbidden-name.md)                           | Avoid to use letters 'I', 'l', 'O' as identifiers.                                                            | $~~~~~~~~$✔️ |             |
+| [var-name-mixedcase](./rules/naming/var-name-mixedcase.md)                           | Variable name must be in mixedCase. (Does not check IMMUTABLES, use immutable-vars-naming)                    | $~~~~~~~~$✔️ |             |
+| [func-order](./rules/order/func-order.md)                                            | Function order is incorrect.                                                                                  |              | $~~~~~~~$✔️ |
+| [imports-on-top](./rules/order/imports-on-top.md)                                    | Import statements must be on top.                                                                             | $~~~~~~~~$✔️ |             |
+| [ordering](./rules/order/ordering.md)                                                | Check order of elements in file and inside each contract, according to the style guide.                       |              |             |
+| [visibility-modifier-order](./rules/order/visibility-modifier-order.md)              | Visibility modifier must be first in list of modifiers.                                                       | $~~~~~~~~$✔️ |             |
         
 
 ## Security Rules
@@ -71,7 +74,7 @@ title:       "Rule Index of Solhint"
 | [no-complex-fallback](./rules/security/no-complex-fallback.md)         | Fallback function must be simple.                                        | $~~~~~~~~$✔️ |             |
 | [no-inline-assembly](./rules/security/no-inline-assembly.md)           | Avoid to use inline assembly. It is acceptable only in rare cases.       | $~~~~~~~~$✔️ |             |
 | [not-rely-on-block-hash](./rules/security/not-rely-on-block-hash.md)   | Do not rely on "block.blockhash". Miners can influence its value.        | $~~~~~~~~$✔️ |             |
-| [not-rely-on-time](./rules/security/not-rely-on-time.md)               | Avoid making time-based decisions in your business logic.                | $~~~~~~~~$✔️ |             |
+| [not-rely-on-time](./rules/security/not-rely-on-time.md)               | Avoid making time-based decisions in your business logic.                |              |             |
 | [reentrancy](./rules/security/reentrancy.md)                           | Possible reentrancy vulnerabilities. Avoid state changes after transfer. | $~~~~~~~~$✔️ |             |
 | [state-visibility](./rules/security/state-visibility.md)               | Explicitly mark visibility of state.                                     | $~~~~~~~~$✔️ |             |
         
diff --git a/docs/rules/best-practises/custom-errors.md b/docs/rules/best-practises/custom-errors.md
new file mode 100644
index 0000000..afe5b3c
--- /dev/null
+++ b/docs/rules/best-practises/custom-errors.md
@@ -0,0 +1,71 @@
+---
+warning:     "This is a dynamically generated file. Do not edit manually."
+layout:      "default"
+title:       "custom-errors | Solhint"
+---
+
+# custom-errors
+![Recommended Badge](https://img.shields.io/badge/-Recommended-brightgreen)
+![Category Badge](https://img.shields.io/badge/-Best%20Practise%20Rules-informational)
+![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)
+> The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
+
+
+## Description
+Enforces the use of Custom Errors over Require and Revert statements
+
+## Options
+This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Default to warn.
+
+### Example Config
+```json
+{
+  "rules": {
+    "custom-errors": "warn"
+  }
+}
+```
+
+
+## Examples
+### 👍 Examples of **correct** code for this rule
+
+#### Use of Custom Errors
+
+```solidity
+revert CustomErrorFunction();
+```
+
+#### Use of Custom Errors with arguments
+
+```solidity
+revert CustomErrorFunction({ msg: "Insufficient Balance" });
+```
+
+### 👎 Examples of **incorrect** code for this rule
+
+#### Use of require statement
+
+```solidity
+require(userBalance >= availableAmount, "Insufficient Balance");
+```
+
+#### Use of plain revert statement
+
+```solidity
+revert();
+```
+
+#### Use of revert statement with message
+
+```solidity
+revert("Insufficient Balance");
+```
+
+## Version
+This rule is introduced in the latest version.
+
+## Resources
+- [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/best-practises/custom-errors.js)
+- [Document source](https://github.com/protofire/solhint/tree/master/docs/rules/best-practises/custom-errors.md)
+- [Test cases](https://github.com/protofire/solhint/tree/master/test/rules/best-practises/custom-errors.js)
diff --git a/docs/rules/best-practises/explicit-types.md b/docs/rules/best-practises/explicit-types.md
index 96cb06a..8448bc6 100644
--- a/docs/rules/best-practises/explicit-types.md
+++ b/docs/rules/best-practises/explicit-types.md
@@ -63,7 +63,7 @@ uint256 public variableName
 ```
 
 ## Version
-This rule is introduced in the latest version.
+This rule was introduced in [Solhint 3.5.1](https://github.com/protofire/solhint/tree/v3.5.1)
 
 ## Resources
 - [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/best-practises/explicit-types.js)
diff --git a/docs/rules/best-practises/no-unused-import.md b/docs/rules/best-practises/no-unused-import.md
index 8d13e89..8d567c9 100644
--- a/docs/rules/best-practises/no-unused-import.md
+++ b/docs/rules/best-practises/no-unused-import.md
@@ -51,7 +51,7 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 ```
 
 ## Version
-This rule is introduced in the latest version.
+This rule was introduced in [Solhint 3.5.1](https://github.com/protofire/solhint/tree/v3.5.1)
 
 ## Resources
 - [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/best-practises/no-unused-import.js)
diff --git a/docs/rules/naming/func-named-parameters.md b/docs/rules/naming/func-named-parameters.md
index 3c6710c..44fe7da 100644
--- a/docs/rules/naming/func-named-parameters.md
+++ b/docs/rules/naming/func-named-parameters.md
@@ -5,29 +5,26 @@ title:       "func-named-parameters | Solhint"
 ---
 
 # func-named-parameters
-![Recommended Badge](https://img.shields.io/badge/-Recommended-brightgreen)
 ![Category Badge](https://img.shields.io/badge/-Style%20Guide%20Rules-informational)
 ![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)
-> The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
-
 
 ## Description
-Enforce function calls with Named Parameters when containing more than the configured qty
+Enforce named parameters for function calls with 4 or more arguments. This rule may have some false positives
 
 ## Options
 This rule accepts an array of options:
 
-| Index | Description                                            | Default Value |
-| ----- | ------------------------------------------------------ | ------------- |
-| 0     | Rule severity. Must be one of "error", "warn", "off".  | warn          |
-| 1     | Maximum qty of unnamed parameters for a function call. | 2             |
+| Index | Description                                                                                              | Default Value |
+| ----- | -------------------------------------------------------------------------------------------------------- | ------------- |
+| 0     | Rule severity. Must be one of "error", "warn", "off".                                                    | warn          |
+| 1     | Minimum qty of unnamed parameters for a function call (to prevent false positives on builtin functions). | 4             |
 
 
 ### Example Config
 ```json
 {
   "rules": {
-    "func-named-parameters": ["warn",2]
+    "func-named-parameters": ["warn",4]
   }
 }
 ```
@@ -36,7 +33,7 @@ This rule accepts an array of options:
 ## Examples
 ### 👍 Examples of **correct** code for this rule
 
-#### Function call with two UNNAMED parameters (default is max 2)
+#### Function call with two UNNAMED parameters (default is 4)
 
 ```solidity
 functionName('0xA81705c8C247C413a19A244938ae7f4A0393944e', 1e18)
@@ -56,14 +53,14 @@ functionName({ sender: _senderAddress, amount: 1e18, token: _tokenAddress, recei
 
 ### 👎 Examples of **incorrect** code for this rule
 
-#### Function call with four UNNAMED parameters (default is max 2)
+#### Function call with four UNNAMED parameters (default 4)
 
 ```solidity
 functionName(_senderAddress, 1e18, _tokenAddress, _receiverAddress )
 ```
 
 ## Version
-This rule is introduced in the latest version.
+This rule was introduced in [Solhint 3.5.1](https://github.com/protofire/solhint/tree/v3.5.1)
 
 ## Resources
 - [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/naming/func-named-parameters.js)
diff --git a/docs/rules/naming/immutable-vars-naming.md b/docs/rules/naming/immutable-vars-naming.md
index 8705d7e..a12c229 100644
--- a/docs/rules/naming/immutable-vars-naming.md
+++ b/docs/rules/naming/immutable-vars-naming.md
@@ -37,7 +37,7 @@ This rule accepts an array of options:
 This rule does not have examples.
 
 ## Version
-This rule is introduced in the latest version.
+This rule was introduced in [Solhint 3.5.1](https://github.com/protofire/solhint/tree/v3.5.1)
 
 ## Resources
 - [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/naming/immutable-vars-naming.js)
diff --git a/docs/rules/naming/named-return-values.md b/docs/rules/naming/named-return-values.md
new file mode 100644
index 0000000..be9ce47
--- /dev/null
+++ b/docs/rules/naming/named-return-values.md
@@ -0,0 +1,50 @@
+---
+warning:     "This is a dynamically generated file. Do not edit manually."
+layout:      "default"
+title:       "named-return-values | Solhint"
+---
+
+# named-return-values
+![Category Badge](https://img.shields.io/badge/-Style%20Guide%20Rules-informational)
+![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)
+
+## Description
+Enforce the return values of a function to be named
+
+## Options
+This rule accepts a string option of rule severity. Must be one of "error", "warn", "off". Default to warn.
+
+### Example Config
+```json
+{
+  "rules": {
+    "named-return-values": "warn"
+  }
+}
+```
+
+
+## Examples
+### 👍 Examples of **correct** code for this rule
+
+#### Function definition with named return values
+
+```solidity
+function checkBalance(address wallet) external view returns(uint256 retBalance) {}
+```
+
+### 👎 Examples of **incorrect** code for this rule
+
+#### Function definition with UNNAMED return values
+
+```solidity
+function checkBalance(address wallet) external view returns(uint256) {}
+```
+
+## Version
+This rule is introduced in the latest version.
+
+## Resources
+- [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/naming/named-return-values.js)
+- [Document source](https://github.com/protofire/solhint/tree/master/docs/rules/naming/named-return-values.md)
+- [Test cases](https://github.com/protofire/solhint/tree/master/test/rules/naming/named-return-values.js)
diff --git a/docs/rules/security/check-send-result.md b/docs/rules/security/check-send-result.md
index 7f8521b..18db9a9 100644
--- a/docs/rules/security/check-send-result.md
+++ b/docs/rules/security/check-send-result.md
@@ -26,6 +26,9 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 }
 ```
 
+### Notes
+- Rule will rise false positive on this: `bool success = walletAddress.send(amount); require(success, "Failed to send"); ` 
+- Rule will skip ERC777 "send" function to prevent false positives
 
 ## Examples
 ### 👍 Examples of **correct** code for this rule
@@ -36,6 +39,12 @@ This rule accepts a string option of rule severity. Must be one of "error", "war
 if(x.send(55)) {}
 ```
 
+#### result of "send" call checked within a require
+
+```solidity
+require(payable(walletAddress).send(moneyAmount), "Failed to send moneyAmount");
+```
+
 ### 👎 Examples of **incorrect** code for this rule
 
 #### result of "send" call ignored
diff --git a/docs/rules/security/compiler-version.md b/docs/rules/security/compiler-version.md
index e930e93..d7bc39d 100644
--- a/docs/rules/security/compiler-version.md
+++ b/docs/rules/security/compiler-version.md
@@ -20,14 +20,14 @@ This rule accepts an array of options:
 | Index | Description                                           | Default Value |
 | ----- | ----------------------------------------------------- | ------------- |
 | 0     | Rule severity. Must be one of "error", "warn", "off". | error         |
-| 1     | Semver requirement                                    | ^0.5.8        |
+| 1     | Semver requirement                                    | ^0.8.0        |
 
 
 ### Example Config
 ```json
 {
   "rules": {
-    "compiler-version": ["error","^0.5.8"]
+    "compiler-version": ["error","^0.8.0"]
   }
 }
 ```
diff --git a/docs/rules/security/not-rely-on-time.md b/docs/rules/security/not-rely-on-time.md
index f9998d7..dcc2425 100644
--- a/docs/rules/security/not-rely-on-time.md
+++ b/docs/rules/security/not-rely-on-time.md
@@ -5,11 +5,8 @@ title:       "not-rely-on-time | Solhint"
 ---
 
 # not-rely-on-time
-![Recommended Badge](https://img.shields.io/badge/-Recommended-brightgreen)
 ![Category Badge](https://img.shields.io/badge/-Security%20Rules-informational)
 ![Default Severity Badge warn](https://img.shields.io/badge/Default%20Severity-warn-yellow)
-> The {"extends": "solhint:recommended"} property in a configuration file enables this rule.
-
 
 ## Description
 Avoid making time-based decisions in your business logic.
diff --git a/lib/common/identifier-naming.js b/lib/common/identifier-naming.js
index 1444d39..efc7e3f 100644
--- a/lib/common/identifier-naming.js
+++ b/lib/common/identifier-naming.js
@@ -30,4 +30,9 @@ module.exports = {
   hasLeadingUnderscore(text) {
     return text && text[0] === '_'
   },
+
+  isNotFoundryTestCase(text) {
+    const regex = /^test(Fork)?(Fuzz)?(Fail)?_(Revert(If_|When_){1})?\w{1,}$/
+    return !match(text, regex)
+  },
 }
diff --git a/lib/config.js b/lib/config.js
index 44b4c42..69b3dad 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -15,11 +15,6 @@ module.exports = {
     return _.isBoolean(configVal) ? configVal : defaultValue
   },
 
-  getStringByPath(path, defaultValue) {
-    const configVal = _.get(this, path)
-    return _.isString(configVal) ? configVal : defaultValue
-  },
-
   getNumber(ruleName, defaultValue) {
     return this.getNumberByPath(`rules["${ruleName}"][1]`, defaultValue)
   },
@@ -32,7 +27,18 @@ module.exports = {
     return this.getBooleanByPath(`rules["${ruleName}"][1][${ruleProperty}]`, defaultValue)
   },
 
-  getString(ruleName, defaultValue) {
-    return this.getStringByPath(`rules["${ruleName}"][1]`, defaultValue)
+  getStringFromArray(ruleName, defaultValue) {
+    if (this.rules && this.rules[ruleName]) {
+      const ruleValue = this.rules[ruleName]
+      return Array.isArray(ruleValue) ? ruleValue[1] : defaultValue
+    } else {
+      return defaultValue
+    }
+  },
+
+  getArray(ruleName, defaultValue) {
+    const path = `rules["${ruleName}"][1]`
+    const configVal = _.get(this, path)
+    return _.isArray(configVal) ? configVal : defaultValue
   },
 }
diff --git a/lib/rules/best-practises/custom-errors.js b/lib/rules/best-practises/custom-errors.js
new file mode 100644
index 0000000..ce4304a
--- /dev/null
+++ b/lib/rules/best-practises/custom-errors.js
@@ -0,0 +1,76 @@
+const BaseChecker = require('../base-checker')
+const { severityDescription } = require('../../doc/utils')
+
+const DEFAULT_SEVERITY = 'warn'
+
+const ruleId = 'custom-errors'
+const meta = {
+  type: 'best-practises',
+
+  docs: {
+    description: 'Enforces the use of Custom Errors over Require and Revert statements',
+    category: 'Best Practise Rules',
+    options: [
+      {
+        description: severityDescription,
+        default: DEFAULT_SEVERITY,
+      },
+    ],
+    examples: {
+      good: [
+        {
+          description: 'Use of Custom Errors',
+          code: 'revert CustomErrorFunction();',
+        },
+        {
+          description: 'Use of Custom Errors with arguments',
+          code: 'revert CustomErrorFunction({ msg: "Insufficient Balance" });',
+        },
+      ],
+      bad: [
+        {
+          description: 'Use of require statement',
+          code: 'require(userBalance >= availableAmount, "Insufficient Balance");',
+        },
+        {
+          description: 'Use of plain revert statement',
+          code: 'revert();',
+        },
+        {
+          description: 'Use of revert statement with message',
+          code: 'revert("Insufficient Balance");',
+        },
+      ],
+    },
+  },
+
+  isDefault: false,
+  recommended: true,
+  defaultSetup: DEFAULT_SEVERITY,
+
+  schema: null,
+}
+
+class CustomErrorsChecker extends BaseChecker {
+  constructor(reporter) {
+    super(reporter, ruleId, meta)
+  }
+
+  FunctionCall(node) {
+    let errorStr = ''
+    if (node.expression.name === 'require') {
+      errorStr = 'require'
+    } else if (
+      node.expression.name === 'revert' &&
+      (node.arguments.length === 0 || node.arguments[0].type === 'StringLiteral')
+    ) {
+      errorStr = 'revert'
+    }
+
+    if (errorStr !== '') {
+      this.error(node, `Use Custom Errors instead of ${errorStr} statements`)
+    }
+  }
+}
+
+module.exports = CustomErrorsChecker
diff --git a/lib/rules/best-practises/explicit-types.js b/lib/rules/best-practises/explicit-types.js
index 4f2a614..ebf7b60 100644
--- a/lib/rules/best-practises/explicit-types.js
+++ b/lib/rules/best-practises/explicit-types.js
@@ -62,13 +62,17 @@ const meta = {
 class ExplicitTypesChecker extends BaseChecker {
   constructor(reporter, config) {
     super(reporter, ruleId, meta)
-    this.configOption = (config && config.getString(ruleId, DEFAULT_OPTION)) || DEFAULT_OPTION
+    this.configOption =
+      (config && config.getStringFromArray(ruleId, DEFAULT_OPTION)) || DEFAULT_OPTION
     this.isExplicit = this.configOption === 'explicit'
-
-    this.validateConfigOption(this.configOption)
   }
 
   VariableDeclaration(node) {
+    if (!VALID_CONFIGURATION_OPTIONS.includes(this.configOption)) {
+      this.error(node, 'Error: Config error on [explicit-types]. See explicit-types.md.')
+      return
+    }
+
     const typeToFind = 'ElementaryTypeName'
     const onlyTypes = this.findNamesOfElementaryTypeName(node, typeToFind)
 
@@ -89,12 +93,6 @@ class ExplicitTypesChecker extends BaseChecker {
     }
   }
 
-  validateConfigOption(configOption) {
-    const configOk = VALID_CONFIGURATION_OPTIONS.includes(configOption)
-    if (!configOk)
-      throw new Error('Error: Config error on [explicit-types]. See explicit-types.md.')
-  }
-
   validateVariables(configType, node, varsToBeChecked) {
     const errorVars = varsToBeChecked.filter((type) => configType.includes(type))
 
diff --git a/lib/rules/best-practises/index.js b/lib/rules/best-practises/index.js
index 6b2ac78..e7f5228 100644
--- a/lib/rules/best-practises/index.js
+++ b/lib/rules/best-practises/index.js
@@ -10,8 +10,9 @@ const NoConsoleLogChecker = require('./no-console')
 const NoGlobalImportsChecker = require('./no-global-import')
 const NoUnusedImportsChecker = require('./no-unused-import')
 const ExplicitTypesChecker = require('./explicit-types')
+const CustomErrorsChecker = require('./custom-errors')
 
-module.exports = function checkers(reporter, config, inputSrc) {
+module.exports = function checkers(reporter, config, inputSrc, tokens) {
   return [
     new CodeComplexityChecker(reporter, config),
     new FunctionMaxLinesChecker(reporter, config),
@@ -23,7 +24,8 @@ module.exports = function checkers(reporter, config, inputSrc) {
     new ReasonStringChecker(reporter, config),
     new NoConsoleLogChecker(reporter),
     new NoGlobalImportsChecker(reporter),
-    new NoUnusedImportsChecker(reporter),
+    new NoUnusedImportsChecker(reporter, tokens),
     new ExplicitTypesChecker(reporter, config),
+    new CustomErrorsChecker(reporter),
   ]
 }
diff --git a/lib/rules/best-practises/no-unused-import.js b/lib/rules/best-practises/no-unused-import.js
index 993ae14..297875f 100644
--- a/lib/rules/best-practises/no-unused-import.js
+++ b/lib/rules/best-practises/no-unused-import.js
@@ -43,9 +43,10 @@ function isImportIdentifier(node) {
 }
 
 class NoUnusedImportsChecker extends BaseChecker {
-  constructor(reporter) {
+  constructor(reporter, tokens) {
     super(reporter, ruleId, meta)
     this.importedNames = {}
+    this.tokens = tokens
   }
 
   registerUsage(rawName) {
@@ -60,14 +61,6 @@ class NoUnusedImportsChecker extends BaseChecker {
     }
   }
 
-  ArrayTypeName(node) {
-    this.registerUsage(node.baseTypeName.namePath)
-  }
-
-  NewExpression(node) {
-    this.registerUsage(node.typeName.namePath)
-  }
-
   Identifier(node) {
     if (!isImportIdentifier(node)) {
       this.registerUsage(node.name)
@@ -75,9 +68,6 @@ class NoUnusedImportsChecker extends BaseChecker {
   }
 
   FunctionDefinition(node) {
-    if (node.override) {
-      node.override.forEach((it) => this.registerUsage(it.namePath))
-    }
     if (node.isConstructor) {
       node.modifiers.forEach((it) => this.registerUsage(it.name))
     }
@@ -93,18 +83,8 @@ class NoUnusedImportsChecker extends BaseChecker {
     }
   }
 
-  VariableDeclaration(node) {
-    // this ignores builtin types, the check inside registerUsage ignores types
-    // defined in the same file
-    if (node.typeName.type === 'UserDefinedTypeName') {
-      this.registerUsage(node.typeName.namePath)
-    }
-  }
-
-  ContractDefinition(node) {
-    node.baseContracts.forEach((inheritanceSpecifier) => {
-      this.registerUsage(inheritanceSpecifier.baseName.namePath)
-    })
+  UserDefinedTypeName(node) {
+    this.registerUsage(node.namePath)
   }
 
   UsingForDeclaration(node) {
@@ -113,6 +93,16 @@ class NoUnusedImportsChecker extends BaseChecker {
   }
 
   'SourceUnit:exit'() {
+    const keywords = this.tokens.filter((it) => it.type === 'Keyword')
+    const inheritdocStatements = keywords.filter(
+      ({ value }) => /^\/\/\/ *@inheritdoc/.test(value) || /^\/\*\* *@inheritdoc/.test(value)
+    )
+    inheritdocStatements.forEach(({ value }) => {
+      const match = value.match(/@inheritdoc *([a-zA-Z0-9_]*)/)
+      if (match && match[1]) {
+        this.registerUsage(match[1])
+      }
+    })
     forIn(this.importedNames, (value, key) => {
       if (!value.used) {
         this.error(value.node, `imported name ${key} is not used`)
diff --git a/lib/rules/index.js b/lib/rules/index.js
index d7e78ab..7e8a3b5 100644
--- a/lib/rules/index.js
+++ b/lib/rules/index.js
@@ -58,7 +58,7 @@ function coreRules(meta) {
   const { reporter, config, inputSrc, tokens } = meta
 
   return [
-    ...bestPractises(reporter, config, inputSrc),
+    ...bestPractises(reporter, config, inputSrc, tokens),
     ...deprecations(reporter),
     ...miscellaneous(reporter, config, tokens),
     ...naming(reporter, config),
diff --git a/lib/rules/naming/func-named-parameters.js b/lib/rules/naming/func-named-parameters.js
index 24d71d1..170ea4b 100644
--- a/lib/rules/naming/func-named-parameters.js
+++ b/lib/rules/naming/func-named-parameters.js
@@ -2,15 +2,14 @@ const BaseChecker = require('../base-checker')
 const { severityDescription } = require('../../doc/utils')
 
 const DEFAULT_SEVERITY = 'warn'
-const DEFAULT_MAX_UNNAMED_ARGUMENTS = 2
+const DEFAULT_MIN_UNNAMED_ARGUMENTS = 4
 
 const ruleId = 'func-named-parameters'
 const meta = {
   type: 'naming',
 
   docs: {
-    description:
-      'Enforce function calls with Named Parameters when containing more than the configured qty',
+    description: `Enforce named parameters for function calls with ${DEFAULT_MIN_UNNAMED_ARGUMENTS} or more arguments. This rule may have some false positives`,
     category: 'Style Guide Rules',
     options: [
       {
@@ -18,14 +17,15 @@ const meta = {
         default: DEFAULT_SEVERITY,
       },
       {
-        description: 'Maximum qty of unnamed parameters for a function call.',
-        default: JSON.stringify(DEFAULT_MAX_UNNAMED_ARGUMENTS),
+        description:
+          'Minimum qty of unnamed parameters for a function call (to prevent false positives on builtin functions).',
+        default: JSON.stringify(DEFAULT_MIN_UNNAMED_ARGUMENTS),
       },
     ],
     examples: {
       good: [
         {
-          description: 'Function call with two UNNAMED parameters (default is max 2)',
+          description: 'Function call with two UNNAMED parameters (default is 4)',
           code: "functionName('0xA81705c8C247C413a19A244938ae7f4A0393944e', 1e18)",
         },
         {
@@ -39,7 +39,7 @@ const meta = {
       ],
       bad: [
         {
-          description: 'Function call with four UNNAMED parameters (default is max 2)',
+          description: 'Function call with four UNNAMED parameters (default 4)',
           code: 'functionName(_senderAddress, 1e18, _tokenAddress, _receiverAddress )',
         },
       ],
@@ -47,8 +47,8 @@ const meta = {
   },
 
   isDefault: false,
-  recommended: true,
-  defaultSetup: [DEFAULT_SEVERITY, DEFAULT_MAX_UNNAMED_ARGUMENTS],
+  recommended: false,
+  defaultSetup: [DEFAULT_SEVERITY, DEFAULT_MIN_UNNAMED_ARGUMENTS],
 
   schema: { type: 'integer' },
 }
@@ -56,8 +56,11 @@ const meta = {
 class FunctionNamedParametersChecker extends BaseChecker {
   constructor(reporter, config) {
     super(reporter, ruleId, meta)
-    this.maxUnnamedArguments = config && config.getNumber(ruleId, DEFAULT_MAX_UNNAMED_ARGUMENTS)
-    if (!(this.maxUnnamedArguments >= 0)) this.maxUnnamedArguments = DEFAULT_MAX_UNNAMED_ARGUMENTS
+    this.maxUnnamedArguments =
+      (config && config.getNumber(ruleId, DEFAULT_MIN_UNNAMED_ARGUMENTS)) ||
+      DEFAULT_MIN_UNNAMED_ARGUMENTS
+    if (this.maxUnnamedArguments < DEFAULT_MIN_UNNAMED_ARGUMENTS)
+      this.maxUnnamedArguments = DEFAULT_MIN_UNNAMED_ARGUMENTS
   }
 
   FunctionCall(node) {
@@ -68,7 +71,7 @@ class FunctionNamedParametersChecker extends BaseChecker {
       if (qtyNamed === 0 && qtyArgs > this.maxUnnamedArguments) {
         this.error(
           node,
-          `Missing named parameters. Max unnamed parameters value is ${this.maxUnnamedArguments}`
+          `Named parameters missing. MIN unnamed argumenst is ${this.maxUnnamedArguments}`
         )
       }
     }
diff --git a/lib/rules/naming/index.js b/lib/rules/naming/index.js
index 1dffa3f..efb3901 100644
--- a/lib/rules/naming/index.js
+++ b/lib/rules/naming/index.js
@@ -10,6 +10,8 @@ const VarNameMixedcaseChecker = require('./var-name-mixedcase')
 const NamedParametersMappingChecker = require('./named-parameters-mapping')
 const ImmutableVarsNamingChecker = require('./immutable-vars-naming')
 const FunctionNamedParametersChecker = require('./func-named-parameters')
+const FoundryTestFunctionsChecker = require('./foundry-test-functions')
+const NamedReturnValuesChecker = require('./named-return-values')
 
 module.exports = function checkers(reporter, config) {
   return [
@@ -25,5 +27,7 @@ module.exports = function checkers(reporter, config) {
     new NamedParametersMappingChecker(reporter),
     new ImmutableVarsNamingChecker(reporter, config),
     new FunctionNamedParametersChecker(reporter, config),
+    new FoundryTestFunctionsChecker(reporter, config),
+    new NamedReturnValuesChecker(reporter),
   ]
 }
diff --git a/lib/rules/naming/named-return-values.js b/lib/rules/naming/named-return-values.js
new file mode 100644
index 0000000..492a81c
--- /dev/null
+++ b/lib/rules/naming/named-return-values.js
@@ -0,0 +1,60 @@
+const BaseChecker = require('../base-checker')
+const { severityDescription } = require('../../doc/utils')
+
+const DEFAULT_SEVERITY = 'warn'
+
+const ruleId = 'named-return-values'
+const meta = {
+  type: 'naming',
+
+  docs: {
+    description: `Enforce the return values of a function to be named`,
+    category: 'Style Guide Rules',
+    options: [
+      {
+        description: severityDescription,
+        default: DEFAULT_SEVERITY,
+      },
+    ],
+    examples: {
+      good: [
+        {
+          description: 'Function definition with named return values',
+          code: 'function checkBalance(address wallet) external view returns(uint256 retBalance) {}',
+        },
+      ],
+      bad: [
+        {
+          description: 'Function definition with UNNAMED return values',
+          code: 'function checkBalance(address wallet) external view returns(uint256) {}',
+        },
+      ],
+    },
+  },
+
+  isDefault: false,
+  recommended: false,
+  defaultSetup: DEFAULT_SEVERITY,
+
+  schema: null,
+}
+
+class NamedReturnValuesChecker extends BaseChecker {
+  constructor(reporter) {
+    super(reporter, ruleId, meta)
+  }
+
+  FunctionDefinition(node) {
+    if (node.returnParameters) {
+      let index = 0
+      for (const returnValue of node.returnParameters) {
+        if (!returnValue.name) {
+          this.error(node, `Named return value is missing - Index ${index}`)
+        }
+        index++
+      }
+    }
+  }
+}
+
+module.exports = NamedReturnValuesChecker
diff --git a/lib/rules/order/ordering.js b/lib/rules/order/ordering.js
index 494f3ad..6d0e8a0 100644
--- a/lib/rules/order/ordering.js
+++ b/lib/rules/order/ordering.js
@@ -122,6 +122,13 @@ function sourceUnitPartOrder(node) {
   throw new Error('Unrecognized source unit part, please report this issue')
 }
 
+function isInitializerModifier(modifiers, targetName, targetArguments) {
+  // search the modifiers array with the name === 'initializer'
+  return modifiers.some(
+    (modifier) => modifier.name === targetName && modifier.arguments === targetArguments
+  )
+}
+
 function contractPartOrder(node) {
   if (node.type === 'UsingForDeclaration') {
     return [0, 'using for declaration']
@@ -154,8 +161,13 @@ function contractPartOrder(node) {
     return [40, 'modifier definition']
   }
 
-  if (node.isConstructor) {
-    return [50, 'constructor']
+  if (
+    node.isConstructor ||
+    (node.type === 'FunctionDefinition' &&
+      node.name === 'initialize' &&
+      isInitializerModifier(node.modifiers, 'initializer', null))
+  ) {
+    return [50, 'constructor/initializer']
   }
 
   if (isReceiveFunction(node)) {
diff --git a/lib/rules/security/check-send-result.js b/lib/rules/security/check-send-result.js
index a20ee2e..e6381f0 100644
--- a/lib/rules/security/check-send-result.js
+++ b/lib/rules/security/check-send-result.js
@@ -14,16 +14,26 @@ const meta = {
       good: [
         {
           description: 'result of "send" call checked with if statement',
-          code: require('../../../test/fixtures/security/send-result-checked'),
+          code: 'if(x.send(55)) {}',
+        },
+        {
+          description: 'result of "send" call checked within a require',
+          code: 'require(payable(walletAddress).send(moneyAmount), "Failed to send moneyAmount");',
         },
       ],
       bad: [
         {
           description: 'result of "send" call ignored',
-          code: require('../../../test/fixtures/security/send-result-ignored'),
+          code: 'x.send(55);',
         },
       ],
     },
+    notes: [
+      {
+        note: 'Rule will rise false positive on this: `bool success = walletAddress.send(amount); require(success, "Failed to send"); ` ',
+      },
+      { note: 'Rule will skip ERC777 "send" function to prevent false positives' },
+    ],
   },
 
   isDefault: false,
@@ -44,17 +54,24 @@ class CheckSendResultChecker extends BaseChecker {
 
   validateSend(node) {
     if (node.memberName === 'send') {
-      const hasVarDeclaration = traversing.statementNotContains(node, 'VariableDeclaration')
-      const hasIfStatement = traversing.statementNotContains(node, 'IfStatement')
-      const hasRequire = traversing.someParent(node, this.isRequire)
-      const hasAssert = traversing.someParent(node, this.isAssert)
+      if (this.isNotErc777Token(node)) {
+        const hasVarDeclaration = traversing.statementNotContains(node, 'VariableDeclaration')
+        const hasIfStatement = traversing.statementNotContains(node, 'IfStatement')
+        const hasRequire = traversing.someParent(node, this.isRequire)
+        const hasAssert = traversing.someParent(node, this.isAssert)
 
-      if (!hasIfStatement && !hasVarDeclaration && !hasRequire && !hasAssert) {
-        this.error(node, 'Check result of "send" call')
+        if (!hasIfStatement && !hasVarDeclaration && !hasRequire && !hasAssert) {
+          this.error(node, 'Check result of "send" call')
+        }
       }
     }
   }
 
+  isNotErc777Token(node) {
+    const isErc777 = node.parent.type === 'FunctionCall' && node.parent.arguments.length >= 3
+    return !isErc777
+  }
+
   isRequire(node) {
     return node.type === 'FunctionCall' && node.expression.name === 'require'
   }
diff --git a/lib/rules/security/compiler-version.js b/lib/rules/security/compiler-version.js
index 3bb5132..955a53b 100644
--- a/lib/rules/security/compiler-version.js
+++ b/lib/rules/security/compiler-version.js
@@ -4,7 +4,7 @@ const { severityDescription } = require('../../doc/utils')
 
 const ruleId = 'compiler-version'
 const DEFAULT_SEVERITY = 'error'
-const DEFAULT_SEMVER = '^0.5.8'
+const DEFAULT_SEMVER = '^0.8.0'
 const meta = {
   type: 'security',
 
@@ -36,7 +36,8 @@ class CompilerVersionChecker extends BaseChecker {
   constructor(reporter, config) {
     super(reporter, ruleId, meta)
 
-    this.requirement = (config && config.getString(ruleId, DEFAULT_SEMVER)) || DEFAULT_SEMVER
+    this.requirement =
+      (config && config.getStringFromArray(ruleId, DEFAULT_SEMVER)) || DEFAULT_SEMVER
   }
 
   SourceUnit(node) {
diff --git a/lib/rules/security/not-rely-on-time.js b/lib/rules/security/not-rely-on-time.js
index f3420c7..00a9609 100644
--- a/lib/rules/security/not-rely-on-time.js
+++ b/lib/rules/security/not-rely-on-time.js
@@ -10,7 +10,7 @@ const meta = {
   },
 
   isDefault: false,
-  recommended: true,
+  recommended: false,
   defaultSetup: 'warn',
 
   schema: null,
diff --git a/package.json b/package.json
index dabbe26..7c53d28 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "solhint",
-  "version": "3.5.1",
+  "version": "3.6.1",
   "description": "Solidity Code Linter",
   "main": "lib/index.js",
   "keywords": [
diff --git a/scripts/generate-rule-docs.js b/scripts/generate-rule-docs.js
index 1e7a02e..c170bb7 100755
--- a/scripts/generate-rule-docs.js
+++ b/scripts/generate-rule-docs.js
@@ -1,75 +1,77 @@
 #!env node
 const { loadRules } = require('../lib/load-rules')
-const fs = require('fs');
-const { exec, mkdir } = require("shelljs");
-const semver = require('semver');
-const path = require('path');
-const table = require('markdown-table');
-const { ruleSeverityEnum } = require('../lib/doc/utils');
+const fs = require('fs')
+const { exec, mkdir } = require('shelljs')
+const semver = require('semver')
+const path = require('path')
+const table = require('markdown-table')
+const { ruleSeverityEnum } = require('../lib/doc/utils')
 
 /**
  * Borrowed from https://github.com/eslint/eslint/blob/master/Makefile.js
  */
 class GitHelper {
-    /**
-     * Gets the tag name where a given file was introduced first.
-     * @param {string} filePath The file path to check.
-     * @returns {string} The tag name.
-     */
-    static getFirstVersionOfFile(filePath) {
-        const firstCommit = GitHelper.getFirstCommitOfFile(filePath);
-        let tags = GitHelper.execSilent(`git tag --contains ${firstCommit}`);
-
-        tags = GitHelper.splitCommandResultToLines(tags);
-        return tags.reduce((list, version) => {
-            const validatedVersion = semver.valid(version.trim());
-
-            if (validatedVersion) {
-                list.push(validatedVersion);
-            }
-            return list;
-        }, []).sort(semver.compare)[0];
-    }
+  /**
+   * Gets the tag name where a given file was introduced first.
+   * @param {string} filePath The file path to check.
+   * @returns {string} The tag name.
+   */
+  static getFirstVersionOfFile(filePath) {
+    const firstCommit = GitHelper.getFirstCommitOfFile(filePath)
+    let tags = GitHelper.execSilent(`git tag --contains ${firstCommit}`)
+
+    tags = GitHelper.splitCommandResultToLines(tags)
+    return tags
+      .reduce((list, version) => {
+        const validatedVersion = semver.valid(version.trim())
+
+        if (validatedVersion) {
+          list.push(validatedVersion)
+        }
+        return list
+      }, [])
+      .sort(semver.compare)[0]
+  }
 
-    /**
-     * Gets the first commit sha of the given file.
-     * @param {string} filePath The file path which should be checked.
-     * @returns {string} The commit sha.
-     */
-    static getFirstCommitOfFile(filePath) {
-        let commits = GitHelper.execSilent(`git rev-list HEAD -- ${filePath}`);
+  /**
+   * Gets the first commit sha of the given file.
+   * @param {string} filePath The file path which should be checked.
+   * @returns {string} The commit sha.
+   */
+  static getFirstCommitOfFile(filePath) {
+    let commits = GitHelper.execSilent(`git rev-list HEAD -- ${filePath}`)
 
-        commits = GitHelper.splitCommandResultToLines(commits);
-        return commits[commits.length - 1].trim();
-    }
+    commits = GitHelper.splitCommandResultToLines(commits)
+    return commits[commits.length - 1].trim()
+  }
 
-    /**
-     * Splits a command result to separate lines.
-     * @param {string} result The command result string.
-     * @returns {Array} The separated lines.
-     */
-    static splitCommandResultToLines(result) {
-        return result.trim().split("\n");
-    }
+  /**
+   * Splits a command result to separate lines.
+   * @param {string} result The command result string.
+   * @returns {Array} The separated lines.
+   */
+  static splitCommandResultToLines(result) {
+    return result.trim().split('\n')
+  }
 
-    /**
-     * Executes a command and returns the output instead of printing it to stdout.
-     * @param {string} cmd The command string to execute.
-     * @returns {string} The result of the executed command.
-     */
-    static execSilent(cmd) {
-        return exec(cmd, {silent: true}).stdout;
-    }
+  /**
+   * Executes a command and returns the output instead of printing it to stdout.
+   * @param {string} cmd The command string to execute.
+   * @returns {string} The result of the executed command.
+   */
+  static execSilent(cmd) {
+    return exec(cmd, { silent: true }).stdout
+  }
 }
 
 function generateRuleDoc(rule) {
-    const isDefault = !rule.meta.deprecated && rule.meta.isDefault;
-    const isRecommended = !rule.meta.deprecated && rule.meta.recommended;
-    const isDeprecated = rule.meta.deprecated;
-    const version = GitHelper.getFirstVersionOfFile(rule.file);
-    const defaultSeverity = getDefaultSeverity(rule);
+  const isDefault = !rule.meta.deprecated && rule.meta.isDefault
+  const isRecommended = !rule.meta.deprecated && rule.meta.recommended
+  const isDeprecated = rule.meta.deprecated
+  const version = GitHelper.getFirstVersionOfFile(rule.file)
+  const defaultSeverity = getDefaultSeverity(rule)
 
-    return `---
+  return `---
 warning:     "This is a dynamically generated file. Do not edit manually."
 layout:      "default"
 title:       "${rule.ruleId} | Solhint"
@@ -77,14 +79,20 @@ title:       "${rule.ruleId} | Solhint"
 
 # ${rule.ruleId}
 ${[
-    recommendedBadge(isRecommended),
-    deprecatedBadge(isDeprecated),
-    categoryBadge(rule.meta.docs.category),
-    defaultSeverityBadge(defaultSeverity),
-    isDefault ? '> The {"extends": "solhint:default"} property in a configuration file enables this rule.\n' : '',
-    isRecommended ? '> The {"extends": "solhint:recommended"} property in a configuration file enables this rule.\n' : '',
-    isDeprecated ? '> This rule is **deprecated**\n' : ''
-].filter(s => s !== '').join("\n")}
+  recommendedBadge(isRecommended),
+  deprecatedBadge(isDeprecated),
+  categoryBadge(rule.meta.docs.category),
+  defaultSeverityBadge(defaultSeverity),
+  isDefault
+    ? '> The {"extends": "solhint:default"} property in a configuration file enables this rule.\n'
+    : '',
+  isRecommended
+    ? '> The {"extends": "solhint:recommended"} property in a configuration file enables this rule.\n'
+    : '',
+  isDeprecated ? '> This rule is **deprecated**\n' : '',
+]
+  .filter((s) => s !== '')
+  .join('\n')}
 
 ## Description
 ${rule.meta.docs.description}
@@ -94,7 +102,7 @@ ${loadOptions(rule)}
 
 ### Example Config
 ${loadExampleConfig(rule)}
-
+${loadNotes(rule)}
 ## Examples
 ${loadExamples(rule)}
 
@@ -109,44 +117,48 @@ ${linkToVersion(version)}
 }
 
 function categoryBadge(category) {
-    return `![Category Badge](https://img.shields.io/badge/-${encodeURIComponent(category)}-informational)`;
+  return `![Category Badge](https://img.shields.io/badge/-${encodeURIComponent(
+    category
+  )}-informational)`
 }
 
 function recommendedBadge(isRecommended) {
-    return isRecommended ? `![Recommended Badge](https://img.shields.io/badge/-Recommended-brightgreen)` : '';
+  return isRecommended
+    ? `![Recommended Badge](https://img.shields.io/badge/-Recommended-brightgreen)`
+    : ''
 }
 
 function deprecatedBadge(isDeprecated) {
-    return isDeprecated ? `![Deprecated Badge](https://img.shields.io/badge/-Deprecated-yellow)` : '';
+  return isDeprecated ? `![Deprecated Badge](https://img.shields.io/badge/-Deprecated-yellow)` : ''
 }
 
 function defaultSeverityBadge(severity) {
-    const colors = {
-        'warn': 'yellow',
-        'error': 'red'
-    };
-    return `![Default Severity Badge ${severity}](https://img.shields.io/badge/Default%20Severity-${severity}-${colors[severity]})`;
+  const colors = {
+    warn: 'yellow',
+    error: 'red',
+  }
+  return `![Default Severity Badge ${severity}](https://img.shields.io/badge/Default%20Severity-${severity}-${colors[severity]})`
 }
 
 function loadOptions(rule) {
-    if (Array.isArray(rule.meta.defaultSetup)) {
-        const optionsTable = [['Index', 'Description', 'Default Value']];
-        rule.meta.docs.options.forEach((option, index) => {
-            optionsTable.push([index, option.description, option.default]);
-        });
-        return `This rule accepts an array of options:
+  if (Array.isArray(rule.meta.defaultSetup)) {
+    const optionsTable = [['Index', 'Description', 'Default Value']]
+    rule.meta.docs.options.forEach((option, index) => {
+      optionsTable.push([index, option.description, option.default])
+    })
+    return `This rule accepts an array of options:
 
 ${table(optionsTable)}
-`;
-    } else if (typeof rule.meta.defaultSetup === 'string') {
-        return `This rule accepts a string option of rule severity. Must be one of ${ruleSeverityEnum}. Default to ${rule.meta.defaultSetup}.`
-    } else {
-        throw new Error(`Unhandled type of rule.meta.defaultSetup from rule ${rule.ruleId}`);
-    }
+`
+  } else if (typeof rule.meta.defaultSetup === 'string') {
+    return `This rule accepts a string option of rule severity. Must be one of ${ruleSeverityEnum}. Default to ${rule.meta.defaultSetup}.`
+  } else {
+    throw new Error(`Unhandled type of rule.meta.defaultSetup from rule ${rule.ruleId}`)
+  }
 }
 
 function loadExampleConfig(rule) {
-    return `\`\`\`json
+  return `\`\`\`json
 {
   "rules": {
     "${rule.ruleId}": ${JSON.stringify(rule.meta.defaultSetup)}
@@ -156,77 +168,109 @@ function loadExampleConfig(rule) {
 `
 }
 
-function linkToVersion(version) {
-    if (version) {
-        return `This rule was introduced in [Solhint ${version}](https://github.com/protofire/solhint/tree/v${version})`;
-    } else {
-        return `This rule is introduced in the latest version.`;
+function loadNotes(rule) {
+  let textToReturn = ''
+  let noteValue = ''
+  if (rule.meta.docs.notes) {
+    textToReturn = `### Notes\n`
+    for (let i = 0; i < rule.meta.docs.notes.length; i++) {
+      noteValue = rule.meta.docs.notes[i].note
+      textToReturn = textToReturn + `- ${noteValue}\n`
     }
+  }
+
+  return textToReturn
+}
+
+function linkToVersion(version) {
+  if (version) {
+    return `This rule was introduced in [Solhint ${version}](https://github.com/protofire/solhint/tree/v${version})`
+  } else {
+    return `This rule is introduced in the latest version.`
+  }
 }
 
 function linkToSource(rule) {
-    const link = rule.file.replace(path.resolve(path.join(__dirname, '..')), '');
-    return `https://github.com/protofire/solhint/tree/master${link}`;
+  const link = rule.file.replace(path.resolve(path.join(__dirname, '..')), '')
+  return `https://github.com/protofire/solhint/tree/master${link}`
 }
 
 function linkToDocumentSource(rule) {
-    const link = rule.file.replace(path.resolve(path.join(__dirname, '..')), '').replace("lib/rules", "docs/rules").replace(/\.js$/, ".md");
-    return `https://github.com/protofire/solhint/tree/master${link}`;
+  const link = rule.file
+    .replace(path.resolve(path.join(__dirname, '..')), '')
+    .replace('lib/rules', 'docs/rules')
+    .replace(/\.js$/, '.md')
+  return `https://github.com/protofire/solhint/tree/master${link}`
 }
 
 function linkToTestCase(rule) {
-    const link = rule.file.replace(path.resolve(path.join(__dirname, '..', 'lib', 'rules')), '');
-    return `https://github.com/protofire/solhint/tree/master/test/rules${link}`;
+  const link = rule.file.replace(path.resolve(path.join(__dirname, '..', 'lib', 'rules')), '')
+  return `https://github.com/protofire/solhint/tree/master/test/rules${link}`
 }
 
 function loadExamples(rule) {
-    if (!rule.meta.docs.examples) {
-        return "This rule does not have examples.";
-    }
+  if (!rule.meta.docs.examples) {
+    return 'This rule does not have examples.'
+  }
 
-    const examples = [loadCorrectExample(rule), loadIncorrectExample(rule)].filter(s => s !== '').join('\n\n');
-    return examples === '' ? 'This rule does not have examples.' : examples;
+  const examples = [loadCorrectExample(rule), loadIncorrectExample(rule)]
+    .filter((s) => s !== '')
+    .join('\n\n')
+  return examples === '' ? 'This rule does not have examples.' : examples
 }
 
 function loadIncorrectExample(rule) {
-    if (rule.meta.docs.examples.bad && rule.meta.docs.examples.bad.length) {
-        return `### 👎 Examples of **incorrect** code for this rule
-
-${rule.meta.docs.examples.bad.map(ex => `#### ${ex.description}\n\n\`\`\`solidity\n${ex.code}\n\`\`\``).join("\n\n")}`;
-    } else {
-        return '';
-    }
+  if (rule.meta.docs.examples.bad && rule.meta.docs.examples.bad.length) {
+    return `### 👎 Examples of **incorrect** code for this rule
+
+${rule.meta.docs.examples.bad
+  .map((ex) => `#### ${ex.description}\n\n\`\`\`solidity\n${ex.code}\n\`\`\``)
+  .join('\n\n')}`
+  } else {
+    return ''
+  }
 }
 
 function loadCorrectExample(rule) {
-    if (rule.meta.docs.examples.good && rule.meta.docs.examples.good.length) {
-        return `### 👍 Examples of **correct** code for this rule
-
-${rule.meta.docs.examples.good.map(ex => `#### ${ex.description}\n\n\`\`\`solidity\n${ex.code}\n\`\`\``).join("\n\n")}`;
-    } else {
-        return '';
-    }
+  if (rule.meta.docs.examples.good && rule.meta.docs.examples.good.length) {
+    return `### 👍 Examples of **correct** code for this rule
+
+${rule.meta.docs.examples.good
+  .map((ex) => `#### ${ex.description}\n\n\`\`\`solidity\n${ex.code}\n\`\`\``)
+  .join('\n\n')}`
+  } else {
+    return ''
+  }
 }
 
 function getDefaultSeverity(rule) {
-    if (Array.isArray(rule.meta.defaultSetup)) {
-        return rule.meta.defaultSetup[0];
-    } else {
-        return rule.meta.defaultSetup;
-    }
+  if (Array.isArray(rule.meta.defaultSetup)) {
+    return rule.meta.defaultSetup[0]
+  } else {
+    return rule.meta.defaultSetup
+  }
 }
 
 function generateRuleIndex(rulesIndexed) {
-    const contents = Object.keys(rulesIndexed).map(category => {
-        const rows = [["Rule Id", "Error", "Recommended", "Deprecated"]];
-        rulesIndexed[category].map(rule => [`[${rule.ruleId}](./rules/${rule.meta.type}/${rule.ruleId}.md)`, rule.meta.docs.description, (rule.meta.recommended && !rule.meta.deprecated) ? '$~~~~~~~~$✔️' : '', rule.meta.deprecated ? '$~~~~~~~$✔️' : '']).forEach(row => rows.push(row));
-        return `## ${category}
+  const contents = Object.keys(rulesIndexed)
+    .map((category) => {
+      const rows = [['Rule Id', 'Error', 'Recommended', 'Deprecated']]
+      rulesIndexed[category]
+        .map((rule) => [
+          `[${rule.ruleId}](./rules/${rule.meta.type}/${rule.ruleId}.md)`,
+          rule.meta.docs.description,
+          rule.meta.recommended && !rule.meta.deprecated ? '$~~~~~~~~$✔️' : '',
+          rule.meta.deprecated ? '$~~~~~~~$✔️' : '',
+        ])
+        .forEach((row) => rows.push(row))
+      return `## ${category}
 
 ${table(rows)}
-        `;
-    }).join("\n\n");
+        `
+    })
+    .join('\n\n')
 
-    return `---
+  return `---
 warning:     "This is a dynamically generated file. Do not edit manually."
 layout:      "default"
 title:       "Rule Index of Solhint"
@@ -238,61 +282,63 @@ ${contents}
 
 - [ConsenSys Guide for Smart Contracts](https://consensys.github.io/smart-contract-best-practices/recommendations/)
 - [Solidity Style Guide](http://solidity.readthedocs.io/en/develop/style-guide.html)
-`;
+`
 }
 
 function main() {
-    const program = require('commander');
-    program.option('--rule-id <rule-id>', 'rule id');
-    program.option('--index-only', 'only generate rule index');
-    program.parse(process.argv);
-
-    const rules = loadRules();
-    if (!program.indexOnly) {
-        let ruleIds = [];
-        if (program.ruleId) {
-            ruleIds = program.ruleId.split(",");
-        }
-
-        rules.filter(rule => {
-            if (ruleIds.length) {
-                return ruleIds.includes(rule.ruleId);
-            } else {
-                return true;
-            }
-        }).forEach(rule => {
-            const ruleDoc = generateRuleDoc(rule);
-            const dir = path.resolve(path.join(__dirname, '..', 'docs', 'rules', rule.meta.type));
-            const fileName = `${rule.ruleId}.md`;
-            const filePath = path.resolve(path.join(dir, fileName));
-            mkdir('-p', dir);
-            fs.writeFile(filePath, ruleDoc, function (err) {
-                if (err) {
-                    console.error(err);
-                } else {
-                    console.log(`Wrote ${filePath}`)
-                }
-            });
-        });
+  const program = require('commander')
+  program.option('--rule-id <rule-id>', 'rule id')
+  program.option('--index-only', 'only generate rule index')
+  program.parse(process.argv)
+
+  const rules = loadRules()
+  if (!program.indexOnly) {
+    let ruleIds = []
+    if (program.ruleId) {
+      ruleIds = program.ruleId.split(',')
     }
 
-    const rulesIndexed = {};
-    rules.forEach(rule => {
-        if (!rulesIndexed[rule.meta.docs.category]) {
-            rulesIndexed[rule.meta.docs.category] = [rule];
+    rules
+      .filter((rule) => {
+        if (ruleIds.length) {
+          return ruleIds.includes(rule.ruleId)
         } else {
-            rulesIndexed[rule.meta.docs.category].push(rule);
+          return true
         }
-    });
-    const ruleIndexDoc = generateRuleIndex(rulesIndexed);
-    const ruleIndexDocPath = path.resolve(path.join(__dirname, '..', 'docs', 'rules.md'));
-    fs.writeFile(ruleIndexDocPath, ruleIndexDoc, function (err) {
-        if (err) {
-            console.error(err);
-        } else {
-            console.log(`Wrote ${ruleIndexDocPath}`)
-        }
-    });
+      })
+      .forEach((rule) => {
+        const ruleDoc = generateRuleDoc(rule)
+        const dir = path.resolve(path.join(__dirname, '..', 'docs', 'rules', rule.meta.type))
+        const fileName = `${rule.ruleId}.md`
+        const filePath = path.resolve(path.join(dir, fileName))
+        mkdir('-p', dir)
+        fs.writeFile(filePath, ruleDoc, function (err) {
+          if (err) {
+            console.error(err)
+          } else {
+            console.log(`Wrote ${filePath}`)
+          }
+        })
+      })
+  }
+
+  const rulesIndexed = {}
+  rules.forEach((rule) => {
+    if (!rulesIndexed[rule.meta.docs.category]) {
+      rulesIndexed[rule.meta.docs.category] = [rule]
+    } else {
+      rulesIndexed[rule.meta.docs.category].push(rule)
+    }
+  })
+  const ruleIndexDoc = generateRuleIndex(rulesIndexed)
+  const ruleIndexDocPath = path.resolve(path.join(__dirname, '..', 'docs', 'rules.md'))
+  fs.writeFile(ruleIndexDocPath, ruleIndexDoc, function (err) {
+    if (err) {
+      console.error(err)
+    } else {
+      console.log(`Wrote ${ruleIndexDocPath}`)
+    }
+  })
 }
 
-main();
+main()


Test patch:
diff --git a/docs/rules/naming/foundry-test-functions.md b/docs/rules/naming/foundry-test-functions.md
new file mode 100644
index 0000000..534ad6e
--- /dev/null
+++ b/docs/rules/naming/foundry-test-functions.md
@@ -0,0 +1,73 @@
+---
+warning:     "This is a dynamically generated file. Do not edit manually."
+layout:      "default"
+title:       "foundry-test-functions | Solhint"
+---
+
+# foundry-test-functions
+![Category Badge](https://img.shields.io/badge/-Style%20Guide%20Rules-informational)
+![Default Severity Badge off](https://img.shields.io/badge/Default%20Severity-off-undefined)
+
+## Description
+Enforce naming convention on functions for Foundry test cases
+
+## Options
+This rule accepts an array of options:
+
+| Index | Description                                           | Default Value |
+| ----- | ----------------------------------------------------- | ------------- |
+| 0     | Rule severity. Must be one of "error", "warn", "off". | off           |
+
+
+### Example Config
+```json
+{
+  "rules": {
+    "foundry-test-functions": ["off",["setUp"]]
+  }
+}
+```
+
+### Notes
+- This rule can be configured to skip certain function names in the SKIP array. In Example Config. ```setUp``` function will be skipped
+- Supported Regex: ```test(Fork)?(Fuzz)?(Fail)?_(Revert(If_|When_){1})?\w{1,}```
+- This rule should be executed in a separate folder with a separate .solhint.json => ```solhint --config .solhint.json testFolder/**/*.sol```
+- This rule applies only to `external` and `public` functions
+- This rule skips the `setUp()` function
+
+## Examples
+### 👍 Examples of **correct** code for this rule
+
+#### Foundry test case with correct Function declaration
+
+```solidity
+function test_NumberIs42() public {}
+```
+
+#### Foundry test case with correct Function declaration
+
+```solidity
+function testFail_Subtract43() public {}
+```
+
+#### Foundry test case with correct Function declaration
+
+```solidity
+function testFuzz_FuzzyTest() public {}
+```
+
+### 👎 Examples of **incorrect** code for this rule
+
+#### Foundry test case with incorrect Function declaration
+
+```solidity
+function numberIs42() public {}
+```
+
+## Version
+This rule is introduced in the latest version.
+
+## Resources
+- [Rule source](https://github.com/protofire/solhint/tree/master/lib/rules/naming/foundry-test-functions.js)
+- [Document source](https://github.com/protofire/solhint/tree/master/docs/rules/naming/foundry-test-functions.md)
+- [Test cases](https://github.com/protofire/solhint/tree/master/test/rules/naming/foundry-test-functions.js)
diff --git a/e2e/05-max-warnings/contracts/Foo.sol b/e2e/05-max-warnings/contracts/Foo.sol
index 659755d..1c04574 100644
--- a/e2e/05-max-warnings/contracts/Foo.sol
+++ b/e2e/05-max-warnings/contracts/Foo.sol
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity >=0.5.8;
+pragma solidity >=0.8.0;
 
 contract Foo {
     uint256 public constant test1 = 1;
diff --git a/e2e/06-formatters/contracts/Foo2.sol b/e2e/06-formatters/contracts/Foo2.sol
index 9fb9801..4a5c2af 100644
--- a/e2e/06-formatters/contracts/Foo2.sol
+++ b/e2e/06-formatters/contracts/Foo2.sol
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity >=0.5.8;
+pragma solidity >=0.8.0;
 
 contract Foo {
     uint256 public constant test1 = 1;
diff --git a/e2e/06-formatters/contracts/Foo3.sol b/e2e/06-formatters/contracts/Foo3.sol
index f89c691..8c1c1e0 100644
--- a/e2e/06-formatters/contracts/Foo3.sol
+++ b/e2e/06-formatters/contracts/Foo3.sol
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity >=0.5.8;
+pragma solidity >=0.8.0;
 
 contract Foo {
     uint256 public constant TEST1 = 1;
diff --git a/e2e/06-formatters/helpers/helpers.js b/e2e/06-formatters/helpers/helpers.js
index 0508991..85d43c6 100644
--- a/e2e/06-formatters/helpers/helpers.js
+++ b/e2e/06-formatters/helpers/helpers.js
@@ -3,7 +3,7 @@ const foo1Output = [
     line: 2,
     column: 1,
     severity: 'Error',
-    message: 'Compiler version >=0.6.0 does not satisfy the ^0.5.8 semver requirement',
+    message: 'Compiler version >=0.6.0 does not satisfy the ^0.8.0 semver requirement',
     ruleId: 'compiler-version',
     fix: null,
     filePath: 'contracts/Foo.sol',
diff --git a/e2e/07-foundry-test/.solhint.json b/e2e/07-foundry-test/.solhint.json
new file mode 100644
index 0000000..92277f3
--- /dev/null
+++ b/e2e/07-foundry-test/.solhint.json
@@ -0,0 +1,7 @@
+{
+  "extends": "solhint:recommended",
+  "rules": {
+    "compiler-version": "off",
+    "func-visibility": "off"
+  }
+}
diff --git a/e2e/07-foundry-test/contracts/Foo.sol b/e2e/07-foundry-test/contracts/Foo.sol
new file mode 100644
index 0000000..3ffecf6
--- /dev/null
+++ b/e2e/07-foundry-test/contracts/Foo.sol
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.8.0;
+
+contract Foo {
+    uint256 public constant TEST = 1;
+
+    constructor() {
+
+    }
+}
diff --git a/e2e/07-foundry-test/test/.solhint.json b/e2e/07-foundry-test/test/.solhint.json
new file mode 100644
index 0000000..da87cc4
--- /dev/null
+++ b/e2e/07-foundry-test/test/.solhint.json
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "foundry-test-functions": ["error", ["setUp", "finish"]]
+  }
+}
diff --git a/e2e/07-foundry-test/test/FooTest.sol b/e2e/07-foundry-test/test/FooTest.sol
new file mode 100644
index 0000000..be603e5
--- /dev/null
+++ b/e2e/07-foundry-test/test/FooTest.sol
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.6.0;
+
+import "./Test.sol";
+
+contract FooTest is Test {
+    uint256 testNumber;
+
+    function setUp() public {
+        testNumber = 42;
+    }
+
+    function testFail_Subtract43() public {
+        testNumber -= 43;
+    }
+
+    function wrongFunctionDefinitionName() public {
+        testNumber -= 43;
+    }
+}
\ No newline at end of file
diff --git a/e2e/07-foundry-test/test/Test.sol b/e2e/07-foundry-test/test/Test.sol
new file mode 100644
index 0000000..d7d1624
--- /dev/null
+++ b/e2e/07-foundry-test/test/Test.sol
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.6.0;
+
+contract Test {}
diff --git a/e2e/test.js b/e2e/test.js
index bf3910f..c218dae 100644
--- a/e2e/test.js
+++ b/e2e/test.js
@@ -147,4 +147,26 @@ describe('e2e', function () {
       expect(stdout.trim()).to.not.contain(errorFound)
     })
   })
+
+  describe('Linter - foundry-test-functions with shell', () => {
+    // Foo contract has 1 warning
+    // FooTest contract has 1 error
+    useFixture('07-foundry-test')
+
+    it(`should raise error for empty blocks only`, () => {
+      const { code, stdout } = shell.exec('solhint contracts/Foo.sol')
+
+      expect(code).to.equal(0)
+      expect(stdout.trim()).to.contain('Code contains empty blocks')
+    })
+
+    it(`should raise error for wrongFunctionDefinitionName() only`, () => {
+      const { code, stdout } = shell.exec('solhint -c test/.solhint.json test/FooTest.sol')
+
+      expect(code).to.equal(1)
+      expect(stdout.trim()).to.contain(
+        'Function wrongFunctionDefinitionName() must match Foundry test naming convention'
+      )
+    })
+  })
 })
diff --git a/lib/rules/naming/foundry-test-functions.js b/lib/rules/naming/foundry-test-functions.js
new file mode 100644
index 0000000..1cc367a
--- /dev/null
+++ b/lib/rules/naming/foundry-test-functions.js
@@ -0,0 +1,93 @@
+const BaseChecker = require('../base-checker')
+const naming = require('../../common/identifier-naming')
+const { severityDescription } = require('../../doc/utils')
+
+const DEFAULT_SEVERITY = 'off'
+const DEFAULT_SKIP_FUNCTIONS = ['setUp']
+
+const ruleId = 'foundry-test-functions'
+const meta = {
+  type: 'naming',
+
+  docs: {
+    description: `Enforce naming convention on functions for Foundry test cases`,
+    category: 'Style Guide Rules',
+    options: [
+      {
+        description: severityDescription,
+        default: DEFAULT_SEVERITY,
+      },
+    ],
+    examples: {
+      good: [
+        {
+          description: 'Foundry test case with correct Function declaration',
+          code: 'function test_NumberIs42() public {}',
+        },
+        {
+          description: 'Foundry test case with correct Function declaration',
+          code: 'function testFail_Subtract43() public {}',
+        },
+        {
+          description: 'Foundry test case with correct Function declaration',
+          code: 'function testFuzz_FuzzyTest() public {}',
+        },
+      ],
+      bad: [
+        {
+          description: 'Foundry test case with incorrect Function declaration',
+          code: 'function numberIs42() public {}',
+        },
+      ],
+    },
+    notes: [
+      {
+        note: 'This rule can be configured to skip certain function names in the SKIP array. In Example Config. ```setUp``` function will be skipped',
+      },
+      { note: 'Supported Regex: ```test(Fork)?(Fuzz)?(Fail)?_(Revert(If_|When_){1})?\\w{1,}```' },
+      {
+        note: 'This rule should be executed in a separate folder with a separate .solhint.json => ```solhint --config .solhint.json testFolder/**/*.sol```',
+      },
+      {
+        note: 'This rule applies only to `external` and `public` functions',
+      },
+      {
+        note: 'This rule skips the `setUp()` function',
+      },
+    ],
+  },
+
+  isDefault: false,
+  recommended: false,
+  defaultSetup: [DEFAULT_SEVERITY, DEFAULT_SKIP_FUNCTIONS],
+
+  schema: { type: 'array' },
+}
+
+class FoundryTestFunctionsChecker extends BaseChecker {
+  constructor(reporter, config) {
+    super(reporter, ruleId, meta)
+    this.skippedFunctions = config
+      ? config.getArray(ruleId, DEFAULT_SKIP_FUNCTIONS)
+      : DEFAULT_SKIP_FUNCTIONS
+  }
+
+  FunctionDefinition(node) {
+    // function name should not be in skipped functions array
+    // should be external or public
+    if (
+      !this.searchInArray(this.skippedFunctions, node.name) &&
+      (node.visibility === 'public' || node.visibility === 'external')
+    ) {
+      if (naming.isNotFoundryTestCase(node.name)) {
+        this.error(node, `Function ${node.name}() must match Foundry test naming convention`)
+      }
+    }
+  }
+
+  searchInArray(array, searchString) {
+    return array.indexOf(searchString) !== -1
+  }
+}
+
+module.exports = FoundryTestFunctionsChecker
diff --git a/test/fixtures/naming/func-named-parameters.js b/test/fixtures/naming/func-named-parameters.js
index d4ceb7a..ef0203c 100644
--- a/test/fixtures/naming/func-named-parameters.js
+++ b/test/fixtures/naming/func-named-parameters.js
@@ -1,53 +1,64 @@
 const FUNCTION_CALLS_ERRORS = {
-  maxUnnamed_0_1u: {
-    code: 'funcName(_sender);',
-    maxUnnamed: 0,
+  err1: {
+    code: 'funcName(_sender, amount, receiver, token1, token2, token3);',
+    minUnnamed: 5,
   },
 
-  maxUnnamed_1_3u: {
-    code: 'funcName(_sender, amount, receiver);',
-    maxUnnamed: 1,
+  err2: {
+    code: 'funcName(_sender, amount, receiver, token1, token2);',
+    minUnnamed: 4,
   },
 
-  maxUnnamed_2_3u: {
-    code: 'funcName(_sender, amount, receiver);',
-    maxUnnamed: 2,
-  },
-
-  maxUnnamed_3_4u: {
-    code: 'funcName(_sender, amount, receiver, token);',
-    maxUnnamed: 3,
+  err3: {
+    code: 'funcName(_sender, amount, receiver, token1, token2);',
+    minUnnamed: 0,
   },
 }
 
 const FUNCTION_CALLS_OK = {
-  maxUnnamed_0_0u: {
+  ok1: {
     code: 'funcName();',
-    maxUnnamed: 0,
+    minUnnamed: 0,
   },
 
-  maxUnnamed_0_0uB: {
-    code: 'funcName();',
-    maxUnnamed: 10,
+  ok2: {
+    code: 'address(0);',
+    minUnnamed: 10,
   },
 
-  maxUnnamed_1_0u: {
+  ok3: {
     code: 'funcName({ sender: _sender, amount: _amount, receiver: _receiver });',
-    maxUnnamed: 1,
+    minUnnamed: 1,
   },
 
-  maxUnnamed_1_1u: {
-    code: 'funcName(sender);',
-    maxUnnamed: 1,
+  ok4: {
+    code: 'assert(1 == 3);',
+    minUnnamed: 1,
   },
-  maxUnnamed_2_2u: {
-    code: 'funcName(sender, amount);',
-    maxUnnamed: 2,
+
+  ok5: {
+    code: 'bytes foo = abi.encodeWithSelector(hex"0102030405060708", uint16(0xff00));',
+    minUnnamed: 2,
   },
 
-  maxUnnamed3_0u: {
-    code: 'funcName({ sender: _sender, amount: _amount, receiver: _receiver });',
-    maxUnnamed: 3,
+  ok6: {
+    code: 'funcName({ sender: _sender, amount: _amount, receiver: _receiver, token1: _token1, token2: _token2 });',
+    minUnnamed: 5,
+  },
+
+  ok7: {
+    code: 'new BeaconProxy(address(0),abi.encodeWithSelector(bytes4(""),address(0),address(0),address(0)));',
+    minUnnamed: 2,
+  },
+
+  ok8: {
+    code: 'salt = keccak256(abi.encode(msg.sender, block.chainid, salt));',
+    minUnnamed: 0,
+  },
+
+  ok9: {
+    code: 'require(foobar != address(0), "foobar must a valid address");',
+    minUnnamed: 0,
   },
 }
 
diff --git a/test/fixtures/security/send-result-checked.js b/test/fixtures/security/send-result-checked.js
deleted file mode 100644
index 6b4f384..0000000
--- a/test/fixtures/security/send-result-checked.js
+++ /dev/null
@@ -1,1 +0,0 @@
-module.exports = 'if(x.send(55)) {}'
diff --git a/test/fixtures/security/send-result-ignored.js b/test/fixtures/security/send-result-ignored.js
deleted file mode 100644
index 040959e..0000000
--- a/test/fixtures/security/send-result-ignored.js
+++ /dev/null
@@ -1,1 +0,0 @@
-module.exports = 'x.send(55);'
diff --git a/test/rules/best-practises/custom-errors.js b/test/rules/best-practises/custom-errors.js
new file mode 100644
index 0000000..1904a3a
--- /dev/null
+++ b/test/rules/best-practises/custom-errors.js
@@ -0,0 +1,103 @@
+const assert = require('assert')
+const {
+  assertNoWarnings,
+  assertNoErrors,
+  assertErrorMessage,
+  assertErrorCount,
+  assertWarnsCount,
+} = require('../../common/asserts')
+const linter = require('../../../lib/index')
+const { funcWith } = require('../../common/contract-builder')
+
+describe('Linter - custom-errors', () => {
+  it('should raise error for revert()', () => {
+    const code = funcWith(`revert();`)
+    const report = linter.processStr(code, {
+      rules: { 'custom-errors': 'error' },
+    })
+
+    assertErrorCount(report, 1)
+    assertErrorMessage(report, 'Use Custom Errors instead of revert statement')
+  })
+
+  it('should raise error for revert([string])', () => {
+    const code = funcWith(`revert("Insufficent funds");`)
+    const report = linter.processStr(code, {
+      rules: { 'custom-errors': 'error' },
+    })
+
+    assertErrorCount(report, 1)
+    assertErrorMessage(report, 'Use Custom Errors instead of revert statement')
+  })
+
+  it('should NOT raise error for revert ErrorFunction()', () => {
+    const code = funcWith(`revert ErrorFunction();`)
+    const report = linter.processStr(code, {
+      rules: { 'custom-errors': 'error' },
+    })
+
+    assertNoWarnings(report)
+    assertNoErrors(report)
+  })
+
+  it('should NOT raise error for revert ErrorFunction() with arguments', () => {
+    const code = funcWith(`revert ErrorFunction({ msg: "Insufficent funds msg" });`)
+    const report = linter.processStr(code, {
+      rules: { 'custom-errors': 'error' },
+    })
+
+    assertNoWarnings(report)
+    assertNoErrors(report)
+  })
+
+  it('should raise error for require', () => {
+    const code = funcWith(`require(!has(role, account), "Roles: account already has role");
+        role.bearer[account] = true;role.bearer[account] = true;
+    `)
+    const report = linter.processStr(code, {
+      rules: { 'custom-errors': 'error' },
+    })
+
+    assertErrorCount(report, 1)
+    assertErrorMessage(report, 'Use Custom Errors instead of require statement')
+  })
+
+  it('should NOT raise error for regular function call', () => {
+    const code = funcWith(`callOtherFunction();
+        role.bearer[account] = true;role.bearer[account] = true;
+    `)
+    const report = linter.processStr(code, {
+      rules: { 'custom-errors': 'error' },
+    })
+    assertNoWarnings(report)
+    assertNoErrors(report)
+  })
+
+  it('should raise error for require, revert message and not for revert CustomError() for [recommended] config', () => {
+    const code = funcWith(`require(!has(role, account), "Roles: account already has role");
+        revert("RevertMessage");
+        revert CustomError();
+    `)
+    const report = linter.processStr(code, {
+      extends: 'solhint:recommended',
+      rules: { 'compiler-version': 'off' },
+    })
+
+    assertWarnsCount(report, 2)
+    assert.equal(report.reports[0].message, 'Use Custom Errors instead of require statements')
+    assert.equal(report.reports[1].message, 'Use Custom Errors instead of revert statements')
+  })
+
+  it('should NOT raise error for default config', () => {
+    const code = funcWith(`require(!has(role, account), "Roles: account already has role");
+        revert("RevertMessage");
+        revert CustomError();
+    `)
+    const report = linter.processStr(code, {
+      extends: 'solhint:default',
+    })
+
+    assertWarnsCount(report, 0)
+    assertErrorCount(report, 0)
+  })
+})
diff --git a/test/rules/best-practises/explicit-types.js b/test/rules/best-practises/explicit-types.js
index 842329c..2ff4a29 100644
--- a/test/rules/best-practises/explicit-types.js
+++ b/test/rules/best-practises/explicit-types.js
@@ -1,4 +1,3 @@
-const assert = require('assert')
 const linter = require('../../../lib/index')
 const contractWith = require('../../common/contract-builder').contractWith
 const { assertErrorCount, assertNoErrors, assertErrorMessage } = require('../../common/asserts')
@@ -21,30 +20,24 @@ const getZeroErrosObject = () => {
 }
 
 describe('Linter - explicit-types rule', () => {
-  it('should throw an error with a wrong configuration rule example 1', () => {
+  it('should throw an error with a wrong configuration rule', () => {
     const code = contractWith('uint256 public constant SNAKE_CASE = 1;')
-    try {
-      linter.processStr(code, {
-        rules: { 'explicit-types': ['error', 'implicito'] },
-      })
-    } catch (error) {
-      assert.ok(
-        error.toString().includes('Error: Config error on [explicit-types]. See explicit-types.md.')
-      )
-    }
+
+    const report = linter.processStr(code, {
+      rules: { 'explicit-types': ['error', 'implicito'] },
+    })
+
+    assertErrorCount(report, 1)
+    assertErrorMessage(report, `Error: Config error on [explicit-types]. See explicit-types.md.`)
   })
 
-  it('should throw an error with a wrong configuration rule example 2', () => {
+  it('should NOT throw error without the config array and default should take place', () => {
     const code = contractWith('uint256 public constant SNAKE_CASE = 1;')
-    try {
-      linter.processStr(code, {
-        rules: { 'explicit-types': 'error' },
-      })
-    } catch (error) {
-      assert.ok(
-        error.toString().includes('Error: Config error on [explicit-types]. See explicit-types.md.')
-      )
-    }
+    const report = linter.processStr(code, {
+      rules: { 'explicit-types': 'error' },
+    })
+
+    assertNoErrors(report)
   })
 
   for (const key in VAR_DECLARATIONS) {
diff --git a/test/rules/best-practises/no-global-import.js b/test/rules/best-practises/no-global-import.js
index 3ab26a1..7a357e1 100644
--- a/test/rules/best-practises/no-global-import.js
+++ b/test/rules/best-practises/no-global-import.js
@@ -28,7 +28,7 @@ describe('Linter - no-global-import', () => {
     assertErrorMessage(report, 'Specify names to import individually')
   })
   it('should raise warning when using solhint:recommended', () => {
-    const code = `pragma solidity ^0.5.8; import "./A.sol";`
+    const code = `pragma solidity ^0.8.0; import "./A.sol";`
 
     const report = linter.processStr(code, {
       extends: 'solhint:recommended',
diff --git a/test/rules/best-practises/no-unused-import.js b/test/rules/best-practises/no-unused-import.js
index 49a2c49..f366689 100644
--- a/test/rules/best-practises/no-unused-import.js
+++ b/test/rules/best-practises/no-unused-import.js
@@ -27,8 +27,28 @@ describe('Linter - no-unused-import', () => {
     assertErrorMessage(report, 'imported name A is not used')
   })
 
+  it('should not crash on, but also not recognize, malformed inheritdoc statements', () => {
+    const code = `
+    import {A} from './A.sol';
+    // inheritdoc A
+    // @inheritdoc A
+    /// inheritdoc A
+    /// @ inherit A
+    /// @ inheritdoc A
+    /// @inheritdoc somethingelse
+    /// @inheritdoc
+    /// @inheritdoc 
+    `
+
+    const report = linter.processStr(code, {
+      rules: { 'no-unused-import': 'error' },
+    })
+    assertErrorCount(report, 1)
+    assertErrorMessage(report, 'imported name A is not used')
+  })
+
   it('should raise error when using solhint:recommended', () => {
-    const code = `pragma solidity ^0.5.8; import {A} from "./A.sol";`
+    const code = `pragma solidity ^0.8.0; import {A} from "./A.sol";`
 
     const report = linter.processStr(code, {
       extends: 'solhint:recommended',
@@ -171,10 +191,11 @@ describe('Linter - no-unused-import', () => {
       description: 'Name is used in an override',
       code: `
         pragma solidity >=0.8.19;
+
         import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
         import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
+
         contract MyContract {
-            /// @inheritdoc ERC721
             function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri) {
                 uri = "example.com";
             }
@@ -185,7 +206,9 @@ describe('Linter - no-unused-import', () => {
       description: 'Type is used in a constructor initializator',
       code: `
         pragma solidity >=0.8.19;
+
         import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
+
         contract MyContract {
             constructor() ERC721("Sablier V2 Lockup Dynamic NFT", "SAB-V2-LOCKUP-DYN") { }
         }
@@ -195,7 +218,9 @@ describe('Linter - no-unused-import', () => {
       description: 'Import is used as value in a function parameter',
       code: `
         pragma solidity >=0.8.19 <0.9.0;
+
         import { UD60x18, ZERO } from "@prb/math/UD60x18.sol";
+
         contract SetProtocolFee_Integration_Fuzz_Test {
             function testFuzz_SetProtocolFee(UD60x18 newProtocolFee) external {
                 newProtocolFee = _bound(newProtocolFee, 1, MAX_FEE);
@@ -209,6 +234,7 @@ describe('Linter - no-unused-import', () => {
       description: 'Import is used as value in a binary expression',
       code: `
         import { ZERO } from "@prb/math/UD60x18.sol";
+
         contract Foo {
             function returnFifteen() public returns (uint){
               return ZERO + 15;
@@ -220,6 +246,7 @@ describe('Linter - no-unused-import', () => {
       description: 'Import is used as value in an assignment',
       code: `
         import { ZERO } from "@prb/math/UD60x18.sol";
+
         contract Foo {
             uint256 public howMuch;
             constructor () {
@@ -228,6 +255,69 @@ describe('Linter - no-unused-import', () => {
         }
       `,
     },
+    {
+      description: 'Import is used in the left side of a using for statement',
+      code: `
+        pragma solidity >=0.8.19;
+
+        import {EnumerableSetUD60x18, EnumerableSet} from "./libraries/EnumerableSetUD60x18.sol";
+
+        contract SolhintTest {
+            using EnumerableSetUD60x18 for EnumerableSet.Bytes32Set;
+        }
+      `,
+    },
+    {
+      description: 'Import is used as the type value of a mapping',
+      code: `
+        pragma solidity >=0.8.19;
+
+        import {UD60x18} from "@prb/math/UD60x18.sol";
+
+        contract SolhintTest {
+            mapping(address user => UD60x18 amount) internal balance;
+        }
+      `,
+    },
+    {
+      description: 'Import is used as the type value of a nested mapping',
+      code: `
+        pragma solidity >=0.8.19;
+        import {SD59x18} from "@prb/math/SD59x18.sol";
+
+        contract SolhintTest {
+            mapping(address user => mapping(address relayer => SD59x18 amount)) internal balance;
+        }
+      `,
+    },
+    {
+      description: 'Import is used in /// @inheritdoc',
+      code: `
+        import { IPRBProxyPlugin } from "@prb/proxy/interfaces/IPRBProxyPlugin.sol";
+
+        contract SablierV2ProxyPlugin {
+          /// @inheritdoc IPRBProxyPlugin
+          function getMethods() external pure returns (bytes4[] memory methods) {
+              methods = new bytes4[](1);
+              methods[0] = this.onStreamCanceled.selector;
+          }
+        }
+      `,
+    },
+    {
+      description: 'Import is used in /** @inheritdoc',
+      code: `
+        import { IPRBProxyPlugin } from "@prb/proxy/interfaces/IPRBProxyPlugin.sol";
+
+        contract SablierV2ProxyPlugin {
+          /** @inheritdoc IPRBProxyPlugin */
+          function getMethods() external pure returns (bytes4[] memory methods) {
+              methods = new bytes4[](1);
+              methods[0] = this.onStreamCanceled.selector;
+          }
+        }
+      `,
+    },
   ].forEach(({ description, code }) => {
     it(`should not raise when ${description}`, () => {
       const report = linter.processStr(code, {
diff --git a/test/rules/naming/foundry-test-functions.js b/test/rules/naming/foundry-test-functions.js
new file mode 100644
index 0000000..9a0feeb
--- /dev/null
+++ b/test/rules/naming/foundry-test-functions.js
@@ -0,0 +1,224 @@
+const assert = require('assert')
+const linter = require('../../../lib/index')
+const contractWith = require('../../common/contract-builder').contractWith
+const { assertErrorCount, assertNoErrors, assertErrorMessage } = require('../../common/asserts')
+
+const ALLOWED_FUNCTION_NAMES = [
+  'test_',
+  'testFork_',
+  'testFuzz_',
+  'testFail_',
+  'test_Revert_',
+  'test_If_',
+  'test_When_',
+  'testFail_Revert_',
+  'testFail_If_',
+  'testFail_When_',
+  'testFork_Revert_',
+  'testFork_If_',
+  'testFork_When_',
+  'testFuzz_Revert_',
+  'testFuzz_If_',
+  'testFuzz_When_',
+]
+
+const DISALLOWED_FUNCTION_NAMES = ['Test_', 'Test', 'test', 'testo_', '', 'any', 'setUp', 'other']
+
+const composeFunctionName = (prefix, name, visibility) =>
+  'function ' + prefix + name + ' ' + visibility + ' { testNumber = 42; }'
+
+describe('Linter - foundry-test-functions', () => {
+  for (const prefix of DISALLOWED_FUNCTION_NAMES) {
+    it(`should raise error for DISALLOWED_FUNCTION_NAMES [${prefix}] when PUBLIC`, () => {
+      const functionDefinition = composeFunctionName(prefix, 'FunctionName()', 'public')
+      const code = contractWith(functionDefinition)
+
+      const report = linter.processStr(code, {
+        rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+      })
+
+      assertErrorCount(report, 1)
+      assertErrorMessage(
+        report,
+        `Function ${prefix + 'FunctionName()'} must match Foundry test naming convention`
+      )
+    })
+  }
+
+  for (const prefix of DISALLOWED_FUNCTION_NAMES) {
+    it(`should NOT raise error for DISALLOWED_FUNCTION_NAMES [${prefix}] when INTERNAL`, () => {
+      const functionDefinition = composeFunctionName(prefix, 'FunctionName()', 'internal')
+      const code = contractWith(functionDefinition)
+
+      const report = linter.processStr(code, {
+        rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+      })
+
+      assertNoErrors(report)
+    })
+  }
+
+  for (const prefix of ALLOWED_FUNCTION_NAMES) {
+    it(`should NOT raise error for ALLOWED_FUNCTION_NAMES [${prefix}] when PUBLIC`, () => {
+      const functionDefinition = composeFunctionName(prefix, 'FunctionName()', 'public')
+      const code = contractWith(functionDefinition)
+
+      const report = linter.processStr(code, {
+        rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+      })
+
+      assertNoErrors(report)
+    })
+  }
+
+  for (const prefix of ALLOWED_FUNCTION_NAMES) {
+    it(`should NOT raise error for ALLOWED_FUNCTION_NAMES [${prefix}] when EXTERNAL`, () => {
+      const functionDefinition = composeFunctionName(prefix, 'FunctionName()', 'external')
+      const code = contractWith(functionDefinition)
+
+      const report = linter.processStr(code, {
+        rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+      })
+
+      assertNoErrors(report)
+    })
+  }
+
+  for (const prefix of ALLOWED_FUNCTION_NAMES) {
+    it(`should NOT raise error for ALLOWED_FUNCTION_NAMES [${prefix}] when INTERNAL`, () => {
+      const functionDefinition = composeFunctionName(prefix, 'FunctionName()', 'external')
+      const code = contractWith(functionDefinition)
+
+      const report = linter.processStr(code, {
+        rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+      })
+
+      assertNoErrors(report)
+    })
+  }
+
+  it(`should NOT raise error for setUp function, since is confired as SKIPPED`, () => {
+    const code = contractWith(
+      'function setUp() public { testNumber = 42; } function finish() public { testNumber = 42; }'
+    )
+
+    const report = linter.processStr(code, {
+      rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+    })
+
+    assertNoErrors(report)
+  })
+
+  it(`should NOT raise error for setUp and finish functions but RAISE for the other two functions`, () => {
+    const code = contractWith(`
+      function setUp() public { testNumber = 42; }
+      function finish() public { testNumber = 43; }
+      function invalidFunction1() external { testNumber = 44; }
+      function invalidFunction2() external { testNumber = 45; }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'foundry-test-functions': ['error', ['setUp', 'finish']] },
+    })
+
+    assertErrorCount(report, 2)
+    assert.equal(
+      report.reports[0].message,
+      `Function invalidFunction1() must match Foundry test naming convention`
+    )
+    assert.equal(
+      report.reports[1].message,
+      'Function invalidFunction2() must match Foundry test naming convention'
+    )
+  })
+
+  it('should NOT raise error when recommended rules are configured', () => {
+    const code = contractWith(`
+      function setUp() public { testNumber = 42; }
+      function finish() public { testNumber = 43; }
+      function invalidFunction1() external { testNumber = 44; }
+      function invalidFunction2() external { testNumber = 45; }`)
+
+    const report = linter.processStr(code, {
+      extends: 'solhint:recommended',
+      rules: { 'compiler-version': 'off' },
+    })
+
+    assertNoErrors(report)
+  })
+
+  it('should raise 2 errors when all rules are configured and setUp is skipped', () => {
+    const code = contractWith(`
+      function setUp() public { testNumber = 42; }
+      function invalidFunction1() external { testNumber = 44; }
+      function invalidFunction2() external { testNumber = 45; }`)
+
+    const report = linter.processStr(code, {
+      extends: 'solhint:recommended',
+      rules: {
+        'compiler-version': 'off',
+        'foundry-test-functions': ['error', ['setUp', 'finish']],
+      },
+    })
+
+    assertErrorCount(report, 2)
+    assert.equal(
+      report.reports[0].message,
+      `Function invalidFunction1() must match Foundry test naming convention`
+    )
+    assert.equal(
+      report.reports[1].message,
+      'Function invalidFunction2() must match Foundry test naming convention'
+    )
+  })
+
+  it(`should NOT raise error only for setUp when rule is just on 'error'`, () => {
+    const code = contractWith(`
+      function setUp() public { testNumber = 42; }
+      function finish() public { testNumber = 43; }
+      function invalidFunction1() external { testNumber = 44; }
+      function invalidFunction2() external { testNumber = 45; }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'foundry-test-functions': 'error' },
+    })
+
+    assertErrorCount(report, 3)
+    assert.equal(
+      report.reports[0].message,
+      'Function finish() must match Foundry test naming convention'
+    )
+    assert.equal(
+      report.reports[1].message,
+      `Function invalidFunction1() must match Foundry test naming convention`
+    )
+    assert.equal(
+      report.reports[2].message,
+      'Function invalidFunction2() must match Foundry test naming convention'
+    )
+  })
+
+  it(`should raise error for all functions when rule SKIP array is empty`, () => {
+    const code = contractWith(`
+      function setUp() public { testNumber = 42; }
+      function finish() public { testNumber = 43; }
+      function invalidFunction() external { testNumber = 44; }`)
+
+    const report = linter.processStr(code, {
+      rules: { 'foundry-test-functions': ['error', []] },
+    })
+
+    assertErrorCount(report, 3)
+    assert.equal(
+      report.reports[0].message,
+      'Function setUp() must match Foundry test naming convention'
+    )
+    assert.equal(
+      report.reports[1].message,
+      `Function finish() must match Foundry test naming convention`
+    )
+    assert.equal(
+      report.reports[2].message,
+      'Function invalidFunction() must match Foundry test naming convention'
+    )
+  })
+})
diff --git a/test/rules/naming/func-named-parameters.js b/test/rules/naming/func-named-parameters.js
index 9fe9056..9591e43 100644
--- a/test/rules/naming/func-named-parameters.js
+++ b/test/rules/naming/func-named-parameters.js
@@ -11,33 +11,37 @@ const {
   FUNCTION_CALLS_OK,
 } = require('../../fixtures/naming/func-named-parameters')
 
+const DEFAULT_MIN_UNNAMED_ARGUMENTS = 4
+
 describe('Linter - func-named-parameters', () => {
   for (const key in FUNCTION_CALLS_ERRORS) {
     it(`should raise error for FUNCTION_CALLS_ERRORS [${key}]`, () => {
-      const { code, maxUnnamed } = FUNCTION_CALLS_ERRORS[key]
+      const { code, minUnnamed } = FUNCTION_CALLS_ERRORS[key]
 
       const sourceCode = contractWith('function callerFunction() public { ' + code + ' }')
 
       const report = linter.processStr(sourceCode, {
-        rules: { 'func-named-parameters': ['error', maxUnnamed] },
+        rules: { 'func-named-parameters': ['error', minUnnamed] },
       })
 
       assertErrorCount(report, 1)
       assertErrorMessage(
         report,
-        `Missing named parameters. Max unnamed parameters value is ${maxUnnamed}`
+        `Named parameters missing. MIN unnamed argumenst is ${
+          minUnnamed < DEFAULT_MIN_UNNAMED_ARGUMENTS ? DEFAULT_MIN_UNNAMED_ARGUMENTS : minUnnamed
+        }`
       )
     })
   }
 
   for (const key in FUNCTION_CALLS_OK) {
     it(`should NOT raise error for FUNCTION_CALLS_OK [${key}]`, () => {
-      const { code, maxUnnamed } = FUNCTION_CALLS_OK[key]
+      const { code, minUnnamed } = FUNCTION_CALLS_OK[key]
 
       const sourceCode = contractWith('function callerFunction() public { ' + code + ' }')
 
       const report = linter.processStr(sourceCode, {
-        rules: { 'func-named-parameters': ['error', maxUnnamed] },
+        rules: { 'func-named-parameters': ['error', minUnnamed] },
       })
 
       assertNoErrors(report)
@@ -46,7 +50,7 @@ describe('Linter - func-named-parameters', () => {
 
   it('should NOT raise error when default rules are configured', () => {
     const code = contractWith(
-      `function callerFunction() public { funcName(sender, amount, receiver); }`
+      `function callerFunction() public { funcName(sender, amount, receiver, token1, token2); }`
     )
     const report = linter.processStr(code, {
       extends: 'solhint:default',
@@ -56,22 +60,39 @@ describe('Linter - func-named-parameters', () => {
     assertNoErrors(report)
   })
 
-  it('should raise error when recommended rules are configured', () => {
+  it('should NOT raise error when recommended rules are configured', () => {
     const code = contractWith(
-      `function callerFunction() public { funcName(sender, amount, receiver); }`
+      `function callerFunction() public { funcName(sender, amount, receiver, token1, token2); }`
     )
     const report = linter.processStr(code, {
       extends: 'solhint:recommended',
       rules: { 'compiler-version': 'off' },
     })
 
+    assertNoErrors(report)
+  })
+
+  it('should raise warning when all rules are configured (no min value)', () => {
+    const code = contractWith(
+      `function callerFunction() public { funcName(sender, amount, receiver, token1, token2, token3); }`
+    )
+
+    const report = linter.processStr(code, {
+      extends: 'solhint:all',
+      rules: { 'compiler-version': 'off', 'comprehensive-interface': 'off' },
+    })
+
     assertWarnsCount(report, 1)
-    assertErrorMessage(report, `Missing named parameters. Max unnamed parameters value is 2`)
+
+    assertErrorMessage(
+      report,
+      `Named parameters missing. MIN unnamed argumenst is ${DEFAULT_MIN_UNNAMED_ARGUMENTS}`
+    )
   })
 
-  it('should raise error when rule has no maxUnnamed arguments is set and default value takes over', () => {
+  it('should raise error when rule has no minUnnamed arguments is set and default value takes over', () => {
     const code = contractWith(
-      `function callerFunction() public { funcName(sender, amount, receiver); }`
+      `function callerFunction() public { funcName(sender, amount, receiver, token1, token2, token3); }`
     )
     const report = linter.processStr(code, {
       rules: { 'func-named-parameters': 'error' },
@@ -79,7 +100,9 @@ describe('Linter - func-named-parameters', () => {
 
     assertErrorCount(report, 1)
 
-    // default value is 2 for this rule
-    assertErrorMessage(report, `Missing named parameters. Max unnamed parameters value is 2`)
+    assertErrorMessage(
+      report,
+      `Named parameters missing. MIN unnamed argumenst is ${DEFAULT_MIN_UNNAMED_ARGUMENTS}`
+    )
   })
 })
diff --git a/test/rules/naming/named-return-values.js b/test/rules/naming/named-return-values.js
new file mode 100644
index 0000000..b93d134
--- /dev/null
+++ b/test/rules/naming/named-return-values.js
@@ -0,0 +1,92 @@
+const assert = require('assert')
+const linter = require('../../../lib/index')
+const contractWith = require('../../common/contract-builder').contractWith
+const { assertErrorCount, assertNoErrors, assertWarnsCount } = require('../../common/asserts')
+
+describe('Linter - named-return-values', () => {
+  it('should NOT raise error for named return values', () => {
+    const code = contractWith(
+      `function getBalanceFromTokens(address wallet) public returns(address token1, address token2, uint256 balance1, uint256 balance2) { balance = 1; }`
+    )
+    const report = linter.processStr(code, {
+      rules: { 'named-return-values': 'error' },
+    })
+    assertNoErrors(report)
+  })
+
+  it('should raise error for unnamed return values', () => {
+    const code = contractWith(
+      `function getBalanceFromTokens(address wallet) public returns(address, address, uint256, uint256) { balance = 1; }`
+    )
+    const report = linter.processStr(code, {
+      rules: { 'named-return-values': 'error' },
+    })
+
+    assertErrorCount(report, 4)
+    for (let index = 0; index < report.reports.length; index++) {
+      assert.equal(report.reports[index].message, `Named return value is missing - Index ${index}`)
+    }
+  })
+
+  it('should NOT raise error for functions without return values', () => {
+    const code = contractWith(`function writeOnStorage(address wallet) public { balance = 1; }`)
+    const report = linter.processStr(code, {
+      rules: { 'named-return-values': 'error' },
+    })
+    assertNoErrors(report)
+  })
+
+  it('should raise error for 2 unnamed return values', () => {
+    const code = contractWith(
+      `function getBalanceFromTokens(address wallet) public returns(address user, address, uint256 amount, uint256) { balance = 1; }`
+    )
+    const report = linter.processStr(code, {
+      rules: { 'named-return-values': 'error' },
+    })
+
+    assertErrorCount(report, 2)
+    assert.equal(report.reports[0].message, `Named return value is missing - Index 1`)
+    assert.equal(report.reports[1].message, `Named return value is missing - Index 3`)
+  })
+
+  it('should NOT raise error for solhint:recommended setup', () => {
+    const code = contractWith(
+      `function getBalanceFromTokens(address wallet) public returns(address, address, uint256, uint256) { balance = 1; }`
+    )
+
+    const report = linter.processStr(code, {
+      extends: 'solhint:recommended',
+      rules: { 'compiler-version': 'off' },
+    })
+
+    assertNoErrors(report)
+  })
+
+  it('should NOT raise error for solhint:default setup', () => {
+    const code = contractWith(
+      `function getBalance(address wallet) public returns(uint256) { balance = 1; }`
+    )
+
+    const report = linter.processStr(code, {
+      extends: 'solhint:default',
+    })
+
+    assertNoErrors(report)
+  })
+
+  it('should raise error for solhint:all setup', () => {
+    const code = contractWith(
+      `function getBalance(uint256 wallet) public override returns(uint256, address) { wallet = 1; }`
+    )
+
+    const report = linter.processStr(code, {
+      extends: 'solhint:all',
+      rules: { 'compiler-version': 'off' },
+    })
+
+    assertWarnsCount(report, 2)
+    for (let index = 0; index < report.reports.length; index++) {
+      assert.equal(report.reports[index].message, `Named return value is missing - Index ${index}`)
+    }
+  })
+})
diff --git a/test/rules/order/ordering.js b/test/rules/order/ordering.js
index d83d73f..1ff356e 100644
--- a/test/rules/order/ordering.js
+++ b/test/rules/order/ordering.js
@@ -427,4 +427,63 @@ describe('Linter - ordering', () => {
 
     assert.equal(report.errorCount, 0)
   })
+
+  it('should raise error when INITIALIZER is NOT well located', () => {
+    const code = `
+      // SPDX-License-Identifier: MIT
+      pragma solidity ^0.8.0;
+      import "@openzeppelin/contracts/ownership/Ownable.sol";
+      uint256 constant oneNiceConstant = 1;
+      struct OneNiceStruct { uint256 a; uint256 b; }            
+      enum MyEnum { A, B }
+      error Unauthorized();
+      function freeFunction() pure returns (uint256) {
+        return 1;
+      }     
+      contract OneNiceContract {
+        function initialize() initializer {
+          oneNiceConstant;
+        }
+        struct OneNiceStruct { uint256 a; uint256 b; }            
+      }
+    `
+
+    const report = linter.processStr(code, {
+      rules: { ordering: 'error' },
+    })
+
+    assert.equal(report.errorCount, 1)
+    assert.ok(
+      report.messages[0].message.includes(
+        'Function order is incorrect, struct definition can not go after constructor/initializer'
+      )
+    )
+  })
+
+  it('should NOT raise error when INITIALIZER is well located', () => {
+    const code = `
+      // SPDX-License-Identifier: MIT
+      pragma solidity ^0.8.0;
+      import "@openzeppelin/contracts/ownership/Ownable.sol";
+      uint256 constant oneNiceConstant = 1;
+      enum MyEnum { A, B }
+      struct OneNiceStruct { uint256 a; uint256 b; }            
+      error Unauthorized();
+            function freeFunction() pure returns (uint256) {
+        return 1;
+      }     
+      contract OneNiceContract {
+        struct OneNiceStruct { uint256 a; uint256 b; }            
+        function initialize() initializer {
+          oneNiceConstant;
+        }
+      }
+    `
+
+    const report = linter.processStr(code, {
+      rules: { ordering: 'error' },
+    })
+
+    assert.equal(report.errorCount, 0)
+  })
 })
diff --git a/test/rules/security/check-send-result.js b/test/rules/security/check-send-result.js
index c2d75d8..69f0875 100644
--- a/test/rules/security/check-send-result.js
+++ b/test/rules/security/check-send-result.js
@@ -4,7 +4,7 @@ const funcWith = require('../../common/contract-builder').funcWith
 
 describe('Linter - check-send-result', () => {
   it('should return "send" call verification error', () => {
-    const code = funcWith(require('../../fixtures/security/send-result-ignored'))
+    const code = funcWith('x.send(55);')
 
     const report = linter.processStr(code, {
       rules: { 'check-send-result': 'error' },
@@ -15,7 +15,7 @@ describe('Linter - check-send-result', () => {
   })
 
   it('should not return "send" call verification error', () => {
-    const code = funcWith(require('../../fixtures/security/send-result-checked'))
+    const code = funcWith('if(x.send(55)) {}')
 
     const report = linter.processStr(code, {
       rules: { 'check-send-result': 'error' },
@@ -73,4 +73,14 @@ describe('Linter - check-send-result', () => {
 
     assert.equal(report.errorCount, 1)
   })
+
+  it('should not emit error when the send() is used for an ERC777', () => {
+    const code = funcWith('erc777.send(recipient, amount, "");')
+
+    const report = linter.processStr(code, {
+      rules: { 'check-send-result': 'error' },
+    })
+
+    assert.equal(report.errorCount, 0)
+  })
 })
diff --git a/test/rules/security/compiler-version.js b/test/rules/security/compiler-version.js
index 3f18d6f..b3c51fe 100644
--- a/test/rules/security/compiler-version.js
+++ b/test/rules/security/compiler-version.js
@@ -2,6 +2,8 @@ const assert = require('assert')
 const { assertNoErrors, assertErrorCount, assertErrorMessage } = require('../../common/asserts')
 const linter = require('../../../lib/index')
 
+const DEFAULT_SEMVER = '^0.8.0'
+
 describe('Linter - compiler-version', () => {
   it('should disable only one compiler error on next line', () => {
     const report = linter.processStr(
@@ -11,7 +13,7 @@ describe('Linter - compiler-version', () => {
                 pragma solidity 0.3.4;
             `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
 
@@ -26,7 +28,7 @@ describe('Linter - compiler-version', () => {
               pragma solidity 0.3.4;
           `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
 
@@ -41,7 +43,7 @@ describe('Linter - compiler-version', () => {
                 pragma solidity 0.3.4;
             `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
 
@@ -56,7 +58,7 @@ describe('Linter - compiler-version', () => {
                 pragma solidity 0.3.4;
             `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
 
@@ -72,12 +74,12 @@ describe('Linter - compiler-version', () => {
                 pragma solidity 0.3.4;
             `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
 
     assertErrorCount(report, 1)
-    assertErrorMessage(report, '0.5.2')
+    assertErrorMessage(report, DEFAULT_SEMVER)
   })
 
   it('should disable all errors', () => {
@@ -88,7 +90,7 @@ describe('Linter - compiler-version', () => {
                 pragma solidity 0.3.4;
             `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
     assertNoErrors(report)
@@ -103,58 +105,58 @@ describe('Linter - compiler-version', () => {
                 pragma solidity ^0.4.4;
             `,
       {
-        rules: { 'compiler-version': ['error', '^0.5.2'] },
+        rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
       }
     )
 
     assertErrorCount(report, 1)
-    assertErrorMessage(report, '0.5.2')
+    assertErrorMessage(report, DEFAULT_SEMVER)
   })
 
   it('should return compiler version error', () => {
     const report = linter.processStr('pragma solidity 0.3.4;', {
-      rules: { 'compiler-version': ['error', '^0.5.2'] },
+      rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
     })
 
     assert.equal(report.errorCount, 1)
-    assert.ok(report.reports[0].message.includes('0.5.2'))
+    assert.ok(report.reports[0].message.includes(DEFAULT_SEMVER))
   })
 
   it('should not report compiler version error on exact match', () => {
-    const report = linter.processStr('pragma solidity 0.5.2;', {
-      rules: { 'compiler-version': ['error', '0.5.2'] },
+    const report = linter.processStr('pragma solidity 0.8.0;', {
+      rules: { 'compiler-version': ['error', '0.8.0'] },
     })
 
     assert.equal(report.errorCount, 0)
   })
 
   it('should not report compiler version error on range match', () => {
-    const report = linter.processStr('pragma solidity ^0.5.2;', {
-      rules: { 'compiler-version': ['error', '^0.5.2'] },
+    const report = linter.processStr('pragma solidity ^0.8.0;', {
+      rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
     })
 
     assert.equal(report.errorCount, 0)
   })
 
   it('should not report compiler version error on patch bump', () => {
-    const report = linter.processStr('pragma solidity 0.5.3;', {
-      rules: { 'compiler-version': ['error', '^0.5.2'] },
+    const report = linter.processStr('pragma solidity 0.8.1;', {
+      rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
     })
 
     assert.equal(report.errorCount, 0)
   })
 
   it('should not report compiler version error on range match', () => {
-    const report = linter.processStr('pragma solidity ^0.5.3;', {
-      rules: { 'compiler-version': ['error', '^0.5.2'] },
+    const report = linter.processStr('pragma solidity ^0.8.2;', {
+      rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
     })
 
     assert.equal(report.errorCount, 0)
   })
 
   it('should report compiler version error on range not matching', () => {
-    const report = linter.processStr('pragma solidity ^0.5.2;', {
-      rules: { 'compiler-version': ['error', '^0.5.3'] },
+    const report = linter.processStr('pragma solidity ^0.8.1;', {
+      rules: { 'compiler-version': ['error', '^0.8.3'] },
     })
 
     assert.equal(report.errorCount, 1)
@@ -162,7 +164,7 @@ describe('Linter - compiler-version', () => {
 
   it('should report compiler version error on minor bump', () => {
     const report = linter.processStr('pragma solidity 0.6.0;', {
-      rules: { 'compiler-version': ['error', '^0.5.2'] },
+      rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
     })
 
     assert.equal(report.errorCount, 1)
@@ -170,7 +172,7 @@ describe('Linter - compiler-version', () => {
 
   it(`should report compiler version error if pragma doesn't exist`, () => {
     const report = linter.processStr('contract Foo {}', {
-      rules: { 'compiler-version': ['error', '^0.5.2'] },
+      rules: { 'compiler-version': ['error', DEFAULT_SEMVER] },
     })
 
     assert.equal(report.errorCount, 1)
@@ -178,10 +180,10 @@ describe('Linter - compiler-version', () => {
 
   it(`should not report compiler version error if pragma exist`, () => {
     const report = linter.processStr(
-      `pragma solidity 0.6.0;
+      `pragma solidity 0.8.2;
       contract Foo {}`,
       {
-        rules: { 'compiler-version': ['error', '^0.6.0'] },
+        rules: { 'compiler-version': ['error', '^0.8.2'] },
       }
     )
 
@@ -202,4 +204,62 @@ describe('Linter - compiler-version', () => {
 
     assert.equal(report.errorCount, 0)
   })
+
+  it(`should not report compiler version error using default and correct pragma`, () => {
+    const report = linter.processStr(
+      `pragma solidity ^0.8.1;
+       pragma experimental ABIEncoderV2;
+       
+       contract Main {
+       }`,
+      {
+        rules: { 'compiler-version': 'error' },
+      }
+    )
+
+    assert.equal(report.errorCount, 0)
+  })
+
+  it(`should report compiler version error using default and lower pragma`, () => {
+    const report = linter.processStr(
+      `pragma solidity ^0.7.4;
+       
+       contract Main {
+       }`,
+      {
+        rules: { 'compiler-version': 'error' },
+      }
+    )
+
+    assert.equal(report.errorCount, 1)
+    assertErrorMessage(report, DEFAULT_SEMVER)
+  })
+
+  it(`should not report compiler version error using >= and default and correct pragma`, () => {
+    const report = linter.processStr(
+      `pragma solidity >=0.8.0;
+       
+       contract Main {
+       }`,
+      {
+        rules: { 'compiler-version': 'error' },
+      }
+    )
+
+    assert.equal(report.errorCount, 0)
+  })
+
+  it(`should report compiler version error using >= and default and lower pragma`, () => {
+    const report = linter.processStr(
+      `pragma solidity >=0.7.4;
+       
+       contract Main {
+       }`,
+      {
+        rules: { 'compiler-version': 'error' },
+      }
+    )
+    assert.equal(report.errorCount, 1)
+    assertErrorMessage(report, DEFAULT_SEMVER)
+  })
 })