arrow 1.0.7

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.
Files changed (198) hide show
  1. data/ChangeLog +1590 -0
  2. data/LICENSE +28 -0
  3. data/README +75 -0
  4. data/Rakefile +366 -0
  5. data/Rakefile.local +63 -0
  6. data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
  7. data/data/arrow/applets/args.rb +50 -0
  8. data/data/arrow/applets/config.rb +55 -0
  9. data/data/arrow/applets/error.rb +63 -0
  10. data/data/arrow/applets/files.rb +46 -0
  11. data/data/arrow/applets/inspect.rb +46 -0
  12. data/data/arrow/applets/nosuchapplet.rb +31 -0
  13. data/data/arrow/applets/status.rb +92 -0
  14. data/data/arrow/applets/test.rb +133 -0
  15. data/data/arrow/applets/tutorial/counter.rb +96 -0
  16. data/data/arrow/applets/tutorial/dingus.rb +67 -0
  17. data/data/arrow/applets/tutorial/hello.rb +34 -0
  18. data/data/arrow/applets/tutorial/hello2.rb +73 -0
  19. data/data/arrow/applets/tutorial/imgtext.rb +90 -0
  20. data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
  21. data/data/arrow/applets/tutorial/index.rb +36 -0
  22. data/data/arrow/applets/tutorial/logo.rb +98 -0
  23. data/data/arrow/applets/tutorial/memcache.rb +61 -0
  24. data/data/arrow/applets/tutorial/missing.rb +37 -0
  25. data/data/arrow/applets/tutorial/protected.rb +100 -0
  26. data/data/arrow/applets/tutorial/redirector.rb +52 -0
  27. data/data/arrow/applets/tutorial/rndimages.rb +159 -0
  28. data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
  29. data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
  30. data/data/arrow/applets/tutorial/superhello.rb +72 -0
  31. data/data/arrow/applets/tutorial/timeclock.rb +78 -0
  32. data/data/arrow/applets/view-applet.rb +123 -0
  33. data/data/arrow/applets/view-template.rb +85 -0
  34. data/data/arrow/applets/wiki.rb +274 -0
  35. data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
  36. data/data/arrow/templates/applet-status.tmpl +153 -0
  37. data/data/arrow/templates/args-display.tmpl +120 -0
  38. data/data/arrow/templates/config/display-table.tmpl +36 -0
  39. data/data/arrow/templates/config/display.tmpl +36 -0
  40. data/data/arrow/templates/counter-deleted.tmpl +33 -0
  41. data/data/arrow/templates/counter.tmpl +59 -0
  42. data/data/arrow/templates/dingus.tmpl +55 -0
  43. data/data/arrow/templates/enumtable.tmpl +8 -0
  44. data/data/arrow/templates/error-display.tmpl +92 -0
  45. data/data/arrow/templates/filemap.tmpl +89 -0
  46. data/data/arrow/templates/hello-world-src.tmpl +34 -0
  47. data/data/arrow/templates/hello-world.tmpl +60 -0
  48. data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
  49. data/data/arrow/templates/imgtext/form.tmpl +70 -0
  50. data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
  51. data/data/arrow/templates/imgtext/reload.tmpl +55 -0
  52. data/data/arrow/templates/inspect/display.tmpl +80 -0
  53. data/data/arrow/templates/loginform.tmpl +64 -0
  54. data/data/arrow/templates/logout.tmpl +32 -0
  55. data/data/arrow/templates/memcache/display.tmpl +41 -0
  56. data/data/arrow/templates/navbar.incl +27 -0
  57. data/data/arrow/templates/nosuchapplet.tmpl +32 -0
  58. data/data/arrow/templates/printsource.tmpl +35 -0
  59. data/data/arrow/templates/protected.tmpl +36 -0
  60. data/data/arrow/templates/rndimages.tmpl +38 -0
  61. data/data/arrow/templates/service-response.tmpl +13 -0
  62. data/data/arrow/templates/sharenotes/display.tmpl +38 -0
  63. data/data/arrow/templates/status.tmpl +120 -0
  64. data/data/arrow/templates/templateviewer.tmpl +43 -0
  65. data/data/arrow/templates/test/harness.tmpl +57 -0
  66. data/data/arrow/templates/test/list.tmpl +48 -0
  67. data/data/arrow/templates/test/problem.tmpl +42 -0
  68. data/data/arrow/templates/tutorial/index.tmpl +37 -0
  69. data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
  70. data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
  71. data/data/arrow/templates/view-applet.tmpl +40 -0
  72. data/data/arrow/templates/view-template.tmpl +83 -0
  73. data/data/arrow/templates/wiki/formerror.tmpl +47 -0
  74. data/data/arrow/templates/wiki/markup_help.incl +6 -0
  75. data/data/arrow/templates/wiki/new.tmpl +56 -0
  76. data/data/arrow/templates/wiki/new_system.tmpl +122 -0
  77. data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
  78. data/data/arrow/templates/wiki/show.tmpl +34 -0
  79. data/docs/manual/layouts/default.page +43 -0
  80. data/docs/manual/lib/api-filter.rb +81 -0
  81. data/docs/manual/lib/editorial-filter.rb +64 -0
  82. data/docs/manual/lib/examples-filter.rb +244 -0
  83. data/docs/manual/lib/links-filter.rb +117 -0
  84. data/lib/apache/fakerequest.rb +448 -0
  85. data/lib/apache/logger.rb +33 -0
  86. data/lib/arrow.rb +51 -0
  87. data/lib/arrow/acceptparam.rb +207 -0
  88. data/lib/arrow/applet.rb +725 -0
  89. data/lib/arrow/appletmixins.rb +218 -0
  90. data/lib/arrow/appletregistry.rb +590 -0
  91. data/lib/arrow/applettestcase.rb +503 -0
  92. data/lib/arrow/broker.rb +255 -0
  93. data/lib/arrow/cache.rb +176 -0
  94. data/lib/arrow/config-loaders/yaml.rb +75 -0
  95. data/lib/arrow/config.rb +615 -0
  96. data/lib/arrow/constants.rb +24 -0
  97. data/lib/arrow/cookie.rb +359 -0
  98. data/lib/arrow/cookieset.rb +108 -0
  99. data/lib/arrow/dispatcher.rb +368 -0
  100. data/lib/arrow/dispatcherloader.rb +50 -0
  101. data/lib/arrow/exceptions.rb +61 -0
  102. data/lib/arrow/fallbackhandler.rb +48 -0
  103. data/lib/arrow/formvalidator.rb +631 -0
  104. data/lib/arrow/htmltokenizer.rb +343 -0
  105. data/lib/arrow/logger.rb +488 -0
  106. data/lib/arrow/logger/apacheoutputter.rb +69 -0
  107. data/lib/arrow/logger/arrayoutputter.rb +63 -0
  108. data/lib/arrow/logger/coloroutputter.rb +111 -0
  109. data/lib/arrow/logger/fileoutputter.rb +96 -0
  110. data/lib/arrow/logger/htmloutputter.rb +54 -0
  111. data/lib/arrow/logger/outputter.rb +123 -0
  112. data/lib/arrow/mixins.rb +425 -0
  113. data/lib/arrow/monkeypatches.rb +94 -0
  114. data/lib/arrow/object.rb +117 -0
  115. data/lib/arrow/path.rb +196 -0
  116. data/lib/arrow/service.rb +447 -0
  117. data/lib/arrow/session.rb +289 -0
  118. data/lib/arrow/session/dbstore.rb +100 -0
  119. data/lib/arrow/session/filelock.rb +160 -0
  120. data/lib/arrow/session/filestore.rb +132 -0
  121. data/lib/arrow/session/id.rb +98 -0
  122. data/lib/arrow/session/lock.rb +253 -0
  123. data/lib/arrow/session/md5id.rb +42 -0
  124. data/lib/arrow/session/nulllock.rb +42 -0
  125. data/lib/arrow/session/posixlock.rb +166 -0
  126. data/lib/arrow/session/sha1id.rb +54 -0
  127. data/lib/arrow/session/store.rb +366 -0
  128. data/lib/arrow/session/usertrackid.rb +52 -0
  129. data/lib/arrow/spechelpers.rb +73 -0
  130. data/lib/arrow/template.rb +713 -0
  131. data/lib/arrow/template/attr.rb +31 -0
  132. data/lib/arrow/template/call.rb +31 -0
  133. data/lib/arrow/template/comment.rb +33 -0
  134. data/lib/arrow/template/container.rb +118 -0
  135. data/lib/arrow/template/else.rb +41 -0
  136. data/lib/arrow/template/elsif.rb +44 -0
  137. data/lib/arrow/template/escape.rb +53 -0
  138. data/lib/arrow/template/export.rb +87 -0
  139. data/lib/arrow/template/for.rb +145 -0
  140. data/lib/arrow/template/if.rb +78 -0
  141. data/lib/arrow/template/import.rb +119 -0
  142. data/lib/arrow/template/include.rb +206 -0
  143. data/lib/arrow/template/iterator.rb +208 -0
  144. data/lib/arrow/template/nodes.rb +734 -0
  145. data/lib/arrow/template/parser.rb +571 -0
  146. data/lib/arrow/template/prettyprint.rb +53 -0
  147. data/lib/arrow/template/render.rb +191 -0
  148. data/lib/arrow/template/selectlist.rb +94 -0
  149. data/lib/arrow/template/set.rb +87 -0
  150. data/lib/arrow/template/timedelta.rb +81 -0
  151. data/lib/arrow/template/unless.rb +78 -0
  152. data/lib/arrow/template/urlencode.rb +51 -0
  153. data/lib/arrow/template/yield.rb +139 -0
  154. data/lib/arrow/templatefactory.rb +125 -0
  155. data/lib/arrow/testcase.rb +567 -0
  156. data/lib/arrow/transaction.rb +608 -0
  157. data/rake/191_compat.rb +26 -0
  158. data/rake/dependencies.rb +76 -0
  159. data/rake/documentation.rb +114 -0
  160. data/rake/helpers.rb +502 -0
  161. data/rake/hg.rb +282 -0
  162. data/rake/manual.rb +787 -0
  163. data/rake/packaging.rb +129 -0
  164. data/rake/publishing.rb +278 -0
  165. data/rake/style.rb +62 -0
  166. data/rake/svn.rb +668 -0
  167. data/rake/testing.rb +187 -0
  168. data/rake/verifytask.rb +64 -0
  169. data/spec/arrow/acceptparam_spec.rb +157 -0
  170. data/spec/arrow/applet_spec.rb +575 -0
  171. data/spec/arrow/appletmixins_spec.rb +409 -0
  172. data/spec/arrow/appletregistry_spec.rb +294 -0
  173. data/spec/arrow/broker_spec.rb +153 -0
  174. data/spec/arrow/config_spec.rb +224 -0
  175. data/spec/arrow/cookieset_spec.rb +164 -0
  176. data/spec/arrow/dispatcher_spec.rb +137 -0
  177. data/spec/arrow/dispatcherloader_spec.rb +65 -0
  178. data/spec/arrow/formvalidator_spec.rb +781 -0
  179. data/spec/arrow/logger_spec.rb +346 -0
  180. data/spec/arrow/mixins_spec.rb +120 -0
  181. data/spec/arrow/service_spec.rb +645 -0
  182. data/spec/arrow/session_spec.rb +121 -0
  183. data/spec/arrow/template/iterator_spec.rb +222 -0
  184. data/spec/arrow/templatefactory_spec.rb +185 -0
  185. data/spec/arrow/transaction_spec.rb +319 -0
  186. data/spec/arrow_spec.rb +37 -0
  187. data/spec/lib/appletmatchers.rb +281 -0
  188. data/spec/lib/constants.rb +77 -0
  189. data/spec/lib/helpers.rb +41 -0
  190. data/spec/lib/matchers.rb +44 -0
  191. data/tests/cookie.tests.rb +310 -0
  192. data/tests/path.tests.rb +157 -0
  193. data/tests/session.tests.rb +111 -0
  194. data/tests/session_id.tests.rb +82 -0
  195. data/tests/session_lock.tests.rb +191 -0
  196. data/tests/session_store.tests.rb +53 -0
  197. data/tests/template.tests.rb +1360 -0
  198. metadata +339 -0
@@ -0,0 +1,503 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless defined? Arrow::TestCase
4
+ testsdir = File.dirname( File.expand_path(__FILE__) )
5
+ basedir = File.dirname( testsdir )
6
+ $LOAD_PATH.unshift "#{basedir}/lib" unless
7
+ $LOAD_PATH.include?( "#{basedir}/lib" )
8
+ $LOAD_PATH.unshift "#{basedir}/tests/lib" unless
9
+ $LOAD_PATH.include?( "#{basedir}/tests/lib" )
10
+ end
11
+
12
+ require 'apache/fakerequest'
13
+ require 'test/unit/assertions'
14
+ require 'test/unit/testcase'
15
+ require 'pathname'
16
+ require 'flexmock'
17
+
18
+ require 'arrow'
19
+ require 'arrow/applet'
20
+ require 'arrow/mixins'
21
+
22
+
23
+ ### Provide a useful representation of a mock in an error message if one
24
+ ### isn't already provided.
25
+ unless FlexMock.instance_methods(false).include?("inspect")
26
+ class FlexMock
27
+ def inspect
28
+ "#<%s:0x%x %s>" % [
29
+ self.class.name,
30
+ self.object_id * 2,
31
+ self.mock_name
32
+ ]
33
+ end
34
+
35
+ def method_missing(sym, *args, &block)
36
+ mock_wrap do
37
+ if handler = @expectations[sym]
38
+ args << block if block_given?
39
+ handler.call(*args)
40
+ else
41
+ raise NoMethodError, "undefined method `%s' for %p" %
42
+ [ sym, self ] unless @ignore_missing
43
+ end
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+
51
+ # This is an abstract test case class for building Test::Unit unit tests for
52
+ # Arrow applets.
53
+ #
54
+ # == Synopsis
55
+ #
56
+ # $LOAD_PATH.unshift "tests/lib" unless $LOAD_PATH.include?("tests/lib")
57
+ # require 'applettestcase'
58
+ #
59
+ # class MySomethingTest < Arrow::AppletTestCase
60
+ #
61
+ # applet_under_test "jobs"
62
+ #
63
+ # def test_default_request_should_return_object_list
64
+ #
65
+ # end
66
+ #
67
+ # def test_default_request_with_oid_arg_should_display_details
68
+ # set_request_params :oid => 13
69
+ # end
70
+ #
71
+ # end
72
+ #
73
+ # == VCS Id
74
+ #
75
+ # $Id$
76
+ #
77
+ # == Authors
78
+ #
79
+ # * Michael Granger <ged@FaerieMUD.org>
80
+ #
81
+ # Copyright (c) 2003, 2004, 2006 RubyCrafters, LLC.
82
+ #
83
+ # This work is licensed under the Creative Commons Attribution License. To view
84
+ # a copy of this license, visit http://creativecommons.org/licenses/by/1.0 or
85
+ # send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
86
+ # 94305, USA.
87
+ #
88
+ #
89
+ class Arrow::AppletTestCase < Test::Unit::TestCase
90
+ include Arrow::Loggable, Test::Unit::Assertions, FlexMock::TestCase
91
+
92
+ # The default path to the directory where applets live
93
+ APPLET_PATH = Pathname.new( $0 ).expand_path.dirname + "applets"
94
+
95
+ class << self
96
+ attr_accessor :appletclass, :appletname, :fixture_data
97
+ end
98
+
99
+
100
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
101
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin
102
+ # <zenin@best.com>
103
+ AnsiAttributes = {
104
+ 'clear' => 0,
105
+ 'reset' => 0,
106
+ 'bold' => 1,
107
+ 'dark' => 2,
108
+ 'underline' => 4,
109
+ 'underscore' => 4,
110
+ 'blink' => 5,
111
+ 'reverse' => 7,
112
+ 'concealed' => 8,
113
+
114
+ 'black' => 30, 'on_black' => 40,
115
+ 'red' => 31, 'on_red' => 41,
116
+ 'green' => 32, 'on_green' => 42,
117
+ 'yellow' => 33, 'on_yellow' => 43,
118
+ 'blue' => 34, 'on_blue' => 44,
119
+ 'magenta' => 35, 'on_magenta' => 45,
120
+ 'cyan' => 36, 'on_cyan' => 46,
121
+ 'white' => 37, 'on_white' => 47
122
+ }
123
+
124
+ ### Returns a String containing the specified ANSI escapes suitable for
125
+ ### inclusion in another string. The <tt>attributes</tt> should be one
126
+ ### or more of the keys of AnsiAttributes.
127
+ def self::ansicode( *attributes )
128
+ return '' unless /(?:xterm(?:-color)?|eterm|linux)/i =~ ENV['TERM']
129
+
130
+ attr = attributes.collect {|a|
131
+ AnsiAttributes[a] ? AnsiAttributes[a] : nil
132
+ }.compact.join(';')
133
+ if attr.empty?
134
+ return ''
135
+ else
136
+ return "\e[%sm" % attr
137
+ end
138
+ end
139
+
140
+
141
+ ### Output the specified <tt>msgs</tt> joined together to
142
+ ### <tt>STDERR</tt> if <tt>$DEBUG</tt> is set.
143
+ def self::debug_msg( *msgs )
144
+ return unless $DEBUG
145
+ self.message "%sDEBUG>>> %s %s" %
146
+ [ ansicode('dark', 'white'), msgs.join(''), ansicode('reset') ]
147
+ end
148
+
149
+
150
+ ### Output the specified <tt>msgs</tt> joined together to
151
+ ### <tt>STDOUT</tt>.
152
+ def self::message( *msgs )
153
+ $stderr.puts msgs.join('')
154
+ $stderr.flush
155
+ end
156
+
157
+
158
+ ### Set up model +data+ for the given +model_class+ that can be used in
159
+ ### the stub data classes. The +data+ argument is an Array of data, and
160
+ ### can be either Hashes or Arrays. If Arrays are used, the first one in
161
+ ### the list should be a list of fields, and each subsequent Array should
162
+ ### be field values. E.g.,
163
+ ### [
164
+ ### [ :title, :description, :date ],
165
+ ### [ "title1", "desc1", Date.today ],
166
+ ### [ "title2", "desc2", Date.today-4 ],
167
+ ### ]
168
+ ### which is equivalent to:
169
+ ### [
170
+ ### { :title => "title1", :description => "desc1", :date => Date.today }
171
+ ### { :title => "title1", :description => "desc1", :date => Date.today }
172
+ ### ]
173
+ def self::set_fixture_data( model_class, data )
174
+ @fixture_data ||= {}
175
+
176
+ # [ [<fields>], [<values1], [<values2>] ]
177
+ if data.first.is_a?( Array )
178
+ fields = data.shift
179
+ objects = data.collect do |row|
180
+ obj = OpenStruct.new
181
+ fields.each_with_index {|f,i| obj.__send__(f, row[i])}
182
+ end
183
+
184
+ # [ {:field1 => <value1>}, {:field1 => <value2>} ]
185
+ elsif data.first.is_a?( Hash )
186
+ objects = data.collect do |row|
187
+ OpenStruct.new( row )
188
+ end
189
+
190
+ # Custom objects (Mocks, etc.)
191
+ elsif data.is_a?( Array )
192
+ objects = data
193
+ end
194
+
195
+ @fixture_data[ model_class ] = objects
196
+ end
197
+
198
+
199
+ ### Define the name of the applet under test. The given +name+ will be
200
+ ### stringified, downcased, and searched for in the #applet_path.
201
+ def self::applet_under_test( applet )
202
+ if applet.is_a?( Class )
203
+ self.appletclass = applet
204
+ self.appletname = applet.signature.name
205
+ else
206
+ debug_msg "Setting applet under test for testcase: %p" % [self]
207
+
208
+ if Arrow::Applet.derivatives.empty?
209
+ Pathname.glob( APPLET_PATH + '**/*.rb' ).each do |appletfile|
210
+ debug_msg "Trying to load #{appletfile}"
211
+ begin
212
+ Arrow::Applet.load( appletfile )
213
+ rescue LoadError
214
+ end
215
+ end
216
+ end
217
+
218
+ # :view_template becomes /view[-_]template/
219
+ applet_pat = Regexp.new( applet.to_s.gsub(/_/, '[-_]?') )
220
+
221
+ self.appletclass = Arrow::Applet.derivatives.find {|klass|
222
+ debug_msg " Checking applet '#{klass.name.downcase}' =~ #{applet_pat}..."
223
+ applet_pat.match( klass.name.downcase ) or
224
+ applet_pat.match( klass.filename )
225
+ } or raise "Failed to load applet matching #{applet_pat}"
226
+ self.appletname = applet.to_s
227
+
228
+ debug_msg "Applet under test is: #{self.appletclass}"
229
+ end
230
+ end
231
+
232
+
233
+ #################################################################
234
+ ### I N S T A N C E M E T H O D S
235
+ #################################################################
236
+
237
+ ### Check to be sure an applet has been associated before
238
+ ### instantiation.
239
+ def initialize( *args ) # :notnew:
240
+ throw :invalid_test unless self.class.appletclass
241
+ super
242
+ end
243
+
244
+
245
+ ### Set up a test with some useful test objects
246
+ def setup
247
+ super
248
+
249
+ debug_msg "%p: Setting up test for applet %p" %
250
+ [self.class, self.class.appletclass]
251
+
252
+ # Give the test an easy reference to the applet class under test
253
+ @appletclass = self.class.appletclass or
254
+ raise "No applet defined for '#{self.class.name}'. Add " +
255
+ "'applet_under_test :<appletname>' to correct this."
256
+ @appletname = self.class.appletname
257
+ @action = nil
258
+
259
+ @config = flexmock( "mock config" )
260
+ @config.should_receive( :symbolize_keys ).and_return({})
261
+ @config.should_receive( :member? ).
262
+ with( :db ).
263
+ and_return( false )
264
+ @config.should_receive( :name ).and_return( "mock" )
265
+ @config.should_receive( :member? ).
266
+ with( :model ).
267
+ and_return( false )
268
+ @config.should_ignore_missing
269
+ @template_factory = flexmock( "mock template factory" )
270
+
271
+ @applet = @appletclass.new( @config, @template_factory, "#{@appletname}" )
272
+
273
+ @delegate_behavior = nil
274
+ @delegate_should_be_called = true
275
+ @delegate_called = false
276
+ end
277
+
278
+ ### Output the name of the test as it's running if in verbose mode, and
279
+ ### support per-test debugging settings.
280
+ def run( result )
281
+ print_test_header self.name
282
+ super
283
+ end
284
+
285
+
286
+
287
+ #################################################################
288
+ ### M E S S A G E M E T H O D S
289
+ #################################################################
290
+
291
+ ### Instance alias for the like-named class method.
292
+ def message( *msgs )
293
+ self.class.message( *msgs )
294
+ end
295
+
296
+
297
+ ### Instance-alias for the like-named class method
298
+ def ansicode( *attributes )
299
+ self.class.ansicode( *attributes )
300
+ end
301
+
302
+
303
+ ### Instance alias for the like-named class method
304
+ def debug_msg( *msgs )
305
+ self.class.debug_msg( *msgs )
306
+ end
307
+
308
+
309
+ ### Return a separator line made up of <tt>length</tt> of the specified
310
+ ### <tt>char</tt>.
311
+ def hrule( length=75, char="-" )
312
+ return (char * length ) + "\n"
313
+ end
314
+
315
+ ### Return a section delimited by hrules with the specified +caption+ and
316
+ ### +content+.
317
+ def hrule_section( content, caption='' )
318
+ caption << ' ' unless caption.empty?
319
+ return caption +
320
+ hrule( 75 - caption.length ) +
321
+ content.chomp + "\n" +
322
+ hrule()
323
+ end
324
+
325
+
326
+ ### Output a header for delimiting tests
327
+ def print_test_header( desc )
328
+ return unless $VERBOSE || $DEBUG
329
+ message "%s>>> %s <<<%s" %
330
+ [ ansicode('bold','yellow','on_blue'), desc, ansicode('reset') ]
331
+ end
332
+
333
+
334
+ #################################################################
335
+ ### T E S T U T I L I T Y M E T H O D S
336
+ #################################################################
337
+
338
+ ### Set up faked request and transaction objects, yield to the given
339
+ ### block with them, then run the applet under test with them when
340
+ ### the block returns.
341
+ def with_fixtured_action( action=nil, *args, &block )
342
+ @action = action
343
+ txn, req, vargs, *args = setup_fixtured_request( action, *args )
344
+
345
+ if block.arity == 3
346
+ block.call( txn, req, vargs )
347
+ else
348
+ block.call( txn, req )
349
+ end
350
+
351
+ return @applet.run( txn, action.to_s, *args )
352
+ ensure
353
+ @action = nil
354
+ end
355
+
356
+
357
+ ### Set up a faked request and transaction object, yield to the given
358
+ ### block with them, and then call the #delegate method of the applet
359
+ ### under test. Unless otherwise indicated (via a call to
360
+ ### #should_not_delegate), the expectation will be set up that the applet
361
+ ### under test should call its delegate.
362
+ def with_fixtured_delegation( chain=[], *args, &block )
363
+ txn, req, vargs, *args = setup_fixtured_request( "delegated_action", *args )
364
+
365
+ # Set delegation expectation
366
+ @delegate_behavior ||= should_delegate()
367
+
368
+ if block.arity == 3
369
+ block.call( txn, req, vargs )
370
+ else
371
+ block.call( txn, req )
372
+ end
373
+
374
+ rval = @applet.delegate( txn, chain, *args, &@delegate_behavior )
375
+
376
+ if @delegate_should_be_called
377
+ assert @delegate_called,
378
+ "delegate applet was never called"
379
+ else
380
+ assert !@delegate_called,
381
+ "delegate applet was called unexpectedly"
382
+ end
383
+
384
+ return rval
385
+ end
386
+
387
+
388
+ ### The default delegate block -- call this from within your
389
+ ### #with_fixtured_delegation block if the applet under test should
390
+ ### delegate to the next applet in the chain.
391
+ def should_delegate( &block )
392
+ @delegate_should_be_called = true
393
+ @delegate_behavior = block ||
394
+ method( :default_delegation_behavior ).to_proc
395
+ end
396
+
397
+
398
+ ### Negated delegate block -- call this at the end of your
399
+ ### #with_fixtured_delegation block if the applet under test should *not*
400
+ ### delegate to the next applet in the chain.
401
+ def should_not_delegate( &block )
402
+ @delegate_should_be_called = false
403
+ @delegate_behavior = block ||
404
+ method( :default_delegation_behavior ).to_proc
405
+ end
406
+
407
+
408
+ ### The default block passed to Arrow::Applet#delegate by
409
+ ### #with_fixtured_delegation if no block is passed to either
410
+ ### #should_delegate or #should_not_delegate. If you override this, you
411
+ ### should either super to this method or set @delegate_called yourself.
412
+ def default_delegation_behavior
413
+ @delegate_called = true
414
+ end
415
+
416
+
417
+ ### Set up faked request and transaction objects for the given +action+,
418
+ ### using the given +args+ as REST-style arguments, and/or query arguments
419
+ ### if the last element is a Hash.
420
+ def setup_fixtured_request( action, *args )
421
+ uri = '/' + File.join( @appletname, action.to_s )
422
+ req = Apache::Request.new( uri )
423
+
424
+ params = args.last.is_a?( Hash ) ? args.pop : {}
425
+ debug_msg "Parameters hash set to: %p" % [params]
426
+ req.paramtable = params
427
+
428
+ debug_msg "Request is: %p" % [req]
429
+ #txn = Arrow::Transaction.new( req, @config, nil )
430
+ txn = flexmock( "transaction" )
431
+ txn.should_receive( :request ).
432
+ and_return( req ).zero_or_more_times
433
+ txn.should_receive( :vargs= ).
434
+ with( Arrow::FormValidator ).zero_or_more_times
435
+
436
+ vargs = flexmock( "form validator" )
437
+ txn.should_receive( :vargs ).
438
+ and_return( vargs ).
439
+ zero_or_more_times
440
+ vargs.should_receive( :[] ).zero_or_more_times
441
+
442
+ debug_msg "Transaction is: %p" % [txn]
443
+ return txn, req, vargs, *args
444
+ end
445
+
446
+
447
+ ### Assert that the current action should load the template associated with
448
+ ### the given +key+, and passes a mock template object to the given block
449
+ ### for further specification.
450
+ def should_load_template( key )
451
+ tname = @applet.signature.templates[ key ] or
452
+ raise Test::Unit::AssertionFailedError.new(
453
+ "Expected applet to load the '#{key.inspect}' template\n" +
454
+ "but there was no such template registered by the application." )
455
+
456
+ mock_template = flexmock( "#{key.inspect} template")
457
+ @template_factory.should_receive( :get_template ).
458
+ with( tname ).and_return( mock_template ).at_least.once
459
+ mock_template.should_ignore_missing
460
+
461
+ yield( mock_template ) if block_given?
462
+
463
+ return mock_template
464
+ end
465
+
466
+
467
+ ### Create a new mock object and register it to be verified at the end of
468
+ ### the test.
469
+ def create_mock( name )
470
+ return flexmock( name )
471
+ end
472
+
473
+
474
+ ### Set up a mock object as the given transaction's session.
475
+ def fixture_session( txn )
476
+ session = create_mock( "session" )
477
+ txn.should_receive( :session ).
478
+ and_return( session ).zero_or_more_times
479
+ session.should_receive( :[] ).and_return( nil ).zero_or_more_times
480
+ session.should_receive( :[]= ).and_return( nil ).zero_or_more_times
481
+
482
+ return session
483
+ end
484
+
485
+
486
+ ### Extract parameters for the given +key+ from the given +queryhash+
487
+ ### using the form validator for the current action and return it.
488
+ def extract_parameters( queryhash, key=nil )
489
+ profile = @applet.signature.validator_profiles[ @action ] ||
490
+ @applet.signature_profiles[ :__default__ ]
491
+ validator = Arrow::FormValidator.new( profile )
492
+
493
+ validator.validate( queryhash )
494
+
495
+ if key
496
+ return validator.valid[ key ]
497
+ else
498
+ return validator.valid
499
+ end
500
+ end
501
+
502
+ end # class Arrow::AppletTestCase
503
+