GCC Code Coverage Report
Directory: . Exec Total Coverage
File: test/unit/context/context_black.cpp Lines: 87 90 96.7 %
Date: 2021-03-23 Branches: 167 706 23.7 %

Line Exec Source
1
/*********************                                                        */
2
/*! \file context_black.cpp
3
 ** \verbatim
4
 ** Top contributors (to current version):
5
 **   Aina Niemetz, Morgan Deters, Dejan Jovanovic
6
 ** This file is part of the CVC4 project.
7
 ** Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 ** in the top-level source directory and their institutional affiliations.
9
 ** All rights reserved.  See the file COPYING in the top-level source
10
 ** directory for licensing information.\endverbatim
11
 **
12
 ** \brief Black box testing of CVC4::context::Context.
13
 **
14
 ** Black box testing of CVC4::context::Context.
15
 **/
16
17
#include <iostream>
18
#include <vector>
19
20
#include "base/exception.h"
21
#include "context/cdlist.h"
22
#include "context/cdo.h"
23
#include "test_context.h"
24
25
namespace CVC4 {
26
27
using namespace context;
28
29
namespace test {
30
31
struct MyContextNotifyObj : public ContextNotifyObj
32
{
33
8
  MyContextNotifyObj(Context* context, bool pre)
34
8
      : ContextNotifyObj(context, pre), d_ncalls(0)
35
  {
36
8
  }
37
38
8
  ~MyContextNotifyObj() override {}
39
40
16
  void contextNotifyPop() override { ++d_ncalls; }
41
42
  int32_t d_ncalls;
43
};
44
45
class MyContextObj : public ContextObj
46
{
47
 public:
48
8
  MyContextObj(Context* context, MyContextNotifyObj& n)
49
8
      : ContextObj(context), d_ncalls(0), d_nsaves(0), d_notify(n)
50
  {
51
8
  }
52
53
  MyContextObj(bool topScope, Context* context, MyContextNotifyObj& n)
54
      : ContextObj(topScope, context), d_ncalls(0), d_nsaves(0), d_notify(n)
55
  {
56
  }
57
58
8
  ~MyContextObj() override { destroy(); }
59
60
16
  ContextObj* save(ContextMemoryManager* pcmm) override
61
  {
62
16
    ++d_nsaves;
63
16
    return new (pcmm) MyContextObj(*this);
64
  }
65
66
16
  void restore(ContextObj* contextObj) override
67
  {
68
16
    d_ncalls = d_notify.d_ncalls;
69
16
  }
70
71
16
  void makeCurrent() { ContextObj::makeCurrent(); }
72
73
  int32_t d_ncalls;
74
  int32_t d_nsaves;
75
76
 private:
77
16
  MyContextObj(const MyContextObj& other)
78
16
      : ContextObj(other), d_ncalls(0), d_nsaves(0), d_notify(other.d_notify)
79
  {
80
16
  }
81
  MyContextNotifyObj& d_notify;
82
};
83
84
12
class TestContextBlack : public TestContext
85
{
86
};
87
88
13
TEST_F(TestContextBlack, push_pop)
89
{
90
  // Test what happens when the context is popped below 0
91
  // the interface doesn't declare any exceptions
92
2
  d_context->push();
93
2
  d_context->pop();
94
#ifdef CVC4_ASSERTIONS
95
2
  ASSERT_DEATH(d_context->pop(), "Cannot pop below level 0");
96
2
  ASSERT_DEATH(d_context->pop(), "Cannot pop below level 0");
97
#endif /* CVC4_ASSERTIONS */
98
}
99
100
13
TEST_F(TestContextBlack, dtor)
101
{
102
  // Destruction of ContextObj was broken in revision 324 (bug #45) when
103
  // at a higher context level with an intervening modification.
104
  // (The following caused a "pure virtual method called" error.)
105
4
  CDO<int32_t> i(d_context.get());
106
2
  d_context->push();
107
2
  i = 5;
108
2
}
109
110
13
TEST_F(TestContextBlack, pre_post_notify)
111
{
112
  // This is tricky; we want to detect if pre- and post-notifies are
113
  // done correctly.  For that, we have to use a special ContextObj,
114
  // since that's the only thing that runs between pre- and post-.
115
116
4
  MyContextNotifyObj a(d_context.get(), true), b(d_context.get(), false);
117
118
  try
119
  {
120
4
    MyContextNotifyObj c(d_context.get(), true), d(d_context.get(), false);
121
122
2
    ASSERT_EQ(a.d_ncalls, 0);
123
2
    ASSERT_EQ(b.d_ncalls, 0);
124
2
    ASSERT_EQ(c.d_ncalls, 0);
125
2
    ASSERT_EQ(d.d_ncalls, 0);
126
127
4
    MyContextObj w(d_context.get(), a);
128
4
    MyContextObj x(d_context.get(), b);
129
4
    MyContextObj y(d_context.get(), c);
130
4
    MyContextObj z(d_context.get(), d);
131
132
2
    d_context->push();
133
134
2
    w.makeCurrent();
135
2
    x.makeCurrent();
136
2
    y.makeCurrent();
137
2
    z.makeCurrent();
138
139
2
    ASSERT_EQ(a.d_ncalls, 0);
140
2
    ASSERT_EQ(b.d_ncalls, 0);
141
2
    ASSERT_EQ(c.d_ncalls, 0);
142
2
    ASSERT_EQ(d.d_ncalls, 0);
143
144
2
    ASSERT_EQ(w.d_ncalls, 0);
145
2
    ASSERT_EQ(x.d_ncalls, 0);
146
2
    ASSERT_EQ(y.d_ncalls, 0);
147
2
    ASSERT_EQ(z.d_ncalls, 0);
148
149
2
    d_context->push();
150
151
2
    w.makeCurrent();
152
2
    x.makeCurrent();
153
2
    y.makeCurrent();
154
2
    z.makeCurrent();
155
156
2
    ASSERT_EQ(a.d_ncalls, 0);
157
2
    ASSERT_EQ(b.d_ncalls, 0);
158
2
    ASSERT_EQ(c.d_ncalls, 0);
159
2
    ASSERT_EQ(d.d_ncalls, 0);
160
161
2
    ASSERT_EQ(w.d_ncalls, 0);
162
2
    ASSERT_EQ(x.d_ncalls, 0);
163
2
    ASSERT_EQ(y.d_ncalls, 0);
164
2
    ASSERT_EQ(z.d_ncalls, 0);
165
166
2
    d_context->pop();
167
168
2
    ASSERT_EQ(a.d_ncalls, 1);
169
2
    ASSERT_EQ(b.d_ncalls, 1);
170
2
    ASSERT_EQ(c.d_ncalls, 1);
171
2
    ASSERT_EQ(d.d_ncalls, 1);
172
173
2
    ASSERT_EQ(w.d_ncalls, 1);
174
2
    ASSERT_EQ(x.d_ncalls, 0);
175
2
    ASSERT_EQ(y.d_ncalls, 1);
176
2
    ASSERT_EQ(z.d_ncalls, 0);
177
178
2
    d_context->pop();
179
180
2
    ASSERT_EQ(a.d_ncalls, 2);
181
2
    ASSERT_EQ(b.d_ncalls, 2);
182
2
    ASSERT_EQ(c.d_ncalls, 2);
183
2
    ASSERT_EQ(d.d_ncalls, 2);
184
185
2
    ASSERT_EQ(w.d_ncalls, 2);
186
2
    ASSERT_EQ(x.d_ncalls, 1);
187
2
    ASSERT_EQ(y.d_ncalls, 2);
188
2
    ASSERT_EQ(z.d_ncalls, 1);
189
  }
190
  catch (Exception& e)
191
  {
192
    std::cerr << e.toString() << std::endl;
193
    ASSERT_TRUE(false) << "Exception thrown from test";
194
  }
195
196
  // we do this (together with the { } block above) to get full code
197
  // coverage of destruction paths; a and b haven't been destructed
198
  // yet, here.
199
2
  d_context.reset(nullptr);
200
}
201
202
// TODO: reenable after #2607 is merged in (issue 6047)
203
#if 0
204
TEST_F(TestContextBlack, top_scope_context_obj)
205
{
206
  // this test's implementation is based on the fact that a
207
  // ContextObj allocated primordially "in the top scope" (first arg
208
  // to ctor is "true"), doesn't get updated if you immediately call
209
  // makeCurrent().
210
211
  MyContextNotifyObj n(d_context.get(), true);
212
213
  d_context->push();
214
215
  MyContextObj x(true, d_context.get(), n);
216
  MyContextObj y(false, d_context.get(), n);
217
218
  ASSERT_EQ(x.d_nsaves, 0);
219
  ASSERT_EQ(y.d_nsaves, 0);
220
221
  x.makeCurrent();
222
  y.makeCurrent();
223
224
  ASSERT_EQ(x.d_nsaves, 0);
225
  ASSERT_EQ(y.d_nsaves, 1);
226
227
  d_context->push();
228
229
  x.makeCurrent();
230
  y.makeCurrent();
231
232
  ASSERT_EQ(x.d_nsaves, 1);
233
  ASSERT_EQ(y.d_nsaves, 2);
234
235
  d_context->pop();
236
  d_context->pop();
237
238
  ASSERT_EQ(x.d_nsaves, 1);
239
  ASSERT_EQ(y.d_nsaves, 2);
240
}
241
#endif
242
243
}  // namespace test
244
15
}  // namespace CVC4