splitwise/super_diff

Failed Assertions on Date Instances Do Not Output a Diff

sshaw opened this issue · 4 comments

sshaw commented

0.9.0, running under Rails:

expect(Date.new(2020, 2, 1)).to eq Date.new(2020, 2, 2)

Results in:

  Expected #<Date:0x0000000124fed510> to eq #<Date:0x0000000124fed470>.

       Diff:

       ┌ (Key) ──────────────────────────┐
       │ ‹-› in expected, not in actual  │
       │ ‹+› in actual, not in expected  │
       │ ‹ › in both expected and actual │
       └─────────────────────────────────┘

         #<Date:0x0000000124fed510 {
         }>

If it is changed Time:

expect(Date.new(2020, 2, 1).to_time).to eq Date.new(2020, 2, 2).to_time

Then a diff is output.

sshaw commented

0.9.0, running under Rails:

Rails 7.0.4.3

This makes sense — super_diff handles Time and Time-like objects specially, but not Date objects. We'd want to add a new OperationTreeBuilder similar to TimeLike and then also add a new date_like? top-level helper like time_like?, then add tests to match.

I can work on a PR when I get a chance!

This has bugged me for a while as well and I wrote up a quick solution that could help folks until a real solution comes along (or I get off my lazy 🧈 and open a PR).

This module effectively copies the Differ and TreeBuilder from TimeLike and totally self contained. Just drop this in a spec/support file and you'll get useful (albeit ugly) diffs like
image

module SuperDiffDate
  module Base
    extend ActiveSupport::Concern

    class_methods do
      def applies_to?(expected, actual) = [expected, actual].all?(&method(:date_like?))

      private def date_like?(value)
        (value.respond_to?(:acts_like_date?) && value.acts_like_date?) ||
        value.is_a?(Date)
      end
    end
  end

  class TreeBuilder < SuperDiff::OperationTreeBuilders::CustomObject
    include Base
    protected def attribute_names = %w[year month day]
  end

  class Differ < SuperDiff::Differs::Base
    include Base
    protected def operation_tree_builder_class = TreeBuilder
  end
end

SuperDiff.configure do |config|
  config.add_extra_differ_class(SuperDiffDate::Differ)
  config.add_extra_operation_tree_builder_class(SuperDiffDate::TreeBuilder)
end

Thanks for posting a workaround @thefotios, glad you were able to navigate the codebase well enough to figure out something :)