LCOV - code coverage report
Current view: top level - buildbot/coverage/build/test/unit/context - context_black.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 94 98 95.9 %
Date: 2026-03-11 10:41:32 Functions: 25 27 92.6 %
Branches: 76 156 48.7 %

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

Generated by: LCOV version 1.14