arrow 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
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
+