// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "message.h"
#include "dynamic.h"
#include "pretty-print.h"
#include <kj/debug.h>
#include <kj/compat/gtest.h>
#include "test-util.h"

namespace capnp {
namespace _ {  // private
namespace {

TEST(Stringify, KjStringification) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<TestAllTypes>();

  // This test got ugly after printing was changed to always print primitives even when they have
  // default values...

  EXPECT_EQ("("
      "voidField = void, "
      "boolField = false, "
      "int8Field = 0, "
      "int16Field = 0, "
      "int32Field = 0, "
      "int64Field = 0, "
      "uInt8Field = 0, "
      "uInt16Field = 0, "
      "uInt32Field = 0, "
      "uInt64Field = 0, "
      "float32Field = 0, "
      "float64Field = 0, "
      "enumField = foo, "
      "interfaceField = void)",
      kj::str(root));

  initTestMessage(root);

  EXPECT_EQ("("
      "voidField = void, "
      "boolField = true, "
      "int8Field = -123, "
      "int16Field = -12345, "
      "int32Field = -12345678, "
      "int64Field = -123456789012345, "
      "uInt8Field = 234, "
      "uInt16Field = 45678, "
      "uInt32Field = 3456789012, "
      "uInt64Field = 12345678901234567890, "
      "float32Field = 1234.5, "
      "float64Field = -1.23e47, "
      "textField = \"foo\", "
      "dataField = \"bar\", "
      "structField = ("
          "voidField = void, "
          "boolField = true, "
          "int8Field = -12, "
          "int16Field = 3456, "
          "int32Field = -78901234, "
          "int64Field = 56789012345678, "
          "uInt8Field = 90, "
          "uInt16Field = 1234, "
          "uInt32Field = 56789012, "
          "uInt64Field = 345678901234567890, "
          "float32Field = -1.25e-10, "
          "float64Field = 345, "
          "textField = \"baz\", "
          "dataField = \"qux\", "
          "structField = ("
              "voidField = void, "
              "boolField = false, "
              "int8Field = 0, "
              "int16Field = 0, "
              "int32Field = 0, "
              "int64Field = 0, "
              "uInt8Field = 0, "
              "uInt16Field = 0, "
              "uInt32Field = 0, "
              "uInt64Field = 0, "
              "float32Field = 0, "
              "float64Field = 0, "
              "textField = \"nested\", "
              "structField = ("
                "voidField = void, "
                "boolField = false, "
                "int8Field = 0, "
                "int16Field = 0, "
                "int32Field = 0, "
                "int64Field = 0, "
                "uInt8Field = 0, "
                "uInt16Field = 0, "
                "uInt32Field = 0, "
                "uInt64Field = 0, "
                "float32Field = 0, "
                "float64Field = 0, "
                "textField = \"really nested\", "
                "enumField = foo, "
                "interfaceField = void), "
              "enumField = foo, "
              "interfaceField = void), "
          "enumField = baz, "
          "interfaceField = void, "
          "voidList = [void, void, void], "
          "boolList = [false, true, false, true, true], "
          "int8List = [12, -34, -128, 127], "
          "int16List = [1234, -5678, -32768, 32767], "
          "int32List = [12345678, -90123456, -2147483648, 2147483647], "
          "int64List = [123456789012345, -678901234567890, "
                       "-9223372036854775808, 9223372036854775807], "
          "uInt8List = [12, 34, 0, 255], "
          "uInt16List = [1234, 5678, 0, 65535], "
          "uInt32List = [12345678, 90123456, 0, 4294967295], "
          "uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615], "
          "float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], "
          "float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], "
          "textList = [\"quux\", \"corge\", \"grault\"], "
          "dataList = [\"garply\", \"waldo\", \"fred\"], "
          "structList = ["
              "("
                "voidField = void, "
                "boolField = false, "
                "int8Field = 0, "
                "int16Field = 0, "
                "int32Field = 0, "
                "int64Field = 0, "
                "uInt8Field = 0, "
                "uInt16Field = 0, "
                "uInt32Field = 0, "
                "uInt64Field = 0, "
                "float32Field = 0, "
                "float64Field = 0, "
                "textField = \"x structlist 1\", "
                "enumField = foo, "
                "interfaceField = void), "
              "("
                "voidField = void, "
                "boolField = false, "
                "int8Field = 0, "
                "int16Field = 0, "
                "int32Field = 0, "
                "int64Field = 0, "
                "uInt8Field = 0, "
                "uInt16Field = 0, "
                "uInt32Field = 0, "
                "uInt64Field = 0, "
                "float32Field = 0, "
                "float64Field = 0, "
                "textField = \"x structlist 2\", "
                "enumField = foo, "
                "interfaceField = void), "
              "("
                "voidField = void, "
                "boolField = false, "
                "int8Field = 0, "
                "int16Field = 0, "
                "int32Field = 0, "
                "int64Field = 0, "
                "uInt8Field = 0, "
                "uInt16Field = 0, "
                "uInt32Field = 0, "
                "uInt64Field = 0, "
                "float32Field = 0, "
                "float64Field = 0, "
                "textField = \"x structlist 3\", "
                "enumField = foo, "
                "interfaceField = void)], "
          "enumList = [qux, bar, grault]), "
      "enumField = corge, "
      "interfaceField = void, "
      "voidList = [void, void, void, void, void, void], "
      "boolList = [true, false, false, true], "
      "int8List = [111, -111], "
      "int16List = [11111, -11111], "
      "int32List = [111111111, -111111111], "
      "int64List = [1111111111111111111, -1111111111111111111], "
      "uInt8List = [111, 222], "
      "uInt16List = [33333, 44444], "
      "uInt32List = [3333333333], "
      "uInt64List = [11111111111111111111], "
      "float32List = [5555.5, inf, -inf, nan], "
      "float64List = [7777.75, inf, -inf, nan], "
      "textList = [\"plugh\", \"xyzzy\", \"thud\"], "
      "dataList = [\"oops\", \"exhausted\", \"rfc3092\"], "
      "structList = ["
          "("
            "voidField = void, "
            "boolField = false, "
            "int8Field = 0, "
            "int16Field = 0, "
            "int32Field = 0, "
            "int64Field = 0, "
            "uInt8Field = 0, "
            "uInt16Field = 0, "
            "uInt32Field = 0, "
            "uInt64Field = 0, "
            "float32Field = 0, "
            "float64Field = 0, "
            "textField = \"structlist 1\", "
            "enumField = foo, "
            "interfaceField = void), "
          "("
            "voidField = void, "
            "boolField = false, "
            "int8Field = 0, "
            "int16Field = 0, "
            "int32Field = 0, "
            "int64Field = 0, "
            "uInt8Field = 0, "
            "uInt16Field = 0, "
            "uInt32Field = 0, "
            "uInt64Field = 0, "
            "float32Field = 0, "
            "float64Field = 0, "
            "textField = \"structlist 2\", "
            "enumField = foo, "
            "interfaceField = void), "
          "("
            "voidField = void, "
            "boolField = false, "
            "int8Field = 0, "
            "int16Field = 0, "
            "int32Field = 0, "
            "int64Field = 0, "
            "uInt8Field = 0, "
            "uInt16Field = 0, "
            "uInt32Field = 0, "
            "uInt64Field = 0, "
            "float32Field = 0, "
            "float64Field = 0, "
            "textField = \"structlist 3\", "
            "enumField = foo, "
            "interfaceField = void)], "
      "enumList = [foo, garply])",
      kj::str(root));
}

TEST(Stringify, PrettyPrint) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<TestAllTypes>();

  EXPECT_EQ(
      "( voidField = void,\n"
      "  boolField = false,\n"
      "  int8Field = 0,\n"
      "  int16Field = 0,\n"
      "  int32Field = 0,\n"
      "  int64Field = 0,\n"
      "  uInt8Field = 0,\n"
      "  uInt16Field = 0,\n"
      "  uInt32Field = 0,\n"
      "  uInt64Field = 0,\n"
      "  float32Field = 0,\n"
      "  float64Field = 0,\n"
      "  enumField = foo,\n"
      "  interfaceField = void )", prettyPrint(root).flatten());

  initTestMessage(root);

  EXPECT_EQ(
      "( voidField = void,\n"
      "  boolField = true,\n"
      "  int8Field = -123,\n"
      "  int16Field = -12345,\n"
      "  int32Field = -12345678,\n"
      "  int64Field = -123456789012345,\n"
      "  uInt8Field = 234,\n"
      "  uInt16Field = 45678,\n"
      "  uInt32Field = 3456789012,\n"
      "  uInt64Field = 12345678901234567890,\n"
      "  float32Field = 1234.5,\n"
      "  float64Field = -1.23e47,\n"
      "  textField = \"foo\",\n"
      "  dataField = \"bar\",\n"
      "  structField = (\n"
      "    voidField = void,\n"
      "    boolField = true,\n"
      "    int8Field = -12,\n"
      "    int16Field = 3456,\n"
      "    int32Field = -78901234,\n"
      "    int64Field = 56789012345678,\n"
      "    uInt8Field = 90,\n"
      "    uInt16Field = 1234,\n"
      "    uInt32Field = 56789012,\n"
      "    uInt64Field = 345678901234567890,\n"
      "    float32Field = -1.25e-10,\n"
      "    float64Field = 345,\n"
      "    textField = \"baz\",\n"
      "    dataField = \"qux\",\n"
      "    structField = (\n"
      "      voidField = void,\n"
      "      boolField = false,\n"
      "      int8Field = 0,\n"
      "      int16Field = 0,\n"
      "      int32Field = 0,\n"
      "      int64Field = 0,\n"
      "      uInt8Field = 0,\n"
      "      uInt16Field = 0,\n"
      "      uInt32Field = 0,\n"
      "      uInt64Field = 0,\n"
      "      float32Field = 0,\n"
      "      float64Field = 0,\n"
      "      textField = \"nested\",\n"
      "      structField = (\n"
      "        voidField = void,\n"
      "        boolField = false,\n"
      "        int8Field = 0,\n"
      "        int16Field = 0,\n"
      "        int32Field = 0,\n"
      "        int64Field = 0,\n"
      "        uInt8Field = 0,\n"
      "        uInt16Field = 0,\n"
      "        uInt32Field = 0,\n"
      "        uInt64Field = 0,\n"
      "        float32Field = 0,\n"
      "        float64Field = 0,\n"
      "        textField = \"really nested\",\n"
      "        enumField = foo,\n"
      "        interfaceField = void ),\n"
      "      enumField = foo,\n"
      "      interfaceField = void ),\n"
      "    enumField = baz,\n"
      "    interfaceField = void,\n"
      "    voidList = [void, void, void],\n"
      "    boolList = [false, true, false, true, true],\n"
      "    int8List = [12, -34, -128, 127],\n"
      "    int16List = [1234, -5678, -32768, 32767],\n"
      "    int32List = [12345678, -90123456, -2147483648, 2147483647],\n"
      "    int64List = [123456789012345, -678901234567890, "
                       "-9223372036854775808, 9223372036854775807],\n"
      "    uInt8List = [12, 34, 0, 255],\n"
      "    uInt16List = [1234, 5678, 0, 65535],\n"
      "    uInt32List = [12345678, 90123456, 0, 4294967295],\n"
      "    uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615],\n"
      "    float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37],\n"
      "    float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306],\n"
      "    textList = [\"quux\", \"corge\", \"grault\"],\n"
      "    dataList = [\"garply\", \"waldo\", \"fred\"],\n"
      "    structList = [\n"
      "      ( voidField = void,\n"
      "        boolField = false,\n"
      "        int8Field = 0,\n"
      "        int16Field = 0,\n"
      "        int32Field = 0,\n"
      "        int64Field = 0,\n"
      "        uInt8Field = 0,\n"
      "        uInt16Field = 0,\n"
      "        uInt32Field = 0,\n"
      "        uInt64Field = 0,\n"
      "        float32Field = 0,\n"
      "        float64Field = 0,\n"
      "        textField = \"x structlist 1\",\n"
      "        enumField = foo,\n"
      "        interfaceField = void ),\n"
      "      ( voidField = void,\n"
      "        boolField = false,\n"
      "        int8Field = 0,\n"
      "        int16Field = 0,\n"
      "        int32Field = 0,\n"
      "        int64Field = 0,\n"
      "        uInt8Field = 0,\n"
      "        uInt16Field = 0,\n"
      "        uInt32Field = 0,\n"
      "        uInt64Field = 0,\n"
      "        float32Field = 0,\n"
      "        float64Field = 0,\n"
      "        textField = \"x structlist 2\",\n"
      "        enumField = foo,\n"
      "        interfaceField = void ),\n"
      "      ( voidField = void,\n"
      "        boolField = false,\n"
      "        int8Field = 0,\n"
      "        int16Field = 0,\n"
      "        int32Field = 0,\n"
      "        int64Field = 0,\n"
      "        uInt8Field = 0,\n"
      "        uInt16Field = 0,\n"
      "        uInt32Field = 0,\n"
      "        uInt64Field = 0,\n"
      "        float32Field = 0,\n"
      "        float64Field = 0,\n"
      "        textField = \"x structlist 3\",\n"
      "        enumField = foo,\n"
      "        interfaceField = void ) ],\n"
      "    enumList = [qux, bar, grault] ),\n"
      "  enumField = corge,\n"
      "  interfaceField = void,\n"
      "  voidList = [void, void, void, void, void, void],\n"
      "  boolList = [true, false, false, true],\n"
      "  int8List = [111, -111],\n"
      "  int16List = [11111, -11111],\n"
      "  int32List = [111111111, -111111111],\n"
      "  int64List = [1111111111111111111, -1111111111111111111],\n"
      "  uInt8List = [111, 222],\n"
      "  uInt16List = [33333, 44444],\n"
      "  uInt32List = [3333333333],\n"
      "  uInt64List = [11111111111111111111],\n"
      "  float32List = [5555.5, inf, -inf, nan],\n"
      "  float64List = [7777.75, inf, -inf, nan],\n"
      "  textList = [\"plugh\", \"xyzzy\", \"thud\"],\n"
      "  dataList = [\"oops\", \"exhausted\", \"rfc3092\"],\n"
      "  structList = [\n"
      "    ( voidField = void,\n"
      "      boolField = false,\n"
      "      int8Field = 0,\n"
      "      int16Field = 0,\n"
      "      int32Field = 0,\n"
      "      int64Field = 0,\n"
      "      uInt8Field = 0,\n"
      "      uInt16Field = 0,\n"
      "      uInt32Field = 0,\n"
      "      uInt64Field = 0,\n"
      "      float32Field = 0,\n"
      "      float64Field = 0,\n"
      "      textField = \"structlist 1\",\n"
      "      enumField = foo,\n"
      "      interfaceField = void ),\n"
      "    ( voidField = void,\n"
      "      boolField = false,\n"
      "      int8Field = 0,\n"
      "      int16Field = 0,\n"
      "      int32Field = 0,\n"
      "      int64Field = 0,\n"
      "      uInt8Field = 0,\n"
      "      uInt16Field = 0,\n"
      "      uInt32Field = 0,\n"
      "      uInt64Field = 0,\n"
      "      float32Field = 0,\n"
      "      float64Field = 0,\n"
      "      textField = \"structlist 2\",\n"
      "      enumField = foo,\n"
      "      interfaceField = void ),\n"
      "    ( voidField = void,\n"
      "      boolField = false,\n"
      "      int8Field = 0,\n"
      "      int16Field = 0,\n"
      "      int32Field = 0,\n"
      "      int64Field = 0,\n"
      "      uInt8Field = 0,\n"
      "      uInt16Field = 0,\n"
      "      uInt32Field = 0,\n"
      "      uInt64Field = 0,\n"
      "      float32Field = 0,\n"
      "      float64Field = 0,\n"
      "      textField = \"structlist 3\",\n"
      "      enumField = foo,\n"
      "      interfaceField = void ) ],\n"
      "  enumList = [foo, garply] )",
      prettyPrint(root).flatten());
}

TEST(Stringify, PrettyPrintAdvanced) {
  MallocMessageBuilder builder;

  {
    auto root = builder.initRoot<test::TestPrintInlineStructs>();

    auto list = root.initStructList(3);
    list[0].setInt32Field(123);
    list[0].setTextField("foo");
    list[1].setInt32Field(456);
    list[1].setTextField("bar");
    list[2].setInt32Field(789);
    list[2].setTextField("baz");

    EXPECT_EQ(
        "( structList = [\n"
        "    (int32Field = 123, textField = \"foo\"),\n"
        "    (int32Field = 456, textField = \"bar\"),\n"
        "    (int32Field = 789, textField = \"baz\") ] )",
        prettyPrint(root).flatten());

    root.setSomeText("foo");

    EXPECT_EQ(
        "( someText = \"foo\",\n"
        "  structList = [\n"
        "    (int32Field = 123, textField = \"foo\"),\n"
        "    (int32Field = 456, textField = \"bar\"),\n"
        "    (int32Field = 789, textField = \"baz\") ] )",
        prettyPrint(root).flatten());
  }

  {
    auto root = builder.initRoot<test::TestLists>();
    auto ll = root.initInt32ListList(3);
    ll.set(0, {123, 456, 789, 1234567890});
    ll.set(1, {234, 567, 891, 1234567890});
    ll.set(2, {345, 678, 912, 1234567890});

    EXPECT_EQ(
        "[ [123, 456, 789, 1234567890],\n"
        "  [234, 567, 891, 1234567890],\n"
        "  [345, 678, 912, 1234567890] ]",
        prettyPrint(ll).flatten());

    EXPECT_EQ(
        "( int32ListList = [\n"
        "    [123, 456, 789, 1234567890],\n"
        "    [234, 567, 891, 1234567890],\n"
        "    [345, 678, 912, 1234567890] ] )",
        prettyPrint(root).flatten());

    root.initList8(0);

    EXPECT_EQ(
        "( list8 = [],\n"
        "  int32ListList = [\n"
        "    [123, 456, 789, 1234567890],\n"
        "    [234, 567, 891, 1234567890],\n"
        "    [345, 678, 912, 1234567890] ] )",
        prettyPrint(root).flatten());

    auto l8 = root.initList8(1);
    l8[0].setF(12);

    EXPECT_EQ(
        "( list8 = [(f = 12)],\n"
        "  int32ListList = [\n"
        "    [123, 456, 789, 1234567890],\n"
        "    [234, 567, 891, 1234567890],\n"
        "    [345, 678, 912, 1234567890] ] )",
        prettyPrint(root).flatten());

    l8 = root.initList8(2);
    l8[0].setF(12);
    l8[1].setF(34);

    EXPECT_EQ(
        "( list8 = [(f = 12), (f = 34)],\n"
        "  int32ListList = [\n"
        "    [123, 456, 789, 1234567890],\n"
        "    [234, 567, 891, 1234567890],\n"
        "    [345, 678, 912, 1234567890] ] )",
        prettyPrint(root).flatten());
  }

  {
    auto root = builder.initRoot<test::TestStructUnion>();

    auto s = root.getUn().initStruct();
    EXPECT_EQ(
        "(un = (struct = ()))",
        prettyPrint(root).flatten());

    s.setSomeText("foo");
    EXPECT_EQ(
        "( un = (\n"
        "    struct = (someText = \"foo\") ) )",
        prettyPrint(root).flatten());

    s.setMoreText("baaaaaaaaaaaaaaaaaaaaaaaaaaaaaar");
    EXPECT_EQ(
        "( un = (\n"
        "    struct = (\n"
        "      someText = \"foo\",\n"
        "      moreText = \"baaaaaaaaaaaaaaaaaaaaaaaaaaaaaar\" ) ) )",
        prettyPrint(root).flatten());
  }
}

TEST(Stringify, Unions) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<TestUnion>();

  root.getUnion0().setU0f0s16(123);
  root.getUnion1().setU1f0sp("foo");
  root.getUnion2().setU2f0s1(true);
  root.getUnion3().setU3f0s64(123456789012345678ll);

  EXPECT_EQ("("
      "union0 = (u0f0s16 = 123), "
      "union1 = (u1f0sp = \"foo\"), "
      "union2 = (u2f0s1 = true), "
      "union3 = (u3f0s64 = 123456789012345678), "
      "bit0 = false, bit2 = false, bit3 = false, bit4 = false, bit5 = false, "
      "bit6 = false, bit7 = false, byte0 = 0)",
      kj::str(root));

  EXPECT_EQ("(u0f0s16 = 123)", kj::str(root.getUnion0()));
  EXPECT_EQ("(u1f0sp = \"foo\")", kj::str(root.getUnion1()));
  EXPECT_EQ("(u2f0s1 = true)", kj::str(root.getUnion2()));
  EXPECT_EQ("(u3f0s64 = 123456789012345678)", kj::str(root.getUnion3()));
}

TEST(Stringify, UnionDefaults) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<TestUnion>();

  root.getUnion0().setU0f0s16(0);     // Non-default field has default value.
  root.getUnion1().setU1f0sp("foo");  // Non-default field has non-default value.
  root.getUnion2().setU2f0s1(false);  // Default field has default value.
  root.getUnion3().setU3f0s1(true);   // Default field has non-default value.

  EXPECT_EQ("("
      "union0 = (u0f0s16 = 0), "
      "union1 = (u1f0sp = \"foo\"), "
      "union2 = (u2f0s1 = false), "
      "union3 = (u3f0s1 = true), "
      "bit0 = false, bit2 = false, bit3 = false, bit4 = false, bit5 = false, "
      "bit6 = false, bit7 = false, byte0 = 0)",
      kj::str(root));

  EXPECT_EQ("(u0f0s16 = 0)", kj::str(root.getUnion0()));
  EXPECT_EQ("(u1f0sp = \"foo\")", kj::str(root.getUnion1()));
  EXPECT_EQ("(u2f0s1 = false)", kj::str(root.getUnion2()));
  EXPECT_EQ("(u3f0s1 = true)", kj::str(root.getUnion3()));
}

TEST(Stringify, UnnamedUnions) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<test::TestUnnamedUnion>();

  root.setBar(123);

  EXPECT_EQ("(middle = 0, bar = 123)", kj::str(root));
  EXPECT_EQ("(middle = 0, bar = 123)", prettyPrint(root).flatten());

  root.setAfter("foooooooooooooooooooooooooooooooo");

  EXPECT_EQ("(middle = 0, bar = 123, after = \"foooooooooooooooooooooooooooooooo\")",
            kj::str(root));
  EXPECT_EQ(
      "( middle = 0,\n"
      "  bar = 123,\n"
      "  after = \"foooooooooooooooooooooooooooooooo\" )",
      prettyPrint(root).flatten());

  root.setBefore("before");

  EXPECT_EQ("(before = \"before\", middle = 0, bar = 123, "
      "after = \"foooooooooooooooooooooooooooooooo\")", kj::str(root));
  EXPECT_EQ(
      "( before = \"before\",\n"
      "  middle = 0,\n"
      "  bar = 123,\n"
      "  after = \"foooooooooooooooooooooooooooooooo\" )",
      prettyPrint(root).flatten());

  root.setFoo(0);

  EXPECT_EQ(
      "(before = \"before\", foo = 0, middle = 0, after = \"foooooooooooooooooooooooooooooooo\")",
      kj::str(root));
  EXPECT_EQ(
      "( before = \"before\",\n"
      "  foo = 0,\n"
      "  middle = 0,\n"
      "  after = \"foooooooooooooooooooooooooooooooo\" )",
      prettyPrint(root).flatten());
}

TEST(Stringify, StructUnions) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<test::TestStructUnion>();

  auto s = root.getUn().initStruct();
  s.setSomeText("foo");
  s.setMoreText("bar");

  EXPECT_EQ("(un = (struct = (someText = \"foo\", moreText = \"bar\")))", kj::str(root));
}

TEST(Stringify, MoreValues) {
  EXPECT_EQ("123", kj::str(DynamicValue::Reader(123)));
  EXPECT_EQ("1.23e47", kj::str(DynamicValue::Reader(123e45)));
  EXPECT_EQ("\"foo\"", kj::str(DynamicValue::Reader("foo")));
  EXPECT_EQ("\"\\a\\b\\n\\t\\\"\"", kj::str(DynamicValue::Reader("\a\b\n\t\"")));

  EXPECT_EQ("foo", kj::str(DynamicValue::Reader(TestEnum::FOO)));
  EXPECT_EQ("(123)", kj::str(DynamicValue::Reader(static_cast<TestEnum>(123))));
}

TEST(Stringify, Generics) {
  MallocMessageBuilder builder;
  auto root = builder.initRoot<test::TestGenerics<Text, List<uint32_t>>::Inner>();
  root.setFoo("abcd");
  auto l = root.initBar(2);
  l.set(0, 123);
  l.set(1, 456);

  EXPECT_EQ("(foo = \"abcd\", bar = [123, 456])", kj::str(root));
}

}  // namespace
}  // namespace _ (private)
}  // namespace capnp