blankslate 2.1.2.4 → 3.1.2

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,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