2024-01-12 22:32:45 +01:00
# include <iostream>
# include <optional>
# include "tester.hpp"
const std : : string ANSI_RESET = " \033 [0m " ;
2024-01-17 14:46:35 +01:00
const std : : string ANSI_DARK = " \033 [38;5;8m " ; // dark gray
const std : : string ANSI_LISTING = " \033 [38;5;208m " ; // orange
const std : : string ANSI_INFO = " \033 [38;5;6m " ; // blue
const std : : string ANSI_SUCCESS = " \033 [38;5;2m " ; // green
const std : : string ANSI_FAIL = " \033 [38;5;1m " ; // red
2024-01-12 22:32:45 +01:00
2024-01-17 12:25:06 +01:00
Tester : : Tester ( std : : string test_name ) :
parent ( ) ,
name ( test_name ) ,
succeeded ( 0 ) , failed ( 0 ) ,
2024-01-17 14:38:14 +01:00
detailed ( true ) ,
started ( std : : chrono : : steady_clock : : now ( ) )
2024-01-17 12:25:06 +01:00
{
intro ( ) ;
}
Tester : : Tester ( Tester * tester_parent , std : : string test_name ) :
parent ( tester_parent ) ,
name ( test_name ) ,
succeeded ( 0 ) , failed ( 0 ) ,
2024-01-17 14:38:14 +01:00
detailed ( false ) ,
started ( std : : chrono : : steady_clock : : now ( ) )
2024-01-17 12:25:06 +01:00
{
intro ( ) ;
}
Tester : : Tester ( Tester * tester_parent , std : : string test_name , bool show_details ) :
parent ( tester_parent ) ,
name ( test_name ) ,
succeeded ( 0 ) , failed ( 0 ) ,
2024-01-17 14:38:14 +01:00
detailed ( show_details ) ,
started ( std : : chrono : : steady_clock : : now ( ) )
2024-01-17 12:25:06 +01:00
{
intro ( ) ;
}
2024-01-12 22:32:45 +01:00
int Tester : : depth ( ) {
int depth = 0 ;
for ( std : : optional < Tester * > at = this ; at . has_value ( ) ; at = ( * at ) - > parent ) {
depth + + ;
}
return depth ;
}
std : : string Tester : : full_name ( ) {
std : : string full_name ( name ) ;
std : : optional < Tester * > at = parent ;
while ( at . has_value ( ) ) {
full_name . insert ( 0 , " " ) ;
full_name . insert ( 0 , ( * at ) - > name ) ;
at = ( * at ) - > parent ;
}
return full_name ;
}
std : : string Tester : : prefix ( ) {
std : : string line = full_name ( ) ;
line . insert ( 0 , " [ " ) ;
line . append ( " ] " ) ;
int wanted_len = 10 * depth ( ) ;
if ( line . length ( ) = = wanted_len ) {
2024-01-17 14:46:35 +01:00
line . insert ( 0 , ANSI_LISTING ) ;
2024-01-12 22:32:45 +01:00
line . append ( ANSI_RESET ) ;
line . append ( " " ) ;
return line ;
} else if ( line . length ( ) > wanted_len ) {
line . append ( " \n " ) ;
line . append ( ANSI_DARK ) ;
for ( int i = 0 ; i < wanted_len ; i + + )
line . append ( " — " ) ;
2024-01-17 14:46:35 +01:00
line . insert ( 0 , ANSI_LISTING ) ;
2024-01-12 22:32:45 +01:00
line . append ( ANSI_RESET ) ;
line . append ( " " ) ;
return line ;
} else {
int extra = wanted_len - line . length ( ) ;
line . append ( " " ) ;
line . append ( ANSI_DARK ) ;
for ( int i = 1 ; i < extra ; i + + )
line . append ( " — " ) ;
2024-01-17 14:46:35 +01:00
line . insert ( 0 , ANSI_LISTING ) ;
2024-01-12 22:32:45 +01:00
line . append ( ANSI_RESET ) ;
line . append ( " " ) ;
return line ;
}
}
void Tester : : intro ( ) {
2024-01-17 12:25:06 +01:00
if ( shown ( ) )
2024-01-17 14:46:35 +01:00
std : : cout < < prefix ( ) < < " === " < < ANSI_INFO < < " start " < < ANSI_RESET < < std : : endl ;
2024-01-12 22:32:45 +01:00
}
2024-01-17 12:25:06 +01:00
bool name_show_overwritten ( std : : string name ) {
char * shown_c = std : : getenv ( " SHOW_CASE " ) ;
if ( shown_c = = NULL )
return false ;
std : : string shown ( shown_c ) ;
shown . push_back ( ' ' ) ;
shown . insert ( 0 , " " ) ;
name . push_back ( ' ' ) ;
name . insert ( 0 , " " ) ;
return shown . find ( name ) ! = std : : string : : npos ;
2024-01-12 22:32:45 +01:00
}
2024-01-17 12:25:06 +01:00
bool Tester : : shown ( ) {
for ( std : : optional < Tester * > at = this ; at . has_value ( ) ; at = ( * at ) - > parent ) {
if ( name_show_overwritten ( ( * at ) - > name ) )
return true ;
}
for ( std : : optional < Tester * > at = this ; at . has_value ( ) ; at = ( * at ) - > parent ) {
if ( ! ( * at ) - > detailed )
return false ;
}
return true ;
2024-01-12 22:32:45 +01:00
}
void Tester : : assert_eq_str ( std : : string test_name , bool correct , std : : string got_s , std : : string expected_s ) {
if ( correct ) {
2024-01-17 12:25:06 +01:00
if ( shown ( ) ) {
2024-01-17 14:46:35 +01:00
std : : cout < < prefix ( ) < < ANSI_SUCCESS < < " ✓ " < < ANSI_RESET < < test_name < < ANSI_RESET < < std : : endl ;
2024-01-17 12:25:06 +01:00
}
2024-01-12 22:32:45 +01:00
for ( std : : optional < Tester * > at = this ; at . has_value ( ) ; at = ( * at ) - > parent ) {
( * at ) - > succeeded + + ;
}
} else {
2024-01-17 14:46:35 +01:00
std : : cout < < prefix ( ) < < ANSI_FAIL < < " ✗ " < < ANSI_RESET < < test_name < < " - " < < ANSI_FAIL < < " got " < < got_s < < " , expected " < < expected_s < < ANSI_RESET < < std : : endl ;
2024-01-12 22:32:45 +01:00
for ( std : : optional < Tester * > at = this ; at . has_value ( ) ; at = ( * at ) - > parent ) {
( * at ) - > failed + + ;
}
}
}
Tester : : ~ Tester ( ) {
finish ( ) ;
}
void Tester : : finish ( ) {
2024-01-17 14:38:14 +01:00
std : : chrono : : duration < double > time_taken = std : : chrono : : steady_clock : : now ( ) - started ;
double time_secs = time_taken . count ( ) ;
double time_per_test_secs = time_secs / ( succeeded + failed ) ;
char time_s [ 20 ] , time_per_s [ 20 ] ;
if ( time_secs < 1e-6 ) {
snprintf ( time_s , sizeof time_s , " %.1fns " , time_secs * 1e9 ) ;
} else if ( time_secs < 1e-3 ) {
snprintf ( time_s , sizeof time_s , " %.1fµs " , time_secs * 1e6 ) ;
} else if ( time_secs < 1 ) {
snprintf ( time_s , sizeof time_s , " %.1fms " , time_secs * 1e3 ) ;
} else {
snprintf ( time_s , sizeof time_s , " %.1fs " , time_secs ) ;
}
if ( time_per_test_secs < 1e-6 ) {
snprintf ( time_per_s , sizeof time_per_s , " %.1fns " , time_per_test_secs * 1e9 ) ;
} else if ( time_per_test_secs < 1e-3 ) {
snprintf ( time_per_s , sizeof time_per_s , " %.1fµs " , time_per_test_secs * 1e6 ) ;
} else if ( time_per_test_secs < 1 ) {
snprintf ( time_per_s , sizeof time_per_s , " %.1fms " , time_per_test_secs * 1e3 ) ;
} else {
snprintf ( time_per_s , sizeof time_per_s , " %.1fs " , time_per_test_secs ) ;
}
2024-01-12 22:32:45 +01:00
char n_cases_s [ 10 ] , n_succeeded_s [ 10 ] , n_failed_s [ 10 ] ;
snprintf ( n_cases_s , sizeof n_cases_s , " %d " , succeeded + failed ) ;
snprintf ( n_succeeded_s , sizeof n_succeeded_s , " %d " , succeeded ) ;
snprintf ( n_failed_s , sizeof n_failed_s , " %d " , failed ) ;
2024-01-17 14:38:14 +01:00
bool printed = false ;
2024-01-12 22:32:45 +01:00
if ( failed = = 0 ) {
2024-01-17 14:38:14 +01:00
if ( shown ( ) ) {
2024-01-17 14:46:35 +01:00
std : : cout < < prefix ( ) < < " === " < < ANSI_SUCCESS < < " all succeeded " < < ANSI_RESET < < " , out of " < < n_cases_s < < " total " ;
2024-01-17 14:38:14 +01:00
printed = true ;
}
2024-01-12 22:32:45 +01:00
} else {
2024-01-17 14:46:35 +01:00
std : : cout < < prefix ( ) < < " === " < < ANSI_FAIL < < n_failed_s < < " failed " < < ANSI_RESET < < " , " < < ANSI_SUCCESS < < n_succeeded_s < < " succeeded " < < ANSI_RESET < < " out of " < < n_cases_s < < " total " ;
2024-01-17 14:38:14 +01:00
printed = true ;
2024-01-12 22:32:45 +01:00
}
2024-01-17 14:38:14 +01:00
if ( printed )
2024-01-17 14:46:35 +01:00
std : : cout < < " ( " < < ANSI_INFO < < time_s < < ANSI_RESET < < " total, " < < ANSI_INFO < < time_per_s < < ANSI_RESET < < " per test) " < < std : : endl ;
2024-01-12 22:32:45 +01:00
}