rfeedparser 0.9.931 → 0.9.940

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.
Files changed (40) hide show
  1. data/lib/rfeedparser.rb +143 -58
  2. data/lib/rfeedparser/aliases.rb +1 -1
  3. data/lib/rfeedparser/better_attributelist.rb +11 -11
  4. data/lib/rfeedparser/better_sgmlparser.rb +1 -1
  5. data/lib/rfeedparser/encoding_helpers.rb +120 -127
  6. data/lib/rfeedparser/feedparserdict.rb +30 -20
  7. data/lib/rfeedparser/forgiving_uri.rb +9 -7
  8. data/lib/rfeedparser/markup_helpers.rb +11 -14
  9. data/lib/rfeedparser/parser_mixin.rb +16 -11
  10. data/lib/rfeedparser/parsers.rb +1 -2
  11. data/lib/rfeedparser/scrub.rb +95 -90
  12. data/lib/rfeedparser/time_helpers.rb +379 -379
  13. data/lib/rfeedparser/utilities.rb +23 -0
  14. data/tests/rfeedparser_test_helper.rb +262 -0
  15. data/tests/rfeedparserserver.rb +3 -109
  16. data/tests/rfeedparsertest.rb +6 -165
  17. data/tests/rfponly/http/200.xml +30 -0
  18. data/tests/rfponly/http/220.xml +28 -0
  19. data/tests/rfponly/http/300.xml +8 -0
  20. data/tests/rfponly/http/300.xml_redirect +25 -0
  21. data/tests/rfponly/http/301.xml +8 -0
  22. data/tests/rfponly/http/301.xml_redirect +25 -0
  23. data/tests/rfponly/http/302.xml +8 -0
  24. data/tests/rfponly/http/302.xml_redirect +25 -0
  25. data/tests/rfponly/http/307.xml +8 -0
  26. data/tests/rfponly/http/307.xml_redirect +25 -0
  27. data/tests/rfponly/http/320.xml +8 -0
  28. data/tests/rfponly/http/320.xml_redirect +25 -0
  29. data/tests/rfponly/http/400.xml +7 -0
  30. data/tests/rfponly/http/404.xml +7 -0
  31. data/tests/rfponly/http/410.xml +7 -0
  32. data/tests/rfponly/http/420.xml +7 -0
  33. data/tests/rfponly/http/500.xml +7 -0
  34. data/tests/rfponly/http/520.xml +7 -0
  35. data/tests/rfponly/http/etag.xml +28 -0
  36. data/tests/rfponly/http/lastmodified.xml +29 -0
  37. data/tests/rfponly/wellformed/date/feed_modified_with_negative_numeric_timezone.xml +9 -0
  38. data/tests/rfponly/wellformed/date/feed_modified_with_positive_numeric_timezone.xml +9 -0
  39. data/tests/rfponly/wellformed/scrub/hpricot_self_closing_tag_workaround.xml +11 -0
  40. metadata +31 -3
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ require File.join(File.dirname(__FILE__), 'aliases')
3
+ require File.join(File.dirname(__FILE__), 'encoding_helpers')
4
+ require File.join(File.dirname(__FILE__), 'markup_helpers')
5
+ require File.join(File.dirname(__FILE__), 'scrub')
6
+ require File.join(File.dirname(__FILE__), 'time_helpers')
7
+
8
+ module FeedParserUtilities
9
+
10
+ def parse_date(date_string)
11
+ FeedParser::FeedTimeParser.parse_date(date_string)
12
+ end
13
+ module_function :parse_date
14
+
15
+ def extract_tuple(atime)
16
+ FeedParser::FeedTimeParser.extract_tuple(atime)
17
+ end
18
+ module_function :extract_tuple
19
+
20
+ def py2rtime(pytuple)
21
+ return Time.utc(*pytuple[0..5]) unless pytuple.blank?
22
+ end
23
+ end
@@ -0,0 +1,262 @@
1
+ require 'test/unit'
2
+ require File.join(File.dirname(__FILE__),'../lib/rfeedparser')
3
+
4
+ begin
5
+ require 'rubygems'
6
+ gem 'mongrel'
7
+ require 'mongrel'
8
+ rescue => details
9
+ STDERR.puts "Whoops, had an error with loading mongrel as a gem. Trying just 'require'. Mongrel is required for testing."
10
+ require 'mongrel'
11
+ end
12
+ Mongrel::HTTP_STATUS_CODES[220] = "Unspecified success"
13
+
14
+ def uconvert(one, two, three); FeedParser::uconvert(one, two, three); end
15
+ def _ebcdic_to_ascii(one); FeedParser::_ebcdic_to_ascii(one); end
16
+
17
+ $PORT = 8097 # Not configurable, hard coded in the xml files
18
+
19
+ def translate_data(data)
20
+ if data[0..3] == "\x4c\x6f\xa7\x94"
21
+ # EBCDIC
22
+ data = _ebcdic_to_ascii(data)
23
+ elsif data[0..3] == "\x00\x3c\x00\x3f"
24
+ # UTF-16BE
25
+ data = uconvert(data, 'utf-16be', 'utf-8')
26
+ elsif data.size >= 4 and data[0..1] == "\xfe\xff" and data[2..3] != "\x00\x00"
27
+ # UTF-16BE with BOM
28
+ data = uconvert(data[2..-1], 'utf-16be', 'utf-8')
29
+ elsif data[0..3] == "\x3c\x00\x3f\x00"
30
+ # UTF-16LE
31
+ data = uconvert(data, 'utf-16le', 'utf-8')
32
+ elsif data.size >=4 and data[0..1] == "\xff\xfe" and data[2..3] != "\x00\x00"
33
+ # UTF-16LE with BOM
34
+ data = uconvert(data[2..-1], 'utf-16le', 'utf-8')
35
+ elsif data[0..3] == "\x00\x00\x00\x3c"
36
+ # UTF-32BE
37
+ data = uconvert(data, 'utf-32be', 'utf-8')
38
+ elsif data[0..3] == "\x3c\x00\x00\x00"
39
+ # UTF-32LE
40
+ data = uconvert(data, 'utf-32le', 'utf-8')
41
+ elsif data[0..3] == "\x00\x00\xfe\xff"
42
+ # UTF-32BE with BOM
43
+ data = uconvert(data[4..-1], 'utf-32BE', 'utf-8')
44
+ elsif data[0..3] == "\xff\xfe\x00\x00"
45
+ # UTF-32LE with BOM
46
+ data = uconvert(data[4..-1], 'utf-32LE', 'utf-8')
47
+ elsif data[0..2] == "\xef\xbb\xbf"
48
+ # UTF-8 with BOM
49
+ data = data[3..-1]
50
+ else
51
+ # ASCII-compatible
52
+ end
53
+ return data
54
+ end
55
+
56
+ def scrape_headers(xmlfile)
57
+ # Called by the server
58
+ xm = open(xmlfile)
59
+ data = xm.read
60
+ htaccess = File.dirname(xmlfile)+"/.htaccess"
61
+ xml_headers = {}
62
+ server_headers = {}
63
+ the_type = nil
64
+ if File.exists? htaccess
65
+ fn = File.split(xm.path)[-1]
66
+ ht_file = open(htaccess)
67
+ type_match = ht_file.read.match(/^\s*<Files\s+#{fn}>\s*\n\s*AddType\s+(.*?)\s+.xml/m)
68
+ the_type = type_match[1].strip.gsub(/^("|')/,'').gsub(/("|')$/,'').strip if type_match and type_match[1]
69
+ if type_match and the_type
70
+ #content_type, charset = type_match[1].split(';')
71
+ server_headers["Content-Type"] = the_type
72
+ end
73
+ end
74
+ data = translate_data(data)
75
+ header_regexp = /^Header:\s*([^:]+)\s*:\s*(.+)\s*$/
76
+ da = data.scan header_regexp
77
+ unless da.nil? or da.empty?
78
+ da.flatten!
79
+ da.each{|e| e.strip!;e.gsub!(/(Content-type|content-type|content-Type)/, "Content-Type")}
80
+ xml_headers = Hash[*da] # Asterisk magic!
81
+ end
82
+ Mongrel::Const::const_set('ETAG_FORMAT', xml_headers['ETag']) unless (xml_headers['ETag'].nil? or xml_headers['ETag'].empty?)
83
+ return xml_headers.merge(server_headers)
84
+ end
85
+
86
+ def scrape_status(xmlfile)
87
+ # Called by the server
88
+ xm = open(xmlfile)
89
+ data = xm.read
90
+ data = translate_data(data)
91
+ da = data.scan /^Status:\s*(.+)\s?$/
92
+ unless da.nil? or da.empty?
93
+ da.flatten!
94
+ da.each{ |e| return e.to_i }
95
+ end
96
+ return 200
97
+ end
98
+
99
+ def scrape_assertion_strings(xmlfile)
100
+ # Called by the testing client
101
+ data = open(xmlfile).read
102
+ data = translate_data(data)
103
+ test = data.scan /Description:\s*(.*?)\s*Expect:\s*(.*)\s*-->/
104
+ description, evalString = test.first.map{ |s| s.strip }
105
+
106
+ # Here we translate the expected values in Python to Ruby
107
+
108
+ # Find Python unicode strings starting with u"
109
+ evalString.gsub!(/\bu'(.*?)'/) do |m|
110
+ esc = $1.to_s.dup
111
+ # Replace \u hex values with actual Unicode char
112
+ esc.gsub!(/\\u([0-9a-fA-F]{4})/){ |m| [$1.hex].pack('U*') }
113
+ " '"+esc+"'"
114
+ end
115
+
116
+ # Find Python unicode strings starting with u"
117
+ evalString.gsub!(/\bu"(.*?)"/) do |m|
118
+ esc = $1.to_s.dup
119
+ # Replace \u hex values with actual Unicode char
120
+ esc.gsub!(/\\u([0-9a-fA-F]{4})/){ |m| [$1.hex].pack('U*') }
121
+ " \""+esc+"\""
122
+ end
123
+ # The above does the following: u'string' => 'string'
124
+ # u'ba\u20acha' => 'ba€ha' # Same for double quoted strings
125
+
126
+ evalString.gsub!(/\\x([0-9a-fA-F]{2})/){ |m| [$1.hex].pack('U*') } # "ba\xa3la" => "ba£la"
127
+ evalString.gsub! /'\s*:\s+/, "' => " # {'foo': 'bar'} => {'foo' => 'bar'}
128
+ evalString.gsub! /"\s*:\s+/, "\" => " # {"foo": 'bar'} => {"foo" => 'bar'}
129
+ evalString.gsub! /\=\s*\((.*?)\)/, '= [\1]' # = (2004, 12, 4) => = [2004, 12, 4]
130
+ evalString.gsub!(/"""(.*?)"""/) do # """<a b="foo">""" => "<a b=\"foo\">"
131
+ "\""+$1.gsub!(/"/,"\\\"")+"\"" # haha, ugly!
132
+ end
133
+ evalString.gsub! /(\w|\])\s*\=\= 0\s*$/, '\1 == false' # ] == 0 => ] == false
134
+ evalString.gsub! /(\w|\])\s*\=\= 1\s*$/, '\1 == true' # ] == 1 => ] == true
135
+ evalString.gsub! /len\((.*?)\)\s*\=\=\s*(\d{1,3})/, '\1.length == \2' # len(ary) == 1 => ary.length == 1
136
+ evalString.gsub! /None/, "nil" # None => nil # well, duh
137
+ return description, evalString
138
+ end
139
+
140
+ def is_invalid(response_status)
141
+ !is_valid(response_status)
142
+ end
143
+
144
+ def is_valid(response_status)
145
+ response_status > 199 && response_status < 300
146
+ end
147
+
148
+ class FeedParserTestRequestHandler < Mongrel::DirHandler
149
+ def process(request, response)
150
+ req_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET
151
+ req_path = can_serve request.params[Mongrel::Const::PATH_INFO]
152
+ if not req_path
153
+ # not found, return a 404
154
+ response.start(404) do |head, out|
155
+ head['Content-Type'] = 'text/plain'
156
+ out << "File not found"
157
+ end
158
+ else
159
+ begin
160
+ if File.directory? req_path
161
+ send_dir_listing(request.params[Mongrel::Const::REQUEST_URI], req_path, response)
162
+ elsif req_method == Mongrel::Const::HEAD
163
+ response_status = scrape_status(req_path)
164
+ response.start(response_status) do |head,out|
165
+ xml_head = scrape_headers(req_path)
166
+ xml_head.each_key{|k| head[k] = xml_head[k] }
167
+
168
+ if is_invalid(response_status)
169
+ head['content-type'] = 'text/plain;'
170
+ out << response_status
171
+ end
172
+ end
173
+
174
+ send_file(req_path, request, response, true) unless is_invalid(response_status)
175
+ elsif req_method == Mongrel::Const::GET
176
+ response_status = scrape_status(req_path)
177
+ response.start(response_status) do |head,out|
178
+ xml_head = scrape_headers(req_path)
179
+ xml_head.each_key{|k| head[k] = xml_head[k] }
180
+ if is_invalid(response_status)
181
+ head['content-type'] = 'text/plain;'
182
+ out << response_status
183
+ end
184
+ end
185
+
186
+ send_file(req_path, request, response, false) unless is_invalid(response_status)
187
+ else
188
+ response.start(403) { |head,out|
189
+ head['Content-Type'] = 'text/plain'
190
+ out.write(ONLY_HEAD_GET)
191
+ }
192
+ end
193
+ rescue => details
194
+ STDERR.puts "Error sending file #{req_path}: #{details}"
195
+ end
196
+ end
197
+ end
198
+
199
+ # Overriding the send_file in DirHandler for a goddamn one line bug fix.
200
+ # Holy shit does this suck. Changing `response.status = 200` to
201
+ # `response.status ||= 200`. Also, adding Mongrel:: in front of the Const
202
+ # because subclassing makes them break.
203
+ def send_file(req_path, request, response, header_only=false)
204
+
205
+ stat = File.stat(req_path)
206
+
207
+ # Set the last modified times as well and etag for all files
208
+ mtime = stat.mtime
209
+ # Calculated the same as apache, not sure how well the works on win32
210
+ etag = Mongrel::Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino]
211
+
212
+ modified_since = request.params[Mongrel::Const::HTTP_IF_MODIFIED_SINCE]
213
+ none_match = request.params[Mongrel::Const::HTTP_IF_NONE_MATCH]
214
+
215
+ # test to see if this is a conditional request, and test if
216
+ # the response would be identical to the last response
217
+ same_response = case
218
+ when modified_since && !last_response_time = Time.httpdate(modified_since) rescue nil : false
219
+ when modified_since && last_response_time > Time.now : false
220
+ when modified_since && mtime > last_response_time : false
221
+ when none_match && none_match == '*' : false
222
+ when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag) : false
223
+ else modified_since || none_match # validation successful if we get this far and at least one of the header exists
224
+ end
225
+
226
+ header = response.header
227
+ header[Mongrel::Const::ETAG] = etag
228
+
229
+ if same_response
230
+ response.start(304) {}
231
+ else
232
+ # first we setup the headers and status then we do a very fast send on the socket directly
233
+ response.status ||= 200
234
+ header[Mongrel::Const::LAST_MODIFIED] = mtime.httpdate
235
+
236
+ # set the mime type from our map based on the ending
237
+ dot_at = req_path.rindex('.')
238
+ if dot_at
239
+ header[Mongrel::Const::CONTENT_TYPE] = MIME_TYPES[req_path[dot_at .. -1]] || @default_content_type
240
+ else
241
+ header[Mongrel::Const::CONTENT_TYPE] = @default_content_type
242
+ end
243
+
244
+ # send a status with out content length
245
+ response.send_status(stat.size)
246
+ response.send_header
247
+
248
+ if not header_only
249
+ response.send_file(req_path, stat.size < Mongrel::Const::CHUNK_SIZE * 2)
250
+ end
251
+ end
252
+ end
253
+ end
254
+
255
+
256
+ class XMLTests < Test::Unit::TestCase
257
+ # Empty, but here for clarity
258
+ def setup
259
+ end
260
+ def teardown
261
+ end
262
+ end
@@ -1,116 +1,10 @@
1
- #!/usr/bin/ruby
2
- # This is the same server code that runs in rfeedparsertest.rb, but split
3
- # off so that we can fully check each test individually (i.e. get the HTTP
4
- # headers right).
5
- # This really needs to be merged into rfeedparsertest.rb
6
- require 'rubygems'
7
- gem 'mongrel'
8
- require 'mongrel'
9
- require File.dirname(__FILE__)+'/../lib/rfeedparser'
10
- $PORT = 8097
11
- def translate_data(data)
12
- if data[0..3] == "\x4c\x6f\xa7\x94"
13
- # EBCDIC
14
- data = _ebcdic_to_ascii(data)
15
- elsif data[0..3] == "\x00\x3c\x00\x3f"
16
- # UTF-16BE
17
- data = uconvert(data, 'utf-16be', 'utf-8')
18
- elsif data.size >= 4 and data[0..1] == "\xfe\xff" and data[2..3] != "\x00\x00"
19
- # UTF-16BE with BOM
20
- data = uconvert(data[2..-1], 'utf-16be', 'utf-8')
21
- elsif data[0..3] == "\x3c\x00\x3f\x00"
22
- # UTF-16LE
23
- data = uconvert(data, 'utf-16le', 'utf-8')
24
- elsif data.size >=4 and data[0..1] == "\xff\xfe" and data[2..3] != "\x00\x00"
25
- # UTF-16LE with BOM
26
- data = uconvert(data[2..-1], 'utf-16le', 'utf-8')
27
- elsif data[0..3] == "\x00\x00\x00\x3c"
28
- # UTF-32BE
29
- data = uconvert(data, 'utf-32be', 'utf-8')
30
- elsif data[0..3] == "\x3c\x00\x00\x00"
31
- # UTF-32LE
32
- data = uconvert(data, 'utf-32le', 'utf-8')
33
- elsif data[0..3] == "\x00\x00\xfe\xff"
34
- # UTF-32BE with BOM
35
- data = uconvert(data[4..-1], 'utf-32BE', 'utf-8')
36
- elsif data[0..3] == "\xef\xfe\x00\x00"
37
- # UTF-32LE with BOM
38
- data = uconvert(data[4..-1], 'utf-32le', 'utf-8')
39
- elsif data[0..2] == "\xef\xbb\xbf"
40
- # UTF-8 with BOM
41
- data = data[3..-1]
42
- end
43
- return data
44
- end
1
+ #!/usr/bin/env ruby
45
2
 
46
-
47
- def scrape_headers(xmlfile)
48
- # Called by the server
49
- xm = open(xmlfile)
50
- data = xm.read
51
- htaccess = File.dirname(xmlfile)+"/.htaccess"
52
- xml_headers = {}
53
- server_headers = {}
54
- the_type = nil
55
- if File.exists? htaccess
56
- fn = xm.path.split(File::Separator)[-1] # I can't find the right method for this
57
- ht_file = open(htaccess)
58
- type_match = ht_file.read.match(/^\s*<Files\s+#{fn}>\s*\n\s*AddType\s+(.*?)\s+.xml/m)
59
- the_type = type_match[1].strip.gsub(/^("|')/,'').gsub(/("|')$/,'').strip if type_match and type_match[1]
60
- if type_match and the_type
61
- #content_type, charset = type_match[1].split(';')
62
- server_headers["Content-Type"] = the_type
63
- end
64
- end
65
- data = translate_data(data)
66
- da = data.scan /^Header:\s*([^:]+):(.+)\s$/
67
- unless da.nil? or da.empty?
68
- da.flatten!
69
- da.each{|e| e.strip!;e.gsub!(/(Content-type|content-type|content-Type)/, "Content-Type")}
70
- xml_headers = Hash[*da] # Asterisk magic!
71
- end
72
- return xml_headers.merge(server_headers)
73
- end
74
-
75
-
76
- class FeedParserTestRequestHandler < Mongrel::DirHandler
77
-
78
- def process(request, response)
79
- req_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET
80
- req_path = can_serve request.params[Mongrel::Const::PATH_INFO]
81
- if not req_path
82
- # not found, return a 404
83
- response.start(404) do |head, out|
84
- out << "File not found"
85
- end
86
- else
87
- begin
88
- if File.directory? req_path
89
- send_dir_listing(request.params[Mongrel::Const::REQUEST_URI], req_path, response)
90
- elsif req_method == Mongrel::Const::HEAD
91
- response.start do |head,out|
92
- xml_head = scape_headers(req_path)
93
- xml_head.each_key{|k| head[k] = xml_head[k] }
94
- end
95
- send_file(req_path, request, response, true)
96
- elsif req_method == Mongrel::Const::GET
97
- response.start do |head,out|
98
- xml_head = scrape_headers(req_path)
99
- xml_head.each_key{|k| head[k] = xml_head[k] }
100
- end
101
- send_file(req_path, request, response, false)
102
- else
103
- response.start(403) {|head,out| out.write(ONLY_HEAD_GET) }
104
- end
105
- rescue => details
106
- STDERR.puts "MON Error sending file #{req_path}: #{details}"
107
- end
108
- end
109
- end
110
- end
3
+ require File.join(File.dirname(__FILE__), 'rfeedparser_test_helper')
111
4
 
112
5
  # Start up the mongrel server and tell it how to send the tests
113
6
  server = Mongrel::HttpServer.new("0.0.0.0", $PORT)
114
7
  Mongrel::DirHandler::add_mime_type('.xml','application/xml')
8
+ Mongrel::DirHandler::add_mime_type('.xml_redirect','application/xml')
115
9
  server.register("/", FeedParserTestRequestHandler.new('.'))
116
10
  server.run.join
@@ -1,175 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
  # This is based off of Sam Ruby's xml_filetest.rb
3
- # I've adapted it for feedparser.rb
3
+ # I've adapted it for rfeedparser
4
4
  # http://intertwingly.net/blog/2005/10/30/Testing-FeedTools-Dynamically/
5
5
 
6
- require 'test/unit'
7
- require File.dirname(__FILE__)+'/../lib/rfeedparser'
8
-
9
- begin
10
- require 'rubygems'
11
- gem 'mongrel'
12
- require 'mongrel'
13
- rescue => details
14
- STDERR.puts "Whoops, had an error with loading mongrel as a gem. Trying just 'require'. Mongrel is required for testing."
15
- require 'mongrel'
16
- end
17
-
18
-
19
- $PORT = 8097 # Not configurable, hard coded in the xml files
20
-
21
- def translate_data(data)
22
- if data[0..3] == "\x4c\x6f\xa7\x94"
23
- # EBCDIC
24
- data = _ebcdic_to_ascii(data)
25
- elsif data[0..3] == "\x00\x3c\x00\x3f"
26
- # UTF-16BE
27
- data = uconvert(data, 'utf-16be', 'utf-8')
28
- elsif data.size >= 4 and data[0..1] == "\xfe\xff" and data[2..3] != "\x00\x00"
29
- # UTF-16BE with BOM
30
- data = uconvert(data[2..-1], 'utf-16be', 'utf-8')
31
- elsif data[0..3] == "\x3c\x00\x3f\x00"
32
- # UTF-16LE
33
- data = uconvert(data, 'utf-16le', 'utf-8')
34
- elsif data.size >=4 and data[0..1] == "\xff\xfe" and data[2..3] != "\x00\x00"
35
- # UTF-16LE with BOM
36
- data = uconvert(data[2..-1], 'utf-16le', 'utf-8')
37
- elsif data[0..3] == "\x00\x00\x00\x3c"
38
- # UTF-32BE
39
- data = uconvert(data, 'utf-32be', 'utf-8')
40
- elsif data[0..3] == "\x3c\x00\x00\x00"
41
- # UTF-32LE
42
- data = uconvert(data, 'utf-32le', 'utf-8')
43
- elsif data[0..3] == "\x00\x00\xfe\xff"
44
- # UTF-32BE with BOM
45
- data = uconvert(data[4..-1], 'utf-32BE', 'utf-8')
46
- elsif data[0..3] == "\xff\xfe\x00\x00"
47
- # UTF-32LE with BOM
48
- data = uconvert(data[4..-1], 'utf-32LE', 'utf-8')
49
- elsif data[0..2] == "\xef\xbb\xbf"
50
- # UTF-8 with BOM
51
- data = data[3..-1]
52
- else
53
- # ASCII-compatible
54
- end
55
- return data
56
- end
57
-
58
- def scrape_headers(xmlfile)
59
- # Called by the server
60
- xm = open(xmlfile)
61
- data = xm.read
62
- htaccess = File.dirname(xmlfile)+"/.htaccess"
63
- xml_headers = {}
64
- server_headers = {}
65
- the_type = nil
66
- if File.exists? htaccess
67
- fn = xm.path.split(File::Separator)[-1] # I can't find the right method for this
68
- ht_file = open(htaccess)
69
- type_match = ht_file.read.match(/^\s*<Files\s+#{fn}>\s*\n\s*AddType\s+(.*?)\s+.xml/m)
70
- the_type = type_match[1].strip.gsub(/^("|')/,'').gsub(/("|')$/,'').strip if type_match and type_match[1]
71
- if type_match and the_type
72
- #content_type, charset = type_match[1].split(';')
73
- server_headers["Content-Type"] = the_type
74
- end
75
- end
76
- data = translate_data(data)
77
- da = data.scan /^Header:\s*([^:]+):(.+)\s$/
78
- unless da.nil? or da.empty?
79
- da.flatten!
80
- da.each{|e| e.strip!;e.gsub!(/(Content-type|content-type|content-Type)/, "Content-Type")}
81
- xml_headers = Hash[*da] # Asterisk magic!
82
- end
83
- return xml_headers.merge(server_headers)
84
- end
85
-
86
- def scrape_assertion_strings(xmlfile)
87
- # Called by the testing client
88
- data = open(xmlfile).read
89
- data = translate_data(data)
90
- test = data.scan /Description:\s*(.*?)\s*Expect:\s*(.*)\s*-->/
91
- description, evalString = test.first.map{ |s| s.strip }
92
-
93
- # Here we translate the expected values in Python to Ruby
94
- evalString.gsub!(/\bu'(.*?)'/) do |m|
95
- esc = $1.to_s.dup
96
- esc.gsub!(/\\u([0-9a-fA-F]{4})/){ |m| [$1.hex].pack('U*') }
97
- " '"+esc+"'"
98
- end
99
- evalString.gsub!(/\bu"(.*?)"/) do |m|
100
- esc = $1.to_s.dup
101
- esc.gsub!(/\\u([0-9a-fA-F]{4})/){ |m| [$1.hex].pack('U*') }
102
- " \""+esc+"\""
103
- end
104
- # The above does the following: u'string' => 'string'
105
- # u'ba\u20acha' => 'ba€ha' # Same for double quoted strings
106
-
107
- evalString.gsub!(/\\x([0-9a-fA-F]{2})/){ |m| [$1.hex].pack('U*') } # "ba\xa3la" => "ba£la"
108
- evalString.gsub! /'\s*:\s+/, "' => " # {'foo': 'bar'} => {'foo' => 'bar'}
109
- evalString.gsub! /"\s*:\s+/, "\" => " # {"foo": 'bar'} => {"foo" => 'bar'}
110
- evalString.gsub! /\=\s*\((.*?)\)/, '= [\1]' # = (2004, 12, 4) => = [2004, 12, 4]
111
- evalString.gsub!(/"""(.*?)"""/) do # """<a b="foo">""" => "<a b="foo">"
112
- "\""+$1.gsub!(/"/,"\\\"")+"\"" # haha, ugly!
113
- end
114
- evalString.gsub! /(\w|\])\s*\=\= 0\s*$/, '\1 == false' # ] == 0 => ] == false
115
- evalString.gsub! /(\w|\])\s*\=\= 1\s*$/, '\1 == true' # ] == 1 => ] == true
116
- evalString.gsub! /len\((.*?)\)\s*\=\=\s*(\d{1,3})/, '\1.length == \2' # len(ary) == 1 => ary.length == 1
117
- evalString.gsub! /None/, "nil" # None => nil # well, duh
118
- return description, evalString
119
- end
120
-
121
- class FeedParserTestRequestHandler < Mongrel::DirHandler
122
- def process(request, response)
123
- req_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET
124
- req_path = can_serve request.params[Mongrel::Const::PATH_INFO]
125
- if not req_path
126
- # not found, return a 404
127
- response.start(404) do |head, out|
128
- out << "File not found"
129
- end
130
- else
131
- begin
132
- if File.directory? req_path
133
- send_dir_listing(request.params[Mongrel::Const::REQUEST_URI], req_path, response)
134
- elsif req_method == Mongrel::Const::HEAD
135
- response.start do |head,out|
136
- xml_head = scrape_headers(req_path)
137
- xml_head.each_key{|k| head[k] = xml_head[k] }
138
- end
139
-
140
- send_file(req_path, request, response, true)
141
- elsif req_method == Mongrel::Const::GET
142
- response.start do |head,out|
143
- xml_head = scrape_headers(req_path)
144
- xml_head.each_key{|k| head[k] = xml_head[k] }
145
- end
146
-
147
- send_file(req_path, request, response, false)
148
- else
149
- response.start(403) {|head,out| out.write(ONLY_HEAD_GET) }
150
- end
151
- rescue => details
152
- STDERR.puts "Error sending file #{req_path}: #{details}"
153
- end
154
- end
155
- end
156
- end
157
-
158
-
159
- class XMLTests < Test::Unit::TestCase
160
- # Empty, but here for clarity
161
- def setup
162
- end
163
- def teardown
164
- end
165
- end
6
+ require File.join(File.dirname(__FILE__),'rfeedparser_test_helper')
166
7
 
167
8
  # default methods to be public
168
9
  XMLTests.send(:public)
169
10
  # add one unit test for each file
170
- Dir['**/*.xml'].each do |xmlfile|
171
- #Dir['tests/**/*.xml'].each do |xmlfile|
172
- methname = "tests_"+xmlfile.gsub('/','_').sub('.xml','')
11
+ Dir["#{File.dirname(__FILE__)}/**/*.xml"].each do |xmlfile|
12
+ methname = "tests_"+xmlfile.gsub('./', '').gsub('/','_').sub('.xml','')
173
13
  XMLTests.send(:define_method, methname) {
174
14
 
175
15
  options = {}
@@ -184,7 +24,7 @@ Dir['**/*.xml'].each do |xmlfile|
184
24
  fp = FeedParser.parse("http://127.0.0.1:#{$PORT}/#{xmlfile}", options)
185
25
  # I should point out that the 'compatible' arg is not necessary,
186
26
  # but probably will be in the future if we decide to change the default.
187
-
27
+
188
28
  description, evalString = scrape_assertion_strings(xmlfile)
189
29
  assert fp.instance_eval(evalString), description.inspect
190
30
  }
@@ -192,5 +32,6 @@ end
192
32
  # Start up the mongrel server and tell it how to send the tests
193
33
  server = Mongrel::HttpServer.new("0.0.0.0",$PORT)
194
34
  Mongrel::DirHandler::add_mime_type('.xml','application/xml')
35
+ Mongrel::DirHandler::add_mime_type('.xml_redirect','application/xml')
195
36
  server.register("/", FeedParserTestRequestHandler.new("."))
196
37
  server.run