blankslate 2.1.2.4 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,573 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Portions copyright 2004 by Jim Weirich (jim@weirichhouse.org).
5
+ # Portions copyright 2005 by Sam Ruby (rubys@intertwingly.net).
6
+ # All rights reserved.
7
+
8
+ # Permission is granted for use, copying, modification, distribution,
9
+ # and distribution of modified versions of this work as long as the
10
+ # above copyright notice is included.
11
+ #++
12
+
13
+ require 'test/unit'
14
+ require 'test/preload'
15
+ require 'builder'
16
+ require 'builder/xmlmarkup'
17
+
18
+ class TestMarkup < Test::Unit::TestCase
19
+ def setup
20
+ @xml = Builder::XmlMarkup.new
21
+ end
22
+
23
+ def test_create
24
+ assert_not_nil @xml
25
+ end
26
+
27
+ def test_simple
28
+ @xml.simple
29
+ assert_equal "<simple/>", @xml.target!
30
+ end
31
+
32
+ def test_value
33
+ @xml.value("hi")
34
+ assert_equal "<value>hi</value>", @xml.target!
35
+ end
36
+
37
+ def test_empty_value
38
+ @xml.value("")
39
+ assert_equal "<value/>", @xml.target!
40
+ end
41
+
42
+ def test_nil_value
43
+ @xml.value(nil)
44
+ assert_equal "<value/>", @xml.target!
45
+ end
46
+
47
+ def test_nested
48
+ @xml.outer { |x| x.inner("x") }
49
+ assert_equal "<outer><inner>x</inner></outer>", @xml.target!
50
+ end
51
+
52
+ def test_attributes
53
+ @xml.ref(:id => 12)
54
+ assert_equal %{<ref id="12"/>}, @xml.target!
55
+ end
56
+
57
+ def test_string_attributes_are_quoted_by_default
58
+ @xml.ref(:id => "H&R")
59
+ assert_equal %{<ref id="H&amp;R"/>}, @xml.target!
60
+ end
61
+
62
+ def test_symbol_attributes_are_unquoted_by_default
63
+ @xml.ref(:id => :"H&amp;R")
64
+ assert_equal %{<ref id="H&amp;R"/>}, @xml.target!
65
+ end
66
+
67
+ def test_attributes_quoted_can_be_turned_on
68
+ @xml = Builder::XmlMarkup.new
69
+ @xml.ref(:id => "<H&R \"block\">")
70
+ assert_equal %{<ref id="&lt;H&amp;R &quot;block&quot;&gt;"/>}, @xml.target!
71
+ end
72
+
73
+ def test_mixed_attribute_quoting_with_nested_builders
74
+ x = Builder::XmlMarkup.new(:target=>@xml)
75
+ @xml.ref(:id=>:"H&amp;R") {
76
+ x.element(:tag=>"Long&Short")
77
+ }
78
+ assert_equal "<ref id=\"H&amp;R\"><element tag=\"Long&amp;Short\"/></ref>",
79
+ @xml.target!
80
+ end
81
+
82
+ def test_multiple_attributes
83
+ @xml.ref(:id => 12, :name => "bill")
84
+ assert_match %r{^<ref( id="12"| name="bill"){2}/>$}, @xml.target!
85
+ end
86
+
87
+ def test_attributes_with_text
88
+ @xml.a("link", :href=>"http://onestepback.org")
89
+ assert_equal %{<a href="http://onestepback.org">link</a>}, @xml.target!
90
+ end
91
+
92
+ def test_attributes_with_newlines
93
+ @xml.abbr("W3C", :title=>"World\nWide\rWeb\r\nConsortium")
94
+ assert_equal %{<abbr title="World&#10;Wide&#13;Web&#13;&#10;Consortium">W3C</abbr>},
95
+ @xml.target!
96
+ end
97
+
98
+ def test_complex
99
+ @xml.body(:bg=>"#ffffff") { |x|
100
+ x.title("T", :style=>"red")
101
+ }
102
+ assert_equal %{<body bg="#ffffff"><title style="red">T</title></body>}, @xml.target!
103
+ end
104
+
105
+ def test_funky_symbol
106
+ @xml.tag!("non-ruby-token", :id=>1) { |x| x.ok }
107
+ assert_equal %{<non-ruby-token id="1"><ok/></non-ruby-token>}, @xml.target!
108
+ end
109
+
110
+ def test_tag_can_handle_private_method
111
+ @xml.tag!("loop", :id=>1) { |x| x.ok }
112
+ assert_equal %{<loop id="1"><ok/></loop>}, @xml.target!
113
+ end
114
+
115
+ def test_no_explicit_marker
116
+ @xml.p { |x| x.b("HI") }
117
+ assert_equal "<p><b>HI</b></p>", @xml.target!
118
+ end
119
+
120
+ def test_reference_local_vars
121
+ n = 3
122
+ @xml.ol { |x| n.times { x.li(n) } }
123
+ assert_equal "<ol><li>3</li><li>3</li><li>3</li></ol>", @xml.target!
124
+ end
125
+
126
+ def test_reference_methods
127
+ @xml.title { |x| x.a { x.b(name) } }
128
+ assert_equal "<title><a><b>bob</b></a></title>", @xml.target!
129
+ end
130
+
131
+ def test_append_text
132
+ @xml.p { |x| x.br; x.text! "HI" }
133
+ assert_equal "<p><br/>HI</p>", @xml.target!
134
+ end
135
+
136
+ def test_ambiguous_markup
137
+ ex = assert_raise(ArgumentError) {
138
+ @xml.h1("data1") { b }
139
+ }
140
+ assert_match(/\btext\b/, ex.message)
141
+ assert_match(/\bblock\b/, ex.message)
142
+ end
143
+
144
+ def test_capitalized_method
145
+ @xml.P { |x| x.B("hi"); x.BR(); x.EM { x.text! "world" } }
146
+ assert_equal "<P><B>hi</B><BR/><EM>world</EM></P>", @xml.target!
147
+ end
148
+
149
+ def test_escaping
150
+ @xml.div { |x| x.text! "<hi>"; x.em("H&R Block") }
151
+ assert_equal %{<div>&lt;hi&gt;<em>H&amp;R Block</em></div>}, @xml.target!
152
+ end
153
+
154
+ def test_non_escaping
155
+ @xml.div("ns:xml"=>:"&xml;") { |x| x << "<h&i>"; x.em("H&R Block") }
156
+ assert_equal %{<div ns:xml="&xml;"><h&i><em>H&amp;R Block</em></div>}, @xml.target!
157
+ end
158
+
159
+ def test_return_value
160
+ str = @xml.x("men")
161
+ assert_equal @xml.target!, str
162
+ end
163
+
164
+ def test_stacked_builders
165
+ b = Builder::XmlMarkup.new( :target => @xml )
166
+ b.div { @xml.span { @xml.a("text", :href=>"ref") } }
167
+ assert_equal "<div><span><a href=\"ref\">text</a></span></div>", @xml.target!
168
+ end
169
+
170
+ def name
171
+ "bob"
172
+ end
173
+ end
174
+
175
+ class TestAttributeEscaping < Test::Unit::TestCase
176
+
177
+ def setup
178
+ @xml = Builder::XmlMarkup.new
179
+ end
180
+
181
+ def test_element_gt
182
+ @xml.title('1<2')
183
+ assert_equal '<title>1&lt;2</title>', @xml.target!
184
+ end
185
+
186
+ def test_element_amp
187
+ @xml.title('AT&T')
188
+ assert_equal '<title>AT&amp;T</title>', @xml.target!
189
+ end
190
+
191
+ def test_element_amp2
192
+ @xml.title('&amp;')
193
+ assert_equal '<title>&amp;amp;</title>', @xml.target!
194
+ end
195
+
196
+ def test_attr_less
197
+ @xml.a(:title => '2>1')
198
+ assert_equal '<a title="2&gt;1"/>', @xml.target!
199
+ end
200
+
201
+ def test_attr_amp
202
+ @xml.a(:title => 'AT&T')
203
+ assert_equal '<a title="AT&amp;T"/>', @xml.target!
204
+ end
205
+
206
+ def test_attr_quot
207
+ @xml.a(:title => '"x"')
208
+ assert_equal '<a title="&quot;x&quot;"/>', @xml.target!
209
+ end
210
+
211
+ end
212
+
213
+ class TestNameSpaces < Test::Unit::TestCase
214
+ def setup
215
+ @xml = Builder::XmlMarkup.new(:indent=>2)
216
+ end
217
+
218
+ def test_simple_name_spaces
219
+ @xml.rdf :RDF
220
+ assert_equal "<rdf:RDF/>\n", @xml.target!
221
+ end
222
+
223
+ def test_long
224
+ xml = Builder::XmlMarkup.new(:indent=>2)
225
+ xml.instruct!
226
+ xml.rdf :RDF,
227
+ "xmlns:rdf" => :"&rdf;",
228
+ "xmlns:rdfs" => :"&rdfs;",
229
+ "xmlns:xsd" => :"&xsd;",
230
+ "xmlns:owl" => :"&owl;" do
231
+ xml.owl :Class, :'rdf:ID'=>'Bird' do
232
+ xml.rdfs :label, 'bird'
233
+ xml.rdfs :subClassOf do
234
+ xml.owl :Restriction do
235
+ xml.owl :onProperty, 'rdf:resource'=>'#wingspan'
236
+ xml.owl :maxCardinality,1,'rdf:datatype'=>'&xsd;nonNegativeInteger'
237
+ end
238
+ end
239
+ end
240
+ end
241
+ assert_match(/^<\?xml/, xml.target!)
242
+ assert_match(/\n<rdf:RDF/m, xml.target!)
243
+ assert_match(/xmlns:rdf="&rdf;"/m, xml.target!)
244
+ assert_match(/<owl:Restriction>/m, xml.target!)
245
+ end
246
+
247
+ def test_ensure
248
+ xml = Builder::XmlMarkup.new
249
+ xml.html do
250
+ xml.body do
251
+ begin
252
+ xml.p do
253
+ raise Exception.new('boom')
254
+ end
255
+ rescue Exception => e
256
+ xml.pre e
257
+ end
258
+ end
259
+ end
260
+ assert_match %r{<p>}, xml.target!
261
+ assert_match %r{</p>}, xml.target!
262
+ end
263
+ end
264
+
265
+ class TestDeclarations < Test::Unit::TestCase
266
+ def setup
267
+ @xml = Builder::XmlMarkup.new(:indent=>2)
268
+ end
269
+
270
+ def test_declare
271
+ @xml.declare! :element
272
+ assert_equal "<!element>\n", @xml.target!
273
+ end
274
+
275
+ def test_bare_arg
276
+ @xml.declare! :element, :arg
277
+ assert_equal"<!element arg>\n", @xml.target!
278
+ end
279
+
280
+ def test_string_arg
281
+ @xml.declare! :element, "string"
282
+ assert_equal"<!element \"string\">\n", @xml.target!
283
+ end
284
+
285
+ def test_mixed_args
286
+ @xml.declare! :element, :x, "y", :z, "-//OASIS//DTD DocBook XML//EN"
287
+ assert_equal "<!element x \"y\" z \"-//OASIS//DTD DocBook XML//EN\">\n", @xml.target!
288
+ end
289
+
290
+ def test_nested_declarations
291
+ @xml = Builder::XmlMarkup.new
292
+ @xml.declare! :DOCTYPE, :chapter do |x|
293
+ x.declare! :ELEMENT, :chapter, "(title,para+)".intern
294
+ end
295
+ assert_equal "<!DOCTYPE chapter [<!ELEMENT chapter (title,para+)>]>", @xml.target!
296
+ end
297
+
298
+ def test_nested_indented_declarations
299
+ @xml.declare! :DOCTYPE, :chapter do |x|
300
+ x.declare! :ELEMENT, :chapter, "(title,para+)".intern
301
+ end
302
+ assert_equal "<!DOCTYPE chapter [\n <!ELEMENT chapter (title,para+)>\n]>\n", @xml.target!
303
+ end
304
+
305
+ def test_complex_declaration
306
+ @xml.declare! :DOCTYPE, :chapter do |x|
307
+ x.declare! :ELEMENT, :chapter, "(title,para+)".intern
308
+ x.declare! :ELEMENT, :title, "(#PCDATA)".intern
309
+ x.declare! :ELEMENT, :para, "(#PCDATA)".intern
310
+ end
311
+ expected = %{<!DOCTYPE chapter [
312
+ <!ELEMENT chapter (title,para+)>
313
+ <!ELEMENT title (#PCDATA)>
314
+ <!ELEMENT para (#PCDATA)>
315
+ ]>
316
+ }
317
+ assert_equal expected, @xml.target!
318
+ end
319
+ end
320
+
321
+
322
+ class TestSpecialMarkup < Test::Unit::TestCase
323
+ def setup
324
+ @xml = Builder::XmlMarkup.new(:indent=>2)
325
+ end
326
+
327
+ def test_comment
328
+ @xml.comment!("COMMENT")
329
+ assert_equal "<!-- COMMENT -->\n", @xml.target!
330
+ end
331
+
332
+ def test_indented_comment
333
+ @xml.p { @xml.comment! "OK" }
334
+ assert_equal "<p>\n <!-- OK -->\n</p>\n", @xml.target!
335
+ end
336
+
337
+ def test_instruct
338
+ @xml.instruct! :abc, :version=>"0.9"
339
+ assert_equal "<?abc version=\"0.9\"?>\n", @xml.target!
340
+ end
341
+
342
+ def test_indented_instruct
343
+ @xml.p { @xml.instruct! :xml }
344
+ assert_match %r{<p>\n <\?xml version="1.0" encoding="UTF-8"\?>\n</p>\n},
345
+ @xml.target!
346
+ end
347
+
348
+ def test_instruct_without_attributes
349
+ @xml.instruct! :zz
350
+ assert_equal "<?zz?>\n", @xml.target!
351
+ end
352
+
353
+ def test_xml_instruct
354
+ @xml.instruct!
355
+ assert_match(/^<\?xml version="1.0" encoding="UTF-8"\?>$/, @xml.target!)
356
+ end
357
+
358
+ def test_xml_instruct_with_overrides
359
+ @xml.instruct! :xml, :encoding=>"UCS-2"
360
+ assert_match(/^<\?xml version="1.0" encoding="UCS-2"\?>$/, @xml.target!)
361
+ end
362
+
363
+ def test_xml_instruct_with_standalong
364
+ @xml.instruct! :xml, :encoding=>"UCS-2", :standalone=>"yes"
365
+ assert_match(/^<\?xml version="1.0" encoding="UCS-2" standalone="yes"\?>$/, @xml.target!)
366
+ end
367
+
368
+ def test_no_blocks
369
+ assert_raise(Builder::IllegalBlockError) do
370
+ @xml.instruct! { |x| x.hi }
371
+ end
372
+ assert_raise(Builder::IllegalBlockError) do
373
+ @xml.comment!(:element) { |x| x.hi }
374
+ end
375
+ end
376
+
377
+ def test_cdata
378
+ @xml.cdata!("TEST")
379
+ assert_equal "<![CDATA[TEST]]>\n", @xml.target!
380
+ end
381
+
382
+ def test_cdata_with_ampersand
383
+ @xml.cdata!("TEST&CHECK")
384
+ assert_equal "<![CDATA[TEST&CHECK]]>\n", @xml.target!
385
+ end
386
+
387
+ def test_cdata_with_included_close
388
+ @xml.cdata!("TEST]]>CHECK")
389
+ assert_equal "<![CDATA[TEST]]]]><![CDATA[>CHECK]]>\n", @xml.target!
390
+ end
391
+ end
392
+
393
+ class TestIndentedXmlMarkup < Test::Unit::TestCase
394
+ def setup
395
+ @xml = Builder::XmlMarkup.new(:indent=>2)
396
+ end
397
+
398
+ def test_one_level
399
+ @xml.ol { |x| x.li "text" }
400
+ assert_equal "<ol>\n <li>text</li>\n</ol>\n", @xml.target!
401
+ end
402
+
403
+ def test_two_levels
404
+ @xml.p { |x|
405
+ x.ol { x.li "text" }
406
+ x.br
407
+ }
408
+ assert_equal "<p>\n <ol>\n <li>text</li>\n </ol>\n <br/>\n</p>\n", @xml.target!
409
+ end
410
+
411
+ def test_initial_level
412
+ @xml = Builder::XmlMarkup.new(:indent=>2, :margin=>4)
413
+ @xml.name { |x| x.first("Jim") }
414
+ assert_equal " <name>\n <first>Jim</first>\n </name>\n", @xml.target!
415
+ end
416
+
417
+ class TestUtfMarkup < Test::Unit::TestCase
418
+ if ! String.method_defined?(:encode)
419
+ def setup
420
+ @old_kcode = $KCODE
421
+ end
422
+
423
+ def teardown
424
+ $KCODE = @old_kcode
425
+ end
426
+
427
+ def test_use_entities_if_no_encoding_is_given_and_kcode_is_none
428
+ $KCODE = 'NONE'
429
+ xml = Builder::XmlMarkup.new
430
+ xml.p("\xE2\x80\x99")
431
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
432
+ end
433
+
434
+ def test_use_entities_if_encoding_is_utf_but_kcode_is_not
435
+ $KCODE = 'NONE'
436
+ xml = Builder::XmlMarkup.new
437
+ xml.instruct!(:xml, :encoding => 'UTF-8')
438
+ xml.p("\xE2\x80\x99")
439
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
440
+ end
441
+ else
442
+ # change in behavior. As there is no $KCODE anymore, the default
443
+ # moves from "does not understand utf-8" to "supports utf-8".
444
+
445
+ def test_use_entities_if_no_encoding_is_given_and_kcode_is_none
446
+ xml = Builder::XmlMarkup.new
447
+ xml.p("\xE2\x80\x99")
448
+ assert_match("<p>\u2019</p>", xml.target!) #
449
+ end
450
+
451
+ def test_use_entities_if_encoding_is_utf_but_kcode_is_not
452
+ xml = Builder::XmlMarkup.new
453
+ xml.instruct!(:xml, :encoding => 'UTF-8')
454
+ xml.p("\xE2\x80\x99")
455
+ assert_match("<p>\u2019</p>", xml.target!) #
456
+ end
457
+ end
458
+
459
+ def encode string, encoding
460
+ if !String.method_defined?(:encode)
461
+ $KCODE = encoding
462
+ string
463
+ elsif encoding == 'UTF8'
464
+ string.force_encoding('UTF-8')
465
+ else
466
+ string
467
+ end
468
+ end
469
+
470
+ def test_use_entities_if_kcode_is_utf_but_encoding_is_dummy_encoding
471
+ xml = Builder::XmlMarkup.new
472
+ xml.instruct!(:xml, :encoding => 'UTF-16')
473
+ xml.p(encode("\xE2\x80\x99", 'UTF8'))
474
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
475
+ end
476
+
477
+ def test_use_entities_if_kcode_is_utf_but_encoding_is_unsupported_encoding
478
+ xml = Builder::XmlMarkup.new
479
+ xml.instruct!(:xml, :encoding => 'UCS-2')
480
+ xml.p(encode("\xE2\x80\x99", 'UTF8'))
481
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
482
+ end
483
+
484
+ def test_use_utf8_if_encoding_defaults_and_kcode_is_utf8
485
+ xml = Builder::XmlMarkup.new
486
+ xml.p(encode("\xE2\x80\x99",'UTF8'))
487
+ assert_equal encode("<p>\xE2\x80\x99</p>",'UTF8'), xml.target!
488
+ end
489
+
490
+ def test_use_utf8_if_both_encoding_and_kcode_are_utf8
491
+ xml = Builder::XmlMarkup.new
492
+ xml.instruct!(:xml, :encoding => 'UTF-8')
493
+ xml.p(encode("\xE2\x80\x99",'UTF8'))
494
+ assert_match encode("<p>\xE2\x80\x99</p>",'UTF8'), xml.target!
495
+ end
496
+
497
+ def test_use_utf8_if_both_encoding_and_kcode_are_utf8_with_lowercase
498
+ xml = Builder::XmlMarkup.new
499
+ xml.instruct!(:xml, :encoding => 'utf-8')
500
+ xml.p(encode("\xE2\x80\x99",'UTF8'))
501
+ assert_match encode("<p>\xE2\x80\x99</p>",'UTF8'), xml.target!
502
+ end
503
+ end
504
+
505
+ class TestXmlEvents < Test::Unit::TestCase
506
+ def setup
507
+ @handler = EventHandler.new
508
+ @xe = Builder::XmlEvents.new(:target=>@handler)
509
+ end
510
+
511
+ def test_simple
512
+ @xe.p
513
+ assert_equal [:start, :p, nil], @handler.events.shift
514
+ assert_equal [:end, :p], @handler.events.shift
515
+ end
516
+
517
+ def test_text
518
+ @xe.p("HI")
519
+ assert_equal [:start, :p, nil], @handler.events.shift
520
+ assert_equal [:text, "HI"], @handler.events.shift
521
+ assert_equal [:end, :p], @handler.events.shift
522
+ end
523
+
524
+ def test_attributes
525
+ @xe.p("id"=>"2")
526
+ ev = @handler.events.shift
527
+ assert_equal [:start, :p], ev[0,2]
528
+ assert_equal "2", ev[2]['id']
529
+ assert_equal [:end, :p], @handler.events.shift
530
+ end
531
+
532
+ def test_indented
533
+ @xml = Builder::XmlEvents.new(:indent=>2, :target=>@handler)
534
+ @xml.p { |x| x.b("HI") }
535
+ assert_equal [:start, :p, nil], @handler.events.shift
536
+ assert_equal "\n ", pop_text
537
+ assert_equal [:start, :b, nil], @handler.events.shift
538
+ assert_equal "HI", pop_text
539
+ assert_equal [:end, :b], @handler.events.shift
540
+ assert_equal "\n", pop_text
541
+ assert_equal [:end, :p], @handler.events.shift
542
+ end
543
+
544
+ def pop_text
545
+ result = ''
546
+ while ! @handler.events.empty? && @handler.events[0][0] == :text
547
+ result << @handler.events[0][1]
548
+ @handler.events.shift
549
+ end
550
+ result
551
+ end
552
+
553
+ class EventHandler
554
+ attr_reader :events
555
+ def initialize
556
+ @events = []
557
+ end
558
+
559
+ def start_tag(sym, attrs)
560
+ @events << [:start, sym, attrs]
561
+ end
562
+
563
+ def end_tag(sym)
564
+ @events << [:end, sym]
565
+ end
566
+
567
+ def text(txt)
568
+ @events << [:text, txt]
569
+ end
570
+ end
571
+ end
572
+
573
+ end