Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: better mutant descriptions #268

Merged
merged 11 commits into from
Dec 12, 2023
Merged

Conversation

nhaajt
Copy link
Contributor

@nhaajt nhaajt commented Dec 12, 2023

Overview

  • Update mutator names, descriptions, and docs for better consistency
  • Add the ability to define better descriptions specific to each mutation
  • Add specific mutation descriptions for built-in mutators

Specific mutation description

Specific mutation description can be defined per mutator that extends TokenMutator by overriding the description method, which provides the original and mutated string representation of the targeted token and the mutation location:

object CharClassNegation extends TokenMutator {
  override val name = "Character class negation"
  override val levels: Seq[Int] = Seq(1)
  override def description(original: String, mutated: String, location: Location): String =
    s"${location.pretty} Negate the character class `$original` to `$mutated`"

  override def mutate(token: RegexTree): Seq[Mutant] = ...
}

With the above definition, the new descriptions for a CharClassNegation would be:

// Original regex
"[ab0-9[A-Z][cd]]"
// Mutants
"[^ab0-9[A-Z][cd]]"
"[ab0-9[^A-Z][cd]]"
"[ab0-9[A-Z][^cd]]"

// Before (same for all mutants)
"Negate character class"
// After
"[0:0, 0:1) Negate the character class `[ab0-9[A-Z][cd]]` to `[^ab0-9[A-Z][cd]]`"
"[0:6, 0:7) Negate the character class `[A-Z]` to `[^A-Z]`"
"[0:11, 0:12) Negate the character class `[cd]` to `[^cd]`"

If more mutation information is desired, a mutation description can also be directly specified during mutation as an argument for the toMutantOf, toMutantBeforeChildrenOf, or toMutantAfterChildrenOf extension methods:

object CharClassChildRemoval extends TokenMutator {
  override val name: String = "Character class child removal"
  override val levels: Seq[Int] = Seq(2, 3)

  override def mutate(token: RegexTree): Seq[Mutant] = {
    def _mutate(token: Node): Seq[Mutant] = token.children map (child =>
      token
        .buildWhile(_ ne child)
        .toMutantOf(
          child,
          description =
            s"${child.location.pretty} Remove the child `${child.build}` from the character class `${token.build}`"
        )
    )

    token match {
      case cc: CharacterClass if cc.children.length > 1      => _mutate(cc)
      case cc: CharacterClassNaked if cc.children.length > 1 => _mutate(cc)
      case _                                                 => Nil
    }
  }
}

New mutant descriptions for a CharClassChildRemoval are shown below:

// Original regex
"[ab0-9[A-Z][cd]]"
// Mutants
"[b0-9[A-Z][cd]]"
"[a0-9[A-Z][cd]]"
"[ab[A-Z][cd]]"
"[ab0-9[cd]]"
"[ab0-9[A-Z]]"
"[ab0-9[A-Z][d]]"
"[ab0-9[A-Z][c]]"

// Before (same for all mutants)
"Remove a child from a character class"
// After
"[0:1, 0:2) Remove the child `a` from the character class `[ab0-9[A-Z][cd]]`"
"[0:2, 0:3) Remove the child `b` from the character class `[ab0-9[A-Z][cd]]`"
"[0:3, 0:6) Remove the child `0-9` from the character class `[ab0-9[A-Z][cd]]`"
"[0:6, 0:11) Remove the child `[A-Z]` from the character class `[ab0-9[A-Z][cd]]`"
"[0:11, 0:15) Remove the child `[cd]` from the character class `[ab0-9[A-Z][cd]]`"
"[0:12, 0:13) Remove the child `c` from the character class `[cd]`"
"[0:13, 0:14) Remove the child `d` from the character class `[cd]`"

Breaking changes

  • TokenMutator.description removed in favor of using TokenMutator.description(original: String, mutated: String, location: Location): String to define and generate a more detailed description for each mutant instead of the mutator.

+ Rework how `Mutant`s are created to provide more precise descriptions
+ Update all mutators
- Remove `toMutantAt` extension method for `TokenMutator`
- Remove `TokenMutatorJS.description` since it is not a value anymore
- Remove the test to check for non-empty description in `MutatorTest` since there should always be a default one
…scription

# Conflicts:
#	core/src/main/scala/weaponregex/mutator/predefCharClassMutator.scala
…with a location

+ Update mutator description to always start with a location
+ Update mutator docstring to be more consistent with its name
+ Add a test to check for mutator description to always start with a location
@nhaajt nhaajt added ✨ enhancement New feature or request 🧬 mutator Related to the mutators labels Dec 12, 2023
Copy link
Member

@hugo-vrijswijk hugo-vrijswijk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I like the implementation. It's pretty clean and makes sense. Some minor comments.

*/
@JSExportAll
case class Location(start: Position, end: Position)
case class Location(start: Position, end: Position) {
val pretty: String = s"[${start.pretty}, ${end.pretty})"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than pretty, how about show? This is also in line with the cats typeclass

Suggested change
val pretty: String = s"[${start.pretty}, ${end.pretty})"
def show: String = s"[${start.show}, ${end.show})"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated 🧐 Good to know.

@hugo-vrijswijk hugo-vrijswijk changed the title Better mutant description feat: better mutant descriptions Dec 12, 2023
Copy link
Member

@hugo-vrijswijk hugo-vrijswijk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM feel free to (squash) merge

@hugo-vrijswijk hugo-vrijswijk merged commit 7a457cc into main Dec 12, 2023
8 checks passed
@hugo-vrijswijk hugo-vrijswijk deleted the feat/better-mutant-description branch December 12, 2023 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ enhancement New feature or request 🧬 mutator Related to the mutators
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants