Skip to content

Commit ecb055d

Browse files
author
Tim Perkins
committed
Add DocumentMatcher
This matcher allows expectations to be checked on the documentation for an exposure.
1 parent 7f76f68 commit ecb055d

File tree

5 files changed

+172
-1
lines changed

5 files changed

+172
-1
lines changed

README.markdown

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ it { is_expected.to represent(:dog).using(PetEntity) }
2727
it { is_expected.to represent(:cat).as(:kitty).using(PetEntity) }
2828

2929
it { is_expected.to represent(:name).with_documentation(type: String) }
30+
31+
it { is_expected.to document(:name).with(type: String, desc: 'Name of the person') }
32+
it { is_expected.to document(:name).type(String).desc('Name of the person') }
3033
```
3134

3235
## Support for Rspec 2.0.0

lib/grape_entity_matchers.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
require 'grape_entity_matchers/version'
22
require 'grape_entity_matchers/represent_matcher'
3+
require 'grape_entity_matchers/document_matcher'
34
require 'grape_entity_matchers/rspec_integration'
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
module GrapeEntityMatchers
2+
module DocumentMatcher
3+
def document(documentable)
4+
DocumentMatcher.new(documentable)
5+
end
6+
7+
class DocumentMatcher
8+
def initialize(documentable)
9+
@expected_documentable = documentable
10+
end
11+
12+
def description
13+
"ensure that #{@subject} documents the #{@expected_documentable} exposure"
14+
end
15+
16+
def matches?(subject)
17+
@subject = subject
18+
19+
has_documentation? && verify_documentation
20+
end
21+
22+
def type(type_value)
23+
@type = type_value
24+
self
25+
end
26+
27+
def required(required_value)
28+
@required = required_value
29+
self
30+
end
31+
32+
def desc(desc_value)
33+
@desc = desc_value
34+
self
35+
end
36+
37+
def default(default_value)
38+
@default = default_value
39+
self
40+
end
41+
42+
def values(values)
43+
@values = values
44+
self
45+
end
46+
47+
def with(documentation)
48+
@documentation = documentation
49+
self
50+
end
51+
52+
def failure_message
53+
"#{@subject} didn't document #{@expected_documentable} "\
54+
"as expected: #{expected_documentation}, got #{match_documentation}"
55+
end
56+
57+
def failure_message_when_negated
58+
message = "didn't expect #{@subject} to document #{@expected_documentable}"
59+
message << " with: #{expected_documentation}" unless expected_documentation.empty?
60+
message << ", got: #{actual_documentation}"
61+
end
62+
63+
private
64+
65+
def expected_documentation
66+
@documentation ||
67+
{
68+
type: @type,
69+
desc: @desc,
70+
required: @required,
71+
default: @default,
72+
values: @values
73+
}.compact
74+
end
75+
76+
def match_documentation
77+
if has_documentation?
78+
exposure[:documentation].slice(*expected_documentation.keys)
79+
end
80+
end
81+
82+
def actual_documentation
83+
exposure.try(:[], :documentation)
84+
end
85+
86+
def has_documentation?
87+
@subject.exposures.has_key?(@expected_documentable) &&
88+
exposure[:documentation]
89+
end
90+
91+
def exposure
92+
@subject.exposures[@expected_documentable]
93+
end
94+
95+
def verify_documentation
96+
if @documentation
97+
@documentation == exposure[:documentation]
98+
else
99+
expected_documentation == match_documentation
100+
end
101+
end
102+
end
103+
end
104+
end

lib/grape_entity_matchers/rspec_integration.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
RSpec.configure do |config|
44
require 'grape_entity_matchers/represent_matcher'
55
config.include GrapeEntityMatchers::RepresentMatcher
6-
end
6+
require 'grape_entity_matchers/document_matcher'
7+
config.include GrapeEntityMatchers::DocumentMatcher
8+
end
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
require 'spec_helper'
2+
require 'grape_entity'
3+
4+
describe GrapeEntityMatchers::DocumentMatcher do
5+
let(:documentation) do
6+
{
7+
type: String,
8+
desc: 'Some string',
9+
default: 'xyz',
10+
required: false,
11+
values: ['abc', 'xyz']
12+
}
13+
end
14+
before(:all) do
15+
class TestEntity < Grape::Entity
16+
expose :str, documentation: {
17+
type: String,
18+
desc: 'Some string',
19+
default: 'xyz',
20+
required: false,
21+
values: ['abc', 'xyz']
22+
}
23+
expose :no_doc
24+
end
25+
end
26+
27+
subject(:entity) { TestEntity }
28+
29+
context "ensure that the exposure matches the documentation" do
30+
it { is_expected.to document(:str).with(documentation) }
31+
end
32+
33+
context "ensure individual keys of documentation" do
34+
it { is_expected.to document(:str).type(String) }
35+
it { is_expected.not_to document(:str).type(Fixnum) }
36+
37+
it { is_expected.to document(:str).desc('Some string') }
38+
it { is_expected.not_to document(:str).desc('Some other string') }
39+
40+
it { is_expected.to document(:str).default('xyz') }
41+
it { is_expected.not_to document(:str).default('abc') }
42+
43+
it { is_expected.to document(:str).required(false) }
44+
it { is_expected.not_to document(:str).required(true) }
45+
46+
it { is_expected.to document(:str).values(['abc', 'xyz']) }
47+
it { is_expected.not_to document(:str).values(['foo', 'bar']) }
48+
end
49+
50+
context "ensure a combination of keys of documentation" do
51+
it { is_expected.to document(:str).type(String).desc('Some string') }
52+
end
53+
54+
context "ensure that an exposure is not documented" do
55+
it { is_expected.to_not document(:no_doc) }
56+
end
57+
58+
context "ensure that a specific documentation is not used" do
59+
it { is_expected.to_not document(:str).with(type: String, required: false) }
60+
end
61+
end

0 commit comments

Comments
 (0)