ucnv-chainsaw 0.0.0

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.
@@ -0,0 +1,87 @@
1
+
2
+ module Chainsaw
3
+
4
+ module Util
5
+
6
+ def is_xml_parsable?(content_type)
7
+ content_type =~ %r{(?:text|application)/x?(?:ht)?ml}
8
+ end
9
+
10
+ def to_nth(num)
11
+ case num.to_i
12
+ when 1
13
+ '1st'
14
+ when 2
15
+ '2nd'
16
+ when 3
17
+ '3rd'
18
+ else
19
+ num.to_i.to_s + 'th'
20
+ end
21
+ end
22
+
23
+ def qq(str)
24
+ "\"#{str}\""
25
+ end
26
+ end
27
+
28
+ module Encoding
29
+ NKF_TO_LIBXML2 = {
30
+ NKF::ASCII => 10, #=> 22,
31
+ NKF::JIS => 19,
32
+ NKF::SJIS => 20,
33
+ NKF::EUC => 21,
34
+ NKF::UTF8 => 1,
35
+ NKF::UTF16 => 2,
36
+ NKF::UNKNOWN => 10,
37
+ NKF::BINARY => 10,
38
+ }
39
+
40
+ def self.guess(data)
41
+ nokogiri_consts = Nokogiri::XML::SAX::Parser::ENCODINGS
42
+ nkf_guessed = NKF.guess data
43
+ value = NKF_TO_LIBXML2[nkf_guessed]
44
+ value = NKF_TO_LIBXML2[NKF::UTF8] unless nokogiri_consts.value?(value)
45
+ c = nokogiri_consts.find do |k, v|
46
+ v == value
47
+ end
48
+ c.first
49
+ end
50
+ end
51
+
52
+ module ErrorWrapper
53
+ APPLY_TESTUNIT_BACKTRACEFILTER = true
54
+ @@indent = '| '
55
+ @@tab = ' '
56
+ def set_backtrace(backtrace)
57
+ root_cause = $!
58
+ unless root_cause.nil?
59
+ backtrace = filter_backtrace(backtrace)
60
+ backtrace.push '............', 'root cause'
61
+ backtrace.push "#{@@indent}#{root_cause.class.name}: #{root_cause.to_s}"
62
+ backtrace.concat(filter_backtrace(root_cause.backtrace).map do |t|
63
+ "#{@@indent}#{@@tab}#{t}"
64
+ end)
65
+ end
66
+ super backtrace
67
+ end
68
+
69
+ def filter_backtrace(backtrace)
70
+ if APPLY_TESTUNIT_BACKTRACEFILTER
71
+ require 'test/unit/util/backtracefilter'
72
+ Test::Unit::Util::BacktraceFilter.module_eval do
73
+ module_function :filter_backtrace
74
+ end
75
+ Test::Unit::Util::BacktraceFilter.filter_backtrace backtrace
76
+ else
77
+ backtrace
78
+ end
79
+ end
80
+ end
81
+
82
+ class RequestError < StandardError
83
+ include Chainsaw::ErrorWrapper
84
+ end
85
+
86
+ end
87
+
@@ -0,0 +1,62 @@
1
+
2
+ require 'pathname'
3
+
4
+ module Chainsaw
5
+ module Element
6
+ include Chainsaw::Util
7
+
8
+ def is_form?
9
+ name =~ /^form$/i
10
+ end
11
+
12
+ def serialize_form(clicked_button = nil, image_x = -1, image_y = -1)
13
+ return nil unless is_form?
14
+ form = []
15
+ if clicked_button.nil?
16
+ s = self.xpath('.//input[@type="submit"]')
17
+ unless s.empty?
18
+ form.push [s.first['name'], s.first['value']]
19
+ end
20
+ else
21
+ s = self.xpath(".//input[@name=#{qq clicked_button}]")
22
+
23
+ if s.size and ['submit', 'image'].include? s.first['type']
24
+ form.push [s.first['name'], s.first['value']]
25
+ form.push [s.first['name'] + '.x', image_x] if image_x > 0
26
+ form.push [s.first['name'] + '.y', image_y] if image_y > 0
27
+ end
28
+ end
29
+ self.xpath('.//input').each do |e|
30
+ next unless e['name']
31
+ case e['type']
32
+ when 'text', 'password', 'hidden', nil
33
+ form.push [e['name'], e['value']]
34
+ when 'radio', 'checkbox'
35
+ form.push [e['name'], e['value']] unless e['checked'].nil?
36
+ when 'file'
37
+ if self['enctype'] =~ %r{^multipart/form-data}i
38
+ f = Pathname.new e['value'].to_s
39
+ form.push [e['name'], f]
40
+ end
41
+ else
42
+ ;
43
+ end
44
+ end
45
+ self.xpath('.//textarea').each do |e|
46
+ form.push [e['name'], e.text]
47
+ end
48
+ self.xpath('.//select').each do |e|
49
+ opt = e.xpath('.//option')
50
+ slctd = opt.reject do |o|
51
+ o['selected'].nil?
52
+ end
53
+ slctd = opt.first if e['multiple'].nil? and slctd.empty?
54
+ slctd.each {|s| form.push([e['name'], s['value']]) } unless slctd.nil?
55
+ end
56
+ form
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+
@@ -0,0 +1,27 @@
1
+
2
+
3
+ class HTTPClient
4
+ def get_r(uri, query = nil, extheader = {}, &block)
5
+ follow_redirect(:get, uri, query, nil, extheader, &block)
6
+ end
7
+
8
+ def post_r(uri, body = nil, extheader = {}, &block)
9
+ follow_redirect(:post, uri, nil, body, extheader, &block)
10
+ end
11
+
12
+ alias do_get_header_original do_get_header
13
+ def do_get_header(req, res, sess)
14
+ # It is not a good way, but HTTPClient cannot keep requested URIs..
15
+ unless res.respond_to?(:uri)
16
+ HTTP::Message.module_eval do
17
+ attr_accessor :uri
18
+ end
19
+ end
20
+ res.uri = req.header.request_uri
21
+ do_get_header_original(req, res, sess)
22
+ end
23
+ end
24
+
25
+ HTTP::Status::SUCCESSFUL_STATUS.push 404
26
+
27
+
@@ -0,0 +1,29 @@
1
+
2
+
3
+ module Nokogiri
4
+ module XML
5
+ class Node
6
+ def fix_xpath(*paths)
7
+ paths.map do |path|
8
+ if path.is_a? String
9
+ # fix for id() func
10
+ path.sub(/^id\(\s*["']([^"']*)["']\s*\)/, './/*[@id="\1"]')
11
+ else
12
+ path
13
+ end
14
+ end
15
+ end
16
+
17
+ alias original_search search
18
+ def search(*paths)
19
+ original_search(*fix_xpath(*paths))
20
+ end
21
+
22
+ alias original_xpath xpath
23
+ def xpath(*paths)
24
+ original_xpath(*fix_xpath(*paths))
25
+ end
26
+
27
+ end
28
+ end
29
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require 'chainsaw'
4
+ require 'open-uri'
5
+ require File.dirname(__FILE__) + '/server.rb'
6
+
7
+ unless defined? TEST_URL
8
+ TEST_URL = "http://#{TEST_SERVER_CONFIG[:BindAddress]}:#{TEST_SERVER_CONFIG[:Port]}/"
9
+
10
+ begin
11
+ open TEST_URL
12
+ rescue
13
+ raise 'Run test/server.rb before you test.'
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ <html>
2
+ <head>
3
+ <title>test 01</title>
4
+ </head>
5
+ <body>
6
+ <div id="links">
7
+ <ul>
8
+ <li><a href="01.html">1</a></li>
9
+ <li><a href="02.html">2</a></li>
10
+ <li><a href="/03.html">3</a></li>
11
+ <li><a href="/cgi.rb">4</a></li>
12
+ <li><a href="00.html">5</a></li>
13
+ </ul>
14
+ </div>
15
+ </body>
16
+ </html>
17
+
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>test go</title>
4
+ </head>
5
+ <body>
6
+ <a href="00.html">not found</a>
7
+ </body>
8
+ </html>
9
+
@@ -0,0 +1,25 @@
1
+ <html>
2
+ <head>
3
+ <title>test 03</title>
4
+ </head>
5
+ <body>
6
+ <div id="forms">
7
+ <form action="cgi.rb" method="get" id="get-form">
8
+ <input type="file" name="f" />
9
+ <input type="text" name="t" />
10
+ <input type="submit" name="s" value="go" />
11
+ </form>
12
+ <form action="cgi.rb" method="post" id="post-form">
13
+ <input type="text" name="t">
14
+ <input type="password" name="p">
15
+
16
+ <input type="submit" name="s" value="go" />
17
+ </form>
18
+ <form action="cgi.rb" method="post" enctype="multipart/form-data" id="upload-form">
19
+ <input type="file" name="f" />
20
+ <input type="submit" name="s" value="go" />
21
+ </form>
22
+ </div>
23
+ </body>
24
+ </html>
25
+
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <head>
3
+ <title>test utf8</title>
4
+ </head>
5
+ <body>
6
+ <div id="links">
7
+ <ul>
8
+ <li><a name="ウェブ検索のサービス" href="http://www.google.co.jp/">グーグル・ジャパン</a></li>
9
+ <li><a name="ウェブ検索のサービス" href="http://www.yahoo.co.jp/">ヤフー・ジャパン</a></li>
10
+ </ul>
11
+ </div>
12
+ </body>
13
+ </html>
14
+ <!-- 上記の内容だけでは NKF#guess が NKF::ASCII を返すため失敗する... -->
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <head>
3
+ <title>test sjis</title>
4
+ </head>
5
+ <body>
6
+ <div id="links">
7
+ <ul>
8
+ <li><a name="�E�F�u�����̃T�[�r�X" href="http://www.google.co.jp/">�O�[�O���E�W���p��</a></li>
9
+ <li><a name="�E�F�u�����̃T�[�r�X" href="http://www.yahoo.co.jp/">���t�[�E�W���p��</a></li>
10
+ </ul>
11
+ </div>
12
+ </body>
13
+ </html>
14
+
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <head>
3
+ <title>test sjis</title>
4
+ </head>
5
+ <body>
6
+ <div id="links">
7
+ <ul>
8
+ <li><a name="�����ָ����Υ����ӥ�" href="http://www.google.co.jp/">�������롦����ѥ�</a></li>
9
+ <li><a name="�����ָ����Υ����ӥ�" href="http://www.yahoo.co.jp/">��ա�������ѥ�</a></li>
10
+ </ul>
11
+ </div>
12
+ </body>
13
+ </html>
14
+
@@ -0,0 +1,50 @@
1
+ require 'cgi'
2
+ require 'yaml'
3
+ require 'base64'
4
+
5
+ cgi = CGI.new
6
+ env = Hash[ENV.collect() { |k, v| [k, v] }]
7
+ res = {}
8
+
9
+ if cgi.has_key? 'redirect'
10
+ l = env['REQUEST_URI'].split('cgi.rb').first + '02.html'
11
+ cgi.print [
12
+ 'Status: 302 Moved Temporarily',
13
+ 'Location: ' + l,
14
+ "\n"
15
+ ].join("\n")
16
+ exit 0
17
+ end
18
+
19
+ if cgi.has_key? 'auth'
20
+ auth = env['HTTP_AUTHORIZATION'] || ''
21
+ user_pass = Base64.decode64(auth.split.last || '').split(/:/, 2)
22
+ if user_pass.empty?
23
+ cgi.print [
24
+ 'Status: 401 Unauthorized',
25
+ 'WWW-Authenticate: Basic realm="test"',
26
+ "\n",
27
+ 'Access denied.'
28
+ ].join("\n")
29
+ exit 0
30
+ else
31
+ res['auth'] = user_pass.join(':')
32
+ end
33
+ end
34
+
35
+ if env['CONTENT_TYPE'] =~ %r{^multipart/form-data;}
36
+ upload = cgi.params['f'][0]
37
+ res['upload'] = {
38
+ 'size' => upload.size,
39
+ 'original_filename' => upload.original_filename,
40
+ 'content_type' => upload.content_type
41
+ } if upload
42
+ end
43
+
44
+ res.update(
45
+ 'params' => cgi.params,
46
+ 'cookies' => cgi.cookies,
47
+ 'env' => env
48
+ )
49
+
50
+ cgi.print "\n\n" + res.to_yaml
Binary file
data/test/server.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'webrick'
2
+
3
+ TEST_SERVER_CONFIG = {
4
+ :DocumentRoot => File.join(File.expand_path(File.dirname(__FILE__)), 'htdocs'),
5
+ :BindAddress => '127.0.0.1',
6
+ :Port => 3080,
7
+ :CGIInterpreter => WEBrick::HTTPServlet::CGIHandler::Ruby,
8
+ }
9
+
10
+ if __FILE__ == $0
11
+ s = WEBrick::HTTPServer.new(TEST_SERVER_CONFIG)
12
+ s.mount(
13
+ '/cgi.rb',
14
+ WEBrick::HTTPServlet::CGIHandler,
15
+ TEST_SERVER_CONFIG[:DocumentRoot] + '/cgi.rb'
16
+ )
17
+ Signal.trap(:INT) { s.shutdown }
18
+ Signal.trap(:TERM) { exit 0 }
19
+ s.start
20
+ end
@@ -0,0 +1,274 @@
1
+ require File.dirname(__FILE__) + '/helper.rb'
2
+
3
+
4
+ class TestBrowser < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @text_val = 'value for text field'
8
+ end
9
+
10
+
11
+ def test_open
12
+ cs = Chainsaw.launch(TEST_URL + '01.html')
13
+ cs.open { |cs|
14
+ assert_equal cs.uri.to_s, TEST_URL + '01.html'
15
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
16
+ assert_equal 200, cs.res.status
17
+ assert_equal 'text/html', cs.res.contenttype
18
+ links = cs.doc.search('//a')
19
+ assert_equal links.length, 5
20
+ cs.set_next links[1]
21
+ }
22
+ cs.open { |cs|
23
+ assert_equal cs.uri.to_s, TEST_URL + '02.html'
24
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
25
+ links = cs.doc.search('//a')
26
+ cs.set_next links.last
27
+ }
28
+ cs.open { |cs|
29
+ assert_equal cs.uri.to_s, TEST_URL + '00.html'
30
+ assert_equal 404, cs.res.status
31
+ }
32
+ end
33
+
34
+ def test_back
35
+ d = ''
36
+ cs = Chainsaw.launch(TEST_URL + '01.html').
37
+ open { |cs|
38
+ d = cs.doc.to_s
39
+ cs.set_next cs.doc.search('//a')[1]
40
+ }.open.back { |cs|
41
+ assert_equal TEST_URL + '01.html', cs.uri.to_s
42
+ assert_equal d, cs.doc.to_s
43
+ }
44
+ end
45
+
46
+ def test_open_file
47
+ Chainsaw.launch(TEST_URL + 'img.gif').
48
+ open { |cs|
49
+ assert_equal 200, cs.res.status
50
+ assert_equal 'image/gif', cs.res.contenttype
51
+ assert_not_nil cs.file
52
+ assert_instance_of Tempfile, cs.file
53
+
54
+ original = File.stat(File.dirname(__FILE__) + '/htdocs/img.gif')
55
+ saved = File.stat(cs.file.path)
56
+ assert_equal saved.size, original.size
57
+ }
58
+ end
59
+
60
+ def test_submit_get
61
+ Chainsaw.launch(TEST_URL + '03.html').
62
+ open { |cs|
63
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
64
+ form = cs.doc.search('id("get-form")').first
65
+ form.xpath('//input[@name="t"]').attr('value', @text_val)
66
+ cs.set_next form
67
+ }.
68
+ submit { |cs|
69
+ x = YAML.load cs.res.content
70
+ assert_equal @text_val, x['params']['t'][0]
71
+ assert_equal 'go', x['params']['s'][0]
72
+ }
73
+ end
74
+
75
+ def test_submit_post
76
+ Chainsaw.launch(TEST_URL + '03.html').
77
+ open { |cs|
78
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
79
+ form = cs.doc.search('id("post-form")').first
80
+ form.xpath('//input[@name="t"]').attr('value', @text_val)
81
+ cs.set_next form
82
+ }.
83
+ submit { |cs|
84
+ x = YAML.load cs.res.content
85
+ assert_equal @text_val, x['params']['t'][0]
86
+ assert_equal 'go', x['params']['s'][0]
87
+ }
88
+ end
89
+
90
+
91
+ def test_submit_process
92
+ Chainsaw.launch(TEST_URL + '03.html').
93
+ process { |cs|
94
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
95
+ form = cs.doc.search('id("post-form")').first
96
+ form.xpath('//input[@name="t"]').attr('value', @text_val)
97
+ cs.set_next form
98
+ }.
99
+ process { |cs|
100
+ x = YAML.load cs.res.content
101
+ assert_equal @text_val, x['params']['t'][0]
102
+ assert_equal 'go', x['params']['s'][0]
103
+ }
104
+ end
105
+
106
+ def test_submit_file
107
+ file_path = File.dirname(__FILE__) + '/htdocs/01.html'
108
+ Chainsaw.launch(TEST_URL + '03.html').
109
+ open { |cs|
110
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
111
+ form = cs.doc.search('id("upload-form")').first
112
+ form.xpath('//input[@name="f"]').attr('value', file_path)
113
+ cs.set_next form
114
+ }.
115
+ submit { |cs|
116
+ stat = File.stat(file_path)
117
+ x = YAML.load cs.res.content
118
+ data = x['upload']
119
+ assert_equal stat.size, data['size'].to_i
120
+ }
121
+ end
122
+
123
+ def test_each
124
+ count = 0
125
+ Chainsaw.launch(TEST_URL + '01.html').open { |cs|
126
+ cs.set_next cs.doc.xpath('//a')
127
+ }.each { |cs|
128
+ count += 1
129
+ cs.open { |cs|
130
+ if count == 4
131
+ x = YAML.load cs.res.content
132
+ assert_equal TEST_URL + '01.html', x['env']['HTTP_REFERER']
133
+ end
134
+ }
135
+ }
136
+ assert_equal 5, count
137
+ end
138
+
139
+ def test_each_with_index
140
+ count = 0
141
+ Chainsaw.launch(TEST_URL + '01.html').open { |cs|
142
+ cs.set_next cs.doc.xpath('//a')
143
+ }.each_with_index { |cs, index|
144
+ assert_equal index, count
145
+ count += 1
146
+ cs.open { |cs|
147
+ if count == 4
148
+ x = YAML.load cs.res.content
149
+ assert_equal TEST_URL + '01.html', x['env']['HTTP_REFERER']
150
+ end
151
+ }
152
+ }
153
+ end
154
+
155
+ def test_referer
156
+ Chainsaw.launch(TEST_URL + '01.html').
157
+ open { |cs|
158
+ cs.set_next cs.doc.search('//a[contains(@href,"cgi.rb")]')[0]
159
+ }.
160
+ open { |cs|
161
+ x = YAML.load cs.res.content
162
+ assert_equal TEST_URL + '01.html', x['env']['HTTP_REFERER']
163
+ }
164
+
165
+ Chainsaw.launch(TEST_URL + '01.html', {:hide_referer => true}).
166
+ open { |cs|
167
+ cs.set_next cs.doc.search('//a[contains(@href,"cgi.rb")]')[0]
168
+ }.
169
+ open { |cs|
170
+ x = YAML.load cs.res.content
171
+ assert_nil x['env']['HTTP_REFERER']
172
+ }
173
+
174
+ end
175
+
176
+ =begin
177
+ def test_auth
178
+ user_pass = 'testuser:testpass'
179
+ Chainsaw.launch(TEST_URL + 'cgi.rb?auth').
180
+ set_auth(*user_pass.split(':')).
181
+ open {|cs|
182
+ x = YAML.load cs.res.content
183
+ assert_equal user_pass, x['auth']
184
+ cs.set_next cs.uri
185
+ }.
186
+ open { |cs|
187
+ assert_equal 200, cs.res.status
188
+ cs.uri
189
+ }
190
+
191
+ # I want to fix this to return 401 status and content body...
192
+ assert_raise Chainsaw::RequestError do
193
+ Chainsaw.launch(TEST_URL + 'cgi.rb?auth').
194
+ open { |cs|
195
+ assert_equal 401, cs.res.status
196
+ }
197
+ end
198
+
199
+ assert_raise Chainsaw::RequestError do
200
+ Chainsaw.launch.
201
+ set_auth(*user_pass.split(':')).
202
+ set_next(TEST_URL + 'cgi.rb?auth').
203
+ open { |cs|
204
+ assert_equal 401, cs.res.status
205
+ }
206
+ end
207
+ end
208
+ =end
209
+
210
+ def test_redirect
211
+ Chainsaw.launch(TEST_URL + 'cgi.rb?redirect').
212
+ open { |cs|
213
+ assert_equal TEST_URL + '02.html', cs.uri.to_s
214
+ }
215
+ end
216
+
217
+ def test_request_failed
218
+ x = begin
219
+ Chainsaw.launch(TEST_URL).open.
220
+ set_next('http://localhost/').open
221
+ rescue => e
222
+ e.message
223
+ end
224
+ assert_equal 'Error occured during 2nd request; url: "http://localhost/"', x
225
+ end
226
+
227
+ def test_invalid_url
228
+ assert_raise(TypeError) { Chainsaw.launch('ppppppppppp').open.doc }
229
+ end
230
+
231
+ def test_max_history_count
232
+ cs = Chainsaw.launch
233
+ cs.max_history_count = 3
234
+ 6.times do |i|
235
+ cs.set_next("#{TEST_URL}0#{i+1}.html").open
236
+ end
237
+
238
+ assert_equal 3, cs.history.size
239
+ assert_equal TEST_URL + '06.html', cs.history.first[:location]
240
+ end
241
+
242
+ def test_ignore_redirect
243
+
244
+ end
245
+
246
+ def test_result
247
+ cs = Chainsaw.launch
248
+ 6.times do |i|
249
+ cs.set_next("#{TEST_URL}0#{i+1}.html").open do |cs|
250
+ [i, cs.uri]
251
+ end
252
+ end
253
+ assert_equal 6, cs.results.size
254
+ assert_equal 2, cs.results[2][0]
255
+ assert_equal TEST_URL + '03.html', cs.results[2][1].to_s
256
+
257
+ end
258
+
259
+ def test_aliases
260
+ Chainsaw.launch(TEST_URL + '03.html').> { |cs|
261
+ assert_instance_of Nokogiri::HTML::Document, cs.doc
262
+ form = cs.doc.search('id("post-form")').first
263
+ form.xpath('//input[@name="t"]').attr('value', @text_val)
264
+ cs.set_next form
265
+ }.> { |cs|
266
+ x = YAML.load cs.res.content
267
+ assert_equal @text_val, x['params']['t'][0]
268
+ assert_equal 'go', x['params']['s'][0]
269
+ }
270
+
271
+ end
272
+
273
+ end
274
+