mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Merge remote-tracking branch 'origin/master' into release/0.10
This commit is contained in:
commit
6c55301d0b
11 changed files with 140 additions and 12 deletions
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -40,6 +40,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Removed
|
||||
- Removed one-liner `it`-syntax without braces (block).
|
||||
|
||||
## [0.9.40] - 2021-07-10
|
||||
### Fixed
|
||||
- Fix stubbing of class methods.
|
||||
- Fix handling of `no_args` in some cases.
|
||||
|
||||
### Changed
|
||||
- Better handling and stubbing of `Process.exit`.
|
||||
|
||||
## [0.9.39] - 2021-07-02
|
||||
### Fixed
|
||||
- Fix `expect().to receive()` syntax not implicitly stubbing the method.
|
||||
- Avoid calling `NoReturn` methods from stubs. [#29](https://github.com/icy-arctic-fox/spectator/issues/29)
|
||||
|
||||
### Added
|
||||
- Added support for `with(no_args)` for method stubs. [#28](https://github.com/icy-arctic-fox/spectator/issues/28)
|
||||
- Allow creation of doubles without definition block. [#30](https://github.com/icy-arctic-fox/spectator/issues/30)
|
||||
|
||||
## [0.9.38] - 2021-05-27
|
||||
### Fixed
|
||||
- Fix `Channel::ClosedError` when using default Crystal Logger. [#27](https://github.com/icy-arctic-fox/spectator/issues/27)
|
||||
|
@ -301,7 +318,8 @@ This has been changed so that it compiles and raises an error at runtime with a
|
|||
First version ready for public use.
|
||||
|
||||
|
||||
[Unreleased]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.39...release%2F0.10
|
||||
[Unreleased]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.40...release%2F0.10
|
||||
[0.9.40]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.39...v0.9.40
|
||||
[0.9.39]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.38...v0.9.39
|
||||
[0.9.38]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.37...v0.9.38
|
||||
[0.9.37]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.36...v0.9.37
|
||||
|
|
|
@ -17,4 +17,24 @@ Spectator.describe "GitHub Issue #29" do
|
|||
subject.goodbye
|
||||
end
|
||||
end
|
||||
|
||||
describe "class method" do
|
||||
class Foo
|
||||
def self.test
|
||||
exit 0
|
||||
end
|
||||
end
|
||||
|
||||
mock Foo do
|
||||
stub self.exit(code)
|
||||
end
|
||||
|
||||
subject { Foo }
|
||||
|
||||
it "must capture exit" do
|
||||
expect(subject).to receive(:exit).with(0)
|
||||
|
||||
subject.test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
37
spec/issues/github_issue_32_spec.cr
Normal file
37
spec/issues/github_issue_32_spec.cr
Normal file
|
@ -0,0 +1,37 @@
|
|||
require "../spec_helper"
|
||||
|
||||
Spectator.describe "GitHub Issue #32" do
|
||||
module TestFoo
|
||||
class TestClass
|
||||
def initialize
|
||||
end
|
||||
|
||||
# the method we are testing
|
||||
def self.test
|
||||
new().test
|
||||
end
|
||||
|
||||
# the method we want to ensure gets called
|
||||
def test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(test_class) { TestFoo::TestClass }
|
||||
let(test_instance) { test_class.new }
|
||||
|
||||
describe "something else" do
|
||||
mock TestFoo::TestClass do
|
||||
stub self.new
|
||||
stub test
|
||||
end
|
||||
|
||||
it "must test when new is called" do
|
||||
expect(test_class).to receive(:new).with(no_args).and_return(test_instance)
|
||||
expect(test_instance).to receive(:test)
|
||||
expect(test_class.new).to be(test_instance)
|
||||
|
||||
test_class.test
|
||||
end
|
||||
end
|
||||
end
|
26
spec/issues/github_issue_33_spec.cr
Normal file
26
spec/issues/github_issue_33_spec.cr
Normal file
|
@ -0,0 +1,26 @@
|
|||
require "../spec_helper"
|
||||
|
||||
Spectator.describe "GitHub Issue #33" do
|
||||
class Test
|
||||
def method2
|
||||
end
|
||||
|
||||
def method1
|
||||
method2
|
||||
end
|
||||
end
|
||||
|
||||
mock Test do
|
||||
stub method2
|
||||
end
|
||||
|
||||
describe Test do
|
||||
describe "#method1" do
|
||||
it do
|
||||
expect(subject).to receive(:method2)
|
||||
|
||||
subject.method1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -98,6 +98,7 @@ module Spectator
|
|||
elapsed = Time.measure do
|
||||
error = catch { yield }
|
||||
end
|
||||
error = nil if error.is_a?(SystemExit) && mocks.exit_handled?
|
||||
{elapsed, error}
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require "./mocks/*"
|
||||
require "./system_exit"
|
||||
|
||||
module Spectator
|
||||
# Functionality for mocking existing types.
|
||||
|
@ -11,3 +12,13 @@ module Spectator
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Add default stub to `exit` method.
|
||||
# This captures *most* (technically not all) attempts to exit the process.
|
||||
# This stub only takes effect in example code.
|
||||
# It intercepts `exit` calls and raises `Spectator::SystemExit` to prevent killing the test.
|
||||
class ::Process
|
||||
include ::Spectator::Mocks::Stubs
|
||||
|
||||
stub self.exit(code) { raise ::Spectator::SystemExit.new }
|
||||
end
|
||||
|
|
|
@ -20,6 +20,8 @@ module Spectator::Mocks
|
|||
value = call(args) { |*ya| yield *ya }
|
||||
if value.is_a?(RT)
|
||||
value.as(RT)
|
||||
elsif value.nil? && RT == NoReturn
|
||||
raise SystemExit.new
|
||||
else
|
||||
raise TypeCastError.new("The return type of stub #{self} doesn't match the expected type #{RT}")
|
||||
end
|
||||
|
|
|
@ -41,6 +41,10 @@ module Spectator::Mocks
|
|||
NilMethodStub.new(@name, @location, args)
|
||||
end
|
||||
|
||||
def with(args : Arguments)
|
||||
NilMethodStub.new(@name, @location, @args)
|
||||
end
|
||||
|
||||
def and_call_original
|
||||
OriginalMethodStub.new(@name, @location, @args)
|
||||
end
|
||||
|
|
|
@ -35,6 +35,10 @@ module Spectator::Mocks
|
|||
fetch_type(object.class).stubs.find(&.callable?(call))
|
||||
end
|
||||
|
||||
def find_stub(type : T.class, call : MethodCall) forall T
|
||||
fetch_type(type).stubs.find(&.callable?(call))
|
||||
end
|
||||
|
||||
def record_call(object, call : MethodCall) : Nil
|
||||
fetch_instance(object).calls << call
|
||||
fetch_type(object.class).calls << call
|
||||
|
@ -53,6 +57,14 @@ module Spectator::Mocks
|
|||
fetch_type(object.class).expected.any?(&.callable?(call))
|
||||
end
|
||||
|
||||
def exit_handled? : Bool
|
||||
# Lazily check if an `exit` method was called and it was expected.
|
||||
# This is okay since an `expect().to receive(:exit)` should check the details of the call.
|
||||
(@entries.any? { |_key, entry| entry.expected.any? { |stub| stub.name == :exit } } ||
|
||||
@all_instances.any? { |_key, entry| entry.expected.any? { |stub| stub.name == :exit } }) &&
|
||||
@entries.any? { |_key, entry| entry.calls.any? { |call| call.name == :exit } }
|
||||
end
|
||||
|
||||
def expect(object, stub : MethodStub) : Nil
|
||||
entry = fetch_instance(object)
|
||||
entry.expected.add(stub)
|
||||
|
|
|
@ -62,7 +62,7 @@ module Spectator::Mocks
|
|||
elsif t.has_method?(name)
|
||||
:previous_def
|
||||
else
|
||||
"::#{name}"
|
||||
name
|
||||
end.id
|
||||
%}
|
||||
|
||||
|
@ -82,11 +82,7 @@ module Spectator::Mocks
|
|||
%call = ::Spectator::Mocks::MethodCall.new({{name.symbolize}}, %args)
|
||||
%harness.mocks.record_call(self, %call)
|
||||
if (%stub = %harness.mocks.find_stub(self, %call))
|
||||
if typeof({{original}}) == NoReturn
|
||||
return %stub.call!(%args) { nil }
|
||||
else
|
||||
return %stub.call!(%args) { {{original}} }
|
||||
end
|
||||
return %stub.call!(%args) { {{original}} }
|
||||
end
|
||||
|
||||
{% if body && !body.is_a?(Nop) || return_type.is_a?(ArrayLiteral) %}
|
||||
|
@ -105,11 +101,7 @@ module Spectator::Mocks
|
|||
%call = ::Spectator::Mocks::MethodCall.new({{name.symbolize}}, %args)
|
||||
%harness.mocks.record_call(self, %call)
|
||||
if (%stub = %harness.mocks.find_stub(self, %call))
|
||||
if typeof({{original}}) == NoReturn
|
||||
return %stub.call!(%args) { nil }
|
||||
else
|
||||
return %stub.call!(%args) { {{original}} { |*%ya| yield *%ya } }
|
||||
end
|
||||
return %stub.call!(%args) { {{original}} { |*%ya| yield *%ya } }
|
||||
end
|
||||
|
||||
{% if body && !body.is_a?(Nop) || return_type.is_a?(ArrayLiteral) %}
|
||||
|
|
5
src/spectator/system_exit.cr
Normal file
5
src/spectator/system_exit.cr
Normal file
|
@ -0,0 +1,5 @@
|
|||
module Spectator
|
||||
# Exception raised when `exit` is called and intercepted from a stub.
|
||||
class SystemExit < Exception
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue