PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/Ruby/Tests/Libraries/Yaml/test_yaml.rb

http://github.com/IronLanguages/main
Ruby | 1286 lines | 1137 code | 65 blank | 84 comment | 5 complexity | e10fdecf8389e604571daa7f29d30837 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*-
  2. # vim:sw=4:ts=4
  3. # $Id: test_yaml.rb 11708 2007-02-12 23:01:19Z shyouhei $
  4. #
  5. require 'test/unit'
  6. require 'yaml'
  7. #System::Console.ReadLine()
  8. # [ruby-core:01946]
  9. module YAML_Tests
  10. StructTest = Struct::new( :c )
  11. end
  12. class YAML_Unit_Tests < Test::Unit::TestCase
  13. #
  14. # Convert between YAML and the object to verify correct parsing and
  15. # emitting
  16. #
  17. def assert_to_yaml( obj, yaml )
  18. assert_equal( obj, YAML::load( yaml ) )
  19. assert_equal( obj, YAML::parse( yaml ).transform )
  20. assert_equal( obj, YAML::load( obj.to_yaml ) )
  21. assert_equal( obj, YAML::parse( obj.to_yaml ).transform )
  22. assert_equal( obj, YAML::load(
  23. obj.to_yaml( :UseVersion => true, :UseHeader => true, :SortKeys => true )
  24. ) )
  25. end
  26. #
  27. # Test parser only
  28. #
  29. def assert_parse_only( obj, yaml )
  30. assert_equal( obj, YAML::load( yaml ) )
  31. assert_equal( obj, YAML::parse( yaml ).transform )
  32. end
  33. def assert_cycle( obj )
  34. assert_equal( obj, YAML::load( obj.to_yaml ) )
  35. end
  36. def assert_path_segments( path, segments )
  37. YAML::YPath.each_path( path ) { |choice|
  38. assert_equal( choice.segments, segments.shift )
  39. }
  40. assert_equal( segments.length, 0, "Some segments leftover: #{ segments.inspect }" )
  41. end
  42. #
  43. # Make a time with the time zone
  44. #
  45. def mktime( year, mon, day, hour, min, sec, usec, zone = "Z" )
  46. usec = usec.to_s.to_f * 1000000
  47. val = Time::utc( year.to_i, mon.to_i, day.to_i, hour.to_i, min.to_i, sec.to_i, usec )
  48. if zone != "Z"
  49. hour = zone[0,3].to_i * 3600
  50. min = zone[3,2].to_i * 60
  51. ofs = (hour + min)
  52. val = Time.at( val.to_f - ofs )
  53. end
  54. return val
  55. end
  56. #
  57. # Tests modified from 00basic.t in YAML.pm
  58. #
  59. def test_basic_map
  60. # Simple map
  61. assert_parse_only(
  62. { 'one' => 'foo', 'three' => 'baz', 'two' => 'bar' }, <<EOY
  63. one: foo
  64. two: bar
  65. three: baz
  66. EOY
  67. )
  68. end
  69. def test_basic_strings
  70. # Common string types
  71. assert_cycle("x")
  72. assert_cycle(":x")
  73. assert_cycle(":")
  74. assert_parse_only(
  75. { 1 => 'simple string', 2 => 42, 3 => '1 Single Quoted String',
  76. 4 => 'YAML\'s Double "Quoted" String', 5 => "A block\n with several\n lines.\n",
  77. 6 => "A \"chomped\" block", 7 => "A folded\n string\n", 8 => ": started string" },
  78. <<EOY
  79. 1: simple string
  80. 2: 42
  81. 3: '1 Single Quoted String'
  82. 4: "YAML's Double \\\"Quoted\\\" String"
  83. 5: |
  84. A block
  85. with several
  86. lines.
  87. 6: |-
  88. A "chomped" block
  89. 7: >
  90. A
  91. folded
  92. string
  93. 8: ": started string"
  94. EOY
  95. )
  96. end
  97. #
  98. # Test the specification examples
  99. # - Many examples have been changes because of whitespace problems that
  100. # caused the two to be inequivalent, or keys to be sorted wrong
  101. #
  102. def test_spec_simple_implicit_sequence
  103. # Simple implicit sequence
  104. assert_to_yaml(
  105. [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ], <<EOY
  106. - Mark McGwire
  107. - Sammy Sosa
  108. - Ken Griffey
  109. EOY
  110. )
  111. end
  112. def test_spec_simple_implicit_map
  113. # Simple implicit map
  114. assert_to_yaml(
  115. { 'hr' => 65, 'avg' => 0.278, 'rbi' => 147 }, <<EOY
  116. avg: 0.278
  117. hr: 65
  118. rbi: 147
  119. EOY
  120. )
  121. end
  122. def test_spec_simple_map_with_nested_sequences
  123. # Simple mapping with nested sequences
  124. assert_to_yaml(
  125. { 'american' =>
  126. [ 'Boston Red Sox', 'Detroit Tigers', 'New York Yankees' ],
  127. 'national' =>
  128. [ 'New York Mets', 'Chicago Cubs', 'Atlanta Braves' ] }, <<EOY
  129. american:
  130. - Boston Red Sox
  131. - Detroit Tigers
  132. - New York Yankees
  133. national:
  134. - New York Mets
  135. - Chicago Cubs
  136. - Atlanta Braves
  137. EOY
  138. )
  139. end
  140. def test_spec_simple_sequence_with_nested_map
  141. # Simple sequence with nested map
  142. assert_to_yaml(
  143. [
  144. {'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278},
  145. {'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288}
  146. ], <<EOY
  147. -
  148. avg: 0.278
  149. hr: 65
  150. name: Mark McGwire
  151. -
  152. avg: 0.288
  153. hr: 63
  154. name: Sammy Sosa
  155. EOY
  156. )
  157. end
  158. def test_spec_sequence_of_sequences
  159. # Simple sequence with inline sequences
  160. assert_parse_only(
  161. [
  162. [ 'name', 'hr', 'avg' ],
  163. [ 'Mark McGwire', 65, 0.278 ],
  164. [ 'Sammy Sosa', 63, 0.288 ]
  165. ], <<EOY
  166. - [ name , hr , avg ]
  167. - [ Mark McGwire , 65 , 0.278 ]
  168. - [ Sammy Sosa , 63 , 0.288 ]
  169. EOY
  170. )
  171. end
  172. def test_spec_mapping_of_mappings
  173. # Simple map with inline maps
  174. assert_parse_only(
  175. { 'Mark McGwire' =>
  176. { 'hr' => 65, 'avg' => 0.278 },
  177. 'Sammy Sosa' =>
  178. { 'hr' => 63, 'avg' => 0.288 }
  179. }, <<EOY
  180. Mark McGwire: {hr: 65, avg: 0.278}
  181. Sammy Sosa: {hr: 63,
  182. avg: 0.288}
  183. EOY
  184. )
  185. end
  186. def test_ambiguous_comments
  187. # [ruby-talk:88012]
  188. assert_to_yaml( "Call the method #dave", <<EOY )
  189. --- "Call the method #dave"
  190. EOY
  191. end
  192. def test_spec_nested_comments
  193. # Map and sequences with comments
  194. assert_parse_only(
  195. { 'hr' => [ 'Mark McGwire', 'Sammy Sosa' ],
  196. 'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] }, <<EOY
  197. hr: # 1998 hr ranking
  198. - Mark McGwire
  199. - Sammy Sosa
  200. rbi:
  201. # 1998 rbi ranking
  202. - Sammy Sosa
  203. - Ken Griffey
  204. EOY
  205. )
  206. end
  207. def test_spec_anchors_and_aliases
  208. # Anchors and aliases
  209. assert_parse_only(
  210. { 'hr' =>
  211. [ 'Mark McGwire', 'Sammy Sosa' ],
  212. 'rbi' =>
  213. [ 'Sammy Sosa', 'Ken Griffey' ] }, <<EOY
  214. hr:
  215. - Mark McGwire
  216. # Name "Sammy Sosa" scalar SS
  217. - &SS Sammy Sosa
  218. rbi:
  219. # So it can be referenced later.
  220. - *SS
  221. - Ken Griffey
  222. EOY
  223. )
  224. assert_to_yaml(
  225. [{"arrival"=>"EDI", "departure"=>"LAX", "fareref"=>"DOGMA", "currency"=>"GBP"}, {"arrival"=>"MEL", "departure"=>"SYD", "fareref"=>"MADF", "currency"=>"AUD"}, {"arrival"=>"MCO", "departure"=>"JFK", "fareref"=>"DFSF", "currency"=>"USD"}], <<EOY
  226. -
  227. &F fareref: DOGMA
  228. &C currency: GBP
  229. &D departure: LAX
  230. &A arrival: EDI
  231. - { *F: MADF, *C: AUD, *D: SYD, *A: MEL }
  232. - { *F: DFSF, *C: USD, *D: JFK, *A: MCO }
  233. EOY
  234. )
  235. assert_to_yaml(
  236. {"ALIASES"=>["fareref", "currency", "departure", "arrival"], "FARES"=>[{"arrival"=>"EDI", "departure"=>"LAX", "fareref"=>"DOGMA", "currency"=>"GBP"}, {"arrival"=>"MEL", "departure"=>"SYD", "fareref"=>"MADF", "currency"=>"AUD"}, {"arrival"=>"MCO", "departure"=>"JFK", "fareref"=>"DFSF", "currency"=>"USD"}]}, <<EOY
  237. ---
  238. ALIASES: [&f fareref, &c currency, &d departure, &a arrival]
  239. FARES:
  240. - *f: DOGMA
  241. *c: GBP
  242. *d: LAX
  243. *a: EDI
  244. - *f: MADF
  245. *c: AUD
  246. *d: SYD
  247. *a: MEL
  248. - *f: DFSF
  249. *c: USD
  250. *d: JFK
  251. *a: MCO
  252. EOY
  253. )
  254. end
  255. def test_spec_mapping_between_sequences
  256. # Complex key #1
  257. dj = Date.new( 2001, 7, 23 )
  258. assert_parse_only(
  259. { [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ],
  260. [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ] }, <<EOY
  261. ? # PLAY SCHEDULE
  262. - Detroit Tigers
  263. - Chicago Cubs
  264. :
  265. - 2001-07-23
  266. ? [ New York Yankees,
  267. Atlanta Braves ]
  268. : [ 2001-07-02, 2001-08-12,
  269. 2001-08-14 ]
  270. EOY
  271. )
  272. # Complex key #2
  273. assert_parse_only(
  274. { [ 'New York Yankees', 'Atlanta Braves' ] =>
  275. [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ),
  276. Date.new( 2001, 8, 14 ) ],
  277. [ 'Detroit Tigers', 'Chicago Cubs' ] =>
  278. [ Date.new( 2001, 7, 23 ) ]
  279. }, <<EOY
  280. ?
  281. - New York Yankees
  282. - Atlanta Braves
  283. :
  284. - 2001-07-02
  285. - 2001-08-12
  286. - 2001-08-14
  287. ?
  288. - Detroit Tigers
  289. - Chicago Cubs
  290. :
  291. - 2001-07-23
  292. EOY
  293. )
  294. end
  295. def test_spec_sequence_key_shortcut
  296. # Shortcut sequence map
  297. assert_parse_only(
  298. { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
  299. 'bill-to' => 'Chris Dumars', 'product' =>
  300. [ { 'item' => 'Super Hoop', 'quantity' => 1 },
  301. { 'item' => 'Basketball', 'quantity' => 4 },
  302. { 'item' => 'Big Shoes', 'quantity' => 1 } ] }, <<EOY
  303. invoice: 34843
  304. date : 2001-01-23
  305. bill-to: Chris Dumars
  306. product:
  307. - item : Super Hoop
  308. quantity: 1
  309. - item : Basketball
  310. quantity: 4
  311. - item : Big Shoes
  312. quantity: 1
  313. EOY
  314. )
  315. end
  316. def test_spec_sequence_in_sequence_shortcut
  317. # Seq-in-seq
  318. assert_parse_only( [ [ [ 'one', 'two', 'three' ] ] ], <<EOY )
  319. - - - one
  320. - two
  321. - three
  322. EOY
  323. end
  324. def test_spec_sequence_shortcuts
  325. # Sequence shortcuts combined
  326. assert_parse_only(
  327. [
  328. [
  329. [ [ 'one' ] ],
  330. [ 'two', 'three' ],
  331. { 'four' => nil },
  332. [ { 'five' => [ 'six' ] } ],
  333. [ 'seven' ]
  334. ],
  335. [ 'eight', 'nine' ]
  336. ], <<EOY )
  337. - - - - one
  338. - - two
  339. - three
  340. - four:
  341. - - five:
  342. - six
  343. - - seven
  344. - - eight
  345. - nine
  346. EOY
  347. end
  348. def test_spec_single_literal
  349. # Literal scalar block
  350. assert_parse_only( [ "\\/|\\/|\n/ | |_\n" ], <<EOY )
  351. - |
  352. \\/|\\/|
  353. / | |_
  354. EOY
  355. end
  356. def test_spec_single_folded
  357. # Folded scalar block
  358. assert_parse_only(
  359. [ "Mark McGwire's year was crippled by a knee injury.\n" ], <<EOY
  360. - >
  361. Mark McGwire\'s
  362. year was crippled
  363. by a knee injury.
  364. EOY
  365. )
  366. end
  367. def test_spec_preserve_indent
  368. # Preserve indented spaces
  369. assert_parse_only(
  370. "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n", <<EOY
  371. --- >
  372. Sammy Sosa completed another
  373. fine season with great stats.
  374. 63 Home Runs
  375. 0.288 Batting Average
  376. What a year!
  377. EOY
  378. )
  379. end
  380. def test_spec_indentation_determines_scope
  381. assert_parse_only(
  382. { 'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n",
  383. 'stats' => "65 Home Runs\n0.278 Batting Average\n" }, <<EOY
  384. name: Mark McGwire
  385. accomplishment: >
  386. Mark set a major league
  387. home run record in 1998.
  388. stats: |
  389. 65 Home Runs
  390. 0.278 Batting Average
  391. EOY
  392. )
  393. end
  394. def test_spec_multiline_scalars
  395. # Multiline flow scalars
  396. assert_parse_only(
  397. { 'plain' => 'This unquoted scalar spans many lines.',
  398. 'quoted' => "So does this quoted scalar.\n" }, <<EOY
  399. plain: This unquoted
  400. scalar spans
  401. many lines.
  402. quoted: "\\
  403. So does this quoted
  404. scalar.\\n"
  405. EOY
  406. )
  407. end
  408. def test_spec_type_int
  409. assert_parse_only(
  410. { 'canonical' => 12345, 'decimal' => 12345, 'octal' => '014'.oct, 'hexadecimal' => '0xC'.hex }, <<EOY
  411. canonical: 12345
  412. decimal: +12,345
  413. octal: 014
  414. hexadecimal: 0xC
  415. EOY
  416. )
  417. assert_parse_only(
  418. { 'canonical' => 685230, 'decimal' => 685230, 'octal' => 02472256, 'hexadecimal' => 0x0A74AE, 'sexagesimal' => 685230 }, <<EOY)
  419. canonical: 685230
  420. decimal: +685,230
  421. octal: 02472256
  422. hexadecimal: 0x0A,74,AE
  423. sexagesimal: 190:20:30
  424. EOY
  425. end
  426. def test_spec_type_float
  427. assert_parse_only(
  428. { 'canonical' => 1230.15, 'exponential' => 1230.15, 'fixed' => 1230.15,
  429. 'negative infinity' => -1.0/0.0 }, <<EOY)
  430. canonical: 1.23015e+3
  431. exponential: 12.3015e+02
  432. fixed: 1,230.15
  433. negative infinity: -.inf
  434. EOY
  435. nan = YAML::load( <<EOY )
  436. not a number: .NaN
  437. EOY
  438. assert( nan['not a number'].nan? )
  439. end
  440. def test_spec_type_misc
  441. assert_parse_only(
  442. { nil => nil, true => true, false => false, 'string' => '12345' }, <<EOY
  443. null: ~
  444. true: yes
  445. false: no
  446. string: '12345'
  447. EOY
  448. )
  449. end
  450. def test_spec_complex_invoice
  451. # Complex invoice type
  452. id001 = { 'given' => 'Chris', 'family' => 'Dumars', 'address' =>
  453. { 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak',
  454. 'state' => 'MI', 'postal' => 48046 } }
  455. assert_parse_only(
  456. { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
  457. 'bill-to' => id001, 'ship-to' => id001, 'product' =>
  458. [ { 'sku' => 'BL394D', 'quantity' => 4,
  459. 'description' => 'Basketball', 'price' => 450.00 },
  460. { 'sku' => 'BL4438H', 'quantity' => 1,
  461. 'description' => 'Super Hoop', 'price' => 2392.00 } ],
  462. 'tax' => 251.42, 'total' => 4443.52,
  463. 'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" }, <<EOY
  464. invoice: 34843
  465. date : 2001-01-23
  466. bill-to: &id001
  467. given : Chris
  468. family : !str Dumars
  469. address:
  470. lines: |
  471. 458 Walkman Dr.
  472. Suite #292
  473. city : Royal Oak
  474. state : MI
  475. postal : 48046
  476. ship-to: *id001
  477. product:
  478. - !map
  479. sku : BL394D
  480. quantity : 4
  481. description : Basketball
  482. price : 450.00
  483. - sku : BL4438H
  484. quantity : 1
  485. description : Super Hoop
  486. price : 2392.00
  487. tax : 251.42
  488. total: 4443.52
  489. comments: >
  490. Late afternoon is best.
  491. Backup contact is Nancy
  492. Billsmer @ 338-4338.
  493. EOY
  494. )
  495. end
  496. def test_spec_log_file
  497. doc_ct = 0
  498. YAML::load_documents( <<EOY
  499. ---
  500. Time: 2001-11-23 15:01:42 -05:00
  501. User: ed
  502. Warning: >
  503. This is an error message
  504. for the log file
  505. ---
  506. Time: 2001-11-23 15:02:31 -05:00
  507. User: ed
  508. Warning: >
  509. A slightly different error
  510. message.
  511. ---
  512. Date: 2001-11-23 15:03:17 -05:00
  513. User: ed
  514. Fatal: >
  515. Unknown variable "bar"
  516. Stack:
  517. - file: TopClass.py
  518. line: 23
  519. code: |
  520. x = MoreObject("345\\n")
  521. - file: MoreClass.py
  522. line: 58
  523. code: |-
  524. foo = bar
  525. EOY
  526. ) { |doc|
  527. case doc_ct
  528. when 0
  529. assert_equal( doc, { 'Time' => mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ),
  530. 'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } )
  531. when 1
  532. assert_equal( doc, { 'Time' => mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ),
  533. 'User' => 'ed', 'Warning' => "A slightly different error message.\n" } )
  534. when 2
  535. assert_equal( doc, { 'Date' => mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ),
  536. 'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n",
  537. 'Stack' => [
  538. { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" },
  539. { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } )
  540. end
  541. doc_ct += 1
  542. }
  543. assert_equal( doc_ct, 3 )
  544. end
  545. def test_spec_root_fold
  546. y = YAML::load( <<EOY
  547. --- >
  548. This YAML stream contains a single text value.
  549. The next stream is a log file - a sequence of
  550. log entries. Adding an entry to the log is a
  551. simple matter of appending it at the end.
  552. EOY
  553. )
  554. assert_equal( y, "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n" )
  555. end
  556. def test_spec_root_mapping
  557. y = YAML::load( <<EOY
  558. # This stream is an example of a top-level mapping.
  559. invoice : 34843
  560. date : 2001-01-23
  561. total : 4443.52
  562. EOY
  563. )
  564. assert_equal( y, { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ), 'total' => 4443.52 } )
  565. end
  566. def test_spec_oneline_docs
  567. doc_ct = 0
  568. YAML::load_documents( <<EOY
  569. # The following is a sequence of three documents.
  570. # The first contains an empty mapping, the second
  571. # an empty sequence, and the last an empty string.
  572. --- {}
  573. --- [ ]
  574. --- ''
  575. EOY
  576. ) { |doc|
  577. case doc_ct
  578. when 0
  579. assert_equal( doc, {} )
  580. when 1
  581. assert_equal( doc, [] )
  582. when 2
  583. assert_equal( doc, '' )
  584. end
  585. doc_ct += 1
  586. }
  587. assert_equal( doc_ct, 3 )
  588. end
  589. def test_spec_domain_prefix
  590. customer_proc = proc { |type, val|
  591. if Hash === val
  592. scheme, domain, type = type.split( ':', 3 )
  593. val['type'] = "domain #{type}"
  594. val
  595. else
  596. raise ArgumentError, "Not a Hash in domain.tld,2002/invoice: " + val.inspect
  597. end
  598. }
  599. YAML.add_domain_type( "domain.tld,2002", 'invoice', &customer_proc )
  600. YAML.add_domain_type( "domain.tld,2002", 'customer', &customer_proc )
  601. assert_parse_only( { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }, <<EOY
  602. # 'http://domain.tld,2002/invoice' is some type family.
  603. invoice: !domain.tld,2002/^invoice
  604. # 'seq' is shorthand for 'http://yaml.org/seq'.
  605. # This does not effect '^customer' below
  606. # because it is does not specify a prefix.
  607. customers: !seq
  608. # '^customer' is shorthand for the full
  609. # notation 'http://domain.tld,2002/customer'.
  610. - !^customer
  611. given : Chris
  612. family : Dumars
  613. EOY
  614. )
  615. end
  616. def test_spec_throwaway
  617. assert_parse_only(
  618. {"this"=>"contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"}, <<EOY
  619. ### These are four throwaway comment ###
  620. ### lines (the second line is empty). ###
  621. this: | # Comments may trail lines.
  622. contains three lines of text.
  623. The third one starts with a
  624. # character. This isn't a comment.
  625. # These are three throwaway comment
  626. # lines (the first line is empty).
  627. EOY
  628. )
  629. end
  630. def test_spec_force_implicit
  631. # Force implicit
  632. assert_parse_only(
  633. { 'integer' => 12, 'also int' => 12, 'string' => '12' }, <<EOY
  634. integer: 12
  635. also int: ! "12"
  636. string: !str 12
  637. EOY
  638. )
  639. end
  640. def test_spec_private_types
  641. doc_ct = 0
  642. YAML::parse_documents( <<EOY
  643. # Private types are per-document.
  644. ---
  645. pool: !!ball
  646. number: 8
  647. color: black
  648. ---
  649. bearing: !!ball
  650. material: steel
  651. EOY
  652. ) { |doc|
  653. case doc_ct
  654. when 0
  655. assert_equal( doc['pool'].type_id, 'x-private:ball' )
  656. assert_equal( doc['pool'].transform.value, { 'number' => 8, 'color' => 'black' } )
  657. when 1
  658. assert_equal( doc['bearing'].type_id, 'x-private:ball' )
  659. assert_equal( doc['bearing'].transform.value, { 'material' => 'steel' } )
  660. end
  661. doc_ct += 1
  662. }
  663. assert_equal( doc_ct, 2 )
  664. end
  665. def test_spec_url_escaping
  666. YAML.add_domain_type( "domain.tld,2002", "type0" ) { |type, val|
  667. "ONE: #{val}"
  668. }
  669. YAML.add_domain_type( "domain.tld,2002", "type%30" ) { |type, val|
  670. "TWO: #{val}"
  671. }
  672. assert_parse_only(
  673. { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value' ] }, <<EOY
  674. same:
  675. - !domain.tld,2002/type\\x30 value
  676. - !domain.tld,2002/type0 value
  677. different: # As far as the YAML parser is concerned
  678. - !domain.tld,2002/type%30 value
  679. EOY
  680. )
  681. end
  682. def test_spec_override_anchor
  683. # Override anchor
  684. a001 = "The alias node below is a repeated use of this value.\n"
  685. assert_parse_only(
  686. { 'anchor' => 'This scalar has an anchor.', 'override' => a001, 'alias' => a001 }, <<EOY
  687. anchor : &A001 This scalar has an anchor.
  688. override : &A001 >
  689. The alias node below is a
  690. repeated use of this value.
  691. alias : *A001
  692. EOY
  693. )
  694. end
  695. def test_spec_explicit_families
  696. YAML.add_domain_type( "somewhere.com,2002", 'type' ) { |type, val|
  697. "SOMEWHERE: #{val}"
  698. }
  699. assert_parse_only(
  700. { 'not-date' => '2002-04-28', 'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 'hmm' => "SOMEWHERE: family above is short for\nhttp://somewhere.com/type\n" }, <<EOY
  701. not-date: !str 2002-04-28
  702. picture: !binary |
  703. R0lGODlhDAAMAIQAAP//9/X
  704. 17unp5WZmZgAAAOfn515eXv
  705. Pz7Y6OjuDg4J+fn5OTk6enp
  706. 56enmleECcgggoBADs=
  707. hmm: !somewhere.com,2002/type |
  708. family above is short for
  709. http://somewhere.com/type
  710. EOY
  711. )
  712. end
  713. def test_spec_application_family
  714. # Testing the clarkevans.com graphs
  715. YAML.add_domain_type( "clarkevans.com,2002", 'graph/shape' ) { |type, val|
  716. if Array === val
  717. val << "Shape Container"
  718. val
  719. else
  720. raise ArgumentError, "Invalid graph of type #{val.class}: " + val.inspect
  721. end
  722. }
  723. one_shape_proc = Proc.new { |type, val|
  724. if Hash === val
  725. type = type.split( /:/ )
  726. val['TYPE'] = "Shape: #{type[2]}"
  727. val
  728. else
  729. raise ArgumentError, "Invalid graph of type #{val.class}: " + val.inspect
  730. end
  731. }
  732. YAML.add_domain_type( "clarkevans.com,2002", 'graph/circle', &one_shape_proc )
  733. YAML.add_domain_type( "clarkevans.com,2002", 'graph/line', &one_shape_proc )
  734. YAML.add_domain_type( "clarkevans.com,2002", 'graph/text', &one_shape_proc )
  735. assert_parse_only(
  736. [[{"radius"=>7, "center"=>{"x"=>73, "y"=>129}, "TYPE"=>"Shape: graph/circle"}, {"finish"=>{"x"=>89, "y"=>102}, "TYPE"=>"Shape: graph/line", "start"=>{"x"=>73, "y"=>129}}, {"TYPE"=>"Shape: graph/text", "value"=>"Pretty vector drawing.", "start"=>{"x"=>73, "y"=>129}, "color"=>16772795}, "Shape Container"]], <<EOY
  737. - !clarkevans.com,2002/graph/^shape
  738. - !^circle
  739. center: &ORIGIN {x: 73, y: 129}
  740. radius: 7
  741. - !^line # !clarkevans.com,2002/graph/line
  742. start: *ORIGIN
  743. finish: { x: 89, y: 102 }
  744. - !^text
  745. start: *ORIGIN
  746. color: 0xFFEEBB
  747. value: Pretty vector drawing.
  748. EOY
  749. )
  750. end
  751. def test_spec_float_explicit
  752. assert_parse_only(
  753. [ 10.0, 10.0, 10.0, 10.0 ], <<EOY
  754. # All entries in the sequence
  755. # have the same type and value.
  756. - 10.0
  757. - !float 10
  758. - !yaml.org,2002/^float '10'
  759. - !yaml.org,2002/float "\\
  760. 1\\
  761. 0"
  762. EOY
  763. )
  764. end
  765. def test_spec_builtin_seq
  766. # Assortment of sequences
  767. assert_parse_only(
  768. { 'empty' => [], 'in-line' => [ 'one', 'two', 'three', 'four', 'five' ],
  769. 'nested' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ],
  770. "A multi-line sequence entry\n", 'Sixth item in top sequence' ] }, <<EOY
  771. empty: []
  772. in-line: [ one, two, three # May span lines,
  773. , four, # indentation is
  774. five ] # mostly ignored.
  775. nested:
  776. - First item in top sequence
  777. -
  778. - Subordinate sequence entry
  779. - >
  780. A multi-line
  781. sequence entry
  782. - Sixth item in top sequence
  783. EOY
  784. )
  785. end
  786. def test_spec_builtin_map
  787. # Assortment of mappings
  788. assert_parse_only(
  789. { 'empty' => {}, 'in-line' => { 'one' => 1, 'two' => 2 },
  790. 'spanning' => { 'one' => 1, 'two' => 2 },
  791. 'nested' => { 'first' => 'First entry', 'second' =>
  792. { 'key' => 'Subordinate mapping' }, 'third' =>
  793. [ 'Subordinate sequence', {}, 'Previous mapping is empty.',
  794. { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' },
  795. 'The previous entry is equal to the following one.',
  796. { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ],
  797. 12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.',
  798. "\a" => 'This key had to be escaped.',
  799. "This is a multi-line folded key\n" => "Whose value is also multi-line.\n",
  800. [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }, <<EOY
  801. empty: {}
  802. in-line: { one: 1, two: 2 }
  803. spanning: { one: 1,
  804. two: 2 }
  805. nested:
  806. first : First entry
  807. second:
  808. key: Subordinate mapping
  809. third:
  810. - Subordinate sequence
  811. - { }
  812. - Previous mapping is empty.
  813. - A key: value pair in a sequence.
  814. A second: key:value pair.
  815. - The previous entry is equal to the following one.
  816. -
  817. A key: value pair in a sequence.
  818. A second: key:value pair.
  819. !float 12 : This key is a float.
  820. ? >
  821. ?
  822. : This key had to be protected.
  823. "\\a" : This key had to be escaped.
  824. ? >
  825. This is a
  826. multi-line
  827. folded key
  828. : >
  829. Whose value is
  830. also multi-line.
  831. ?
  832. - This key
  833. - is a sequence
  834. :
  835. - With a sequence value.
  836. # The following parses correctly,
  837. # but Ruby 1.6.* fails the comparison!
  838. # ?
  839. # This: key
  840. # is a: mapping
  841. # :
  842. # with a: mapping value.
  843. EOY
  844. )
  845. end
  846. def test_spec_builtin_literal_blocks
  847. # Assortment of literal scalar blocks
  848. assert_parse_only(
  849. {"both are equal to"=>" This has no newline.", "is equal to"=>"The \\ ' \" characters may be\nfreely used. Leading white\n space is significant.\n\nLine breaks are significant.\nThus this value contains one\nempty line and ends with a\nsingle line break, but does\nnot start with one.\n", "also written as"=>" This has no newline.", "indented and chomped"=>" This has no newline.", "empty"=>"", "literal"=>"The \\ ' \" characters may be\nfreely used. Leading white\n space is significant.\n\nLine breaks are significant.\nThus this value contains one\nempty line and ends with a\nsingle line break, but does\nnot start with one.\n"}, <<EOY
  850. empty: |
  851. literal: |
  852. The \\ ' " characters may be
  853. freely used. Leading white
  854. space is significant.
  855. Line breaks are significant.
  856. Thus this value contains one
  857. empty line and ends with a
  858. single line break, but does
  859. not start with one.
  860. is equal to: "The \\ ' \\" characters may \\
  861. be\\nfreely used. Leading white\\n space \\
  862. is significant.\\n\\nLine breaks are \\
  863. significant.\\nThus this value contains \\
  864. one\\nempty line and ends with a\\nsingle \\
  865. line break, but does\\nnot start with one.\\n"
  866. # Comments may follow a nested
  867. # scalar value. They must be
  868. # less indented.
  869. # Modifiers may be combined in any order.
  870. indented and chomped: |2-
  871. This has no newline.
  872. also written as: |-2
  873. This has no newline.
  874. both are equal to: " This has no newline."
  875. EOY
  876. )
  877. str1 = "This has one newline.\n"
  878. str2 = "This has no newline."
  879. str3 = "This has two newlines.\n\n"
  880. assert_parse_only(
  881. { 'clipped' => str1, 'same as "clipped" above' => str1,
  882. 'stripped' => str2, 'same as "stripped" above' => str2,
  883. 'kept' => str3, 'same as "kept" above' => str3 }, <<EOY
  884. clipped: |
  885. This has one newline.
  886. same as "clipped" above: "This has one newline.\\n"
  887. stripped: |-
  888. This has no newline.
  889. same as "stripped" above: "This has no newline."
  890. kept: |+
  891. This has two newlines.
  892. same as "kept" above: "This has two newlines.\\n\\n"
  893. EOY
  894. )
  895. end
  896. def test_spec_span_single_quote
  897. assert_parse_only( {"third"=>"a single quote ' must be escaped.", "second"=>"! : \\ etc. can be used freely.", "is same as"=>"this contains six spaces\nand one line break", "empty"=>"", "span"=>"this contains six spaces\nand one line break"}, <<EOY
  898. empty: ''
  899. second: '! : \\ etc. can be used freely.'
  900. third: 'a single quote '' must be escaped.'
  901. span: 'this contains
  902. six spaces
  903. and one
  904. line break'
  905. is same as: "this contains six spaces\\nand one line break"
  906. EOY
  907. )
  908. end
  909. def test_spec_span_double_quote
  910. assert_parse_only( {"is equal to"=>"this contains four spaces", "third"=>"a \" or a \\ must be escaped.", "second"=>"! : etc. can be used freely.", "empty"=>"", "fourth"=>"this value ends with an LF.\n", "span"=>"this contains four spaces"}, <<EOY
  911. empty: ""
  912. second: "! : etc. can be used freely."
  913. third: "a \\\" or a \\\\ must be escaped."
  914. fourth: "this value ends with an LF.\\n"
  915. span: "this contains
  916. four \\
  917. spaces"
  918. is equal to: "this contains four spaces"
  919. EOY
  920. )
  921. end
  922. def test_spec_builtin_time
  923. # Time
  924. assert_parse_only(
  925. { "space separated" => mktime( 2001, 12, 14, 21, 59, 43, ".10", "-05:00" ),
  926. "canonical" => mktime( 2001, 12, 15, 2, 59, 43, ".10" ),
  927. "date (noon UTC)" => Date.new( 2002, 12, 14),
  928. "valid iso8601" => mktime( 2001, 12, 14, 21, 59, 43, ".10", "-05:00" ) }, <<EOY
  929. canonical: 2001-12-15T02:59:43.1Z
  930. valid iso8601: 2001-12-14t21:59:43.10-05:00
  931. space separated: 2001-12-14 21:59:43.10 -05:00
  932. date (noon UTC): 2002-12-14
  933. EOY
  934. )
  935. end
  936. def test_spec_builtin_binary
  937. arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005, \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;"
  938. assert_parse_only(
  939. { 'canonical' => arrow_gif, 'base64' => arrow_gif,
  940. 'description' => "The binary value above is a tiny arrow encoded as a gif image.\n" }, <<EOY
  941. canonical: !binary "\\
  942. R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf\\
  943. n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW\\
  944. NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++\\
  945. f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg\\
  946. d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN\\
  947. AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww\\
  948. EeECcgggoBADs="
  949. base64: !binary |
  950. R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf
  951. n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW
  952. NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++
  953. f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg
  954. d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN
  955. AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww
  956. EeECcgggoBADs=
  957. description: >
  958. The binary value above is a tiny arrow
  959. encoded as a gif image.
  960. EOY
  961. )
  962. end
  963. def test_ruby_regexp
  964. # Test Ruby regular expressions
  965. assert_to_yaml(
  966. { 'simple' => /a.b/, 'complex' => %r'\A"((?:[^"]|\")+)"',
  967. 'case-insensitive' => /George McFly/i }, <<EOY
  968. case-insensitive: !ruby/regexp "/George McFly/i"
  969. complex: !ruby/regexp "/\\\\A\\"((?:[^\\"]|\\\\\\")+)\\"/"
  970. simple: !ruby/regexp "/a.b/"
  971. EOY
  972. )
  973. end
  974. #
  975. # Test of Ranges
  976. #
  977. def test_ranges
  978. # Simple numeric
  979. assert_to_yaml( 1..3, <<EOY )
  980. --- !ruby/range 1..3
  981. EOY
  982. # Simple alphabetic
  983. assert_to_yaml( 'a'..'z', <<EOY )
  984. --- !ruby/range a..z
  985. EOY
  986. # Float
  987. assert_to_yaml( 10.5...30.3, <<EOY )
  988. --- !ruby/range 10.5...30.3
  989. EOY
  990. end
  991. def test_ruby_struct
  992. # Ruby structures
  993. book_struct = Struct::new( "BookStruct", :author, :title, :year, :isbn )
  994. assert_to_yaml(
  995. [ book_struct.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" ),
  996. book_struct.new( [ 'Dave Thomas', 'Andy Hunt' ], "The Pickaxe", 2002,
  997. book_struct.new( "This should be the ISBN", "but I have another struct here", 2002, "None" )
  998. ) ], <<EOY
  999. - !ruby/struct:BookStruct
  1000. author: Yukihiro Matsumoto
  1001. title: Ruby in a Nutshell
  1002. year: 2002
  1003. isbn: 0-596-00214-9
  1004. - !ruby/struct:BookStruct
  1005. author:
  1006. - Dave Thomas
  1007. - Andy Hunt
  1008. title: The Pickaxe
  1009. year: 2002
  1010. isbn: !ruby/struct:BookStruct
  1011. author: This should be the ISBN
  1012. title: but I have another struct here
  1013. year: 2002
  1014. isbn: None
  1015. EOY
  1016. )
  1017. assert_to_yaml( YAML_Tests::StructTest.new( 123 ), <<EOY )
  1018. --- !ruby/struct:YAML_Tests::StructTest
  1019. c: 123
  1020. EOY
  1021. end
  1022. def test_emitting_indicators
  1023. assert_to_yaml( "Hi, from Object 1. You passed: please, pretty please", <<EOY
  1024. --- "Hi, from Object 1. You passed: please, pretty please"
  1025. EOY
  1026. )
  1027. end
  1028. #
  1029. # Test the YAML::Stream class -- INACTIVE at the moment
  1030. #
  1031. def test_document
  1032. y = YAML::Stream.new( :Indent => 2, :UseVersion => 0 )
  1033. y.add(
  1034. { 'hi' => 'hello', 'map' =>
  1035. { 'good' => 'two' },
  1036. 'time' => Time.now,
  1037. 'try' => /^po(.*)$/,
  1038. 'bye' => 'goodbye'
  1039. }
  1040. )
  1041. y.add( { 'po' => 'nil', 'oper' => 90 } )
  1042. y.add( { 'hi' => 'wow!', 'bye' => 'wow!' } )
  1043. y.add( { [ 'Red Socks', 'Boston' ] => [ 'One', 'Two', 'Three' ] } )
  1044. y.add( [ true, false, false ] )
  1045. end
  1046. #
  1047. # Test YPath choices parsing
  1048. #
  1049. def test_ypath_parsing
  1050. assert_path_segments( "/*/((one|three)/name|place)|//place",
  1051. [ ["*", "one", "name"],
  1052. ["*", "three", "name"],
  1053. ["*", "place"],
  1054. ["/", "place"] ]
  1055. )
  1056. end
  1057. #
  1058. # Tests from Tanaka Akira on [ruby-core]
  1059. #
  1060. def test_akira
  1061. # Commas in plain scalars [ruby-core:1066]
  1062. assert_to_yaml(
  1063. {"A"=>"A,","B"=>"B"}, <<EOY
  1064. A: "A,"
  1065. B: B
  1066. EOY
  1067. )
  1068. # Double-quoted keys [ruby-core:1069]
  1069. assert_to_yaml(
  1070. {"1"=>2, "2"=>3}, <<EOY
  1071. '1': 2
  1072. "2": 3
  1073. EOY
  1074. )
  1075. # Anchored mapping [ruby-core:1071]
  1076. assert_to_yaml(
  1077. [{"a"=>"b"}] * 2, <<EOY
  1078. - &id001
  1079. a: b
  1080. - *id001
  1081. EOY
  1082. )
  1083. # Stress test [ruby-core:1071]
  1084. # a = []; 1000.times { a << {"a"=>"b", "c"=>"d"} }
  1085. # YAML::load( a.to_yaml )
  1086. end
  1087. #
  1088. # Test Time.now cycle
  1089. #
  1090. def test_time_now_cycle
  1091. #
  1092. # From Minero Aoki [ruby-core:2305]
  1093. #
  1094. require 'yaml'
  1095. t = Time.now
  1096. 5.times do
  1097. assert_cycle(t)
  1098. end
  1099. end
  1100. #
  1101. # Test Range cycle
  1102. #
  1103. def test_range_cycle
  1104. #
  1105. # From Minero Aoki [ruby-core:02306]
  1106. #
  1107. assert_cycle("a".."z")
  1108. #
  1109. # From Nobu Nakada [ruby-core:02311]
  1110. #
  1111. assert_cycle(0..1)
  1112. assert_cycle(1.0e20 .. 2.0e20)
  1113. assert_cycle("0".."1")
  1114. assert_cycle(".."..."...")
  1115. assert_cycle(".rb"..".pl")
  1116. assert_cycle(".rb"...".pl")
  1117. assert_cycle('"'...".")
  1118. assert_cycle("'"...".")
  1119. end
  1120. #
  1121. # Circular references
  1122. #
  1123. def test_circular_references
  1124. a = []; a[0] = a; a[1] = a
  1125. inspect_str = "[[...], [...]]"
  1126. assert_equal( inspect_str, YAML::load( a.to_yaml ).inspect )
  1127. end
  1128. #
  1129. # Test Symbol cycle
  1130. #
  1131. def test_symbol_cycle
  1132. #
  1133. # From Aaron Schrab [ruby-Bugs:2535]
  1134. #
  1135. assert_cycle(:"^foo")
  1136. end
  1137. #
  1138. # Test Numeric cycle
  1139. #
  1140. class NumericTest < Numeric
  1141. def initialize(value)
  1142. @value = value
  1143. end
  1144. def ==(other)
  1145. @value == other.instance_eval{ @value }
  1146. end
  1147. end
  1148. def test_numeric_cycle
  1149. assert_cycle(1) # Fixnum
  1150. assert_cycle(111111111111111111111111111111111) # Bignum
  1151. assert_cycle(NumericTest.new(3)) # Subclass of Numeric
  1152. end
  1153. #
  1154. # Test empty map/seq in map cycle
  1155. #
  1156. def test_empty_map_key
  1157. #
  1158. # empty seq as key
  1159. #
  1160. o = YAML.load({[]=>""}.to_yaml)
  1161. assert_equal(Hash, o.class)
  1162. assert_equal([[]], o.keys)
  1163. #
  1164. # empty map as key
  1165. #
  1166. o = YAML.load({{}=>""}.to_yaml)
  1167. assert_equal(Hash, o.class)
  1168. assert_equal([{}], o.keys)
  1169. end
  1170. end
  1171. if $0 == __FILE__
  1172. suite = Test::Unit::TestSuite.new('YAML')
  1173. ObjectSpace.each_object(Class) do |klass|
  1174. suite << klass.suite if (Test::Unit::TestCase > klass)
  1175. end
  1176. require 'test/unit/ui/console/testrunner'
  1177. Test::Unit::UI::Console::TestRunner.run(suite).passed?
  1178. end