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.
- 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
|
+
|