@@ -171,4 +171,132 @@ describe('CLI integration', () => {
171171 expect ( result . exitCode ) . not . toBe ( 0 ) ;
172172 } ) ;
173173 } ) ;
174+
175+ describe ( 'ci' , ( ) => {
176+ it ( 'runs all scenarios and exits 0 when all pass' , async ( ) => {
177+ const result = await runCli ( 'ci' ) ;
178+ expect ( result . exitCode ) . toBe ( 0 ) ;
179+ expect ( result . stdout ) . toContain ( 'CI Mode' ) ;
180+ expect ( result . stdout ) . toContain ( 'PASS' ) ;
181+ } ) ;
182+
183+ it ( 'supports --format json' , async ( ) => {
184+ const result = await runCli ( 'ci' , '--format' , 'json' ) ;
185+ expect ( result . exitCode ) . toBe ( 0 ) ;
186+ const parsed = JSON . parse ( result . stdout ) ;
187+ expect ( parsed ) . toHaveProperty ( 'results' ) ;
188+ expect ( parsed ) . toHaveProperty ( 'allPassed' ) ;
189+ expect ( parsed . allPassed ) . toBe ( true ) ;
190+ expect ( parsed . results . length ) . toBeGreaterThan ( 0 ) ;
191+ } ) ;
192+ } ) ;
193+
194+ describe ( 'anonymize' , ( ) => {
195+ it ( 'anonymizes sensitive fields in a trace' , async ( ) => {
196+ const trace = {
197+ events : [
198+ {
199+ timestamp : '2024-01-15T10:00:00.000Z' ,
200+ message : [
201+ 2 ,
202+ 'msg-001' ,
203+ 'BootNotification' ,
204+ {
205+ chargePointSerialNumber : 'REAL-SERIAL-001' ,
206+ chargePointVendor : 'VendorX' ,
207+ } ,
208+ ] ,
209+ } ,
210+ {
211+ timestamp : '2024-01-15T10:00:01.000Z' ,
212+ message : [ 2 , 'msg-002' , 'Authorize' , { idTag : 'REAL-TAG-123' } ] ,
213+ } ,
214+ {
215+ timestamp : '2024-01-15T10:00:02.000Z' ,
216+ message : [ 2 , 'msg-003' , 'StartTransaction' , { connectorId : 1 , idTag : 'REAL-TAG-123' } ] ,
217+ } ,
218+ {
219+ timestamp : '2024-01-15T10:00:02.500Z' ,
220+ message : [ 3 , 'msg-003' , { transactionId : 99999 , idTagInfo : { status : 'Accepted' } } ] ,
221+ } ,
222+ ] ,
223+ } ;
224+ const filePath = writeTempTrace ( trace ) ;
225+ const result = await runCli ( 'anonymize' , filePath ) ;
226+ expect ( result . exitCode ) . toBe ( 0 ) ;
227+ expect ( result . stdout ) . not . toContain ( 'REAL-SERIAL-001' ) ;
228+ expect ( result . stdout ) . not . toContain ( 'REAL-TAG-123' ) ;
229+ expect ( result . stdout ) . toContain ( 'anonymized' ) ;
230+ expect ( result . stdout ) . toContain ( 'station-anon' ) ;
231+ } ) ;
232+
233+ it ( 'writes to file with --output' , async ( ) => {
234+ const trace = {
235+ events : [
236+ {
237+ timestamp : '2024-01-15T10:00:00.000Z' ,
238+ message : [ 2 , 'msg-001' , 'BootNotification' , { chargePointSerialNumber : 'SECRET' } ] ,
239+ } ,
240+ ] ,
241+ } ;
242+ const filePath = writeTempTrace ( trace ) ;
243+ const outputPath = join ( mkdtempSync ( join ( tmpdir ( ) , 'ocpp-out-' ) ) , 'anon.json' ) ;
244+ const result = await runCli ( 'anonymize' , filePath , '--output' , outputPath ) ;
245+ expect ( result . exitCode ) . toBe ( 0 ) ;
246+ expect ( result . stdout ) . toContain ( 'Anonymized trace written to' ) ;
247+ } ) ;
248+ } ) ;
249+
250+ describe ( 'diff' , ( ) => {
251+ it ( 'shows differences between two traces' , async ( ) => {
252+ const traceA = {
253+ events : [
254+ {
255+ timestamp : '2024-01-15T10:00:00.000Z' ,
256+ message : [ 2 , 'msg-001' , 'BootNotification' , { chargePointSerialNumber : 'CS-001' } ] ,
257+ } ,
258+ {
259+ timestamp : '2024-01-15T10:00:00.500Z' ,
260+ message : [ 3 , 'msg-001' , { status : 'Accepted' , interval : 60 } ] ,
261+ } ,
262+ ] ,
263+ } ;
264+ const traceB = {
265+ events : [
266+ {
267+ timestamp : '2024-01-15T10:00:00.000Z' ,
268+ message : [ 2 , 'msg-001' , 'BootNotification' , { chargePointSerialNumber : 'CS-001' } ] ,
269+ } ,
270+ {
271+ timestamp : '2024-01-15T10:00:01.500Z' ,
272+ message : [ 3 , 'msg-001' , { status : 'Accepted' , interval : 60 } ] ,
273+ } ,
274+ ] ,
275+ } ;
276+ const fileA = writeTempTrace ( traceA ) ;
277+ const fileB = writeTempTrace ( traceB ) ;
278+ const result = await runCli ( 'diff' , fileA , fileB ) ;
279+ expect ( result . exitCode ) . toBe ( 0 ) ;
280+ expect ( result . stdout ) . toContain ( 'Trace Diff' ) ;
281+ expect ( result . stdout ) . toContain ( 'Modified events' ) ;
282+ } ) ;
283+
284+ it ( 'supports --format json' , async ( ) => {
285+ const traceA = {
286+ events : [
287+ { timestamp : '2024-01-15T10:00:00.000Z' , message : [ 2 , 'ma1' , 'BootNotification' , { } ] } ,
288+ ] ,
289+ } ;
290+ const traceB = {
291+ events : [ { timestamp : '2024-01-15T10:00:00.000Z' , message : [ 2 , 'mb1' , 'Heartbeat' , { } ] } ] ,
292+ } ;
293+ const fileA = writeTempTrace ( traceA ) ;
294+ const fileB = writeTempTrace ( traceB ) ;
295+ const result = await runCli ( 'diff' , fileA , fileB , '--format' , 'json' ) ;
296+ expect ( result . exitCode ) . toBe ( 0 ) ;
297+ const parsed = JSON . parse ( result . stdout ) ;
298+ expect ( parsed ) . toHaveProperty ( 'onlyInA' ) ;
299+ expect ( parsed ) . toHaveProperty ( 'onlyInB' ) ;
300+ } ) ;
301+ } ) ;
174302} ) ;
0 commit comments