diff --git a/lib/quo/fakes/collection_backed_fake.rb b/lib/quo/fakes/collection_backed_fake.rb new file mode 100644 index 0000000..f9494f4 --- /dev/null +++ b/lib/quo/fakes/collection_backed_fake.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# rbs_inline: enabled + +module Quo + module Fakes + class CollectionBackedFake < CollectionBackedQuery + prop :results, _Any, reader: false + prop :page_count, _Nilable(Integer), reader: false + + def collection + @results + end + + def results + klass = Class.new(CollectionResults) do + def page_count + @query.page_count + end + end + klass.new(self) + end + + def page_count + @page_count || validated_query.size + end + end + end +end diff --git a/lib/quo/fakes/relation_backed_fake.rb b/lib/quo/fakes/relation_backed_fake.rb new file mode 100644 index 0000000..3a18cd5 --- /dev/null +++ b/lib/quo/fakes/relation_backed_fake.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +# rbs_inline: enabled + +module Quo + module Fakes + class RelationBackedFake < RelationBackedQuery + prop :results, _Any, reader: false + prop :page_count, _Nilable(Integer), reader: false + prop :total_count, _Nilable(Integer), reader: false + + def query + @results + end + + def results + klass = Class.new(RelationResults) do + def page_count + @query.page_count + end + + def total_count + @query.total_count + end + end + klass.new(self) + end + + def page_count + @page_count || validated_query.size + end + + def total_count + @total_count || validated_query.size + end + + private + + def validated_query + query + end + + def underlying_query + validated_query + end + + def configured_query + validated_query + end + end + end +end diff --git a/lib/quo/minitest/helpers.rb b/lib/quo/minitest/helpers.rb index eb24dda..0ce2ac0 100644 --- a/lib/quo/minitest/helpers.rb +++ b/lib/quo/minitest/helpers.rb @@ -2,32 +2,40 @@ require "minitest/mock" +require_relative "../fakes/collection_backed_fake" +require_relative "../fakes/relation_backed_fake" + module Quo module Minitest module Helpers - # Stub query takes a block, and will yield to it with the stub on `new` set up.] - # Optionally, you can provide a mock to use for the fake query, instead of using a CollectionBackedQuery instance. - def stub_query(query_class, mock: nil, results: []) - raise "stub_query requires a block" unless block_given? + def fake_query(query_class, results: [], total_count: nil, page_count: nil) + # make it so that results of instances of this class return a fake Result object + # of the right type which returns the results passed in + if query_class < Quo::CollectionBackedQuery + klass = Class.new(Quo::Fakes::CollectionBackedFake) do + if query_class < Quo::Preloadable + include Quo::Preloadable - fake = if mock - proc { |*p, **k, &b| mock.new(*p, **k, &b) } + def query + collection + end + end + end + query_class.stub(:new, ->(**kwargs) { + klass.new(**kwargs, results: results, total_count: total_count, page_count: page_count) + }) do + yield + end + elsif query_class < Quo::RelationBackedQuery + query_class.stub(:new, ->(**kwargs) { + Quo::Fakes::RelationBackedFake.new(**kwargs, results: results, total_count: total_count, page_count: page_count) + }) do + yield + end else - ::Quo::CollectionBackedQuery.wrap(results).new - end - query_class.stub(:new, fake) do - yield + raise ArgumentError, "Not a Query class: #{query_class}" end end - - # Return a Mock query. This can then be used with `stub_query` if desired. - # `args`/`kwargs` are optional, and if provided, the mock will expect `new` with the given arguments. - def mock_query(query_class, args: [], kwargs: nil, results: []) - query_class_mock = ::Minitest::Mock.new(query_class) - fake_qo_instance = ::Quo::CollectionBackedQuery.wrap(results).new - query_class_mock.expect(:new, fake_qo_instance, args, **kwargs) - query_class_mock - end end end end diff --git a/test/quo/fake_query_test.rb b/test/quo/fake_query_test.rb new file mode 100644 index 0000000..7096cbc --- /dev/null +++ b/test/quo/fake_query_test.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require_relative "../test_helper" +require "quo/minitest/helpers" + +class Quo::FakeQueryTest < ActiveSupport::TestCase + include Quo::Minitest::Helpers + + def create_query_class + Class.new(Quo::CollectionBackedQuery) do + include Quo::Preloadable + + def collection + [1, 2, 3] + end + end + end + + test "RelationBackedFake acts like a RelationBackedQuery" do + fake_query(UnreadCommentsQuery, results: [1, 2]) do + q = UnreadCommentsQuery.new + assert q.results.is_a?(Quo::RelationResults) + assert q.is_a?(Quo::RelationBackedQuery) + assert_equal 2, q.results.count + assert_equal 1, q.results.first + assert_nothing_raised do + q.includes(:foo).order(:bar).limit(10).preload(:x).results.first + end + end + end + + test "CollectionBackedFake acts like a CollectionBackedQuery" do + klass = create_query_class + fake_query(klass, results: [1, 2]) do + q = klass.new + assert q.results.is_a?(Quo::CollectionResults) + assert q.is_a?(Quo::CollectionBackedQuery) + assert_equal 2, q.results.count + assert_equal 1, q.results.first + assert_nothing_raised do + q.preload(:x).results.first + end + end + end +end