arrow 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. data/ChangeLog +1590 -0
  2. data/LICENSE +28 -0
  3. data/README +75 -0
  4. data/Rakefile +366 -0
  5. data/Rakefile.local +63 -0
  6. data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
  7. data/data/arrow/applets/args.rb +50 -0
  8. data/data/arrow/applets/config.rb +55 -0
  9. data/data/arrow/applets/error.rb +63 -0
  10. data/data/arrow/applets/files.rb +46 -0
  11. data/data/arrow/applets/inspect.rb +46 -0
  12. data/data/arrow/applets/nosuchapplet.rb +31 -0
  13. data/data/arrow/applets/status.rb +92 -0
  14. data/data/arrow/applets/test.rb +133 -0
  15. data/data/arrow/applets/tutorial/counter.rb +96 -0
  16. data/data/arrow/applets/tutorial/dingus.rb +67 -0
  17. data/data/arrow/applets/tutorial/hello.rb +34 -0
  18. data/data/arrow/applets/tutorial/hello2.rb +73 -0
  19. data/data/arrow/applets/tutorial/imgtext.rb +90 -0
  20. data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
  21. data/data/arrow/applets/tutorial/index.rb +36 -0
  22. data/data/arrow/applets/tutorial/logo.rb +98 -0
  23. data/data/arrow/applets/tutorial/memcache.rb +61 -0
  24. data/data/arrow/applets/tutorial/missing.rb +37 -0
  25. data/data/arrow/applets/tutorial/protected.rb +100 -0
  26. data/data/arrow/applets/tutorial/redirector.rb +52 -0
  27. data/data/arrow/applets/tutorial/rndimages.rb +159 -0
  28. data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
  29. data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
  30. data/data/arrow/applets/tutorial/superhello.rb +72 -0
  31. data/data/arrow/applets/tutorial/timeclock.rb +78 -0
  32. data/data/arrow/applets/view-applet.rb +123 -0
  33. data/data/arrow/applets/view-template.rb +85 -0
  34. data/data/arrow/applets/wiki.rb +274 -0
  35. data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
  36. data/data/arrow/templates/applet-status.tmpl +153 -0
  37. data/data/arrow/templates/args-display.tmpl +120 -0
  38. data/data/arrow/templates/config/display-table.tmpl +36 -0
  39. data/data/arrow/templates/config/display.tmpl +36 -0
  40. data/data/arrow/templates/counter-deleted.tmpl +33 -0
  41. data/data/arrow/templates/counter.tmpl +59 -0
  42. data/data/arrow/templates/dingus.tmpl +55 -0
  43. data/data/arrow/templates/enumtable.tmpl +8 -0
  44. data/data/arrow/templates/error-display.tmpl +92 -0
  45. data/data/arrow/templates/filemap.tmpl +89 -0
  46. data/data/arrow/templates/hello-world-src.tmpl +34 -0
  47. data/data/arrow/templates/hello-world.tmpl +60 -0
  48. data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
  49. data/data/arrow/templates/imgtext/form.tmpl +70 -0
  50. data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
  51. data/data/arrow/templates/imgtext/reload.tmpl +55 -0
  52. data/data/arrow/templates/inspect/display.tmpl +80 -0
  53. data/data/arrow/templates/loginform.tmpl +64 -0
  54. data/data/arrow/templates/logout.tmpl +32 -0
  55. data/data/arrow/templates/memcache/display.tmpl +41 -0
  56. data/data/arrow/templates/navbar.incl +27 -0
  57. data/data/arrow/templates/nosuchapplet.tmpl +32 -0
  58. data/data/arrow/templates/printsource.tmpl +35 -0
  59. data/data/arrow/templates/protected.tmpl +36 -0
  60. data/data/arrow/templates/rndimages.tmpl +38 -0
  61. data/data/arrow/templates/service-response.tmpl +13 -0
  62. data/data/arrow/templates/sharenotes/display.tmpl +38 -0
  63. data/data/arrow/templates/status.tmpl +120 -0
  64. data/data/arrow/templates/templateviewer.tmpl +43 -0
  65. data/data/arrow/templates/test/harness.tmpl +57 -0
  66. data/data/arrow/templates/test/list.tmpl +48 -0
  67. data/data/arrow/templates/test/problem.tmpl +42 -0
  68. data/data/arrow/templates/tutorial/index.tmpl +37 -0
  69. data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
  70. data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
  71. data/data/arrow/templates/view-applet.tmpl +40 -0
  72. data/data/arrow/templates/view-template.tmpl +83 -0
  73. data/data/arrow/templates/wiki/formerror.tmpl +47 -0
  74. data/data/arrow/templates/wiki/markup_help.incl +6 -0
  75. data/data/arrow/templates/wiki/new.tmpl +56 -0
  76. data/data/arrow/templates/wiki/new_system.tmpl +122 -0
  77. data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
  78. data/data/arrow/templates/wiki/show.tmpl +34 -0
  79. data/docs/manual/layouts/default.page +43 -0
  80. data/docs/manual/lib/api-filter.rb +81 -0
  81. data/docs/manual/lib/editorial-filter.rb +64 -0
  82. data/docs/manual/lib/examples-filter.rb +244 -0
  83. data/docs/manual/lib/links-filter.rb +117 -0
  84. data/lib/apache/fakerequest.rb +448 -0
  85. data/lib/apache/logger.rb +33 -0
  86. data/lib/arrow.rb +51 -0
  87. data/lib/arrow/acceptparam.rb +207 -0
  88. data/lib/arrow/applet.rb +725 -0
  89. data/lib/arrow/appletmixins.rb +218 -0
  90. data/lib/arrow/appletregistry.rb +590 -0
  91. data/lib/arrow/applettestcase.rb +503 -0
  92. data/lib/arrow/broker.rb +255 -0
  93. data/lib/arrow/cache.rb +176 -0
  94. data/lib/arrow/config-loaders/yaml.rb +75 -0
  95. data/lib/arrow/config.rb +615 -0
  96. data/lib/arrow/constants.rb +24 -0
  97. data/lib/arrow/cookie.rb +359 -0
  98. data/lib/arrow/cookieset.rb +108 -0
  99. data/lib/arrow/dispatcher.rb +368 -0
  100. data/lib/arrow/dispatcherloader.rb +50 -0
  101. data/lib/arrow/exceptions.rb +61 -0
  102. data/lib/arrow/fallbackhandler.rb +48 -0
  103. data/lib/arrow/formvalidator.rb +631 -0
  104. data/lib/arrow/htmltokenizer.rb +343 -0
  105. data/lib/arrow/logger.rb +488 -0
  106. data/lib/arrow/logger/apacheoutputter.rb +69 -0
  107. data/lib/arrow/logger/arrayoutputter.rb +63 -0
  108. data/lib/arrow/logger/coloroutputter.rb +111 -0
  109. data/lib/arrow/logger/fileoutputter.rb +96 -0
  110. data/lib/arrow/logger/htmloutputter.rb +54 -0
  111. data/lib/arrow/logger/outputter.rb +123 -0
  112. data/lib/arrow/mixins.rb +425 -0
  113. data/lib/arrow/monkeypatches.rb +94 -0
  114. data/lib/arrow/object.rb +117 -0
  115. data/lib/arrow/path.rb +196 -0
  116. data/lib/arrow/service.rb +447 -0
  117. data/lib/arrow/session.rb +289 -0
  118. data/lib/arrow/session/dbstore.rb +100 -0
  119. data/lib/arrow/session/filelock.rb +160 -0
  120. data/lib/arrow/session/filestore.rb +132 -0
  121. data/lib/arrow/session/id.rb +98 -0
  122. data/lib/arrow/session/lock.rb +253 -0
  123. data/lib/arrow/session/md5id.rb +42 -0
  124. data/lib/arrow/session/nulllock.rb +42 -0
  125. data/lib/arrow/session/posixlock.rb +166 -0
  126. data/lib/arrow/session/sha1id.rb +54 -0
  127. data/lib/arrow/session/store.rb +366 -0
  128. data/lib/arrow/session/usertrackid.rb +52 -0
  129. data/lib/arrow/spechelpers.rb +73 -0
  130. data/lib/arrow/template.rb +713 -0
  131. data/lib/arrow/template/attr.rb +31 -0
  132. data/lib/arrow/template/call.rb +31 -0
  133. data/lib/arrow/template/comment.rb +33 -0
  134. data/lib/arrow/template/container.rb +118 -0
  135. data/lib/arrow/template/else.rb +41 -0
  136. data/lib/arrow/template/elsif.rb +44 -0
  137. data/lib/arrow/template/escape.rb +53 -0
  138. data/lib/arrow/template/export.rb +87 -0
  139. data/lib/arrow/template/for.rb +145 -0
  140. data/lib/arrow/template/if.rb +78 -0
  141. data/lib/arrow/template/import.rb +119 -0
  142. data/lib/arrow/template/include.rb +206 -0
  143. data/lib/arrow/template/iterator.rb +208 -0
  144. data/lib/arrow/template/nodes.rb +734 -0
  145. data/lib/arrow/template/parser.rb +571 -0
  146. data/lib/arrow/template/prettyprint.rb +53 -0
  147. data/lib/arrow/template/render.rb +191 -0
  148. data/lib/arrow/template/selectlist.rb +94 -0
  149. data/lib/arrow/template/set.rb +87 -0
  150. data/lib/arrow/template/timedelta.rb +81 -0
  151. data/lib/arrow/template/unless.rb +78 -0
  152. data/lib/arrow/template/urlencode.rb +51 -0
  153. data/lib/arrow/template/yield.rb +139 -0
  154. data/lib/arrow/templatefactory.rb +125 -0
  155. data/lib/arrow/testcase.rb +567 -0
  156. data/lib/arrow/transaction.rb +608 -0
  157. data/rake/191_compat.rb +26 -0
  158. data/rake/dependencies.rb +76 -0
  159. data/rake/documentation.rb +114 -0
  160. data/rake/helpers.rb +502 -0
  161. data/rake/hg.rb +282 -0
  162. data/rake/manual.rb +787 -0
  163. data/rake/packaging.rb +129 -0
  164. data/rake/publishing.rb +278 -0
  165. data/rake/style.rb +62 -0
  166. data/rake/svn.rb +668 -0
  167. data/rake/testing.rb +187 -0
  168. data/rake/verifytask.rb +64 -0
  169. data/spec/arrow/acceptparam_spec.rb +157 -0
  170. data/spec/arrow/applet_spec.rb +575 -0
  171. data/spec/arrow/appletmixins_spec.rb +409 -0
  172. data/spec/arrow/appletregistry_spec.rb +294 -0
  173. data/spec/arrow/broker_spec.rb +153 -0
  174. data/spec/arrow/config_spec.rb +224 -0
  175. data/spec/arrow/cookieset_spec.rb +164 -0
  176. data/spec/arrow/dispatcher_spec.rb +137 -0
  177. data/spec/arrow/dispatcherloader_spec.rb +65 -0
  178. data/spec/arrow/formvalidator_spec.rb +781 -0
  179. data/spec/arrow/logger_spec.rb +346 -0
  180. data/spec/arrow/mixins_spec.rb +120 -0
  181. data/spec/arrow/service_spec.rb +645 -0
  182. data/spec/arrow/session_spec.rb +121 -0
  183. data/spec/arrow/template/iterator_spec.rb +222 -0
  184. data/spec/arrow/templatefactory_spec.rb +185 -0
  185. data/spec/arrow/transaction_spec.rb +319 -0
  186. data/spec/arrow_spec.rb +37 -0
  187. data/spec/lib/appletmatchers.rb +281 -0
  188. data/spec/lib/constants.rb +77 -0
  189. data/spec/lib/helpers.rb +41 -0
  190. data/spec/lib/matchers.rb +44 -0
  191. data/tests/cookie.tests.rb +310 -0
  192. data/tests/path.tests.rb +157 -0
  193. data/tests/session.tests.rb +111 -0
  194. data/tests/session_id.tests.rb +82 -0
  195. data/tests/session_lock.tests.rb +191 -0
  196. data/tests/session_store.tests.rb +53 -0
  197. data/tests/template.tests.rb +1360 -0
  198. metadata +339 -0
@@ -0,0 +1,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
+
@@ -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: