assert_xpath 0.4.2 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,254 @@
1
+ # CONSIDER split the patch in two for separate submissions
2
+
3
+ ##################################################################
4
+ ## eek eek ook ook patch to add directives to RDocage
5
+
6
+ require 'rdoc/rdoc'
7
+ require 'rdoc/markup/simple_markup'
8
+ require 'rdoc/markup/simple_markup/lines'
9
+ require 'rdoc/markup/simple_markup/fragments'
10
+ require 'rdoc/markup/simple_markup/to_html'
11
+
12
+ # note: RDoc task fails if transcluder not found
13
+
14
+ def find_method_contents(file_info, modool, method)
15
+ file_info.each do |top|
16
+ if mod = top.find_module_named(modool) and
17
+ symbol = mod.find_local_symbol(method)
18
+ return symbol.token_stream
19
+ end
20
+ end
21
+ return nil
22
+ end
23
+
24
+ module RubyToken
25
+ class Token
26
+ def to_html
27
+ html = CGI.escapeHTML(text)
28
+
29
+ if text.size == 1 and '!@#$%^&*(){}?+/=[]\\|.,"\'<>-_;:'.include?(text)
30
+ return "<strong>#{ html }</strong>"
31
+ else
32
+ return html
33
+ end
34
+ end
35
+ end
36
+
37
+ class TkCOMMENT; def to_html; '<em style="color: #666; font-size: 110%">' + super + '</em>' ; end; end
38
+ class TkKW; def to_html; '<span style="color: #990099">' + super + '</span>' ; end; end
39
+ class TkIDENTIFIER; def to_html; '<span style="color: #003399">' + super + '</span>' ; end; end
40
+ class TkSYMBOL ; def to_html; '<span style="color: #006600">' + super + '</span>' ; end; end
41
+ class TkOp; def to_html; '<strong>' + super + '</strong>' ; end; end
42
+ class TkSTRING; def to_html; '<span style="background-color: #ddffdd">' + super + '</span>' ; end; end
43
+
44
+ #<RubyToken::TkASSIGN:0xb7870368 @text="=", @char_no=11, @line_no=346>
45
+ #<RubyToken::TkTRUE:0xb786ddac @text="true", @char_no=19, @line_no=347, @name="true">
46
+ #<RubyToken::TkCOMMA:0xb786db7c @text=",", @char_no=23, @line_no=347>
47
+ #<RubyToken::TkfLBRACK:0xb786d2d0 @text="[", @char_no=30, @line_no=347>
48
+ #<RubyToken::TkRBRACK:0xb786c8d0 @text="]", @char_no=39, @line_no=347>
49
+ #<RubyToken::TkFALSE:0xb7868488 @text="false", @char_no=19, @line_no=349, @name="false">
50
+
51
+ end
52
+
53
+ module SM
54
+
55
+ class Line
56
+ PURE_HTML = :PURE_HTML
57
+ PURE_RUBY = :PURE_RUBY
58
+ TRANSCLUDE = :TRANSCLUDE
59
+ end
60
+
61
+ class PureHTML < Fragment
62
+ type_name Line::PURE_HTML
63
+ end
64
+
65
+ class PureRUBY < Fragment
66
+ type_name Line::PURE_RUBY
67
+ end
68
+
69
+ class Transclude < Fragment
70
+ type_name Line::TRANSCLUDE
71
+ end
72
+
73
+ class ToHtml
74
+ def accept_transclude(am, fragment)
75
+ if @context.context.parent and
76
+ (found = find_method_contents(@context.context.parent.in_files, *fragment.txt.split('#')))
77
+ @res << '<pre style="background-color: white">'
78
+ # to do: hilite syntax; make method name clickable
79
+ found.each_with_index do |tok, index|
80
+ next if 0 == index and tok.text =~ /^\#/
81
+ next if 1 == index and tok.text == "\n"
82
+ @res << tok.to_html
83
+ end
84
+ @res << '</pre>'
85
+ else
86
+ raise "missing transclusion: #{ fragment.inspect }"
87
+ @res << fragment.txt
88
+ end
89
+ end
90
+
91
+ def accept_pure_html(am, fragment)
92
+ @res << fragment.txt
93
+ end
94
+
95
+ def accept_pure_ruby(am, fragment)
96
+ @res << eval(fragment.txt)
97
+ end
98
+ end
99
+
100
+ class LineCollection
101
+ def accept(am, visitor)
102
+ visitor.start_accepting
103
+
104
+ @fragments.each do |fragment|
105
+ case fragment
106
+ when Verbatim
107
+ visitor.accept_verbatim(am, fragment)
108
+ when PureHTML
109
+ visitor.accept_pure_html(am, fragment)
110
+ when PureRUBY
111
+ visitor.accept_pure_ruby(am, fragment)
112
+ when Transclude
113
+ visitor.accept_transclude(am, fragment)
114
+ when Rule
115
+ visitor.accept_rule(am, fragment)
116
+ when ListStart
117
+ visitor.accept_list_start(am, fragment)
118
+ when ListEnd
119
+ visitor.accept_list_end(am, fragment)
120
+ when ListItem
121
+ visitor.accept_list_item(am, fragment)
122
+ when BlankLine
123
+ visitor.accept_blank_line(am, fragment)
124
+ when Heading
125
+ visitor.accept_heading(am, fragment)
126
+ when Paragraph
127
+ visitor.accept_paragraph(am, fragment)
128
+ end
129
+ end
130
+
131
+ visitor.end_accepting
132
+ end
133
+
134
+ end
135
+
136
+ class SimpleMarkup
137
+ private
138
+
139
+ def assign_types_to_lines(margin = 0, level = 0)
140
+
141
+ while line = @lines.next
142
+
143
+ if /^\s*%html/ === line.text then
144
+ line.text.sub!("%html","")
145
+ line.stamp( Line::PURE_HTML, level )
146
+ next
147
+ end
148
+
149
+ if /^\s*%transclude/ === line.text then
150
+ line.text.sub!("%transclude","")
151
+ line.stamp( Line::TRANSCLUDE, level )
152
+ next
153
+ end
154
+
155
+ if /^\s*%ruby/ === line.text then
156
+ line.text.sub!("%ruby","")
157
+ line.stamp( Line::PURE_RUBY, level )
158
+ next
159
+ end
160
+
161
+ if line.isBlank?
162
+ line.stamp(Line::BLANK, level)
163
+ next
164
+ end
165
+
166
+ # if a line contains non-blanks before the margin, then it must belong
167
+ # to an outer level
168
+
169
+ text = line.text
170
+
171
+ for i in 0...margin
172
+ if text[i] != SPACE
173
+ @lines.unget
174
+ return
175
+ end
176
+ end
177
+
178
+ active_line = text[margin..-1]
179
+
180
+ # Rules (horizontal lines) look like
181
+ #
182
+ # --- (three or more hyphens)
183
+ #
184
+ # The more hyphens, the thicker the rule
185
+ #
186
+
187
+ if /^(---+)\s*$/ =~ active_line
188
+ line.stamp(Line::RULE, level, $1.length-2)
189
+ next
190
+ end
191
+
192
+ # Then look for list entries. First the ones that have to have
193
+ # text following them (* xxx, - xxx, and dd. xxx)
194
+
195
+ if SIMPLE_LIST_RE =~ active_line
196
+
197
+ offset = margin + $1.length
198
+ prefix = $2
199
+ prefix_length = prefix.length
200
+
201
+ flag = case prefix
202
+ when "*","-" then ListBase::BULLET
203
+ when /^\d/ then ListBase::NUMBER
204
+ when /^[A-Z]/ then ListBase::UPPERALPHA
205
+ when /^[a-z]/ then ListBase::LOWERALPHA
206
+ else raise "Invalid List Type: #{self.inspect}"
207
+ end
208
+
209
+ line.stamp(Line::LIST, level+1, prefix, flag)
210
+ text[margin, prefix_length] = " " * prefix_length
211
+ assign_types_to_lines(offset, level + 1)
212
+ next
213
+ end
214
+
215
+
216
+ if LABEL_LIST_RE =~ active_line
217
+ offset = margin + $1.length
218
+ prefix = $2
219
+ prefix_length = prefix.length
220
+
221
+ next if handled_labeled_list(line, level, margin, offset, prefix)
222
+ end
223
+
224
+ # Headings look like
225
+ # = Main heading
226
+ # == Second level
227
+ # === Third
228
+ #
229
+ # Headings reset the level to 0
230
+
231
+ if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/
232
+ prefix_length = $1.length
233
+ prefix_length = 6 if prefix_length > 6
234
+ line.stamp(Line::HEADING, 0, prefix_length)
235
+ line.strip_leading(margin + prefix_length)
236
+ next
237
+ end
238
+
239
+ # If the character's a space, then we have verbatim text,
240
+ # otherwise
241
+
242
+ if active_line[0] == SPACE
243
+ line.strip_leading(margin) if margin > 0
244
+ line.stamp(Line::VERBATIM, level)
245
+ else
246
+ line.stamp(Line::PARAGRAPH, level)
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+ ## eek eek ook ook patch to add directives to RDocage
254
+ ##################################################################
metadata CHANGED
@@ -1,66 +1,96 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: assert_xpath
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.4.2
7
- date: 2008-04-13 00:00:00 -07:00
8
- summary: unit-test HTML at very high resolution
9
- require_paths:
10
- - lib
11
- email: phlip2005@gmail.com
12
- homepage: http://assertxpath.rubyforge.org/
13
- rubyforge_project: assertxpath
14
- description:
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: false
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.4.6
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Phlip
31
- files:
32
- - lib/assert_javascript.rb
33
- - lib/assert_xpath.rb~
34
- - lib/jsToXml.pl
35
- - lib/assert_xpath.rb
36
- test_files: []
37
-
38
- rdoc_options: []
39
-
40
- extra_rdoc_files: []
41
-
42
- executables: []
43
-
44
- extensions: []
45
-
46
- requirements: []
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
47
11
 
12
+ date: 2008-09-28 00:00:00 -07:00
13
+ default_executable:
48
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: assert2
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
49
25
  - !ruby/object:Gem::Dependency
50
26
  name: rubynode
27
+ type: :runtime
51
28
  version_requirement:
52
- version_requirements: !ruby/object:Gem::Version::Requirement
29
+ version_requirements: !ruby/object:Gem::Requirement
53
30
  requirements:
54
- - - ">"
31
+ - - ">="
55
32
  - !ruby/object:Gem::Version
56
- version: 0.0.0
33
+ version: "0"
57
34
  version:
58
35
  - !ruby/object:Gem::Dependency
59
- name: assert2
36
+ name: css_parser
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: libxml-ruby
47
+ type: :runtime
60
48
  version_requirement:
61
- version_requirements: !ruby/object:Gem::Version::Requirement
49
+ version_requirements: !ruby/object:Gem::Requirement
62
50
  requirements:
63
- - - ">"
51
+ - - ">="
64
52
  - !ruby/object:Gem::Version
65
- version: 0.0.0
53
+ version: "0"
66
54
  version:
55
+ description:
56
+ email: phlip2005@gmail.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files: []
62
+
63
+ files:
64
+ - lib/assert_css.rb
65
+ - lib/jsToXml.pl
66
+ - lib/rdoc_patch.rb
67
+ - lib/assert_xpath.rb
68
+ - lib/assert_javascript.rb
69
+ has_rdoc: false
70
+ homepage: http://assertxpath.rubyforge.org/
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
88
+ requirements: []
89
+
90
+ rubyforge_project: assertxpath
91
+ rubygems_version: 1.2.0
92
+ signing_key:
93
+ specification_version: 2
94
+ summary: assert_xpath and deny_xpath call assert_ and deny_tag_id
95
+ test_files: []
96
+
@@ -1,997 +0,0 @@
1
- require 'rexml/document'
2
- require 'stringio'
3
- require 'libxml' # FIXME soften that requirement!
4
-
5
- RAILS_ENV = ENV.fetch('RAILS_ENV', 'test') unless defined?(RAILS_ENV)
6
- AFE = Test::Unit::AssertionFailedError unless defined?(AFE)
7
-
8
- =begin
9
- #:stopdoc:
10
- # "We had so much fun robbing the bank we forgot to take the money"
11
- #
12
- # ERGO comic book: programmers hunting bugs portrayed as big game hunters in jungle
13
-
14
- # ERGO use length not size
15
-
16
- # ERGO complain to ZenTest forum that
17
- # assert_in_epsilon should not blot out
18
- # its internal message if you add an external one
19
- - test_zentest_assertions should use assert_raise_message
20
- - we should use assert_include more
21
- - use util_capture more!
22
- - use Test::Rails::ControllerTestCase & HelperTestCase
23
- - use all the assertions in ViewTest (and compete!)
24
- - tell ZT their view assertions should nest
25
- - take target name out of render calls if the test case name is correct!
26
- - use path_parameters to override
27
- - use the LayoutsController dummy object trick!
28
- - use named routes more!
29
-
30
- # ERGO learn FormEncodedPairParser
31
- # ERGO RDoc a blog entry
32
- # ERGO write deny_match, and make it work correctly!!
33
- # ERGO link from Hpricot references to real Hpricot verbiage
34
- # ERGO <tt> -> <code> in RDoc!!
35
- # ERGO assert_xpath is nothing but a call to assert_any_xpath
36
- # ERGO two %transclude directives in a row should work
37
- # ERGO document, redundantly, that @xdoc always has bequeathed_attributes
38
- # ERGO complain to RDoc maintainers that {}[] targets the current frame!
39
- # monkey-patch thereof
40
- # ERGO link out to REXML::Element
41
- # ERGO how to RDoc format the sample for indent_xml etc?
42
- # ERGO how to syntax hilite the sample for indent_xml etc?
43
- # ERGO cross links in sample code
44
- # ERGO back RDoc with complete source
45
- # ERGO links from RDoc file reports in their contents
46
- # ERGO is search{} defined in terms of assert_any_xpath??
47
- # ERGO get Hpricot::search going for self-or-descendent, and take out all Hpricot::Doc cruft!
48
- # ERGO does Hpricot#Doc[] or #Elem[] conflict with anything?
49
- # ERGO merge the common bequeathed attributes into one module
50
- # indent_xml should find a system built-into Hpricot?
51
- #:startdoc:
52
- =end
53
-
54
-
55
- =begin rdoc
56
- See: http://assertxpath.rubyforge.org/
57
-
58
- %html <pre>
59
- ___________________________
60
- # __/ >tok tok tok< \
61
- #< <%< <__ assert_xpath reads XHTML |
62
- # (\\= | and queries its details! |
63
- # | ---------------------------
64
- #===={===
65
- #
66
- %html </pre>
67
-
68
- =end
69
-
70
-
71
- module AssertXPath
72
-
73
- module CommonXPathExtensions #:nodoc:
74
-
75
- def symbolic?(index)
76
- return index.to_s if (index.kind_of? String or index.kind_of? Symbol)
77
- end
78
-
79
- def[](index)
80
- if symbol = symbolic?(index)
81
- return attributes[symbol] if attributes.has_key? symbol
82
- raise_magic_member_not_found(symbol, caller)
83
- end
84
-
85
- return super # ERGO test this works?
86
- end
87
-
88
- def raise_magic_member_not_found(symbol, whats_caller_ERGO)
89
- raise AFE, # ERGO merge with other raiser(s)
90
- "missing attribute: `#{symbol}` in " +
91
- "<#{ name } #{ attributes.keys.join(' ') }>",
92
- whats_caller_ERGO
93
- end
94
-
95
- def identifiable?(str) # ERGO self. ?
96
- return str =~ /^ [[:alpha:]] [[:alnum:]_]* $/ix
97
- end # ERGO simplify??
98
-
99
- # ERGO mock the YarWiki and run its tests locally!!!
100
-
101
- def tribute(block)
102
- stash = {} # put back the ones we changed!
103
-
104
- if block
105
- varz = instance_variables
106
-
107
- attributes.each do |key, value|
108
- if identifiable?(key) # deal if the key ain't a valid variable
109
- key = "@#{ key }"
110
- stash[key] = instance_variable_get(key) if varz.include?(key)
111
- #p stash[key]
112
- instance_variable_set key, value
113
- end
114
- end
115
-
116
- return instance_eval(&block)
117
- end
118
- ensure # put them back!
119
- stash.each{|key, value| instance_variable_set(key, value) }
120
- end # this utterly sick convenience helps Ruby {@id} look like XPathic [@id]
121
-
122
- end
123
-
124
- # ERGO document me
125
- def drill(&block)
126
- if block
127
- # ERGO harmonize with bang! version
128
- # ERGO deal if the key ain't a valid variable
129
-
130
- unless tribute(block) # ERGO pass in self (node)?
131
- sib = self
132
- nil while (sib = sib.next_sibling) and sib.node_type != :element
133
- p sib # ERGO do tests ever get here?
134
- q = sib and _bequeath_attributes(sib).drill(&block)
135
- return sib if q
136
- raise Test::Unit::AssertionFailedError.new("can't find beyond <#{xpath}>")
137
- end
138
- end
139
-
140
- return self
141
- # ERGO if block returns false/nil, find siblings until it passes.
142
- # throw a test failure if it don't.
143
- # ERGO axis concept
144
- end
145
-
146
- end
147
-
148
- # ERGO node.descendant{ @type == 'text' and @id == 'foo' }.value
149
- # ERGO node..a_descendant - overload ..
150
-
151
- def _bequeath_attributes(node) #:nodoc:
152
- return node if node.kind_of?(::Hpricot::Elem) or node.kind_of?(::Hpricot::Doc)
153
- # ERGO shouldn't this be in a stinkin' module??
154
- # ERGO SIMPLER!!
155
- # ERGO document me
156
- def node.drill(&block)
157
- if block
158
- # ERGO harmonize with bang! version
159
- # ERGO deal if the key ain't a valid variable
160
-
161
- unless tribute(block) # ERGO pass in self (node)?
162
- sib = self
163
- nil while (sib = sib.next_sibling) and sib.node_type != :element
164
- q = sib and _bequeath_attributes(sib).drill(&block)
165
- return sib if q
166
- raise Test::Unit::AssertionFailedError.new("can't find beyond <#{ xpath }>")
167
- end
168
- end
169
-
170
- return self
171
- # ERGO if block returns false/nil, find siblings until it passes.
172
- # throw a test failure if it don't.
173
- # ERGO axis concept
174
- end
175
-
176
- return node # ERGO use this return value
177
- end # ERGO is _ a good RPP for a "pretend private"?
178
-
179
-
180
- module AssertXPath
181
-
182
- Element = ::REXML::Element unless defined?(Element) #:nodoc:
183
-
184
- class XmlHelper #:nodoc:
185
- def libxml? ; false end # this is not a 'downcast' (bad in OO)
186
- def rexml? ; false end # becase diverse libraries are a "boundary"
187
- def hpricot? ; false end # situation. We can't control their contents!
188
- end
189
-
190
- class HpricotHelper < XmlHelper #:nodoc:
191
- def hpricot? ; true end
192
- def symbol_to_xpath(tag) tag.to_s end
193
- def assert_xml(suite, *args, &block)
194
- return suite.assert_hpricot(*args, &block)
195
- end
196
- end
197
-
198
- class LibxmlHelper < XmlHelper #:nodoc:
199
- def libxml? ; true end
200
- def symbol_to_xpath(tag) "descendant-or-self::#{tag}" end
201
- def assert_xml(suite, *args, &block)
202
- return suite.assert_libxml(*args, &block)
203
- end
204
- end
205
-
206
- class RexmlHelper < XmlHelper #:nodoc:
207
- def rexml? ; true end
208
- def symbol_to_xpath(tag) ".//#{tag}" end
209
- def assert_xml(suite, *args, &block)
210
- return suite.assert_rexml(*args, &block)
211
- end
212
- end
213
-
214
- # Subsequent +assert_xml+ calls will use
215
- # Hpricot[http://code.whytheluckystiff.net/hpricot/].
216
- # (Alternately,
217
- # +assert_hpricot+ will run one assertion in Hpricot mode.)
218
- # Put +invoke_hpricot+ into +setup+() method, to
219
- # run entire suites in this mode. These test cases
220
- # explore some differences between the two assertion systems:
221
- # %transclude AssertXPathSuite#test_assert_long_xpath
222
- #
223
- def invoke_hpricot
224
- @xdoc = nil
225
- @helper = HpricotHelper.new
226
- end
227
-
228
- # Subsequent +assert_xml+ calls will use
229
- # LibXML[http://libxml.rubyforge.org/].
230
- # (Alternately,
231
- # +assert_libxml+ will run one assertion in Hpricot mode.)
232
- # Put +invoke_libxml+ into +setup+() method, to
233
- # run entire suites in this mode.
234
- #
235
- def invoke_libxml(favorite_flavor = :html)
236
- @_favorite_flavor = favorite_flavor
237
- @xdoc = nil
238
- @helper = LibxmlHelper.new
239
- end
240
-
241
- def _doc_type # ERGO document all these!
242
- { :html => '<!DOCTYPE HTML PUBLIC ' +
243
- '"-//W3C//DTD HTML 4.01 Transitional//EN" '+
244
- '"http://www.w3.org/TR/html4/loose.dtd">',
245
- :xhtml => '<!DOCTYPE html PUBLIC ' +
246
- '"-//W3C//DTD XHTML 1.0 Transitional//EN" ' +
247
- '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >',
248
- :xml => nil
249
- }.freeze
250
- end
251
- private :_doc_type
252
-
253
- # ERGO what happens to assert_js_replace_html bearing entities??
254
-
255
- # Subsequent +assert_xml+ calls will use REXML. See
256
- # +invoke_hpricot+ to learn the various differences between the
257
- # two systems
258
- def invoke_rexml
259
- @xdoc = nil
260
- @helper = RexmlHelper.new
261
- end
262
-
263
- # %html <a name='assert_xml'></a>
264
- #
265
- # Prepare XML for assert_xpath <em>et al</em>
266
- # * +xml+ - optional string containing XML. Without it, we read <code>@response.body</code>
267
- # * <code>xpath, diagnostic, block</code> - optional arguments passed to +assert_xpath+
268
- # Sets and returns the new secret <code>@xdoc</code> REXML::Element root
269
- # call-seq:
270
- # assert_xml(xml = @response.body <em>[, assert_xpath arguments]</em>) -> @xdoc, or assert_xpath's return value
271
- #
272
- # Assertions based on +assert_xpath+ will call this automatically if
273
- # the secret <code>@xdoc</code> is +nil+. This implies we may freely call
274
- # +assert_xpath+ after any method that populates <code>@response.body</code>
275
- # -- if <code>@xdoc</code> is +nil+. When in doubt, call +assert_xml+ explicitly
276
- #
277
- # +assert_xml+ also translates the contents of +assert_select+ nodes. Use this to
278
- # bridge assertions from one system to another. For example:
279
- #
280
- # Returns the first node in the XML
281
- #
282
- # Examples:
283
- # assert_select 'div#home_page' do |home_page|
284
- # assert_xml home_page # <-- calls home_page.to_s
285
- # assert_xpath ".//img[ @src = '#{newb.image_uri(self)}' ]"
286
- # deny_tag_id :form, :edit_user
287
- # end
288
- #
289
- # %transclude AssertXPathSuite#test_assert_long_sick_expression
290
- # See: AssertXPathSuite#test_assert_xml_drill
291
- #
292
- def assert_xml(*args, &block)
293
- using :libxml? # prop-ulates @helper
294
- return @helper.assert_xml(self, *args, &block)
295
- end # ERGO take out the rescue nil!, and pass the diagnostic thru
296
-
297
- # Processes a string of text, or the hidden <code>@response.body</code>,
298
- # using REXML, and sets the hidden <code>@xdoc</code> node. Does
299
- # not depend on, or change, the values of +invoke_hpricot+, +invoke_libxml+,
300
- # or +invoke_rexml+
301
- #
302
- # Example:
303
- # %transclude AssertXPathSuite#test_assert_rexml
304
- #
305
- def assert_rexml(*args, &block)
306
- contents = (args.shift || @response.body).to_s
307
- # ERGO benchmark these things
308
-
309
- contents.gsub!('\\\'', '&apos;')
310
- contents.gsub!('//<![CDATA[<![CDATA[', '')
311
- contents.gsub!('//<![CDATA[', '')
312
- contents.gsub!('//]]>', '')
313
- contents.gsub!('//]>', '')
314
- contents.gsub!('//]]', '')
315
- contents.gsub!('//]', '')
316
-
317
- begin
318
- @xdoc = REXML::Document.new(contents)
319
- rescue REXML::ParseException => e
320
- raise e unless e.message =~ /attempted adding second root element to document/
321
- @xdoc = REXML::Document.new("<xhtml>#{ contents }</xhtml>")
322
- end
323
-
324
- _bequeath_attributes(@xdoc)
325
- assert_xpath(*args, &block) if args != []
326
- return (assert_xpath('/*') rescue nil) if @xdoc
327
- end
328
-
329
- # Temporarily sets the validation type to :xml, :html, or :xhtml
330
- #
331
- def validate_as(type) # FIXME use or lose this
332
- @_favorite_flavor, formerly = type, @_favorite_flavor
333
- yield
334
- ensure
335
- @_favorite_flavor = type
336
- end # ERGO more documentation!
337
-
338
- def assert_libxml(*args, &block)
339
- xml = args.shift || @xdoc || @response.body
340
- xhtml = xml.to_s
341
-
342
- # CONSIDER fix this like at the source??
343
- xhtml.gsub!('<![CDATA[>', '')
344
- xhtml.gsub!('<![CDATA[', '')
345
- xhtml.gsub!('//]]]]>', '')
346
- xhtml.gsub!(']]>', '')
347
-
348
- if xhtml !~ /^\<\!DOCTYPE\b/ and xhtml !~ /\<\?xml\b/
349
- xhtml = _doc_type[@_favorite_flavor || :html] + "\n" + xhtml if _doc_type[@_favorite_flavor]
350
- end # ERGO document we pass HTML level into invoker
351
-
352
- if xhtml.index('<?xml version="1" standalone="yes"?>') == 0
353
- xhtml.gsub!('<?xml version="1" standalone="yes"?>', '')
354
- xhtml.strip! # ERGO what is libxml's problem with that line???
355
- end
356
-
357
- # # FIXME blog that libxml will fully validate your ass...
358
-
359
- xp = xhtml =~ /\<\!DOCTYPE/ ? XML::HTMLParser.new() : XML::Parser.new()
360
- xhtml = '<xml/>' unless xhtml.any?
361
- xp.string = xhtml
362
- # FIXME blog we don't work with libxml-ruby 3.8.4
363
- # XML::Parser.default_load_external_dtd = false
364
- XML::Parser.default_pedantic_parser = false # FIXME optionalize that
365
-
366
- #what? xp
367
- doc = xp.parse
368
- #what? doc
369
- #puts doc.debug_dump
370
- @xdoc = doc.root
371
- # @xdoc.namespace ||= XML::NS.new('')
372
-
373
- #pp (@xdoc.root.public_methods - public_methods).sort
374
- return assert_xpath(*args, &block) if args.length > 0
375
- return @xdoc
376
- end
377
-
378
- def using(kode)
379
- @helper ||= RexmlHelper.new # ERGO escallate this!
380
- return @helper.send(kode)
381
- end
382
-
383
- # FIXME test that the helper system withstands this effect:
384
- # ""
385
-
386
- # %html <a name='assert_hpricot'></a>
387
- #
388
- # This parses one XML string using Hpricot, so subsequent
389
- # calls to +assert_xpath+ will use Hpricot expressions.
390
- # This method does not depend on +invoke_hpricot+, and
391
- # subsequent test cases will run in their suite's mode.
392
- #
393
- # Example:
394
- # %transclude AssertXPathSuite#test_assert_hpricot
395
- #
396
- # See also: assert_hpricot[http://www.oreillynet.com/onlamp/blog/2007/08/assert_hpricot_1.html]
397
- #
398
- def assert_hpricot(*args, &block)
399
- xml = args.shift || @xdoc || @response.body ## ERGO why @xdoc??
400
- # ERGO document that callseq!
401
- require 'hpricot'
402
- @xdoc = Hpricot(xml.to_s) # ERGO take that to_s out of all callers
403
- return assert_xpath(*args, &block) if args.length > 0
404
- return @xdoc
405
- end # ERGO reasonable error message if ill-formed
406
-
407
- # ENCORE Bus to Julian! (-;
408
- # ERGO why %html <a name='assert_xpath' /> screws up?
409
-
410
- # %html <a name='assert_xpath'></a>
411
- #
412
- # Return the first XML node matching a query string. Depends on +assert_xml+
413
- # to populate our secret internal REXML::Element, <code>@xdoc</code>
414
- # * +xpath+ - a query string describing a path among XML nodes.
415
- # See: {XPath Tutorial Roundup}[http://krow.livejournal.com/523993.html]
416
- # * +diagnostic+ - optional string to add to failure message
417
- # * <code>block|node|</code> - optional block containing assertions, based on +assert_xpath+,
418
- # which operate on this node as the XPath '.' current +node+
419
- # Returns the obtained REXML::Element +node+
420
- #
421
- # Examples:
422
- #
423
- # render :partial => 'my_partial'
424
- #
425
- # assert_xpath '/table' do |table|
426
- # assert_xpath './/p[ @class = "brown_text" ]/a' do |a|
427
- # assert_equal user.login, a.text # <-- native <code>REXML::Element#text</code> method
428
- # assert_match /\/my_name$/, a[:href] # <-- attribute generated by +assert_xpath+
429
- # end
430
- # assert_equal "ring_#{ring.id}", table.id! # <-- attribute generated by +assert_xpath+, escaped with !
431
- # end
432
- #
433
- # %transclude AssertXPathSuite#test_assert_xpath
434
- #
435
- # See: AssertXPathSuite#test_indent_xml,
436
- # {XPath Checker}[https://addons.mozilla.org/en-US/firefox/addon/1095]
437
- #
438
- def assert_xpath(xpath, diagnostic = nil, &block)
439
- # return assert_any_xpath(xpath, diagnostic) {
440
- # block.call(@xdoc) if block
441
- # true
442
- # }
443
- stash_xdoc do
444
- xpath = symbol_to_xpath(xpath)
445
- node = @xdoc.search(xpath).first
446
- @xdoc = node || flunk_xpath(diagnostic, "should find xpath <#{_esc xpath}>")
447
- @xdoc = _bequeath_attributes(@xdoc)
448
- block.call(@xdoc) if block # ERGO tribute here?
449
- return @xdoc
450
- end
451
- end
452
-
453
- # FIXME assert_js_argument(2) gotta return nill for nada
454
-
455
- # Negates +assert_xpath+. Depends on +assert_xml+
456
- #
457
- # Examples:
458
- # assert_tag_id :td, :object_list do
459
- # assert_xpath "table[ position() = 1 and @id = 'object_#{object1.id}' ]"
460
- # deny_xpath "table[ position() = 2 and @id = 'object_#{object2.id}' ]"
461
- # end # find object1 is still displayed, but object2 is not in position 2
462
- #
463
- # %transclude AssertXPathSuite#test_deny_xpath
464
- #
465
- def deny_xpath(xpath, diagnostic = nil)
466
- @xdoc or assert_xml
467
- xpath = symbol_to_xpath(xpath)
468
-
469
- @xdoc.search(xpath).first and
470
- flunk_xpath(diagnostic, "should not find: <#{_esc xpath}>")
471
- end
472
-
473
- # Search nodes for a matching XPath whose <code>AssertXPath::Element#inner_text</code> matches a Regular Expression. Depends on +assert_xml+
474
- # * +xpath+ - a query string describing a path among XML nodes.
475
- # See: {XPath Tutorial Roundup}[http://krow.livejournal.com/523993.html]
476
- # * +matcher+ - optional Regular Expression to test node contents
477
- # * +diagnostic+ - optional string to add to failure message
478
- # * <code>block|node|</code> - optional block called once per match.
479
- # If this block returns a value other than +false+ or +nil+,
480
- # assert_any_xpath stops looping and returns the current +node+
481
- #
482
- # Example:
483
- # %transclude AssertXPathSuite#test_assert_any_xpath
484
- #
485
- def assert_any_xpath(xpath, matcher = nil, diagnostic = nil, &block)
486
- matcher ||= //
487
- block ||= lambda{ true }
488
- found_any = false
489
- found_match = false
490
- xpath = symbol_to_xpath(xpath)
491
-
492
- stash_xdoc do
493
- #assert_xpath xpath, diagnostic
494
-
495
- if !using(:rexml?)
496
- @xdoc.search(xpath) do |@xdoc|
497
- found_any = true
498
-
499
- if @xdoc.inner_text =~ matcher
500
- found_match = true
501
- _bequeath_attributes(@xdoc)
502
- return @xdoc if block.call(@xdoc)
503
- # note we only exit block if block.nil? or call returns false
504
- end
505
- end
506
- else # ERGO merge!
507
- @xdoc.each_element(xpath) do |@xdoc|
508
- found_any = true
509
-
510
- if @xdoc.inner_text =~ matcher
511
- found_match = true
512
- _bequeath_attributes(@xdoc)
513
- return @xdoc if block.call(@xdoc)
514
- # note we only exit block if block.nil? or call returns false
515
- end
516
- end
517
- end
518
- end
519
-
520
- found_any or
521
- flunk_xpath(diagnostic, "should find xpath <#{_esc xpath}>")
522
-
523
- found_match or
524
- flunk_xpath(
525
- diagnostic,
526
- "can find xpath <#{_esc xpath}> but can't find pattern <?>",
527
- matcher
528
- )
529
- end
530
-
531
- # Negates +assert_any_xpath+. Depends on +assert_xml+
532
- #
533
- # * +xpath+ - a query string describing a path among XML nodes. This
534
- # must succeed - use +deny_xpath+ for simple queries that must fail
535
- # * +matcher+ - optional Regular Expression to test node contents. If +xpath+ locates multiple nodes,
536
- # this pattern must fail to match each node to pass the assertion.
537
- # * +diagnostic+ - optional string to add to failure message
538
- #
539
- # Contrived example:
540
- # assert_xml '<heathrow><terminal>5</terminal><lean>methods</lean></heathrow>'
541
- #
542
- # assert_raise_message Test::Unit::AssertionFailedError,
543
- # /all xpath.*\.\/\/lean.*not have.*methods/ do
544
- # deny_any_xpath :lean, /methods/
545
- # end
546
- #
547
- # deny_any_xpath :lean, /denver/
548
- #
549
- # See: AssertXPathSuite#test_deny_any_xpath,
550
- # {assert_raise (on Ruby) - Don't Just Say "No"}[http://www.oreillynet.com/onlamp/blog/2007/07/assert_raise_on_ruby_dont_just.html]
551
- #
552
- def deny_any_xpath(xpath, matcher, diagnostic = nil)
553
- @xdoc or assert_xml
554
- xpath = symbol_to_xpath(xpath)
555
-
556
- assert_any_xpath xpath, nil, diagnostic do |node|
557
- if node.inner_text =~ matcher
558
- flunk_xpath(
559
- diagnostic,
560
- "all xpath <#{_esc xpath}> nodes should not have pattern <?>",
561
- matcher
562
- )
563
- end
564
- end
565
- end
566
-
567
- # FIXME @helper -> @_helper
568
-
569
- # Wraps the common idiom <code>assert_xpath('descendant-or-self::./<em>my_tag</em>[ @id = "<em>my_id</em>" ]')</code>. Depends on +assert_xml+
570
- # * +tag+ - an XML node name, such as +div+ or +input+.
571
- # If this is a <code>:symbol</code>, we prefix "<code>.//</code>"
572
- # * +id+ - string, symbol, or hash identifying the node. ids must not contain punctuation
573
- # * +diagnostic+ - optional string to add to failure message
574
- # * <code>block|node|</code> - optional block containing assertions, based on
575
- # +assert_xpath+, which operate on this node as the XPath '.' current node.
576
- # Returns the obtained REXML::Element +node+
577
- #
578
- # Examples:
579
- #
580
- # assert_tag_id '/span/div', "audience_#{ring.id}" do
581
- # assert_xpath 'table/tr/td[1]' do |td|
582
- # #...
583
- # assert_tag_id :form, :for_sale
584
- # end
585
- # end
586
- #
587
- # %transclude AssertXPathSuite#test_assert_tag_id_and_tidy
588
- #
589
- # %transclude AssertXPathSuite#test_assert_tag_id
590
- #
591
- def assert_tag_id(tag, id = {}, diagnostic = nil, diagnostic2 = nil, &block)
592
- # if id is not a hash, diagnostic might be a hash too!
593
- # CONSIDER upgrade assert_tag_id to use each_element_with_attribute
594
- assert_xpath build_xpath(tag, id, diagnostic), diagnostic2 || diagnostic, &block
595
- end # NOTE: ids may not contain ', so we are delimiter-safe
596
-
597
- # Negates +assert_tag_id+. Depends on +assert_xml+
598
- #
599
- # Example - see: +assert_xml+
600
- #
601
- # See: +assert_tag_id+
602
- #
603
- def deny_tag_id(tag, id, diagnostic = nil, diagnostic2 = nil)
604
- deny_xpath build_xpath(tag, id, diagnostic), diagnostic2 || diagnostic
605
- end
606
-
607
- # Pretty-print a REXML::Element or Hpricot::Elem
608
- # * +doc+ - optional element. Defaults to the current +assert_xml+ document
609
- # returns: string with indented XML
610
- #
611
- # Use this while developing a test case, to see what
612
- # the current <code>@xdoc</code> node contains (as populated by +assert_xml+ and
613
- # manipulated by +assert_xpath+ <em>et al</em>)
614
- #
615
- # For example:
616
- # assert_javascript 'if(x == 42) answer_great_question();'
617
- #
618
- # assert_js_if /x.*42/ do
619
- # puts indent_xml # <-- temporary statement to see what to assert next!
620
- # end
621
- #
622
- # See: AssertXPathSuite#test_indent_xml
623
- #
624
- def indent_xml(doc = @xdoc || assert_xml)
625
- if doc.kind_of?(Hpricot::Elem) or doc.kind_of?(Hpricot::Doc)
626
- zdoc = doc
627
- doc = REXML::Document.new(doc.to_s.strip) rescue nil
628
- unless doc # Hpricot didn't well-formify the HTML!
629
- return zdoc.to_s # note: not indented, but good enough for error messages
630
- end
631
- end
632
-
633
- # require 'rexml/formatters/default'
634
- # bar = REXML::Formatters::Pretty.new
635
- # out = String.new
636
- # bar.write(doc, out)
637
- # return out
638
-
639
- return doc.to_s # ERGO reconcile with 1.8.6.111!
640
-
641
- x = StringIO.new
642
- doc.write(x, 2)
643
- return x.string # CONSIDER does REXML have a simpler way?
644
- end
645
-
646
- # %html <a name='assert_tidy'></a>
647
- # Thin wrapper on the Tidy command line program (the one released 2005 September)
648
- # * +messy+ - optional string containing messy HTML. Defaults to <code>@response.body</code>.
649
- # * +verbosity+ - optional noise level. Defaults to <code>:noisy</code>, which
650
- # reports most errors. :verbose reports all information, and other value
651
- # will repress all of Tidy's screams of horror regarding the quality of your HTML.
652
- # The resulting XHTML loads into +assert_xml+. Use this to retrofit +assert_xpath+ tests
653
- # to less-than-pristine HTML.
654
- #
655
- # +assert_tidy+ obeys +invoke_rexml+ and +invoke_hpricot+, to
656
- # select its HTML parser
657
- #
658
- # Examples:
659
- #
660
- # get :adjust, :id => transaction.id # <-- fetches ill-formed HTML
661
- # assert_tidy @response.body, :quiet # <-- upgrades it to well-formed
662
- # assert_tag_id '//table', :payment_history do # <-- sees good XML
663
- # #...
664
- # end
665
- #
666
- # %transclude AssertXPathSuite#test_assert_tag_id_and_tidy
667
- #
668
- def assert_tidy(messy = @response.body, verbosity = :noisy)
669
- scratch_html = RAILS_ROOT + '/tmp/scratch.html'
670
- # CONSIDER a railsoid tmp file system?
671
- # CONSIDER yield to something to respond to errors?
672
- File.open(scratch_html, 'w'){|f| f.write(messy) }
673
- gripes = `tidy -eq #{scratch_html} 2>&1`
674
- gripes.split("\n")
675
-
676
- # TODO kvetch about client_input_channel_req: channel 0 rtype keepalive@openssh.com reply 1
677
-
678
- puts gripes if verbosity == :verbose
679
-
680
- puts gripes.reject{|g|
681
- g =~ / - Info\: / or
682
- g =~ /Warning\: missing \<\!DOCTYPE\> declaration/ or
683
- g =~ /proprietary attribute/ or
684
- g =~ /lacks "(summary|alt)" attribute/
685
- } if verbosity == :noisy
686
-
687
- assert_xml `tidy -wrap 1001 -asxhtml #{ scratch_html } 2>/dev/null`
688
- # CONSIDER that should report serious HTML deformities
689
- end # CONSIDER how to tidy <% escaped %> eRB code??
690
-
691
- # FIXME write a plugin for cruisecontrol.rb
692
- # that links metrics to Gruff per project
693
- # (and link from assert2.rf.org to rf.org/projects/assert2
694
-
695
- private
696
-
697
- # ERGO switch to descendant-or-self
698
- # ERGO then update documentation of those who use this
699
- def symbol_to_xpath(tag)
700
- return tag unless tag.class == Symbol
701
- @helper or using :libxml? # prop-ulates @helper
702
- return @helper.symbol_to_xpath(tag)
703
- end
704
-
705
- def build_xpath(tag, id, diagnostic)
706
- options = ( case id
707
- when Symbol, String ; { :id => id }
708
- when Hash ; id
709
- end )
710
-
711
- options.merge!(diagnostic) if diagnostic.kind_of? Hash
712
- predicate = options.map{|k,v| "@#{k} = '#{v}'" }.join('')
713
- return symbol_to_xpath(tag) + "[ #{predicate} ]"
714
- end
715
-
716
- def stash_xdoc
717
- former_xdoc = @xdoc || assert_xml
718
- yield ensure @xdoc = former_xdoc
719
- end
720
-
721
- def flunk_xpath(diagnostic, template, *args) #:nodoc:
722
- xml = _esc(indent_xml).relevance || '(@xdoc is blank!)'
723
- flunk build_message(diagnostic, "#{template} in\n#{xml}", *args)
724
- end
725
-
726
- end
727
-
728
-
729
- def _esc(x) #:nodoc:
730
- return x.gsub('?', '\?')
731
- end
732
-
733
-
734
- #####################################################
735
-
736
- # FIXME got_libxml?
737
-
738
- # ERGO hpricot gets its own module (REXML-free!)
739
-
740
- def got_hpricot? # ERGO help tests pass without it
741
- require 'hpricot'
742
- return true
743
- rescue MissingSourceFile
744
- return false
745
- end
746
-
747
- #####################################################
748
-
749
- # parking some tiny conveniences here,
750
- # where even production code can get to them...
751
- module Relevate
752
- def relevant?
753
- return ! blank?
754
- end
755
-
756
- def relevance
757
- return to_s if relevant?
758
- end
759
- end
760
-
761
- # ERGO dry these up
762
- class String
763
- def blank?
764
- return strip.size == 0
765
- end
766
- end
767
-
768
- class NilClass
769
- def blank?; true; end
770
- end
771
-
772
- # ERGO include our test modules like this too
773
- # ERGO seek relevant? calls that could use relevance
774
-
775
- NilClass.send :include, Relevate
776
- String .send :include, Relevate
777
-
778
- #:enddoc:
779
-
780
- # props: http://www.intertwingly.net/blog/2007/11/02/MonkeyPatch-for-Ruby-1-8-6
781
- doc = REXML::Document.new '<doc xmlns="ns"><item name="foo"/></doc>'
782
- if not doc.root.elements["item[@name='foo']"]
783
- class REXML::Element
784
- def attribute( name, namespace=nil )
785
- prefix = nil
786
- prefix = namespaces.index(namespace) if namespace
787
- prefix = nil if prefix == 'xmlns'
788
- attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
789
- end
790
- end
791
- end
792
-
793
-
794
- # These monkey patches push Hpricot behavior closer to our customized REXML behavior
795
- module Hpricot #:nodoc:
796
- class Doc #:nodoc:
797
- include AssertXPath::CommonXPathExtensions
798
-
799
- def [](index) #:nodoc:
800
- return root[index] if symbolic? index
801
- super
802
- end
803
-
804
- def text
805
- return root.text
806
- end
807
-
808
- def method_missing(*args, &block) #:nodoc:
809
- # if got = search(symbol).first get first descendant working here!
810
- # ERGO call root here
811
- symbol = args.first.to_s.sub(/\!$/, '')
812
-
813
- root.children.grep(Hpricot::Elem).each do |kid|
814
- if kid.name == symbol
815
- return kid.drill(&block)
816
- # ERGO assert on return value
817
- # ERGO pass kid in for if you want it
818
- end
819
- end
820
- # ERGO raise here?
821
- end
822
- end
823
-
824
- class Elem #:nodoc:
825
- include AssertXPath::CommonXPathExtensions
826
-
827
- def [](index) #:nodoc:
828
- # ERGO do this conflict with anything?
829
- if symbol = symbolic?(index)
830
- return attributes[symbol] if attributes.has_key? symbol
831
- raise_magic_member_not_found(symbol, caller)
832
- end
833
-
834
- super
835
- end
836
-
837
- def text # simulate REXML style - fetch child with text
838
- return (text? ? to_s : '') + children.select(&:text?).map(&:to_s).compact.join
839
- end
840
-
841
- def node_type
842
- return :element # ERGO make me less useless
843
- end
844
-
845
- def drill(&block)
846
- if block
847
- # ERGO harmonize with bang! version
848
- # ERGO deal if the key ain't a valid variable
849
- # ERGO get method_missing to stop returning []
850
- unless tribute(block) # ERGO pass in self (node)?
851
- sib = self
852
- nil while (sib = sib.next_sibling) and sib.node_type != :element
853
- q = sib and _bequeath_attributes(sib).drill(&block)
854
- return sib if q
855
- raise Test::Unit::AssertionFailedError.new("can't find beyond <#{_esc xpath}>")
856
- end
857
- end
858
-
859
- return self
860
- # ERGO if block returns false/nil, find siblings until it passes.
861
- # throw a test failure if it don't.
862
- # ERGO axis concept
863
- end
864
-
865
- def method_missing(*args, &block) #:nodoc:
866
- symbol = args.shift.to_s.sub(/\!$/, '')
867
-
868
- children.grep(Hpricot::Elem).each do |kid|
869
- if kid.name == symbol
870
- kid.tribute(block)
871
- # ERGO assert on return value
872
- # ERGO pass kid in for if you want it
873
- return kid
874
- end
875
- end
876
-
877
- raise_magic_member_not_found(symbol, caller) # ERGO repurpose!
878
- end
879
- end
880
-
881
- end
882
-
883
-
884
- module XML
885
- class Node #:nodoc:
886
- include AssertXPath::CommonXPathExtensions
887
-
888
- def search(xpath, &block)
889
- if block
890
- find(xpath, "x:http://www.w3.org/1999/xhtml").each(&block)
891
- #find(xpath, &block)
892
- end
893
- return [find_first(xpath, "x:http://www.w3.org/1999/xhtml")]
894
- end
895
- alias each_element search
896
-
897
- def text
898
- #p text?
899
- find_first('text()').to_s
900
- #text? ? content : ''
901
- end
902
-
903
- def inner_text(interstitial = '')
904
- array = []
905
- self.find( 'descendant-or-self::text()' ).each{|x| array << x }
906
- return array.join(interstitial)
907
- end # ERGO match??
908
-
909
- def attributes
910
- hash = {}
911
- each_attr{|attr| hash[attr.name] = attr.value }
912
- return hash # ERGO uh, was there a leaner way??
913
- end
914
-
915
- def [](index) #:nodoc:
916
- return attributes[index.to_s] || super
917
- end
918
-
919
- def get_path(xpath)
920
- node = find_first(xpath.to_s)
921
- return _bequeath_attributes(node) if node
922
- end # ERGO test that attributes are bequeathed!
923
-
924
- alias :/ get_path
925
-
926
- def method_missing(*args, &block) #:nodoc:
927
- # ERGO use the define_method trick here
928
- symbol = args.shift.to_s
929
- symbol.sub!(/\!$/, '')
930
-
931
- kid = if symbol == '/'
932
- find_first('/')
933
- else
934
- find_first("./#{symbol}")
935
- end
936
- return _bequeath_attributes(kid).drill(&block) if kid
937
- raise_magic_member_not_found(symbol, caller)
938
- end
939
- end
940
-
941
- end
942
-
943
-
944
- class REXML::Element
945
- include AssertXPath::CommonXPathExtensions
946
-
947
- # Semi-private method to match Hpricotic abilities
948
- def search(xpath)
949
- return self.each_element( xpath ){}
950
- end
951
-
952
- def method_missing(*args, &block) #:nodoc:
953
- symbol = args.shift
954
-
955
- each_element("./#{symbol}") do |kid|
956
- return _bequeath_attributes(kid).drill(&block)
957
- end # ERGO element/:child - def/
958
-
959
- raise_magic_member_not_found(symbol, caller) # ERGO repurpose!
960
- end # ERGO convert attribute chain to xpath
961
-
962
- # Returns all text contents from a node and its descendants
963
- #
964
- # Example:
965
- #
966
- # assert_match 'can\'t be blank', assert_tag_id(:div, :errorExplanation).inner_text.strip
967
- #
968
- # %transclude AssertXPathSuite#test_inner_text
969
- #
970
- def inner_text(interstitial = '')
971
- return self.each_element( './/text()' ){}.join(interstitial)
972
- end # ERGO match??
973
-
974
- def get_path(xpath)
975
- node = each_element(xpath.to_s){}.first
976
- return _bequeath_attributes(node) if node
977
- end # ERGO test that attributes are bequeathed!
978
-
979
- alias :/ get_path
980
-
981
- # ERGO use set_backtrace to seat the backtracer to your code
982
- # ERGO move _bequeath stuff in here!
983
- # ERGO phase out the missing_method stuff that adds props
984
-
985
- end
986
-
987
-
988
- # FIXME hpricot, libxml, rexml always in alpha order
989
-
990
- # http://www.oreillynet.com/ruby/blog/2008/01/assert_efficient_sql.html
991
- # http://www.oreillynet.com/onlamp/blog/2007/09/big_requirements_up_front.html
992
- # http://www.oreillynet.com/onlamp/blog/2007/08/assert_hpricot_1.html
993
- # http://www.oreillynet.com/onlamp/blog/2007/08/xpath_checker_and_assert_xpath.html
994
- # http://phlip.eblogs.com/2007/07/28/javascriptpureperl-for-ruby-enthusiasts/
995
- # http://www.oreillynet.com/onlamp/blog/2007/07/assert_latest_and_greatest.html
996
- # http://www.oreillynet.com/onlamp/blog/2007/07/assert_raise_on_ruby_dont_just.html
997
- # http://phlip.eblogs.com/2007/01/02/growl-driven-development/