@@ -418,4 +418,206 @@ describe("awk command", () => {
418418 expect ( result . exitCode ) . toBe ( 0 ) ;
419419 } ) ;
420420 } ) ;
421+
422+ describe ( "match() function with RSTART/RLENGTH" , ( ) => {
423+ it ( "should return position and set RSTART/RLENGTH" , async ( ) => {
424+ const env = new BashEnv ( {
425+ files : { "/data.txt" : "hello foo world\n" } ,
426+ } ) ;
427+ const result = await env . exec (
428+ "awk '{print match($0, /foo/), RSTART, RLENGTH}' /data.txt" ,
429+ ) ;
430+ expect ( result . stdout ) . toBe ( "7 7 3\n" ) ;
431+ expect ( result . exitCode ) . toBe ( 0 ) ;
432+ } ) ;
433+
434+ it ( "should return 0 when no match" , async ( ) => {
435+ const env = new BashEnv ( {
436+ files : { "/data.txt" : "hello world\n" } ,
437+ } ) ;
438+ const result = await env . exec (
439+ "awk '{print match($0, /foo/), RSTART, RLENGTH}' /data.txt" ,
440+ ) ;
441+ expect ( result . stdout ) . toBe ( "0 0 -1\n" ) ;
442+ expect ( result . exitCode ) . toBe ( 0 ) ;
443+ } ) ;
444+ } ) ;
445+
446+ describe ( "gensub() function" , ( ) => {
447+ it ( "should replace globally with g flag" , async ( ) => {
448+ const env = new BashEnv ( {
449+ files : { "/data.txt" : "hello world\n" } ,
450+ } ) ;
451+ const result = await env . exec (
452+ 'awk \'{print gensub(/o/, "0", "g")}\' /data.txt' ,
453+ ) ;
454+ expect ( result . stdout ) . toBe ( "hell0 w0rld\n" ) ;
455+ expect ( result . exitCode ) . toBe ( 0 ) ;
456+ } ) ;
457+
458+ it ( "should replace Nth occurrence" , async ( ) => {
459+ const env = new BashEnv ( {
460+ files : { "/data.txt" : "foo bar foo baz foo\n" } ,
461+ } ) ;
462+ const result = await env . exec (
463+ "awk '{print gensub(/foo/, \"XXX\", 2)}' /data.txt" ,
464+ ) ;
465+ expect ( result . stdout ) . toBe ( "foo bar XXX baz foo\n" ) ;
466+ expect ( result . exitCode ) . toBe ( 0 ) ;
467+ } ) ;
468+ } ) ;
469+
470+ describe ( "power operator" , ( ) => {
471+ it ( "should compute power with ^" , async ( ) => {
472+ const env = new BashEnv ( {
473+ files : { "/data.txt" : "test\n" } ,
474+ } ) ;
475+ const result = await env . exec ( "awk '{print 2^3}' /data.txt" ) ;
476+ expect ( result . stdout ) . toBe ( "8\n" ) ;
477+ expect ( result . exitCode ) . toBe ( 0 ) ;
478+ } ) ;
479+
480+ it ( "should compute power with **" , async ( ) => {
481+ const env = new BashEnv ( {
482+ files : { "/data.txt" : "test\n" } ,
483+ } ) ;
484+ const result = await env . exec ( "awk '{print 3**2}' /data.txt" ) ;
485+ expect ( result . stdout ) . toBe ( "9\n" ) ;
486+ expect ( result . exitCode ) . toBe ( 0 ) ;
487+ } ) ;
488+ } ) ;
489+
490+ describe ( "FILENAME and FNR variables" , ( ) => {
491+ it ( "should track FILENAME" , async ( ) => {
492+ const env = new BashEnv ( {
493+ files : { "/data.txt" : "line1\nline2\n" } ,
494+ } ) ;
495+ const result = await env . exec ( "awk '{print FILENAME, NR}' /data.txt" ) ;
496+ expect ( result . stdout ) . toBe ( "/data.txt 1\n/data.txt 2\n" ) ;
497+ expect ( result . exitCode ) . toBe ( 0 ) ;
498+ } ) ;
499+
500+ it ( "should reset FNR per file" , async ( ) => {
501+ const env = new BashEnv ( {
502+ files : {
503+ "/a.txt" : "a1\na2\n" ,
504+ "/b.txt" : "b1\nb2\n" ,
505+ } ,
506+ } ) ;
507+ const result = await env . exec (
508+ "awk '{print FILENAME, FNR, NR}' /a.txt /b.txt" ,
509+ ) ;
510+ expect ( result . stdout ) . toBe (
511+ "/a.txt 1 1\n/a.txt 2 2\n/b.txt 1 3\n/b.txt 2 4\n" ,
512+ ) ;
513+ expect ( result . exitCode ) . toBe ( 0 ) ;
514+ } ) ;
515+ } ) ;
516+
517+ describe ( "exit and next statements" , ( ) => {
518+ it ( "should exit with code" , async ( ) => {
519+ const env = new BashEnv ( {
520+ files : { "/data.txt" : "line1\nline2\nline3\n" } ,
521+ } ) ;
522+ const result = await env . exec ( "awk 'NR==2{exit 5}' /data.txt" ) ;
523+ expect ( result . exitCode ) . toBe ( 5 ) ;
524+ } ) ;
525+
526+ it ( "should skip to next line with next" , async ( ) => {
527+ const env = new BashEnv ( {
528+ files : { "/data.txt" : "a\nb\nc\n" } ,
529+ } ) ;
530+ const result = await env . exec ( "awk '/b/{next}{print}' /data.txt" ) ;
531+ expect ( result . stdout ) . toBe ( "a\nc\n" ) ;
532+ expect ( result . exitCode ) . toBe ( 0 ) ;
533+ } ) ;
534+ } ) ;
535+
536+ describe ( "do-while loops" , ( ) => {
537+ it ( "should execute do-while at least once" , async ( ) => {
538+ const env = new BashEnv ( {
539+ files : { "/data.txt" : "test\n" } ,
540+ } ) ;
541+ const result = await env . exec (
542+ "awk 'BEGIN{i=0; do{i++}while(i<3); print i}'" ,
543+ ) ;
544+ expect ( result . stdout ) . toBe ( "3\n" ) ;
545+ expect ( result . exitCode ) . toBe ( 0 ) ;
546+ } ) ;
547+ } ) ;
548+
549+ describe ( "break and continue" , ( ) => {
550+ it ( "should break out of loop" , async ( ) => {
551+ const env = new BashEnv ( {
552+ files : { "/data.txt" : "test\n" } ,
553+ } ) ;
554+ const result = await env . exec (
555+ "awk 'BEGIN{for(i=1;i<=10;i++){if(i==5)break; print i}}'" ,
556+ ) ;
557+ expect ( result . stdout ) . toBe ( "1\n2\n3\n4\n" ) ;
558+ expect ( result . exitCode ) . toBe ( 0 ) ;
559+ } ) ;
560+
561+ it ( "should continue to next iteration" , async ( ) => {
562+ const env = new BashEnv ( {
563+ files : { "/data.txt" : "test\n" } ,
564+ } ) ;
565+ const result = await env . exec (
566+ "awk 'BEGIN{for(i=1;i<=5;i++){if(i==3)continue; print i}}'" ,
567+ ) ;
568+ expect ( result . stdout ) . toBe ( "1\n2\n4\n5\n" ) ;
569+ expect ( result . exitCode ) . toBe ( 0 ) ;
570+ } ) ;
571+ } ) ;
572+
573+ describe ( "printf formats" , ( ) => {
574+ it ( "should format hex with %x" , async ( ) => {
575+ const env = new BashEnv ( {
576+ files : { "/data.txt" : "test\n" } ,
577+ } ) ;
578+ const result = await env . exec ( "awk 'BEGIN{printf \"%x\\n\", 255}'" ) ;
579+ expect ( result . stdout ) . toBe ( "ff\n" ) ;
580+ expect ( result . exitCode ) . toBe ( 0 ) ;
581+ } ) ;
582+
583+ it ( "should format octal with %o" , async ( ) => {
584+ const env = new BashEnv ( {
585+ files : { "/data.txt" : "test\n" } ,
586+ } ) ;
587+ const result = await env . exec ( "awk 'BEGIN{printf \"%o\\n\", 8}'" ) ;
588+ expect ( result . stdout ) . toBe ( "10\n" ) ;
589+ expect ( result . exitCode ) . toBe ( 0 ) ;
590+ } ) ;
591+
592+ it ( "should format char with %c" , async ( ) => {
593+ const env = new BashEnv ( {
594+ files : { "/data.txt" : "test\n" } ,
595+ } ) ;
596+ const result = await env . exec ( "awk 'BEGIN{printf \"%c\\n\", 65}'" ) ;
597+ expect ( result . stdout ) . toBe ( "A\n" ) ;
598+ expect ( result . exitCode ) . toBe ( 0 ) ;
599+ } ) ;
600+
601+ it ( "should format scientific with %e" , async ( ) => {
602+ const env = new BashEnv ( {
603+ files : { "/data.txt" : "test\n" } ,
604+ } ) ;
605+ const result = await env . exec ( "awk 'BEGIN{printf \"%.2e\\n\", 1234}'" ) ;
606+ expect ( result . stdout ) . toBe ( "1.23e+3\n" ) ;
607+ expect ( result . exitCode ) . toBe ( 0 ) ;
608+ } ) ;
609+ } ) ;
610+
611+ describe ( "regex field separator" , ( ) => {
612+ it ( "should split on regex pattern" , async ( ) => {
613+ const env = new BashEnv ( {
614+ files : { "/data.txt" : "a1b2c\n" } ,
615+ } ) ;
616+ const result = await env . exec (
617+ "awk -F'[0-9]+' '{print $1, $2, $3}' /data.txt" ,
618+ ) ;
619+ expect ( result . stdout ) . toBe ( "a b c\n" ) ;
620+ expect ( result . exitCode ) . toBe ( 0 ) ;
621+ } ) ;
622+ } ) ;
421623} ) ;
0 commit comments