/ test / tnative.nim
tnative.nim
  1  #            NimYAML - YAML implementation in Nim
  2  #        (c) Copyright 2015-2023 Felix Krause
  3  #
  4  #    See the file "copying.txt", included in this
  5  #    distribution, for details about the copyright.
  6  
  7  import "../yaml"
  8  import unittest, strutils, tables, times, math, options
  9  import commonTestUtils
 10  
 11  type
 12    MyTuple = tuple
 13      str: string
 14      i: int32
 15      b: bool
 16  
 17    TrafficLight = enum
 18      tlGreen, tlYellow, tlRed
 19  
 20    Person = object
 21      firstnamechar: char
 22      surname: string
 23      age: int32
 24  
 25    Node = object
 26      value: string
 27      next: ref Node
 28  
 29    BetterInt = distinct int
 30  
 31    AnimalKind = enum
 32      akCat, akDog
 33  
 34    Animal = object
 35      name: string
 36      case kind: AnimalKind
 37      of akCat:
 38        purringIntensity: float
 39      of akDog: barkometer: int
 40  
 41    DumbEnum = enum
 42      deA, deB, deC
 43  
 44    NonVariantWithTransient = object
 45      a {.transient.}, b, c {.transient.}, d: string
 46  
 47    VariantWithTransient = object
 48      gStorable: string
 49      gTemporary {.transient.}: string
 50      case kind: DumbEnum
 51      of deA:
 52        cStorable: string
 53        cTemporary {.transient.}: string
 54      of deB:
 55        alwaysThere: int
 56      of deC:
 57        neverThere {.transient.}: int
 58  
 59    WithDefault = object
 60      a, b {.defaultVal: "b".}, c, d {.defaultVal: "d".}: string
 61  
 62    WithIgnoredField {.ignore: ["z"].} = object
 63      x, y: int
 64  
 65    Parent = object of RootObj
 66      i*: int
 67    Child = object of Parent
 68      s*: string
 69      
 70    AsFlow {.collection: csFlow.} = object
 71      a* {.scalar: ssSingleQuoted.}: string
 72      b* {.scalar: ssDoubleQuoted.}: string
 73      c* {.scalar: ssPlain.}: string
 74    
 75    OverrideColStyle = object
 76      flowChild: AsFlow
 77      blockChild {.collection: csBlock.}: AsFlow
 78  
 79  proc `$`(v: BetterInt): string {.borrow.}
 80  proc `==`(left, right: BetterInt): bool {.borrow.}
 81  
 82  setTag(TrafficLight, Tag("!tl"))
 83  setTag(Node, Tag("!example.net:Node"))
 84  setTag(BetterInt, Tag("!test:BetterInt"))
 85  
 86  const yamlDir = "---"
 87  const yamlTagDirs = "%TAG !n! tag:nimyaml.org,2016:\n---"
 88  
 89  proc representObject*(
 90    ctx  : var SerializationContext,
 91    value: BetterInt,
 92    tag  : Tag
 93  ) {.raises: [].} =
 94    var
 95      val = $value
 96      i = val.len - 3
 97    while i > 0:
 98      val.insert("_", i)
 99      i -= 3
100    ctx.put(scalarEvent(val, tag, yAnchorNone))
101  
102  proc constructObject*(
103    ctx   : var ConstructionContext,
104    result: var BetterInt,
105  ) {.raises: [YamlConstructionError, YamlStreamError].} =
106    ctx.input.constructScalarItem(item, BetterInt):
107      result = BetterInt(parseBiggestInt(item.scalarContent) + 1)
108  
109  template expectConstructionError(li, co: int, message: string, body: typed) =
110    try:
111      body
112      echo "Expected YamlConstructionError, but none was raised!"
113      fail()
114    except YamlConstructionError as e:
115      doAssert li == e.mark.line, "Expected error line " & $li & ", was " & $e.mark.line
116      doAssert co == e.mark.column, "Expected error column " & $co & ", was " & $e.mark.column
117      doAssert message == e.msg, "Expected error message \n" & escape(message) &
118          ", got \n" & escape(e.msg)
119  
120  proc newNode(v: string): ref Node =
121    new(result)
122    result.value = v
123    result.next = nil
124  
125  template dualTest(name: string, body: untyped) =
126    test name:
127      body
128  
129    # fix for compiler problem (comptime doesn't work when included from tests.nim)
130    # possibly this issue: https://github.com/nim-lang/Nim/issues/18103
131    when isMainModule:
132      test name & " [comptime]":
133        static: body
134  
135  suite "Serialization":
136    dualTest "Load integer without fixed length":
137      var input = "-4247"
138      var result: int
139      load(input, result)
140      assert result == -4247, "result is " & $result
141  
142      input = $(int64(int32.high) + 1'i64)
143      var gotException = false
144      try: load(input, result)
145      except YamlConstructionError: gotException = true
146      assert gotException, "Expected exception, got none."
147  
148    test "Dump integer without fixed length":
149      var input = -4247
150      var output = blockOnlyDumper().dump(input)
151      assertStringEqual  "\"-4247\"\n", output
152  
153      when sizeof(int) == sizeof(int64):
154        input = int(int32.high) + 1
155        var gotException = false
156        try: output = blockOnlyDumper().dump(input)
157        except YamlSerializationError: gotException = true
158        assert gotException, "Expected exception, got none."
159  
160    dualTest "Load Hex byte (0xFF)":
161      let input = "0xFF"
162      var result: byte
163      load(input, result)
164      assert(result == 255)
165  
166    dualTest "Load Hex byte (0xC)":
167      let input = "0xC"
168      var result: byte
169      load(input, result)
170      assert(result == 12)
171  
172    dualTest "Load Octal byte (0o14)":
173      let input = "0o14"
174      var result: byte
175      load(input, result)
176      assert(result == 12)
177  
178    dualTest "Load byte (14)":
179      let input = "14"
180      var result: byte
181      load(input, result)
182      assert(result == 14)
183  
184    dualTest "Load Hex int (0xFF)":
185      let input = "0xFF"
186      var result: int
187      load(input, result)
188      assert(result == 255)
189  
190    dualTest "Load Hex int (0xC)":
191      let input = "0xC"
192      var result: int
193      load(input, result)
194      assert(result == 12)
195  
196    dualTest "Load Octal int (0o14)":
197      let input = "0o14"
198      var result: int
199      load(input, result)
200      assert(result == 12)
201  
202    dualTest "Load int (14)":
203      let input = "14"
204      var result: int
205      load(input, result)
206      assert(result == 14)
207  
208    dualTest "Load floats":
209      let input = "[6.8523015e+5, 685.230_15e+03, 685_230.15, -.inf, .NaN]"
210      var result: seq[float]
211      load(input, result)
212      for i in 0..2:
213        assert result[i] == 6.8523015e+5
214      assert result[3] == NegInf
215      assert classify(result[4]) == fcNan
216  
217    test "Load timestamps":
218      let input = "[2001-12-15T02:59:43.1Z, 2001-12-14t21:59:43.10-05:00, 2001-12-14 21:59:43.10-5]"
219      var result: seq[Time]
220      load(input, result)
221      assert result.len() == 3
222      # currently, there is no good way of checking the result content, because
223      # the parsed Time may have any timezone offset.
224  
225    dualTest "Load string sequence":
226      let input = " - a\n - b"
227      var result: seq[string]
228      load(input, result)
229      assert result.len == 2
230      assert result[0] == "a"
231      assert result[1] == "b"
232  
233    test "Dump string sequence":
234      var input = @["a", "b"]
235      var output = blockOnlyDumper().dump(input)
236      assertStringEqual "- a\n- b\n", output
237  
238    dualTest "Load char set":
239      let input = "- a\n- b"
240      var result: set[char]
241      load(input, result)
242      assert result.card == 2
243      assert 'a' in result
244      assert 'b' in result
245  
246    test "Dump char set":
247      var input = {'a', 'b'}
248      var output = blockOnlyDumper().dump(input)
249      assertStringEqual "- a\n- b\n", output
250  
251    dualTest "Load array":
252      let input = "- 23\n- 42\n- 47"
253      var result: array[0..2, int32]
254      load(input, result)
255      assert result[0] == 23
256      assert result[1] == 42
257      assert result[2] == 47
258  
259    test "Dump array":
260      let input = [23'i32, 42'i32, 47'i32]
261      var output = blockOnlyDumper().dump(input)
262      assertStringEqual "- 23\n- 42\n- 47\n", output
263  
264    dualTest "Load Option":
265      let input = "- Some\n- !!null ~"
266      var result: array[0..1, Option[string]]
267      load(input, result)
268      assert result[0].isSome
269      assert result[0].get() == "Some"
270      assert not result[1].isSome
271  
272    test "Dump Option":
273      let input = [none(int32), some(42'i32), none(int32)]
274      let output = blockOnlyDumper().dump(input)
275      assertStringEqual "- !!null ~\n- 42\n- !!null ~\n", output
276    
277    dualTest "Load Option of seq":
278      let input = "- !!null\n- [a, b]"
279      var result: array[0..1, Option[seq[string]]]
280      load(input, result)
281      assert not result[0].isSome
282      assert result[1].get()[0] == "a"
283      assert result[1].get()[1] == "b"
284    
285    test "Dump Option of seq":
286      let input = [none(seq[string]), some(@["a", "b"])]
287      let output = Dumper().dump(input)
288      assertStringEqual "- !!null ~\n- [a, b]\n", output
289  
290    dualTest "Load Table[int, string]":
291      let input = "23: dreiundzwanzig\n42: zweiundvierzig"
292      var result: Table[int32, string]
293      load(input, result)
294      assert result.len == 2
295      assert result[23] == "dreiundzwanzig"
296      assert result[42] == "zweiundvierzig"
297  
298    test "Dump Table[int, string]":
299      var input = initTable[int32, string]()
300      input[23] = "dreiundzwanzig"
301      input[42] = "zweiundvierzig"
302      var output = blockOnlyDumper().dump(input)
303      assertStringEqual("23: dreiundzwanzig\n42: zweiundvierzig\n",
304          output)
305  
306    dualTest "Load OrderedTable[tuple[int32, int32], string]":
307      let input = "- {a: 23, b: 42}: drzw\n- {a: 13, b: 47}: drsi"
308      var result: OrderedTable[tuple[a, b: int32], string]
309      load(input, result)
310      var i = 0
311      for key, value in result.pairs:
312        case i
313        of 0:
314          assert key == (a: 23'i32, b: 42'i32)
315          assert value == "drzw"
316        of 1:
317          assert key == (a: 13'i32, b: 47'i32)
318          assert value == "drsi"
319        else: assert false
320        i.inc()
321  
322    test "Dump OrderedTable[tuple[int32, int32], string]":
323      var input = initOrderedTable[tuple[a, b: int32], string]()
324      input[(a: 23'i32, b: 42'i32)] = "dreiundzwanzigzweiundvierzig"
325      input[(a: 13'i32, b: 47'i32)] = "dreizehnsiebenundvierzig"
326      var dumper = blockOnlyDumper()
327      dumper.serialization.tagStyle = tsRootOnly
328      dumper.serialization.handles = initNimYamlTagHandle()
329      var output = dumper.dump(input)
330      assertStringEqual(yamlTagDirs &
331          " !n!tables:OrderedTable(tag:nimyaml.org;2016:tuple(tag:nimyaml.org;2016:system:int32;tag:nimyaml.org;2016:system:int32);tag:yaml.org;2002:str)\n" &
332          "- ? a: 23\n" &
333          "    b: 42\n" &
334          "  : dreiundzwanzigzweiundvierzig\n" &
335          "- ? a: 13\n" &
336          "    b: 47\n" &
337          "  : dreizehnsiebenundvierzig\n", output)
338  
339    dualTest "Load Sequences in Sequence":
340      let input = " - [1, 2, 3]\n - [4, 5]\n - [6]"
341      var result: seq[seq[int32]]
342      load(input, result)
343      assert result.len == 3
344      assert result[0] == @[1.int32, 2.int32, 3.int32]
345      assert result[1] == @[4.int32, 5.int32]
346      assert result[2] == @[6.int32]
347  
348    test "Dump Sequences in Sequence":
349      let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], @[6.int32]]
350      var output = Dumper().dump(input)
351      assertStringEqual "- [1, 2, 3]\n- [4, 5]\n- [6]\n", output
352  
353    dualTest "Load Enum":
354      let input =
355        "!<tag:nimyaml.org,2016:system:seq(tl)>\n- !tl tlRed\n- tlGreen\n- tlYellow"
356      var result: seq[TrafficLight]
357      load(input, result)
358      assert result.len == 3
359      assert result[0] == tlRed
360      assert result[1] == tlGreen
361      assert result[2] == tlYellow
362  
363    test "Dump Enum":
364      let input = @[tlRed, tlGreen, tlYellow]
365      var output = blockOnlyDumper().dump(input)
366      assertStringEqual "- tlRed\n- tlGreen\n- tlYellow\n", output
367  
368    dualTest "Load Tuple":
369      let input = "str: value\ni: 42\nb: true"
370      var result: MyTuple
371      load(input, result)
372      assert result.str == "value"
373      assert result.i == 42
374      assert result.b == true
375  
376    test "Dump Tuple":
377      let input = (str: "value", i: 42.int32, b: true)
378      var output = Dumper().dump(input)
379      assertStringEqual "str: value\ni: 42\nb: true\n", output
380  
381    test "Load Tuple - unknown field":
382      let input = "str: value\nfoo: bar\ni: 42\nb: true"
383      var result: MyTuple
384      expectConstructionError(2, 1, "While constructing MyTuple: Unknown field: \"foo\""):
385        load(input, result)
386  
387    test "Load Tuple - missing field":
388      let input = "str: value\nb: true"
389      var result: MyTuple
390      expectConstructionError(1, 1, "While constructing MyTuple: Missing field: \"i\""):
391        load(input, result)
392  
393    test "Load Tuple - duplicate field":
394      let input = "str: value\ni: 42\nb: true\nb: true"
395      var result: MyTuple
396      expectConstructionError(4, 1, "While constructing MyTuple: Duplicate field: \"b\""):
397        load(input, result)
398  
399    dualTest "Load Multiple Documents":
400      let input = "1\n---\n2"
401      var result: seq[int]
402      loadMultiDoc(input, result)
403      assert(result.len == 2)
404      assert result[0] == 1
405      assert result[1] == 2
406  
407    dualTest "Load Multiple Documents (Single Doc)":
408      let input = "1"
409      var result: seq[int]
410      loadMultiDoc(input, result)
411      assert(result.len == 1)
412      assert result[0] == 1
413  
414    dualTest "Load custom object":
415      let input = "firstnamechar: P\nsurname: Pan\nage: 12"
416      var result: Person
417      load(input, result)
418      assert result.firstnamechar == 'P'
419      assert result.surname == "Pan"
420      assert result.age == 12
421  
422    test "Dump custom object":
423      let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
424      var output = blockOnlyDumper().dump(input)
425      assertStringEqual(
426          "firstnamechar: P\nsurname: Pan\nage: 12\n", output)
427  
428    test "Load custom object - unknown field":
429      let input = "  firstnamechar: P\n  surname: Pan\n  age: 12\n  occupation: free"
430      var result: Person
431      expectConstructionError(4, 3, "While constructing Person: Unknown field: \"occupation\""):
432        load(input, result)
433  
434    test "Load custom object - missing field":
435      let input = "surname: Pan\nage: 12\n  "
436      var result: Person
437      expectConstructionError(1, 1, "While constructing Person: Missing field: \"firstnamechar\""):
438        load(input, result)
439  
440    test "Load custom object - duplicate field":
441      let input = "firstnamechar: P\nsurname: Pan\nage: 12\nsurname: Pan"
442      var result: Person
443      expectConstructionError(4, 1, "While constructing Person: Duplicate field: \"surname\""):
444        load(input, result)
445  
446    dualTest "Load sequence with explicit tags":
447      let input = yamlTagDirs & " !n!system:seq(" &
448          "tag:yaml.org;2002:str)\n- !!str one\n- !!str two"
449      var result: seq[string]
450      load(input, result)
451      assert result[0] == "one"
452      assert result[1] == "two"
453  
454    test "Dump sequence with explicit tags":
455      let input = @["one", "two"]
456      var dumper = blockOnlyDumper()
457      dumper.serialization.tagStyle = tsAll
458      dumper.serialization.handles = initNimYamlTagHandle()
459      var output = dumper.dump(input)
460      assertStringEqual(yamlTagDirs & " !n!system:seq(" &
461          "tag:yaml.org;2002:str)\n- !!str one\n- !!str two\n", output)
462  
463    dualTest "Load custom object with explicit root tag":
464      let input =
465          "--- !<tag:nimyaml.org,2016:custom:Person>\nfirstnamechar: P\nsurname: Pan\nage: 12"
466      var result: Person
467      load(input, result)
468      assert result.firstnamechar == 'P'
469      assert result.surname == "Pan"
470      assert result.age == 12
471  
472    test "Dump custom object with explicit root tag":
473      let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
474      var dumper = blockOnlyDumper()
475      dumper.serialization.tagStyle = tsRootOnly
476      dumper.serialization.handles = initNimYamlTagHandle()
477      var output = dumper.dump(input)
478      assertStringEqual(yamlTagDirs &
479          " !n!custom:Person\nfirstnamechar: P\nsurname: Pan\nage: 12\n", output)
480  
481    dualTest "Load object with inherited fields":
482      let input =
483        "i: 4\ns: hello"
484      var result: Child
485      load(input, result)
486      assert result.i == 4
487      assert result.s == "hello"
488  
489    dualTest "Load custom variant object":
490      let input =
491        "---\n- - name: Bastet\n  - kind: akCat\n  - purringIntensity: 7.2\n" &
492        "- - name: Anubis\n  - kind: akDog\n  - barkometer: 13"
493      var result: seq[Animal]
494      load(input, result)
495      assert result.len == 2
496      assert result[0].name == "Bastet"
497      assert result[0].kind == akCat
498      assert abs(result[0].purringIntensity - 7.2) < 1E-7
499      assert result[1].name == "Anubis"
500      assert result[1].kind == akDog
501      assert result[1].barkometer == 13
502  
503    test "Dump custom variant object":
504      let input = @[Animal(name: "Bastet", kind: akCat, purringIntensity: 7.2),
505                    Animal(name: "Anubis", kind: akDog, barkometer: 13)]
506      var output = blockOnlyDumper().dump(input)
507      assertStringEqual "" &
508          "- - name: Bastet\n" &
509          "  - kind: akCat\n" &
510          "  - purringIntensity: 7.2\n" &
511          "- - name: Anubis\n" &
512          "  - kind: akDog\n" &
513          "  - barkometer: 13\n", output
514  
515    test "Load custom variant object - missing field":
516      let input = "[{name: Bastet}, {kind: akCat}]"
517      var result: Animal
518      expectConstructionError(1, 1, "While constructing Animal: Missing field: \"purringIntensity\""):
519        load(input, result)
520  
521    dualTest "Load non-variant object with transient fields":
522      let input = "{b: b, d: d}"
523      var result: NonVariantWithTransient
524      load(input, result)
525      assert result.a.len == 0
526      assert result.b == "b"
527      assert result.c.len == 0
528      assert result.d == "d"
529  
530    test "Load non-variant object with transient fields - unknown field":
531      let input = "{b: b, c: c, d: d}"
532      var result: NonVariantWithTransient
533      expectConstructionError(1, 8, "While constructing NonVariantWithTransient: Field \"c\" is transient and may not occur in input"):
534        load(input, result)
535  
536    test "Dump non-variant object with transient fields":
537      let input = NonVariantWithTransient(a: "a", b: "b", c: "c", d: "d")
538      let output = blockOnlyDumper().dump(input)
539      assertStringEqual "b: b\nd: d\n", output
540  
541    dualTest "Load variant object with transient fields":
542      let input = "[[gStorable: gs, kind: deA, cStorable: cs], [gStorable: a, kind: deC]]"
543      var result: seq[VariantWithTransient]
544      load(input, result)
545      assert result.len == 2
546      assert result[0].kind == deA
547      assert result[0].gStorable == "gs"
548      assert result[0].cStorable == "cs"
549      assert result[1].kind == deC
550      assert result[1].gStorable == "a"
551  
552    test "Load variant object with transient fields, error":
553      let input = "[gStorable: gc, kind: deC, neverThere: foo]"
554      var result: VariantWithTransient
555      expectConstructionError(1, 28, "While constructing VariantWithTransient: Field \"neverThere\" is transient and may not occur in input"):
556        load(input, result)
557  
558    test "Dump variant object with transient fields":
559      let input = @[VariantWithTransient(kind: deA, gStorable: "gs",
560          gTemporary: "gt", cStorable: "cs", cTemporary: "ct"),
561          VariantWithTransient(kind: deC, gStorable: "a", gTemporary: "b",
562          neverThere: 42)]
563      let output = blockOnlyDumper().dump(input)
564      assertStringEqual "" &
565          "- - gStorable: gs\n" &
566          "  - kind: deA\n" &
567          "  - cStorable: cs\n" &
568          "- - gStorable: a\n" &
569          "  - kind: deC\n", output
570  
571    dualTest "Load object with ignored key":
572      let input = "[{x: 1, y: 2}, {x: 3, z: 4, y: 5}, {z: [1, 2, 3], x: 4, y: 5}]"
573      var result: seq[WithIgnoredField]
574      load(input, result)
575      assert result.len == 3
576      assert result[0].x == 1
577      assert result[0].y == 2
578      assert result[1].x == 3
579      assert result[1].y == 5
580      assert result[2].x == 4
581      assert result[2].y == 5
582  
583    test "Load object with ignored key - unknown field":
584      let input = "{x: 1, y: 2, zz: 3}"
585      var result: WithIgnoredField
586      expectConstructionError(1, 14, "While constructing WithIgnoredField: Unknown field: \"zz\""):
587        load(input, result)
588  
589    when not defined(JS):
590      test "Dump cyclic data structure":
591        var
592          a = newNode("a")
593          b = newNode("b")
594          c = newNode("c")
595        a.next = b
596        b.next = c
597        c.next = a
598        var dumper = blockOnlyDumper()
599        dumper.serialization.tagStyle = tsRootOnly
600        var output = dumper.dump(a)
601        assertStringEqual yamlDir & " !example.net:Node &a\n" &
602            "value: a\n" &
603            "next:\n" &
604            "  value: b\n" &
605            "  next:\n" &
606            "    value: c\n" &
607            "    next: *a\n", output
608  
609      test "Load cyclic data structure":
610        let input = yamlTagDirs & """ !n!system:seq(example.net:Node)
611    - &a
612      value: a
613      next: &b
614        value: b
615        next: &c
616          value: c
617          next: *a
618    - *b
619    - *c
620    """
621        var result: seq[ref Node]
622        try: load(input, result)
623        except YamlConstructionError:
624          let ex = (ref YamlConstructionError)(getCurrentException())
625          echo "line ", ex.mark.line, ", column ", ex.mark.column, ": ", ex.msg
626          echo ex.lineContent
627          raise ex
628  
629        assert(result.len == 3)
630        assert(result[0].value == "a")
631        assert(result[1].value == "b")
632        assert(result[2].value == "c")
633        assert(result[0].next == result[1])
634        assert(result[1].next == result[2])
635        assert(result[2].next == result[0])
636  
637    dualTest "Load object with default values":
638      let input = "a: abc\nc: dce"
639      var result: WithDefault
640      load(input, result)
641      assert result.a == "abc"
642      assert result.b == "b"
643      assert result.c == "dce"
644      assert result.d == "d"
645  
646    dualTest "Load object with partly default values":
647      let input = "a: abc\nb: bcd\nc: cde"
648      var result: WithDefault
649      load(input, result)
650      assert result.a == "abc"
651      assert result.b == "bcd"
652      assert result.c == "cde"
653      assert result.d == "d"
654  
655    dualTest "Custom constructObject":
656      let input = "- 1\n- !test:BetterInt 2"
657      var result: seq[BetterInt]
658      load(input, result)
659      assert(result.len == 2)
660      assert(result[0] == 2.BetterInt)
661      assert(result[1] == 3.BetterInt)
662  
663    test "Custom representObject":
664      let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt]
665      var dumper = blockOnlyDumper()
666      dumper.serialization.tagStyle = tsAll
667      dumper.serialization.handles = initNimYamlTagHandle()
668      var output = dumper.dump(input)
669      assertStringEqual yamlTagDirs & " !n!system:seq(test:BetterInt)\n" &
670          "- !test:BetterInt 1\n" &
671          "- !test:BetterInt 9_998_887\n" &
672          "- !test:BetterInt 98_312\n", output
673  
674    test "Representation pragmas":
675      let input = OverrideColStyle(
676        flowChild: AsFlow(a: "abc", b: "abc", c: "abc"),
677        blockChild: AsFlow(a: "a\nc", b: "abc", c: "ab:")
678      )
679      var dumper = blockOnlyDumper()
680      dumper.presentation.maxLineLength = some(20)
681      var output = dumper.dump(input)
682      assertStringEqual "flowChild: {\n" &
683        "    a: 'abc',\n" &
684        "    b: \"abc\",\n" &
685        "    c: abc\n" &
686        "  }\n" &
687        "blockChild:\n" &
688        "  a: \"a\\nc\"\n" &
689        "  b: \"abc\"\n" &
690        "  c: \"ab:\"\n", output
691