splitwise / super_diff Goto Github PK
View Code? Open in Web Editor NEWA more helpful way to view differences between complex data structures in RSpec.
Home Page: https://mcmire.github.io/super_diff
License: MIT License
A more helpful way to view differences between complex data structures in RSpec.
Home Page: https://mcmire.github.io/super_diff
License: MIT License
This is gonna be a big one...
There are no tests for "assuming color is disabled".
The CommandRunner is copied from my work with shoulda-matchers
, and I imagine using it other places. Keeping it here bloats the codebase.
Right now we're getting output like:
+ [#<ShippingAddress
+ id:
+ 1,
+ name:
+ "Rosa
+ Diaz",
+ phone:
+ "639-351-1301",
+ company:
+ nil,
+ line_1:
+ "111
+ Park
+ Place",
+ line_2:
+ "#13",
+ city:
+ "Denver",
+ state:
+ "CO",
+ zip:
+ "12345",
+ country:
+ "US"
Currently we use a different algorithm to inspect two complex objects on a single line and then generate a diff of those objects. Here is a good example of this:
Differing objects.
Expected: #<SuperDiff::Test::Player:0x7fcdb0a77440 @handle="martymcfly" @character="mirage" @inventory=["flatline", "purple body shield"] @shields=0.6 @health=0.3 @ultimate=0.8>
Actual: #<SuperDiff::Test::Player:0x7fcdb0a77300 @handle="docbrown" @character="lifeline" @inventory=["wingman", "mastiff"] @shields=0.6 @health=0.3 @ultimate=0.8>
Diff:
#<SuperDiff::Test::Player {
- handle: "martymcfly",
+ handle: "docbrown",
- character: "mirage",
+ character: "lifeline",
inventory: [
- "flatline",
+ "wingman",
- "purple body shield"
+ "mastiff"
],
shields: 0.6,
health: 0.3,
ultimate: 0.8
}>
In this case, "Expected" vs "Actual" uses deep inspection to generate an inspection of the two objects, whereas the diff uses an entirely different algorithm. Thus, you get SuperDiff::Test::Player:0x7fcdb0a77440
vs SuperDiff::Test::Player
. Maybe there's a way we can make use of the pretty printing algorithm to generate a diff?
No one needs another library to colorize text, but keeping it here bloats the codebase.
Unfortunately csi
is already taken as a gem name. Something else?
When comparing the following
A: {:fiz => "gram", 1 => {2 => :sym}}
B: {42 => {:raz => "matazz"}, :fiz => "graeme", 1 => 3}
Output should be:
- *[42]: Expected to not be present, but found (value: {:raz => "matazz"})
- *[:fiz]...
Currently keys not found in A are listed at the very end.
Using match
+ a_collection_containing_exactly
doesn't seem to be producing a useful diff. Let's look into this.
https://github.com/mcmire/super_diff/blob/master/lib/super_diff/rspec/monkey_patches.rb#L591
This seems to happen if the given block doesn't actually raise an error.
Currently, have_attributes
is not colored like eq
.
Use "explicit mode" so we're not monkeypatching Object.
For instance, instead of producing this diff:
{
"data" => {
- "getCurrentAccount" => {
- "key" => "49b471a566d7762da44778ff63526401",
- "firstName" => "Elliot",
- "lastName" => "Winkler"
}
},
+ "errors" => [{ "type" => "unknown", "message" => "Something bad happened", "details" => nil }]
}
It would produce this instead:
{
"data" => {
- "getCurrentAccount" => {
- "key" => "49b471a566d7762da44778ff63526401",
- "firstName" => "Elliot",
- "lastName" => "Winkler"
}
},
+ "errors" => [
+ {
+ "type" => "unknown",
+ "message" => "Something bad happened",
+ "details" => nil
+ }
+ ]
}
Red and green connote good and bad. It means that the "actual" value is correct and the "expected" value is not. Well, who's to say? Sometimes it's the other way around. So maybe we shouldn't use overloaded colors in this way.
When printing:
Expected: ...
to eq: ...
The "actual" value is in red and the "expected" value is in green. Shouldn't it be the other way around? (i.e. the actual value should be assumed to be the right one).
Note that this means we'd have to flip the colors in the diff as well, and update the legend.
We already sort keys for ActiveRecord::Base instances, so it may make sense to sort hash keys too.
If there is a bug in the gem such that diffing, or even our custom overrides for matchers, don't work correctly, should we fall back to RSpec so as not to disrupt the developer?
This may be tricky since we're using Appraisal. Can use rubyfmt's workflow file as inspiration, but will have to do research on this first.
Currently, OperationSequence is the only class for which we do not have a factory function. In theory we shouldn't need a factory function for DiffFormatter, as operational sequences have a to_diff
method and we should be able to use that. Can we extend this pattern to find the correct OperationSequence for an OperationalSequencer? And find the right OperationalSequencer for a Differ? That may obviate the need to repeat the applies_to?
logic for each stratum of class in the hierarchy, as we have to do that right now (and it's a bit inconsistent).
One example is the String differ that some dude wrote and posted to the RSpec issue tracker.
Another example is an OrderedHash differ that works very similar to the Hash differ.
In other words, the current differs need to be extracted into classes somehow.
Right now the JRuby tests take 9 times as long to run as the MRI tests. This is probably because for each integration test, we spawn a sub-ruby, which is a pretty big performance hit. In fact, JRuby recommends not doing this. There are ways to get around this, but perhaps the simplest way is to stuff all of the integration tests into a single file? This means that only one sub-ruby would be spawned. The results of each test would then be collected and compared to expected outputs. This would likely create some kind of Frankenstein in terms of the integration tests, so maybe this isn't worth it for now?
For instance, if a class merely accepts a bunch of values or keyword values and sets instance variables, and we have two instances of the same class, it might be nice if the gem automatically compared them using instance variables instead of having to write a custom differ for that class.
What I mean by collapsed output is this:
Error: ...
Expected: ...
Got: ...
Breakdown:
- *["foo"][1]["bar"][:baz]: Differing strings.
- Expected: ...
- Got: ...
instead of this:
Error: ...
Expected: ...
Got: ...
Breakdown:
- *["foo"]: ...
- *[1]: ...
- *["bar"]: ...
- *[:baz]: Differing strings.
- Expected: ...
- Got: ...
In other words, it would collapse everything until it gets to a node beyond which we can no longer recurse (a simple type, in other words).
Rubocop is getting super annoying. I end up having to tweak the rules a lot and they're just not working for me. I really like the idea of using an autoformatter. The best candidate seems like rubyfmt. I'm not sure when it'll be available, but I can't wait.
Importing super_diff/rspec
technically works in Cucumber but diffs aren't showing for some reason.
There are a few different kinds of classes that have some duplication in them. Making a new strategy is a bit painful because you end up repeating yourself and only a small part of the class changes. Especially with DiffFormatters and using Collection.
If a test like the following fails:
expect(person.shipping_addresses.order(:id)).to match([
existing_shipping_address
])
then the diff should skip over the fact that person.shipping_addresses.order(:id)
returns a relation object and not an array.
By turning off all of RSpec's colorization and then turning it on in select places, we've made it more difficult to know how to interpret unhandled errors.
At work, escaped color sequences are showing up on CircleCI when tests fail, even though RSpec has been configured to not show color.
Currently if you have two arrays:
a = %w(a b c d)
b = %w(1 2 a b)
and you diff them, the differ will tell you this, basically:
0: "a" != "1"
1: "b" != "2"
2: "c" != "a"
3: "d" != "b"
Now, ideally, this is not very helpful. We should be able to figure out that "1" and "2" were inserted before "a" and that "c" and "d" were removed. So maybe the output would be exactly that:
- "1", "2" inserted before "a"
- "b", "c" deleted after "b"
Notice that we aren't listing the array indices anymore, since those are no longer meaningful.
This actually sounds like a proper use case for the LCS algorithm.
Currently, respond_to
is not colored like eq
.
Right now we have tests for comparing objects, but it uses the same class for both objects. We could have a case, however, where we're trying to compare totally different objects. We should make sure that the correct output is produced. (I don't think we should show a diff if you're comparing two objects, unless those objects are inside of another data structure.)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.