Xyst test code coverage report
Current view: top level - Base - Print.hpp (source / functions) Coverage Total Hit
Commit: 1fb74642dd9d7732b67f32dec2f2762e238d3fa7 Lines: 97.8 % 90 88
Test Date: 2025-08-13 22:18:46 Functions: 100.0 % 22 22
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 52.9 % 204 108

             Branch data     Line data    Source code
       1                 :             : // *****************************************************************************
       2                 :             : /*!
       3                 :             :   \file      src/Base/Print.hpp
       4                 :             :   \copyright 2012-2015 J. Bakosi,
       5                 :             :              2016-2018 Los Alamos National Security, LLC.,
       6                 :             :              2019-2021 Triad National Security, LLC.,
       7                 :             :              2022-2025 J. Bakosi
       8                 :             :              All rights reserved. See the LICENSE file for details.
       9                 :             :   \brief     General purpose pretty printer functionality
      10                 :             :   \details   This file contains general purpose printer functions. Using the
      11                 :             :     functions defined here provides formatting, and a consistent look with
      12                 :             :     simple client-side code.
      13                 :             : */
      14                 :             : // *****************************************************************************
      15                 :             : #pragma once
      16                 :             : 
      17                 :             : #include <iostream>
      18                 :             : #include <cmath>
      19                 :             : 
      20                 :             : #include "Timer.hpp"
      21                 :             : #include "Exception.hpp"
      22                 :             : #include "PrintUtil.hpp"
      23                 :             : 
      24                 :             : namespace tk {
      25                 :             : 
      26                 :             : //! Pretty printer base. Contains general purpose printer functions. Using the
      27                 :             : //! functions defined here provides formatting, and a consistent look with
      28                 :             : //! simple client-side code.
      29                 :             : class Print {
      30                 :             : 
      31                 :             :   public:
      32                 :             :     //! Constructor
      33 [ +  - ][ +  + ]:        9252 :     explicit Print() : m_stream( std::cout ) {}
                 [ +  - ]
      34                 :             : 
      35                 :             :     //! Operator << for printing any type to the verbose stream.
      36                 :             :     //! \param[in] os Reference to pretty printer object
      37                 :             :     //! \param[in] t Reference to an arbitrary object of type T. T must define
      38                 :             :     //! operator<< for std::ostream-compatible streams.
      39                 :             :     //! \return The internal stream buffer of the stream
      40                 :             :     template< typename T >
      41                 :       10561 :     friend const Print& operator<<( const Print& os, const T& t ) {
      42 [ +  - ][ +  - ]:      107070 :       os.m_stream << t << std::flush;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ -  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      43                 :       15776 :       return os;
      44                 :             :     }
      45                 :             : 
      46                 :             :     //! Formatted print of section title
      47                 :             :     //! \param[in] t Section title to be printed
      48                 :        2458 :     void section( const std::string& t ) const {
      49                 :             :       std::string underline( t.size(), '-' );
      50 [ +  - ][ +  - ]:        2458 :       m_stream << '\n' << t.c_str() << '\n' << underline.c_str() << std::endl;
         [ +  - ][ +  - ]
      51                 :        2458 :     }
      52                 :             : 
      53                 :             :     //! Formatted print of item: name : value
      54                 :             :     //! \param[in] name Item name to be printed
      55                 :             :     //! \param[in] value Item value to be printed
      56                 :             :     template< typename T >
      57                 :        4501 :     void item( const std::string& name, const T& value ) const {
      58                 :        4501 :       m_stream << name.c_str() << ": ";
      59                 :             :       if constexpr( std::is_same_v< T, std::string > ) {
      60                 :        2865 :         m_stream << value.c_str();
      61                 :             :       } else {
      62                 :        1636 :         m_stream << value;
      63                 :             :       }
      64                 :        4501 :       m_stream << std::endl;
      65                 :        4501 :     }
      66                 :             : 
      67                 :             :     //! Formatted print of item: h:m:s.
      68                 :             :     //! \param[in] name Item name to be printed
      69                 :             :     //! \param[in] watch Watch (in hours, minutes, seconds) to be printed as
      70                 :             :     //!   item value
      71                 :         646 :     void item( const std::string& name, const tk::Timer::Watch& watch ) const {
      72                 :         646 :       m_stream << name.c_str() << ": "
      73                 :         646 :                << watch.hrs.count() << ':'
      74                 :         646 :                << watch.min.count() << ':'
      75                 :             :                << watch.sec.count() << std::endl;
      76                 :         646 :     }
      77                 :             : 
      78                 :             :     //! Formatted print of a performance statistic (an item of a list)
      79                 :             :     //! \param[in] name Performance statistic name to be printed
      80                 :             :     //! \param[in] value Performance statistic value
      81                 :             :     void perfitem( const std::string& name, tk::real value ) const {
      82                 :             :       m_stream << name.c_str() << " : " << value << std::endl;
      83                 :             :     }
      84                 :             : 
      85                 :             :     //! Formatted print of elapsed times
      86                 :             :     //! \param[in] t Title of section containing a list of elapsed times
      87                 :             :     //! \param[in] clock std::vector of strings (clock names) and associated
      88                 :             :     //!   timers which could be in various formats as long as there is a
      89                 :             :     //!   corresponding item() overload that can apply operator << for outputing
      90                 :             :     //!   their value to an output stream. Examples of allowed ClockFormats are:
      91                 :             :     //!   tk::Timer::Watch, which is a struct containing a timestamp in h:m:s
      92                 :             :     //!   format, and the return value of Timer::dsec(), which is a tk::real.
      93                 :             :     template< class ClockFormat >
      94                 :         288 :     void time( const std::string& t,
      95                 :             :                const std::vector<
      96                 :             :                  std::pair< std::string, ClockFormat > >& clock ) const
      97                 :             :     {
      98                 :         288 :       section( t );
      99         [ +  + ]:         934 :       for (const auto& c : clock) item( c.first, c.second );
     100                 :         288 :       m_stream << std::endl;
     101                 :         288 :     }
     102                 :             : 
     103                 :             :     //! Echo formatted print of a diagnostics message within a progress section
     104                 :             :     //! \param[in] labels Label parts of diagnostics message
     105                 :             :     //! \param[in] values Value parts of diagnostics message
     106                 :             :     //! \note The number of labels and values must equal.
     107         [ +  - ]:          35 :     void diag( const std::vector< std::string >& labels,
     108                 :             :                const std::vector< std::string >& values ) const
     109                 :             :     {
     110                 :             :       Assert( labels.size() == values.size(), "Size mismatch" );
     111         [ +  - ]:          35 :       if (!labels.empty()) {
     112                 :          35 :         m_stream << labels[0] << ": " << values[0];
     113         [ +  + ]:         210 :         for (std::size_t i=1; i<labels.size(); ++i) {
     114                 :         175 :           m_stream << ", " << labels[i] << ": " << values[i];
     115                 :             :         }
     116                 :          35 :         m_stream << std::flush;
     117                 :             :       }
     118                 :          35 :     }
     119                 :             : 
     120                 :             :     //! Start formatted print of a diagnostics message
     121                 :             :     //! Start formatted print of a diagnostics message
     122                 :             :     //! \param[in] msg First part of message to print as a diagnostics message
     123                 :         583 :     void diagstart( const std::string& msg ) const {
     124                 :         583 :       m_stream << msg.c_str() << ' ' << std::flush;
     125                 :         583 :     }
     126                 :             : 
     127                 :             :     //! Finish formatted print of a diagnostics message
     128                 :             :     //! \param[in] msg Last part of message to print as a diagnostics message
     129                 :             :     void diagend( const std::string& msg ) const {
     130 [ +  - ][ +  - ]:         583 :       m_stream << msg.c_str() << std::endl;
         [ +  - ][ +  - ]
     131                 :         583 :     }
     132                 :             : 
     133                 :             :     //! Echo formatted print of a progress message
     134                 :             :     //! \param[in] prefix Strings to output prefixing the progress report
     135                 :             :     //! \param[in] done Array of integers indicating how many have been done
     136                 :             :     //! \param[in] max Array of integers indicating how many to be done
     137                 :             :     //! \param[in] progress_size Size of previous progress report (to overwrite)
     138                 :             :     //! \details All input arrays are the same size. The prefix strings
     139                 :             :     //!   are optional, i.e., they can be empty strings. The function generates
     140                 :             :     //!   an output to the stream configured in the following fashion:
     141                 :             :     //!   pre1[done1/max1], pre2[done2/max2], ..., e.g., r:[1/3], b[2/8].
     142                 :             :     //!   Whenever this function is called, a number of backspaces are put into
     143                 :             :     //!   the stream so that the new progress report string overwrites the old
     144                 :             :     //!   one. In order to backtrack the correct amount, the length of the old
     145                 :             :     //!   progress report is stored (by whatever object holds us) and passed in
     146                 :             :     //!   by reference in progress_size, which is overwritten here once it has
     147                 :             :     //!   been used for backtracking. Therefore, for restarting a new series of
     148                 :             :     //!   progress reports, this variable must be zeroed. Also, it is best to
     149                 :             :     //!   not to interleave multiple tasks, because even if a different
     150                 :             :     //!   progress_size is kept for each, there is no regard as to which line we
     151                 :             :     //!   output to in the stream. In other words, multiple task outputs will
     152                 :             :     //!   be intermingled, leading to confusing output.
     153                 :             :     template< std::size_t N >
     154                 :         276 :     void progress( const std::array< std::string, N >& prefix,
     155                 :             :                    const std::array< int, N >& done,
     156                 :             :                    const std::array< int, N >& max,
     157                 :             :                    std::size_t& progress_size ) const
     158                 :             :     {
     159                 :             :       // lambda to determine the number of digits in an integer
     160                 :             :       auto numdig = []( int i ) -> std::size_t {
     161                 :        4738 :         return i > 0 ?
     162                 :        1642 :           static_cast< std::size_t >( std::log10(static_cast<double>(i)) ) + 1
     163                 :             :           : 1; };
     164                 :             :       // Backspace so that new progress can overwrite old one
     165         [ +  - ]:         276 :       m_stream << std::string( progress_size, '\b' ).c_str();
     166                 :         276 :       std::stringstream ss;
     167                 :             :       auto ip = prefix.cbegin();
     168                 :             :       auto id = done.cbegin();
     169                 :             :       auto im = max.cbegin();
     170                 :         276 :       progress_size = 0;
     171         [ +  + ]:        1824 :       while (ip != prefix.cend()) {
     172                 :             :         // Compute new length of progress string
     173 [ +  + ][ +  + ]:        3190 :         progress_size += 4 + ip->size() + numdig(*id) + numdig(*im);
                 [ +  - ]
     174                 :             :         // Construct and output new progress string to stream
     175 [ +  - ][ +  - ]:        1548 :         ss << *ip << ":[" << *id << '/' << *im << ']';
         [ +  - ][ +  - ]
     176                 :        1548 :         ++ip; ++id; ++im;
     177                 :             :         // if next subprogress is not the last one, put in a comma
     178         [ +  + ]:        1548 :         if (ip != prefix.cend()) {
     179         [ +  - ]:        1272 :           ss << ", ";
     180                 :        1272 :           progress_size += 2;
     181                 :             :         } else {
     182         [ +  - ]:         276 :           ss << ' ';
     183                 :         276 :           ++progress_size;
     184                 :             :         }
     185                 :             :       }
     186 [ +  - ][ +  - ]:         276 :       m_stream << ss.str().c_str() << std::flush;
     187                 :         276 :     }
     188                 :             : 
     189                 :             :     //! Print version information
     190                 :             :     //! \param[in] executable Name of executable to output version for
     191                 :             :     //! \param[in] git_commit Git commit sha1 to output
     192                 :           3 :     void version( const std::string& executable,
     193                 :             :                   const std::string& git_commit ) const {
     194                 :           3 :       m_stream << "\nXyst::" << executable.c_str()
     195                 :           6 :                << ", revision " << git_commit.c_str() << '\n' << std::endl;
     196                 :           3 :     }
     197                 :             : 
     198                 :             :     //! Print mandatory arguments information
     199                 :             :     //! \param[in] args Mandaatory-arguments infor to output
     200                 :             :     void mandatory( const std::string& args ) const {
     201                 :             :       m_stream << "\n>>> ERROR: " << args.c_str() << std::endl;
     202                 :             :     }
     203                 :             : 
     204                 :             :     //! Print example usage information
     205                 :             :     //! \param[in] example Example command line to output
     206                 :             :     //! \param[in] msg Message to output after example
     207                 :             :     void usage( const std::string& example, const std::string& msg ) const {
     208                 :             :       m_stream << "\nUsage: " << example.c_str() << '\n'
     209                 :             :                << msg.c_str() << ". See also -h." << '\n' << std::endl;
     210                 :             :     }
     211                 :             : 
     212                 :             :     //! Print lower and upper bounds for a keyword if defined
     213                 :             :     template< typename Info >
     214                 :             :     void bounds( const Info& info ) const {
     215                 :             :       if (info.lower) {
     216                 :             :         m_stream << splitLines( *info.lower, "  ", "Lower bound: " ).c_str();
     217                 :             :       }
     218                 :             :       if (info.upper) {
     219                 :             :         m_stream << splitLines( *info.upper, "  ", "Upper bound: " ).c_str();
     220                 :             :       }
     221                 :             :       m_stream << std::flush;
     222                 :             :     }
     223                 :             : 
     224                 :             :     //! Print unit tests header (with legend)
     225                 :             :     //! \param[in] t Section title
     226                 :             :     //! \param[in] group String attempting to match unit test groups
     227                 :           2 :     void unithead( const std::string& t, const std::string& group ) const {
     228                 :           2 :       section( t );
     229 [ +  + ][ +  - ]:           3 :       m_stream << "Groups: " + (group.empty() ? "all" : group) +
     230                 :           2 :                   " (use -g str to match groups)\n" +
     231                 :             :                   "Legend: [done/failed] group/test: result\n" << std::endl;
     232                 :           2 :     }
     233                 :             : 
     234                 :             :     //! Print one-liner info for test
     235                 :             :     //! \details Columns:
     236                 :             :     //!   [done/failed]
     237                 :             :     //!   - done: number of tests completed so far
     238                 :             :     //!   - failed: number of failed tests so far
     239                 :             :     //!   name of the test group
     240                 :             :     //!   name of the test
     241                 :             :     //!   result (with additional info if failed)
     242                 :             :     //!   Assumed fields for status:
     243                 :             :     //!   - status[0]: test group name
     244                 :             :     //!   - status[1]: test name
     245                 :             :     //!   - status[2]: result (tut::test_result::result_type as string)
     246                 :             :     //!   - status[3]: exception message for failed test
     247                 :             :     //!   - status[4]: exception type id for failed test
     248         [ +  + ]:        2527 :     void test( std::size_t ncomplete,
     249                 :             :                std::size_t nfail,
     250                 :             :                const std::vector< std::string >& status )
     251                 :             :     {
     252         [ +  + ]:        2527 :       if (status[2] != "8") {             // if not dummy
     253                 :         365 :         std::stringstream ss;
     254         [ +  - ]:         365 :         ss << " [" << ncomplete << '/' << nfail << "] " << status[0] << ':'
     255         [ +  - ]:         365 :            << status[1];
     256 [ +  - ][ +  - ]:        1095 :         auto s = ss.str() + ' ' + std::string(80-ss.str().size(),'.') + "  ";
                 [ +  - ]
     257 [ +  - ][ +  - ]:         730 :         m_stream << s << result( status[2], status[3], status[4] ) << std::endl;
     258                 :         365 :       }
     259                 :        2527 :     }
     260                 :             : 
     261                 :             :     //! Print Inciter header. Text ASCII Art Generator used for executable
     262                 :             :     //! names: http://patorjk.com/software/taag.
     263                 :         268 :     void headerInciter() const {
     264                 :         268 :        m_stream << R"(
     265                 :             : ____  ___                __    __   .___              .__  __                
     266                 :             : \   \/  /___.__. _______/  |_  \ \  |   | ____   ____ |__|/  |_  ___________ 
     267                 :             :  \     /<   |  |/  ___/\   __\  \ \ |   |/    \_/ ___\|  \   __\/ __ \_  __ \
     268                 :             :  /     \ \___  |\___ \  |  |    / / |   |   |  \  \___|  ||  | \  ___/|  | \/
     269                 :             : /___/\  \/ ____/____  > |__|   /_/  |___|___|  /\___  >__||__|  \___  >__|   
     270                 :             :       \_/\/         \/                       \/     \/              \/)"
     271                 :             :       << std::endl;
     272                 :         268 :     }
     273                 :             : 
     274                 :             :     //! Print UnitTest header. Text ASCII Art Generator used for executable
     275                 :             :     //! names: http://patorjk.com/software/taag.
     276                 :           2 :     void headerUnitTest() const {
     277                 :           2 :        m_stream << R"(
     278                 :             : ____  ___                __    __    ____ ___      .__  __ ___________              __   
     279                 :             : \   \/  /___.__. _______/  |_  \ \  |    |   \____ |__|/  |\__    ___/___   _______/  |_ 
     280                 :             :  \     /<   |  |/  ___/\   __\  \ \ |    |   /    \|  \   __\|    |_/ __ \ /  ___/\   __\
     281                 :             :  /     \ \___  |\___ \  |  |    / / |    |  /   |  \  ||  |  |    |\  ___/ \___ \  |  |  
     282                 :             : /___/\  \/ ____/____  > |__|   /_/  |______/|___|  /__||__|  |____| \___  >____  > |__|  
     283                 :             :       \_/\/         \/                           \/                     \/     \/)"
     284                 :             :       << std::endl;
     285                 :           2 :     }
     286                 :             : 
     287                 :             :     //! Print MeshConv header. Text ASCII Art Generator used for executable
     288                 :             :     //! names: http://patorjk.com/software/taag.
     289                 :          20 :     void headerMeshConv() const {
     290                 :          20 :       m_stream << R"(
     291                 :             : ____  ___                __    __      _____                .__    _________                     
     292                 :             : \   \/  /___.__. _______/  |_  \ \    /     \   ____   _____|  |__ \_   ___ \  ____   _______  __
     293                 :             :  \     /<   |  |/  ___/\   __\  \ \  /  \ /  \_/ __ \ /  ___/  |  \/    \  \/ /  _ \ /    \  \/ /
     294                 :             :  /     \ \___  |\___ \  |  |    / / /    Y    \  ___/ \___ \|   Y  \     \___(  <_> )   |  \   / 
     295                 :             : /___/\  \/ ____/____  > |__|   /_/  \____|__  /\___  >____  >___|  /\______  /\____/|___|  /\_/  
     296                 :             :       \_/\/         \/                      \/     \/     \/     \/        \/            \/)"
     297                 :             :       << std::endl;
     298                 :          20 :     }
     299                 :             : 
     300                 :             :   private:
     301                 :             :     std::ostream& m_stream;     //!< Output stream
     302                 :             : 
     303                 :             :     //! Return human-readable test result based on result code
     304                 :             :     //! \param[in] code Result code
     305                 :             :     //! \param[in] msg Message to append
     306                 :             :     //! \param[in] ex Exception message to attach to exceptions cases
     307                 :         365 :     std::string result( const std::string& code,
     308                 :             :                         const std::string& msg,
     309                 :             :                         const std::string& ex ) const
     310                 :             :     {
     311         [ +  + ]:         365 :       if (code == "0") return "Pass";
     312         [ -  + ]:         103 :       else if (code == "1") return "Fail: " + msg;
     313         [ -  + ]:         103 :       else if (code == "2") return "Except: " + msg + ex;
     314         [ -  + ]:         103 :       else if (code == "3") return "Warning: " + msg;
     315         [ -  + ]:         103 :       else if (code == "4") return "Terminate: " + msg;
     316         [ -  + ]:         103 :       else if (code == "5") return "Ex_ctor: " + msg + ex;
     317         [ -  + ]:         103 :       else if (code == "6") return "Rethrown: " + msg + ex;
     318         [ +  - ]:         103 :       else if (code == "7") return "Skipped: " + msg;
     319         [ -  - ]:           0 :       else if (code == "8") return "Dummy";
     320 [ -  - ][ -  - ]:           0 :       else Throw( "No such unit test result code found" );
                 [ -  - ]
     321                 :             :     }
     322                 :             : };
     323                 :             : 
     324                 :             : } // tk::
        

Generated by: LCOV version 2.0-1