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
data/rake/testing.rb
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Rake tasklib for testing tasks
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Authors:
|
|
6
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
unless defined?( COVERAGE_MINIMUM )
|
|
10
|
+
if ENV['COVVERAGE_MINIMUM']
|
|
11
|
+
COVERAGE_MINIMUM = Float( ENV['COVERAGE_MINIMUM'] )
|
|
12
|
+
else
|
|
13
|
+
COVERAGE_MINIMUM = 85.0
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
SPEC_FILES = [] unless defined?( SPEC_FILES )
|
|
17
|
+
TEST_FILES = [] unless defined?( TEST_FILES )
|
|
18
|
+
|
|
19
|
+
COMMON_SPEC_OPTS = ['-Du'] unless defined?( COMMON_SPEC_OPTS )
|
|
20
|
+
|
|
21
|
+
COVERAGE_TARGETDIR = BASEDIR + 'coverage' unless defined?( COVERAGE_TARGETDIR )
|
|
22
|
+
RCOV_EXCLUDES = 'spec,tests,/Library/Ruby,/var/lib,/usr/local/lib' unless
|
|
23
|
+
defined?( RCOV_EXCLUDES )
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
desc "Run all defined tests"
|
|
27
|
+
task :test do
|
|
28
|
+
unless SPEC_FILES.empty?
|
|
29
|
+
log "Running specs"
|
|
30
|
+
Rake::Task['spec:quiet'].invoke
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
unless TEST_FILES.empty?
|
|
34
|
+
log "Running unit tests"
|
|
35
|
+
Rake::Task[:unittests].invoke
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### RSpec specifications
|
|
41
|
+
begin
|
|
42
|
+
gem 'rspec', '>= 1.1.3'
|
|
43
|
+
|
|
44
|
+
require 'spec'
|
|
45
|
+
require 'spec/rake/spectask'
|
|
46
|
+
|
|
47
|
+
### Task: spec
|
|
48
|
+
desc "Run specs"
|
|
49
|
+
task :spec => 'spec:doc'
|
|
50
|
+
|
|
51
|
+
namespace :spec do
|
|
52
|
+
desc "Run rspec every time there's a change to one of the files"
|
|
53
|
+
task :autotest do
|
|
54
|
+
require 'autotest/rspec'
|
|
55
|
+
|
|
56
|
+
autotester = Autotest::Rspec.new
|
|
57
|
+
autotester.run
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
desc "Generate regular color 'doc' spec output"
|
|
61
|
+
Spec::Rake::SpecTask.new( :doc ) do |task|
|
|
62
|
+
task.spec_files = SPEC_FILES
|
|
63
|
+
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 's', '-c']
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
desc "Generate spec output with profiling"
|
|
67
|
+
Spec::Rake::SpecTask.new( :profile ) do |task|
|
|
68
|
+
task.spec_files = SPEC_FILES
|
|
69
|
+
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'o']
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
desc "Generate quiet non-colored plain-text output"
|
|
73
|
+
Spec::Rake::SpecTask.new( :quiet ) do |task|
|
|
74
|
+
task.spec_files = SPEC_FILES
|
|
75
|
+
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'p']
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
desc "Generate HTML output"
|
|
79
|
+
Spec::Rake::SpecTask.new( :html ) do |task|
|
|
80
|
+
task.spec_files = SPEC_FILES
|
|
81
|
+
task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'h']
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
rescue LoadError => err
|
|
86
|
+
task :no_rspec do
|
|
87
|
+
$stderr.puts "Specification tasks not defined: %s" % [ err.message ]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
task :spec => :no_rspec
|
|
91
|
+
namespace :spec do
|
|
92
|
+
task :autotest => :no_rspec
|
|
93
|
+
task :doc => :no_rspec
|
|
94
|
+
task :profile => :no_rspec
|
|
95
|
+
task :quiet => :no_rspec
|
|
96
|
+
task :html => :no_rspec
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
### Test::Unit tests
|
|
102
|
+
begin
|
|
103
|
+
require 'rake/testtask'
|
|
104
|
+
|
|
105
|
+
Rake::TestTask.new( :unittests ) do |task|
|
|
106
|
+
task.libs += [LIBDIR]
|
|
107
|
+
task.test_files = TEST_FILES
|
|
108
|
+
task.verbose = true
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
rescue LoadError => err
|
|
112
|
+
task :no_test do
|
|
113
|
+
$stderr.puts "Test tasks not defined: %s" % [ err.message ]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
task :unittests => :no_rspec
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
### RCov (via RSpec) tasks
|
|
121
|
+
begin
|
|
122
|
+
gem 'rcov'
|
|
123
|
+
gem 'rspec', '>= 1.1.3'
|
|
124
|
+
|
|
125
|
+
require 'spec'
|
|
126
|
+
require 'rcov'
|
|
127
|
+
|
|
128
|
+
### Task: coverage (via RCov)
|
|
129
|
+
desc "Build test coverage reports"
|
|
130
|
+
unless SPEC_FILES.empty?
|
|
131
|
+
Spec::Rake::SpecTask.new( :coverage ) do |task|
|
|
132
|
+
task.spec_files = SPEC_FILES
|
|
133
|
+
task.libs += [LIBDIR]
|
|
134
|
+
task.spec_opts = ['-f', 'p', '-b']
|
|
135
|
+
task.rcov_opts = RCOV_OPTS
|
|
136
|
+
task.rcov = true
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
### Task: rcov
|
|
142
|
+
task :rcov => :coverage
|
|
143
|
+
|
|
144
|
+
### Other coverage tasks
|
|
145
|
+
namespace :coverage do
|
|
146
|
+
desc "Generate a detailed text coverage report"
|
|
147
|
+
Spec::Rake::SpecTask.new( :text ) do |task|
|
|
148
|
+
task.spec_files = SPEC_FILES
|
|
149
|
+
task.rcov_opts = RCOV_OPTS + ['--text-report']
|
|
150
|
+
task.rcov = true
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
desc "Show differences in coverage from last run"
|
|
154
|
+
Spec::Rake::SpecTask.new( :diff ) do |task|
|
|
155
|
+
task.spec_files = SPEC_FILES
|
|
156
|
+
task.spec_opts = ['-f', 'p', '-b']
|
|
157
|
+
task.rcov_opts = RCOV_OPTS - ['--save'] + ['--text-coverage-diff']
|
|
158
|
+
task.rcov = true
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
desc "Run RCov in 'spec-only' mode to check coverage from specs"
|
|
162
|
+
Spec::Rake::SpecTask.new( :speconly ) do |task|
|
|
163
|
+
task.spec_files = SPEC_FILES
|
|
164
|
+
task.rcov_opts = ['--exclude', RCOV_EXCLUDES, '--text-report', '--save']
|
|
165
|
+
task.rcov = true
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
CLOBBER.include( COVERAGE_TARGETDIR )
|
|
170
|
+
|
|
171
|
+
rescue LoadError => err
|
|
172
|
+
task :no_rcov do
|
|
173
|
+
$stderr.puts "Coverage tasks not defined: RSpec+RCov tasklib not available: %s" %
|
|
174
|
+
[ err.message ]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
task :coverage => :no_rcov
|
|
178
|
+
task :clobber_coverage
|
|
179
|
+
task :rcov => :no_rcov
|
|
180
|
+
namespace :coverage do
|
|
181
|
+
task :text => :no_rcov
|
|
182
|
+
task :diff => :no_rcov
|
|
183
|
+
end
|
|
184
|
+
task :verify => :no_rcov
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
|
data/rake/verifytask.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#####################################################################
|
|
2
|
+
### S U B V E R S I O N T A S K S A N D H E L P E R S
|
|
3
|
+
#####################################################################
|
|
4
|
+
|
|
5
|
+
require 'rake/tasklib'
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# Work around the inexplicable behaviour of the original RDoc::VerifyTask, which
|
|
9
|
+
# errors if your coverage isn't *exactly* the threshold.
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
# A task that can verify that the RCov coverage doesn't
|
|
13
|
+
# drop below a certain threshold. It should be run after
|
|
14
|
+
# running Spec::Rake::SpecTask.
|
|
15
|
+
class VerifyTask < Rake::TaskLib
|
|
16
|
+
|
|
17
|
+
COVERAGE_PERCENTAGE_PATTERN =
|
|
18
|
+
%r{<tt class='coverage_code'>(\d+\.\d+)%</tt>}
|
|
19
|
+
|
|
20
|
+
# Name of the task. Defaults to :verify_rcov
|
|
21
|
+
attr_accessor :name
|
|
22
|
+
|
|
23
|
+
# Path to the index.html file generated by RCov, which
|
|
24
|
+
# is the file containing the total coverage.
|
|
25
|
+
# Defaults to 'coverage/index.html'
|
|
26
|
+
attr_accessor :index_html
|
|
27
|
+
|
|
28
|
+
# Whether or not to output details. Defaults to true.
|
|
29
|
+
attr_accessor :verbose
|
|
30
|
+
|
|
31
|
+
# The threshold value (in percent) for coverage. If the
|
|
32
|
+
# actual coverage is not equal to this value, the task will raise an
|
|
33
|
+
# exception.
|
|
34
|
+
attr_accessor :threshold
|
|
35
|
+
|
|
36
|
+
def initialize( name=:verify )
|
|
37
|
+
@name = name
|
|
38
|
+
@index_html = 'coverage/index.html'
|
|
39
|
+
@verbose = true
|
|
40
|
+
yield self if block_given?
|
|
41
|
+
raise "Threshold must be set" if @threshold.nil?
|
|
42
|
+
define
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def define
|
|
46
|
+
desc "Verify that rcov coverage is at least #{threshold}%"
|
|
47
|
+
|
|
48
|
+
task @name do
|
|
49
|
+
total_coverage = nil
|
|
50
|
+
if match = File.read( index_html ).match( COVERAGE_PERCENTAGE_PATTERN )
|
|
51
|
+
total_coverage = Float( match[1] )
|
|
52
|
+
else
|
|
53
|
+
raise "Couldn't find the coverage percentage in #{index_html}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
puts "Coverage: #{total_coverage}% (threshold: #{threshold}%)" if verbose
|
|
57
|
+
if total_coverage < threshold
|
|
58
|
+
raise "Coverage must be at least #{threshold}% but was #{total_coverage}%"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# vim: set nosta noet ts=4 sw=4:
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
BEGIN {
|
|
4
|
+
require 'pathname'
|
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
|
6
|
+
|
|
7
|
+
libdir = basedir + "lib"
|
|
8
|
+
|
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
require 'spec'
|
|
14
|
+
require 'spec/lib/constants'
|
|
15
|
+
require 'spec/lib/helpers'
|
|
16
|
+
require 'arrow'
|
|
17
|
+
require 'arrow/constants'
|
|
18
|
+
require 'arrow/acceptparam'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
#####################################################################
|
|
22
|
+
### C O N T E X T S
|
|
23
|
+
#####################################################################
|
|
24
|
+
|
|
25
|
+
describe Arrow::AcceptParam do
|
|
26
|
+
include Arrow::SpecHelpers
|
|
27
|
+
|
|
28
|
+
before( :all ) do
|
|
29
|
+
setup_logging( :crit )
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
after( :all ) do
|
|
33
|
+
reset_logging()
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
ValidHeaders = {
|
|
38
|
+
'*/*' =>
|
|
39
|
+
{:type => nil, :subtype => nil, :qval => 1.0},
|
|
40
|
+
'*/*; q=0.1' =>
|
|
41
|
+
{:type => nil, :subtype => nil, :qval => 0.1},
|
|
42
|
+
'*/*;q=0.1' =>
|
|
43
|
+
{:type => nil, :subtype => nil, :qval => 0.1},
|
|
44
|
+
'image/*' =>
|
|
45
|
+
{:type => 'image', :subtype => nil, :qval => 1.0},
|
|
46
|
+
'image/*; q=0.18' =>
|
|
47
|
+
{:type => 'image', :subtype => nil, :qval => 0.18},
|
|
48
|
+
'image/*;q=0.4' =>
|
|
49
|
+
{:type => 'image', :subtype => nil, :qval => 0.4},
|
|
50
|
+
'image/*;q=0.9; porn=0; anseladams=1' =>
|
|
51
|
+
{:type => 'image', :subtype => nil, :qval => 0.9,
|
|
52
|
+
:extensions => %w[anseladams=1 porn=0]},
|
|
53
|
+
'image/png' =>
|
|
54
|
+
{:type => 'image', :subtype => 'png', :qval => 1.0},
|
|
55
|
+
'IMAGE/pNg' =>
|
|
56
|
+
{:type => 'image', :subtype => 'png', :qval => 1.0},
|
|
57
|
+
'application/x-porno' =>
|
|
58
|
+
{:type => 'application', :subtype => 'x-porno', :qval => 1.0},
|
|
59
|
+
'image/png; q=0.2' =>
|
|
60
|
+
{:type => 'image', :subtype => 'png', :qval => 0.2},
|
|
61
|
+
'image/x-giraffes;q=0.2' =>
|
|
62
|
+
{:type => 'image', :subtype => 'x-giraffes', :qval => 0.2},
|
|
63
|
+
'example/pork; headcheese=0;withfennel=1' =>
|
|
64
|
+
{:type => 'example', :subtype => 'pork', :qval => 1.0,
|
|
65
|
+
:extensions => %w[headcheese=0 withfennel=1]},
|
|
66
|
+
'model/vnd.moml+xml' =>
|
|
67
|
+
{:type => 'model', :subtype => 'vnd.moml+xml', :qval => 1.0},
|
|
68
|
+
'model/parasolid.transmit.binary; q=0.2' =>
|
|
69
|
+
{:type => 'model', :subtype => 'parasolid.transmit.binary',
|
|
70
|
+
:qval => 0.2},
|
|
71
|
+
'image/png; q=0.2; compression=1' =>
|
|
72
|
+
{:type => 'image', :subtype => 'png', :qval => 0.2,
|
|
73
|
+
:extensions => %w[compression=1]},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
it "parses valid Accept header values" do
|
|
78
|
+
ValidHeaders.each do |hdr, expectations|
|
|
79
|
+
rval = Arrow::AcceptParam.parse( hdr )
|
|
80
|
+
|
|
81
|
+
rval.should be_an_instance_of( Arrow::AcceptParam )
|
|
82
|
+
rval.type.should == expectations[:type]
|
|
83
|
+
rval.subtype.should == expectations[:subtype]
|
|
84
|
+
rval.qvalue.should == expectations[:qval]
|
|
85
|
+
if expectations[:extensions]
|
|
86
|
+
expectations[:extensions].each do |ext|
|
|
87
|
+
rval.extensions.should include(ext)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "is lenient (but warns) about invalid qvalues" do
|
|
94
|
+
rval = nil
|
|
95
|
+
lambda {
|
|
96
|
+
rval = Arrow::AcceptParam.parse( '*/*; q=18' )
|
|
97
|
+
}.should_not raise_error()
|
|
98
|
+
|
|
99
|
+
rval.should be_an_instance_of( Arrow::AcceptParam )
|
|
100
|
+
rval.qvalue.should == 1.0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
it "rejects invalid Accept header values" do
|
|
105
|
+
lambda {
|
|
106
|
+
Arrow::AcceptParam.parse( 'porksausage' )
|
|
107
|
+
}.should raise_error()
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
it "can represent itself in a human-readable object format" do
|
|
112
|
+
header = "text/html; q=0.9; level=2"
|
|
113
|
+
acceptparam = Arrow::AcceptParam.parse( header )
|
|
114
|
+
acceptparam.inspect.should =~ %r{AcceptParam.*text/html.*q=0.9}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
it "can represent itself as an Accept header" do
|
|
119
|
+
header = "text/html;q=0.9;level=2"
|
|
120
|
+
acceptparam = Arrow::AcceptParam.parse( header )
|
|
121
|
+
acceptparam.to_s.should == header
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
it "can compare and sort on specificity" do
|
|
126
|
+
header = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9," +
|
|
127
|
+
"text/html;q=0.9;level=1,text/plain;q=0.8,image/png,*/*;q=0.5"
|
|
128
|
+
params = header.split(/\s*,\s*/).collect {|par|
|
|
129
|
+
Arrow::AcceptParam.parse( par )
|
|
130
|
+
}.sort
|
|
131
|
+
|
|
132
|
+
params[0].to_s.should == 'application/xhtml+xml;q=1.0'
|
|
133
|
+
params[1].to_s.should == 'application/xml;q=1.0'
|
|
134
|
+
params[2].to_s.should == 'image/png;q=1.0'
|
|
135
|
+
params[3].to_s.should == 'text/xml;q=1.0'
|
|
136
|
+
params[4].to_s.should == 'text/html;q=0.9;level=1'
|
|
137
|
+
params[5].to_s.should == 'text/html;q=0.9'
|
|
138
|
+
params[6].to_s.should == 'text/plain;q=0.8'
|
|
139
|
+
params[7].to_s.should == '*/*;q=0.5'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
it "can be compared against strings" do
|
|
144
|
+
specific_param = Arrow::AcceptParam.parse( 'text/html' )
|
|
145
|
+
type_wildcard_param = Arrow::AcceptParam.parse( '*/*' )
|
|
146
|
+
subtype_wildcard_param = Arrow::AcceptParam.parse( 'image/*' )
|
|
147
|
+
|
|
148
|
+
( specific_param =~ 'text/html' ).should be_true()
|
|
149
|
+
( specific_param =~ 'image/png' ).should be_false()
|
|
150
|
+
|
|
151
|
+
( subtype_wildcard_param =~ 'image/png' ).should be_true()
|
|
152
|
+
( subtype_wildcard_param =~ 'image/jpeg' ).should be_true()
|
|
153
|
+
( subtype_wildcard_param =~ 'text/plain' ).should be_false()
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# vim: set nosta noet ts=4 sw=4:
|
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# Specification for the Arrow::Applet class
|
|
4
|
+
# $Id$
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2004-2008 The FaerieMUD Consortium. Most rights reserved.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
BEGIN {
|
|
10
|
+
require 'pathname'
|
|
11
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
|
12
|
+
|
|
13
|
+
libdir = basedir + "lib"
|
|
14
|
+
|
|
15
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
require 'spec'
|
|
19
|
+
|
|
20
|
+
require 'apache/fakerequest'
|
|
21
|
+
require 'arrow'
|
|
22
|
+
require 'arrow/applet'
|
|
23
|
+
|
|
24
|
+
require 'spec/lib/helpers'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
#####################################################################
|
|
28
|
+
### C O N T E X T S
|
|
29
|
+
#####################################################################
|
|
30
|
+
|
|
31
|
+
describe Arrow::Applet do
|
|
32
|
+
include Arrow::SpecHelpers
|
|
33
|
+
|
|
34
|
+
before( :all ) do
|
|
35
|
+
setup_logging( :crit )
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
after( :all ) do
|
|
39
|
+
reset_logging()
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
it "has a signature even if it doesn't declare one" do
|
|
44
|
+
plainclass = Class.new( Arrow::Applet )
|
|
45
|
+
plainclass.signature.should be_an_instance_of( Arrow::Applet::SignatureStruct )
|
|
46
|
+
plainclass.signature.members.should include( 'name' )
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "subclasses know if further subclasses of itself have been loaded" do
|
|
50
|
+
plainclass = Class.new( Arrow::Applet )
|
|
51
|
+
plainclass.should_not be_inherited_from()
|
|
52
|
+
subclass = Class.new( plainclass )
|
|
53
|
+
plainclass.should be_inherited_from()
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "raises an exception if an action method that doesn't accept arguments is declared" do
|
|
57
|
+
lambda {
|
|
58
|
+
Class.new( Arrow::Applet ) do
|
|
59
|
+
def no_arg_action
|
|
60
|
+
raise "shouldn't be callable"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
}.should raise_error( ::ScriptError, 'Inappropriate arity for no_arg_action' )
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
describe "concrete child and grandchild classes" do
|
|
68
|
+
before(:each) do
|
|
69
|
+
@appletclass = Class.new( Arrow::Applet ) do
|
|
70
|
+
default_action :test
|
|
71
|
+
|
|
72
|
+
applet_name "SuperApplet"
|
|
73
|
+
applet_description "A superclass applet"
|
|
74
|
+
applet_version 177
|
|
75
|
+
applet_maintainer "ged@FaerieMUD.org"
|
|
76
|
+
end
|
|
77
|
+
@appletsubclass = Class.new( @appletclass )
|
|
78
|
+
|
|
79
|
+
@applet = @appletclass.new( nil, nil, nil )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
it "don't return superclass applets from ::load by default" do
|
|
84
|
+
Kernel.stub!( :load ).and_return do
|
|
85
|
+
Arrow::Applet.newly_loaded << @appletclass << @appletsubclass
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
applets = Arrow::Applet.load( 'stubbedapplet' )
|
|
89
|
+
|
|
90
|
+
applets.should have(1).member
|
|
91
|
+
applets.should_not include( @appletclass )
|
|
92
|
+
applets.should include( @appletsubclass )
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
it "return superclass applets from ::load if asked to do so" do
|
|
97
|
+
Kernel.stub!( :load ).and_return do
|
|
98
|
+
Arrow::Applet.newly_loaded << @appletclass << @appletsubclass
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
applets = Arrow::Applet.load( 'stubbedapplet', true )
|
|
102
|
+
|
|
103
|
+
applets.should have(2).members
|
|
104
|
+
applets.should include( @appletclass )
|
|
105
|
+
applets.should include( @appletsubclass )
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
it "inherit some values from their parent's signature" do
|
|
110
|
+
@appletsubclass.signature.maintainer.should == @appletclass.signature.maintainer
|
|
111
|
+
@appletsubclass.signature.maintainer.should_not be_equal(@appletclass.signature.maintainer)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "don't inherit the :version, :name, and :description from their parent's signature" do
|
|
115
|
+
@appletsubclass.signature.version.should_not == @appletclass.signature.version
|
|
116
|
+
@appletsubclass.signature.name.should == @appletsubclass.name
|
|
117
|
+
@appletsubclass.signature.description.should == '(none)'
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
describe "instance" do
|
|
123
|
+
before( :all ) do
|
|
124
|
+
setup_logging( :crit )
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
before( :each ) do
|
|
128
|
+
@appletclass = Class.new( Arrow::Applet ) do
|
|
129
|
+
def test_action( txn, *args )
|
|
130
|
+
return [txn, args]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def one_arg_action( txn, one )
|
|
134
|
+
return one
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def two_args_action( txn, one, two )
|
|
138
|
+
return [ one, two ]
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def action_missing_action( txn, missing, *args )
|
|
142
|
+
return [ :missing, missing, *args ]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def load_template_action( txn, template_name )
|
|
146
|
+
return self.load_template( template_name )
|
|
147
|
+
end
|
|
148
|
+
template :devdas, "dola/re/dola.tmpl"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
@uri = '/test'
|
|
152
|
+
@factory = mock( "template factory" )
|
|
153
|
+
|
|
154
|
+
@applet = @appletclass.new( nil, @factory, @uri )
|
|
155
|
+
|
|
156
|
+
@txn = stub( "transaction", :vargs => nil, :form_request? => false, :vargs= => nil )
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
it "delegates template-loading to its template factory" do
|
|
161
|
+
@factory.should_receive( :get_template ).with( 'dola/re/dola.tmpl' ).
|
|
162
|
+
and_return( :the_template )
|
|
163
|
+
@applet.load_template_action( @txn, :devdas ).should == :the_template
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "eliminates URI arguments to match the arity of actions with only one argument" do
|
|
167
|
+
@applet.run( @txn, 'one_arg', :first, :second, :third ).should == :first
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it "eliminates URI arguments to match the arity of actions with two arguments" do
|
|
171
|
+
@applet.run( @txn, 'two_args', :first, :second, :third ).should == [:first, :second]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "appends nil URI arguments to match the arity of actions with two arguments" do
|
|
175
|
+
@applet.run( @txn, 'two_args', :first ).should == [:first, nil]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
it "maps invocations of nonexistent actions to the action_missing action" do
|
|
180
|
+
@applet.run( @txn, "nonexistent", :first ).should == [ :missing, "nonexistent", :first ]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "doesn't use libapreq's param parser for a POST with content-type " +
|
|
184
|
+
"other than 'application/www-form-url-encoded" do
|
|
185
|
+
request = mock( "request", :null_object => true )
|
|
186
|
+
request.should_not_receive( :paramtable )
|
|
187
|
+
|
|
188
|
+
txn = mock( "transaction", :null_object => true )
|
|
189
|
+
txn.should_receive( :form_request? ).at_least(1).and_return( false )
|
|
190
|
+
txn.stub!( :request ).and_return( request )
|
|
191
|
+
|
|
192
|
+
@applet.run( txn, 'test' )
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
end # describe "instance"
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
describe "instance with an action that accepts form parameters" do
|
|
199
|
+
before( :all ) do
|
|
200
|
+
setup_logging( :crit )
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "allows a validator to be declared using 'action, hash' syntax" do
|
|
204
|
+
appletclass = Class.new( Arrow::Applet ) do
|
|
205
|
+
def comma_action( txn, *args )
|
|
206
|
+
return 'yay'
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
validator :comma, :optional => :formy
|
|
210
|
+
end
|
|
211
|
+
appletclass.signature.validator_profiles[ :comma ].should == {
|
|
212
|
+
:optional => :formy
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "allows a validator to be declared using 'action => { hash }' syntax" do
|
|
217
|
+
appletclass = Class.new( Arrow::Applet ) do
|
|
218
|
+
def hash_action( txn, *args )
|
|
219
|
+
return 'yay'
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
validator :hash => { :optional => :formy }
|
|
223
|
+
end
|
|
224
|
+
appletclass.signature.validator_profiles[ :hash ].should == {
|
|
225
|
+
:optional => :formy
|
|
226
|
+
}
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
describe "instance without an #action_missing_action method" do
|
|
232
|
+
before( :all ) do
|
|
233
|
+
setup_logging( :crit )
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
before( :each ) do
|
|
237
|
+
@appletclass = Class.new( Arrow::Applet ) do
|
|
238
|
+
template :test => 'test.tmpl'
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
@uri = '/test'
|
|
242
|
+
@factory = mock( "template factory" )
|
|
243
|
+
|
|
244
|
+
@applet = @appletclass.new( nil, @factory, @uri )
|
|
245
|
+
|
|
246
|
+
@txn = stub( "transaction", :vargs => nil, :form_request? => false, :vargs= => nil )
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it "maps missing actions to like-named templates" do
|
|
250
|
+
template = stub( "test template" )
|
|
251
|
+
@factory.should_receive( :get_template ).with( 'test.tmpl' ).and_return( template )
|
|
252
|
+
|
|
253
|
+
template.should_receive( :txn= ).with( @txn )
|
|
254
|
+
template.should_receive( :applet= ).with( @applet )
|
|
255
|
+
|
|
256
|
+
@applet.run( @txn, 'test' ).should == template
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it "untaints the action before using it to look up the missing action template" do
|
|
260
|
+
template = stub( "test template" )
|
|
261
|
+
@factory.should_receive( :get_template ).with( 'test.tmpl' ).and_return( template )
|
|
262
|
+
|
|
263
|
+
template.should_receive( :txn= ).with( @txn )
|
|
264
|
+
template.should_receive( :applet= ).with( @applet )
|
|
265
|
+
|
|
266
|
+
action = 'test'
|
|
267
|
+
action.taint
|
|
268
|
+
|
|
269
|
+
Thread.new do
|
|
270
|
+
Thread.current.abort_on_exception = true
|
|
271
|
+
$SAFE = 1
|
|
272
|
+
lambda {
|
|
273
|
+
@applet.run( @txn, action )
|
|
274
|
+
}.should_not raise_error()
|
|
275
|
+
end.join
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
### TODO: Convert these to specs
|
|
281
|
+
|
|
282
|
+
def test_load_template_should_raise_an_error_for_templates_not_in_the_signature
|
|
283
|
+
assert_raises( Arrow::AppletError ) do
|
|
284
|
+
applet = @appletclass.new( nil, nil, nil )
|
|
285
|
+
applet.__send__( :load_template, :foo )
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def test_template_directive_should_add_a_template_to_the_signature
|
|
291
|
+
assert !@appletclass.signature.templates.key?( :foo )
|
|
292
|
+
|
|
293
|
+
assert_nothing_raised do
|
|
294
|
+
@appletclass.class_eval do
|
|
295
|
+
template :foo, "foo.tmpl"
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
assert_equal "foo.tmpl", @appletclass.signature.templates[:foo]
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def test_template_directive_should_accept_single_hash_pair
|
|
303
|
+
assert !@appletclass.signature.templates.key?( :foo )
|
|
304
|
+
|
|
305
|
+
assert_nothing_raised do
|
|
306
|
+
@appletclass.class_eval do
|
|
307
|
+
template :foo => "foo.tmpl"
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
assert_equal "foo.tmpl", @appletclass.signature.templates[:foo]
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def test_template_directive_should_accept_multiple_hash_pairs
|
|
315
|
+
assert !@appletclass.signature.templates.key?( :foo )
|
|
316
|
+
assert !@appletclass.signature.templates.key?( :bar )
|
|
317
|
+
|
|
318
|
+
assert_nothing_raised do
|
|
319
|
+
@appletclass.class_eval do
|
|
320
|
+
template :foo => "foo.tmpl",
|
|
321
|
+
:bar => "bar.tmpl"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
assert_equal "foo.tmpl", @appletclass.signature.templates[:foo]
|
|
326
|
+
assert_equal "bar.tmpl", @appletclass.signature.templates[:bar]
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def test_applet_name_directive_should_set_signature_name
|
|
330
|
+
assert_not_equal "foo", @appletclass.signature.name
|
|
331
|
+
|
|
332
|
+
assert_nothing_raised do
|
|
333
|
+
@appletclass.class_eval do
|
|
334
|
+
applet_name "foo"
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
assert_equal "foo", @appletclass.signature.name
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def test_applet_description_directive_should_set_signature_description
|
|
342
|
+
assert_not_equal "foo", @appletclass.signature.description
|
|
343
|
+
|
|
344
|
+
assert_nothing_raised do
|
|
345
|
+
@appletclass.class_eval do
|
|
346
|
+
applet_description "foo"
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
assert_equal "foo", @appletclass.signature.description
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def test_applet_maintainer_directive_should_set_signature_maintainer
|
|
354
|
+
assert_not_equal "foo", @appletclass.signature.maintainer
|
|
355
|
+
|
|
356
|
+
assert_nothing_raised do
|
|
357
|
+
@appletclass.class_eval do
|
|
358
|
+
applet_maintainer "foo"
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
assert_equal "foo", @appletclass.signature.maintainer
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def test_applet_appicon_directive_should_set_signature_appicon
|
|
366
|
+
assert_not_equal "foo.png", @appletclass.signature.appicon
|
|
367
|
+
|
|
368
|
+
assert_nothing_raised do
|
|
369
|
+
@appletclass.class_eval do
|
|
370
|
+
applet_maintainer "foo.png"
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
assert_equal "foo.png", @appletclass.signature.maintainer
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def test_applet_version_directive_should_set_signature_version
|
|
378
|
+
assert_not_equal "200.1", @appletclass.signature.version
|
|
379
|
+
|
|
380
|
+
assert_nothing_raised do
|
|
381
|
+
@appletclass.class_eval do
|
|
382
|
+
applet_version "200.1"
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
assert_equal "200.1", @appletclass.signature.version
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def test_default_action_directive_should_set_signature_default_action
|
|
390
|
+
assert_not_equal :edit, @appletclass.signature.default_action
|
|
391
|
+
|
|
392
|
+
assert_nothing_raised do
|
|
393
|
+
@appletclass.class_eval do
|
|
394
|
+
default_action :edit
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
assert_equal "edit", @appletclass.signature.default_action
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def test_run_should_track_run_times
|
|
403
|
+
assert_equal 0.0, @applet.total_utime
|
|
404
|
+
assert_equal 0.0, @applet.total_stime
|
|
405
|
+
|
|
406
|
+
@applet.def_action_body do |txn|
|
|
407
|
+
# This will hopefully take more than 0.0 seconds on any machine.
|
|
408
|
+
10_000.times do
|
|
409
|
+
# This causes a system access, which makes for stime
|
|
410
|
+
# the previous code was only usertime on my linux machine -JJ
|
|
411
|
+
d = Dir.open('.')
|
|
412
|
+
d.close
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
with_run_fixtured_transaction do |txn|
|
|
417
|
+
@applet.run( txn, "test" )
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
assert (@applet.total_utime > 0.0),
|
|
421
|
+
"Applet utime after run: %0.5f" % [@applet.total_utime]
|
|
422
|
+
assert (@applet.total_stime > 0.0),
|
|
423
|
+
"Applet stime after run: %0.5f" % [@applet.total_stime]
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def test_defining_an_action_method_with_inappropriate_arity_should_raise_scripterror
|
|
428
|
+
assert_raises( ScriptError ) do
|
|
429
|
+
@appletclass.class_eval { def malformed_action; end }
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def test_running_against_action_method_with_inappropriate_arity_should_raise_appleterror
|
|
435
|
+
# We have to sneak a method past the ::method_added check...
|
|
436
|
+
@appletclass.class_eval do
|
|
437
|
+
def self::method_added(sym); end
|
|
438
|
+
def malformed_action; end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
assert_raises( Arrow::AppletError ) do
|
|
442
|
+
with_run_fixtured_transaction do |txn|
|
|
443
|
+
@applet.run( txn, "malformed" )
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def test_run_with_two_arg_action_sends_the_appropriate_number_of_args
|
|
450
|
+
@appletclass.class_eval do
|
|
451
|
+
def two_arg_action( txn, arg )
|
|
452
|
+
[ txn, arg ]
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
@applet = @appletclass.new( nil, nil, nil )
|
|
456
|
+
|
|
457
|
+
with_run_fixtured_transaction do |txn|
|
|
458
|
+
rval = @applet.run( txn, "two_arg", "arg1", "arg2", "arg3" )
|
|
459
|
+
|
|
460
|
+
assert_instance_of Array, rval
|
|
461
|
+
assert_equal 2, rval.length
|
|
462
|
+
assert_same txn, rval.first
|
|
463
|
+
assert_equal "arg1", rval[1]
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def test_run_with_block_yields_action_method_and_transaction_instead_of_invoking
|
|
470
|
+
rval, meth, rtxn, rargs = nil
|
|
471
|
+
|
|
472
|
+
with_run_fixtured_transaction do |txn|
|
|
473
|
+
rval = @applet.run( txn, "test", "arg1", "arg2" ) do |metharg, txn2, *args|
|
|
474
|
+
meth = metharg
|
|
475
|
+
rtxn = txn2
|
|
476
|
+
rargs = args
|
|
477
|
+
|
|
478
|
+
:passed
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
assert_instance_of Method, meth
|
|
482
|
+
assert_match( /#test_action/, meth.to_s )
|
|
483
|
+
assert_same txn, rtxn
|
|
484
|
+
assert_equal ["arg1", "arg2"], rargs
|
|
485
|
+
|
|
486
|
+
assert_equal :passed, rval
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def test_run_with_parameterless_action_method_raises_an_appleterror
|
|
492
|
+
@applet.def_action_body do
|
|
493
|
+
flunk "Expected exception before action body was run"
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
with_run_fixtured_transaction do |txn|
|
|
497
|
+
assert_raises( Arrow::AppletError ) do
|
|
498
|
+
@applet.run( txn, "malformed" )
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def test_run_without_an_action_invokes_the_default_action
|
|
505
|
+
invoked = false
|
|
506
|
+
|
|
507
|
+
@applet.def_action_body do
|
|
508
|
+
invoked = true
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
with_run_fixtured_transaction do |txn|
|
|
512
|
+
rval = @applet.run( txn )
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
assert_equal true, invoked, "Default action was not invoked"
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def test_looking_up_a_valid_action_method_should_return_method_object_for_it
|
|
520
|
+
rval = nil
|
|
521
|
+
args = []
|
|
522
|
+
|
|
523
|
+
assert_nothing_raised do
|
|
524
|
+
rval, *args = @applet.send( :lookup_action_method, nil, "test" )
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
assert_instance_of Method, rval
|
|
528
|
+
assert_match( /#test_action/, rval.to_s )
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def test_default_delegation_method_just_yields
|
|
535
|
+
rval = nil
|
|
536
|
+
|
|
537
|
+
assert_nothing_raised do
|
|
538
|
+
rval = @applet.delegate( nil, [:chain] ) {|arg| rval = arg }
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
assert_equal [:chain], rval
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def test_subrun_from_delegation_populates_txn_vargs
|
|
546
|
+
|
|
547
|
+
# Define the delegator and an action to subrun
|
|
548
|
+
@appletclass.class_eval do
|
|
549
|
+
def delegate( txn, chain, *args )
|
|
550
|
+
self.subrun( 'test_vargs', txn, *args )
|
|
551
|
+
end
|
|
552
|
+
def test_vargs_action( txn, *args )
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
applet = @appletclass.new( nil, nil, nil )
|
|
557
|
+
|
|
558
|
+
# Even though it's not a real #run, the transaction should be
|
|
559
|
+
# set up the same way passing through #subrun
|
|
560
|
+
with_run_fixtured_transaction do |txn, req|
|
|
561
|
+
txn.should_receive( :vargs ).and_return(nil).at_least.once
|
|
562
|
+
|
|
563
|
+
assert_nothing_raised do
|
|
564
|
+
applet.delegate( txn, nil )
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
end # describe "concrete subclass"
|
|
571
|
+
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
# vim: set nosta noet ts=4 sw=4:
|