Commit 94c9ea1b authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'ajk-be-sorted' into 'master'

[TOOLING] Add fluent API to be_sorted matcher [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!50347
parents ccfbc5da bbd2681a
...@@ -4,18 +4,75 @@ ...@@ -4,18 +4,75 @@
# #
# By default, this checks that the collection is sorted ascending # By default, this checks that the collection is sorted ascending
# but you can check order by specific field and order by passing # but you can check order by specific field and order by passing
# them, eg: # them, either as arguments, or using the fluent interface, eg:
# #
# ``` # ```
# # Usage examples:
# expect(collection).to be_sorted
# expect(collection).to be_sorted(:field)
# expect(collection).to be_sorted(:field, :desc) # expect(collection).to be_sorted(:field, :desc)
# 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] }
# ``` # ```
RSpec::Matchers.define :be_sorted do |by, order = :asc| 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
match do |actual| match do |actual|
next true unless actual.present? # emtpy collection is sorted 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
actual def show(things)
.then { |collection| by ? collection.sort_by(&by) : collection.sort } if @format_with
.then { |sorted_collection| order.to_sym == :desc ? sorted_collection.reverse : sorted_collection } things.map(&@format_with)
.then { |sorted_collection| sorted_collection == actual } else
things
end
end end
end end
# frozen_string_literal: true
require 'fast_spec_helper'
load File.expand_path('../../../spec/support/matchers/be_sorted.rb', __dir__)
RSpec.describe 'be_sorted' do
it 'matches empty collections, regardless of arguments' do
expect([])
.to be_sorted
.and be_sorted.asc
.and be_sorted.desc
.and be_sorted(:foo)
.and be_sorted(:bar)
expect([].to_set).to be_sorted
expect({}).to be_sorted
end
it 'matches in both directions' do
expect([1, 2, 3]).to be_sorted.asc
expect([3, 2, 1]).to be_sorted.desc
end
it 'can match on a projection' do
xs = [['a', 10], ['b', 7], ['c', 4]]
expect(xs).to be_sorted.asc.by(&:first)
expect(xs).to be_sorted(:first, :asc)
expect(xs).to be_sorted.desc.by(&:second)
expect(xs).to be_sorted(:second, :desc)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment