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

2.7 Syntax - Upgrade to unparser ~> 0.5.2 #1062

Merged
merged 2 commits into from
Oct 16, 2020
Merged

2.7 Syntax - Upgrade to unparser ~> 0.5.2 #1062

merged 2 commits into from
Oct 16, 2020

Conversation

mbj
Copy link
Owner

@mbj mbj commented Oct 16, 2020

  • Remove all hacks for unparser normalization
  • Adjust verification to enforce the better unparser constraints
  • Add 2.7 syntax support

@mbj mbj force-pushed the upgrade/unparser branch 3 times, most recently from e1611f5 to d12d1fa Compare October 16, 2020 04:05
@mbj mbj changed the title Upgrade to unparser ~> 0.5.2 2.7 Syntax - Upgrade to unparser ~> 0.5.2 Oct 16, 2020
@mbj mbj force-pushed the upgrade/unparser branch 3 times, most recently from d6c91fb to 2b896a0 Compare October 16, 2020 04:08
@@ -42,7 +42,7 @@ def prepare
private

def wrap_node(mutant)
s(:begin, mutant, s(:send, nil, :memoize, s(:args, s(:sym, name), *options)))
Copy link
Owner Author

Choose a reason for hiding this comment

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

@snusnu All this years we where generating invalid AST that would silently be emitted as correct intended source.


source s(:begin, s(:true))
# Mutation of each statement in block
mutation s(:begin, s(:false))
Copy link
Owner Author

Choose a reason for hiding this comment

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

@dgollahon ^^ was part of the unparser preprocessor hack artifacts.

@@ -8,9 +8,9 @@
# edge cases
mutation '0.0'
mutation '1.0'
mutation '(0.0 / 0.0)'
mutation '(1.0 / 0.0)'
mutation '(-1.0 / 0.0)'
Copy link
Owner Author

Choose a reason for hiding this comment

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

@dgollahon ^^ Another one. This redundant begin was needed as unparser pre 0.5 was not able to infer or vs || based on AST structure and had to preserve semantic equivalency via extra parens. This extra parsens where an artifact of that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This one in particular seems like a nice quality of life improvement.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yeah, the unparser preprocessor hack was a bad shortcut of mine I took years ago when I had "nothing" and had to 80/20 a lot of subsystems to get something.

@@ -1,16 +1,10 @@
# frozen_string_literal: true

Mutant::Meta::Example.add :lvar do
source 'a = nil; a'
declare_lvar :a
Copy link
Owner Author

Choose a reason for hiding this comment

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

Not really an unparser artifact. But correctly using the parser API to avoid redundancy.

# TODO: fix invalid AST
# These ASTs are not valid and should NOT be emitted
# Mutations of lvarasgn need to be special cased to avoid this.
mutation s(:begin, s(:lvasgn, :a__mutant__, s(:nil)), s(:lvar, :a))
Copy link
Owner Author

Choose a reason for hiding this comment

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

No need anymore to specify AST with forwad lvar declaration.

* Remove all hacks for unparser normalization
* Adjust verification to enforce the better unparser constraints
* Add 2.7 syntax support
mutation 'self.b += 1'
# TODO: fix invalid AST
# This should not get emitted as invalid AST with valid unparsed source
mutation s(:op_asgn, s(:ivar, :@a), :+, s(:int, 1))
Copy link
Owner Author

Choose a reason for hiding this comment

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

Side effect of better unparser we can remove that one now.

@mbj mbj self-assigned this Oct 16, 2020
@mbj mbj merged commit 502aad0 into master Oct 16, 2020
@mbj mbj deleted the upgrade/unparser branch October 16, 2020 04:16
Comment on lines +65 to +74
let(:source) { 'false' }

let(:expected) do
[
Mutant::Meta::Example::Expected.new(
node: s(:nil),
original_source: 'nil'
)
]
end
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is kind of interesting. I'm not sure I fully understand the context of this spec, but does this mutate false -> nil somehow? I removed that mutation recently (I thought). Or is this just an artifact of test setup but wouldn't actually happen in practice?

Copy link
Owner Author

Choose a reason for hiding this comment

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

This spec does not demonstrate the mutations. It never calls the mutation engine, AKA Mutant::Mutator::Node is never called. Instead it specifies on how mutations are specified. For this I run through the scenarios:

  • There was a mutation being generated that was not expected.
  • A mutation that was expected was not being generated.
  • A mutation that was generated unparses to invalid syntax
  • The original code that was being specified did not round trip.

And for each of these cases above I set-up an Mutant::Meta::Example object in that specific state. But I intentionally do NOT run the engine here. But still use AST nodes that can round trip to unparser at low complexity.

Copy link
Owner Author

Choose a reason for hiding this comment

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

or TLDR: This code is the specification of the mutant mutation specifications and uses fake mutated nodes to not hard code the specification of properties of the specification against the mutation engine.

Copy link
Collaborator

Choose a reason for hiding this comment

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

or TLDR: This code is the specification of the mutant mutation specifications and uses fake mutated nodes to not hard code the specification of properties of the specification against the mutation engine.

Ok, cool. I thought that might be the case but wasn't 100% sure at a glance. Might make sense to use a valid mutation for documentation consistency but probably doesn't matter much.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Might make sense to use a valid mutation for documentation consistency but probably doesn't matter much.

it is a valid mutation example to demonstrate the specification of the specification on the properties I listed above. And I do not wish to call the real mutation engine here. I only wish to demonstrate I can find specific expected, missing and invalid mutations.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right, I just meant I usually like to have examples in my tests match "real" behavior as much as possible. It is clearly valid in this context to mutate to anything but I thought it might be slightly less confusing to match the "real" behavior. Doesn't actually matter though, feel free to ignore.

Copy link
Owner Author

Choose a reason for hiding this comment

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

If I where to start having to manually have generated mutations in sync here, I'd enforce something that adds no value to the test. And even would break as mutations are about to change drastically.

I'm experimenting a lot with "tiers" of mutations to default to only the most useful etc.

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

Successfully merging this pull request may close these issues.

2 participants