1# @(#)stests 8.1 (Berkeley) 06/06/93 2 3#Latest version. My sort passes all tests because I wrote it. 4#We differ only on 25E and 25H. 5#(I found at least one bug in constructing test 25, and was driven 6#to rewrite field parsing to clarify it.) 7# 8#In 25E, -k2.3,2.1b, the fields are not necessarily out of order. 9#Even if they were, it would be legal (11752-3), although certainly 10#justification for warning. 11# 12#On 25H, your answer is as defensible as mine. (Our suggestion 13#*1 backs mine.) 14 15 16# Tests for the Unix sort utility 17# Test Posix features except for locale. 18# Test some nonstandard features if present. 19 20# Other tests should be made for files too big to fit in memory. 21 22 23# Initialize switches for nonstandard features. 24# Use parenthesized settings for supported features. 25 26o=: # officially obsolescent features: +1 -2, misplaced -o (o=) 27g=: # -g numeric sort including e-format numbers (g=) 28M=: # -M sort by month names (M=) 29s=: # -s stable, do not compare raw bytes on equal keys (s=) 30y= # -y user-specified memory size (y=-y10000) 31 32# Detect what features are supported, assuming bad options cause 33# errors. Set switches accordingly. 34 35echo obsolescent and nonstandard features recognized, if any: 36if sort +0 </dev/null 2>/dev/null; then o= 37 echo ' +1 -2'; fi 38if sort /dev/null -o xx 2>/dev/null; then o= 39 echo ' displaced -o'; fi 40if sort -g </dev/null 2>/dev/null; then g= 41 echo ' -g g-format numbers'; fi 42if sort -M </dev/null 2>/dev/null; then M= 43 echo ' -M months'; fi 44if sort -s </dev/null 2>/dev/null; then s= 45 echo ' -s stable'; fi 46if sort -y10000 </dev/null 2>/dev/null; then y=-y10000 47 echo ' -y space'; fi 48if sort -z10000 </dev/null 2>/dev/null; then 49 echo ' -z size (not exercised)'; fi 50if sort -T. </dev/null 2>/dev/null; then 51 echo ' -T tempdir (not exercised)'; fi 52 53 54export TEST # major sequence number of test 55 56trap "rm -f in in1 out xx -k xsort linecount fields; exit" 0 1 2 13 15 57 58# xsort testno options 59# Sort file "in" with specified options. 60# Compare with file "out" if that is supplied, 61# otherwise make plausibility checks on output 62 63# "sum" must be dumb; insensitive to the 64# order of lines within a file. 65# System V sum is suitable; sum -5 is the v10 equivalent. 66 67PATH=.:$PATH 68export PATH 69cat <<'!' >xsort; chmod +x xsort 70 71 X=$1; shift 72 73 if sort "$@" in >xx && sort -c "$@" xx 74 then 75 if test -f out 76 then 77 cmp xx out >/dev/null && exit 0 78 echo $TEST$X comparison failed 79 else 80 test "`cksum -o2 <in`" = "`cksum -o2 <xx`" && exit 0 81 echo $TEST$X checksum failed 82 fi 83 else 84 echo $TEST$X failed 85 fi 86 exit 1 87! 88 89# linecount testno file count 90# declares the given "testno" to be in error if number of 91# lines in "file" differs from "count" 92 93cat <<'!' >linecount; chmod +x linecount 94awk 'END{ if(NR!='$3') print "'$TEST$1' failed" }' $2 95! 96 97rm -f out 98 99#--------------------------------------------------------------- 100TEST=01; echo $TEST # -c status, checksum 101 # obsolescent features go together 102cat <<! >in 103b 104a 105! 106rm -f out -o 107 108sort -c in 2>/dev/null && echo ${TEST}A failed 109 110xsort B || '"cksum"' is probably unsuitable - see comments 111 112$o sort +0 in -o in || echo ${TEST}c failed 113 114#--------------------------------------------------------------- 115TEST=02; echo $TEST # output from -c 116cat <<! >in 117x 118y 119! 120 121sort -cr in >out 2>xx && echo ${TEST}A failed 122test -s out && echo ${TEST}B failed 123test -s xx && echo option -c is noisy "(probably legal)" 124test -s xx || echo option -c is quiet "(legal, not classical)" 125 126#--------------------------------------------------------------- 127TEST=03; echo $TEST # -n 128cat <<! >in 129-99.0 130-99.1 131-.0002 132-10 1332 1340010.000000000000000000000000000000000001 13510 1363x 137x 138! 139cat <<! >out 140-99.1 141-99.0 142-10 143-.0002 144x 1452 1463x 14710 1480010.000000000000000000000000000000000001 149! 150 151xsort "" -n 152 153#--------------------------------------------------------------- 154TEST=04; echo $TEST # -b without fields, piping, -c status return 155cat <<! >in 156 b 157 a 158! 159cp in out 160 161xsort A -b 162 163cat in | sort | cat >xx 164cmp xx out >/dev/null || echo ${TEST}B failed 165 166sort in | sort -cr 2>/dev/null && echo ${TEST}C failed 167 168#--------------------------------------------------------------- 169TEST=05; echo $TEST # fields, reverse fields, -c status return 170cat <<! >in 171b b p 172a b q 173x a 174! 175cat <<! >out 176x a 177a b q 178b b p 179! 180 181$o xsort A +1 -2 182 183$o xsort B +1 -2 +2r 184 185xsort C -k 2,2 186 187xsort D -k 2,2 -k 3r 188 189xsort E -k 2,2.0 190 191xsort F -k 2,2 -k 1,1 -k 3 192 193sort -c -k 2 in 2>/dev/null && ${TEST}G failed 194 195#--------------------------------------------------------------- 196TEST=06; echo $TEST # -t 197cat <<! >in 198a: 199a! 200! 201cp in out 202 203$o xsort A -t : -r +0 204 205$o xsort B -t : +0 -1 206 207xsort C -t : -r -k 1 208 209xsort D -t : -k 1,1 210 211#--------------------------------------------------------------- 212TEST=07; echo $TEST # -t, character positions in fields 213 # -t: as 1 arg is not strictly conforming, but classical 214cat <<! >in 215: ab 216:bac 217! 218cat <<! >out 219:bac 220: ab 221! 222 223$o xsort A -b -t: +1.1 224 225$o xsort B -t: +1.1r 226 227xsort C -b -t: -k 2.2 228 229xsort D -t: -k 2.2r 230 231#--------------------------------------------------------------- 232TEST=08; echo $TEST # space and tab as -t characters 233cat <<! >in 234 b c 235 b c 236 b c 237! 238cp in out 239 240xsort A -t ' ' -k2,2 241 242xsort B -t ' ' -k2.1,2.0 243 244cat <<! >out 245 b c 246 b c 247 b c 248! 249 250xsort C -t ' ' -k2,2 251 252xsort D -t ' ' -k2.1,2.0 253 254cat <<! >out 255 b c 256 b c 257 b c 258! 259 260xsort E -k2 261 262cat <<! >out 263 b c 264 b c 265 b c 266! 267 268xsort F -k2b 269 270#--------------------------------------------------------------- 271TEST=09; echo $TEST # alphabetic as -t character 272cat <<! >in 273zXa 274yXa 275zXb 276! 277cp in out 278 279xsort "" -tX -k2 -k1r,1 280 281#--------------------------------------------------------------- 282TEST=10; echo $TEST # -m 283cat <<! >in 284a 285ab 286ab 287bc 288ca 289! 290cat <<! >in1 291Z 292a 293aa 294ac 295c 296! 297cat <<! >out 298Z 299a 300a 301aa 302ab 303ab 304ac 305bc 306c 307ca 308! 309 310sort -m in in1 >xx 311cmp xx out >/dev/null || echo $TEST failed 312 313#--------------------------------------------------------------- 314TEST=11; echo $TEST # multiple files, -o overwites input, -m, -mu 315cat <<! >in 316a 317b 318c 319d 320! 321 322sort -o xx in in in in in in in in in in in in in in in in in 323linecount A xx 68 324sort -o in -mu in in in in in in in in in in in in in in in in in 325linecount B in 4 326sort -o in -m in in in in in in in in in in in in in in in in in 327 328cmp in xx >/dev/null || echo ${TEST}C failed 329 330#--------------------------------------------------------------- 331TEST=12; echo $TEST # does -mu pick the first among equals? 332cat <<! >in 3333B 3343b 3353B2 336~3B2 3374.1 33841 3395 3405. 341! 342cat <<! >out 3433B 3443B2 3454.1 3465 347! 348 349xsort A -mudf || echo "(other behavior is legal, not classical)" 350 351xsort B -mudf -k1 || echo "(other behavior is legal, not classical)" 352 353#--------------------------------------------------------------- 354TEST=13; echo $TEST # long records (>8000 bytes, keys >16000), -r 355awk ' 356BEGIN { x="x" 357 for(i=1; i<=12; i++) x = x x 358 for(i=15; i<=25; i++) print x i 359}' >in 360awk ' 361BEGIN { x="x" 362 for(i=1; i<=12; i++) x = x x 363 for(i=25; i>=15; i--) print x i 364}' >out 365 366xsort A -r 367 368xsort B -k 1,1r -k 1 369 370#--------------------------------------------------------------- 371TEST=14; echo $TEST "(3 long parts)" 372awk 'BEGIN { for(i=0; i<100000; i++) print rand() }' | grep -v e >in 373rm -f out 374 375xsort A; echo $TEST "(part A done)" 376 377xsort B -n; echo $TEST "(part B done)" 378 379# next test is unclean: xx is a hidden side-effect of xsort 380 381awk ' 382 $0 < x { print "test '${TEST}C' failed"; exit } 383 $0 "" != x { print >"out"; x = $0 } 384' xx 385 386xsort C -n -u 387 388#--------------------------------------------------------------- 389TEST=15; echo $TEST "(long)" # force intermediate files if possible 390awk 'BEGIN { for(i=0; i<20000; i++) print rand() }' >in 391rm -f out 392 393xsort A -r $y 394 395sort -r in | awk '$0 "x" != x { print ; x = $0 "x" }' >out 396 397xsort B -u -r $y 398 399#--------------------------------------------------------------- 400TEST=16; echo $TEST # -nr, -nm, file name - 401awk 'BEGIN { for(i=-100; i<=100; i+=2) printf "%.10d\n", i }' >in 402 403awk 'BEGIN { for(i=-99; i<=100; i+=2) print i }' | sort -nr in - >xx 404awk '$0+0 != 101-NR { print "'${TEST}A' failed"; exit }' xx 405 406awk 'BEGIN { for(i=-99; i<=100; i+=2) print i }' | sort -mn in - >xx 407awk '$0+0 != -101+NR { print "'${TEST}B' failed"; exit }' xx 408 409#--------------------------------------------------------------- 410TEST=17; echo $TEST # -d, fields without end, modifier override 411cat <<! >in 412a-B 413a+b 414a b 415A+b 416a b 417! 418cat <<! >out 419a b 420a b 421A+b 422a-B 423a+b 424! 425 426$o xsort A -df +0 +0d 427 428xsort B -df -k 1 -k 1d 429 430#--------------------------------------------------------------- 431TEST=18; echo $TEST # -u on key only 432cat <<! >in 43312 y 43413 z 43512 x 436! 437cat <<! >out 43812 x 43912 y 44013 z 441! 442 443$o xsort A +0 -1 444 445xsort B -k 1,1 446 447sort -u -k 1,1 in >xx 448linecount C xx 2 449 450#--------------------------------------------------------------- 451TEST=19; echo $TEST # -i, -d, -f 452cat <<! >xx.c 453run(i,j){ for( ; i<=j; i++) printf("%.3o %c\n",i,i); } 454main(){ run(0, 011); /* 012=='\n' */ 455 run(013, 0377); } 456! 457cc xx.c 458a.out >in 459cat <<! >xx.c 460run(i,j){ for( ; i<=j; i++) printf("%.3o %c\n",i,i); } 461main(){ run(0, 011); 462 run(013, ' '-1); 463 run(0177, 0377); 464 run(' ', 0176); } 465! 466cc xx.c 467a.out >out 468 469xsort A -i -k 2 470 471cat <<! >xx.c 472run(i,j){ for( ; i<=j; i++) printf("%.3o %c\n",i,i); } 473main(){ run(0, 010); /* 011=='\t', 012=='\n' */ 474 run(013, ' '-1); 475 run(' '+1, '0'-1); 476 run('9'+1, 'A'-1); 477 run('Z'+1, 'a'-1); 478 run('z'+1, 0377); 479 run('\t', '\t'); 480 run(' ', ' '); 481 run('0', '9'); 482 run('A', 'Z'); 483 run('a', 'z'); } 484! 485cc xx.c 486a.out >out 487 488xsort B -d -k 2 489 490cat <<! >xx.c 491run(i,j){ for( ; i<=j; i++) printf("%.3o %c\n",i,i); } 492main(){ int i; 493 run(0, 011); 494 run(013, 'A'-1); 495 for(i='A'; i<='Z'; i++) 496 printf("%.3o %c\n%.3o %c\n",i,i,i+040,i+040); 497 run('Z'+1, 'a'-1); 498 run('z'+1, 0377); } 499! 500cc xx.c 501a.out >out 502rm xx.c 503 504xsort C -f -k 2 505 506#--------------------------------------------------------------- 507TEST=20; echo $TEST # -d, -f, -b applies only to fields 508cat <<! >in 509 b 510'C 511a 512! 513cp in out 514 515xsort A -d 516 517xsort B -f 518 519cat <<! >out 520 b 521a 522'C 523! 524 525xsort C -dfb 526 527#--------------------------------------------------------------- 528TEST=21; echo $TEST # behavior of null bytes 529cat <<'!' >xx.c 530main() { printf("%cb\n%ca\n",0,0); } 531! 532cc xx.c 533a.out >in 534sort in >xx 535cmp in xx >/dev/null && echo ${TEST}A failed 536test "`wc -c <in`" = "`wc -c <xx`" || echo ${TEST}B failed 537rm xx.c a.out 538 539#--------------------------------------------------------------- 540TEST=22; echo $TEST # field limits 541cat <<! >in 542a 2 543a 1 544b 2 545b 1 546! 547cat <<! >out 548b 1 549b 2 550a 1 551a 2 552! 553 554xsort "" -r -k1,1 -k2n 555 556#--------------------------------------------------------------- 557TEST=23; echo $TEST # empty file 558 559sort -o xx </dev/null 560cmp xx /dev/null 2>/dev/null || echo ${TEST}A failed 561 562sort -c </dev/null || echo ${TEST}B failed 563 564sort -cu </dev/null || echo ${TEST}C failed 565 566#--------------------------------------------------------------- 567TEST=24; echo $TEST # many fields 568cat <<! >in 5690:2:3:4:5:6:7:8:9 5701:1:3:4:5:6:7:8:9 5711:2:2:4:5:6:7:8:9 5721:2:3:3:5:6:7:8:9 5731:2:3:4:4:6:7:8:9 5741:2:3:4:5:5:7:8:9 5751:2:3:4:5:6:6:8:9 5761:2:3:4:5:6:7:7:9 5771:2:3:4:5:6:7:8:8 578! 579cat <<! >out 5801:2:3:4:5:6:7:8:8 5811:2:3:4:5:6:7:7:9 5821:2:3:4:5:6:6:8:9 5831:2:3:4:5:5:7:8:9 5841:2:3:4:4:6:7:8:9 5851:2:3:3:5:6:7:8:9 5861:2:2:4:5:6:7:8:9 5871:1:3:4:5:6:7:8:9 5880:2:3:4:5:6:7:8:9 589! 590 591xsort "" -t: -k9 -k8 -k7 -k6 -k5 -k4 -k3 -k2 -k1 592 593#--------------------------------------------------------------- 594TEST=25; echo $TEST # variously specified alpha fields 595 # numbers give the correct orderings 596cat <<! >in 59701:04:19:01:16:01:21:01 a 59802:03:13:15:13:19:15:02 a 59903:02:07:09:07:13:09:03 a 60004:01:01:03:01:07:03:04 a 60105:08:20:16:17:02:20:05 aa 60206:07:14:18:14:20:14:06 aa 60307:06:08:10:08:14:08:07 aa 60408:05:02:04:02:08:02:08 aa 60509:16:22:02:22:04:24:13 b 60610:15:16:20:19:22:18:14 b 60711:14:10:12:10:16:12:15 b 60812:13:04:06:04:10:06:16 b 60913:24:24:22:24:06:22:21 bb 61014:23:18:24:21:24:16:22 bb 61115:22:12:14:12:18:10:23 bb 61216:21:06:08:06:12:04:24 bb 61317:12:21:21:18:03:19:09 ab 61418:11:15:19:15:21:13:10 ab 61519:10:09:11:09:15:07:11 ab 61620:09:03:05:03:09:01:12 ab 61721:20:23:17:23:05:23:17 ba 61822:19:17:23:20:23:17:18 ba 61923:18:11:13:11:17:11:19 ba 62024:17:05:07:05:11:05:20 ba 621! 622sort -k2b -k2 in >xx && 623 sort -c -t: -k2n xx 2>/dev/null || echo ${TEST}A failed 624sort -k2,2.1b -k2 in >xx && 625 sort -c -t: -k3n xx 2>/dev/null || echo ${TEST}B failed 626sort -k2.3 -k2 in >xx && 627 sort -c -t: -k4n xx 2>/dev/null || echo ${TEST}C failed 628sort -k2b,2.3 -k2 in >xx && 629 sort -c -t: -k5n xx 2>/dev/null || echo ${TEST}D failed 630sort -k2.3,2.1b -k2 in >xx && 631 sort -c -t: -k6n xx 2>/dev/null || echo ${TEST}E failed 632sort -k2,2.1b -k2r in >xx && 633 sort -c -t: -k7n xx 2>/dev/null || echo ${TEST}F failed 634sort -b -k2,2 -k2 in >xx && 635 sort -c -t: -k8n xx 2>/dev/null || echo ${TEST}G failed 636sort -b -k2,2b -k2 in >xx && # perhaps same as G 637 sort -c -t: -k3n xx 2>/dev/null || echo ${TEST}H failed\ 638 "(standard is not clear on this)" 639 640#--------------------------------------------------------------- 641TEST=26; echo $TEST # empty fields, out of bounds fields 642cat <<! >in 6430 5 6441 4 6452 3 6463 2 6474 1 6485 0 649! 650cp in out 651 652xsort "" -k2.2,2.1 -k2.3,2.4 653 654#--------------------------------------------------------------- 655TEST=27; echo $TEST # displaced -o 656rm -f out 657 658$o sort /dev/null -o out || $o echo ${TEST}B failed 659$o test -f out || $o echo ${TEST}C failed 660 661#--------------------------------------------------------------- 662TEST=28; echo $TEST # apparently nonmonotone field specs 663cat <<! >in 664aaaa c 665x a 6660 b 667! 668cp in out 669 670$o xsort A +1 -0.3 +1.4 -1.5 671 672xsort B -k2,1.3 -k2.5,2.5 673 674#--------------------------------------------------------------- 675TEST=29; echo $TEST # determination of end of option list 676cat >-k <<! 677x 678! 679rm -f out -c 680 681sort -- -k </dev/null >xx || echo ${TEST}A argument failed 682cmp xx -k || echo ${TEST}A comparison failed 683 684sort - -c </dev/null 2>/dev/null && echo ${TEST}B failed 685 686#--------------------------------------------------------------- 687TEST=30; echo $TEST # missing newline 688awk 'BEGIN{ printf "%s", "x"}' | sort >xx 689wc -c <xx | awk '$1!=2{ print "'${TEST}' failed" }' 690 691#--------------------------------------------------------------- 692TEST=31; echo $TEST # -M, multiple fields 693cat <<! >in 694jan 10 1900 695Feb 26 1900 696feb 25 1900 697January xx 1900 698August 11 1900 699jan 15 1990 700feb 22 1990 701mar 15 1990 702apr 1 1990 703may 45 1990 704jun 14 1990 705jul 4 1990 706aug 1~ 1990 707aug 11 1990 708sep 1 1990 709oct 12 1990 710nov 24 1990 711dec 25 1990 712never 3 1990 713 Dec 25 1990 714! 715cat <<! >out 716January xx 1900 717jan 10 1900 718feb 25 1900 719Feb 26 1900 720August 11 1900 721never 3 1990 722jan 15 1990 723feb 22 1990 724mar 15 1990 725apr 1 1990 726may 45 1990 727jun 14 1990 728jul 4 1990 729aug 1~ 1990 730aug 11 1990 731sep 1 1990 732oct 12 1990 733nov 24 1990 734 Dec 25 1990 735dec 25 1990 736! 737 738$M xsort "" -k3n -k1M -k2n 739 740#--------------------------------------------------------------- 741TEST=32; echo $TEST # -M case insensitivity, -r 742cat <<! >in 743x 744june 745january 746december 747! 748cat <<! >out 749december 750june 751january 752x 753! 754 755$M xsort "" -Mr 756 757#--------------------------------------------------------------- 758TEST=33; echo $TEST # -g 759cat <<! >in 7602 7611 76210 763.2 7641e 7651E1 7661e. 767! 768cat <<! >out 769.2 7701 7711e 7721e. 7732 77410 7751E1 776! 777 778$g xsort "" -g 779 780#--------------------------------------------------------------- 781TEST=34; echo $TEST # -g wide operands 782cat <<! >in 783.99999999999999999999 784099999999999999999999e-21 785099999999999999999999e-19 786.1e1 787! 788cat <<! >out 789099999999999999999999e-21 790.99999999999999999999 791.1e1 792099999999999999999999e-19 793! 794 795$g xsort A -g 796 797cat <<! >out 798.1e1 799.99999999999999999999 800099999999999999999999e-19 801099999999999999999999e-21 802! 803 804xsort B -n 805 806#--------------------------------------------------------------- 807TEST=35; echo $TEST #-g, -u with different fp reps 808cat <<! >in 809+0 810-0 8110.10 812+.1 813-.1 814-100e-3 815x 816! 817cat <<! >out 818-.1 819-100e-3 820+0 821-0 822x 823+.1 8240.10 825! 826 827$g xsort A -g 828 829$g sort -gu in >xx && $g sort -c -gu xx || echo ${TEST}B failed 830$g linecount C xx 3 831 832#--------------------------------------------------------------- 833TEST=36; echo $TEST # -s 834cat <<! >in 835a 2 836b 1 837c 2 838a 1 839b 2 840c 1 841! 842cat <<! >out 843a 2 844a 1 845b 1 846b 2 847c 2 848c 1 849! 850 851$s xsort "" -s -k1,1 852 853#--------------------------------------------------------------- 854TEST=37; echo $TEST # -s, multiple files 855cat <<! >in 856a 2 857c 2 858! 859cat <<! >in1 860a 1 861b 1 862c 1 863! 864cat <<! >out 865c 2 866b 1 867a 2 868! 869 870$s sort -smru -k1,1 in in in1 in1 >xx 871$s cmp xx out >/dev/null || echo $TEST failed 872 873#--------------------------------------------------------------- 874TEST=38; echo $TEST # -s 875$s awk ' 876 BEGIN { 877 for(i=1; i<50; i++) 878 for(j=1; j<=i; j++) { 879 print i, 2 >"in" 880 print i, 1 >"in1" 881 } 882 }' 883 884$s sort -m -s -k1,1n in in1 >out 885 886$s awk ' 887 func stop() { print "'$TEST' failed"; exit } 888 $1!=last1 { if(count!=last1 || $2!=2) stop(); 889 count = 0} 890 $1==last1 && $2!=last2 { if(count!=last1 || $2!=1) stop(); 891 count = 0 } 892 { count++; last1 = $1; last2 = $2 } 893 ' out 894