1 //===-- ReproducerInstrumentationTest.cpp -----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11
12 #include <cmath>
13 #include <limits>
14
15 #include "lldb/Utility/ReproducerInstrumentation.h"
16
17 using namespace lldb_private;
18 using namespace lldb_private::repro;
19
20 struct Foo {
21 int m = 1;
22 };
23 struct Bar {
24 double m = 2;
25 };
26
operator ==(const Foo & LHS,const Foo & RHS)27 bool operator==(const Foo &LHS, const Foo &RHS) { return LHS.m == RHS.m; }
operator ==(const Bar & LHS,const Bar & RHS)28 bool operator==(const Bar &LHS, const Bar &RHS) { return LHS.m == RHS.m; }
29
30 struct Pod {
31 bool a = true;
32 bool b = false;
33 char c = 'a';
34 float d = 1.1f;
35 int e = 2;
36 long long f = 3;
37 long g = 4;
38 short h = 5;
39 unsigned char i = 'b';
40 unsigned int j = 6;
41 unsigned long long k = 7;
42 unsigned long l = 8;
43 unsigned short m = 9;
44
PodPod45 Pod() {}
46 };
47
48 class TestingRegistry : public Registry {
49 public:
50 TestingRegistry();
51 };
52
53 static llvm::Optional<Serializer> g_serializer;
54 static llvm::Optional<TestingRegistry> g_registry;
55
56 #define LLDB_GET_INSTRUMENTATION_DATA() \
57 g_serializer ? InstrumentationData(*g_serializer, *g_registry) : InstrumentationData()
58
59 class InstrumentedFoo {
60 public:
61 InstrumentedFoo() = default;
62 /// Instrumented methods.
63 /// {
64 InstrumentedFoo(int i);
65 InstrumentedFoo(const InstrumentedFoo &foo);
66 InstrumentedFoo &operator=(const InstrumentedFoo &foo);
67 void A(int a);
68 void B(int &b) const;
69 int C(float *c);
70 int D(const char *d) const;
71 static void E(double e);
72 static int F();
73 void Validate();
74 //// }
75
76 private:
77 int m_a = 0;
78 mutable int m_b = 0;
79 float m_c = 0;
80 mutable std::string m_d = {};
81 static double g_e;
82 static bool g_f;
83 mutable int m_called = 0;
84 };
85
86 class InstrumentedBar {
87 public:
88 /// Instrumented methods.
89 /// {
90 InstrumentedBar();
91 InstrumentedFoo GetInstrumentedFoo();
92 InstrumentedFoo &GetInstrumentedFooRef();
93 InstrumentedFoo *GetInstrumentedFooPtr();
94 void SetInstrumentedFoo(InstrumentedFoo *foo);
95 void SetInstrumentedFoo(InstrumentedFoo &foo);
96 void Validate();
97 /// }
98
99 private:
100 bool m_get_instrumend_foo_called = false;
101 InstrumentedFoo *m_foo_set_by_ptr = nullptr;
102 InstrumentedFoo *m_foo_set_by_ref = nullptr;
103 };
104
105 double InstrumentedFoo::g_e = 0;
106 bool InstrumentedFoo::g_f = false;
107
108 static std::vector<InstrumentedFoo *> g_foos;
109 static std::vector<InstrumentedBar *> g_bars;
110
ClearObjects()111 void ClearObjects() {
112 g_registry.reset();
113 g_serializer.reset();
114 g_foos.clear();
115 g_bars.clear();
116 }
117
ValidateObjects(size_t expected_foos,size_t expected_bars)118 void ValidateObjects(size_t expected_foos, size_t expected_bars) {
119 EXPECT_EQ(expected_foos, g_foos.size());
120 EXPECT_EQ(expected_bars, g_bars.size());
121
122 for (auto *foo : g_foos) {
123 foo->Validate();
124 }
125
126 for (auto *bar : g_bars) {
127 bar->Validate();
128 }
129 }
130
InstrumentedFoo(int i)131 InstrumentedFoo::InstrumentedFoo(int i) {
132 LLDB_RECORD_CONSTRUCTOR(InstrumentedFoo, (int), i);
133 g_foos.push_back(this);
134 }
135
InstrumentedFoo(const InstrumentedFoo & foo)136 InstrumentedFoo::InstrumentedFoo(const InstrumentedFoo &foo) {
137 LLDB_RECORD_CONSTRUCTOR(InstrumentedFoo, (const InstrumentedFoo &), foo);
138 g_foos.erase(std::remove(g_foos.begin(), g_foos.end(), &foo));
139 g_foos.push_back(this);
140 }
141
operator =(const InstrumentedFoo & foo)142 InstrumentedFoo &InstrumentedFoo::operator=(const InstrumentedFoo &foo) {
143 LLDB_RECORD_METHOD(InstrumentedFoo &,
144 InstrumentedFoo, operator=,(const InstrumentedFoo &), foo);
145 g_foos.erase(std::remove(g_foos.begin(), g_foos.end(), &foo));
146 g_foos.push_back(this);
147 return *this;
148 }
149
A(int a)150 void InstrumentedFoo::A(int a) {
151 LLDB_RECORD_METHOD(void, InstrumentedFoo, A, (int), a);
152 B(a);
153 m_a = a;
154 }
155
B(int & b) const156 void InstrumentedFoo::B(int &b) const {
157 LLDB_RECORD_METHOD_CONST(void, InstrumentedFoo, B, (int &), b);
158 m_called++;
159 m_b = b;
160 }
161
C(float * c)162 int InstrumentedFoo::C(float *c) {
163 LLDB_RECORD_METHOD(int, InstrumentedFoo, C, (float *), c);
164 m_c = *c;
165 return 1;
166 }
167
D(const char * d) const168 int InstrumentedFoo::D(const char *d) const {
169 LLDB_RECORD_METHOD_CONST(int, InstrumentedFoo, D, (const char *), d);
170 m_d = std::string(d);
171 return 2;
172 }
173
E(double e)174 void InstrumentedFoo::E(double e) {
175 LLDB_RECORD_STATIC_METHOD(void, InstrumentedFoo, E, (double), e);
176 g_e = e;
177 }
178
F()179 int InstrumentedFoo::F() {
180 LLDB_RECORD_STATIC_METHOD_NO_ARGS(int, InstrumentedFoo, F);
181 g_f = true;
182 return 3;
183 }
184
Validate()185 void InstrumentedFoo::Validate() {
186 LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedFoo, Validate);
187 EXPECT_EQ(m_a, 100);
188 EXPECT_EQ(m_b, 200);
189 EXPECT_NEAR(m_c, 300.3, 0.01);
190 EXPECT_EQ(m_d, "bar");
191 EXPECT_NEAR(g_e, 400.4, 0.01);
192 EXPECT_EQ(g_f, true);
193 EXPECT_EQ(2, m_called);
194 }
195
InstrumentedBar()196 InstrumentedBar::InstrumentedBar() {
197 LLDB_RECORD_CONSTRUCTOR_NO_ARGS(InstrumentedBar);
198 g_bars.push_back(this);
199 }
200
GetInstrumentedFoo()201 InstrumentedFoo InstrumentedBar::GetInstrumentedFoo() {
202 LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo, InstrumentedBar,
203 GetInstrumentedFoo);
204 m_get_instrumend_foo_called = true;
205 return LLDB_RECORD_RESULT(InstrumentedFoo(0));
206 }
207
GetInstrumentedFooRef()208 InstrumentedFoo &InstrumentedBar::GetInstrumentedFooRef() {
209 LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo &, InstrumentedBar,
210 GetInstrumentedFooRef);
211 InstrumentedFoo *foo = new InstrumentedFoo(0);
212 m_get_instrumend_foo_called = true;
213 return LLDB_RECORD_RESULT(*foo);
214 }
215
GetInstrumentedFooPtr()216 InstrumentedFoo *InstrumentedBar::GetInstrumentedFooPtr() {
217 LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo *, InstrumentedBar,
218 GetInstrumentedFooPtr);
219 InstrumentedFoo *foo = new InstrumentedFoo(0);
220 m_get_instrumend_foo_called = true;
221 return LLDB_RECORD_RESULT(foo);
222 }
223
SetInstrumentedFoo(InstrumentedFoo * foo)224 void InstrumentedBar::SetInstrumentedFoo(InstrumentedFoo *foo) {
225 LLDB_RECORD_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
226 (InstrumentedFoo *), foo);
227 m_foo_set_by_ptr = foo;
228 }
229
SetInstrumentedFoo(InstrumentedFoo & foo)230 void InstrumentedBar::SetInstrumentedFoo(InstrumentedFoo &foo) {
231 LLDB_RECORD_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
232 (InstrumentedFoo &), foo);
233 m_foo_set_by_ref = &foo;
234 }
235
Validate()236 void InstrumentedBar::Validate() {
237 LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedBar, Validate);
238
239 EXPECT_TRUE(m_get_instrumend_foo_called);
240 EXPECT_NE(m_foo_set_by_ptr, nullptr);
241 EXPECT_EQ(m_foo_set_by_ptr, m_foo_set_by_ref);
242 }
243
TestingRegistry()244 TestingRegistry::TestingRegistry() {
245 Registry& R = *this;
246
247 LLDB_REGISTER_CONSTRUCTOR(InstrumentedFoo, (int i));
248 LLDB_REGISTER_CONSTRUCTOR(InstrumentedFoo, (const InstrumentedFoo &));
249 LLDB_REGISTER_METHOD(InstrumentedFoo &,
250 InstrumentedFoo, operator=,(const InstrumentedFoo &));
251 LLDB_REGISTER_METHOD(void, InstrumentedFoo, A, (int));
252 LLDB_REGISTER_METHOD_CONST(void, InstrumentedFoo, B, (int &));
253 LLDB_REGISTER_METHOD(int, InstrumentedFoo, C, (float *));
254 LLDB_REGISTER_METHOD_CONST(int, InstrumentedFoo, D, (const char *));
255 LLDB_REGISTER_STATIC_METHOD(void, InstrumentedFoo, E, (double));
256 LLDB_REGISTER_STATIC_METHOD(int, InstrumentedFoo, F, ());
257 LLDB_REGISTER_METHOD(void, InstrumentedFoo, Validate, ());
258
259 LLDB_REGISTER_CONSTRUCTOR(InstrumentedBar, ());
260 LLDB_REGISTER_METHOD(InstrumentedFoo, InstrumentedBar, GetInstrumentedFoo,
261 ());
262 LLDB_REGISTER_METHOD(InstrumentedFoo &, InstrumentedBar,
263 GetInstrumentedFooRef, ());
264 LLDB_REGISTER_METHOD(InstrumentedFoo *, InstrumentedBar,
265 GetInstrumentedFooPtr, ());
266 LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
267 (InstrumentedFoo *));
268 LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
269 (InstrumentedFoo &));
270 LLDB_REGISTER_METHOD(void, InstrumentedBar, Validate, ());
271 }
272
273 static const Pod p;
274
TEST(IndexToObjectTest,ObjectForIndex)275 TEST(IndexToObjectTest, ObjectForIndex) {
276 IndexToObject index_to_object;
277 Foo foo;
278 Bar bar;
279
280 EXPECT_EQ(nullptr, index_to_object.GetObjectForIndex<Foo>(1));
281 EXPECT_EQ(nullptr, index_to_object.GetObjectForIndex<Bar>(2));
282
283 index_to_object.AddObjectForIndex<Foo>(1, foo);
284 index_to_object.AddObjectForIndex<Bar>(2, &bar);
285
286 EXPECT_EQ(&foo, index_to_object.GetObjectForIndex<Foo>(1));
287 EXPECT_EQ(&bar, index_to_object.GetObjectForIndex<Bar>(2));
288 }
289
TEST(DeserializerTest,HasData)290 TEST(DeserializerTest, HasData) {
291 {
292 Deserializer deserializer("");
293 EXPECT_FALSE(deserializer.HasData(1));
294 }
295
296 {
297 Deserializer deserializer("a");
298 EXPECT_TRUE(deserializer.HasData(1));
299 EXPECT_FALSE(deserializer.HasData(2));
300 }
301 }
302
TEST(SerializationRountripTest,SerializeDeserializePod)303 TEST(SerializationRountripTest, SerializeDeserializePod) {
304 std::string str;
305 llvm::raw_string_ostream os(str);
306
307 Serializer serializer(os);
308 serializer.SerializeAll(p.a, p.b, p.c, p.d, p.e, p.f, p.g, p.h, p.i, p.j, p.k,
309 p.l, p.m);
310
311 llvm::StringRef buffer(os.str());
312 Deserializer deserializer(buffer);
313
314 EXPECT_EQ(p.a, deserializer.Deserialize<bool>());
315 EXPECT_EQ(p.b, deserializer.Deserialize<bool>());
316 EXPECT_EQ(p.c, deserializer.Deserialize<char>());
317 EXPECT_EQ(p.d, deserializer.Deserialize<float>());
318 EXPECT_EQ(p.e, deserializer.Deserialize<int>());
319 EXPECT_EQ(p.f, deserializer.Deserialize<long long>());
320 EXPECT_EQ(p.g, deserializer.Deserialize<long>());
321 EXPECT_EQ(p.h, deserializer.Deserialize<short>());
322 EXPECT_EQ(p.i, deserializer.Deserialize<unsigned char>());
323 EXPECT_EQ(p.j, deserializer.Deserialize<unsigned int>());
324 EXPECT_EQ(p.k, deserializer.Deserialize<unsigned long long>());
325 EXPECT_EQ(p.l, deserializer.Deserialize<unsigned long>());
326 EXPECT_EQ(p.m, deserializer.Deserialize<unsigned short>());
327 }
328
TEST(SerializationRountripTest,SerializeDeserializePodPointers)329 TEST(SerializationRountripTest, SerializeDeserializePodPointers) {
330 std::string str;
331 llvm::raw_string_ostream os(str);
332
333 Serializer serializer(os);
334 serializer.SerializeAll(&p.a, &p.b, &p.c, &p.d, &p.e, &p.f, &p.g, &p.h, &p.i,
335 &p.j, &p.k, &p.l, &p.m);
336
337 llvm::StringRef buffer(os.str());
338 Deserializer deserializer(buffer);
339
340 EXPECT_EQ(p.a, *deserializer.Deserialize<bool *>());
341 EXPECT_EQ(p.b, *deserializer.Deserialize<bool *>());
342 EXPECT_EQ(p.c, *deserializer.Deserialize<char *>());
343 EXPECT_EQ(p.d, *deserializer.Deserialize<float *>());
344 EXPECT_EQ(p.e, *deserializer.Deserialize<int *>());
345 EXPECT_EQ(p.f, *deserializer.Deserialize<long long *>());
346 EXPECT_EQ(p.g, *deserializer.Deserialize<long *>());
347 EXPECT_EQ(p.h, *deserializer.Deserialize<short *>());
348 EXPECT_EQ(p.i, *deserializer.Deserialize<unsigned char *>());
349 EXPECT_EQ(p.j, *deserializer.Deserialize<unsigned int *>());
350 EXPECT_EQ(p.k, *deserializer.Deserialize<unsigned long long *>());
351 EXPECT_EQ(p.l, *deserializer.Deserialize<unsigned long *>());
352 EXPECT_EQ(p.m, *deserializer.Deserialize<unsigned short *>());
353 }
354
TEST(SerializationRountripTest,SerializeDeserializePodReferences)355 TEST(SerializationRountripTest, SerializeDeserializePodReferences) {
356 std::string str;
357 llvm::raw_string_ostream os(str);
358
359 Serializer serializer(os);
360 serializer.SerializeAll(p.a, p.b, p.c, p.d, p.e, p.f, p.g, p.h, p.i, p.j, p.k,
361 p.l, p.m);
362
363 llvm::StringRef buffer(os.str());
364 Deserializer deserializer(buffer);
365
366 EXPECT_EQ(p.a, deserializer.Deserialize<bool &>());
367 EXPECT_EQ(p.b, deserializer.Deserialize<bool &>());
368 EXPECT_EQ(p.c, deserializer.Deserialize<char &>());
369 EXPECT_EQ(p.d, deserializer.Deserialize<float &>());
370 EXPECT_EQ(p.e, deserializer.Deserialize<int &>());
371 EXPECT_EQ(p.f, deserializer.Deserialize<long long &>());
372 EXPECT_EQ(p.g, deserializer.Deserialize<long &>());
373 EXPECT_EQ(p.h, deserializer.Deserialize<short &>());
374 EXPECT_EQ(p.i, deserializer.Deserialize<unsigned char &>());
375 EXPECT_EQ(p.j, deserializer.Deserialize<unsigned int &>());
376 EXPECT_EQ(p.k, deserializer.Deserialize<unsigned long long &>());
377 EXPECT_EQ(p.l, deserializer.Deserialize<unsigned long &>());
378 EXPECT_EQ(p.m, deserializer.Deserialize<unsigned short &>());
379 }
380
TEST(SerializationRountripTest,SerializeDeserializeCString)381 TEST(SerializationRountripTest, SerializeDeserializeCString) {
382 const char *cstr = "string";
383
384 std::string str;
385 llvm::raw_string_ostream os(str);
386
387 Serializer serializer(os);
388 serializer.SerializeAll(cstr);
389
390 llvm::StringRef buffer(os.str());
391 Deserializer deserializer(buffer);
392
393 EXPECT_STREQ(cstr, deserializer.Deserialize<const char *>());
394 }
395
TEST(SerializationRountripTest,SerializeDeserializeObjectPointer)396 TEST(SerializationRountripTest, SerializeDeserializeObjectPointer) {
397 Foo foo;
398 Bar bar;
399
400 std::string str;
401 llvm::raw_string_ostream os(str);
402
403 Serializer serializer(os);
404 serializer.SerializeAll(static_cast<unsigned>(1), static_cast<unsigned>(2));
405 serializer.SerializeAll(&foo, &bar);
406
407 llvm::StringRef buffer(os.str());
408 Deserializer deserializer(buffer);
409
410 deserializer.HandleReplayResult(&foo);
411 deserializer.HandleReplayResult(&bar);
412
413 EXPECT_EQ(foo, *deserializer.Deserialize<Foo *>());
414 EXPECT_EQ(bar, *deserializer.Deserialize<Bar *>());
415 }
416
TEST(SerializationRountripTest,SerializeDeserializeObjectReference)417 TEST(SerializationRountripTest, SerializeDeserializeObjectReference) {
418 Foo foo;
419 Bar bar;
420
421 std::string str;
422 llvm::raw_string_ostream os(str);
423
424 Serializer serializer(os);
425 serializer.SerializeAll(static_cast<unsigned>(1), static_cast<unsigned>(2));
426 serializer.SerializeAll(foo, bar);
427
428 llvm::StringRef buffer(os.str());
429 Deserializer deserializer(buffer);
430
431 deserializer.HandleReplayResult(&foo);
432 deserializer.HandleReplayResult(&bar);
433
434 EXPECT_EQ(foo, deserializer.Deserialize<Foo &>());
435 EXPECT_EQ(bar, deserializer.Deserialize<Bar &>());
436 }
437
TEST(RecordReplayTest,InstrumentedFoo)438 TEST(RecordReplayTest, InstrumentedFoo) {
439 std::string str;
440 llvm::raw_string_ostream os(str);
441 g_registry.emplace();
442 g_serializer.emplace(os);
443
444 {
445 int b = 200;
446 float c = 300.3f;
447 double e = 400.4;
448
449 InstrumentedFoo foo(0);
450 foo.A(100);
451 foo.B(b);
452 foo.C(&c);
453 foo.D("bar");
454 InstrumentedFoo::E(e);
455 InstrumentedFoo::F();
456 foo.Validate();
457 }
458
459 ClearObjects();
460
461 TestingRegistry registry;
462 registry.Replay(os.str());
463
464 ValidateObjects(1, 0);
465 }
466
TEST(RecordReplayTest,InstrumentedFooSameThis)467 TEST(RecordReplayTest, InstrumentedFooSameThis) {
468 std::string str;
469 llvm::raw_string_ostream os(str);
470 g_registry.emplace();
471 g_serializer.emplace(os);
472
473 int b = 200;
474 float c = 300.3f;
475 double e = 400.4;
476
477 InstrumentedFoo *foo = new InstrumentedFoo(0);
478 foo->A(100);
479 foo->B(b);
480 foo->C(&c);
481 foo->D("bar");
482 InstrumentedFoo::E(e);
483 InstrumentedFoo::F();
484 foo->Validate();
485 foo->~InstrumentedFoo();
486
487 InstrumentedFoo *foo2 = new (foo) InstrumentedFoo(0);
488 foo2->A(100);
489 foo2->B(b);
490 foo2->C(&c);
491 foo2->D("bar");
492 InstrumentedFoo::E(e);
493 InstrumentedFoo::F();
494 foo2->Validate();
495 delete foo2;
496
497 ClearObjects();
498
499 TestingRegistry registry;
500 registry.Replay(os.str());
501
502 ValidateObjects(2, 0);
503 }
504
TEST(RecordReplayTest,InstrumentedBar)505 TEST(RecordReplayTest, InstrumentedBar) {
506 std::string str;
507 llvm::raw_string_ostream os(str);
508 g_registry.emplace();
509 g_serializer.emplace(os);
510
511 {
512 InstrumentedBar bar;
513 InstrumentedFoo foo = bar.GetInstrumentedFoo();
514 #if 0
515 InstrumentedFoo& foo_ref = bar.GetInstrumentedFooRef();
516 InstrumentedFoo* foo_ptr = bar.GetInstrumentedFooPtr();
517 #endif
518
519 int b = 200;
520 float c = 300.3f;
521 double e = 400.4;
522
523 foo.A(100);
524 foo.B(b);
525 foo.C(&c);
526 foo.D("bar");
527 InstrumentedFoo::E(e);
528 InstrumentedFoo::F();
529 foo.Validate();
530
531 bar.SetInstrumentedFoo(foo);
532 bar.SetInstrumentedFoo(&foo);
533 bar.Validate();
534 }
535
536 ClearObjects();
537
538 TestingRegistry registry;
539 registry.Replay(os.str());
540
541 ValidateObjects(1, 1);
542 }
543
TEST(RecordReplayTest,InstrumentedBarRef)544 TEST(RecordReplayTest, InstrumentedBarRef) {
545 std::string str;
546 llvm::raw_string_ostream os(str);
547 g_registry.emplace();
548 g_serializer.emplace(os);
549
550 {
551 InstrumentedBar bar;
552 InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
553
554 int b = 200;
555 float c = 300.3f;
556 double e = 400.4;
557
558 foo.A(100);
559 foo.B(b);
560 foo.C(&c);
561 foo.D("bar");
562 InstrumentedFoo::E(e);
563 InstrumentedFoo::F();
564 foo.Validate();
565
566 bar.SetInstrumentedFoo(foo);
567 bar.SetInstrumentedFoo(&foo);
568 bar.Validate();
569 }
570
571 ClearObjects();
572
573 TestingRegistry registry;
574 registry.Replay(os.str());
575
576 ValidateObjects(1, 1);
577 }
578
TEST(RecordReplayTest,InstrumentedBarPtr)579 TEST(RecordReplayTest, InstrumentedBarPtr) {
580 std::string str;
581 llvm::raw_string_ostream os(str);
582 g_registry.emplace();
583 g_serializer.emplace(os);
584
585 {
586 InstrumentedBar bar;
587 InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
588
589 int b = 200;
590 float c = 300.3f;
591 double e = 400.4;
592
593 foo.A(100);
594 foo.B(b);
595 foo.C(&c);
596 foo.D("bar");
597 InstrumentedFoo::E(e);
598 InstrumentedFoo::F();
599 foo.Validate();
600
601 bar.SetInstrumentedFoo(foo);
602 bar.SetInstrumentedFoo(&foo);
603 bar.Validate();
604 }
605
606 ClearObjects();
607
608 TestingRegistry registry;
609 registry.Replay(os.str());
610
611 ValidateObjects(1, 1);
612 }
613