Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ 2 lib, 3 stdenv, 4 buildEnv, 5 runCommand, 6 fetchurl, 7 file, 8 texlive, 9 writeShellScript, 10 writeText, 11 texliveInfraOnly, 12 texliveConTeXt, 13 texliveSmall, 14 texliveMedium, 15 texliveFull, 16}: 17 18rec { 19 20 mkTeXTest = lib.makeOverridable ( 21 { 22 name, 23 format, 24 text, 25 texLive ? texliveSmall, 26 options ? "-interaction=errorstopmode", 27 preTest ? "", 28 postTest ? "", 29 ... 30 }@attrs: 31 runCommand "texlive-test-tex-${name}" 32 ( 33 { 34 nativeBuildInputs = [ texLive ] ++ attrs.nativeBuildInputs or [ ]; 35 text = builtins.toFile "${name}.tex" text; 36 } 37 // builtins.removeAttrs attrs [ 38 "nativeBuildInputs" 39 "text" 40 "texLive" 41 ] 42 ) 43 '' 44 export HOME="$(mktemp -d)" 45 mkdir "$out" 46 cd "$out" 47 cp "$text" "$name.tex" 48 ${preTest} 49 $format $options "$name.tex" 50 ${postTest} 51 '' 52 ); 53 54 tlpdbNix = 55 runCommand "texlive-test-tlpdb-nix" 56 { 57 nixpkgsTlpdbNix = ../../tools/typesetting/tex/texlive/tlpdb.nix; 58 tlpdbNix = texlive.tlpdb.nix; 59 } 60 '' 61 mkdir -p "$out" 62 diff -u "''${nixpkgsTlpdbNix}" "''${tlpdbNix}" | tee "$out/tlpdb.nix.patch" 63 ''; 64 65 # test two completely different font discovery mechanisms, both of which were once broken: 66 # - lualatex uses its own luaotfload script (#220228) 67 # - xelatex uses fontconfig (#228196) 68 opentype-fonts = lib.recurseIntoAttrs rec { 69 lualatex = mkTeXTest { 70 name = "opentype-fonts-lualatex"; 71 format = "lualatex"; 72 texLive = texliveSmall.withPackages (ps: [ ps.libertinus-fonts ]); 73 text = '' 74 \documentclass{article} 75 \usepackage{fontspec} 76 \setmainfont{Libertinus Serif} 77 \begin{document} 78 \LaTeX{} is great 79 \end{document} 80 ''; 81 }; 82 xelatex = lualatex.override { 83 name = "opentype-fonts-xelatex"; 84 format = "xelatex"; 85 }; 86 }; 87 88 chktex = 89 runCommand "texlive-test-chktex" 90 { 91 nativeBuildInputs = [ 92 (texlive.withPackages (ps: [ ps.chktex ])) 93 ]; 94 input = builtins.toFile "chktex-sample.tex" '' 95 \documentclass{article} 96 \begin{document} 97 \LaTeX is great 98 \end{document} 99 ''; 100 } 101 '' 102 # chktex is supposed to return 2 when it (successfully) finds warnings, but no errors, 103 # see http://git.savannah.nongnu.org/cgit/chktex.git/commit/?id=ec0fb9b58f02a62ff0bfec98b997208e9d7a5998 104 (set +e; chktex -v -nall -w1 "$input" 2>&1; [ $? = 2 ] || exit 1; set -e) | tee "$out" 105 # also check that the output does indeed contain "One warning printed" 106 grep "One warning printed" "$out" 107 ''; 108 109 context = mkTeXTest { 110 name = "texlive-test-context"; 111 format = "context"; 112 texLive = texliveConTeXt; 113 # check that the PDF has been created: we have hit cases of context 114 # failing with exit status 0 due to a misconfigured texlive 115 postTest = '' 116 if [[ ! -f "$name".pdf ]] ; then 117 echo "ConTeXt test failed: file '$name.pdf' not found" 118 exit 1 119 fi 120 ''; 121 text = '' 122 \starttext 123 \startsection[title={ConTeXt test document}] 124 This is an {\em incredibly} simple ConTeXt document. 125 \stopsection 126 \stoptext 127 ''; 128 }; 129 130 dvipng = lib.recurseIntoAttrs { 131 # https://github.com/NixOS/nixpkgs/issues/75605 132 basic = 133 runCommand "texlive-test-dvipng-basic" 134 { 135 nativeBuildInputs = [ 136 file 137 texliveMedium 138 ]; 139 input = fetchurl { 140 name = "test_dvipng.tex"; 141 url = "http://git.savannah.nongnu.org/cgit/dvipng.git/plain/test_dvipng.tex?id=b872753590a18605260078f56cbd6f28d39dc035"; 142 sha256 = "1pjpf1jvwj2pv5crzdgcrzvbmn7kfmgxa39pcvskl4pa0c9hl88n"; 143 }; 144 } 145 '' 146 cp "$input" ./document.tex 147 148 latex document.tex 149 dvipng -T tight -strict -picky document.dvi 150 for f in document*.png; do 151 file "$f" | tee output 152 grep PNG output 153 done 154 155 mkdir "$out" 156 mv document*.png "$out"/ 157 ''; 158 159 # test dvipng's limited capability to render postscript specials via GS 160 ghostscript = 161 runCommand "texlive-test-ghostscript" 162 { 163 nativeBuildInputs = [ 164 file 165 (texliveSmall.withPackages (ps: [ ps.dvipng ])) 166 ]; 167 input = builtins.toFile "postscript-sample.tex" '' 168 \documentclass{minimal} 169 \begin{document} 170 Ni 171 \special{ps: 172 newpath 173 0 0 moveto 174 7 7 rlineto 175 0 7 moveto 176 7 -7 rlineto 177 stroke 178 showpage 179 } 180 \end{document} 181 ''; 182 gs_trap = writeShellScript "gs_trap.sh" '' 183 exit 1 184 ''; 185 } 186 '' 187 cp "$gs_trap" ./gs 188 export PATH=$PWD:$PATH 189 # check that the trap works 190 gs && exit 1 191 192 cp "$input" ./document.tex 193 194 latex document.tex 195 dvipng -T 1in,1in -strict -picky document.dvi 196 for f in document*.png; do 197 file "$f" | tee output 198 grep PNG output 199 done 200 201 mkdir "$out" 202 mv document*.png "$out"/ 203 ''; 204 }; 205 206 # https://github.com/NixOS/nixpkgs/issues/75070 207 dvisvgm = 208 runCommand "texlive-test-dvisvgm" 209 { 210 nativeBuildInputs = [ 211 file 212 texliveMedium 213 ]; 214 input = builtins.toFile "dvisvgm-sample.tex" '' 215 \documentclass{article} 216 \begin{document} 217 mwe 218 \end{document} 219 ''; 220 } 221 '' 222 cp "$input" ./document.tex 223 224 latex document.tex 225 dvisvgm document.dvi -n -o document_dvi.svg 226 cat document_dvi.svg 227 file document_dvi.svg | grep SVG 228 229 pdflatex document.tex 230 dvisvgm -P document.pdf -n -o document_pdf.svg 231 cat document_pdf.svg 232 file document_pdf.svg | grep SVG 233 234 mkdir "$out" 235 mv document*.svg "$out"/ 236 ''; 237 238 texdoc = 239 runCommand "texlive-test-texdoc" 240 { 241 nativeBuildInputs = [ 242 (texlive.withPackages (ps: [ 243 ps.luatex 244 ps.texdoc 245 ps.texdoc.texdoc 246 ])) 247 ]; 248 } 249 '' 250 texdoc --version 251 252 texdoc --debug --list texdoc | tee "$out" 253 grep texdoc.pdf "$out" 254 ''; 255 256 # check that the default language is US English 257 defaultLanguage = lib.recurseIntoAttrs rec { 258 # language.def 259 etex = mkTeXTest { 260 name = "default-language-etex"; 261 format = "etex"; 262 text = '' 263 \catcode`\@=11 264 \ifnum\language=\lang@USenglish \message{[tests.texlive] Default language is US English.} 265 \else\errmessage{[tests.texlive] Error: default language is NOT US English.}\fi 266 \ifnum\language=0\message{[tests.texlive] Default language has id 0.} 267 \else\errmessage{[tests.texlive] Error: default language does NOT have id 0.}\fi 268 \bye 269 ''; 270 }; 271 # language.dat 272 latex = mkTeXTest { 273 name = "default-language-latex"; 274 format = "latex"; 275 text = '' 276 \makeatletter 277 \ifnum\language=\l@USenglish \GenericWarning{}{[tests.texlive] Default language is US English} 278 \else\GenericError{}{[tests.texlive] Error: default language is NOT US English}{}{}\fi 279 \ifnum\language=0\GenericWarning{}{[tests.texlive] Default language has id 0} 280 \else\GenericError{}{[tests.texlive] Error: default language does NOT have id 0}{}{}\fi 281 \stop 282 ''; 283 }; 284 # language.dat.lua 285 luatex = etex.override { 286 name = "default-language-luatex"; 287 format = "luatex"; 288 }; 289 }; 290 291 # check that all languages are available, including synonyms 292 allLanguages = 293 let 294 hyphenBase = texlive.pkgs.hyphen-base; 295 texLive = texliveFull; 296 in 297 lib.recurseIntoAttrs { 298 # language.def 299 etex = mkTeXTest { 300 name = "all-languages-etex"; 301 format = "etex"; 302 inherit hyphenBase texLive; 303 text = '' 304 \catcode`\@=11 305 \input kvsetkeys.sty 306 \def\CheckLang#1{ 307 \ifcsname lang@#1\endcsname\message{[tests.texlive] Found language #1} 308 \else\errmessage{[tests.texlive] Error: missing language #1}\fi 309 } 310 \comma@parse{@texLanguages@}\CheckLang 311 \bye 312 ''; 313 preTest = '' 314 texLanguages="$(sed -n -E 's/^\\addlanguage\s*\{([^}]+)\}.*$/\1/p' < "$hyphenBase"/tex/generic/config/language.def)" 315 texLanguages="''${texLanguages//$'\n'/,}" 316 substituteInPlace "$name.tex" --subst-var texLanguages 317 ''; 318 }; 319 # language.dat 320 latex = mkTeXTest { 321 name = "all-languages-latex"; 322 format = "latex"; 323 inherit hyphenBase texLive; 324 text = '' 325 \makeatletter 326 \@for\Lang:=italian,@texLanguages@\do{ 327 \ifcsname l@\Lang\endcsname 328 \GenericWarning{}{[tests.texlive] Found language \Lang} 329 \else 330 \GenericError{}{[tests.texlive] Error: missing language \Lang}{}{} 331 \fi 332 } 333 \stop 334 ''; 335 preTest = '' 336 texLanguages="$(sed -n -E 's/^([^%= \t]+).*$/\1/p' < "$hyphenBase"/tex/generic/config/language.dat)" 337 texLanguages="''${texLanguages//$'\n'/,}" 338 substituteInPlace "$name.tex" --subst-var texLanguages 339 ''; 340 }; 341 # language.dat.lua 342 luatex = mkTeXTest { 343 name = "all-languages-luatex"; 344 format = "luatex"; 345 inherit hyphenBase texLive; 346 text = '' 347 \directlua{ 348 require('luatex-hyphen.lua') 349 langs = '@texLanguages@,' 350 texio.write('\string\n') 351 for l in langs:gmatch('([^,]+),') do 352 if luatexhyphen.lookupname(l) \string~= nil then 353 texio.write('[tests.texlive] Found language '..l..'.\string\n') 354 else 355 error('[tests.texlive] Error: missing language '..l..'.', 2) 356 end 357 end 358 } 359 \bye 360 ''; 361 preTest = '' 362 texLanguages="$(sed -n -E 's/^.*\[("|'\''')(.*)("|'\''')].*$/\2/p' < "$hyphenBase"/tex/generic/config/language.dat.lua)" 363 texLanguages="''${texLanguages//$'\n'/,}" 364 substituteInPlace "$name.tex" --subst-var texLanguages 365 ''; 366 }; 367 }; 368 369 # test that language files are generated as expected 370 hyphen-base = 371 runCommand "texlive-test-hyphen-base" 372 { 373 hyphenBase = texlive.pkgs.hyphen-base; 374 schemeFull = texliveFull; 375 schemeInfraOnly = texliveInfraOnly; 376 } 377 '' 378 mkdir -p "$out"/{scheme-infraonly,scheme-full} 379 380 # create language files with no hyphenation patterns 381 cat "$hyphenBase"/tex/generic/config/language.us >language.dat 382 cat "$hyphenBase"/tex/generic/config/language.us.def >language.def 383 cat "$hyphenBase"/tex/generic/config/language.us.lua >language.dat.lua 384 385 cat >>language.dat.lua <<EOF 386 } 387 EOF 388 389 cat >>language.def <<EOF 390 %%% No changes may be made beyond this point. 391 392 \uselanguage {USenglish} %%% This MUST be the last line of the file. 393 EOF 394 395 for fname in language.{dat,def,dat.lua} ; do 396 diff --ignore-matching-lines='^\(%\|--\) Generated by ' -u \ 397 {"$hyphenBase","$schemeFull"/share/texmf-var}/tex/generic/config/"$fname" \ 398 | tee "$out/scheme-full/$fname.patch" 399 diff --ignore-matching-lines='^\(%\|--\) Generated by ' -u \ 400 {,"$schemeInfraOnly"/share/texmf-var/tex/generic/config/}"$fname" \ 401 | tee "$out/scheme-infraonly/$fname.patch" 402 done 403 ''; 404 405 # verify that the restricted mode gets enabled when 406 # needed (detected by checking if it disallows --gscmd) 407 repstopdf = 408 runCommand "texlive-test-repstopdf" 409 { 410 nativeBuildInputs = [ (texlive.withPackages (ps: [ ps.epstopdf ])) ]; 411 } 412 '' 413 ! (epstopdf --gscmd echo /dev/null 2>&1 || true) | grep forbidden >/dev/null 414 (repstopdf --gscmd echo /dev/null 2>&1 || true) | grep forbidden >/dev/null 415 mkdir "$out" 416 ''; 417 418 # verify that the restricted mode gets enabled when 419 # needed (detected by checking if it disallows --gscmd) 420 rpdfcrop = 421 runCommand "texlive-test-rpdfcrop" 422 { 423 nativeBuildInputs = [ (texlive.withPackages (ps: [ ps.pdfcrop ])) ]; 424 } 425 '' 426 ! (pdfcrop --gscmd echo $(command -v pdfcrop) 2>&1 || true) | grep 'restricted mode' >/dev/null 427 (rpdfcrop --gscmd echo $(command -v pdfcrop) 2>&1 || true) | grep 'restricted mode' >/dev/null 428 mkdir "$out" 429 ''; 430 431 # check that all binaries run successfully, in the following sense: 432 # (1) run --version, -v, --help, -h successfully; or 433 # (2) run --help, -h, or no argument with error code but show help text; or 434 # (3) run successfully on a test.tex or similar file 435 # we ignore the binaries that cannot be tested as above, and are either 436 # compiled binaries or trivial shell wrappers 437 binaries = 438 let 439 # TODO known broken binaries 440 broken = [ 441 # do not know how to test without a valid build.lua 442 "ppmcheckpdf" 443 444 # 'Error initialising QuantumRenderer: no suitable pipeline found' 445 "tlcockpit" 446 ] 447 ++ lib.optional stdenv.hostPlatform.isDarwin "epspdftk"; # wish shebang is a script, not a binary! 448 449 # (1) binaries requiring -v 450 shortVersion = [ 451 "devnag" 452 "diadia" 453 "pmxchords" 454 "ptex2pdf" 455 "simpdftex" 456 "ttf2afm" 457 ]; 458 # (1) binaries requiring --help or -h 459 help = [ 460 "arlatex" 461 "bundledoc" 462 "cachepic" 463 "checklistings" 464 "dvipos" 465 "extractres" 466 "fig4latex" 467 "fragmaster" 468 "kpsewhere" 469 "latex-git-log" 470 "ltxfileinfo" 471 "mendex" 472 "pdflatexpicscale" 473 "perltex" 474 "pn2pdf" 475 "psbook" 476 "psnup" 477 "psresize" 478 "purifyeps" 479 "simpdftex" 480 "tex2xindy" 481 "texluac" 482 "texluajitc" 483 "upmendex" 484 "urlbst" 485 "yplan" 486 ]; 487 shortHelp = [ 488 "adhocfilelist" 489 "authorindex" 490 "bbl2bib" 491 "bibdoiadd" 492 "bibmradd" 493 "biburl2doi" 494 "bibzbladd" 495 "bookshelf-listallfonts" 496 "bookshelf-mkfontsel" 497 "ctanupload" 498 "disdvi" 499 "dvibook" 500 "dviconcat" 501 "getmapdl" 502 "latex2man" 503 "listings-ext.sh" 504 "pygmentex" 505 ]; 506 # (2) binaries that return non-zero exit code even if correctly asked for help 507 ignoreExitCode = [ 508 "authorindex" 509 "bookshelf-listallfonts" 510 "bookshelf-mkfontsel" 511 "dvibook" 512 "dviconcat" 513 "dvipos" 514 "extractres" 515 "fig4latex" 516 "fragmaster" 517 "latex2man" 518 "latex-git-log" 519 "listings-ext.sh" 520 "psbook" 521 "psnup" 522 "psresize" 523 "purifyeps" 524 "tex2xindy" 525 "texluac" 526 "texluajitc" 527 ]; 528 # (2) binaries that print help on no argument, returning non-zero exit code 529 noArg = [ 530 "a2ping" 531 "bg5+latex" 532 "bg5+pdflatex" 533 "bg5latex" 534 "bg5pdflatex" 535 "cef5latex" 536 "cef5pdflatex" 537 "ceflatex" 538 "cefpdflatex" 539 "cefslatex" 540 "cefspdflatex" 541 "chkdvifont" 542 "dvi2fax" 543 "dvired" 544 "dviselect" 545 "dvitodvi" 546 "epsffit" 547 "findhyph" 548 "gbklatex" 549 "gbkpdflatex" 550 "komkindex" 551 "kpsepath" 552 "listbib" 553 "listings-ext" 554 "mag" 555 "mathspic" 556 "mf2pt1" 557 "mk4ht" 558 "mkt1font" 559 "mkgrkindex" 560 "musixflx" 561 "pdf2ps" 562 "pdfclose" 563 "pdftosrc" 564 "pdfxup" 565 "pedigree" 566 "pfb2pfa" 567 "pk2bm" 568 "prepmx" 569 "ps2pk" 570 "psselect" 571 "pstops" 572 "rubibtex" 573 "rubikrotation" 574 "sjislatex" 575 "sjispdflatex" 576 "srcredact" 577 "t4ht" 578 "teckit_compile" 579 "tex4ht" 580 "texdiff" 581 "texdirflatten" 582 "texplate" 583 "tie" 584 "ttf2kotexfont" 585 "ttfdump" 586 "vlna" 587 "vpl2ovp" 588 "vpl2vpl" 589 "yplan" 590 ]; 591 # (3) binaries requiring a .tex file 592 contextTest = [ "htcontext" ]; 593 latexTest = [ 594 "de-macro" 595 "e2pall" 596 "htlatex" 597 "htxelatex" 598 "makeindex" 599 "pslatex" 600 "rumakeindex" 601 "tpic2pdftex" 602 "wordcount" 603 "xhlatex" 604 ]; 605 texTest = [ 606 "fontinst" 607 "htmex" 608 "httex" 609 "httexi" 610 "htxetex" 611 ]; 612 # tricky binaries or scripts that are obviously working but are hard to test 613 # (e.g. because they expect user input no matter the arguments) 614 # (printafm comes from ghostscript, not texlive) 615 ignored = [ 616 # compiled binaries 617 "dt2dv" 618 "dv2dt" 619 "dvi2tty" 620 "dvidvi" 621 "dvispc" 622 "otp2ocp" 623 "outocp" 624 "pmxab" 625 626 # GUI scripts that accept no argument or crash without a graphics server; please test manually 627 "epspdftk" 628 "texdoctk" 629 "tlshell" 630 "xasy" 631 632 # requires Cinderella, not open source and not distributed via Nixpkgs 633 "ketcindy" 634 ]; 635 # binaries that need a combined scheme and cannot work standalone 636 needScheme = [ 637 # pfarrei: require working kpse to find lua module 638 "a5toa4" 639 640 # show-pdf-tags: require working kpse to find lualatex and lua modules 641 "show-pdf-tags" 642 643 # bibexport: requires kpsewhich 644 "bibexport" 645 646 # crossrefware: require bibtexperllibs under TEXMFROOT 647 "bbl2bib" 648 "bibdoiadd" 649 "bibmradd" 650 "biburl2doi" 651 "bibzbladd" 652 "checkcites" 653 "ltx2crossrefxml" 654 655 # epstopdf: requires kpsewhich 656 "epstopdf" 657 "repstopdf" 658 659 # requires kpsewhich 660 "memoize-extract.pl" 661 "memoize-extract.py" 662 663 # require other texlive binaries in PATH 664 "allcm" 665 "allec" 666 "chkweb" 667 "explcheck" 668 "extractbb" 669 "fontinst" 670 "ht*" 671 "installfont-tl" 672 "kanji-config-updmap-sys" 673 "kanji-config-updmap-user" 674 "kpse*" 675 "latexfileversion" 676 "mkocp" 677 "mkofm" 678 "mtxrunjit" 679 "pdftex-quiet" 680 "pslatex" 681 "rumakeindex" 682 "texconfig" 683 "texconfig-sys" 684 "texexec" 685 "texlinks" 686 "texmfstart" 687 "typeoutfileinfo" 688 "wordcount" 689 "xdvi" 690 "xhlatex" 691 692 # misc luatex binaries searching for luatex in PATH 693 "citeproc-lua" 694 "context" 695 "contextjit" 696 "ctanbib" 697 "digestif" 698 "epspdf" 699 "l3build" 700 "luafindfont" 701 "luaotfload-tool" 702 "luatools" 703 "make4ht" 704 "pmxchords" 705 "tex4ebook" 706 "texblend" 707 "texdoc" 708 "texfindpkg" 709 "texlogsieve" 710 "xindex" 711 712 # requires full TEXMFROOT (e.g. for config) 713 "mktexfmt" 714 "mktexmf" 715 "mktexpk" 716 "mktextfm" 717 "psnup" 718 "psresize" 719 "pstops" 720 "tlmgr" 721 "updmap" 722 "webquiz" 723 724 # texlive-scripts: requires texlive.infra's TeXLive::TLUtils under TEXMFROOT 725 "fmtutil" 726 "fmtutil-sys" 727 "fmtutil-user" 728 729 # texlive-scripts: not used in nixpkgs, need updmap in PATH 730 "updmap-sys" 731 "updmap-user" 732 ]; 733 734 # simple test files 735 contextTestTex = writeText "context-test.tex" '' 736 \starttext 737 A simple test file. 738 \stoptext 739 ''; 740 latexTestTex = writeText "latex-test.tex" '' 741 \documentclass{article} 742 \begin{document} 743 A simple test file. 744 \end{document} 745 ''; 746 texTestTex = writeText "tex-test.tex" '' 747 Hello. 748 \bye 749 ''; 750 751 # link all binaries in single derivation 752 binPackages = lib.catAttrs "out" (lib.attrValues texlive.pkgs); 753 binaries = buildEnv { 754 name = "texlive-binaries"; 755 paths = binPackages; 756 }; 757 in 758 runCommand "texlive-test-binaries" 759 { 760 inherit 761 binaries 762 contextTestTex 763 latexTestTex 764 texTestTex 765 ; 766 texliveScheme = texliveFull; 767 } 768 '' 769 loadables="$(command -v bash)" 770 loadables="''${loadables%/bin/bash}/lib/bash" 771 enable -f "$loadables/realpath" realpath 772 mkdir -p "$out" 773 export HOME="$(mktemp -d)" 774 declare -i binCount=0 ignoredCount=0 brokenCount=0 failedCount=0 775 cp "$contextTestTex" context-test.tex 776 cp "$latexTestTex" latex-test.tex 777 cp "$texTestTex" tex-test.tex 778 779 testBin () { 780 path="$(realpath "$bin")" 781 path="''${path##*/}" 782 if [[ -z "$ignoreExitCode" ]] ; then 783 PATH="$path" "$bin" $args >"$out/$base.log" 2>&1 784 ret=$? 785 if [[ $ret == 0 ]] && grep -i 'command not found' "$out/$base.log" >/dev/null ; then 786 echo "command not found when running '$base''${args:+ $args}'" 787 return 1 788 fi 789 return $ret 790 else 791 PATH="$path" "$bin" $args >"$out/$base.log" 2>&1 792 ret=$? 793 if [[ $ret == 0 ]] && grep -i 'command not found' "$out/$base.log" >/dev/null ; then 794 echo "command not found when running '$base''${args:+ $args}'" 795 return 1 796 fi 797 if ! grep -Ei '(Example:|Options:|Syntax:|Usage:|improper command|SYNOPSIS)' "$out/$base.log" >/dev/null ; then 798 echo "did not find usage info when running '$base''${args:+ $args}'" 799 return $ret 800 fi 801 fi 802 } 803 804 for bin in "$binaries"/bin/* ; do 805 base="''${bin##*/}" 806 args= 807 ignoreExitCode= 808 binCount=$((binCount + 1)) 809 810 # ignore non-executable files (such as context.lua) 811 if [[ ! -x "$bin" ]] ; then 812 ignoredCount=$((ignoredCount + 1)) 813 continue 814 fi 815 816 case "$base" in 817 ${lib.concatStringsSep "|" ignored}) 818 ignoredCount=$((ignoredCount + 1)) 819 continue ;; 820 ${lib.concatStringsSep "|" broken}) 821 brokenCount=$((brokenCount + 1)) 822 continue ;; 823 ${lib.concatStringsSep "|" help}) 824 args=--help ;; 825 ${lib.concatStringsSep "|" shortHelp}) 826 args=-h ;; 827 ${lib.concatStringsSep "|" noArg}) 828 ;; 829 ${lib.concatStringsSep "|" contextTest}) 830 args=context-test.tex ;; 831 ${lib.concatStringsSep "|" latexTest}) 832 args=latex-test.tex ;; 833 ${lib.concatStringsSep "|" texTest}) 834 args=tex-test.tex ;; 835 ${lib.concatStringsSep "|" shortVersion}) 836 args=-v ;; 837 ebong) 838 touch empty 839 args=empty ;; 840 ht) 841 args='latex latex-test.tex' ;; 842 pdf2dsc) 843 args='--help --help --help' ;; 844 typeoutfileinfo) 845 args=/dev/null ;; 846 *) 847 args=--version ;; 848 esac 849 850 case "$base" in 851 ${lib.concatStringsSep "|" (ignoreExitCode ++ noArg)}) 852 ignoreExitCode=1 ;; 853 esac 854 855 case "$base" in 856 ${lib.concatStringsSep "|" needScheme}) 857 bin="$texliveScheme/bin/$base" 858 if [[ ! -f "$bin" ]] ; then 859 ignoredCount=$((ignoredCount + 1)) 860 continue 861 fi ;; 862 esac 863 864 if testBin ; then : ; else # preserve exit code 865 echo "failed '$base''${args:+ $args}' (exit code: $?)" 866 sed 's/^/ > /' < "$out/$base.log" 867 failedCount=$((failedCount + 1)) 868 fi 869 done 870 871 echo "tested $binCount binaries: $ignoredCount ignored, $brokenCount broken, $failedCount failed" 872 [[ $failedCount = 0 ]] 873 ''; 874 875 # check that all scripts have a Nix shebang 876 shebangs = 877 let 878 binPackages = lib.catAttrs "out" (lib.attrValues texlive.pkgs); 879 in 880 runCommand "texlive-test-shebangs" { } ( 881 '' 882 echo "checking that all texlive scripts shebangs are in '$NIX_STORE'" 883 declare -i scriptCount=0 invalidCount=0 884 '' 885 + (lib.concatMapStrings (pkg: '' 886 for bin in '${pkg.outPath}'/bin/* ; do 887 grep -I -q . "$bin" || continue # ignore binary files 888 [[ -x "$bin" ]] || continue # ignore non-executable files (such as context.lua) 889 scriptCount=$((scriptCount + 1)) 890 read -r cmdline < "$bin" 891 read -r interp <<< "$cmdline" 892 if [[ "$interp" != "#!$NIX_STORE"/* && "$interp" != "#! $NIX_STORE"/* ]] ; then 893 echo "error: non-nix shebang '$interp' in script '$bin'" 894 invalidCount=$((invalidCount + 1)) 895 fi 896 done 897 '') binPackages) 898 + '' 899 echo "checked $scriptCount scripts, found $invalidCount non-nix shebangs" 900 [[ $invalidCount -gt 0 ]] && exit 1 901 mkdir -p "$out" 902 '' 903 ); 904 905 # verify that the precomputed licensing information in default.nix 906 # does indeed match the metadata of the individual packages. 907 # 908 # This is part of the test suite (and not the normal evaluation) to save 909 # time for "normal" evaluations. To be more in line with the other tests, this 910 # also builds a derivation, even though it is essentially an eval-time assertion. 911 licenses = 912 let 913 concatLicenses = builtins.foldl' (acc: el: if builtins.elem el acc then acc else acc ++ [ el ]); 914 # converts a license to its attribute name in lib.licenses 915 licenseToAttrName = 916 license: builtins.head (builtins.attrNames (lib.filterAttrs (n: v: license == v) lib.licenses)); 917 lt = (a: b: a < b); 918 919 savedLicenses = scheme: scheme.meta.license; 920 savedLicensesAttrNames = scheme: map licenseToAttrName (savedLicenses scheme); 921 922 correctLicenses = 923 scheme: 924 builtins.foldl' ( 925 acc: pkg: concatLicenses acc (lib.toList (pkg.meta.license or [ ])) 926 ) [ ] scheme.passthru.requiredTeXPackages; 927 correctLicensesAttrNames = scheme: lib.sort lt (map licenseToAttrName (correctLicenses scheme)); 928 929 hasLicenseMismatch = 930 scheme: 931 (lib.isDerivation scheme) && (savedLicensesAttrNames scheme) != (correctLicensesAttrNames scheme); 932 incorrectSchemes = lib.filterAttrs (n: hasLicenseMismatch) (texlive.combined // texlive.schemes); 933 prettyPrint = name: scheme: '' 934 license info for ${name} is incorrect! Note that order is enforced. 935 saved: [ ${lib.concatStringsSep " " (savedLicensesAttrNames scheme)} ] 936 correct: [ ${lib.concatStringsSep " " (correctLicensesAttrNames scheme)} ] 937 ''; 938 errorText = lib.concatStringsSep "\n\n" (lib.mapAttrsToList prettyPrint incorrectSchemes); 939 in 940 runCommand "texlive-test-license" 941 { 942 inherit errorText; 943 } 944 ( 945 if (incorrectSchemes == { }) then 946 "echo everything is fine! > $out" 947 else 948 '' 949 echo "$errorText" 950 false 951 '' 952 ); 953 954 # verify that all fixed hashes are present 955 # this is effectively an eval-time assertion, converted into a derivation for 956 # ease of testing 957 fixedHashes = 958 let 959 fods = lib.concatMap ( 960 p: 961 lib.optional (p ? tex && lib.isDerivation p.tex) p.tex 962 ++ lib.optional (p ? texdoc) p.texdoc 963 ++ lib.optional (p ? texsource) p.texsource 964 ++ lib.optional (p ? tlpkg) p.tlpkg 965 ) (lib.attrValues texlive.pkgs); 966 errorText = lib.concatMapStrings ( 967 p: 968 lib.optionalString ( 969 !p ? outputHash 970 ) "${p.pname}-${p.tlOutputName} does not have a fixed output hash\n" 971 ) fods; 972 in 973 runCommand "texlive-test-fixed-hashes" 974 { 975 inherit errorText; 976 passAsFile = [ "errorText" ]; 977 } 978 '' 979 if [[ -s "$errorTextPath" ]] ; then 980 cat "$errorTextPath" 981 echo Failed: some TeX Live packages do not have fixed output hashes. Please read UPGRADING.md for how to generate a new fixed-hashes.nix. 982 exit 1 983 else 984 touch "$out" 985 fi 986 ''; 987}