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