sdl4r 0.9.9 → 0.9.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG +70 -1
  2. data/LICENSE +499 -497
  3. data/Rakefile +38 -28
  4. data/TODO +194 -45
  5. data/doc/classes/SDL4R/AbbreviationTimezoneProxy.html +151 -0
  6. data/doc/classes/SDL4R/ConstantTimezone.html +129 -0
  7. data/doc/classes/SDL4R/Element.html +148 -0
  8. data/doc/classes/SDL4R/Reader.html +683 -0
  9. data/doc/classes/SDL4R/RelativeTimezone.html +187 -0
  10. data/doc/classes/SDL4R/SdlBinary.html +188 -0
  11. data/doc/classes/SDL4R/SdlParseError.html +110 -0
  12. data/doc/classes/SDL4R/SdlTimeSpan.html +651 -0
  13. data/doc/classes/SDL4R/Serializer.html +557 -0
  14. data/doc/classes/SDL4R/Serializer/Ref.html +138 -0
  15. data/doc/classes/SDL4R/TZAbbreviationDB/Record.html +117 -0
  16. data/doc/classes/SDL4R/Tag.html +1274 -0
  17. data/doc/classes/SDL4R/Token.html +131 -0
  18. data/doc/created.rid +1 -0
  19. data/doc/files/CHANGELOG.html +290 -0
  20. data/doc/files/LICENSE.html +53 -0
  21. data/doc/files/README.html +405 -0
  22. data/doc/files/lib/sdl4r/abbreviation_timezone_proxy_rb.html +63 -0
  23. data/doc/files/lib/sdl4r/constant_timezone_rb.html +54 -0
  24. data/doc/files/lib/sdl4r/element_rb.html +54 -0
  25. data/doc/files/lib/sdl4r/reader_rb.html +68 -0
  26. data/doc/files/lib/sdl4r/relative_timezone_rb.html +62 -0
  27. data/doc/files/lib/sdl4r/sdl4r_rb.html +66 -0
  28. data/doc/files/lib/sdl4r/sdl4r_tzinfo_rb.html +64 -0
  29. data/doc/files/lib/sdl4r/sdl4r_version_rb.html +54 -0
  30. data/doc/files/lib/sdl4r/sdl_binary_rb.html +54 -0
  31. data/doc/files/lib/sdl4r/sdl_parse_error_rb.html +54 -0
  32. data/doc/files/lib/sdl4r/sdl_time_span_rb.html +54 -0
  33. data/doc/files/lib/sdl4r/serializer_rb.html +62 -0
  34. data/doc/files/lib/sdl4r/tag_rb.html +66 -0
  35. data/doc/files/lib/sdl4r/token_rb.html +54 -0
  36. data/doc/files/lib/sdl4r/tokenizer_rb.html +64 -0
  37. data/doc/files/lib/sdl4r/tz_abbreviation_db_rb.html +67 -0
  38. data/doc/files/lib/sdl4r_rb.html +54 -0
  39. data/doc/files/lib/sdl4r_tzinfo_rb.html +54 -0
  40. data/doc/fr_class_index.html +23 -0
  41. data/doc/fr_file_index.html +40 -0
  42. data/doc/fr_method_index.html +4711 -0
  43. data/doc/index.html +15 -0
  44. data/doc/rdoc-style.css +328 -0
  45. data/lib/sdl4r.rb +3 -1
  46. data/lib/sdl4r/abbreviation_timezone_proxy.rb +38 -0
  47. data/lib/sdl4r/constant_timezone.rb +58 -0
  48. data/{test/sdl4r/sdl_test.rb → lib/sdl4r/element.rb} +19 -14
  49. data/lib/sdl4r/reader.rb +772 -0
  50. data/lib/sdl4r/relative_timezone.rb +156 -0
  51. data/lib/sdl4r/sdl4r.rb +187 -45
  52. data/lib/sdl4r/sdl4r_tzinfo.rb +75 -0
  53. data/lib/sdl4r/sdl4r_version.rb +24 -0
  54. data/lib/sdl4r/sdl_parse_error.rb +1 -1
  55. data/lib/sdl4r/sdl_time_span.rb +5 -1
  56. data/lib/sdl4r/serializer.rb +473 -60
  57. data/lib/sdl4r/tag.rb +126 -51
  58. data/lib/sdl4r/token.rb +49 -0
  59. data/lib/sdl4r/tokenizer.rb +431 -0
  60. data/lib/sdl4r/tz_abbreviation_db.rb +266 -0
  61. data/read_jprof.html +16934 -0
  62. data/read_jprof_pull.html +14451 -0
  63. data/read_prof.html +4983 -0
  64. data/read_prof_pull.html +4896 -0
  65. data/test/sdl4r/parser_test.rb +577 -503
  66. data/test/sdl4r/read_jprof.rb +58 -0
  67. data/test/sdl4r/read_prof.rb +70 -0
  68. data/test/sdl4r/reader_test.rb +173 -0
  69. data/test/sdl4r/relative_timezone_test.rb +102 -0
  70. data/test/sdl4r/sdl4r_test.rb +611 -528
  71. data/test/sdl4r/sdl4r_tzinfo_test.rb +108 -0
  72. data/test/sdl4r/sdl_test_case.rb +60 -0
  73. data/test/sdl4r/serializer_test.rb +448 -11
  74. data/test/sdl4r/tag_test.rb +84 -5
  75. data/test/sdl4r/tokenizer_test.rb +128 -0
  76. metadata +69 -11
  77. data/lib/sdl4r/parser.rb +0 -648
  78. data/lib/sdl4r/parser/reader.rb +0 -184
  79. data/lib/sdl4r/parser/time_span_with_zone.rb +0 -57
  80. data/lib/sdl4r/parser/token.rb +0 -138
  81. data/lib/sdl4r/parser/tokenizer.rb +0 -507
@@ -1,504 +1,578 @@
1
- #!/usr/bin/env ruby -w
2
- # encoding: UTF-8
3
-
4
- #--
5
- # Simple Declarative Language (SDL) for Ruby
6
- # Copyright 2005 Ikayzo, inc.
7
- #
8
- # This program is free software. You can distribute or modify it under the
9
- # terms of the GNU Lesser General Public License version 2.1 as published by
10
- # the Free Software Foundation.
11
- #
12
- # This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
13
- # INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
14
- # See the GNU Lesser General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU Lesser General Public License
17
- # along with this program; if not, contact the Free Software Foundation, Inc.,
18
- # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
- #++
20
-
21
- # Work-around a bug in NetBeans (http://netbeans.org/bugzilla/show_bug.cgi?id=188653)
22
- # $:[0] = File.join(File.dirname(__FILE__),'../../lib') if ENV["NB_EXEC_EXTEXECUTION_PROCESS_UUID"]
23
-
24
- module SDL4R
25
-
26
- require 'bigdecimal'
27
- require 'test/unit'
28
-
29
- require "sdl4r/tag"
30
-
31
- class ParserTest < Test::Unit::TestCase
32
-
33
- @@zone_offset = Rational(Time.now.utc_offset, 24 * 60 * 60)
34
-
35
-
36
- public
37
-
38
- def test_empty
39
- root = Tag.new("root")
40
- root.read("")
41
- root.children(false) { fail("no child expected") }
42
- end
43
-
44
- def test_one_tag_alone
45
- # Tag without namespace
46
- tag1 = parse_one_tag1("tag1")
47
- assert_equal("tag1", tag1.name, "name" )
48
- assert_equal("", tag1.namespace, "namespace" )
49
-
50
- assert_equal(0, tag1.values.size, "values")
51
- assert_equal(0, tag1.attributes.size, "attributes")
52
-
53
- # Tag with namespace
54
- tag1 = parse_one_tag1("ns1:tag1")
55
- assert_equal("tag1", tag1.name, "name" )
56
- assert_equal("ns1", tag1.namespace, "namespace" )
57
- end
58
-
59
- def test_tag_with_one_value
60
- tag1 = parse_one_tag1("tag1 1")
61
- assert_not_nil(tag1, "tag1")
62
- assert_equal(1, tag1.value, "value")
63
- end
64
-
65
- def test_tag_with_two_values
66
- tag1 = parse_one_tag1("tag1 1 \"abc\"")
67
- assert_not_nil(tag1, "tag1")
68
- values = tag1.values
69
- assert_equal(1, values[0], "1st value")
70
- assert_equal("abc", values[1], "2nd value")
71
- end
72
-
73
- def test_tag_with_double_quote_string_values
74
- tag1 = parse_one_tag1("tag1 \"abc\" \"d\\\ne\\\nf\" \"g\\\n \t hi\"")
75
- assert_not_nil(tag1, "tag1")
76
- values = tag1.values
77
- assert_equal("abc", values[0], "values[0]")
78
- assert_equal("def", values[1], "values[1]")
79
- assert_equal("ghi", values[2], "values[2]")
80
- end
81
-
82
- def test_tag_with_back_quote_string_values
83
- tag1 = parse_one_tag1(
84
- "tag1 `abc` \"d`e`f\" `g\"h\"i` `j\\k+l` `m\\\nn\\\r\n \t o\r`")
85
- assert_not_nil(tag1, "tag1")
86
- values = tag1.values
87
- assert_equal("abc", values[0], "values[0]")
88
- assert_equal("d`e`f", values[1], "values[1]")
89
- assert_equal("g\"h\"i", values[2], "values[2]")
90
- assert_equal("j\\k+l", values[3], "values[3]")
91
- assert_equal("m\\\nn\\\n \t o\r", values[4], "values[4]")
92
- end
93
-
94
- def test_tag_with_base64_values
95
- tag1 = parse_one_tag1(
96
- <<EOS
97
- tag1 [V2VsY29tZSB0byB0aGUgY3J1ZWwgd29ybGQu] [
98
- SG9wZSB5
99
- b3UnbGwg
100
- ZmluZCB5
101
- b3VyIHdh
102
- eS4=
103
- ]
104
- EOS
105
- )
106
- assert_not_nil(tag1, "tag1")
107
- values = tag1.values
108
- assert_equal(SDL4R::SdlBinary("Welcome to the cruel world."), values[0], "values[0]")
109
- assert_equal(SDL4R::SdlBinary("Hope you'll find your way."), values[1], "values[1]")
110
- end
111
-
112
- def test_tag_with_one_attribute
113
- tag1 = parse_one_tag1("tag1 attr1=99")
114
- assert_not_nil(tag1, "tag1")
115
-
116
- values = tag1.values
117
- assert(values.empty?, "value count")
118
-
119
- attributes = tag1.attributes
120
- assert_equal(1, attributes.size, "attribute count")
121
- assert_equal(99, attributes["attr1"], "attr1")
122
-
123
- # check the parsing with line continuations
124
- tag1 = parse_one_tag1("tag1\\\nattr1=\\\n99")
125
- assert_not_nil(tag1, "tag1")
126
- assert_equal(99, tag1.attribute("attr1"), "attr1")
127
- end
128
-
129
- def test_tag_with_attributes
130
- tag1 = parse_one_tag1(
131
- "tag1 attr1=\"99\" ns:attr2=[QmVhdXR5IGlzIG5vdCBlbm91Z2gu]")
132
- assert_not_nil(tag1, "tag1")
133
-
134
- attributes = tag1.attributes
135
- assert_equal(2, attributes.size, "attribute count")
136
- assert_equal("99", attributes["attr1"], "attr1")
137
- assert_equal(SDL4R::SdlBinary("Beauty is not enough."), attributes["ns:attr2"], "attr2")
138
- end
139
-
140
- def test_date
141
- tag1 = parse_one_tag1("tag1 2005/12/05")
142
- date = tag1.value
143
- assert_equal(Date.civil(2005, 12, 5), date, "date value")
144
-
145
- # check negative years
146
- tag1 = parse_one_tag1("tag1 -145/12/23");
147
- date = tag1.value
148
- assert_equal(Date.civil(-145, 12, 23), date, "negative year")
149
- end
150
-
151
- def test_time
152
- tag1 = parse_one_tag1(
153
- "tag1 time=12:23:56 short_time=00:12:32.423" +
154
- " long_time=30d:15:23:04.023 before=-00:02:30")
155
- assert_equal(
156
- SdlTimeSpan.new(0, 12, 23, 56),
157
- tag1.attribute("time"),
158
- "time");
159
- assert_equal(
160
- SdlTimeSpan.new(0, 0, 12, 32, 423),
161
- tag1.attribute("short_time"),
162
- "short_time");
163
- assert_equal(
164
- SdlTimeSpan.new(30, 15, 23, 4, 23),
165
- tag1.attribute("long_time"),
166
- "long_time");
167
- assert_equal(
168
- SdlTimeSpan.new(0, 0, -2, -30),
169
- tag1.attribute("before"),
170
- "before");
171
- end
172
-
173
- def test_date_time
174
- tag1 = parse_one_tag1(
175
- "tag1 date1=2008/06/01 12:34" +
176
- " date2=1999/12/31 23:59:58" +
177
- " date3=2000/05/01 12:01:35.997" +
178
- " date4=2015/12/05 14:12:23.345-JST" +
179
- " date5=1414/05/12 03:00:01.107-UTC-04" +
180
- " date6=1807/11/11 22:28:13.888-GMT-08:30")
181
- assert_equal(
182
- local_civil_date(2008, 6, 1, 12, 34),
183
- tag1.attribute("date1"),
184
- "date1");
185
- assert_equal(
186
- local_civil_date(1999, 12, 31, 23, 59, 58),
187
- tag1.attribute("date2"),
188
- "date2");
189
- assert_equal(
190
- local_civil_date(2000, 5, 1, 12, 1, Rational(35997, 1000)),
191
- tag1.attribute("date3"),
192
- "date3");
193
- assert_equal(
194
- local_civil_date(2015, 12, 5, 14, 12, Rational(23345, 1000), Rational(9, 24)),
195
- tag1.attribute("date4"),
196
- "date4");
197
- assert_equal(
198
- local_civil_date(1414, 5, 12, 3, 0, Rational(1107, 1000), Rational(-4, 24)),
199
- tag1.attribute("date5"),
200
- "date5");
201
- assert_equal(
202
- local_civil_date(1807, 11, 11, 22, 28, Rational(13888, 1000), Rational(-85, 240)),
203
- tag1.attribute("date6"),
204
- "date6");
205
-
206
- tag1 = parse_one_tag1("tag1 2008/06/01 5d:12:34") # not a datetime: a date + a timespan
207
- assert_equal Date.civil(2008, 6, 1), tag1.values[0]
208
- assert_equal SdlTimeSpan.new(5, 12, 34), tag1.values[1]
209
- end
210
-
211
- def test_numbers
212
- tag1 = parse_one_tag1(
213
- "tag1 123 3000000000 456l 789L 123.45f 67.8F 910.11 12.13d 1415.16D 171.8BD 1.920bd 12345678901234567890BD")
214
- values = tag1.values
215
- assert_equal(123, values[0])
216
- assert_equal(3000000000, values[1])
217
- assert_equal(456, values[2])
218
- assert_equal(789, values[3])
219
- assert_equal(123.45, values[4])
220
- assert_equal(67.8, values[5])
221
- assert_equal(910.11, values[6])
222
- assert_equal(12.13, values[7])
223
- assert_equal(1415.16, values[8])
224
- assert_equal(BigDecimal("171.8"), values[9])
225
- assert_equal(BigDecimal("1.920"), values[10])
226
- assert_equal(BigDecimal("12345678901234567890"), values[11])
227
-
228
- assert_raise SdlParseError do
229
- parse_one_tag1("tag1 123.2.2")
230
- end
231
- assert_raise SdlParseError do
232
- parse_one_tag1("tag1 123.2e")
233
- end
234
- assert_raise SdlParseError do
235
- parse_one_tag1("tag1 +-123.2")
236
- end
237
- end
238
-
239
- def test_booleans
240
- tag1 = parse_one_tag1("tag1 b1=true b2=false b3=on b4=off")
241
- assert_equal(true, tag1.attribute("b1"))
242
- assert_equal(false, tag1.attribute("b2"))
243
- assert_equal(true, tag1.attribute("b3"))
244
- assert_equal(false, tag1.attribute("b4"))
245
- end
246
-
247
- def test_null
248
- tag1 = parse_one_tag1("tag1 null attr1=null")
249
- values = tag1.values
250
- assert_equal(1, values.size)
251
- assert_equal(nil, values[0])
252
- assert_equal(nil, tag1.attribute("attr1"))
253
- assert(tag1.has_attribute?("attr1"))
254
- end
255
-
256
- def test_comments
257
- root = Tag.new("root")
258
- root.read(
259
- <<EOS
260
- tag1 123
261
- #tag2 456
262
- tag3 789
263
- --tag4 012
264
- tag5 345
265
- //tag6 678
266
- tag7 901
267
- /*tag8 234
268
- tag9 567*/
269
- tag10 890
270
- EOS
271
- )
272
- children = root.children
273
- assert_equal(5, children.size, "children count")
274
- assert_equal(123, root.child("tag1").value)
275
- assert_nil(root.child("tag2"))
276
- assert_equal(789, root.child("tag3").value)
277
- assert_nil(root.child("tag4"))
278
- assert_equal(345, root.child("tag5").value)
279
- assert_nil(root.child("tag6"))
280
- assert_equal(901, root.child("tag7").value)
281
- assert_nil(root.child("tag8"))
282
- assert_nil(root.child("tag9"))
283
- assert_equal(890, root.child("tag10").value)
284
- end
285
-
286
- def test_double_quote_strings
287
- root = SDL4R::read(
288
- <<EOS
289
- tag1 "cheese and cherry jam"
290
- tag2 "cheese and \\
291
- cherry jam"
292
- tag3 "cheese \\
293
- and \\
294
- cherry jam"
295
- tag4 "Did you say this soup was \\"good\\"?"
296
- tag5 "Even my dog wouldn't\\thave\\tit!"
297
- tag6 "\\"\\t\\r\\n\\\\"
298
- tag7 equation="is not x=y*z" color="blue \\
299
- and yellow"
300
- EOS
301
- )
302
-
303
- assert_equal "cheese and cherry jam", root.child("tag1").value, "double-quote string"
304
- assert_equal(
305
- "cheese and cherry jam", root.child("tag2").value, "continued double-quote string")
306
- assert_equal(
307
- "cheese and cherry jam", root.child("tag3").value, "continued double-quote string")
308
- assert_equal(
309
- 'Did you say this soup was "good"?', root.child("tag4").value, "escaped quotes")
310
- assert_equal(
311
- "Even my dog wouldn't\thave\tit!", root.child("tag5").value, "escaped tabs")
312
- assert_equal "\"\t\r\n\\", root.child("tag6").value, "escaped white spaces"
313
- assert_equal "is not x=y*z", root.child("tag7").attribute("equation")
314
- assert_equal "blue and yellow", root.child("tag7").attribute("color")
315
- end
316
-
317
- def test_characters
318
- root = SDL4R::read "tag1 ' ' 'a' '\\\\' '\\t' '\\n' '\\r'"
319
- assert_equal [" ", "a", "\\", "\t", "\n", "\r"], root.child("tag1").values
320
-
321
- assert_raise SdlParseError do
322
- SDL4R::read "tag1 '"
323
- end
324
- assert_raise SdlParseError do
325
- SDL4R::read "tag1 'a"
326
- end
327
- assert_raise SdlParseError do
328
- SDL4R::read "tag1 'abc'"
329
- end
330
- assert_raise SdlParseError do
331
- SDL4R::read "tag1 ''"
332
- end
333
- assert_raise SdlParseError do
334
- SDL4R::read "tag1 '\\'"
335
- end
336
- assert_raise SdlParseError do
337
- SDL4R::read "tag1 '\\"
338
- end
339
- end
340
-
341
- def test_backquote_strings
342
- root = SDL4R::read <<EOS
343
- winfile `c:\\directory\\myfile.xls`
344
- talk `I said "something"`
345
- xml `
346
- <product>
347
- <shoes color="blue"/>
348
- </product>
349
- `
350
- regex `\\w+\\.suite\\(\\)`
351
- EOS
352
-
353
- assert_equal "c:\\directory\\myfile.xls", root.child("winfile").value
354
- assert_equal 'I said "something"', root.child("talk").value
355
- assert_equal(
356
- "\n<product>\n <shoes color=\"blue\"/>\n</product>\n", root.child("xml").value)
357
- assert_equal "\\w+\\.suite\\(\\)", root.child("regex").value
358
- end
359
-
360
- def test_sub_tags
361
- root = SDL4R::read <<EOS
362
- wax {
363
- }
364
- steack {
365
- bees {
366
- monopoly {
367
- }
368
- }
369
- goat_cheese
370
- truck {
371
- cathedral
372
- }
373
- }
374
- peanut.butter
375
- EOS
376
-
377
- expected = Tag.new("root") do
378
- new_child("wax")
379
- new_child("steack") do
380
- new_child("bees") do
381
- new_child("monopoly")
382
- end
383
- new_child("goat_cheese")
384
- new_child("truck") do
385
- new_child("cathedral")
386
- end
387
- end
388
- new_child("peanut.butter")
389
- end
390
-
391
- assert_equal expected, root
392
- end
393
-
394
- def test_identifiers
395
- root = SDL4R::read("my_ns:my_tag my_ns2:my_attr=-13.8")
396
- assert_equal "my_ns", root.child.namespace
397
- assert_equal "my_tag", root.child.name
398
- assert_equal({ "my_ns2:my_attr" => -13.8 }, root.child.attributes)
399
-
400
- root = SDL4R::read("_my_ns:_my_tag _my_ns2:_my_attr=-13.8")
401
- assert_equal "_my_ns", root.child.namespace
402
- assert_equal "_my_tag", root.child.name
403
- assert_equal({ "_my_ns2:_my_attr" => -13.8 }, root.child.attributes)
404
-
405
- root = SDL4R::read("my.ns:my.tag my.ns2:my.attr=-13.8")
406
- assert_equal "my.ns", root.child.namespace
407
- assert_equal "my.tag", root.child.name
408
- assert_equal({ "my.ns2:my.attr" => -13.8 }, root.child.attributes)
409
-
410
- root = SDL4R::read("my$ns:my$tag my$ns2:my$attr=-13.8")
411
- assert_equal "my$ns", root.child.namespace
412
- assert_equal "my$tag", root.child.name
413
- assert_equal({ "my$ns2:my$attr" => -13.8 }, root.child.attributes)
414
- end
415
-
416
- def test_empty_block
417
- tag1 = parse_one_tag1("tag1 {\n}")
418
- assert_equal [], tag1.values
419
- assert_equal({}, tag1.attributes)
420
- assert_equal [], tag1.children
421
-
422
- # tag1 = parse_one_tag1("tag1 {}")
423
- # assert_equal [], tag1.values
424
- # assert_equal({}, tag1.attributes)
425
- # assert_equal [], tag1.children
426
- end
427
-
428
- def test_parse_error
429
- # WARNING: the line and col of an error is not accurate science. The goal here is to point to
430
- # coordinates that are useful to the user.
431
- # Exampe for a string litteral that spans over several line, some errors could be point to
432
- # the start or to the end without too much ambiguity.
433
- # Consequently, feel free to change the coordinates, if a change in the implementation
434
- # modifies the x/y of the error and they still make sense.
435
- assert_error_xy "=", 1, 1
436
- assert_error_xy "tag1 xyz", 1, 6
437
- assert_error_xy "tag1 \\\nxyz", 2, 1
438
- assert_error_xy "tag1 \\\n xyz", 2, 4
439
-
440
- source = <<EOS
441
- -- my comment
442
- =
443
- EOS
444
- assert_error_xy source, 2, 1
445
-
446
- source = <<EOS
447
- murder_plot 123 \\
448
- weight=456 \\
449
- * \\
450
- length=789
451
- EOS
452
- assert_error_xy source, 3, 6
453
-
454
- assert_error_xy 'tag1 "text\\"', 1, 13
455
-
456
- source = <<EOS
457
- murder_plot "abcd\\
458
- efghij\\
459
- kl\\
460
- mnopq
461
- EOS
462
- assert_error_xy source, 4, 13
463
- end
464
-
465
- private
466
-
467
- def assert_error_xy source, expected_line, expected_pos
468
- error = get_parse_error_or_fail source
469
- begin
470
- assert_equal expected_line, error.line, "line"
471
- assert_equal expected_pos, error.position, "position"
472
- rescue
473
- puts "Expected error: #{error}"
474
- puts error.backtrace
475
- raise $!
476
- end
477
- end
478
-
479
- def get_parse_error_or_fail source
480
- begin
481
- SDL4R::read source
482
-
483
- rescue
484
- return $! if $!.is_a? SdlParseError
485
- raise AssertionFailedError, "was expecting a SdlParseError"
486
- end
487
- end
488
-
489
- # Creates and returns a DateTime where an unspecified +zone_offset+ means 'the local zone
490
- # offset' (contrarily to DateTime#civil())
491
- def local_civil_date(year, month, day, hour = 0, min = 0, sec = 0, zone_offset = nil)
492
- zone_offset ||= @@zone_offset
493
- return DateTime.civil(year, month, day, hour, min, sec, zone_offset)
494
- end
495
-
496
- def parse_one_tag1(text)
497
- root = SDL4R::read(text)
498
- tag1 = root.child("tag1")
499
- assert_not_nil(tag1, "tag1")
500
- assert_equal 1, root.child_count, "only 1 tag expected"
501
- return tag1
502
- end
503
- end
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # Simple Declarative Language (SDL) for Ruby
6
+ # Copyright 2005 Ikayzo, inc.
7
+ #
8
+ # This program is free software. You can distribute or modify it under the
9
+ # terms of the GNU Lesser General Public License version 2.1 as published by
10
+ # the Free Software Foundation.
11
+ #
12
+ # This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
13
+ # INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
14
+ # See the GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, contact the Free Software Foundation, Inc.,
18
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
+ #++
20
+
21
+ # Work-around a bug in NetBeans (http://netbeans.org/bugzilla/show_bug.cgi?id=188653)
22
+ if ENV["NB_EXEC_EXTEXECUTION_PROCESS_UUID"]
23
+ $:[0] = File.join(File.dirname(__FILE__),'../../lib')
24
+ $:.unshift(File.join(File.dirname(__FILE__),'../../test'))
25
+ end
26
+
27
+ if RUBY_VERSION < '1.9.0'
28
+ $KCODE = 'u'
29
+ require 'jcode'
30
+ end
31
+
32
+ module SDL4R
33
+
34
+ require 'rubygems'
35
+ require 'bigdecimal'
36
+ require 'test/unit'
37
+
38
+ require "sdl4r/tag"
39
+
40
+ require 'sdl4r/sdl_test_case'
41
+
42
+ class ParserTest < Test::Unit::TestCase
43
+ include SdlTestCase
44
+
45
+ def test_empty
46
+ root = Tag.new("root")
47
+ root.read("")
48
+ root.children(false) { fail("no child expected") }
49
+ end
50
+
51
+ def test_one_tag_alone
52
+ # Tag without namespace
53
+ tag1 = parse_one_tag1("tag1")
54
+ assert_equal("tag1", tag1.name, "name" )
55
+ assert_equal("", tag1.namespace, "namespace" )
56
+
57
+ assert_equal(0, tag1.values.size, "values")
58
+ assert_equal(0, tag1.attributes.size, "attributes")
59
+
60
+ # Tag with namespace
61
+ tag1 = SDL4R::read("ns1:tag1").child("ns1", "tag1")
62
+ assert_equal("tag1", tag1.name, "name" )
63
+ assert_equal("ns1", tag1.namespace, "namespace" )
64
+ end
65
+
66
+ def test_tag_with_one_value
67
+ tag1 = parse_one_tag1("tag1 1")
68
+ assert_not_nil(tag1, "tag1")
69
+ assert_equal(1, tag1.value, "value")
70
+ end
71
+
72
+ def test_tag_with_two_values
73
+ tag1 = parse_one_tag1("tag1 1 \"abc\"")
74
+ assert_not_nil(tag1, "tag1")
75
+ values = tag1.values
76
+ assert_equal(1, values[0], "1st value")
77
+ assert_equal("abc", values[1], "2nd value")
78
+ end
79
+
80
+ def test_tag_with_double_quote_string_values
81
+ tag1 = parse_one_tag1("tag1 \"abc\" \"d\\\ne\\\nf\" \"g\\\n \t hi\"")
82
+ assert_not_nil(tag1, "tag1")
83
+ values = tag1.values
84
+ assert_equal("abc", values[0], "values[0]")
85
+ assert_equal("def", values[1], "values[1]")
86
+ assert_equal("ghi", values[2], "values[2]")
87
+ end
88
+
89
+ def test_tag_with_back_quote_string_values
90
+ tag1 = parse_one_tag1(
91
+ "tag1 `abc` \"d`e`f\" `g\"h\"i` `j\\k+l` `m\\\nn\\\r\n \t o\r`")
92
+ assert_not_nil(tag1, "tag1")
93
+ values = tag1.values
94
+ assert_equal("abc", values[0], "values[0]")
95
+ assert_equal("d`e`f", values[1], "values[1]")
96
+ assert_equal("g\"h\"i", values[2], "values[2]")
97
+ assert_equal("j\\k+l", values[3], "values[3]")
98
+ assert_equal("m\\\nn\\\n \t o\r", values[4], "values[4]")
99
+ end
100
+
101
+ def test_tag_with_base64_values
102
+ tag1 = parse_one_tag1(
103
+ <<EOS
104
+ tag1 [V2VsY29tZSB0byB0aGUgY3J1ZWwgd29ybGQu] [
105
+ SG9wZSB5
106
+ b3UnbGwg
107
+ ZmluZCB5
108
+ b3VyIHdh
109
+ eS4=
110
+ ]
111
+ EOS
112
+ )
113
+ assert_not_nil(tag1, "tag1")
114
+ values = tag1.values
115
+ assert_equal(SDL4R::SdlBinary("Welcome to the cruel world."), values[0], "values[0]")
116
+ assert_equal(SDL4R::SdlBinary("Hope you'll find your way."), values[1], "values[1]")
117
+ end
118
+
119
+ def test_tag_with_one_attribute
120
+ tag1 = parse_one_tag1("tag1 attr1=99")
121
+ assert_not_nil(tag1, "tag1")
122
+
123
+ values = tag1.values
124
+ assert(values.empty?, "value count")
125
+
126
+ attributes = tag1.attributes
127
+ assert_equal(1, attributes.size, "attribute count")
128
+ assert_equal(99, attributes["attr1"], "attr1")
129
+
130
+ # check the parsing with line continuations
131
+ tag1 = parse_one_tag1("tag1\\\nattr1=\\\n99")
132
+ assert_not_nil(tag1, "tag1")
133
+ assert_equal(99, tag1.attribute("attr1"), "attr1")
134
+ end
135
+
136
+ def test_tag_with_attributes
137
+ tag1 = parse_one_tag1(
138
+ "tag1 attr1=\"99\" ns:attr2=[QmVhdXR5IGlzIG5vdCBlbm91Z2gu]")
139
+ assert_not_nil(tag1, "tag1")
140
+
141
+ attributes = tag1.attributes
142
+ assert_equal(2, attributes.size, "attribute count")
143
+ assert_equal("99", attributes["attr1"], "attr1")
144
+ assert_equal(SDL4R::SdlBinary("Beauty is not enough."), attributes["ns:attr2"], "attr2")
145
+ end
146
+
147
+ def test_date
148
+ tag1 = parse_one_tag1("tag1 2005/12/05")
149
+ date = tag1.value
150
+ assert_equal(Date.civil(2005, 12, 5), date, "date value")
151
+
152
+ # check negative years
153
+ tag1 = parse_one_tag1("tag1 -145/12/23");
154
+ date = tag1.value
155
+ assert_equal(Date.civil(-145, 12, 23), date, "negative year")
156
+ end
157
+
158
+ def test_time
159
+ tag1 = parse_one_tag1(
160
+ "tag1 time=12:23:56 short_time=00:12:32.423" +
161
+ " long_time=30d:15:23:04.023 before=-00:02:30")
162
+ assert_equal(
163
+ SdlTimeSpan.new(0, 12, 23, 56),
164
+ tag1.attribute("time"),
165
+ "time");
166
+ assert_equal(
167
+ SdlTimeSpan.new(0, 0, 12, 32, 423),
168
+ tag1.attribute("short_time"),
169
+ "short_time");
170
+ assert_equal(
171
+ SdlTimeSpan.new(30, 15, 23, 4, 23),
172
+ tag1.attribute("long_time"),
173
+ "long_time");
174
+ assert_equal(
175
+ SdlTimeSpan.new(0, 0, -2, -30),
176
+ tag1.attribute("before"),
177
+ "before");
178
+ end
179
+
180
+ def test_date_time
181
+ tag1 = parse_one_tag1(
182
+ "tag1 date1=2008/06/01 12:34" +
183
+ " date2=1999/12/31 23:59:58" +
184
+ " date3=2000/05/01 12:01:35.997" +
185
+ " date4=2015/12/05 14:12:23.345-JST" +
186
+ " date5=1414/05/12 03:00:01.107-UTC-04" +
187
+ " date6=1807/11/11 22:28:13.888-GMT-08:30")
188
+ assert_equal(
189
+ local_civil_date(2008, 6, 1, 12, 34),
190
+ tag1.attribute("date1"),
191
+ "date1");
192
+ assert_equal(
193
+ local_civil_date(1999, 12, 31, 23, 59, 58),
194
+ tag1.attribute("date2"),
195
+ "date2");
196
+ assert_equal_date_time(
197
+ local_civil_date(2000, 5, 1, 12, 1, Rational(35997, 1000)),
198
+ tag1.attribute("date3"),
199
+ "date3");
200
+ assert_equal(
201
+ local_civil_date(2015, 12, 5, 14, 12, Rational(23345, 1000), Rational(9, 24)),
202
+ tag1.attribute("date4"),
203
+ "date4");
204
+ assert_equal(
205
+ local_civil_date(1414, 5, 12, 3, 0, Rational(1107, 1000), Rational(-4, 24)),
206
+ tag1.attribute("date5"),
207
+ "date5");
208
+ assert_equal(
209
+ local_civil_date(1807, 11, 11, 22, 28, Rational(13888, 1000), Rational(-85, 240)),
210
+ tag1.attribute("date6"),
211
+ "date6");
212
+
213
+ tag1 = parse_one_tag1("tag1 2008/06/01 5d:12:34") # not a datetime: a date + a timespan
214
+ assert_equal Date.civil(2008, 6, 1), tag1.values[0]
215
+ assert_equal SdlTimeSpan.new(5, 12, 34), tag1.values[1]
216
+
217
+ # Check that the timezone is correct when and where day saving time is in use
218
+ # FIXME: neither DateTime/Date nor Time seem to handle zones and DST correctly.
219
+ # tag1 = parse_one_tag1("tag1 2001/01/01 12:00:00-CET") # winter time
220
+ # assert_equal(local_civil_date(2001, 01, 01, 12, 0, 0, Rational(1, 24)), tag1.value)
221
+ # tag1 = parse_one_tag1("tag1 2001/07/01 12:00:00-CET") # summer time
222
+ # assert_equal(local_civil_date(2001, 01, 01, 12, 0, 0, Rational(2, 24)), tag1.value)
223
+ end
224
+
225
+ def test_numbers
226
+ tag1 = parse_one_tag1(
227
+ "tag1 123 3000000000 456l 789L 123.45f 67.8F" +
228
+ " 910.11 12.13d 1415.16D 171.8BD 1.920bd 12345678901234567890BD -13.05")
229
+ values = tag1.values
230
+ assert_equal(123, values[0])
231
+ assert_equal(3000000000, values[1])
232
+ assert_equal(456, values[2])
233
+ assert_equal(789, values[3])
234
+ assert_equal(123.45, values[4])
235
+ assert_equal(67.8, values[5])
236
+ assert_equal(910.11, values[6])
237
+ assert_equal(12.13, values[7])
238
+ assert_equal(1415.16, values[8])
239
+ assert_equal(BigDecimal("171.8"), values[9])
240
+ assert_equal(BigDecimal("1.920"), values[10])
241
+ assert_equal(BigDecimal("12345678901234567890"), values[11])
242
+ assert_equal(-13.05, values[12])
243
+
244
+ assert_raise SdlParseError do
245
+ parse_one_tag1("tag1 123.2.2")
246
+ end
247
+ assert_raise SdlParseError do
248
+ parse_one_tag1("tag1 123.2e")
249
+ end
250
+ assert_raise SdlParseError do
251
+ parse_one_tag1("tag1 +-123.2")
252
+ end
253
+ end
254
+
255
+ def test_booleans
256
+ tag1 = parse_one_tag1("tag1 b1=true b2=false b3=on b4=off")
257
+ assert_equal(true, tag1.attribute("b1"))
258
+ assert_equal(false, tag1.attribute("b2"))
259
+ assert_equal(true, tag1.attribute("b3"))
260
+ assert_equal(false, tag1.attribute("b4"))
261
+ end
262
+
263
+ def test_null
264
+ tag1 = parse_one_tag1("tag1 null attr1=null")
265
+ values = tag1.values
266
+ assert_equal(1, values.size)
267
+ assert_equal(nil, values[0])
268
+ assert_equal(nil, tag1.attribute("attr1"))
269
+ assert(tag1.has_attribute?("attr1"))
270
+ end
271
+
272
+ def test_comments
273
+ root = Tag.new("root")
274
+ root.read(
275
+ <<EOS
276
+ tag1 123
277
+ #tag2 456
278
+ tag3 789
279
+ --tag4 012
280
+ tag5 345
281
+ //tag6 678
282
+ tag7 901
283
+ /*tag8 234
284
+ tag9 567*/
285
+ tag10 890
286
+ EOS
287
+ )
288
+ children = root.children
289
+ assert_equal(5, children.size, "children count")
290
+ assert_equal(123, root.child("tag1").value)
291
+ assert_nil(root.child("tag2"))
292
+ assert_equal(789, root.child("tag3").value)
293
+ assert_nil(root.child("tag4"))
294
+ assert_equal(345, root.child("tag5").value)
295
+ assert_nil(root.child("tag6"))
296
+ assert_equal(901, root.child("tag7").value)
297
+ assert_nil(root.child("tag8"))
298
+ assert_nil(root.child("tag9"))
299
+ assert_equal(890, root.child("tag10").value)
300
+ end
301
+
302
+ def test_double_quote_strings
303
+ root = SDL4R::read(
304
+ <<EOS
305
+ tag1 "cheese and cherry jam"
306
+ tag2 "cheese and \\
307
+ cherry jam"
308
+ tag3 "cheese \\
309
+ and \\
310
+ cherry jam"
311
+ tag4 "Did you say this soup was \\"good\\"?"
312
+ tag5 "Even my dog wouldn't\\thave\\tit!"
313
+ tag6 "\\"\\t\\r\\n\\\\"
314
+ tag7 equation="is not x=y*z" color="blue \\
315
+ and yellow"
316
+ EOS
317
+ )
318
+
319
+ assert_equal "cheese and cherry jam", root.child("tag1").value, "double-quote string"
320
+ assert_equal(
321
+ "cheese and cherry jam", root.child("tag2").value, "continued double-quote string")
322
+ assert_equal(
323
+ "cheese and cherry jam", root.child("tag3").value, "continued double-quote string")
324
+ assert_equal(
325
+ 'Did you say this soup was "good"?', root.child("tag4").value, "escaped quotes")
326
+ assert_equal(
327
+ "Even my dog wouldn't\thave\tit!", root.child("tag5").value, "escaped tabs")
328
+ assert_equal "\"\t\r\n\\", root.child("tag6").value, "escaped white spaces"
329
+ assert_equal "is not x=y*z", root.child("tag7").attribute("equation")
330
+ assert_equal "blue and yellow", root.child("tag7").attribute("color")
331
+ end
332
+
333
+ def test_characters
334
+ root = SDL4R::read "tag1 ' ' 'a' '\\\\' '\\t' '\\n' '\\r'"
335
+ assert_equal [" ", "a", "\\", "\t", "\n", "\r"], root.child("tag1").values
336
+
337
+ assert_raise SdlParseError do
338
+ SDL4R::read "tag1 '"
339
+ end
340
+ assert_raise SdlParseError do
341
+ SDL4R::read "tag1 'a"
342
+ end
343
+ assert_raise SdlParseError do
344
+ SDL4R::read "tag1 'abc'"
345
+ end
346
+ assert_raise SdlParseError do
347
+ SDL4R::read "tag1 ''"
348
+ end
349
+ assert_raise SdlParseError do
350
+ SDL4R::read "tag1 '\\'"
351
+ end
352
+ assert_raise SdlParseError do
353
+ SDL4R::read "tag1 '\\"
354
+ end
355
+
356
+ if SDL4R::supports_unicode_identifiers?
357
+ kanji = SDL4R::read("kanji '日'").child
358
+ assert_equal "日", kanji.value
359
+ end
360
+ end
361
+
362
+ def test_backquote_strings
363
+ root = SDL4R::read <<EOS
364
+ winfile `c:\\directory\\myfile.xls`
365
+ talk `I said "something"`
366
+ xml `
367
+ <product>
368
+ <shoes color="blue"/>
369
+ </product>
370
+ `
371
+ regex `\\w+\\.suite\\(\\)`
372
+ EOS
373
+
374
+ assert_equal "c:\\directory\\myfile.xls", root.child("winfile").value
375
+ assert_equal 'I said "something"', root.child("talk").value
376
+ assert_equal(
377
+ "\n<product>\n <shoes color=\"blue\"/>\n</product>\n", root.child("xml").value)
378
+ assert_equal "\\w+\\.suite\\(\\)", root.child("regex").value
379
+ end
380
+
381
+ def test_sub_tags
382
+ root = SDL4R::read <<EOS
383
+ wax {
384
+ }
385
+ steack {
386
+ bees {
387
+ monopoly {
388
+ }
389
+ }
390
+ goat_cheese
391
+ truck {
392
+ cathedral
393
+ }
394
+ }
395
+ peanut.butter
396
+ EOS
397
+
398
+ expected = Tag.new("root") do
399
+ new_child("wax")
400
+ new_child("steack") do
401
+ new_child("bees") do
402
+ new_child("monopoly")
403
+ end
404
+ new_child("goat_cheese")
405
+ new_child("truck") do
406
+ new_child("cathedral")
407
+ end
408
+ end
409
+ new_child("peanut.butter")
410
+ end
411
+
412
+ assert_equal expected, root
413
+ end
414
+
415
+ def test_identifiers
416
+ root = SDL4R::read("my_ns:my_tag my_ns2:my_attr=-13.8")
417
+
418
+ assert_equal "my_ns", root.child.namespace
419
+ assert_equal "my_tag", root.child.name
420
+ assert_equal({ "my_ns2:my_attr" => -13.8 }, root.child.attributes)
421
+
422
+ root = SDL4R::read("_my_ns:_my_tag _my_ns2:_my_attr=-13.8")
423
+ assert_equal "_my_ns", root.child.namespace
424
+ assert_equal "_my_tag", root.child.name
425
+ assert_equal({ "_my_ns2:_my_attr" => -13.8 }, root.child.attributes)
426
+
427
+ root = SDL4R::read("my.ns:my.tag my.ns2:my.attr=-13.8")
428
+ assert_equal "my.ns", root.child.namespace
429
+ assert_equal "my.tag", root.child.name
430
+ assert_equal({ "my.ns2:my.attr" => -13.8 }, root.child.attributes)
431
+
432
+ root = SDL4R::read("my$ns:my$tag my$ns2:my$attr=-13.8")
433
+ assert_equal "my$ns", root.child.namespace
434
+ assert_equal "my$tag", root.child.name
435
+ assert_equal({ "my$ns2:my$attr" => -13.8 }, root.child.attributes)
436
+
437
+ if SDL4R::supports_unicode_identifiers?
438
+ root = SDL4R::read("京都:アイスクリーム 京都:味=`いちご`")
439
+ assert_equal "京都", root.child.namespace
440
+ assert_equal "アイスクリーム", root.child.name
441
+ assert_equal({ "京都:味" => 'いちご' }, root.child.attributes)
442
+ end
443
+ end
444
+
445
+ def test_empty_block
446
+ tag1 = parse_one_tag1("tag1 {\n}")
447
+ assert_equal [], tag1.values
448
+ assert_equal({}, tag1.attributes)
449
+ assert_equal [], tag1.children
450
+
451
+ tag1 = parse_one_tag1("tag1 {}")
452
+ assert_equal [], tag1.values
453
+ assert_equal({}, tag1.attributes)
454
+ assert_equal [], tag1.children
455
+ end
456
+
457
+ def test_anonymous_tags
458
+ tag = SDL4R::read('123').child
459
+ assert_equal "", tag.namespace
460
+ assert_equal "content", tag.name
461
+ assert_equal [123], tag.values
462
+ assert_equal({}, tag.attributes)
463
+
464
+ tag = SDL4R::read('123 attr=456').child
465
+ assert_equal "", tag.namespace
466
+ assert_equal "content", tag.name
467
+ assert_equal [123], tag.values
468
+ assert_equal({"attr" => 456}, tag.attributes)
469
+
470
+ tag = SDL4R::read('"abc"').child
471
+ assert_equal "", tag.namespace
472
+ assert_equal "content", tag.name
473
+ assert_equal ["abc"], tag.values
474
+ assert_equal({}, tag.attributes)
475
+
476
+ tag = SDL4R::read('`abc`').child
477
+ assert_equal "", tag.namespace
478
+ assert_equal "content", tag.name
479
+ assert_equal ["abc"], tag.values
480
+ assert_equal({}, tag.attributes)
481
+
482
+ tag = SDL4R::read("'\\\\'").child
483
+ assert_equal "", tag.namespace
484
+ assert_equal "content", tag.name
485
+ assert_equal ["\\"], tag.values
486
+ assert_equal({}, tag.attributes)
487
+
488
+ assert_raise SDL4R::SdlParseError do SDL4R::read("attr=123") end
489
+
490
+ # Anonymous tags inside tags
491
+ tag = SDL4R::read(<<-EOS).child
492
+ files {
493
+ "/home/s-austin/price.txt"
494
+ `/home/spiderman/tarantula_porn.avi` size="200Mb"
495
+ }
496
+ EOS
497
+
498
+ child = tag.child
499
+ assert_equal '', child.namespace
500
+ assert_equal 'content', child.name
501
+ assert_equal ["/home/s-austin/price.txt"], child.values
502
+
503
+ child = tag.children[1]
504
+ assert_equal '', child.namespace
505
+ assert_equal 'content', child.name
506
+ assert_equal ["/home/spiderman/tarantula_porn.avi"], child.values
507
+ end
508
+
509
+ def test_parse_error
510
+ # WARNING: the line and col of an error is not accurate science. The goal here is to point to
511
+ # coordinates that are useful to the user.
512
+ # For example, if we have a string literal spanning over several lines, some errors could be
513
+ # pointing to the start or to the end without too much ambiguity.
514
+ # Consequently, feel free to change the coordinates, if a change in the implementation
515
+ # modifies the x/y of the error and they still make sense.
516
+ assert_error_xy "=", 1, 1
517
+ assert_error_xy "tag1 xyz", 1, 9
518
+ assert_error_xy "tag1 \\\nxyz", 2, 4
519
+ assert_error_xy "tag1 \\\n xyz", 2, 7
520
+
521
+ source = <<EOS
522
+ -- my comment
523
+ =
524
+ EOS
525
+ assert_error_xy source, 2, 1
526
+
527
+ source = <<EOS
528
+ murder_plot 123 \\
529
+ weight=456 \\
530
+ * \\
531
+ length=789
532
+ EOS
533
+ assert_error_xy source, 3, 7
534
+
535
+ assert_error_xy 'tag1 "text\\"', 1, 13
536
+
537
+ source = <<EOS
538
+ murder_plot "abcd\\
539
+ efghij\\
540
+ kl\\
541
+ mnopq
542
+ EOS
543
+ assert_error_xy source, 4, 13
544
+ end
545
+
546
+ private
547
+
548
+ def assert_error_xy source, expected_line, expected_pos
549
+ error = get_parse_error_or_fail source
550
+ begin
551
+ assert_equal expected_line, error.line, "line"
552
+ assert_equal expected_pos, error.position, "position"
553
+ rescue
554
+ puts "Expected error: #{error}"
555
+ puts error.backtrace
556
+ raise $!
557
+ end
558
+ end
559
+
560
+ def get_parse_error_or_fail source
561
+ begin
562
+ SDL4R::read source
563
+
564
+ rescue
565
+ return $! if $!.is_a? SdlParseError
566
+ raise Test::Unit::AssertionFailedError, "was expecting a SdlParseError"
567
+ end
568
+ end
569
+
570
+ def parse_one_tag1(text)
571
+ root = SDL4R::read(text)
572
+ tag1 = root.child("tag1")
573
+ assert_not_nil(tag1, "tag1")
574
+ assert_equal 1, root.child_count, "only 1 tag expected"
575
+ return tag1
576
+ end
577
+ end
504
578
  end