/DeepMutate

A Language/Platform agnostic Mutation & Analysis Language.

Primary LanguageJavaMIT LicenseMIT

DeepMutate

A Language/Platform agnostic Mutation & Analysis Language.

Useful for:

  • Mutation Analysis
  • Generating synthetic code data for DeepLearning models etc
  • Analyzing interesting code points

Setup

    git clone https://github.com/talalzone/DeepMutate
    ./gradlew clean shadowJar

Requirements

  • Java 17+

Quickstart

    from (dir='/path/to/java-project')
    mutate(lang='java', type='semantic', analyze='true')
    out(store='mongodb', report='html') {
        
        def mutators {
    
            [method_call_returns_int][active='true']
            match:  'int i = someNonVoidMethod();'
            set:    'int i = 0;'
    
            [method_call_returns_obj][active='true']
            match:  'Object o = someNonVoidMethod();'
            set:    'Object o = null;'
    
            [method_call_only][active='false']
            match:  'someVoidMethodCall()'
            set:    'NO_OP'
    
            [binaryop_switch][active='false']
            match:  'if (a == b)'
            set:    'if (a != b)'
        
        }

    }

To run sample.dm (containing above code)

    java -jar deep-mutate-<version>.jar --run sample.dm   

See all CLI commands:

    java -jar deep-mutate-<version>.jar --help

Reports are generated under directory:

    deep-mutate-report

Specifications

Project Declaration(s)

DeepMutate consists of one or more Project Declarations.

A Project Declaration consists of FROM, MUTATE and OUTPUT statements.

This is followed by one or more Mutation Functions containing one or more Mutation Statements (clauses).

FROM STATEMENT

Read from project directory(s):

    // Single project directory
    FROM (dir='/path/to/project-dir', build='gradle') 

    // Multiple project directories
    FROM (dir=['/path/to/project-1', '/path/to/project-2'], build_system='maven']

Read from code file(s):

    // Read single file
    FROM ( file='/path/to/ClassA.java' )
    
    // Read multiple files
    FROM ( files=['/path/to/ClassA.java', '/path/to/ClassB.java'] )'   
    

Read from inline code:

    FROM (code='ClassA { void someMethod() { /* some code etc */ } }'

Read from console:

    FROM (console)

NOTE: build or build_system need to be set for mutation analysis (i.e., when analyze='true')

ATTRIBUTES SUMMARY
Type Values
DIR Dir path(s) e.g., 'java/project' or ['java/project-1', 'java/project-2']
FILE File path(s) e.g., 'ClassA.java' or ['ClassA.java', 'ClassB.java']
CODE Any syntactically correct code e.g., 'AnyClassA { void anyMethod() {/* method body */} }
CONSOLE Read input from console
BUILD or BUILD_SYSTEM Build System to use. Available: Maven, Gradle

MUTATE STATEMENT

    MUTATE (lang='java', type='semantic', analyze='true')
ATTRIBUTES SUMMARY
Type Values Default
LANG or LANGUAGE 'java', 'python' etc Not set
TYPE 'semantic' or 'syntactic' 'semantic'
ANALYZE 'true' or 'false' 'false'

OUTPUT STATEMENT

Sending mutations out to a datastore (e.g., MongoDB):

    // Connects to default mongodb local instance
    OUT (store='mongodb', report='true')
    
    // Same statement but a bit verbose
    OUTPUT (datastore='mongodb', report='html')
ATTRIBUTES SUMMARY
Type Values Default
STORE or DATASTORE 'mongodb', 'arangodb', 'csv', 'cache' Not set
URI 'mongodb://...', 'arangodb://' Not set
REPORT 'csv', 'console', html', 'true', 'false' 'false'
DB or DATABASE 'any_database_name' 'deepmutate'
COL or COLLECTION 'any_collection_or_table_name' 'mutations'
ANALYZE 'true' or 'false' 'false'

MUTATION FUNCTIONS

Mutation functions groups together different mutator statements.

    def <some_mutation_function_identifier> {
    
        /*
            match:  '<pattern>'
            set:    '<update>'
            
            match:  '<pattern>'
            set:    '<update>'
        */
    }

    def <another_mutation_function_identifier> {
    
        /*
            match:  '<pattern>'
            where:  '<filter>'
            set:    '<update>'
            
            match:  '<pattern>'
            where:  '<filter>'
            set:    '<update>'
        */
    }

MUTATION STATEMENTS

A mutation statement consists of MATCH, WHERE and SET clauses.

    ['optional_mutation_identifier'][<optional configurations e.g., active='true'>]
    match:  'return x;' // Pattern in code to match
    
    // Any filter clause
    where:  'x is java.util.Optional'
    
    // Changes to be applied to the matched pattern
    set:    'return Optional.empty()'

MATCH should have a syntactically correct expression, conditional, declaration etc.

DeepMutate checks for lexical type match in the sourcecode Abstract Syntax Tree (AST). The 'match' context is replaced by the 'set' context in the AST.

The variable names are kept as is.

ATTRIBUTES SUMMARY
Type Values Optional Default
IDENTIFIER 'any_string_identifier' without spaces Yes auto-generated
ACTIVE 'true' or 'false' Yes 'true'

COMMENTS

Comments can appear any where in the DeepMutate code.

Inline comments:

    // This is an inline comments

Block comments:

    /*
         This is a block comment
    */

Features

Extensible Architecture

  • Further languages can be added
  • Support for Semantic & Syntactic mutations
  • Support for Multi-model DBMS: SQL, NoSQL and Graph
  • Generates mutations with several accessible data points:
    • Source code
    • Mutated code
    • Mutation patterns
    • Stack traces

Languages

  • Java
  • Future: Python, Javascript, Golang etc

Build Systems

  • Gradle
  • Maven

Datastores

  • MongoDB
  • ArangoDB
  • CSV

Reports

  • HTML
  • CSV
  • Console

License

This project is licensed under the MIT License