mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Initial work on Double
This commit is contained in:
parent
8ac6546bdd
commit
26deea3d20
4 changed files with 216 additions and 0 deletions
|
@ -1,3 +1,5 @@
|
|||
require "json" # Needed to test masking Object#to_json in doubles.
|
||||
require "yaml" # Needed to test masking Object#to_yaml in doubles.
|
||||
require "../src/spectator"
|
||||
require "../src/spectator/should"
|
||||
require "./helpers/**"
|
||||
|
|
114
spec/spectator/mocks/double_spec.cr
Normal file
114
spec/spectator/mocks/double_spec.cr
Normal file
|
@ -0,0 +1,114 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::Double do
|
||||
subject(dbl) { Spectator::Double.new(foo: 42, bar: "baz") }
|
||||
|
||||
it "responds to defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.bar).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "fails on undefined messages" do
|
||||
expect { dbl.baz }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
subject(dbl) do
|
||||
Spectator::Double.new(
|
||||
"!=": "!=",
|
||||
"!~": "!~",
|
||||
"==": "==",
|
||||
"===": "===",
|
||||
"=~": "=~",
|
||||
"class": "class",
|
||||
"dup": "dup",
|
||||
"hash": "hash",
|
||||
"in?": true,
|
||||
"inspect": "inspect",
|
||||
"itself": "itself",
|
||||
"not_nil!": "not_nil!",
|
||||
"pretty_inspect": "pretty_inspect",
|
||||
"tap": "tap",
|
||||
"to_json": "to_json",
|
||||
"to_pretty_json": "to_pretty_json",
|
||||
"to_s": "to_s",
|
||||
"to_yaml": "to_yaml",
|
||||
"try": "try",
|
||||
"object_id": 42_u64,
|
||||
"same?": false,
|
||||
)
|
||||
end
|
||||
|
||||
it "responds with defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to eq("!=")
|
||||
expect(dbl.!~(42)).to eq("!~")
|
||||
expect(dbl.==(42)).to eq("==")
|
||||
expect(dbl.===(42)).to eq("===")
|
||||
expect(dbl.=~(42)).to eq("=~")
|
||||
expect(dbl.class).to eq("class")
|
||||
expect(dbl.dup).to eq("dup")
|
||||
expect(dbl.hash(42)).to eq("hash")
|
||||
expect(dbl.hash).to eq("hash")
|
||||
expect(dbl.in?(42)).to eq(true)
|
||||
expect(dbl.in?(1, 2, 3)).to eq(true)
|
||||
expect(dbl.inspect).to eq("inspect")
|
||||
expect(dbl.itself).to eq("itself")
|
||||
expect(dbl.not_nil!).to eq("not_nil!")
|
||||
expect(dbl.pretty_inspect).to eq("pretty_inspect")
|
||||
expect(dbl.tap { nil }).to eq("tap")
|
||||
expect(dbl.to_json).to eq("to_json")
|
||||
expect(dbl.to_pretty_json).to eq("to_pretty_json")
|
||||
expect(dbl.to_s).to eq("to_s")
|
||||
expect(dbl.to_yaml).to eq("to_yaml")
|
||||
expect(dbl.try { nil }).to eq("try")
|
||||
expect(dbl.object_id).to eq(42_u64)
|
||||
expect(dbl.same?(dbl)).to eq(false)
|
||||
expect(dbl.same?(nil)).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "without common object methods" do
|
||||
subject(dbl) { Spectator::Double.new }
|
||||
|
||||
it "raises with undefined messages" do
|
||||
io = IO::Memory.new
|
||||
pp = PrettyPrint.new(io)
|
||||
aggregate_failures do
|
||||
expect { dbl.!=(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.!~(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.==(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.===(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.=~(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.class }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.dup }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.hash(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.hash }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.in?(42) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.in?(1, 2, 3) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.inspect }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.itself }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.not_nil! }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.pretty_inspect }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.pretty_inspect(io) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.pretty_print(pp) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.tap { nil } }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_json }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_json(io) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_pretty_json }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_pretty_json(io) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_s }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_s(io) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_yaml }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.to_yaml(io) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.try { nil } }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.object_id }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.same?(dbl) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
expect { dbl.same?(nil) }.to raise_error(Spectator::UnexpectedMessage, /mask/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
95
src/spectator/mocks/double.cr
Normal file
95
src/spectator/mocks/double.cr
Normal file
|
@ -0,0 +1,95 @@
|
|||
require "./unexpected_message"
|
||||
|
||||
module Spectator
|
||||
class Double(Messages)
|
||||
def initialize(**@messages : **Messages)
|
||||
end
|
||||
|
||||
# TODO: Define macro to redefine a type's method.
|
||||
# TODO: Better error for type mismatch
|
||||
macro finished
|
||||
# Object
|
||||
{% for meth in @type.superclass.superclass.methods %}
|
||||
{% if !meth.abstract? && !DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize) %}
|
||||
{% if meth.visibility != :public %}{{meth.visibility.id}}{% end %} def {{meth.receiver}}{{meth.name}}(
|
||||
{{meth.args.splat}}{% if !meth.args.empty? %}, {% end %}
|
||||
{% if meth.double_splat %}**{{meth.double_splat}}, {% end %}
|
||||
{% if meth.block_arg %}&{{meth.block_arg}}{% elsif meth.accepts_block? %}&{% end %}
|
||||
){% if meth.return_type %} : {{meth.return_type}}{% end %}{% if !meth.free_vars.empty? %} forall {{meth.free_vars.splat}}{% end %}
|
||||
\{% if type = Messages[{{meth.name.symbolize}}] %}
|
||||
{% if meth.return_type %}
|
||||
\{% if type <= {{meth.return_type}} %}
|
||||
@messages[{{meth.name.symbolize}}].as({{meth.return_type}})
|
||||
\{% else %}
|
||||
raise "Type mismatch {{meth.name}} : {{meth.return_type}}"
|
||||
\{% end %}
|
||||
{% else %}
|
||||
@messages[{{meth.name.symbolize}}]
|
||||
{% end %}
|
||||
\{% else %}
|
||||
raise UnexpectedMessage.new("Received unexpected message {{meth.name}} on double <TODO:NAME> (masking ancestor).")
|
||||
\{% end %}
|
||||
end
|
||||
{% end %}
|
||||
{% end %}
|
||||
|
||||
# Reference
|
||||
{% for meth in @type.superclass.methods %}
|
||||
{% if !meth.abstract? && !DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize) %}
|
||||
{% if meth.visibility != :public %}{{meth.visibility.id}}{% end %} def {{meth.receiver}}{{meth.name}}(
|
||||
{{meth.args.splat}}{% if !meth.args.empty? %}, {% end %}
|
||||
{% if meth.double_splat %}**{{meth.double_splat}}, {% end %}
|
||||
{% if meth.block_arg %}&{{meth.block_arg}}{% elsif meth.accepts_block? %}&{% end %}
|
||||
){% if meth.return_type %} : {{meth.return_type}}{% end %}{% if !meth.free_vars.empty? %} forall {{meth.free_vars.splat}}{% end %}
|
||||
\{% if type = Messages[{{meth.name.symbolize}}] %}
|
||||
{% if meth.return_type %}
|
||||
\{% if type <= {{meth.return_type}} %}
|
||||
@messages[{{meth.name.symbolize}}].as({{meth.return_type}})
|
||||
\{% else %}
|
||||
raise "Type mismatch {{meth.name}} : {{meth.return_type}}"
|
||||
\{% end %}
|
||||
{% else %}
|
||||
@messages[{{meth.name.symbolize}}]
|
||||
{% end %}
|
||||
\{% else %}
|
||||
raise UnexpectedMessage.new("Received unexpected message {{meth.name}} on double <TODO:NAME> (masking ancestor).")
|
||||
\{% end %}
|
||||
end
|
||||
{% end %}
|
||||
{% end %}
|
||||
|
||||
# Double
|
||||
{% for meth in @type.methods %}
|
||||
{% if !meth.abstract? && !DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize) %}
|
||||
{% if meth.visibility != :public %}{{meth.visibility.id}}{% end %} def {{meth.receiver}}{{meth.name}}(
|
||||
{{meth.args.splat}}{% if !meth.args.empty? %}, {% end %}
|
||||
{% if meth.double_splat %}**{{meth.double_splat}}, {% end %}
|
||||
{% if meth.block_arg %}&{{meth.block_arg}}{% elsif meth.accepts_block? %}&{% end %}
|
||||
){% if meth.return_type %} : {{meth.return_type}}{% end %}{% if !meth.free_vars.empty? %} forall {{meth.free_vars.splat}}{% end %}
|
||||
\{% if type = Messages[{{meth.name.symbolize}}] %}
|
||||
{% if meth.return_type %}
|
||||
\{% if type <= {{meth.return_type}} %}
|
||||
@messages[{{meth.name.symbolize}}].as({{meth.return_type}})
|
||||
\{% else %}
|
||||
raise "Type mismatch {{meth.name}} : {{meth.return_type}}"
|
||||
\{% end %}
|
||||
{% else %}
|
||||
@messages[{{meth.name.symbolize}}]
|
||||
{% end %}
|
||||
\{% else %}
|
||||
raise UnexpectedMessage.new("Received unexpected message {{meth.name}} on double <TODO:NAME> (masking ancestor).")
|
||||
\{% end %}
|
||||
end
|
||||
{% end %}
|
||||
{% end %}
|
||||
end
|
||||
|
||||
macro method_missing(call)
|
||||
\{% if Messages.keys.includes?({{call.name.symbolize}}.id) %}
|
||||
@messages[{{call.name.symbolize}}]
|
||||
\{% else %}
|
||||
raise UnexpectedMessage.new("Received unexpected message {{call.name}} on double <TODO:NAME>.")
|
||||
\{% end %}
|
||||
end
|
||||
end
|
||||
end
|
5
src/spectator/mocks/unexpected_message.cr
Normal file
5
src/spectator/mocks/unexpected_message.cr
Normal file
|
@ -0,0 +1,5 @@
|
|||
module Spectator
|
||||
# Exception raised by a mock or double when a message is received that have been.
|
||||
class UnexpectedMessage < Exception
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue