npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@morenabarboni/sumo

v3.2.1

Published

A mutation testing tool for Ethereum smart contracts

Downloads

322

Readme

SuMo

SuMo is a mutation testing tool for Solidity Smart Contracts.

SuMo was designed to run mutation testing on Solidity projects in a NodeJS environment. It can run test using Hardhat, Brownie and Forge, hybrid test suites, and custom test scripts.

Table of Contents

Installation

To install sumo run npm install @morenabarboni/sumo

Configuration ⚙️

Before using SuMo you must specify your desired configuration in a sumo-config.js in the root directory of your project. The sumo-config.js is automatically generated when SuMo is installed.

Here's a simple example of sumo-config.js:

module.exports = {  
      buildDir: "auto",                               //build directory of the SUT (auto detect)
      contractsDir: "auto",                           //contract directory of the SUT (auto detect)
      testDir: "auto",                                //test directory of the SUT (auto detect)
      skipContracts: ["interfaces", "mock", "test"],  // Relative paths from contractsDir
      skipTests: [],                                  // Relative paths from testsDir
      testingFramework: "auto",                      //testing framework (auto detect)
      minimalOperators: false,                       // use minimal mutation rules
      randomSampling: false,                         //use random mutant sampling
      randomMutants: 100,                            //if random sampling is enabled, generate 100 mutants max
      testingTimeOutInSec: 500                       //testing time-out for a mutant
}

1) SUT directories

SuMo will try to automatically find your project directories based on standard naming conventions (e.g., /contracts and /test). These can be overriden in the sumo-config.js file. Contracts and test files/folders to be ignored by SuMo can be specified as well.

| Field | Description | Default Value | | ------ | ------ | :----: | | contractsDir| relative path to the directory of the contracts to be mutated | auto | | testDir| relative path to the directory of the tests to be evaluated | auto | | buildDir| relative path to the directory of the compilation artifacts | auto |
| skipContracts| blacklist of relative paths to contract files (or folders) | ["interfaces", "mock", "test"] | | skipTests| blacklist of relative paths to test files (or folders) | [] |

2) Testing Frameworks Configuration 🔗

These fields allow to customize the testing frameworks used by SuMo.

By default, testingFramework is set to auto: SuMo will automatically select the testing framework(s) to be used based on the configuration files (e.g., foundry.toml) present in your workspace. If multiple configuration files are found, SuMo will try to run a hybrid testing process.

| Field | Description | Available Options | Default Value | | ------ | ------ | ------ | :----: | | testingFramework| the testing framework to be used for compiling and testing the smart contracts | auto, brownie, forge, hardhat, custom | auto |

Brownie

When choosing brownie:

  • SuMo will rely on a local/global brownie installation;
  • The smart contracts will be compiled with a minimal compile command (e.g., brownie compile );
  • The smart contracts will be tested with a minimal test command and (optionally) by a list of test files to be executed (e.g., brownie test ...testFiles --exitfirst) .

Forge

When choosing forge :

  • SuMo will rely on the global installation of foundry;
  • The smart contracts will be compiled with a minimal compile command (e.g., forge build);
  • The smart contracts will be tested with a minimal test command and (optionally) by a list of test files to be executed (e.g., forge test ...testFiles --fail-fast).
  • Make sure that your forge installation is up-to-date to enable --fail-fast.

Custom

If you set testingFramework to custom, SuMo will invoke the compile and test script defined in your package.json. This allows you to customize both scripts and have more control over the testing process. For example, you can define the scripts as follows:

//package.json
 scripts: {
    compile: "hardhat compile",
    test "hardhat test --bail && forge test --fail-fast"
 }

//sumo-config.js
 project: {
    buildDir: "artifacts",
 }

Additionally, you must also explicitly define a buildDir (matching your compile command) in your sumo-config.js.

⚠️ Limitations of Custom Test Scripts:
     * buildDir: must be explicitly specified it in the sumo-config.js
     * skipTests: will be ignored. You have to specify them in your custom script.

3) Mutation Testing Process Configuration

These fields allow you to further customize the mutation testing process:

| Field | Description | Default Value | | ------ | ------ | :----: | | minimalOperators| use minimal mutation rules | false | | randomSampling| use Random Mutant Sampling | false |
| randomMutants| the maximum number of mutants to be tested (only if randomSampling is enabled) | 100 |
| testingTimeOutInSec| seconds after which a mutant is marked as timed-out during testing | 500 |

CLI Usage

Selecting the Mutation Operators

Before starting the mutation process you can choose which mutation operators to use:

| Command | Description | Usage | Example | |---------------|------------------------------------|--------------------------|-------------------------------------| | list | Shows the enabled mutation operators. | npx/yarn sumo list | $ npx sumo list | | enable | Enables one or more mutation operators. If no operator IDs are specified, all of them are enabled. | npx/yarn sumo enable [...ID] | $ npx sumo enable $ npx sumo enable AOR BOR | | disable | Disables one or more mutation operators. If no operator IDs are specified, all of them are disabled. | npx/yarn sumo disable [...ID] | $ npx sumo disable $ npx sumo disable FVR |

Viewing the available mutations

| Command | Description | Usage | Example | |---------------|------------------------------------|--------------------------|-------------------------------------| | lookup | Generates the mutations and creates reports without starting mutation testing. | npx/yarn sumo lookup | $ npx sumo lookup | | mutate | Generates the mutations and saves a copy of each .sol mutant to to ./sumo/mutants. | npx/yarn sumo mutate | $ npx sumo mutate |

Running Mutation Testing

| Command | Description | Usage | Example | |---------------|------------------------------------|--------------------------|-------------------------------------| | pretest | Runs the test suite on the original smart contracts to check if all tests pass and can be successfully evaluated. Pretest is automatically run when sumo test is executed. | npx/yarn sumo pretest | $ npx sumo pretest | | test | Starts the mutation testing process. You can also choose a single mutant / an interval of mutants to be tested by sepcifying <startHash> and (optionally) <endHash>.| npx/yarn sumo test <startHash> <endHash> | $ npx sumo test $ npx sumo test mbc5e8f56 mbg5t86o6| | restore | Restores the SUT files to a clean version. This should be executed if you suddenly interrupt the mutation process. Note that the restore command overwrites your codebase with the files stored in the sumo/baseline folder. If you need to restore the project files, make sure to do so before performing other operations as the baseline is automatically refreshed on subsequent preflight or test runs.| $ npx/yarn sumo restore | $ npx sumo restore|

Viewing the results

SuMo automatically creates a sumo\results folder in the root directory of the project with the following reports:

  • mutations.json: List of mutations in json format, synchronoysly updated during testing.
  • index.html: A simple web display of the results (you can view this using VSCode extensions like Live Server). From here, you can also download a csv with the results.
  • \mutants: Folder with mutated .sol source files (only if generated with sumo mutate)

Mutation Operators 👾

SuMo includes the following Traditional and Solidity-specific operators. Note that not all mutation operators are enabled by default.

Traditional Mutation Operators

| Operator | Name | Mutation Example | Enabled by Default | Minimal Available | | ------ | ------ | ------ | ------ | :----: | | ACM| Argument Change of overloaded Method call | overloadedFunc(a,b);overloadedFunc(a,b,c); | Y | N | | AOR | Assignment Operator Replacement | += = | Y | N | | BCRD | Break and Continue Replacement and Deletion | break continuebreak | Y | N | | BLR | Boolean Literal Replacement | truefalse | Y | N | | BOR | Binary Operator Replacement | +- <>= | Y | Y | | CBD | Catch Block Deletion | catch{} | Y | N | | CSC | Conditional Statement Change | if(condition)if(false) else{} | Y | N | | ER | Enum Replacemet | enum.member1enum.member2 | Y | Y | | ECS | Explicit Conversion to Smaller type | uint256uint8 | Y | N | | FCD | Function Call Deletion | foo() | Y | N | | HLR | Hexadecimal Literal Replacement | hex\"01\"hex\"random\"| Y | N | | ILR | Integer Literal Replacement | 10 | Y | N | | LCS | Loop Statement Change | while(condition)while(false) | Y | N | | OLFD | Overloaded Function Deletion | function overloadedF(){} | Y | N | | ORFD | Overridden Function Deletion | function f() override {} | Y | N | | SKR | Super Keyword Replacement | x = getData()x = super.getData() | Y | N | | SLR | String Literal Replacement | "string""" | Y | N | | UORD | Unary Operator Replacement and Deletion | ++-- ! | Y | Y |

Solidity Mutation Operators

| Operator | Name | Mutation Example |Enabled by Default | Minimal version available | | ------ | ------ | ------ | ------ | :----: | | AVR | Address Value Replacement | 0x67ED2e5dD3d0... address.this()| Y | Y | | CCD | Contract Constructor Deletion | constructor(){} | Y | N | | DLR | Data Location Keyword Replacement | memorystorage | N | N | | DOD | Delete Operator Deletion | delete → | Y | N | | ETR | Ether Transfer function Replacement | delegatecall()call() | Y | Y | | EED | Event Emission Deletion | emit Deposit(...)/*emit Deposit(...)*/ | Y | N | | EHD | Exception Handling Deletion | require(...)/*require(...)*/ | Y | N | | FVR | Function Visibility Replacement | function f() publicfunction f() private | N | Y | | GVR | Global Variable Replacement | msg.value()tx.gasprice() | Y | Y | | MCR | Mathematical and Cryptographic function Replacement | addmodmulmod keccak256sha256 | Y | Y | | MOD | Modifier Deletion | function f() onlyOwnerfunction f() | Y | Y | | MOI | Modifier Insertion | function f()function f() onlyOwner | N | Y | | OMD | Overridden Modifier Deletion | modifier m() override {} | Y | N | | PKD | Payable Keyword Deletion | function f() payablefunction f() | Y | N | | RSD | Return Statement Deletion | return amount;//return amount; | Y | N | | RVS | Return Values Swap | return (1, "msg", 100);return (100, "msg", 1); | Y | Y | | SCD | Selfdestruct Call Deletion | selfdestruct();//selfdestruct(); | Y | N | | SFR | SafeMath Function Replacement | SafeMath.addSafeMath.sub | Y | Y | | SCEC | Switch Call Expression Casting | Contract c = Contract(0x86C9...);Contract c = Contract(0x67ED...); | Y | N | | TOR | Transaction Origin Replacement | msg.sendertx.origin | Y | N | | VUR | Variable Unit Replacement | weiether minuteshours | Y | Y | | VVR | Variable Visibility Replacement | uint private data;uint public data; | N | Y |

Minimal Mutation Rules

Some mutation operators foresee a minimal version:

  • The extended operators generate a more comprehensive set of mutants. These guarantee a more in-depth test adequacy assessment, but they can generate more than one replacement per target (e.g., + is mutated in both - and *), which can lead to longer execution times.
  • The minimal operators define simplified rules that only inject one replacement per target (e.g., + is mutated in -), limiting the generation of subsumed mutants and speeding up the testing process.

By default, SuMo employs the extended operators. However, you can enable the minimal rules in the sumo-config.js file.

Publications

To cite SuMo, please use the following:

@article{BARBONI2022111445,
  title = {SuMo: A mutation testing approach and tool for the Ethereum blockchain},
  journal = {Journal of Systems and Software},
  volume = {193},
  pages = {111445},
  year = {2022},
  issn = {0164-1212},
  doi = {https://doi.org/10.1016/j.jss.2022.111445},
  author = {Morena Barboni and Andrea Morichetta and Andrea Polini}
}