Giter Club home page Giter Club logo

weapon-regex's Introduction

Mutation testing badge Build Status GitHub Pages

Weapon regeX Logo

Weapon regeX

Weapon regeX mutates regular expressions for use in mutation testing. It has been designed from the ground up to support Stryker Mutator. Weapon regeX is available for both JavaScript and Scala and is used in Stryker4s and StrykerJS flavors of Stryker. The JavaScript version of the library is generated from Scala using Scala.js. The generated mutant regular expressions cover human errors, such as edge cases and typos. A list of provided mutators is given below. For an introduction to mutation testing, see Stryker's website.

The current supported versions for Scala are: 2.12, 2.13 and 3.

Getting started

In case you want to incorporate Weapon-regeX into your project.

Scala

Add Weapon regeX to your build.sbt Maven Central:

libraryDependencies += "io.stryker-mutator" %% "weapon-regex" % weaponRegexVersion

Mutate!

import weaponregex.WeaponRegeX

WeaponRegeX.mutate("^abc(d+|[xyz])$") match {
    case Right(mutants) => mutants map (_.pattern)
    case Left(e)        => throw new RuntimeException(e)
}
// res0: Seq[String] = List(
//   "abc(d+|[xyz])$",
//   "^abc(d+|[xyz])",
//   "\\Aabc(d+|[xyz])$",
//   "^abc(?:d+|[xyz])$",
//   "^abc(d|[xyz])$",
//   "^abc(d{0,}|[xyz])$",
//   "^abc(d{2,}|[xyz])$",
//   "^abc(d{1}|[xyz])$",
//   "^abc(d+?|[xyz])$",
//   "^abc(d+|[^xyz])$",
//   "^abc(d+|[yz])$",
//   "^abc(d+|[xz])$",
//   "^abc(d+|[xy])$",
//   "^abc(d+|[\\w\\W])$",
//   "^abc(d+|[xyz])\\z"
// )

JavaScript

Install Weapon regeX with npm.

npm install weapon-regex

Mutate!

import wrx from 'weapon-regex';

let mutants = wrx.mutate('^abc(d+|[xyz])$');

mutants.forEach((mutant) => {
    console.log(mutant.pattern);
});

Note: as of 1.0.0 weapon-regex uses ES Modules.

Try it!

API

Scala

The mutate function has the following signature:

import weaponregex.model.mutation._
import weaponregex.mutator.BuiltinMutators
import weaponregex.parser.{ParserFlavor, ParserFlavorJVM}

def mutate(
              pattern       : String,
              mutators      : Seq[TokenMutator] = BuiltinMutators.all,
              mutationLevels: Seq[Int] = null,
              flavor        : ParserFlavor = ParserFlavorJVM
          ): Either[String, Seq[Mutant]] = ???

With the mutators argument you can give a select list of mutators that should be used in the mutation process. If omitted, all built-in mutators will be used. This list will be filtered depending on the mutationLevels argument.

A list of mutationLevels can also be passed to the function. The mutators will be filtered based on the levels in the list. If omitted, no filtering takes place.

The flavor argument allows setting the parser flavor that will be used to parse the pattern. Currently, we support a ParserFlavorJVM and ParserFlavorJS. By default in Scala the JVM flavor is used.

This function will return a Right with Seq[Mutant] if it can be parsed, or a Left with the error message otherwise.

JavaScript

The mutate function can be called with regular expression flags and an options object to control which mutators and which parser flavor should be used in the mutation process:

import wrx from 'weapon-regex';

let mutants = wrx.mutate('^abc(d+|[xyz])$', 'u', {
    mutators: Array.from(wrx.mutators.values()),
    mutationLevels: [1, 2, 3],
    flavor: wrx.ParserFlavorJS,
});

Both options can be omitted, and have the same functionality as the options described in the Scala API section. By default in JS the JS parser flavor is used. You can get a map of mutators from the mutators attribute of the library. It is a Map<string, Mutator> from string (mutator name) to a mutator object.

This function will return a JavaScript Array of Mutant if it can be parsed, or throw an exception otherwise.

Supported mutators

All the supported mutators and at which mutation level they appear are shown in the table below.

Name 1 2 3
BOLRemoval
EOLRemoval
BOL2BOI
EOL2EOI
CharClassNegation
CharClassChildRemoval
CharClassAnyChar
CharClassRangeModification
PredefCharClassNegation
PredefCharClassNullification
PredefCharClassAnyChar
UnicodeCharClassNegation
QuantifierRemoval
QuantifierNChange
QuantifierNOrMoreModification
QuantifierNOrMoreChange
QuantifierNMModification
QuantifierShortModification
QuantifierShortChange
QuantifierReluctantAddition
GroupToNCGroup
LookaroundNegation

Boundary Mutators

BOLRemoval

Remove the beginning of line character ^.

Original Mutated
^abc abc

Back to table 🔝

EOLRemoval

Remove the end of line character $.

Original Mutated
abc$ abc

Back to table 🔝

BOL2BOI

Change the beginning of line character ^ to a beginning of input character \A.

Original Mutated
^abc \Aabc

Back to table 🔝

EOL2EOI

Change the end of line character ^ to a end of input character \z.

Original Mutated
abc$ abc\z

Back to table 🔝

Character class mutators

CharClassNegation

Flips the sign of a character class.

Original Mutated
[abc] [^abc]
[^abc] [abc]

Back to table 🔝

CharClassChildRemoval

Remove a child of a character class.

Original Mutated
[abc] [bc]
[abc] [ac]
[abc] [ab]

Back to table 🔝

CharClassAnyChar

Change a character class to a character class which matches any character.

Original Mutated
[abc] [\w\W]

Back to table 🔝

CharClassRangeModification

Change the high and low of a range by one in both directions if possible.

Original Mutated
[b-y] [a-y]
[b-y] [c-y]
[b-y] [b-z]
[b-y] [b-x]

Back to table 🔝

Predefined character class mutators

PredefCharClassNegation

Flips the sign of a predefined character class. All the predefined character classes are shown in the table below.

Original Mutated
\d \D
\D \d
\s \S
\S \s
\w \W
\W \w

Back to table 🔝

PredefCharClassNullification

Remove the backslash from a predefined character class such as \w.

Original Mutated
\d d
\D D
\s s
\S S
\w w
\W W

Back to table 🔝

PredefCharClassAnyChar

Change a predefined character class to a character class containing the predefined one and its negation.

Original Mutated
\d [\d\D]
\D [\D\d]
\s [\s\S]
\S [\S\s]
\w [\w\W]
\W [\W\w]

Back to table 🔝

UnicodeCharClassNegation

Flips the sign of a Unicode character class.

Original Mutated
\p{Alpha} \P{Alpha}
\P{Alpha} \p{Alpha}

Back to table 🔝

Quantifier mutators

QuantifierRemoval

Remove a quantifier. This is done for all possible quantifiers, even ranges, and the reluctant and possessive variants.

Original Mutated
abc? abc
abc* abc
abc+ abc
abc{1,3} abc
abc?? abc
abc*? abc
abc+? abc
abc{1,3}? abc
abc?+ abc
abc*+ abc
abc++ abc
abc{1,3}+ abc

Back to table 🔝

QuantifierNChange

Change the fixed amount quantifier to a couple of range variants.

Original Mutated
abc{9} abc{0,9}
abc{9} abc{9,}

Back to table 🔝

QuantifierNOrMoreModification

Change the n to infinity range quantifier to a couple of variants where the low of the range is incremented and decremented by one.

Original Mutated
abc{9,} abc{8,}
abc{9,} abc{10,}

Back to table 🔝

QuantifierNOrMoreChange

Turn an n or more range quantifier into a fixed number quantifier.

Original Mutated
abc{9,} abc{9}

Back to table 🔝

QuantifierNMModification

Alter the n to m range quantifier by decrementing or incrementing the high and low of the range by one.

Original Mutated
abc{3,9} abc{2,9}
abc{3,9} abc{4,9}
abc{3,9} abc{3,8}
abc{3,9} abc{3,10}

Back to table 🔝

QuantifierShortModification

Treat the shorthand quantifiers (?, *, +) as their corresponding range quantifier variant ({0,1}, {0,}, {1,}), and applies the same mutations as mentioned in the mutators above.

Original Mutated
abc? abc{1,1}
abc? abc{0,0}
abc? abc{0,2}
abc* abc{1,}
abc+ abc{0,}
abc+ abc{2,}

Back to table 🔝

QuantifierShortChange

Change the shorthand quantifiers * and + to their fixed range quantifier variant.

Original Mutated
abc* abc{0}
abc+ abc{1}

Back to table 🔝

QuantifierReluctantAddition

Change greedy quantifiers to reluctant quantifiers.

Original Mutated
abc? abc??
abc* abc*?
abc+ abc+?
abc{9} abc{9}?
abc{9,} abc{9,}?
abc{9,13} abc{9,13}?

Back to table 🔝

Group-related construct mutators

GroupToNCGroup

Change a normal group to a non-capturing group.

Original Mutated
(abc) (?:abc)

Back to table 🔝

LookaroundNegation

Flips the sign of a lookaround (lookahead, lookbehind) construct.

Original Mutated
(?=abc) (?!abc)
(?!abc) (?=abc)
(?<=abc) (?<!abc)
(?<!abc) (?<=abc)

Back to table 🔝

weapon-regex's People

Contributors

dependabot[bot] avatar github-actions[bot] avatar hugo-vrijswijk avatar jpgsmits avatar julienrf avatar nhaajt avatar nicojs avatar scala-steward avatar stryker-mutator[bot] avatar stryker-steward[bot] avatar strykermutator-npa avatar wijtserekker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

weapon-regex's Issues

Chinese regular expressions

Hi!
Sorry to raise a question (more than a bug).
I was running Stryker with production code with a regular expression like this - as I need to do something specific with Chinese characters.:

const findChineseCharacter = /\p{Script_Extensions=Han}/gu;

So, when running Stryker I got:

[RegexMutator]: The Regex parser of weapon-regex couldn't parse this regex pattern: "\p{Script_Extensions=Han}". Please report this issue at https://github.com/stryker-mutator/weapon-regex/issues. Inner error: [Error] Parser: Position 1:1, found "\\p{Script_"

It's not very important, but that's definitely part of the regular expression of Typescript regular expressions as this entry points out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape

Note that Java has a quite different way to handle Chinese in regular expressions.

Mutation testing is dramatically slower with code coverage instrumentation

I've noticed that Stryker4s is a lot slower when code coverage is enabled. I think this is because code instrumentation is done twice: once by Stryker4s to place mutants, and once by sbt-jacoco for coverage analysis on top of that. Removing sbt-jacoco gave me substantial performance improvements when running Stryker4s.

Suggestion:

  1. Replace sbt-jacoco with another tool that explicitly enables coverage instrumentation, like sbt-scoverage (sbt "coverage test").
  2. Remove code coverage altogether. I'm not a big fan anyway 😊 and if mutation testing is fast then set thresholds for it instead

@stryker-mutator/weapon-regex-team thoughts?

Support native ES module

Native ES modules are finally supported in all current LTS NodeJS versions 🎉. I've since migrated StrykerJS to a native ESM here: stryker-mutator/stryker-js#3409

This means that we can finally use ES modules in all StrykerJS dependencies! This is a great time to do the same for weapon-regex. The benefits would be better performance for all StrykerJS users because ES modules are loaded in parallel instead of serial.

I think this change is fairly small.

MFA is now required for all members of stryker-mutator

@nhaajt we have enabled enforcement of MFA for the stryker-mutator organization. Due to the enforcement your membership has been revoked by Github. Could you enable MFA? I'll invite you back into the organization when you have MFA enabled on your account.

The regex `\u{0}` mutates to invalid syntax in node 18

Hi guys 🙋‍♂️, how is it going?

The regex \u{0} results in an invalid regex:

- /\u{0}/
+ /\u/

The name of the mutation is "Quantifier removal". However, this isn't a quantifier in this context, but rather the unicode character 0. In node 16, this was silently ignored, however in the latest major release of node (v18) this results in a syntax error during the initial test run (dry run).

Originally reported here: stryker-mutator/stryker-js#3579

image

Failed to parse an unconventional regex

Hello!

For fun, I wanted to use the native node:test & node:assert.
Sadly, it doesn't have a feature to mock imported modules when doing tests.
So as a side project, I wanted to see if I could make a custom loader that would allow just that.

When trying to run stryker, weapon-regex was stumped on my import regex and could not parse it.

/import\s*(?<imported_items>.+?)\s*from\s*['"](?<dependency_identifier>[^'"]+)['"]/g

It could be that he is stumped by the named capturing groups <imported_items> and <dependency_identifier>.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group

The error message was

[RegexMutator]: The Regex parser of weapon-regex couldn't parse this regex pattern:
"import\s*(?<imported_items>.+?)\s*from\s*['"](?<dependency_identifier>[^'"]+)['"]".
Please report this issue at https://github.com/stryker-mutator/weapon-regex/issues.
Inner error: [Error] Parser: Position 1:10, found "(?<importe"

Unparsable but valid regex

Error

[RegexMutator]: The Regex parser of weapon-regex couldn't parse this regex pattern: "mini-css-extract-plugin[^]*Conflicting order between:". Please report this issue at https://github.com/stryker-mutator/weapon-regex/issues. Inner error: [Error] Parser: Position 1:24, found "[^]*Confli"

Regex

/mini-css-extract-plugin[^]*Conflicting order between:/

This is a valid regex though and works as expected so not sure why it is unparseable?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.