ruby-web 1.1.1
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 +474 -0
- data/INSTALL.txt +9 -0
- data/InstalledFiles +180 -0
- data/LICENSE.txt +74 -0
- data/Rakefile +529 -0
- data/TODO +65 -0
- data/doc/additional.xml +149 -0
- data/doc/core.xml +652 -0
- data/doc/credits/index.xml +52 -0
- data/doc/credits/php.contributors.xml +118 -0
- data/doc/credits/php.language-snippets.ent +622 -0
- data/doc/install/index.xml +136 -0
- data/doc/install/mac/index.xml +21 -0
- data/doc/install/ruby-web.install.rb.instructions.xml +7 -0
- data/doc/install/unix/index.xml +46 -0
- data/doc/install/win/apache1.xml +166 -0
- data/doc/install/win/apache2.xml +141 -0
- data/doc/install/win/iis.xml +162 -0
- data/doc/install/win/index.xml +24 -0
- data/doc/install/win/installer.xml +31 -0
- data/doc/install/win/manual.xml +43 -0
- data/doc/manual.xml +69 -0
- data/doc/old/apache_cgi.txt +23 -0
- data/doc/old/fastcgi.txt +23 -0
- data/doc/old/mod_ruby.txt +21 -0
- data/doc/old/snippets.rdoc +183 -0
- data/doc/old/webrick.txt +23 -0
- data/doc/old/windows_cgi.txt +9 -0
- data/doc/tutorial.xml +14 -0
- data/doc/xsl/manual-multi.xsl +10 -0
- data/doc/xsl/manual-pdf.xsl +6 -0
- data/doc/xsl/manual-single.xsl +6 -0
- data/doc/xsl/manual.css +22 -0
- data/install.rb +1022 -0
- data/lib/formatter.rb +314 -0
- data/lib/html-parser.rb +429 -0
- data/lib/htmlrepair.rb +113 -0
- data/lib/htmlsplit.rb +842 -0
- data/lib/sgml-parser.rb +332 -0
- data/lib/web.rb +68 -0
- data/lib/web/assertinclude.rb +129 -0
- data/lib/web/config.rb +50 -0
- data/lib/web/connection.rb +1070 -0
- data/lib/web/convenience.rb +154 -0
- data/lib/web/formreader.rb +318 -0
- data/lib/web/htmlparser/html-parser.rb +429 -0
- data/lib/web/htmlparser/sgml-parser.rb +332 -0
- data/lib/web/htmltools/element.rb +296 -0
- data/lib/web/htmltools/stparser.rb +276 -0
- data/lib/web/htmltools/tags.rb +286 -0
- data/lib/web/htmltools/tree.rb +139 -0
- data/lib/web/htmltools/xmltree.rb +160 -0
- data/lib/web/htmltools/xpath.rb +71 -0
- data/lib/web/info.rb +63 -0
- data/lib/web/load.rb +210 -0
- data/lib/web/mime.rb +87 -0
- data/lib/web/phprb.rb +340 -0
- data/lib/web/resources/test/cookie.rb +33 -0
- data/lib/web/resources/test/counter.rb +20 -0
- data/lib/web/resources/test/multipart.rb +14 -0
- data/lib/web/resources/test/redirect.rb +8 -0
- data/lib/web/resources/test/stock.rb +33 -0
- data/lib/web/sapi/apache.rb +129 -0
- data/lib/web/sapi/fastcgi.rb +22 -0
- data/lib/web/sapi/install/apache.rb +180 -0
- data/lib/web/sapi/install/iis.rb +93 -0
- data/lib/web/sapi/install/macosx.rb +90 -0
- data/lib/web/sapi/webrick.rb +86 -0
- data/lib/web/session.rb +83 -0
- data/lib/web/shim/cgi.rb +129 -0
- data/lib/web/shim/rails.rb +175 -0
- data/lib/web/stringio.rb +78 -0
- data/lib/web/strscanparser.rb +24 -0
- data/lib/web/tagparser.rb +96 -0
- data/lib/web/testing.rb +666 -0
- data/lib/web/traceoutput.rb +75 -0
- data/lib/web/unit.rb +56 -0
- data/lib/web/upload.rb +59 -0
- data/lib/web/validate.rb +52 -0
- data/lib/web/wiki.rb +557 -0
- data/lib/web/wiki/linker.rb +72 -0
- data/lib/web/wiki/page.rb +201 -0
- data/lib/webunit.rb +27 -0
- data/lib/webunit/assert.rb +152 -0
- data/lib/webunit/converter.rb +154 -0
- data/lib/webunit/cookie.rb +118 -0
- data/lib/webunit/domwalker.rb +185 -0
- data/lib/webunit/exception.rb +14 -0
- data/lib/webunit/form.rb +116 -0
- data/lib/webunit/frame.rb +37 -0
- data/lib/webunit/htmlelem.rb +122 -0
- data/lib/webunit/image.rb +26 -0
- data/lib/webunit/jscript.rb +31 -0
- data/lib/webunit/link.rb +33 -0
- data/lib/webunit/params.rb +321 -0
- data/lib/webunit/parser.rb +229 -0
- data/lib/webunit/response.rb +464 -0
- data/lib/webunit/runtest.rb +41 -0
- data/lib/webunit/table.rb +148 -0
- data/lib/webunit/testcase.rb +45 -0
- data/lib/webunit/ui/cui/testrunner.rb +50 -0
- data/lib/webunit/utils.rb +68 -0
- data/lib/webunit/webunit.rb +28 -0
- data/test/dev/action.rb +83 -0
- data/test/dev/forms.rb +104 -0
- data/test/dev/forms2.rb +104 -0
- data/test/dev/parser.rb +17 -0
- data/test/dev/scripts/dump.rb +24 -0
- data/test/dev/scripts/makedist.rb +62 -0
- data/test/dev/scripts/uri.rb +41 -0
- data/test/dev/scripts/uri/common.rb +432 -0
- data/test/dev/scripts/uri/ftp.rb +149 -0
- data/test/dev/scripts/uri/generic.rb +1106 -0
- data/test/dev/scripts/uri/http.rb +76 -0
- data/test/dev/scripts/uri/https.rb +26 -0
- data/test/dev/scripts/uri/ldap.rb +238 -0
- data/test/dev/scripts/uri/mailto.rb +260 -0
- data/test/dev/scripts/urireg.rb +174 -0
- data/test/dev/simpledispatcher.rb +156 -0
- data/test/dev/test.action.rb +146 -0
- data/test/dev/test.formreader.rb +463 -0
- data/test/dev/test.simpledispatcher.rb +186 -0
- data/test/dev/webunit/conv/digit-0.rb +21 -0
- data/test/dev/webunit/conv/digit-1.rb +17 -0
- data/test/dev/webunit/conv/digit.rb +23 -0
- data/test/dev/webunit/conv/test_digit-0.rb +16 -0
- data/test/dev/webunit/conv/test_digit-1.rb +19 -0
- data/test/dev/webunit/conv/test_digit.rb +26 -0
- data/test/dev/webunit/conv/test_digit_view-0.rb +76 -0
- data/test/dev/webunit/conv/test_digit_view-1.rb +102 -0
- data/test/dev/webunit/conv/test_digit_view.rb +134 -0
- data/test/installation/htdocs/cgi_test.rb +296 -0
- data/test/installation/htdocs/test_install.rb +4 -0
- data/test/installation/runwebtest.rb +5 -0
- data/test/installation/test_cookie.rb +128 -0
- data/test/installation/test_form.rb +47 -0
- data/test/installation/test_multipart.rb +51 -0
- data/test/installation/test_request.rb +24 -0
- data/test/installation/test_response.rb +35 -0
- data/test/unit/htdocs/cookie.rb +32 -0
- data/test/unit/htdocs/multipart.rb +28 -0
- data/test/unit/htdocs/redirect.rb +12 -0
- data/test/unit/htdocs/simple.rb +13 -0
- data/test/unit/htdocs/stock.rb +33 -0
- data/test/unit/test_assert.rb +162 -0
- data/test/unit/test_cookie.rb +114 -0
- data/test/unit/test_domwalker.rb +77 -0
- data/test/unit/test_form.rb +42 -0
- data/test/unit/test_frame.rb +40 -0
- data/test/unit/test_htmlelem.rb +74 -0
- data/test/unit/test_image.rb +45 -0
- data/test/unit/test_jscript.rb +57 -0
- data/test/unit/test_link.rb +85 -0
- data/test/unit/test_multipart.rb +51 -0
- data/test/unit/test_params.rb +210 -0
- data/test/unit/test_parser.rb +53 -0
- data/test/unit/test_response.rb +150 -0
- data/test/unit/test_table.rb +70 -0
- data/test/unit/test_utils.rb +106 -0
- data/test/unit/test_webunit.rb +28 -0
- data/test/web/mod_ruby_stub.rb +39 -0
- data/test/web/test.assertinclude.rb +109 -0
- data/test/web/test.buffer.rb +182 -0
- data/test/web/test.code.loader.rb +78 -0
- data/test/web/test.config.rb +31 -0
- data/test/web/test.error.handling.rb +91 -0
- data/test/web/test.formreader-2.0.rb +352 -0
- data/test/web/test.load.rb +125 -0
- data/test/web/test.mime-type.rb +23 -0
- data/test/web/test.narf.cgi.rb +106 -0
- data/test/web/test.phprb.rb +239 -0
- data/test/web/test.request.rb +368 -0
- data/test/web/test.response.rb +637 -0
- data/test/web/test.ruby-web.rb +10 -0
- data/test/web/test.session.rb +50 -0
- data/test/web/test.shim.cgi.rb +96 -0
- data/test/web/test.tagparser.rb +65 -0
- data/test/web/test.template2.rb +297 -0
- data/test/web/test.testing2.rb +318 -0
- data/test/web/test.upload.rb +45 -0
- data/test/web/test.validate.rb +46 -0
- data/test/web/test.web.test.rb +495 -0
- data/test/wiki/test.history.rb +297 -0
- data/test/wiki/test.illustration_page.rb +287 -0
- data/test/wiki/test.linker.rb +197 -0
- data/test/wiki/test.tarpit.rb +56 -0
- data/test/wiki/test.wiki.rb +300 -0
- data/test/wikitestroot/admin.rb +7 -0
- data/test/wikitestroot/wiki.rb +6 -0
- metadata +234 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#require 'action_controller/cgi_ext/cgi_ext'
|
|
2
|
+
#require 'action_controller/cgi_ext/cookie_performance_fix'
|
|
3
|
+
#require 'action_controller/cgi_ext/raw_post_data_fix'
|
|
4
|
+
#require 'action_controller/session/drb_store'
|
|
5
|
+
#require 'action_controller/session/mem_cache_store'
|
|
6
|
+
#if Object.const_defined?(:ActiveRecord)
|
|
7
|
+
# require 'action_controller/session/active_record_store'
|
|
8
|
+
#end
|
|
9
|
+
|
|
10
|
+
module ActionController #:nodoc:
|
|
11
|
+
class Base
|
|
12
|
+
# Derived from CGI controller.
|
|
13
|
+
# Process a request extracted from an CGI object and return a response. Pass false as <tt>session_options</tt> to disable
|
|
14
|
+
# sessions (large performance increase if sessions are not needed). The <tt>session_options</tt> are the same as for CGI::Session:
|
|
15
|
+
#
|
|
16
|
+
# * <tt>:database_manager</tt> - standard options are CGI::Session::FileStore, CGI::Session::MemoryStore, and CGI::Session::PStore
|
|
17
|
+
# (default). Additionally, there is CGI::Session::DRbStore and CGI::Session::ActiveRecordStore. Read more about these in
|
|
18
|
+
# lib/action_controller/session.
|
|
19
|
+
# * <tt>:session_key</tt> - the parameter name used for the session id. Defaults to '_session_id'.
|
|
20
|
+
# * <tt>:session_id</tt> - the session id to use. If not provided, then it is retrieved from the +session_key+ parameter
|
|
21
|
+
# of the request, or automatically generated for a new session.
|
|
22
|
+
# * <tt>:new_session</tt> - if true, force creation of a new session. If not set, a new session is only created if none currently
|
|
23
|
+
# exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set,
|
|
24
|
+
# an ArgumentError is raised.
|
|
25
|
+
# * <tt>:session_expires</tt> - the time the current session expires, as a +Time+ object. If not set, the session will continue
|
|
26
|
+
# indefinitely.
|
|
27
|
+
# * <tt>:session_domain</tt> - the hostname domain for which this session is valid. If not set, defaults to the hostname of the
|
|
28
|
+
# server.
|
|
29
|
+
# * <tt>:session_secure</tt> - if +true+, this session will only work over HTTPS.
|
|
30
|
+
# * <tt>:session_path</tt> - the path for which this session applies. Defaults to the directory of the CGI script.
|
|
31
|
+
def self.process_cgi(cgi = CGI.new, session_options = {})
|
|
32
|
+
new.process_cgi(cgi, session_options)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def process_cgi(cgi, session_options = {}) #:nodoc:
|
|
36
|
+
process(CgiRequest.new(cgi, session_options), CgiResponse.new(cgi)).out
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class CgiRequest < AbstractRequest #:nodoc:
|
|
41
|
+
attr_accessor :cgi
|
|
42
|
+
|
|
43
|
+
DEFAULT_SESSION_OPTIONS = {
|
|
44
|
+
:database_manager => CGI::Session::PStore,
|
|
45
|
+
:prefix => "ruby_sess.",
|
|
46
|
+
:session_path => "/"
|
|
47
|
+
} unless const_defined?(:DEFAULT_SESSION_OPTIONS)
|
|
48
|
+
|
|
49
|
+
def initialize(cgi, session_options = {})
|
|
50
|
+
@cgi = cgi
|
|
51
|
+
@session_options = session_options
|
|
52
|
+
super()
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def query_string
|
|
56
|
+
return @cgi.query_string unless @cgi.query_string.nil? || @cgi.query_string.empty?
|
|
57
|
+
unless env['REQUEST_URI'].nil?
|
|
58
|
+
parts = env['REQUEST_URI'].split('?')
|
|
59
|
+
else
|
|
60
|
+
return env['QUERY_STRING'] || ''
|
|
61
|
+
end
|
|
62
|
+
parts.shift
|
|
63
|
+
return parts.join('?')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def query_parameters
|
|
67
|
+
qs = self.query_string
|
|
68
|
+
qs.empty? ? {} : CGIMethods.parse_query_parameters(query_string)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def request_parameters
|
|
72
|
+
if formatted_post?
|
|
73
|
+
CGIMethods.parse_formatted_request_parameters(post_format, env['RAW_POST_DATA'])
|
|
74
|
+
else
|
|
75
|
+
CGIMethods.parse_request_parameters(@cgi.params)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def env
|
|
80
|
+
@cgi.send(:env_table)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def cookies
|
|
84
|
+
@cgi.cookies.freeze
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def host
|
|
88
|
+
env["HTTP_X_FORWARDED_HOST"] || @cgi.host.to_s.split(":").first
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def session
|
|
92
|
+
return @session unless @session.nil?
|
|
93
|
+
|
|
94
|
+
begin
|
|
95
|
+
@session = (@session_options == false ? {} : CGI::Session.new(@cgi, session_options_with_string_keys))
|
|
96
|
+
@session["__valid_session"]
|
|
97
|
+
return @session
|
|
98
|
+
rescue ArgumentError => e
|
|
99
|
+
if e.message =~ %r{undefined class/module (\w+)}
|
|
100
|
+
begin
|
|
101
|
+
Module.const_missing($1)
|
|
102
|
+
rescue LoadError, NameError => e
|
|
103
|
+
raise(
|
|
104
|
+
ActionController::SessionRestoreError,
|
|
105
|
+
"Session contained objects where the class definition wasn't available. " +
|
|
106
|
+
"Remember to require classes for all objects kept in the session. " +
|
|
107
|
+
"(Original exception: #{e.message} [#{e.class}])"
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
retry
|
|
112
|
+
else
|
|
113
|
+
raise
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def reset_session
|
|
119
|
+
@session.delete
|
|
120
|
+
@session = (@session_options == false ? {} : new_session)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def method_missing(method_id, *arguments)
|
|
124
|
+
@cgi.send(method_id, *arguments) rescue super
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
def new_session
|
|
129
|
+
CGI::Session.new(@cgi, session_options_with_string_keys.merge("new_session" => true))
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def session_options_with_string_keys
|
|
133
|
+
DEFAULT_SESSION_OPTIONS.merge(@session_options).inject({}) { |options, pair| options[pair.first.to_s] = pair.last; options }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class CgiResponse < AbstractResponse #:nodoc:
|
|
138
|
+
def initialize(cgi)
|
|
139
|
+
@cgi = cgi
|
|
140
|
+
super()
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def out(output = $stdout)
|
|
144
|
+
convert_content_type!(@headers)
|
|
145
|
+
output.binmode if output.respond_to?(:binmode)
|
|
146
|
+
output.sync = false if output.respond_to?(:sync=)
|
|
147
|
+
|
|
148
|
+
begin
|
|
149
|
+
output.write(@cgi.header(@headers))
|
|
150
|
+
|
|
151
|
+
if @cgi.send(:env_table)['REQUEST_METHOD'] == 'HEAD'
|
|
152
|
+
return
|
|
153
|
+
elsif @body.respond_to?(:call)
|
|
154
|
+
@body.call(self)
|
|
155
|
+
else
|
|
156
|
+
output.write(@body)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
output.flush if output.respond_to?(:flush)
|
|
160
|
+
rescue Errno::EPIPE => e
|
|
161
|
+
# lost connection to the FCGI process -- ignore the output, then
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
def convert_content_type!(headers)
|
|
167
|
+
%w( Content-Type Content-type content-type ).each do |ct|
|
|
168
|
+
if headers[ct]
|
|
169
|
+
headers["type"] = headers[ct]
|
|
170
|
+
headers.delete(ct)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
data/lib/web/stringio.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Web
|
|
2
|
+
# WritableIO uses << operator to add io style write, print, and puts methods
|
|
3
|
+
module WritableIO # :nodoc:
|
|
4
|
+
# writes object to output stream
|
|
5
|
+
def write object
|
|
6
|
+
self << object
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# writes objects to the output stream
|
|
10
|
+
def print( *objects )
|
|
11
|
+
if (objects.empty?)
|
|
12
|
+
self << $_
|
|
13
|
+
else
|
|
14
|
+
self << objects.collect{ |s| s.to_s }.join("")
|
|
15
|
+
end
|
|
16
|
+
if $\ then self << $\ end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# writes multiple lines to the output stream
|
|
20
|
+
def puts( *objects )
|
|
21
|
+
objects.flatten!
|
|
22
|
+
self << objects.collect{ |s|
|
|
23
|
+
s.to_s
|
|
24
|
+
}.collect{ |s|
|
|
25
|
+
unless ( /(\r|\n)\z/ =~ s )
|
|
26
|
+
s + $/
|
|
27
|
+
else
|
|
28
|
+
s
|
|
29
|
+
end
|
|
30
|
+
}.join("")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
require('stringio')
|
|
37
|
+
rescue LoadError
|
|
38
|
+
module Web
|
|
39
|
+
class StringIO # :nodoc:
|
|
40
|
+
def initialize
|
|
41
|
+
@___content___ = ""
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def read
|
|
45
|
+
@___content___
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def clear
|
|
49
|
+
@___content___ = ""
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def string
|
|
53
|
+
@___content___
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def puts(*args)
|
|
57
|
+
@___content___ << args.join("\n") << "\n"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def << var
|
|
61
|
+
@___content___ << var.to_s
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def write var
|
|
65
|
+
@___content___ << var.to_s
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def print var
|
|
69
|
+
@___content___ << var.to_s
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
unless Kernel.const_defined? "StringIO"
|
|
75
|
+
StringIO = Web::StringIO.clone
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class StrScanParserR # :nodoc:
|
|
2
|
+
def initialize scanner
|
|
3
|
+
@scanner = scanner
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def match regex, &block
|
|
7
|
+
if s = @scanner.scan(regex)
|
|
8
|
+
# $stderr.puts "got: #{s}"
|
|
9
|
+
yield @scanner if block
|
|
10
|
+
s
|
|
11
|
+
else
|
|
12
|
+
# $stderr.puts "tried #{regex.source} on: #{@scanner.rest}"
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def rest?
|
|
18
|
+
@scanner.rest?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def rest
|
|
22
|
+
@scanner.rest
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Struct.new("Tag",:name,:attributes)
|
|
2
|
+
Tag = Struct::Tag
|
|
3
|
+
|
|
4
|
+
class StrScanParser < StrScanParserR #:nodoc:
|
|
5
|
+
|
|
6
|
+
TAG_START = /<narf:/
|
|
7
|
+
TAG_END = />/
|
|
8
|
+
TAG_CLOSE_START = /<\/narf:/
|
|
9
|
+
TAG_NAME = /(\w+)/
|
|
10
|
+
WHITESPACE = /\s*/
|
|
11
|
+
QUOTE = /"/
|
|
12
|
+
QUOTED_ATTRIBUTE_VALUE = /([^"?]+)/
|
|
13
|
+
UNQUOTED_ATTRIBUTE_VALUE = /([\w.\/\$?]+)/
|
|
14
|
+
EQUALS = /=/
|
|
15
|
+
ATTRIBUTE_NAME = /(\w+)/
|
|
16
|
+
|
|
17
|
+
def match_value
|
|
18
|
+
if @scanner.scan(QUOTE)
|
|
19
|
+
if @scanner.scan(QUOTED_ATTRIBUTE_VALUE)
|
|
20
|
+
yield @scanner[1]
|
|
21
|
+
@scanner.scan(QUOTE) || raise(MissingQuoteException.new)
|
|
22
|
+
end
|
|
23
|
+
elsif @scanner.scan(UNQUOTED_ATTRIBUTE_VALUE)
|
|
24
|
+
yield @scanner[1]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def match_attribute
|
|
29
|
+
if @scanner.scan(ATTRIBUTE_NAME)
|
|
30
|
+
name = @scanner[1]
|
|
31
|
+
if @scanner.scan(EQUALS)
|
|
32
|
+
match_value do |value|
|
|
33
|
+
yield({ name => value })
|
|
34
|
+
end || raise(MissingAttributeException.new)
|
|
35
|
+
else
|
|
36
|
+
yield({ name => nil })
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def match_tag
|
|
42
|
+
if @scanner.scan(TAG_START)
|
|
43
|
+
name = ""
|
|
44
|
+
nvs = {}
|
|
45
|
+
if @scanner.scan(TAG_NAME)
|
|
46
|
+
name = @scanner[1]
|
|
47
|
+
while true
|
|
48
|
+
@scanner.scan(WHITESPACE)
|
|
49
|
+
match_attribute do |nv|
|
|
50
|
+
nvs.update(nv)
|
|
51
|
+
end || if @scanner.scan(TAG_END)
|
|
52
|
+
yield Tag.new(name,nvs)
|
|
53
|
+
return true
|
|
54
|
+
else
|
|
55
|
+
raise(TagNotClosedException.new)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
raise(TagNotNamedException.new)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def match_close_tag
|
|
65
|
+
if @scanner.scan(TAG_CLOSE_START)
|
|
66
|
+
tag = nil
|
|
67
|
+
if @scanner.scan(TAG_NAME)
|
|
68
|
+
tag = @scanner[1]
|
|
69
|
+
end # TODO raise missing name exception
|
|
70
|
+
@scanner.scan(TAG_END) # TODO raise missing end tag exception
|
|
71
|
+
yield tag if tag
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def match_identifier
|
|
76
|
+
if @scanner.scan(/\{\$([\w.\?]*?)\}/)
|
|
77
|
+
yield @scanner[1]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class MissingAttributeException < Exception # :nodoc:
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class TagNotClosedException < Exception # :nodoc:
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class TagNotNamedException < Exception # :nodoc:
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class MissingQuoteException < Exception # :nodoc:
|
|
95
|
+
|
|
96
|
+
end
|
data/lib/web/testing.rb
ADDED
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
require 'web'
|
|
2
|
+
|
|
3
|
+
require 'web/htmltools/tree'
|
|
4
|
+
module HTMLTree # :nodoc: all
|
|
5
|
+
module TreeElement
|
|
6
|
+
def get_elements aname, elements=[]
|
|
7
|
+
children.each { |element|
|
|
8
|
+
if element.tag == aname
|
|
9
|
+
elements.push element
|
|
10
|
+
else
|
|
11
|
+
element.get_elements aname, elements
|
|
12
|
+
end
|
|
13
|
+
}
|
|
14
|
+
elements
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require 'web/assertinclude'
|
|
20
|
+
require 'web/strscanparser'
|
|
21
|
+
require 'web/tagparser'
|
|
22
|
+
require 'web/formreader.rb'
|
|
23
|
+
|
|
24
|
+
require 'test/unit/assertions'
|
|
25
|
+
|
|
26
|
+
module Web
|
|
27
|
+
def Web::setup( options = {} )
|
|
28
|
+
options[:out] ||= ''
|
|
29
|
+
Web::config[:error_style] = :testing
|
|
30
|
+
Web.connection = Web::Connection.new(options)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def Web::teardown
|
|
34
|
+
Web::config[:error_style] = :default
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Connection
|
|
38
|
+
include Test::Unit::Assertions
|
|
39
|
+
|
|
40
|
+
# for testing: raises Test::Unit exception if content
|
|
41
|
+
# is not set to the provided string.
|
|
42
|
+
def assert_content expected, message=""
|
|
43
|
+
assert_equal( expected, get_content, message );
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def get_formreader #:nodoc:
|
|
47
|
+
return @form_fields_cache ||= FormReader.new( get_content )
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def get_form( name ) #:nodoc:
|
|
51
|
+
get_formreader[name]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def get_form_fields(name) #:nodoc:
|
|
55
|
+
get_formreader.get_fields(name)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def get_form_value formname, name #:nodoc:
|
|
59
|
+
form = get_form_fields(formname)
|
|
60
|
+
if form == nil
|
|
61
|
+
raise Web::Error.new("Form '#{formname}' does not exist")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
value = form[name]
|
|
65
|
+
value
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# assert output content contains a form
|
|
69
|
+
# that includes the given hash of values. See Web::Testing
|
|
70
|
+
def assert_form_includes formname, vars
|
|
71
|
+
assert_includes vars, get_form_fields(formname)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Raises Test::Unit::AssertionFailedError if the header
|
|
75
|
+
# has not been set to the provided value(s)
|
|
76
|
+
def assert_header( name, values, message="" )
|
|
77
|
+
assert_equal( [values].flatten, get_header(name), message )
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Throws Test::Unit::AssertionFailedException if
|
|
81
|
+
# cookie values are not present.
|
|
82
|
+
def assert_cookie( name, values, message="" )
|
|
83
|
+
assert_equal( [ values ].flatten, [ cookies_sent[name] ].flatten, message )
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Check that a particluar template was used
|
|
87
|
+
def assert_template_used expected, message =""
|
|
88
|
+
_wrap_assertion {
|
|
89
|
+
flunk("No template used") if @templates == nil
|
|
90
|
+
unless @templates.include? expected
|
|
91
|
+
msg = "expected template:<#{expected}> but not one of:<#{@templates.inspect}>"
|
|
92
|
+
flunk(msg)
|
|
93
|
+
end
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Check that a particluar template was not used
|
|
98
|
+
def assert_template_not_used expected, message =""
|
|
99
|
+
_wrap_assertion {
|
|
100
|
+
if (@templates.kind_of?(Array) && @templates.include?(expected) )
|
|
101
|
+
msg = "template:<#{expected}> not supposed to be used in:<#{@templates.inspect}>"
|
|
102
|
+
flunk(msg)
|
|
103
|
+
end
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Check that these values were included in the output
|
|
108
|
+
def assert_local_includes expected
|
|
109
|
+
assert_includes expected, @local
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def assert_vars_equals
|
|
113
|
+
raise Exception.new("Not yet implemented")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# == Purpose
|
|
120
|
+
# The testing module facilitates the testing of Web applications
|
|
121
|
+
# without the overhead of a web server to run.
|
|
122
|
+
#
|
|
123
|
+
# Given these files:
|
|
124
|
+
#
|
|
125
|
+
# script.rb
|
|
126
|
+
# test.rb
|
|
127
|
+
#
|
|
128
|
+
# where script.rb is:
|
|
129
|
+
#
|
|
130
|
+
# #!/usr/bin/ruby
|
|
131
|
+
# require 'web'
|
|
132
|
+
#
|
|
133
|
+
# Web::process {
|
|
134
|
+
# Web.write "param is #{Web["param"]}"
|
|
135
|
+
# }
|
|
136
|
+
#
|
|
137
|
+
# and test.rb is:
|
|
138
|
+
#
|
|
139
|
+
# require 'web'
|
|
140
|
+
# require 'test/unit'
|
|
141
|
+
#
|
|
142
|
+
# class MyAppTest < Test::Unit::TestCase
|
|
143
|
+
# include Web::Testing
|
|
144
|
+
#
|
|
145
|
+
# def test_prints_content
|
|
146
|
+
# do_request "script.rb", "param" => "THIS!"
|
|
147
|
+
# assert_content "param is THIS!"
|
|
148
|
+
# end
|
|
149
|
+
# end
|
|
150
|
+
#
|
|
151
|
+
# Do this to run tests:
|
|
152
|
+
#
|
|
153
|
+
# ruby test.rb
|
|
154
|
+
#
|
|
155
|
+
# If you have a more complicated app, where the tests live in
|
|
156
|
+
# a different place than your scripts, you can use:
|
|
157
|
+
#
|
|
158
|
+
# Web::docroot = path
|
|
159
|
+
#
|
|
160
|
+
# To tell narf where to find your cgi scripts.
|
|
161
|
+
#
|
|
162
|
+
#
|
|
163
|
+
# === Testing with Templates
|
|
164
|
+
#
|
|
165
|
+
# Using Narflates you can test functionality without having to
|
|
166
|
+
# do lengthly string comparisons. For example, create the following
|
|
167
|
+
# file in 'mytemplate.html'
|
|
168
|
+
#
|
|
169
|
+
# <html>
|
|
170
|
+
# <body>
|
|
171
|
+
# {$myvar}
|
|
172
|
+
# </body>
|
|
173
|
+
# </html>
|
|
174
|
+
#
|
|
175
|
+
# Create a 'script.rb' as follows:
|
|
176
|
+
#
|
|
177
|
+
# #!/usr/bin/narf
|
|
178
|
+
# require 'web'
|
|
179
|
+
#
|
|
180
|
+
# Web::process{
|
|
181
|
+
# Web.print_template "mytemplate.html", { "myvar" => "Hello World" }
|
|
182
|
+
# }
|
|
183
|
+
#
|
|
184
|
+
# Now, we can check that the right values got displayed without
|
|
185
|
+
# needing to check that the template is correct as a side effect.
|
|
186
|
+
# Save this into 'test.rb' and run it:
|
|
187
|
+
#
|
|
188
|
+
# require 'web'
|
|
189
|
+
#
|
|
190
|
+
# class MyAppTest < Test::Unit::TestCase
|
|
191
|
+
# include Web::Testing # adds the modules
|
|
192
|
+
#
|
|
193
|
+
# def test_prints_content
|
|
194
|
+
# do_request "script.rb"
|
|
195
|
+
# assert_vars_includes "myvar" => "Hello World"
|
|
196
|
+
# end
|
|
197
|
+
# end
|
|
198
|
+
#
|
|
199
|
+
# === Testing Forms
|
|
200
|
+
#
|
|
201
|
+
# The following example demonstrates testing a simple HTML form.
|
|
202
|
+
# Creating mytemplate.html as:
|
|
203
|
+
#
|
|
204
|
+
#
|
|
205
|
+
# <html>
|
|
206
|
+
# <body>
|
|
207
|
+
# <form name="myform">
|
|
208
|
+
# <input type="text" name="foo">
|
|
209
|
+
# <input type="submit" name="submit" value="Submit">
|
|
210
|
+
# </body>
|
|
211
|
+
# </html>
|
|
212
|
+
#
|
|
213
|
+
# To print this form and handle a submit save this as 'script.rb':
|
|
214
|
+
#
|
|
215
|
+
# #!/usr/bin/narf
|
|
216
|
+
#
|
|
217
|
+
# require 'web'
|
|
218
|
+
#
|
|
219
|
+
# Web::process {
|
|
220
|
+
# if Web["submit"] # check to see whether a form was
|
|
221
|
+
# Web.puts "Form Submitted with value '#{Web["foo"]}'"
|
|
222
|
+
# else
|
|
223
|
+
# Web.print_template "mytemplate.html"
|
|
224
|
+
# end
|
|
225
|
+
# }
|
|
226
|
+
#
|
|
227
|
+
# Use this 'test.rb' to test it:
|
|
228
|
+
#
|
|
229
|
+
# class MyAppTest < Test::Unit::TestCase
|
|
230
|
+
# include Web::Testing # adds the modules
|
|
231
|
+
#
|
|
232
|
+
# def test_prints_content
|
|
233
|
+
# do_request "script.rb"
|
|
234
|
+
# do_submit "myform", "foo" => "bar"
|
|
235
|
+
# assert_content "Form Submitted with value '#{Web["foo"]}'"
|
|
236
|
+
# end
|
|
237
|
+
# end
|
|
238
|
+
#
|
|
239
|
+
#
|
|
240
|
+
# === Test <input type="text|password|hidden"> and <textarea>
|
|
241
|
+
#
|
|
242
|
+
# html:
|
|
243
|
+
#
|
|
244
|
+
# <form name='aForm'>
|
|
245
|
+
# <input name="bare">
|
|
246
|
+
# <input name="named" type="text" value="foo">
|
|
247
|
+
# <input name="pass" type="password" value="secret">
|
|
248
|
+
# <input name="obscure" type="hidden" value="discrete">
|
|
249
|
+
# <textarea name="big_text">
|
|
250
|
+
# big paragraph here
|
|
251
|
+
# </textarea>
|
|
252
|
+
# </form>
|
|
253
|
+
#
|
|
254
|
+
# assert:
|
|
255
|
+
#
|
|
256
|
+
# assert_form_includes( 'aForm', "bare" => "",
|
|
257
|
+
# "named" => "foo",
|
|
258
|
+
# "pass" => "secret",
|
|
259
|
+
# "obscure" => "discrete",
|
|
260
|
+
# "big_text" => "big paragraph here" )
|
|
261
|
+
#
|
|
262
|
+
# submit:
|
|
263
|
+
#
|
|
264
|
+
# do_submit( 'aForm', "bare" => "empty",
|
|
265
|
+
# "named" => "bare",
|
|
266
|
+
# "pass" => "shhhhh",
|
|
267
|
+
# "obscure" => "secretive",
|
|
268
|
+
# "big_text" => "windbag" )
|
|
269
|
+
#
|
|
270
|
+
# === Test <input type="file">
|
|
271
|
+
#
|
|
272
|
+
# html:
|
|
273
|
+
#
|
|
274
|
+
# <form name='aForm' enctype='multipart/form-data'>
|
|
275
|
+
# <input name="upload" type="file">
|
|
276
|
+
# </form>
|
|
277
|
+
#
|
|
278
|
+
# assert:
|
|
279
|
+
#
|
|
280
|
+
# assert_form_includes( 'aForm', "upload" => "" )
|
|
281
|
+
#
|
|
282
|
+
# submit:
|
|
283
|
+
#
|
|
284
|
+
# do_submit( 'aForm', "upload" => Web::Upload.new(
|
|
285
|
+
# File.new( "testfile" ),
|
|
286
|
+
# "content-type",
|
|
287
|
+
# "original-filename" ) )
|
|
288
|
+
#
|
|
289
|
+
# === Test <select> and <input type="radio">
|
|
290
|
+
#
|
|
291
|
+
#
|
|
292
|
+
#
|
|
293
|
+
# === Test <select multiple> and <input type="checkbox">
|
|
294
|
+
#
|
|
295
|
+
#
|
|
296
|
+
# === Bugs: Unsupported behaviour
|
|
297
|
+
#
|
|
298
|
+
# The following situations will have unknown results:
|
|
299
|
+
#
|
|
300
|
+
# * Combining different types of elements into one field;
|
|
301
|
+
# i.e. <input name="field" type="text"> and <select name="field">
|
|
302
|
+
# * Comparing <input name="page.name"> and <input name="page.content">
|
|
303
|
+
# with assert_vars_include("page" => { "name" => ..., "content" => ... } )
|
|
304
|
+
#
|
|
305
|
+
module Testing
|
|
306
|
+
class FormNotFoundException < Exception #:nodoc:
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
class FieldNotFoundException < Exception #:nodoc:
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
class MustSetDocrootForAbsolutePathException < Exception #:nodoc:
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def write_file( path, content )
|
|
316
|
+
filename = File.join( Web::docroot, path )
|
|
317
|
+
filedir = File.dirname(filename)
|
|
318
|
+
unless File.exists? filedir
|
|
319
|
+
require 'fileutils'
|
|
320
|
+
FileUtils::mkdir_p(filedir, :verbose => false)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
File.open( filename, "w" ) do |f|
|
|
324
|
+
f.write content
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def select( *args )
|
|
329
|
+
hash = {}
|
|
330
|
+
|
|
331
|
+
if (args.length == 1 and args[0].kind_of? Hash)
|
|
332
|
+
hash = args[0]
|
|
333
|
+
else
|
|
334
|
+
args.each { |e|
|
|
335
|
+
hash[e] = true
|
|
336
|
+
}
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
hash
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
@@test_session = nil
|
|
343
|
+
|
|
344
|
+
# Reset the session used by the test framework. Call prior to all tests
|
|
345
|
+
# that rely on the session being clean
|
|
346
|
+
def reset_session
|
|
347
|
+
@@test_session = nil
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Run a request, parameters are the name value pairs that would be
|
|
351
|
+
# passed in the query string. The webpath is a document root relative
|
|
352
|
+
# path to a ruby script.
|
|
353
|
+
def do_request(webpath, parameters={})
|
|
354
|
+
options = {}
|
|
355
|
+
@@test_session ||= {}
|
|
356
|
+
options[:session] = @@test_session
|
|
357
|
+
options[:env] = parameters[:env]
|
|
358
|
+
options[:request] = parameters
|
|
359
|
+
options[:document_root] = Web::docroot
|
|
360
|
+
options[:out] = StringIO.new
|
|
361
|
+
script_path, script_name, path_info = get_script_part(webpath)
|
|
362
|
+
|
|
363
|
+
options[:path_info] = path_info
|
|
364
|
+
options[:script_name] = script_name
|
|
365
|
+
load_request( options, script_path, webpath )
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def load_request( options, script_path, webpath ) #:nodoc:
|
|
369
|
+
options[:webpath] = webpath
|
|
370
|
+
### re-throw errors
|
|
371
|
+
Web::config[:error_style] = :custom
|
|
372
|
+
Web::config[:error_handler] = lambda do |error|
|
|
373
|
+
raise error
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# out with the old....
|
|
377
|
+
#Web::connection.close
|
|
378
|
+
Web::connection = nil
|
|
379
|
+
error = nil
|
|
380
|
+
Web::open( options ) do
|
|
381
|
+
Web::load( script_path )
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
if Web.status == "302"
|
|
385
|
+
Web.location =~ /(.*)\?(.*)/
|
|
386
|
+
target = $1
|
|
387
|
+
params = Connection::parse_query_string($2)
|
|
388
|
+
|
|
389
|
+
unless (target =~ /^\//)
|
|
390
|
+
webpath =~ /(.*)#{File.basename(script_path)}/
|
|
391
|
+
target = $1 + target
|
|
392
|
+
end
|
|
393
|
+
do_request( target, params )
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Submit the form 'formname' with the formfields described in newvalues
|
|
398
|
+
def do_submit( formname, newvalues={} )
|
|
399
|
+
form = Web.get_form(formname)
|
|
400
|
+
|
|
401
|
+
if form == nil
|
|
402
|
+
#if Web.get_form_fields[formname] == nil
|
|
403
|
+
raise FormNotFoundException.new("Form '#{formname}' does not exist")
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
#MultiHashTree::flatten(newvalues).keys.each do |key|
|
|
407
|
+
#unless( Web.get_form_fields[formname].valid_key?(key) )
|
|
408
|
+
# raise FieldNotFoundException.new( "#{ key } is not present in form" )
|
|
409
|
+
#end
|
|
410
|
+
#end
|
|
411
|
+
|
|
412
|
+
webpath = nil
|
|
413
|
+
|
|
414
|
+
#Web.get_html_tree.get_elements("form").each { |form|
|
|
415
|
+
# if (form.attribute("name") == formname)
|
|
416
|
+
# webpath = form.attribute("action")
|
|
417
|
+
# end
|
|
418
|
+
#}
|
|
419
|
+
webpath = form.action
|
|
420
|
+
|
|
421
|
+
unless (webpath)
|
|
422
|
+
webpath = Web.options[:webpath]
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
script_path, script_name, path_info = get_script_part(webpath)
|
|
426
|
+
|
|
427
|
+
old_connection = Web.connection
|
|
428
|
+
|
|
429
|
+
options = {}
|
|
430
|
+
@@test_session ||= {}
|
|
431
|
+
options[:session] = @@test_session
|
|
432
|
+
options[:out] = StringIO.new
|
|
433
|
+
### patrick
|
|
434
|
+
options[:request] = form.merge_fields( newvalues )
|
|
435
|
+
#options[:request] = Web.get_form_fields[formname].params(MultiHashTree::flatten(newvalues))
|
|
436
|
+
options[:document_root] = old_connection.document_root
|
|
437
|
+
|
|
438
|
+
options[:path_info] = path_info #old_connection.path_info
|
|
439
|
+
options[:script_name] = script_name #old_connection.script_name
|
|
440
|
+
|
|
441
|
+
load_request( options, script_path, webpath )
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Assert that a give template was displayed
|
|
445
|
+
def assert_template_used filename, msg=""
|
|
446
|
+
Web.assert_template_used filename, msg
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# Assert that a give template was not displayed
|
|
450
|
+
def assert_template_not_used filename, msg=""
|
|
451
|
+
Web.assert_template_not_used filename, msg
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Assert that the values passed in to expected were set on the template
|
|
455
|
+
def assert_vars_includes expected
|
|
456
|
+
Web.assert_vars_includes expected
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# Assert that the form displayed contains particular values
|
|
460
|
+
def assert_form_includes formname, expected
|
|
461
|
+
Web::assert_form_includes formname, expected
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
# Assert that the entire content displayed is equal to expected
|
|
465
|
+
def assert_content expected, msg=""
|
|
466
|
+
Web.assert_content expected, msg
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
# Assert that the header key has the value 'value'
|
|
470
|
+
def assert_header key, value, msg=""
|
|
471
|
+
Web.assert_header key, value, msg
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# Assert that the cookie key, has the cookie value
|
|
475
|
+
def assert_cookie key, value, msg=""
|
|
476
|
+
Web.assert_cookie key, value, msg
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Assert that a form field has exactly the given options
|
|
480
|
+
# can't assert order, though
|
|
481
|
+
def assert_options( formname, expected={})
|
|
482
|
+
options = Web.get_formreader.get_options(formname)
|
|
483
|
+
expected.each{ |k,v|
|
|
484
|
+
assert_equal( v.sort, options[k].sort )
|
|
485
|
+
}
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def remove_trailing_slashes(filename) #:nodoc:
|
|
489
|
+
/(.*?)\/?$/.match(filename)[1]
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def get_script_part(webpath) #:nodoc:
|
|
493
|
+
# two cases:
|
|
494
|
+
# absolute webpath (requires Web::docroot to be correct)
|
|
495
|
+
# relative webpath (doesn't require Web::docroot to be correct)
|
|
496
|
+
if ( webpath =~ /^\// )
|
|
497
|
+
prefix = Web::docroot
|
|
498
|
+
raise MustSetDocrootForAbsolutePathException unless prefix
|
|
499
|
+
path = "/"
|
|
500
|
+
else
|
|
501
|
+
prefix = ""
|
|
502
|
+
path = ""
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
new_script_path = ""
|
|
506
|
+
webpath.split("/").each do |file|
|
|
507
|
+
file =~ /^([a-zA-Z]{1,1}:)$/
|
|
508
|
+
|
|
509
|
+
if (path.empty?)
|
|
510
|
+
newpath = file
|
|
511
|
+
else
|
|
512
|
+
newpath = File.join( path , file ).gsub("//","/")
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
new_script_path = ""
|
|
516
|
+
if (prefix.empty?)
|
|
517
|
+
new_script_path = newpath
|
|
518
|
+
else
|
|
519
|
+
new_script_path = File.join( prefix, newpath ).gsub("//","/")
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
if (File.file?(new_script_path))
|
|
523
|
+
return new_script_path, "/" + File.basename( new_script_path ), webpath[newpath.length...webpath.length]
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
path = newpath
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
if (!File.exists?(new_script_path) && prefix.empty?)
|
|
530
|
+
return get_script_part( "/" + webpath )
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
return new_script_path, "/" + File.basename( new_script_path ), ""
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
class SelectHash < Hash #:nodoc:
|
|
537
|
+
def == other
|
|
538
|
+
if (other.kind_of? Hash)
|
|
539
|
+
super(other)
|
|
540
|
+
elsif (other.class == TrueClass)
|
|
541
|
+
result = true
|
|
542
|
+
self.each{ |k, v|
|
|
543
|
+
result = false unless v
|
|
544
|
+
}
|
|
545
|
+
result
|
|
546
|
+
elsif (other.class == FalseClass)
|
|
547
|
+
result = true
|
|
548
|
+
self.each{ |k,v|
|
|
549
|
+
result = false if v
|
|
550
|
+
}
|
|
551
|
+
result
|
|
552
|
+
else
|
|
553
|
+
### this is wrong
|
|
554
|
+
other.to_s == self.default.join(",")
|
|
555
|
+
end
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def field_value
|
|
559
|
+
values = [ ]
|
|
560
|
+
self.each{ |k,v|
|
|
561
|
+
values.push k if v
|
|
562
|
+
}
|
|
563
|
+
values.join(",")
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
# could I get an explanation of this?
|
|
569
|
+
# just for me? please?
|
|
570
|
+
# not to long... probably not longer than this comment here.
|
|
571
|
+
class MultiHashTree # :nodoc:
|
|
572
|
+
attr_reader :fields, :unmodified_fields
|
|
573
|
+
|
|
574
|
+
def initialize fields = {}
|
|
575
|
+
@fields = {}
|
|
576
|
+
@unmodified_fields = {}
|
|
577
|
+
fields.each do |k,value_array|
|
|
578
|
+
value_array.each{ |v|
|
|
579
|
+
push_field k, v
|
|
580
|
+
}
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
def valid_key? (aKey)
|
|
585
|
+
unmodified_fields.has_key?(aKey) || fields.has_key?(aKey)
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def push_impl hash, name, value
|
|
589
|
+
if name =~ Web::Connection::MULTIPLE_KEY && !value.kind_of?(Web::Testing::SelectHash)
|
|
590
|
+
hash[name] ||= []
|
|
591
|
+
hash[name].push value
|
|
592
|
+
elsif m = /^(\w+(\[\])?)\.(.+)/.match(name)
|
|
593
|
+
hash[m[1]] ||= {}
|
|
594
|
+
push_impl(hash[m[1]], m[3], value)
|
|
595
|
+
elsif m = /^(\w+)\[(\d+)\].(.+)/.match(name)
|
|
596
|
+
hash[m[1]] ||= []
|
|
597
|
+
hash[m[1]][m[2].to_i] ||= {}
|
|
598
|
+
push_impl hash[m[1]][m[2].to_i], m[3], value
|
|
599
|
+
else
|
|
600
|
+
hash[name] ||= []
|
|
601
|
+
hash[name].push(value)
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def push_field name, value
|
|
606
|
+
@unmodified_fields[name] ||= []
|
|
607
|
+
@unmodified_fields[name].push value
|
|
608
|
+
push_impl @fields, name, value
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
def params values
|
|
612
|
+
retval = @unmodified_fields.clone
|
|
613
|
+
values.each do |key,value|
|
|
614
|
+
if value.kind_of? SelectHash
|
|
615
|
+
selected_options = []
|
|
616
|
+
value.each{ |k,v|
|
|
617
|
+
selected_options.push k if v
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if m = Web::Connection::MULTIPLE_KEY.match(key)
|
|
621
|
+
retval[key] ||= []
|
|
622
|
+
retval[key] = (retval[key] + selected_options).uniq
|
|
623
|
+
else
|
|
624
|
+
retval[key] = selected_options.join(",")
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
else
|
|
628
|
+
if m = Web::Connection::MULTIPLE_KEY.match(key)
|
|
629
|
+
retval[key] ||= []
|
|
630
|
+
retval[key] << value
|
|
631
|
+
else
|
|
632
|
+
retval[key] = value
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
retval
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def MultiHashTree.flatten node, newhash = {} , nameroot = "" # :nodoc:
|
|
640
|
+
if node.kind_of? Hash
|
|
641
|
+
node.each do |k,v|
|
|
642
|
+
if nameroot == ""
|
|
643
|
+
varname = k
|
|
644
|
+
else
|
|
645
|
+
varname = "#{nameroot}.#{k}"
|
|
646
|
+
end
|
|
647
|
+
flatten( v, newhash, varname )
|
|
648
|
+
end
|
|
649
|
+
elsif node.kind_of? Array
|
|
650
|
+
unless node.find { |i| !i.kind_of? String }
|
|
651
|
+
newhash[nameroot] = node
|
|
652
|
+
else
|
|
653
|
+
node.each_with_index do |v,i|
|
|
654
|
+
flatten( v, newhash, "#{nameroot}[#{i}]" )
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
else
|
|
658
|
+
newhash[ nameroot ]=node
|
|
659
|
+
end
|
|
660
|
+
newhash
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
end
|
|
666
|
+
end
|