rj_schema 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rj_schema/rapidjson/CMakeLists.txt +23 -1
  3. data/ext/rj_schema/rapidjson/appveyor.yml +49 -1
  4. data/ext/rj_schema/rapidjson/bin/types/alotofkeys.json +502 -0
  5. data/ext/rj_schema/rapidjson/bin/unittestschema/idandref.json +69 -0
  6. data/ext/rj_schema/rapidjson/doc/stream.md +7 -7
  7. data/ext/rj_schema/rapidjson/doc/stream.zh-cn.md +1 -1
  8. data/ext/rj_schema/rapidjson/doc/tutorial.md +15 -15
  9. data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +2 -0
  10. data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
  11. data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +460 -52
  12. data/ext/rj_schema/rapidjson/include/rapidjson/document.h +350 -60
  13. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +14 -0
  14. data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +68 -1
  15. data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +60 -11
  16. data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +249 -102
  17. data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
  18. data/ext/rj_schema/rapidjson/test/perftest/perftest.h +5 -4
  19. data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +20 -2
  20. data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +2 -0
  21. data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +193 -1
  22. data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +2 -0
  23. data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
  24. data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +62 -2
  25. data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +372 -7
  26. data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
  27. data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +12 -2
  28. data/ext/rj_schema/rj_schema.cpp +1 -1
  29. data/lib/rj_schema.rb +1 -1
  30. metadata +9 -3
@@ -130,7 +130,8 @@ public:
130
130
  "integers.json",
131
131
  "mixed.json",
132
132
  "nulls.json",
133
- "paragraphs.json"
133
+ "paragraphs.json",
134
+ "alotofkeys.json"
134
135
  };
135
136
 
136
137
  for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
@@ -158,7 +159,7 @@ public:
158
159
  free(whitespace_);
159
160
  json_ = 0;
160
161
  whitespace_ = 0;
161
- for (size_t i = 0; i < 7; i++) {
162
+ for (size_t i = 0; i < 8; i++) {
162
163
  free(types_[i]);
163
164
  types_[i] = 0;
164
165
  }
@@ -174,8 +175,8 @@ protected:
174
175
  size_t length_;
175
176
  char *whitespace_;
176
177
  size_t whitespace_length_;
177
- char *types_[7];
178
- size_t typesLength_[7];
178
+ char *types_[8];
179
+ size_t typesLength_[8];
179
180
 
180
181
  static const size_t kTrialCount = 1000;
181
182
  };
@@ -26,6 +26,7 @@
26
26
  #include "rapidjson/memorystream.h"
27
27
 
28
28
  #include <fstream>
29
+ #include <vector>
29
30
 
30
31
  #ifdef RAPIDJSON_SSE2
31
32
  #define SIMD_SUFFIX(name) name##_SSE2
@@ -52,7 +53,7 @@ public:
52
53
  // Parse as a document
53
54
  EXPECT_FALSE(doc_.Parse(json_).HasParseError());
54
55
 
55
- for (size_t i = 0; i < 7; i++)
56
+ for (size_t i = 0; i < 8; i++)
56
57
  EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
57
58
  }
58
59
 
@@ -68,7 +69,7 @@ private:
68
69
  protected:
69
70
  char *temp_;
70
71
  Document doc_;
71
- Document typesDoc_[7];
72
+ Document typesDoc_[8];
72
73
  };
73
74
 
74
75
  TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
@@ -335,6 +336,23 @@ TEST_F(RapidJson, DocumentAccept) {
335
336
  }
336
337
  }
337
338
 
339
+ TEST_F(RapidJson, DocumentFind) {
340
+ typedef Document::ValueType ValueType;
341
+ typedef ValueType::ConstMemberIterator ConstMemberIterator;
342
+ const Document &doc = typesDoc_[7]; // alotofkeys.json
343
+ if (doc.IsObject()) {
344
+ std::vector<const ValueType*> keys;
345
+ for (ConstMemberIterator it = doc.MemberBegin(); it != doc.MemberEnd(); ++it) {
346
+ keys.push_back(&it->name);
347
+ }
348
+ for (size_t i = 0; i < kTrialCount; i++) {
349
+ for (size_t j = 0; j < keys.size(); j++) {
350
+ EXPECT_TRUE(doc.FindMember(*keys[j]) != doc.MemberEnd());
351
+ }
352
+ }
353
+ }
354
+ }
355
+
338
356
  struct NullStream {
339
357
  typedef char Ch;
340
358
 
@@ -16,6 +16,7 @@ set(UNITTEST_SOURCES
16
16
  jsoncheckertest.cpp
17
17
  namespacetest.cpp
18
18
  pointertest.cpp
19
+ platformtest.cpp
19
20
  prettywritertest.cpp
20
21
  ostreamwrappertest.cpp
21
22
  readertest.cpp
@@ -26,6 +27,7 @@ set(UNITTEST_SOURCES
26
27
  stringbuffertest.cpp
27
28
  strtodtest.cpp
28
29
  unittest.cpp
30
+ uritest.cpp
29
31
  valuetest.cpp
30
32
  writertest.cpp)
31
33
 
@@ -16,6 +16,11 @@
16
16
 
17
17
  #include "rapidjson/allocators.h"
18
18
 
19
+ #include <map>
20
+ #include <string>
21
+ #include <utility>
22
+ #include <functional>
23
+
19
24
  using namespace rapidjson;
20
25
 
21
26
  template <typename Allocator>
@@ -47,19 +52,206 @@ void TestAllocator(Allocator& a) {
47
52
  EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
48
53
  }
49
54
 
55
+ struct TestStdAllocatorData {
56
+ TestStdAllocatorData(int &constructions, int &destructions) :
57
+ constructions_(&constructions),
58
+ destructions_(&destructions)
59
+ {
60
+ ++*constructions_;
61
+ }
62
+ TestStdAllocatorData(const TestStdAllocatorData& rhs) :
63
+ constructions_(rhs.constructions_),
64
+ destructions_(rhs.destructions_)
65
+ {
66
+ ++*constructions_;
67
+ }
68
+ TestStdAllocatorData& operator=(const TestStdAllocatorData& rhs)
69
+ {
70
+ this->~TestStdAllocatorData();
71
+ constructions_ = rhs.constructions_;
72
+ destructions_ = rhs.destructions_;
73
+ ++*constructions_;
74
+ return *this;
75
+ }
76
+ ~TestStdAllocatorData()
77
+ {
78
+ ++*destructions_;
79
+ }
80
+ private:
81
+ TestStdAllocatorData();
82
+ int *constructions_,
83
+ *destructions_;
84
+ };
85
+
86
+ template <typename Allocator>
87
+ void TestStdAllocator(const Allocator& a) {
88
+ #if RAPIDJSON_HAS_CXX17
89
+ typedef StdAllocator<bool, Allocator> BoolAllocator;
90
+ #else
91
+ typedef StdAllocator<void, Allocator> VoidAllocator;
92
+ typedef typename VoidAllocator::template rebind<bool>::other BoolAllocator;
93
+ #endif
94
+ BoolAllocator ba(a), ba2(a);
95
+ EXPECT_TRUE(ba == ba2);
96
+ EXPECT_FALSE(ba!= ba2);
97
+ ba.deallocate(ba.allocate());
98
+ EXPECT_TRUE(ba == ba2);
99
+ EXPECT_FALSE(ba != ba2);
100
+
101
+ unsigned long long ll = 0, *llp = &ll;
102
+ const unsigned long long cll = 0, *cllp = &cll;
103
+ StdAllocator<unsigned long long, Allocator> lla(a);
104
+ EXPECT_EQ(lla.address(ll), llp);
105
+ EXPECT_EQ(lla.address(cll), cllp);
106
+ EXPECT_TRUE(lla.max_size() > 0 && lla.max_size() <= SIZE_MAX / sizeof(unsigned long long));
107
+
108
+ int *arr;
109
+ StdAllocator<int, Allocator> ia(a);
110
+ arr = ia.allocate(10 * sizeof(int));
111
+ EXPECT_TRUE(arr != 0);
112
+ for (int i = 0; i < 10; ++i) {
113
+ arr[i] = 0x0f0f0f0f;
114
+ }
115
+ ia.deallocate(arr, 10);
116
+ arr = Malloc<int>(ia, 10);
117
+ EXPECT_TRUE(arr != 0);
118
+ for (int i = 0; i < 10; ++i) {
119
+ arr[i] = 0x0f0f0f0f;
120
+ }
121
+ arr = Realloc<int>(ia, arr, 10, 20);
122
+ EXPECT_TRUE(arr != 0);
123
+ for (int i = 0; i < 10; ++i) {
124
+ EXPECT_EQ(arr[i], 0x0f0f0f0f);
125
+ }
126
+ for (int i = 10; i < 20; i++) {
127
+ arr[i] = 0x0f0f0f0f;
128
+ }
129
+ Free<int>(ia, arr, 20);
130
+
131
+ int cons = 0, dest = 0;
132
+ StdAllocator<TestStdAllocatorData, Allocator> da(a);
133
+ for (int i = 1; i < 10; i++) {
134
+ TestStdAllocatorData *d = da.allocate();
135
+ EXPECT_TRUE(d != 0);
136
+
137
+ da.destroy(new(d) TestStdAllocatorData(cons, dest));
138
+ EXPECT_EQ(cons, i);
139
+ EXPECT_EQ(dest, i);
140
+
141
+ da.deallocate(d);
142
+ }
143
+
144
+ typedef StdAllocator<char, Allocator> CharAllocator;
145
+ typedef std::basic_string<char, std::char_traits<char>, CharAllocator> String;
146
+ #if RAPIDJSON_HAS_CXX11
147
+ String s(CharAllocator{a});
148
+ #else
149
+ CharAllocator ca(a);
150
+ String s(ca);
151
+ #endif
152
+ for (int i = 0; i < 26; i++) {
153
+ s.push_back(static_cast<char>('A' + i));
154
+ }
155
+ EXPECT_TRUE(s == "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
156
+
157
+ typedef StdAllocator<std::pair<const int, bool>, Allocator> MapAllocator;
158
+ typedef std::map<int, bool, std::less<int>, MapAllocator> Map;
159
+ #if RAPIDJSON_HAS_CXX11
160
+ Map map(std::less<int>(), MapAllocator{a});
161
+ #else
162
+ MapAllocator ma(a);
163
+ Map map(std::less<int>(), ma);
164
+ #endif
165
+ for (int i = 0; i < 10; i++) {
166
+ map.insert(std::make_pair(i, (i % 2) == 0));
167
+ }
168
+ EXPECT_TRUE(map.size() == 10);
169
+ for (int i = 0; i < 10; i++) {
170
+ typename Map::iterator it = map.find(i);
171
+ EXPECT_TRUE(it != map.end());
172
+ EXPECT_TRUE(it->second == ((i % 2) == 0));
173
+ }
174
+ }
175
+
50
176
  TEST(Allocator, CrtAllocator) {
51
177
  CrtAllocator a;
178
+
52
179
  TestAllocator(a);
180
+ TestStdAllocator(a);
181
+
182
+ CrtAllocator a2;
183
+ EXPECT_TRUE(a == a2);
184
+ EXPECT_FALSE(a != a2);
185
+ a2.Free(a2.Malloc(1));
186
+ EXPECT_TRUE(a == a2);
187
+ EXPECT_FALSE(a != a2);
53
188
  }
54
189
 
55
190
  TEST(Allocator, MemoryPoolAllocator) {
56
- MemoryPoolAllocator<> a;
191
+ const size_t capacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY;
192
+ MemoryPoolAllocator<> a(capacity);
193
+
194
+ a.Clear(); // noop
195
+ EXPECT_EQ(a.Size(), 0u);
196
+ EXPECT_EQ(a.Capacity(), 0u);
197
+ EXPECT_EQ(a.Shared(), false);
198
+ {
199
+ MemoryPoolAllocator<> a2(a);
200
+ EXPECT_EQ(a2.Shared(), true);
201
+ EXPECT_EQ(a.Shared(), true);
202
+ EXPECT_TRUE(a == a2);
203
+ EXPECT_FALSE(a != a2);
204
+ a2.Free(a2.Malloc(1));
205
+ EXPECT_TRUE(a == a2);
206
+ EXPECT_FALSE(a != a2);
207
+ }
208
+ EXPECT_EQ(a.Shared(), false);
209
+ EXPECT_EQ(a.Capacity(), capacity);
210
+ EXPECT_EQ(a.Size(), 8u); // aligned
211
+ a.Clear();
212
+ EXPECT_EQ(a.Capacity(), 0u);
213
+ EXPECT_EQ(a.Size(), 0u);
214
+
57
215
  TestAllocator(a);
216
+ TestStdAllocator(a);
58
217
 
59
218
  for (size_t i = 1; i < 1000; i++) {
60
219
  EXPECT_TRUE(a.Malloc(i) != 0);
61
220
  EXPECT_LE(a.Size(), a.Capacity());
62
221
  }
222
+
223
+ CrtAllocator baseAllocator;
224
+ a = MemoryPoolAllocator<>(capacity, &baseAllocator);
225
+ EXPECT_EQ(a.Capacity(), 0u);
226
+ EXPECT_EQ(a.Size(), 0u);
227
+ a.Free(a.Malloc(1));
228
+ EXPECT_EQ(a.Capacity(), capacity);
229
+ EXPECT_EQ(a.Size(), 8u); // aligned
230
+
231
+ {
232
+ a.Clear();
233
+ const size_t bufSize = 1024;
234
+ char *buffer = (char *)a.Malloc(bufSize);
235
+ MemoryPoolAllocator<> aligned_a(buffer, bufSize);
236
+ EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
237
+ EXPECT_EQ(aligned_a.Size(), 0u);
238
+ aligned_a.Free(aligned_a.Malloc(1));
239
+ EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
240
+ EXPECT_EQ(aligned_a.Size(), 8u); // aligned
241
+ }
242
+
243
+ {
244
+ a.Clear();
245
+ const size_t bufSize = 1024;
246
+ char *buffer = (char *)a.Malloc(bufSize);
247
+ RAPIDJSON_ASSERT(bufSize % sizeof(void*) == 0);
248
+ MemoryPoolAllocator<> unaligned_a(buffer + 1, bufSize - 1);
249
+ EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
250
+ EXPECT_EQ(unaligned_a.Size(), 0u);
251
+ unaligned_a.Free(unaligned_a.Malloc(1));
252
+ EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
253
+ EXPECT_EQ(unaligned_a.Size(), 8u); // aligned
254
+ }
63
255
  }
64
256
 
65
257
  TEST(Allocator, Alignment) {
@@ -325,6 +325,8 @@ TEST(Document, Swap) {
325
325
  EXPECT_TRUE(d1.IsNull());
326
326
 
327
327
  // reset document, including allocator
328
+ // so clear o before so that it doesnt contain dangling elements
329
+ o.Clear();
328
330
  Document().Swap(d2);
329
331
  EXPECT_TRUE(d2.IsNull());
330
332
  EXPECT_NE(&d2.GetAllocator(), &a);
@@ -0,0 +1,40 @@
1
+ // Tencent is pleased to support the open source community by making RapidJSON available.
2
+ //
3
+ // Copyright (C) 2021 THL A29 Limited, a Tencent company, and Milo Yip.
4
+ //
5
+ // Licensed under the MIT License (the "License"); you may not use this file except
6
+ // in compliance with the License. You may obtain a copy of the License at
7
+ //
8
+ // http://opensource.org/licenses/MIT
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software distributed
11
+ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12
+ // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13
+ // specific language governing permissions and limitations under the License.
14
+
15
+ #include "unittest.h"
16
+
17
+ // see https://github.com/Tencent/rapidjson/issues/1448
18
+ // including windows.h on purpose to provoke a compile time problem as GetObject is a
19
+ // macro that gets defined when windows.h is included
20
+ #ifdef _WIN32
21
+ #include <windows.h>
22
+ #endif
23
+
24
+ #include "rapidjson/document.h"
25
+ #undef GetObject
26
+
27
+ using namespace rapidjson;
28
+
29
+ TEST(Platform, GetObject) {
30
+ Document doc;
31
+ doc.Parse(" { \"object\" : { \"pi\": 3.1416} } ");
32
+ EXPECT_TRUE(doc.IsObject());
33
+ EXPECT_TRUE(doc.HasMember("object"));
34
+ const Document::ValueType& o = doc["object"];
35
+ EXPECT_TRUE(o.IsObject());
36
+ Value::ConstObject sub = o.GetObject();
37
+ EXPECT_TRUE(sub.HasMember("pi"));
38
+ Value::ConstObject sub2 = o.GetObj();
39
+ EXPECT_TRUE(sub2.HasMember("pi"));
40
+ }
@@ -475,7 +475,9 @@ TEST(Pointer, CopyConstructor) {
475
475
  EXPECT_EQ(1u, q.GetTokens()[1].length);
476
476
  EXPECT_STREQ("0", q.GetTokens()[1].name);
477
477
  EXPECT_EQ(0u, q.GetTokens()[1].index);
478
- EXPECT_EQ(&p.GetAllocator(), &q.GetAllocator());
478
+
479
+ // Copied pointer needs to have its own allocator
480
+ EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
479
481
  }
480
482
 
481
483
  // Static tokens
@@ -648,6 +650,52 @@ TEST(Pointer, Create) {
648
650
  }
649
651
  }
650
652
 
653
+ static const char kJsonIds[] = "{\n"
654
+ " \"id\": \"/root/\","
655
+ " \"foo\":[\"bar\", \"baz\", {\"id\": \"inarray\", \"child\": 1}],\n"
656
+ " \"int\" : 2,\n"
657
+ " \"str\" : \"val\",\n"
658
+ " \"obj\": {\"id\": \"inobj\", \"child\": 3},\n"
659
+ " \"jbo\": {\"id\": true, \"child\": 4}\n"
660
+ "}";
661
+
662
+
663
+ TEST(Pointer, GetUri) {
664
+ CrtAllocator allocator;
665
+ Document d;
666
+ d.Parse(kJsonIds);
667
+ Pointer::UriType doc("http://doc");
668
+ Pointer::UriType root("http://doc/root/");
669
+ Pointer::UriType empty = Pointer::UriType();
670
+
671
+ EXPECT_TRUE(Pointer("").GetUri(d, doc) == doc);
672
+ EXPECT_TRUE(Pointer("/foo").GetUri(d, doc) == root);
673
+ EXPECT_TRUE(Pointer("/foo/0").GetUri(d, doc) == root);
674
+ EXPECT_TRUE(Pointer("/foo/2").GetUri(d, doc) == root);
675
+ EXPECT_TRUE(Pointer("/foo/2/child").GetUri(d, doc) == Pointer::UriType("http://doc/root/inarray"));
676
+ EXPECT_TRUE(Pointer("/int").GetUri(d, doc) == root);
677
+ EXPECT_TRUE(Pointer("/str").GetUri(d, doc) == root);
678
+ EXPECT_TRUE(Pointer("/obj").GetUri(d, doc) == root);
679
+ EXPECT_TRUE(Pointer("/obj/child").GetUri(d, doc) == Pointer::UriType("http://doc/root/inobj"));
680
+ EXPECT_TRUE(Pointer("/jbo").GetUri(d, doc) == root);
681
+ EXPECT_TRUE(Pointer("/jbo/child").GetUri(d, doc) == root); // id not string
682
+
683
+ size_t unresolvedTokenIndex;
684
+ EXPECT_TRUE(Pointer("/abc").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // Out of boundary
685
+ EXPECT_EQ(0u, unresolvedTokenIndex);
686
+ EXPECT_TRUE(Pointer("/foo/3").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // Out of boundary
687
+ EXPECT_EQ(1u, unresolvedTokenIndex);
688
+ EXPECT_TRUE(Pointer("/foo/a").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo" is an array, cannot query by "a"
689
+ EXPECT_EQ(1u, unresolvedTokenIndex);
690
+ EXPECT_TRUE(Pointer("/foo/0/0").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo/0" is an string, cannot further query
691
+ EXPECT_EQ(2u, unresolvedTokenIndex);
692
+ EXPECT_TRUE(Pointer("/foo/0/a").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo/0" is an string, cannot further query
693
+ EXPECT_EQ(2u, unresolvedTokenIndex);
694
+
695
+ Pointer::Token tokens[] = { { "foo ...", 3, kPointerInvalidIndex } };
696
+ EXPECT_TRUE(Pointer(tokens, 1).GetUri(d, doc) == root);
697
+ }
698
+
651
699
  TEST(Pointer, Get) {
652
700
  Document d;
653
701
  d.Parse(kJson);
@@ -664,7 +712,8 @@ TEST(Pointer, Get) {
664
712
  EXPECT_EQ(&d["k\"l"], Pointer("/k\"l").Get(d));
665
713
  EXPECT_EQ(&d[" "], Pointer("/ ").Get(d));
666
714
  EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d));
667
- EXPECT_TRUE(Pointer("/abc").Get(d) == 0);
715
+
716
+ EXPECT_TRUE(Pointer("/abc").Get(d) == 0); // Out of boundary
668
717
  size_t unresolvedTokenIndex;
669
718
  EXPECT_TRUE(Pointer("/foo/2").Get(d, &unresolvedTokenIndex) == 0); // Out of boundary
670
719
  EXPECT_EQ(1u, unresolvedTokenIndex);
@@ -1668,3 +1717,14 @@ TEST(Pointer, Issue483) {
1668
1717
  value.SetString(mystr.c_str(), static_cast<SizeType>(mystr.length()), document.GetAllocator());
1669
1718
  myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator());
1670
1719
  }
1720
+
1721
+ TEST(Pointer, Issue1899) {
1722
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
1723
+ PointerType p;
1724
+ PointerType q = p.Append("foo");
1725
+ EXPECT_TRUE(PointerType("/foo") == q);
1726
+ q = q.Append(1234);
1727
+ EXPECT_TRUE(PointerType("/foo/1234") == q);
1728
+ q = q.Append("");
1729
+ EXPECT_TRUE(PointerType("/foo/1234/") == q);
1730
+ }