arrow 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- 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
|
+
|