22#include <stdio.h>
33#include <time.h>
44#include <string.h>
5+ #ifdef __unix__
6+ #include <unistd.h>
7+ #endif
58
69// JUnit XML state tracking
710#define MAX_TESTS 100
811static struct {
912 char name [64 ];
1013 int passed ;
14+ double duration ; // Test execution time in seconds
1115} test_results [MAX_TESTS ];
1216static int test_count = 0 ;
1317static time_t start_time ;
1418static int junit_enabled = 0 ;
19+ static clock_t current_test_start ;
1520
1621// Initialize JUnit XML output
1722void initJunitXml (void ) {
1823 junit_enabled = 1 ;
1924 test_count = 0 ;
2025 start_time = time (NULL );
26+ current_test_start = 0 ;
27+ }
28+
29+ // Start timing a test case
30+ void startTestTiming (void ) {
31+ if (!junit_enabled ) return ;
32+ current_test_start = clock ();
2133}
2234
2335// Record a test result for JUnit XML output
2436void recordJunitTestResult (const char * testName , bin_int_t results ) {
2537 if (!junit_enabled || test_count >= MAX_TESTS ) return ;
2638
39+ // Calculate test duration
40+ double duration = 0.0 ;
41+ if (current_test_start != 0 ) {
42+ clock_t end_time = clock ();
43+ duration = ((double )(end_time - current_test_start )) / CLOCKS_PER_SEC ;
44+ }
45+
2746 strncpy (test_results [test_count ].name , testName , sizeof (test_results [test_count ].name ) - 1 );
2847 test_results [test_count ].name [sizeof (test_results [test_count ].name ) - 1 ] = '\0' ;
2948 test_results [test_count ].passed = results ;
49+ test_results [test_count ].duration = duration ;
3050 test_count ++ ;
3151}
3252
@@ -50,16 +70,78 @@ void finalizeJunitXml(void) {
5070
5171 fprintf (junit_file , "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
5272 fprintf (junit_file , "<testsuites>\n" );
53- fprintf (junit_file , " <testsuite name=\"libbin_tests\" tests=\"%d\" failures=\"%d\" time=\"%.3f\" timestamp=\"%ld\">\n" ,
54- test_count , failure_count , duration , (long )start_time );
73+
74+ // Get hostname
75+ char hostname [256 ] = "unknown" ;
76+ #ifdef __unix__
77+ if (gethostname (hostname , sizeof (hostname )) != 0 ) {
78+ strcpy (hostname , "unix-host" );
79+ }
80+ #elif defined(_WIN32 )
81+ strcpy (hostname , "windows-host" );
82+ #else
83+ strcpy (hostname , "unknown-host" );
84+ #endif
85+
86+ // Format ISO 8601 timestamp
87+ char iso_timestamp [32 ];
88+ struct tm * tm_info = gmtime (& start_time );
89+ strftime (iso_timestamp , sizeof (iso_timestamp ), "%Y-%m-%dT%H:%M:%SZ" , tm_info );
90+
91+ fprintf (junit_file , " <testsuite name=\"libbin_tests\" tests=\"%d\" failures=\"%d\" errors=\"0\" skipped=\"0\" time=\"%.3f\" timestamp=\"%s\" hostname=\"%s\">\n" ,
92+ test_count , failure_count , duration , iso_timestamp , hostname );
93+
94+ // Add properties section with environment info
95+ fprintf (junit_file , " <properties>\n" );
96+ fprintf (junit_file , " <property name=\"test.framework\" value=\"libbin-custom\"/>\n" );
97+ fprintf (junit_file , " <property name=\"test.language\" value=\"C\"/>\n" );
98+ fprintf (junit_file , " <property name=\"test.standard\" value=\"c2x\"/>\n" );
99+ fprintf (junit_file , " <property name=\"test.compiler\" value=\"clang\"/>\n" );
100+ #ifdef __VERSION__
101+ fprintf (junit_file , " <property name=\"test.compiler.version\" value=\"%s\"/>\n" , __VERSION__ );
102+ #endif
103+ #ifdef BIN_BITS
104+ fprintf (junit_file , " <property name=\"libbin.bits\" value=\"%d\"/>\n" , BIN_BITS );
105+ #endif
106+ #ifdef BIN_INT_MAX
107+ fprintf (junit_file , " <property name=\"libbin.int_max\" value=\"%d\"/>\n" , BIN_INT_MAX );
108+ #endif
109+ fprintf (junit_file , " <property name=\"test.date\" value=\"%s\"/>\n" , iso_timestamp );
110+ fprintf (junit_file , " </properties>\n" );
55111
56112 for (int i = 0 ; i < test_count ; i ++ ) {
57- fprintf (junit_file , " <testcase name=\"%s\" classname=\"libbin\"" , test_results [i ].name );
113+ // Determine test category from name
114+ const char * category = "misc" ;
115+ if (strstr (test_results [i ].name , "bin" ) == test_results [i ].name ) {
116+ if (strstr (test_results [i ].name , "MSB" ) || strstr (test_results [i ].name , "LSB" ) ||
117+ strstr (test_results [i ].name , "Shift" ) || strstr (test_results [i ].name , "AND" ) ||
118+ strstr (test_results [i ].name , "OR" ) || strstr (test_results [i ].name , "XOR" ) ||
119+ strstr (test_results [i ].name , "NOT" ) || strstr (test_results [i ].name , "Rotate" )) {
120+ category = "bitwise" ;
121+ } else if (strstr (test_results [i ].name , "Add" ) || strstr (test_results [i ].name , "Sub" ) ||
122+ strstr (test_results [i ].name , "Mult" ) || strstr (test_results [i ].name , "Div" ) ||
123+ strstr (test_results [i ].name , "Mod" ) || strstr (test_results [i ].name , "Pow" ) ||
124+ strstr (test_results [i ].name , "Sqrt" ) || strstr (test_results [i ].name , "Log" )) {
125+ category = "math" ;
126+ } else if (strstr (test_results [i ].name , "EQ" ) || strstr (test_results [i ].name , "GT" ) ||
127+ strstr (test_results [i ].name , "LT" )) {
128+ category = "boolean" ;
129+ }
130+ }
131+
132+ fprintf (junit_file , " <testcase name=\"%s\" classname=\"libbin.%s\" time=\"%.6f\"" ,
133+ test_results [i ].name , category , test_results [i ].duration );
134+
58135 if (test_results [i ].passed ) {
59- fprintf (junit_file , "/>\n" );
136+ fprintf (junit_file , ">\n" );
137+ fprintf (junit_file , " <system-out><![CDATA[Test passed successfully]]></system-out>\n" );
138+ fprintf (junit_file , " </testcase>\n" );
60139 } else {
61140 fprintf (junit_file , ">\n" );
62- fprintf (junit_file , " <failure message=\"Test failed\" type=\"AssertionError\"></failure>\n" );
141+ fprintf (junit_file , " <failure message=\"Test assertion failed\" type=\"AssertionError\">\n" );
142+ fprintf (junit_file , " <![CDATA[Test '%s' failed assertion checks]]>\n" , test_results [i ].name );
143+ fprintf (junit_file , " </failure>\n" );
144+ fprintf (junit_file , " <system-err><![CDATA[Test failed - check implementation]]></system-err>\n" );
63145 fprintf (junit_file , " </testcase>\n" );
64146 }
65147 }
@@ -79,6 +161,6 @@ void processTestResults(const char* testName, const bin_int_t results) {
79161 printf (format , testName , color , text , CC_RESET );
80162 fflush (stdout );
81163
82- // Also record for JUnit XML
164+ // Also record for JUnit XML (timing already started before test execution)
83165 recordJunitTestResult (testName , results );
84166}
0 commit comments