public
Fork of wycats/merb-core
Description: Merb Core: All you need. None you don't.
Homepage: http://www.merbivore.com
Clone URL: git://github.com/auser/merb-core.git
raycmorgan (author)
Sat Mar 15 21:23:26 -0700 2008
ezmobius (committer)
Wed Mar 19 12:20:49 -0700 2008
commit  130ee1ee30e08e23cd4563bce954ecacff88a5b3
tree    3040cdac5906c6a4c6c493a49d6e8a59bc6201ba
parent  ce659ee9d210df80d177d686c836a20d5585c00b
merb-core / lib / merb-core / test / matchers / view_matchers.rb
100644 293 lines (258 sloc) 7.835 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
module Merb::Test::Rspec::ViewMatchers
  class HaveSelector
 
    # ==== Parameters
    # expected<String>:: The string to look for.
    def initialize(expected)
      @expected = expected
    end
 
    # ==== Parameters
    # stringlike<Hpricot::Elem, StringIO, String>:: The thing to search in.
    #
    # ==== Returns
    # Boolean:: True if there was at least one match.
    def matches?(stringlike)
      @document = case stringlike
      when Hpricot::Elem
        stringlike
      when StringIO
        Hpricot.parse(stringlike.string)
      else
        Hpricot.parse(stringlike)
      end
      !@document.search(@expected).empty?
    end
 
    # ==== Returns
    # String:: The failure message.
    def failure_message
      "expected following text to match selector #{@expected}:\n#{@document}"
    end
 
    # ==== Returns
    # String:: The failure message to be displayed in negative matches.
    def negative_failure_message
      "expected following text to not match selector #{@expected}:\n#{@document}"
    end
  end
 
  class MatchTag
 
    # ==== Parameters
    # name<~to_s>:: The name of the tag to look for.
    # attrs<Hash>:: Attributes to look for in the tag (see below).
    #
    # ==== Options (attrs)
    # :content<String>:: Optional content to match.
    def initialize(name, attrs)
      @name, @attrs = name, attrs
      @content = @attrs.delete(:content)
    end
 
    # ==== Parameters
    # target<String>:: The string to look for the tag in.
    #
    # ==== Returns
    # Boolean:: True if the tag matched.
    def matches?(target)
      @errors = []
      unless target.include?("<#{@name}")
        @errors << "Expected a <#{@name}>, but was #{target}"
      end
      @attrs.each do |attr, val|
        unless target.include?("#{attr}=\"#{val}\"")
          @errors << "Expected #{attr}=\"#{val}\", but was #{target}"
        end
      end
      if @content
        unless target.include?(">#{@content}<")
          @errors << "Expected #{target} to include #{@content}"
        end
      end
      @errors.size == 0
    end
 
    # ==== Returns
    # String:: The failure message.
    def failure_message
      @errors[0]
    end
 
    # ==== Returns
    # String:: The failure message to be displayed in negative matches.
    def negative_failure_message
      "Expected not to match against <#{@name} #{@attrs.map{ |a,v| "#{a}=\"#{v}\"" }.join(" ")}> tag, but it matched"
    end
  end
 
  class NotMatchTag
 
    # === Parameters
    # attrs<Hash>:: A set of attributes that must not be matched.
    def initialize(attrs)
      @attrs = attrs
    end
 
    # ==== Parameters
    # target<String>:: The target to look for the match in.
    #
    # ==== Returns
    # Boolean:: True if none of the attributes were matched.
    def matches?(target)
      @errors = []
      @attrs.each do |attr, val|
        if target.include?("#{attr}=\"#{val}\"")
          @errors << "Should not include #{attr}=\"#{val}\", but was #{target}"
        end
      end
      @errors.size == 0
    end
 
    # ==== Returns
    # String:: The failure message.
    def failure_message
      @errors[0]
    end
  end
 
  class HasTag
 
    # ==== Parameters
    # tag<~to_s>:: The tag to look for.
    # attributes<Hash>:: Attributes for the tag (see below).
    def initialize(tag, attributes = {})
      @tag, @attributes = tag, attributes
      @id, @class = @attributes.delete(:id), @attributes.delete(:class)
    end
 
    # ==== Parameters
    # stringlike<Hpricot::Elem, StringIO, String>:: The thing to search in.
    # &blk:: An optional block for searching in child elements using with_tag.
    #
    # ==== Returns
    # Boolean:: True if there was at least one match.
    def matches?(stringlike, &blk)
      @document = case stringlike
      when Hpricot::Elem
        stringlike
      when StringIO
        Hpricot.parse(stringlike.string)
      else
        Hpricot.parse(stringlike)
      end
 
      if block_given?
        !@document.search(selector).select do |ele|
          begin
            blk.call(ele)
          rescue Spec::Expectations::ExpectationNotMetError
            false
          end
        end.empty?
      else
        !@document.search(selector).empty?
      end
    end
 
    # ==== Returns
    # String:: The complete selector for element queries.
    def selector
      @selector = "//#{@tag}#{id_selector}#{class_selector}"
      @selector << @attributes.map{|a, v| "[@#{a}=\"#{v}\"]"}.join
 
      @selector << @inner_has_tag.selector unless @inner_has_tag.nil?
 
      @selector
    end
 
    # ==== Returns
    # String:: ID selector for use in element queries.
    def id_selector
      "##{@id}" if @id
    end
 
    # ==== Returns
    # String:: Class selector for use in element queries.
    def class_selector
      ".#{@class}" if @class
    end
 
    # ==== Returns
    # String:: The failure message.
    def failure_message
      "expected following output to contain a #{tag_for_error} tag:\n#{@document}"
    end
 
    # ==== Returns
    # String:: The failure message to be displayed in negative matches.
    def negative_failure_message
      "expected following output to omit a #{tag_for_error} tag:\n#{@document}"
    end
    
    # ==== Returns
    # String:: The tag used in failure messages.
    def tag_for_error
      "#{inner_failure_message}<#{@tag}#{id_for_error}#{class_for_error}#{attributes_for_error}>"
    end
 
    # ==== Returns
    # String::
    # The failure message to be displayed in negative matches within the
    # have_tag block.
    def inner_failure_message
      "#{@inner_has_tag.tag_for_error} tag within a " unless @inner_has_tag.nil?
    end
 
    # ==== Returns
    # String:: ID for the error tag.
    def id_for_error
      " id=\"#{@id}\"" unless @id.nil?
    end
 
    # ==== Returns
    # String:: Class for the error tag.
    def class_for_error
      " class=\"#{@class}\"" unless @class.nil?
    end
 
    # ==== Returns
    # String:: Class for the error tag.
    def attributes_for_error
      @attributes.map{|a,v| " #{a}=\"#{v}\""}.join
    end
 
    # Search for a child tag within a have_tag block.
    #
    # ==== Parameters
    # tag<~to_s>:: The tag to look for.
    # attributes<Hash>:: Attributes for the tag (see below).
    def with_tag(name, attrs={})
      @inner_has_tag = HasTag.new(name, attrs)
    end
  end
 
  # ==== Parameters
  # name<~to_s>:: The name of the tag to look for.
  # attrs<Hash>:: Attributes to look for in the tag (see below).
  #
  # ==== Options (attrs)
  # :content<String>:: Optional content to match.
  #
  # ==== Returns
  # MatchTag:: A new match tag matcher.
  def match_tag(name, attrs={})
    MatchTag.new(name, attrs)
  end
 
  # ==== Parameters
  # attrs<Hash>:: A set of attributes that must not be matched.
  #
  # ==== Returns
  # NotMatchTag:: A new not match tag matcher.
  def not_match_tag(attrs)
    NotMatchTag.new(attrs)
  end
 
  # ==== Parameters
  # expected<String>:: The string to look for.
  #
  # ==== Returns
  # HaveSelector:: A new have selector matcher.
  def have_selector(expected)
    HaveSelector.new(expected)
  end
  alias_method :match_selector, :have_selector
 
  # RSpec matcher to test for the presence of tags.
  #
  # ==== Parameters
  # tag<~to_s>:: The name of the tag.
  # attributes<Hash>:: Tag attributes.
  #
  # ==== Returns
  # HasTag:: A new has tag matcher.
  #
  # ==== Examples
  # # Check for <div>
  # body.should have_tag("div")
  #
  # # Check for <span id="notice">
  # body.should have_tag("span", :id => :notice)
  #
  # # Check for <h1 id="foo" class="bar">
  # body.should have_tag(:h2, :class => "bar", :id => "foo")
  #
  # # Check for <div attr="val">
  # body.should have_tag(:div, :attr => :val)
  def have_tag(tag, attributes = {})
    HasTag.new(tag, attributes)
  end
 
  alias_method :with_tag, :have_tag
end