Xyst test code coverage report
Current view: top level - Base - Print.hpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 94 103 91.3 %
Date: 2024-11-22 19:17:03 Functions: 64 67 95.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 68 164 41.5 %

           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-2024 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                 :       9745 :     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                 :     129890 :     friend const Print& operator<<( const Print& os, const T& t ) {
      42                 :     129890 :       os.m_stream << t << std::flush;
      43                 :     129890 :       return os;
      44                 :            :     }
      45                 :            : 
      46                 :            :     //! Formatted print of section title
      47                 :            :     //! \param[in] t Section title to be printed
      48                 :       2331 :     void section( const std::string& t ) const {
      49         [ +  - ]:       2331 :       std::string underline( t.size(), '-' );
      50 [ +  - ][ +  - ]:       2331 :       m_stream << '\n' << t.c_str() << '\n' << underline.c_str() << std::endl;
         [ +  - ][ +  - ]
                 [ +  - ]
      51                 :       2331 :     }
      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                 :       4271 :     void item( const std::string& name, const T& value ) const {
      58                 :       4271 :       m_stream << name.c_str() << ": ";
      59                 :            :       if constexpr( std::is_same_v< T, std::string > ) {
      60                 :       2717 :         m_stream << value.c_str();
      61                 :            :       } else {
      62                 :       1554 :         m_stream << value;
      63                 :            :       }
      64                 :       4271 :       m_stream << std::endl;
      65                 :       4271 :     }
      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                 :        618 :     void item( const std::string& name, const tk::Timer::Watch& watch ) const {
      72                 :        618 :       m_stream << name.c_str() << ": "
      73                 :        618 :                << watch.hrs.count() << ':'
      74                 :        618 :                << watch.min.count() << ':'
      75                 :        618 :                << watch.sec.count() << std::endl;
      76                 :        618 :     }
      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                 :        273 :     void time( const std::string& t,
      95                 :            :                const std::vector<
      96                 :            :                  std::pair< std::string, ClockFormat > >& clock ) const
      97                 :            :     {
      98                 :        273 :       section( t );
      99 [ +  - ][ +  + ]:        891 :       for (const auto& c : clock) item( c.first, c.second );
     100                 :        273 :       m_stream << std::endl;
     101                 :        273 :     }
     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 [ -  + ][ -  - ]:         35 :       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                 :        557 :     void diagstart( const std::string& msg ) const {
     124                 :        557 :       m_stream << msg.c_str() << ' ' << std::flush;
     125                 :        557 :     }
     126                 :            : 
     127                 :            :     //! Finish formatted print of a diagnostics message
     128                 :            :     //! \param[in] msg Last part of message to print as a diagnostics message
     129                 :        557 :     void diagend( const std::string& msg ) const {
     130                 :        557 :       m_stream << msg.c_str() << std::endl;
     131                 :        557 :     }
     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                 :        230 :     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                 :       2596 :       auto numdig = []( int i ) -> std::size_t {
     161 [ +  - ][ +  + ]:       2596 :         return i > 0 ?
     162                 :       1402 :           static_cast< std::size_t >( std::log10(static_cast<double>(i)) ) + 1
     163                 :       2596 :           : 1; };
     164                 :            :       // Backspace so that new progress can overwrite old one
     165 [ +  - ][ +  - ]:        230 :       m_stream << std::string( progress_size, '\b' ).c_str();
     166         [ +  - ]:        230 :       std::stringstream ss;
     167                 :        230 :       auto ip = prefix.cbegin();
     168                 :        230 :       auto id = done.cbegin();
     169                 :        230 :       auto im = max.cbegin();
     170                 :        230 :       progress_size = 0;
     171         [ +  + ]:       1528 :       while (ip != prefix.cend()) {
     172                 :            :         // Compute new length of progress string
     173                 :       1298 :         progress_size += 4 + ip->size() + numdig(*id) + numdig(*im);
     174                 :            :         // Construct and output new progress string to stream
     175 [ +  - ][ +  - ]:       1298 :         ss << *ip << ":[" << *id << '/' << *im << ']';
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     176                 :       1298 :         ++ip; ++id; ++im;
     177                 :            :         // if next subprogress is not the last one, put in a comma
     178         [ +  + ]:       1298 :         if (ip != prefix.cend()) {
     179         [ +  - ]:       1068 :           ss << ", ";
     180                 :       1068 :           progress_size += 2;
     181                 :            :         } else {
     182         [ +  - ]:        230 :           ss << ' ';
     183                 :        230 :           ++progress_size;
     184                 :            :         }
     185                 :            :       }
     186 [ +  - ][ +  - ]:        230 :       m_stream << ss.str().c_str() << std::flush;
                 [ +  - ]
     187                 :        230 :     }
     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                 :          3 :                << ", 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 [ +  + ][ +  - ]:          4 :       m_stream << "Groups: " + (group.empty() ? "all" : group) +
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
                 [ -  - ]
     230         [ +  - ]:          4 :                   " (use -g str to match groups)\n" +
     231 [ +  - ][ +  - ]:          2 :                   "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 [ +  - ][ +  - ]:        365 :         auto s = ss.str() + ' ' + std::string(80-ss.str().size(),'.') + "  ";
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     257 [ +  - ][ +  - ]:        365 :         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                 :        253 :     void headerInciter() const {
     264                 :        253 :        m_stream << R"(
     265                 :            : ____  ___                __    __   .___              .__  __                
     266                 :            : \   \/  /___.__. _______/  |_  \ \  |   | ____   ____ |__|/  |_  ___________ 
     267                 :            :  \     /<   |  |/  ___/\   __\  \ \ |   |/    \_/ ___\|  \   __\/ __ \_  __ \
     268                 :            :  /     \ \___  |\___ \  |  |    / / |   |   |  \  \___|  ||  | \  ___/|  | \/
     269                 :            : /___/\  \/ ____/____  > |__|   /_/  |___|___|  /\___  >__||__|  \___  >__|   
     270                 :            :       \_/\/         \/                       \/     \/              \/)"
     271                 :        253 :       << std::endl;
     272                 :        253 :     }
     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                 :          2 :       << 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                 :         20 :       << 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 Expection 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         [ -  - ]:          0 :       else if (code == "1") return "Fail: " + msg;
     313 [ -  - ][ -  - ]:          0 :       else if (code == "2") return "Except: " + msg + ex;
                 [ -  - ]
     314         [ -  - ]:          0 :       else if (code == "3") return "Warning: " + msg;
     315         [ -  - ]:          0 :       else if (code == "4") return "Terminate: " + msg;
     316 [ -  - ][ -  - ]:          0 :       else if (code == "5") return "Ex_ctor: " + msg + ex;
                 [ -  - ]
     317 [ -  - ][ -  - ]:          0 :       else if (code == "6") return "Rethrown: " + msg + ex;
                 [ -  - ]
     318         [ -  - ]:          0 :       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 1.16