mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Add type capturing arguments
This commit is contained in:
parent
d7f8c2b958
commit
de7cd90d11
2 changed files with 231 additions and 0 deletions
162
spec/spectator/mocks/arguments_spec.cr
Normal file
162
spec/spectator/mocks/arguments_spec.cr
Normal file
|
@ -0,0 +1,162 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::Arguments do
|
||||
subject(arguments) do
|
||||
Spectator::Arguments.new(
|
||||
args: {42, "foo"},
|
||||
kwargs: {bar: "baz", qux: 123}
|
||||
)
|
||||
end
|
||||
|
||||
it "stores the arguments" do
|
||||
expect(arguments.args).to eq({42, "foo"})
|
||||
end
|
||||
|
||||
it "stores the keyword arguments" do
|
||||
expect(arguments.kwargs).to eq({bar: "baz", qux: 123})
|
||||
end
|
||||
|
||||
describe ".capture" do
|
||||
subject { Spectator::Arguments.capture(42, "foo", bar: "baz", qux: 123) }
|
||||
|
||||
it "stores the arguments and keyword arguments" do
|
||||
is_expected.to have_attributes(args: {42, "foo"}, kwargs: {bar: "baz", qux: 123})
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject { arguments.to_s }
|
||||
|
||||
it "formats the arguments" do
|
||||
is_expected.to eq("(42, \"foo\", bar: \"baz\", qux: 123)")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#==" do
|
||||
subject { arguments == other }
|
||||
|
||||
context "with equal arguments" do
|
||||
let(other) { arguments }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(other) do
|
||||
Spectator::Arguments.new(
|
||||
args: {123, :foo, "bar"},
|
||||
kwargs: {opt: "foobar"}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(other) do
|
||||
Spectator::Arguments.new(
|
||||
args: arguments.args,
|
||||
kwargs: {qux: 123, bar: "baz"}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(other) do
|
||||
Spectator::Arguments.new(
|
||||
args: arguments.args,
|
||||
kwargs: {bar: "baz"}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { pattern === arguments }
|
||||
|
||||
context "with equal arguments" do
|
||||
let(pattern) { arguments }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(pattern) do
|
||||
Spectator::Arguments.new(
|
||||
args: {123, :foo, "bar"},
|
||||
kwargs: {opt: "foobar"}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(pattern) do
|
||||
Spectator::Arguments.new(
|
||||
args: arguments.args,
|
||||
kwargs: {qux: 123, bar: "baz"}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(pattern) do
|
||||
Spectator::Arguments.new(
|
||||
args: arguments.args,
|
||||
kwargs: {bar: "baz"}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with matching types and regex" do
|
||||
let(pattern) do
|
||||
Spectator::Arguments.new(
|
||||
args: {Int32, /foo/},
|
||||
kwargs: {bar: String, qux: 123}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with different types and regex" do
|
||||
let(pattern) do
|
||||
Spectator::Arguments.new(
|
||||
args: {Symbol, /bar/},
|
||||
kwargs: {bar: String, qux: 42}
|
||||
)
|
||||
end
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
69
src/spectator/mocks/arguments.cr
Normal file
69
src/spectator/mocks/arguments.cr
Normal file
|
@ -0,0 +1,69 @@
|
|||
module Spectator
|
||||
# Arguments used in a method call.
|
||||
#
|
||||
# Can also be used to match arguments.
|
||||
# *T* must be a `Tuple` type representing the positional arguments.
|
||||
# *NT* must be a `NamedTuple` type representing the keyword arguments.
|
||||
class Arguments(T, NT)
|
||||
# Positional arguments.
|
||||
getter args : T
|
||||
|
||||
# Keyword arguments.
|
||||
getter kwargs : NT
|
||||
|
||||
# Creates arguments used in a method call.
|
||||
def initialize(@args : T, @kwargs : NT)
|
||||
end
|
||||
|
||||
# Constructs an instance from literal arguments.
|
||||
def self.capture(*args, **kwargs) : self
|
||||
new(args, kwargs)
|
||||
end
|
||||
|
||||
# Constructs a string representation of the arguments.
|
||||
def to_s(io : IO) : Nil
|
||||
io << '('
|
||||
|
||||
# Add the positional arguments.
|
||||
args.each_with_index do |arg, i|
|
||||
io << ", " if i > 0
|
||||
arg.inspect(io)
|
||||
end
|
||||
|
||||
# Add the keyword arguments.
|
||||
size = args.size + kwargs.size
|
||||
kwargs.each_with_index(args.size) do |k, v, i|
|
||||
io << ", " if 0 < i < size
|
||||
io << k << ": "
|
||||
v.inspect(io)
|
||||
end
|
||||
|
||||
io << ')'
|
||||
end
|
||||
|
||||
# Checks if this set of arguments and another are equal.
|
||||
def ==(other : Arguments)
|
||||
args == other.args && kwargs == other.kwargs
|
||||
end
|
||||
|
||||
# Checks if another set of arguments matches this set of arguments.
|
||||
def ===(other : Arguments)
|
||||
args === other.args && named_tuples_match?(kwargs, other.kwargs)
|
||||
end
|
||||
|
||||
# Checks if two named tuples match.
|
||||
#
|
||||
# Uses case equality (`===`) on every key-value pair.
|
||||
# NamedTuple doesn't have a `===` operator, even though Tuple does.
|
||||
private def named_tuples_match?(a : NamedTuple, b : NamedTuple)
|
||||
return false if a.size != b.size
|
||||
|
||||
a.each do |k, v|
|
||||
return false unless b.has_key?(k)
|
||||
return false unless v === b[k]
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue