2020-09-24 12:09:37 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Assert that this collection is sorted by argument and order
|
|
|
|
#
|
|
|
|
# By default, this checks that the collection is sorted ascending
|
|
|
|
# but you can check order by specific field and order by passing
|
2020-12-22 21:10:06 +00:00
|
|
|
# them, either as arguments, or using the fluent interface, eg:
|
2020-09-24 12:09:37 +00:00
|
|
|
#
|
|
|
|
# ```
|
2020-12-22 21:10:06 +00:00
|
|
|
# # Usage examples:
|
|
|
|
# expect(collection).to be_sorted
|
|
|
|
# expect(collection).to be_sorted(:field)
|
2020-09-24 12:09:37 +00:00
|
|
|
# expect(collection).to be_sorted(:field, :desc)
|
2020-12-22 21:10:06 +00:00
|
|
|
# expect(collection).to be_sorted.asc
|
|
|
|
# expect(collection).to be_sorted.desc.by(&:field)
|
|
|
|
# expect(collection).to be_sorted.by(&:field).desc
|
|
|
|
# expect(collection).to be_sorted.by { |x| [x.foo, x.bar] }
|
2020-09-24 12:09:37 +00:00
|
|
|
# ```
|
2020-12-22 21:10:06 +00:00
|
|
|
RSpec::Matchers.define :be_sorted do |on = :itself, order = :asc|
|
|
|
|
def by(&block)
|
|
|
|
@comparator = block
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def asc
|
|
|
|
@direction = :asc
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def desc
|
|
|
|
@direction = :desc
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def format_with(proc)
|
|
|
|
@format_with = proc
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
define_method :comparator do
|
|
|
|
@comparator || on
|
|
|
|
end
|
|
|
|
|
|
|
|
define_method :descending? do
|
|
|
|
(@direction || order.to_sym) == :desc
|
|
|
|
end
|
|
|
|
|
|
|
|
def order(items)
|
|
|
|
descending? ? items.reverse : items
|
|
|
|
end
|
|
|
|
|
|
|
|
def sort(items)
|
|
|
|
items.sort_by(&comparator)
|
|
|
|
end
|
|
|
|
|
2020-09-24 12:09:37 +00:00
|
|
|
match do |actual|
|
2020-12-22 21:10:06 +00:00
|
|
|
next true unless actual.present? # empty collection is sorted
|
|
|
|
|
|
|
|
actual = actual.to_a if actual.respond_to?(:to_a) && !actual.respond_to?(:sort_by)
|
|
|
|
|
|
|
|
@got = actual
|
|
|
|
@expected = order(sort(actual))
|
|
|
|
|
|
|
|
@expected == actual
|
|
|
|
end
|
|
|
|
|
|
|
|
def failure_message
|
|
|
|
"Expected #{show(@expected)}, got #{show(@got)}"
|
|
|
|
end
|
2020-09-24 12:09:37 +00:00
|
|
|
|
2020-12-22 21:10:06 +00:00
|
|
|
def show(things)
|
|
|
|
if @format_with
|
|
|
|
things.map(&@format_with)
|
|
|
|
else
|
|
|
|
things
|
|
|
|
end
|
2020-09-24 12:09:37 +00:00
|
|
|
end
|
|
|
|
end
|