domohuhn / mutation-test

Automated mutation testing for any programming language
BSD 3-Clause "New" or "Revised" License
21 stars 3 forks source link

Remove lines of codes, like method calls or List arguments #25

Open passsy opened 10 months ago

passsy commented 10 months ago

Thanks for creating this awesome tool! I used https://github.com/hcoles/pitest a lot in Java and I'm happy to see a similar tool for Dart. So far it is working, but the results are not very useful.

Remove method calls

The most common thing I detect with pitest is that method calls are not covered NonVoidMethodCallMutator. Look at this example:

void removeListener(void Function() listener) {
    _listeners.remove(listener);
}

I might call removeLister in my test, but I may not have a test that ensures the listener is removed from the internal list and won't fire anymore.

A mutation, removing the line would cover it:

void removeListener(void Function() listener) {
-   _listeners.remove(listener);
}

Remove list entries.

In my spot package, I create lists where each item is necessary. It would be beneficial to have a mutation that removes one entry.

  @useResult
  WidgetSelector<W> spot<W extends Widget>({
    List<WidgetSelector> parents = const [],
    List<WidgetSelector> children = const [],
  }) {
    final p = [if (self != null) self!, ...parents];
    final selector = WidgetSelector<W>(
      stages: [
        WidgetTypeFilter<W>(),
-       if (children.isNotEmpty) ChildFilter(children),
        if (p.isNotEmpty) ParentFilter(p),
      ],
    );
    return selector;
  }

Unfortunately, I think the XML Regex syntax is too limited for this kind of mutation. Do we maybe need a Dart API with granular control of the AST?

domohuhn commented 9 months ago

I agree that the regex syntax only allows simple mutations. Arbitrarily selecting mutants only in a certain context, like lists, is basically not possible (or at least it would very likely produce a significant amount of useless mutants). However, adding a full parser for the Dart language and an API that allows adding fully custom mutations is a very large task, even if parsing the code is done by another package. The dart analyzer package provides an AST and could be used to improve this tool. But I would need to have a clear picture what kind of features you have in mind when using the AST.

The usefulness of certain mutants fully depends on your project. Some developers may specifically need the changes you suggested, but they may not be useful for everyone. There is pretty much an unlimited parameter space to check. I believe most people will simply stick to the default configuration, so providing a code extension that can arbitrarily manipulate the AST may be overengineered. What's your vision regarding the API/new ways to add mutations? Do you want an additional DSL that can be used to arbitrarily create mutants? Or should there be a set of mutation passes that are defined in the code and that can be switched on and off via the configuration.

Removing the first and last entry in a list should be possible with the current implementation of the tool. Hitting an entry in the middle of list will be difficult. Removing method calls should be partially possible without adding a full-scale parser. As a first step I can add additional rules based on your suggestions in this ticket, and check if they do not cause too many false positive matches.