LCOV - code coverage report
Current view: top level - buildbot/coverage/build/test/api/cpp - ouroborous.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 63 70 90.0 %
Date: 2026-03-26 10:42:46 Functions: 5 5 100.0 %
Branches: 10 20 50.0 %

           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                 :            :  * "Ouroborous" test: does cvc5 read its own output?
      11                 :            :  *
      12                 :            :  * The "Ouroborous" test, named after the serpent that swallows its
      13                 :            :  * own tail, ensures that cvc5 can parse some input, output it again
      14                 :            :  * (in any of its languages) and then parse it again.  The result of
      15                 :            :  * the first parse must be equal to the result of the second parse;
      16                 :            :  * both strings and expressions are compared for equality.
      17                 :            :  *
      18                 :            :  * To add a new test, simply add a call to runTestString() under
      19                 :            :  * runTest(), below.  If you don't specify an input language,
      20                 :            :  * LANG_SMTLIB_V2 is used.  If your example depends on symbolic constants,
      21                 :            :  * you'll need to declare them in the "declarations" global, just
      22                 :            :  * below, in SMT-LIBv2 form (but they're good for all languages).
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <cvc5/cvc5.h>
      26                 :            : #include <cvc5/cvc5_parser.h>
      27                 :            : 
      28                 :            : #include <cassert>
      29                 :            : #include <iostream>
      30                 :            : #include <string>
      31                 :            : 
      32                 :            : using namespace cvc5;
      33                 :            : using namespace cvc5::internal;
      34                 :            : using namespace cvc5::parser;
      35                 :            : 
      36                 :            : int runTest();
      37                 :            : 
      38                 :          1 : int main()
      39                 :            : {
      40                 :            :   try
      41                 :            :   {
      42                 :          1 :     return runTest();
      43                 :            :   }
      44         [ -  - ]:          0 :   catch (cvc5::CVC5ApiException& e)
      45                 :            :   {
      46                 :          0 :     std::cerr << e.getMessage() << std::endl;
      47                 :          0 :   }
      48                 :          0 :   catch (...)
      49                 :            :   {
      50                 :          0 :     std::cerr << "non-cvc5 exception thrown" << std::endl;
      51                 :          0 :   }
      52                 :          0 :   return 1;
      53                 :            : }
      54                 :            : 
      55                 :         12 : std::string parse(std::string instr,
      56                 :            :                   std::string input_language,
      57                 :            :                   std::string output_language)
      58                 :            : {
      59         [ -  + ]:         12 :   assert(input_language == "smt2");
      60         [ -  + ]:         12 :   assert(output_language == "smt2");
      61                 :            : 
      62                 :            :   std::string declarations =
      63                 :            :       "(set-logic ALL)\n"
      64                 :            :       "(declare-sort U 0)\n"
      65                 :            :       "(declare-fun f (U) U)\n"
      66                 :            :       "(declare-fun x () U)\n"
      67                 :            :       "(declare-fun y () U)\n"
      68                 :            :       "(assert (= (f x) x))\n"
      69                 :         12 :       "(declare-fun a () (Array U (Array U U)))\n";
      70                 :            : 
      71                 :         12 :   cvc5::TermManager tm;
      72                 :         12 :   cvc5::Solver solver(tm);
      73                 :            : 
      74                 :         12 :   modes::InputLanguage ilang = modes::InputLanguage::SMT_LIB_2_6;
      75                 :            : 
      76                 :         12 :   solver.setOption("input-language", input_language);
      77                 :         12 :   solver.setOption("output-language", output_language);
      78                 :         12 :   SymbolManager symman(tm);
      79                 :         12 :   InputParser parser(&solver, &symman);
      80                 :         12 :   std::stringstream ss;
      81                 :         12 :   ss << declarations;
      82                 :         12 :   parser.setStreamInput(ilang, ss, "internal-buffer");
      83                 :            :   // we don't need to execute the commands, but we DO need to parse them to
      84                 :            :   // get the declarations
      85                 :         12 :   std::stringstream tmp;
      86                 :         12 :   Command c;
      87                 :            :   while (true)
      88                 :            :   {
      89                 :         96 :     c = parser.nextCommand();
      90         [ +  + ]:         96 :     if (c.isNull())
      91                 :            :     {
      92                 :         12 :       break;
      93                 :            :     }
      94                 :            :     // invoke the command, which may bind symbols
      95                 :         84 :     c.invoke(&solver, &symman, tmp);
      96                 :            :   }
      97         [ -  + ]:         12 :   assert(parser.done());  // parser should be done
      98                 :         12 :   std::stringstream ssi;
      99                 :         12 :   ssi << instr;
     100                 :         12 :   parser.setStreamInput(ilang, ss, "internal-buffer");
     101                 :         12 :   cvc5::Term e = parser.nextTerm();
     102                 :         12 :   std::string s = e.toString();
     103         [ -  + ]:         12 :   assert(parser.nextTerm().isNull());  // next expr should be null
     104                 :         24 :   return s;
     105                 :         12 : }
     106                 :            : 
     107                 :          6 : std::string translate(std::string instr,
     108                 :            :                       std::string input_language,
     109                 :            :                       std::string output_language)
     110                 :            : {
     111         [ -  + ]:          6 :   assert(input_language == "smt2");
     112         [ -  + ]:          6 :   assert(output_language == "smt2");
     113                 :            : 
     114                 :          6 :   std::cout << "==============================================" << std::endl
     115                 :            :             << "translating from " << input_language << " to "
     116                 :          6 :             << output_language << " this string:" << std::endl
     117                 :          6 :             << instr << std::endl;
     118                 :         12 :   std::string outstr = parse(instr, input_language, output_language);
     119                 :          6 :   std::cout << "got this:" << std::endl
     120                 :          6 :             << outstr << std::endl
     121                 :          6 :             << "reparsing as " << output_language << std::endl;
     122                 :         12 :   std::string poutstr = parse(outstr, output_language, output_language);
     123         [ -  + ]:          6 :   assert(outstr == poutstr);
     124                 :          6 :   std::cout << "got same expressions " << outstr << " and " << poutstr
     125                 :          6 :             << std::endl
     126                 :          6 :             << "==============================================" << std::endl;
     127                 :         12 :   return outstr;
     128                 :          6 : }
     129                 :            : 
     130                 :          3 : void runTestString(std::string instr, std::string instr_language)
     131                 :            : {
     132                 :          3 :   std::cout << std::endl
     133                 :          3 :             << "starting with: " << instr << std::endl
     134                 :          3 :             << "   in language " << instr_language << std::endl;
     135                 :          6 :   std::string smt2str = translate(instr, instr_language, "smt2");
     136                 :          3 :   std::cout << "in SMT2      : " << smt2str << std::endl;
     137                 :          6 :   std::string outstr = translate(smt2str, "smt2", "smt2");
     138                 :          3 :   std::cout << "to SMT2 : " << outstr << std::endl << std::endl;
     139                 :            : 
     140         [ -  + ]:          3 :   assert(outstr == smt2str);  // differences in output
     141                 :          3 : }
     142                 :            : 
     143                 :          1 : int32_t runTest()
     144                 :            : {
     145                 :          1 :   runTestString("(= (f (f y)) x)", "smt2");
     146                 :          1 :   runTestString("(= ((_ extract 2 1) (bvnot (bvadd #b000 #b011))) #b10)",
     147                 :            :                 "smt2");
     148                 :          1 :   runTestString("((_ extract 2 0) (bvnot (bvadd (bvmul #b001 #b011) #b011)))",
     149                 :            :                 "smt2");
     150                 :          1 :   return 0;
     151                 :            : }

Generated by: LCOV version 1.14