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

Leave only one element in the non empty returned array #735

Merged
merged 2 commits into from
Jul 4, 2019

Conversation

maks-rafalko
Copy link
Member

@maks-rafalko maks-rafalko commented Jul 1, 2019

This PR:

Closes #690

@maks-rafalko maks-rafalko added this to the 0.14.0 milestone Jul 1, 2019
@BackEndTea
Copy link
Member

I was thinking maybe we could use array_key_first, but because array_value_first didn't get implemented, that isn't as useful.

@sanmai sanmai self-requested a review July 2, 2019 23:23
Copy link
Member

@BackEndTea BackEndTea left a comment

Choose a reason for hiding this comment

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

👍

@maks-rafalko maks-rafalko merged commit 8b93ca5 into master Jul 4, 2019
@maks-rafalko maks-rafalko deleted the feature/array-one-element branch July 4, 2019 19:26
@maks-rafalko
Copy link
Member Author

Thank you @sanmai & @BackEndTea

public function getCollection() : array
{
$collection = [1, 2, 3];
return count($collection) > 1 ? array_slice($collection, 0, 1, true) : $collection;
Copy link
Contributor

@morozov morozov Oct 12, 2019

Choose a reason for hiding this comment

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

The fact that the mutation produces a conditional statement opens up the possibility of false positives. At the code execution time, depending on the size of the collection, the mutation may or may not effectively happen but it will also be counted as such.

Some collections have one element by design. For instance, all sorts of JSON-based API responses that have one top-level element:

{
   "response": { /* ... */}
}

The code that consumes this API and the corresponding tests don't expect any other elements in the collection, therefore the mutation (that effectively doesn't change anything) passes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree. And this is where the user can disable mutator for particular line, method or completely for the project.

Do you have any suggestions here?

This mutator is useful for the opposite scenario, where we are working with e.g. Doctrine repositories and expect > 1 elements in the returned array.

Copy link
Contributor

@morozov morozov Oct 12, 2019

Choose a reason for hiding this comment

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

This mutator is useful for the opposite scenario, where we are working with e.g. Doctrine repositories and expect > 1 elements in the returned array.

Do you mean that they expect more than one item but only check the first one? Shouldn't the ArrayItemRemoval mutation flag such tests?

Do you have any suggestions here?

Judging by the documentation, this is the only mutation that generates a conditional, one branch of which is the same as the original code. I suggest to avoid that and make sure the code is mutated unconditionally (however it's still not clear how it's different from ArrayItemRemoval).

Alternatively, the mutated code, instead of returning the one-element collection as is could throw an exception indicating that the mutation didn't happen and shouldn't be counted.

Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't the ArrayItemRemoval mutation flag such tests?

ArrayItemRemoval mutates the raw arrays, not variables. When you literally have ['a' => 1, 2, 3, 'd' => 4] for example.

This mutator, ArrayOneItem, mutates returned array variables. That's the difference.

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed, even item removal cannot be done unconditionally. You cannot remove it from an empty array. Still, throwing an exception on an unsuccessful mutation should help avoid false positives.

Copy link
Member Author

Choose a reason for hiding this comment

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

even item removal cannot be done unconditionally. You cannot remove it from an empty array

we don't mutate empty array with ArrayItermRemoval mutator :) So there are no conditions.

Still, throwing an exception on an unsuccessful mutation should help avoid false positives.

Do you have false-positives with ArrayOneItem mutator because of conditions? What is the real source code?

I'm open to change it to throw an exception, just need more information about real cases and then we can create issue and discuss farther / implement.

Copy link
Contributor

Choose a reason for hiding this comment

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

we don't mutate empty array with ArrayItermRemoval mutator :) So there are no conditions.

That's the thing. You can see if the array literal is empty at mutation time and avoid false positives but you cannot do the same with a variable.

Do you have false-positives with ArrayOneItem mutator because of conditions? What is the real source code?

Yes. See morozov/kih#13.

Copy link
Member

Choose a reason for hiding this comment

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

I have put this into an issue so we can track this a bit better: #803

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RFC: leave only one element in the non empty returned array
4 participants