aboutsummaryrefslogtreecommitdiff
path: root/src/tools/rununits.cpp
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2023-08-08 16:33:38 -0700
committerMike Buland <eichlan@xagasoft.com>2023-08-08 16:33:38 -0700
commitc7e1277ecaf40c6d8ee945418a306f5b15189b97 (patch)
tree05a04473ffe90a76a4e7dd170c221141fea87b7e /src/tools/rununits.cpp
parent7c36f58654f1b238d1b416927c9485a151216b1b (diff)
downloadlibbu++-c7e1277ecaf40c6d8ee945418a306f5b15189b97.tar.gz
libbu++-c7e1277ecaf40c6d8ee945418a306f5b15189b97.tar.bz2
libbu++-c7e1277ecaf40c6d8ee945418a306f5b15189b97.tar.xz
libbu++-c7e1277ecaf40c6d8ee945418a306f5b15189b97.zip
Unit test augmentations and harness.
Added some features to the mkunit program, including cleanup routine support. Added reporting modes for the UnitSuite class, and it can now generate machine readable reports. Added a new program, rununits that runs all unit tests and generates a synopsis of what you really care about at the end, issues!
Diffstat (limited to 'src/tools/rununits.cpp')
-rw-r--r--src/tools/rununits.cpp186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/tools/rununits.cpp b/src/tools/rununits.cpp
new file mode 100644
index 0000000..769d3ab
--- /dev/null
+++ b/src/tools/rununits.cpp
@@ -0,0 +1,186 @@
1#include <bu/sio.h>
2#include <bu/json.h>
3#include <bu/process.h>
4#include <bu/optparser.h>
5#include <bu/blob.h>
6#include <bu/blobbuilder.h>
7
8#include <sys/types.h>
9#include <dirent.h>
10
11Bu::Blob getSuiteName( const Bu::Blob &bSuiteExec )
12{
13 Bu::Process proc(
14 Bu::Process::StdOut,
15 bSuiteExec.getData(),
16 bSuiteExec.getData(),
17 "--print-name",
18 NULL
19 );
20
21 Bu::String sResult = proc.readAll().trimWhitespace();
22 Bu::Blob bRet( sResult.getStr(), sResult.getSize() );
23 return bRet;
24}
25
26Bu::Json *runSuite( const Bu::Blob &bSuiteExec )
27{
28 Bu::Process proc(
29 Bu::Process::StdOut,
30 bSuiteExec.getData(),
31 bSuiteExec.getData(),
32 "--interop",
33 NULL
34 );
35 Bu::BlobBuilder bbReport;
36 while( proc.isRunning() )
37 {
38 int iRead = 0;
39 char dRead[4096];
40 iRead = proc.read( dRead, 4096 );
41 if( iRead > 0 )
42 {
43 bbReport.append( dRead, iRead );
44 }
45 }
46 Bu::Json *pReport = new Bu::Json();
47 pReport->parse( bbReport.getBlob() );
48 return pReport;
49}
50
51typedef Bu::List<Bu::Blob> BlobList;
52
53BlobList getSuitePaths( const Bu::Blob &bDir )
54{
55 BlobList lPaths;
56 DIR *dir = opendir( bDir.getData() );
57 if( dir == NULL )
58 {
59 Bu::println("Could not open directory: %1").arg( bDir );
60 return lPaths;
61 }
62 struct dirent *de = NULL;
63 while( (de = readdir( dir )) != NULL )
64 {
65 if( de->d_type != DT_REG )
66 continue;
67
68 Bu::BlobBuilder bbPath;
69 bbPath.append( bDir );
70 bbPath.append("/");
71 bbPath.append( de->d_name );
72 Bu::Blob bPath = bbPath.getBlob();
73 if( access( bPath.getData(), X_OK ) != 0 )
74 continue;
75
76 lPaths.append( bPath );
77 }
78 closedir( dir );
79
80 return lPaths;
81}
82
83int main( int /*argc*/, char * /*argv*/[] )
84{
85 Bu::Blob bDir("unit");
86 BlobList lPaths = getSuitePaths( bDir );
87
88 int iNumLen = Bu::String("%1").arg( lPaths.getSize() ).end().getSize();
89 int iMaxSuiteName = 0;
90 Bu::Hash<Bu::Blob, Bu::Blob> hName;
91 for( BlobList::iterator i = lPaths.begin(); i; i++ )
92 {
93 Bu::Blob bSuiteName = getSuiteName( *i );
94 if( iMaxSuiteName < bSuiteName.getSize() )
95 iMaxSuiteName = bSuiteName.getSize();
96 hName.insert( *i, bSuiteName );
97 }
98
99 Bu::List<Bu::Json *> lReport;
100
101 int iTest = 0;
102 for( BlobList::iterator i = lPaths.begin(); i; i++ )
103 {
104 iTest++;
105 Bu::Blob bSuiteName = hName.get( *i );
106 Bu::print("\rRunning test suite [%1/%2]: %3")
107 .arg( iTest, Bu::Fmt().width( iNumLen ).right() )
108 .arg( lPaths.getSize(), Bu::Fmt().width( iNumLen ) )
109 .arg( bSuiteName, Bu::Fmt().width( iMaxSuiteName ).fill(' ').left() );
110 Bu::sio << Bu::sio.flush;
111
112 Bu::Json *pReport = runSuite( (*i) );
113 int iUnexpected = 0;
114 int iTotal = 0;
115 iTotal = (*pReport)["tests"].getSize();
116 for( int j = 0; j < iTotal; j++ )
117 {
118 if( !((*pReport)["tests"][j]["expected"].getString() ==
119 (*pReport)["tests"][j]["result"].getString()) )
120 {
121 iUnexpected++;
122 }
123 }
124 if( iUnexpected == 0 )
125 {
126 delete pReport;
127 }
128 else
129 {
130 lReport.append( pReport );
131 }
132 }
133 Bu::println("\rCompleted %1 unit test suites.%2")
134 .arg( lPaths.getSize(), Bu::Fmt().width( iNumLen ) )
135 .arg( Bu::Blob(""), Bu::Fmt().width( iMaxSuiteName ).fill(' ').left() );
136
137 if( lReport.getSize() == 0 )
138 {
139 Bu::println("\nNothing unexpected in unit tests.");
140 }
141 else
142 {
143 for( Bu::List<Bu::Json *>::iterator i = lReport.begin(); i; i++ )
144 {
145 Bu::println("\nUnexpected results in: %1")
146 .arg( (**i)["suite"].getString().get() );
147
148 for( Bu::Json::iterator iTest = (**i)["tests"].begin();
149 iTest; iTest++ )
150 {
151 if( (**iTest)["expected"].getString() ==
152 (**iTest)["result"].getString() )
153 {
154 continue;
155 }
156
157 Bu::println(" %1: unexpected %2")
158 .arg( (**iTest)["name"].getString().get() )
159 .arg( (**iTest)["result"].getString().get() );
160 if( (**iTest).has("fail") )
161 {
162 if( (**iTest)["fail"].has("action") )
163 {
164 Bu::println(" unitTest( %1 );")
165 .arg( (**iTest)["fail"]["action"].getString().get() );
166 Bu::println(" at %1:%2")
167 .arg( (**iTest)["fail"]["file"].getString().get() )
168 .arg( (int)(**iTest)["fail"]["line"].getNumber() );
169 }
170 else if( (**iTest)["fail"].has("what") )
171 {
172 Bu::println(" Unexpected exception: %1")
173 .arg( (**iTest)["fail"]["what"].getString().get() );
174 }
175 }
176 else
177 {
178 Bu::println(" No further details.");
179 }
180 }
181 delete *i;
182 }
183 }
184
185 return 0;
186}