tests
@@ -0,0 +1,24 @@
|
||||
# Our Logo
|
||||
|
||||
<div align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="dark_mode_cube.svg">
|
||||
<img alt="" src="light_mode_cube.svg">
|
||||
</picture>
|
||||
</div>
|
||||
|
||||
## Usage Guide for Third Parties
|
||||
|
||||
There may be cases where you want to use our logo. Please follow these rules:
|
||||
|
||||
**DO** use our logo as a part of thumbnails, banners/images in articles, or on a README in reference to the this project.
|
||||
|
||||
**DO** use our logo to relate resources back to the Bats project, like file associations or links to the project page.
|
||||
|
||||
**DO NOT** use our logo as the face of a third-party tool or extension that is not affiliated with the Bats project or Bats maintainers.
|
||||
|
||||
If in doubt, ask if your intended usecase is approved.
|
||||
|
||||
## Credits
|
||||
|
||||
The Bats Logo was created by [Vukory](https://www.artstation.com/vukory) ([Github](https://github.com/vukory)) and sponsored by [SethFalco](https://github.com/SethFalco).
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="54.261147mm"
|
||||
height="43.081844mm"
|
||||
viewBox="0 0 54.261147 43.081844"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
id="layer1"
|
||||
transform="translate(-71.195776,-139.44713)">
|
||||
<g
|
||||
id="g9615">
|
||||
<g
|
||||
id="g41739"
|
||||
transform="matrix(0.85714226,0,0,0.85714226,-1218.3151,927.76689)"
|
||||
style="display:inline;stroke-width:1.16667">
|
||||
<g
|
||||
id="g24595"
|
||||
transform="matrix(1.8087061,0,0,1.8087061,-1236.9066,713.01919)"
|
||||
style="stroke-width:0.64503">
|
||||
<path
|
||||
style="fill:#b1bbc0;fill-opacity:1;stroke:none;stroke-width:0.51199;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1533.1344,-889.4993 2.9413,-2.92919 0.8498,3.37817 13.7088,-13.65367 -1.5371,6.21648 1.1421,4.5359 -3.0032,2.99127 -1.666,6.73802 -8.7932,3.67943 -3.6425,3.62793 -3.6425,-3.62793 -8.7932,-3.67943 -1.666,-6.73802 -3.0033,-2.99127 1.1421,-4.5359 -1.537,-6.21648 13.7088,13.65367 0.8498,-3.37817 z"
|
||||
id="path41727" />
|
||||
<g
|
||||
id="g41737"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.64503">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1545.57,-882.22245 -8.7932,3.67942 4.7021,-4.68334 z"
|
||||
id="path41729" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1533.1343,-885.27404 17.5,-17.42995 -3.3983,13.74351 -5.7571,5.73411 z"
|
||||
id="path41731" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1520.6986,-882.22245 8.7932,3.67942 -4.7021,-4.68334 z"
|
||||
id="path41733" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1533.1343,-885.27404 -17.5,-17.42995 3.3983,13.74351 5.7571,5.73411 z"
|
||||
id="path41735" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="54mm"
|
||||
height="49.773262mm"
|
||||
viewBox="0 0 54 49.773262"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
sodipodi:docname="dark_mode_cube.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview22"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.5617892"
|
||||
inkscape:cx="16.007282"
|
||||
inkscape:cy="85.158741"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g9615" />
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
id="layer1"
|
||||
transform="translate(-71.28524,-137.37328)">
|
||||
<g
|
||||
id="g9615">
|
||||
<g
|
||||
id="g1124">
|
||||
<path
|
||||
id="path41791"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.22665;stroke-linecap:round;stroke-linejoin:round"
|
||||
d="m 96.963564,151.38471 23.654566,-13.59708 a 3.1148255,3.1148255 0 0 1 4.66711,2.70047 v 27.80743 a 5.5821378,5.5821378 0 0 1 -2.80027,4.83957 l -23.654571,13.59709 a 3.1148255,3.1148255 0 0 1 -4.667106,-2.70048 v -27.80743 a 5.5821378,5.5821378 0 0 1 2.800271,-4.83957 z" />
|
||||
<path
|
||||
id="path41803"
|
||||
style="display:inline;fill:#45b34f;stroke-width:0.118768;stroke-linecap:round;stroke-linejoin:round"
|
||||
d="m 114.81168,169.4541 5.56851,-3.20545 a 0.09387282,0.09387282 0 0 1 0.14066,0.0782 l 0.0603,1.77975 a 0.19488658,0.19488658 0 0 1 -0.0976,0.17551 l -5.5685,3.20545 a 0.09387286,0.09387286 0 0 1 -0.14066,-0.0782 l -0.0603,-1.77976 a 0.19488664,0.19488664 0 0 1 0.0976,-0.1755 z" />
|
||||
<g
|
||||
id="g1108">
|
||||
<g
|
||||
id="g9585">
|
||||
<path
|
||||
id="path41793"
|
||||
style="fill:#b1bbc0;fill-opacity:1;stroke:none;stroke-width:0.793752;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 71.285354,146.05562 2.00944,8.127 -1.49302,5.92984 3.92614,3.91052 2.17795,8.80874 11.4956,4.81002 4.76194,4.74298 v -4e-4 -19.06604 0 l -3.84523,-3.82922 -1.11095,4.41624 z" />
|
||||
<g
|
||||
id="g9208">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 77.905907,172.83169 11.49544,4.81016 -6.147116,-6.12259 z"
|
||||
id="path41799" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 94.163216,168.8423 -22.877976,-22.78639 4.442674,17.96707 7.526317,7.49628 z"
|
||||
id="path41801" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g1090">
|
||||
<g
|
||||
id="g9214">
|
||||
<path
|
||||
id="path41805"
|
||||
style="fill:#3e474b;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 117.04103,146.05561 -2.00944,8.1268 1.49326,5.92985 -3.92634,3.91052 -2.17795,8.80874 -11.495396,4.81022 -4.76176,4.74257 v 0 -19.06603 l 3.84524,-3.82942 1.11094,4.41623 z" />
|
||||
</g>
|
||||
<g
|
||||
id="g1081"
|
||||
transform="translate(-5e-5,-2e-4)">
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 110.42056,172.83169 -11.495474,4.81016 6.147114,-6.12259 z"
|
||||
id="path41795" />
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 94.163216,168.8423 22.877974,-22.78639 -4.44263,17.96707 -7.52636,7.49628 z"
|
||||
id="path41797" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="70.001816mm"
|
||||
height="22.666498mm"
|
||||
viewBox="0 0 70.001816 22.666498"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
sodipodi:docname="dark_mode_wordmark_lowercase.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview12"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.9994422"
|
||||
inkscape:cx="123.03431"
|
||||
inkscape:cy="-15.504324"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2478" />
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
id="g967"
|
||||
transform="translate(-2.2495861,-17.599696)">
|
||||
<g
|
||||
id="g9615"
|
||||
transform="translate(-59.217329,-138.31344)">
|
||||
<g
|
||||
id="g41739"
|
||||
transform="matrix(0.85714226,0,0,0.85714226,-1218.3151,927.76689)"
|
||||
style="display:inline;stroke-width:1.16667">
|
||||
<g
|
||||
id="g41829"
|
||||
style="display:inline"
|
||||
transform="matrix(1.1666675,0,0,1.1666675,-235.22352,200.90935)">
|
||||
<path
|
||||
d="m 1481.5343,-921.52789 v -22.40145 h 11.8268 c 2.2494,0 3.9423,0.53337 5.0786,1.6001 1.1595,1.06674 1.7393,2.57408 1.7393,4.52204 0,1.18268 -0.2319,2.17985 -0.6957,2.99149 -0.4406,0.78846 -1.032,1.40299 -1.7741,1.8436 1.0204,0.37104 1.8204,0.916 2.4002,1.63489 0.5797,0.71889 0.8696,1.79722 0.8696,3.23499 0,2.13347 -0.6261,3.76836 -1.8784,4.90466 -1.2522,1.11312 -3.0494,1.66968 -5.3916,1.66968 z m 4.4993,-13.28782 h 6.8068 c 0.9739,0 1.6812,-0.2203 2.1218,-0.66091 0.4406,-0.44061 0.661,-1.05514 0.661,-1.8436 0,-0.85802 -0.2204,-1.49575 -0.661,-1.91316 -0.4406,-0.44061 -1.2406,-0.66092 -2.4001,-0.66092 h -6.5285 z m 0,9.28756 h 7.3633 c 1.0204,0 1.774,-0.20871 2.261,-0.62613 0.5102,-0.41742 0.7653,-1.15949 0.7653,-2.22623 0,-0.85802 -0.2435,-1.49575 -0.7305,-1.91317 -0.487,-0.4406 -1.3218,-0.66091 -2.5045,-0.66091 h -7.1546 z"
|
||||
id="path41821"
|
||||
style="font-weight:600;font-size:135.945px;line-height:1.25;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';word-spacing:0px;fill:#ffffff;stroke:#ffffff;stroke-width:0.264583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path41823"
|
||||
style="font-weight:600;font-size:135.945px;line-height:1.25;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';word-spacing:0px;fill:#ffffff;stroke:#ffffff;stroke-width:0.264583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1506.4181,-940.01134 v 3.60332 h 4.173 c 2.6047,0 4.2857,-0.0426 4.4195,1.62757 v 0.87865 c -0.037,0 -0.2304,6.8e-4 -0.3233,8.1e-4 h -2.4927 c 0,0 -0.049,6.8e-4 -0.099,10e-4 -0.3506,-6.8e-4 -0.6995,-10e-4 -1.0639,-0.002 -5.2023,0 -6.9053,2.88353 -7.1561,5.75075 -0.015,5.2321 3.7291,6.56658 7.1561,6.61879 2.1165,-0.009 4.173,0 4.173,0 h 3.9656 v -6.1849 -6.18478 -0.49069 c 0,-4.48165 -2.4644,-5.61832 -7.2996,-5.61832 z m 4.2893,10.10451 h 4.3032 v 2.18928 2.18941 h -1.7445 -2.5587 c -0.9821,0 -1.7058,-0.19377 -2.171,-0.58128 -0.4652,-0.38748 -0.6978,-0.91705 -0.6978,-1.5887 0,-0.007 7e-4,-0.0129 7e-4,-0.0194 h 7e-4 v -0.007 c 0,-0.15019 0.012,-0.29241 0.033,-0.4271 0.079,-0.47856 0.2998,-0.87018 0.6646,-1.17403 0.4652,-0.38751 1.1889,-0.58128 2.171,-0.58128 z" />
|
||||
<path
|
||||
d="m 1528.5277,-921.52789 c -3.1768,-0.15406 -4.4238,-2.60536 -4.3648,-5.87864 v -8.59296 h -2.4895 v -4.01186 h 2.4895 v -3.91799 h 4.0169 v 3.91799 h 4.4177 v 4.01186 h -4.4177 v 8.21032 c 0,0.78846 0.1971,1.48415 0.5914,1.80881 0.3942,0.30147 0.9855,0.45221 1.774,0.45221 l 2.0523,0.006 v 3.99471 z"
|
||||
id="path41825"
|
||||
style="font-weight:600;font-size:135.945px;line-height:1.25;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';word-spacing:0px;fill:#ffffff;stroke:#ffffff;stroke-width:0.264583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path41827"
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.264583;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1543.5776,-940.01134 c -5.3998,0 -7.8157,1.34284 -7.9478,5.27667 0.1079,1.84396 0.6367,3.10179 2.0737,3.96515 h 0.024 c 0.1601,0.0968 0.3347,0.18873 0.5194,0.28834 3.2668,1.76133 7.8402,1.45762 8.1892,3.67678 0,0 0.092,1.20801 -1.2599,1.28157 h -3.1895 -2.7156 -3.6349 v 3.9951 h 3.9693 3.7181 c 5.3998,0 7.8156,-1.34284 7.9478,-5.27667 -0.108,-1.84396 -0.6368,-3.10176 -2.0737,-3.96512 h -0.024 c -0.16,-0.0968 -0.3346,-0.18875 -0.5193,-0.28837 -3.2668,-1.76133 -7.8403,-1.45764 -8.1892,-3.67678 0,0 -0.092,-1.20801 1.2599,-1.28156 h 3.1895 2.7155 3.635 v -3.99511 h -3.9693 z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="80.745293mm"
|
||||
height="21.625351mm"
|
||||
viewBox="0 0 80.745293 21.625351"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
sodipodi:docname="dark_mode_wordmark_uppercase.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview2480"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.0469406"
|
||||
inkscape:cx="102.20255"
|
||||
inkscape:cy="46.325454"
|
||||
inkscape:window-width="1284"
|
||||
inkscape:window-height="1040"
|
||||
inkscape:window-x="632"
|
||||
inkscape:window-y="71"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g41739" />
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-69.238415,-136.04173)">
|
||||
<g
|
||||
id="g9615">
|
||||
<g
|
||||
id="g41739"
|
||||
transform="matrix(0.85714226,0,0,0.85714226,-1218.3151,927.76689)"
|
||||
style="display:inline;stroke-width:1.16667">
|
||||
<g
|
||||
aria-label="BATS"
|
||||
id="g41789"
|
||||
style="font-size:15.875px;line-height:1.25;word-spacing:0px;display:inline;fill:#ffffff;stroke-width:0.128968"
|
||||
transform="matrix(2.3934725,0,0,2.3934725,1452.4353,-1069.4974)"
|
||||
inkscape:export-filename="D:\Art2021\2023\Bats-refined.png"
|
||||
inkscape:export-xdpi="150"
|
||||
inkscape:export-ydpi="150">
|
||||
<path
|
||||
d="m 20.76962,71.305199 v -10.2235 h 5.3975 q 1.539875,0 2.31775,0.73025 0.79375,0.73025 0.79375,2.06375 0,0.809625 -0.3175,1.36525 -0.301625,0.53975 -0.809625,0.841375 0.6985,0.254 1.095375,0.746125 0.396875,0.492125 0.396875,1.476375 0,1.4605 -0.85725,2.238375 -0.85725,0.762 -2.460625,0.762 z m 2.555875,-6.06425 h 2.079625 q 0.66675,0 0.968375,-0.301625 0.301625,-0.301625 0.301625,-0.841375 0,-0.587375 -0.301625,-0.873125 -0.301625,-0.301625 -1.095375,-0.301625 h -1.952625 z m 0,4.238625 h 2.333625 q 0.6985,0 1.031875,-0.28575 0.34925,-0.28575 0.34925,-1.016 0,-0.587375 -0.333375,-0.873125 -0.333375,-0.301625 -1.143,-0.301625 h -2.238375 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';stroke-width:0.128968"
|
||||
id="path41781" />
|
||||
<path
|
||||
d="m 31.152168,71.305199 3.90525,-10.2235 h 2.76225 l 3.90525,10.2235 h -2.667 l -0.92075,-2.31775 h -3.413125 l -0.904875,2.31775 z m 3.921125,-4.206875 h 2.714625 l -1.36525,-3.556 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';stroke-width:0.128968"
|
||||
id="path41783" />
|
||||
<path
|
||||
d="m 44.89475,71.305199 v -8.255 h -3.000375 v -1.9685 H 50.451 v 1.9685 h -3.000375 v 8.255 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';stroke-width:0.128968"
|
||||
id="path41785" />
|
||||
<path
|
||||
d="m 55.873376,71.463949 q -1.016,0 -1.905,-0.15875 -0.873125,-0.142875 -1.508125,-0.428625 v -2.174875 q 0.6985,0.301625 1.539875,0.492125 0.85725,0.1905 1.61925,0.1905 0.9525,0 1.412875,-0.174625 0.47625,-0.174625 0.47625,-0.762 0,-0.396875 -0.238125,-0.635 -0.22225,-0.238125 -0.746125,-0.41275 -0.508,-0.1905 -1.397,-0.4445 -1.04775,-0.3175 -1.666875,-0.6985 -0.619125,-0.396875 -0.889,-0.9525 -0.269875,-0.555625 -0.269875,-1.36525 0,-1.4605 1.04775,-2.238375 1.04775,-0.777875 3.095625,-0.777875 0.889,0 1.730375,0.142875 0.841375,0.127 1.36525,0.301625 v 2.19075 q -0.682625,-0.269875 -1.381125,-0.396875 -0.682625,-0.127 -1.3335,-0.127 -0.85725,0 -1.397,0.15875 -0.523875,0.15875 -0.523875,0.73025 0,0.333375 0.1905,0.53975 0.1905,0.1905 0.650875,0.34925 0.47625,0.15875 1.285875,0.381 1.254125,0.333375 1.920875,0.809625 0.66675,0.460375 0.92075,1.0795 0.254,0.60325 0.254,1.36525 0,1.349375 -1.04775,2.19075 -1.04775,0.8255 -3.20675,0.8255 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';stroke-width:0.128968"
|
||||
id="path41787" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="54.261147mm"
|
||||
height="43.081844mm"
|
||||
viewBox="0 0 54.261147 43.081844"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
sodipodi:docname="light_mode_bat.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview2480"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.0469406"
|
||||
inkscape:cx="95.5164"
|
||||
inkscape:cy="32.953158"
|
||||
inkscape:window-width="1284"
|
||||
inkscape:window-height="1040"
|
||||
inkscape:window-x="632"
|
||||
inkscape:window-y="71"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g41739" />
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-71.195776,-139.44713)">
|
||||
<g
|
||||
id="g9615">
|
||||
<g
|
||||
id="g41739"
|
||||
transform="matrix(0.85714226,0,0,0.85714226,-1218.3151,927.76689)"
|
||||
style="display:inline;stroke-width:1.16667">
|
||||
<g
|
||||
id="g24595"
|
||||
transform="matrix(1.8087061,0,0,1.8087061,-1236.9066,713.01919)"
|
||||
style="stroke-width:0.64503">
|
||||
<path
|
||||
style="fill:#3e474b;fill-opacity:1;stroke:none;stroke-width:0.51199;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1533.1344,-889.4993 2.9413,-2.92919 0.8498,3.37817 13.7088,-13.65367 -1.5371,6.21648 1.1421,4.5359 -3.0032,2.99127 -1.666,6.73802 -8.7932,3.67943 -3.6425,3.62793 -3.6425,-3.62793 -8.7932,-3.67943 -1.666,-6.73802 -3.0033,-2.99127 1.1421,-4.5359 -1.537,-6.21648 13.7088,13.65367 0.8498,-3.37817 z"
|
||||
id="path41727"
|
||||
inkscape:export-filename="D:\Art2021\2023\BatsLogo\test.png"
|
||||
inkscape:export-xdpi="150"
|
||||
inkscape:export-ydpi="150" />
|
||||
<g
|
||||
id="g41737"
|
||||
style="fill:#515b60;fill-opacity:1;stroke-width:0.64503">
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1545.57,-882.22245 -8.7932,3.67942 4.7021,-4.68334 z"
|
||||
id="path41729"
|
||||
inkscape:export-filename="D:\Art2021\2023\BatsLogo\test.png"
|
||||
inkscape:export-xdpi="150"
|
||||
inkscape:export-ydpi="150" />
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1533.1343,-885.27404 17.5,-17.42995 -3.3983,13.74351 -5.7571,5.73411 z"
|
||||
id="path41731"
|
||||
inkscape:export-filename="D:\Art2021\2023\BatsLogo\test.png"
|
||||
inkscape:export-xdpi="150"
|
||||
inkscape:export-ydpi="150" />
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1520.6986,-882.22245 8.7932,3.67942 -4.7021,-4.68334 z"
|
||||
id="path41733"
|
||||
inkscape:export-filename="D:\Art2021\2023\BatsLogo\test.png"
|
||||
inkscape:export-xdpi="150"
|
||||
inkscape:export-ydpi="150" />
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.170933;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1533.1343,-885.27404 -17.5,-17.42995 3.3983,13.74351 5.7571,5.73411 z"
|
||||
id="path41735"
|
||||
inkscape:export-filename="D:\Art2021\2023\BatsLogo\test.png"
|
||||
inkscape:export-xdpi="150"
|
||||
inkscape:export-ydpi="150" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="54mm"
|
||||
height="49.773262mm"
|
||||
viewBox="0 0 54 49.773262"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
sodipodi:docname="light_mode_cube.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview22"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.1235784"
|
||||
inkscape:cx="81.797212"
|
||||
inkscape:cy="86.439323"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2478" />
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
id="g1227">
|
||||
<path
|
||||
id="path41791"
|
||||
style="fill:#3e474b;fill-opacity:1;stroke-width:0.22665;stroke-linecap:round;stroke-linejoin:round"
|
||||
d="M 25.678324,14.01143 49.33289,0.41435 A 3.1148255,3.1148255 0 0 1 54,3.11482 v 27.80743 a 5.5821378,5.5821378 0 0 1 -2.80027,4.83957 L 27.545159,49.35891 A 3.1148255,3.1148255 0 0 1 22.878053,46.65843 V 18.851 a 5.5821378,5.5821378 0 0 1 2.800271,-4.83957 z" />
|
||||
<path
|
||||
id="path41803"
|
||||
style="display:inline;fill:#45b34f;stroke-width:0.118768;stroke-linecap:round;stroke-linejoin:round"
|
||||
d="m 43.52644,32.08082 5.56851,-3.20545 a 0.09387282,0.09387282 0 0 1 0.14066,0.0782 l 0.0603,1.77975 a 0.19488658,0.19488658 0 0 1 -0.0976,0.17551 l -5.5685,3.20545 a 0.09387286,0.09387286 0 0 1 -0.14066,-0.0782 l -0.0603,-1.77976 a 0.19488664,0.19488664 0 0 1 0.0976,-0.1755 z" />
|
||||
<g
|
||||
id="g1212">
|
||||
<g
|
||||
id="g9585"
|
||||
transform="translate(-71.28524,-137.37328)">
|
||||
<path
|
||||
id="path41793"
|
||||
style="fill:#3e474b;fill-opacity:1;stroke:none;stroke-width:0.793752;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 71.285354,146.05562 2.00944,8.127 -1.49302,5.92984 3.92614,3.91052 2.17795,8.80874 11.4956,4.81002 4.76194,4.74298 v -4e-4 -19.06604 0 l -3.84523,-3.82922 -1.11095,4.41624 z" />
|
||||
<g
|
||||
id="g9208">
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 77.905907,172.83169 11.49544,4.81016 -6.147116,-6.12259 z"
|
||||
id="path41799" />
|
||||
<path
|
||||
style="fill:#515b60;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 94.163216,168.8423 -22.877976,-22.78639 4.442674,17.96707 7.526317,7.49628 z"
|
||||
id="path41801" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g9214"
|
||||
transform="translate(-71.28524,-137.37328)">
|
||||
<path
|
||||
id="path41805"
|
||||
style="fill:#b1bbc0;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 117.04096,146.05572 -2.00944,8.1268 1.49326,5.92985 -3.92634,3.91052 -2.17795,8.80874 -11.495404,4.81022 -4.761755,4.74257 v 0 -19.06603 l 3.845235,-3.82942 1.110946,4.41623 z" />
|
||||
<g
|
||||
id="g9204"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 110.42056,172.83169 -11.495474,4.81016 6.147114,-6.12259 z"
|
||||
id="path41807" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 94.163216,168.8423 22.877974,-22.78639 -4.44263,17.96707 -7.52636,7.49628 z"
|
||||
id="path41809" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="70.001816mm"
|
||||
height="22.666498mm"
|
||||
viewBox="0 0 70.001816 22.666498"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
sodipodi:docname="wordmark_lowercase_dark.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview2480"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.0469406"
|
||||
inkscape:cx="115.57484"
|
||||
inkscape:cy="-0.477582"
|
||||
inkscape:window-width="1284"
|
||||
inkscape:window-height="1040"
|
||||
inkscape:window-x="632"
|
||||
inkscape:window-y="71"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g41739" />
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-65.637684,-148.3707)">
|
||||
<g
|
||||
id="g9615">
|
||||
<g
|
||||
id="g41739"
|
||||
transform="matrix(0.85714226,0,0,0.85714226,-1218.3151,927.76689)"
|
||||
style="display:inline;stroke-width:1.16667">
|
||||
<g
|
||||
id="g41939"
|
||||
transform="matrix(1.1666675,0,0,1.1666675,-230.35762,192.10983)"
|
||||
style="display:inline;fill:#3e474b;fill-opacity:1;stroke:#3e474b;stroke-opacity:1">
|
||||
<path
|
||||
d="m 1481.5343,-921.52789 v -22.40145 h 11.8268 c 2.2494,0 3.9423,0.53337 5.0786,1.6001 1.1595,1.06674 1.7393,2.57408 1.7393,4.52204 0,1.18268 -0.2319,2.17985 -0.6957,2.99149 -0.4406,0.78846 -1.032,1.40299 -1.7741,1.8436 1.0204,0.37104 1.8204,0.916 2.4002,1.63489 0.5797,0.71889 0.8696,1.79722 0.8696,3.23499 0,2.13347 -0.6261,3.76836 -1.8784,4.90466 -1.2522,1.11312 -3.0494,1.66968 -5.3916,1.66968 z m 4.4993,-13.28782 h 6.8068 c 0.9739,0 1.6812,-0.2203 2.1218,-0.66091 0.4406,-0.44061 0.661,-1.05514 0.661,-1.8436 0,-0.85802 -0.2204,-1.49575 -0.661,-1.91316 -0.4406,-0.44061 -1.2406,-0.66092 -2.4001,-0.66092 h -6.5285 z m 0,9.28756 h 7.3633 c 1.0204,0 1.774,-0.20871 2.261,-0.62613 0.5102,-0.41742 0.7653,-1.15949 0.7653,-2.22623 0,-0.85802 -0.2435,-1.49575 -0.7305,-1.91317 -0.487,-0.4406 -1.3218,-0.66091 -2.5045,-0.66091 h -7.1546 z"
|
||||
id="path41931"
|
||||
sodipodi:nodetypes="ccscsccsscsccssscscccscscscc"
|
||||
style="font-weight:600;font-size:135.945px;line-height:1.25;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';word-spacing:0px;fill:#3e474b;fill-opacity:1;stroke:#3e474b;stroke-width:0.264583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path41933"
|
||||
style="font-weight:600;font-size:135.945px;line-height:1.25;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';word-spacing:0px;fill:#3e474b;fill-opacity:1;stroke:#3e474b;stroke-width:0.264583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1506.4181,-940.01134 v 3.60332 h 4.173 c 2.6047,0 4.2857,-0.0426 4.4195,1.62757 v 0.87865 c -0.037,0 -0.2304,6.8e-4 -0.3233,8.1e-4 h -2.4927 c 0,0 -0.049,6.8e-4 -0.099,10e-4 -0.3506,-6.8e-4 -0.6995,-10e-4 -1.0639,-0.002 -5.2023,0 -6.9053,2.88353 -7.1561,5.75075 -0.015,5.2321 3.7291,6.56658 7.1561,6.61879 2.1165,-0.009 4.173,0 4.173,0 h 3.9656 v -6.1849 -6.18478 -0.49069 c 0,-4.48165 -2.4644,-5.61832 -7.2996,-5.61832 z m 4.2893,10.10451 h 4.3032 v 2.18928 2.18941 h -1.7445 -2.5587 c -0.9821,0 -1.7058,-0.19377 -2.171,-0.58128 -0.4652,-0.38748 -0.6978,-0.91705 -0.6978,-1.5887 0,-0.007 7e-4,-0.0129 7e-4,-0.0194 h 7e-4 v -0.007 c 0,-0.15019 0.012,-0.29241 0.033,-0.4271 0.079,-0.47856 0.2998,-0.87018 0.6646,-1.17403 0.4652,-0.38751 1.1889,-0.58128 2.171,-0.58128 z"
|
||||
sodipodi:nodetypes="ccsccccccccccccscccccccsssccccscc" />
|
||||
<path
|
||||
d="m 1528.5277,-921.52789 c -3.1768,-0.15406 -4.4238,-2.60536 -4.3648,-5.87864 v -8.59296 h -2.4895 v -4.01186 h 2.4895 v -3.91799 h 4.0169 v 3.91799 h 4.4177 v 4.01186 h -4.4177 v 8.21032 c 0,0.78846 0.1971,1.48415 0.5914,1.80881 0.3942,0.30147 0.9855,0.45221 1.774,0.45221 l 2.0523,0.006 v 3.99471 z"
|
||||
id="path41935"
|
||||
style="font-weight:600;font-size:135.945px;line-height:1.25;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';word-spacing:0px;fill:#3e474b;fill-opacity:1;stroke:#3e474b;stroke-width:0.264583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccccccccccccscsccc" />
|
||||
<path
|
||||
id="path41937"
|
||||
style="fill:#3e474b;fill-opacity:1;stroke:#3e474b;stroke-width:0.264583;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1543.5776,-940.01134 c -5.3998,0 -7.8157,1.34284 -7.9478,5.27667 0.1079,1.84396 0.6367,3.10179 2.0737,3.96515 h 0.024 c 0.1601,0.0968 0.3347,0.18873 0.5194,0.28834 3.2668,1.76133 7.8402,1.45762 8.1892,3.67678 0,0 0.092,1.20801 -1.2599,1.28157 h -3.1895 -2.7156 -3.6349 v 3.9951 h 3.9693 3.7181 c 5.3998,0 7.8156,-1.34284 7.9478,-5.27667 -0.108,-1.84396 -0.6368,-3.10176 -2.0737,-3.96512 h -0.024 c -0.16,-0.0968 -0.3346,-0.18875 -0.5193,-0.28837 -3.2668,-1.76133 -7.8403,-1.45764 -8.1892,-3.67678 0,0 -0.092,-1.20801 1.2599,-1.28156 h 3.1895 2.7155 3.635 v -3.99511 h -3.9693 z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="80.745293mm"
|
||||
height="21.625351mm"
|
||||
viewBox="0 0 80.745293 21.625351"
|
||||
version="1.1"
|
||||
id="svg2478"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs2475" />
|
||||
<g
|
||||
id="layer1"
|
||||
transform="translate(-69.301072,-141.15047)">
|
||||
<g
|
||||
id="g9615">
|
||||
<g
|
||||
id="g41739"
|
||||
transform="matrix(0.85714226,0,0,0.85714226,-1218.3151,927.76689)"
|
||||
style="display:inline;stroke-width:1.16667">
|
||||
<g
|
||||
aria-label="BATS"
|
||||
id="g41869"
|
||||
style="font-size:15.875px;line-height:1.25;word-spacing:0px;display:inline;fill:#3e474b;fill-opacity:1;stroke-width:0.128968"
|
||||
transform="matrix(2.3934725,0,0,2.3934725,1452.5084,-1063.5372)">
|
||||
<path
|
||||
d="m 20.76962,71.305199 v -10.2235 h 5.3975 q 1.539875,0 2.31775,0.73025 0.79375,0.73025 0.79375,2.06375 0,0.809625 -0.3175,1.36525 -0.301625,0.53975 -0.809625,0.841375 0.6985,0.254 1.095375,0.746125 0.396875,0.492125 0.396875,1.476375 0,1.4605 -0.85725,2.238375 -0.85725,0.762 -2.460625,0.762 z m 2.555875,-6.06425 h 2.079625 q 0.66675,0 0.968375,-0.301625 0.301625,-0.301625 0.301625,-0.841375 0,-0.587375 -0.301625,-0.873125 -0.301625,-0.301625 -1.095375,-0.301625 h -1.952625 z m 0,4.238625 h 2.333625 q 0.6985,0 1.031875,-0.28575 0.34925,-0.28575 0.34925,-1.016 0,-0.587375 -0.333375,-0.873125 -0.333375,-0.301625 -1.143,-0.301625 h -2.238375 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';fill:#3e474b;fill-opacity:1;stroke-width:0.128968"
|
||||
id="path41861" />
|
||||
<path
|
||||
d="m 31.152168,71.305199 3.90525,-10.2235 h 2.76225 l 3.90525,10.2235 h -2.667 l -0.92075,-2.31775 h -3.413125 l -0.904875,2.31775 z m 3.921125,-4.206875 h 2.714625 l -1.36525,-3.556 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';fill:#3e474b;fill-opacity:1;stroke-width:0.128968"
|
||||
id="path41863" />
|
||||
<path
|
||||
d="m 44.89475,71.305199 v -8.255 h -3.000375 v -1.9685 H 50.451 v 1.9685 h -3.000375 v 8.255 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';fill:#3e474b;fill-opacity:1;stroke-width:0.128968"
|
||||
id="path41865" />
|
||||
<path
|
||||
d="m 55.873376,71.463949 q -1.016,0 -1.905,-0.15875 -0.873125,-0.142875 -1.508125,-0.428625 v -2.174875 q 0.6985,0.301625 1.539875,0.492125 0.85725,0.1905 1.61925,0.1905 0.9525,0 1.412875,-0.174625 0.47625,-0.174625 0.47625,-0.762 0,-0.396875 -0.238125,-0.635 -0.22225,-0.238125 -0.746125,-0.41275 -0.508,-0.1905 -1.397,-0.4445 -1.04775,-0.3175 -1.666875,-0.6985 -0.619125,-0.396875 -0.889,-0.9525 -0.269875,-0.555625 -0.269875,-1.36525 0,-1.4605 1.04775,-2.238375 1.04775,-0.777875 3.095625,-0.777875 0.889,0 1.730375,0.142875 0.841375,0.127 1.36525,0.301625 v 2.19075 q -0.682625,-0.269875 -1.381125,-0.396875 -0.682625,-0.127 -1.3335,-0.127 -0.85725,0 -1.397,0.15875 -0.523875,0.15875 -0.523875,0.73025 0,0.333375 0.1905,0.53975 0.1905,0.1905 0.650875,0.34925 0.47625,0.15875 1.285875,0.381 1.254125,0.333375 1.920875,0.809625 0.66675,0.460375 0.92075,1.0795 0.254,0.60325 0.254,1.36525 0,1.349375 -1.04775,2.19075 -1.04775,0.8255 -3.20675,0.8255 z"
|
||||
style="font-weight:600;font-family:Kanit;-inkscape-font-specification:'Kanit Semi-Bold';fill:#3e474b;fill-opacity:1;stroke-width:0.128968"
|
||||
id="path41867" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,74 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'bats-core'
|
||||
copyright = '2022, bats-core organization'
|
||||
author = 'bats-core organization'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'recommonmark',
|
||||
'sphinxcontrib.programoutput',
|
||||
'sphinx.ext.autosectionlabel'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
html_sidebars = { '**': [
|
||||
'about.html',
|
||||
'navigation.html',
|
||||
'relations.html',
|
||||
'searchbox.html',
|
||||
'donate.html'] }
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#html_theme = 'alabaster'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static', 'assets']
|
||||
html_logo = "assets/light_mode_cube.svg"
|
||||
|
||||
#man_pages = [ ('man.1', 'bats', 'bats documentation', ['bats-core Contributors'], 1)]
|
||||
|
||||
def setup(app):
|
||||
app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True)
|
||||
import recommonmark
|
||||
from recommonmark.transform import AutoStructify
|
||||
app.add_transform(AutoStructify)
|
||||
@@ -0,0 +1,70 @@
|
||||
# Docker Usage Guide
|
||||
|
||||
- [Docker Usage Guide](#docker-usage-guide)
|
||||
* [Basic Usage](#basic-usage)
|
||||
* [Basic Usage for bats project](#basic-usage-for-bats-project)
|
||||
* [Docker Gotchas](#docker-gotchas)
|
||||
* [Extending from the base image](#extending-from-the-base-image)
|
||||
|
||||
## Basic Usage
|
||||
|
||||
For test suites that are intended to run in isolation from their project code, you can mount the test directory and run the [official bats docker image](https://hub.docker.com/r/bats/bats):
|
||||
|
||||
```bash
|
||||
$ docker run -it -v "$PWD:/code" bats/bats:latest /code/test
|
||||
```
|
||||
|
||||
This Docker image includes libraries like [bats-support](https://github.com/bats-core/bats-support) and [bats-assert](https://github.com/bats-core/bats-assert), which can be loaded in `setup` like this:
|
||||
|
||||
```bash
|
||||
setup() {
|
||||
bats_load_library bats-support
|
||||
bats_load_library bats-assert
|
||||
}
|
||||
```
|
||||
|
||||
## Basic Usage for Bats Project
|
||||
|
||||
To build and run `bats`' own tests:
|
||||
```bash
|
||||
$ git clone https://github.com/bats-core/bats-core.git
|
||||
Cloning into 'bats-core'...
|
||||
remote: Counting objects: 1222, done.
|
||||
remote: Compressing objects: 100% (53/53), done.
|
||||
remote: Total 1222 (delta 34), reused 55 (delta 21), pack-reused 1146
|
||||
Receiving objects: 100% (1222/1222), 327.28 KiB | 1.70 MiB/s, done.
|
||||
Resolving deltas: 100% (661/661), done.
|
||||
|
||||
$ cd bats-core/
|
||||
$ docker build --tag bats/bats:latest .
|
||||
...
|
||||
$ docker run -it bats/bats:latest --formatter tap /opt/bats/test
|
||||
```
|
||||
|
||||
To mount your tests into the container, first build the image as above. Then, for example with `bats`:
|
||||
```bash
|
||||
$ docker run -it -v "$PWD:/opt/bats" bats/bats:latest /opt/bats/test
|
||||
```
|
||||
This runs the `test/` directory from the bats-core repository inside the bats Docker container.
|
||||
|
||||
## Docker Gotchas
|
||||
|
||||
Relying on functionality provided by your environment (ssh keys or agent, installed binaries, fixtures outside the mounted test directory) will fail when running inside Docker.
|
||||
|
||||
`--interactive`/`-i` attaches an interactive terminal and is useful to kill hanging processes (otherwise has to be done via docker stop command). `--tty`/`-t` simulates a tty (often not used, but most similar to test runs from a Bash prompt). Interactivity is important to a user, but not a build, and TTYs are probably more important to a headless build. Everything's least-surprising to a new Docker use if both are used.
|
||||
|
||||
## Extending from the base image
|
||||
|
||||
Docker operates on a principle of isolation, and bundles all dependencies required into the Docker image. These can be mounted in at runtime (for test files, configuration, etc). For binary dependencies it may be better to extend the base Docker image with further tools and files.
|
||||
|
||||
```dockerfile
|
||||
FROM bats/bats
|
||||
|
||||
RUN \
|
||||
apk \
|
||||
--no-cache \
|
||||
--update \
|
||||
add \
|
||||
openssh
|
||||
|
||||
```
|
||||
@@ -0,0 +1,172 @@
|
||||
FAQ
|
||||
===
|
||||
|
||||
How do I set the working directory?
|
||||
-----------------------------------
|
||||
|
||||
The working directory is simply the directory where you started when executing bats.
|
||||
If you want to enforce a specific directory, you can use `cd` in the `setup_file`/`setup` functions.
|
||||
However, be aware that code outside any function will run before any of these setup functions and might interfere with bats' internals.
|
||||
|
||||
|
||||
How do I see the output of the command under `run` when a test fails?
|
||||
---------------------------------------------------------------------
|
||||
|
||||
`run` captures stdout and stderr of its command and stores it in the `$output` and `${lines[@]}` variables.
|
||||
If you want to see this output, you need to print it yourself, or use functions like `assert_output` that will reproduce it on failure.
|
||||
|
||||
Can I use `--filter` to exclude files/tests?
|
||||
--------------------------------------------
|
||||
|
||||
No, not directly. `--filter` uses a regex to match against test names. So you could try to invert the regex.
|
||||
The filename won't be part of the strings that are tested, so you cannot filter against files.
|
||||
|
||||
How can I exclude a single test from a test run?
|
||||
------------------------------------------------
|
||||
|
||||
If you want to exclude only few tests from a run, you can either `skip` them:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "Testname" {
|
||||
# yadayada
|
||||
}
|
||||
|
||||
becomes
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "Testname" {
|
||||
skip 'Optional skip message'
|
||||
# yadayada
|
||||
}
|
||||
|
||||
or comment them out, e.g.:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "Testname" {
|
||||
|
||||
becomes
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
disabled() { # @test "Testname" {
|
||||
|
||||
For multiple tests or all tests of a file, this becomes tedious, so read on.
|
||||
|
||||
How can I exclude all tests of a file from a test run?
|
||||
--------------------------------------------------------
|
||||
|
||||
If you run your test suite by naming individual files like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ bats test/a.bats test/b.bats ...
|
||||
|
||||
you can simply omit your file. When running a folder like
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ bats test/
|
||||
|
||||
you can prevent test files from being picked up by changing their extension to something other than `.bats`.
|
||||
|
||||
It is also possible to `skip` in `setup_file`/`setup` which will skip all tests in the file.
|
||||
|
||||
How can I include my own `.sh` files for testing?
|
||||
-------------------------------------------------
|
||||
|
||||
You can simply `source <your>.sh` files. However, be aware that `source`ing files with errors outside of any function (or inside `setup_file`) will trip up bats
|
||||
and lead to hard to diagnose errors.
|
||||
Therefore, it is safest to only `source` inside `setup` or the test functions themselves.
|
||||
|
||||
How can I debug a failing test?
|
||||
-------------------------------
|
||||
|
||||
Short of using a bash debugger you should make sure to use appropriate asserts for your task instead of raw bash comparisons, e.g.:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test test {
|
||||
run echo test failed
|
||||
assert_output "test"
|
||||
# instead of
|
||||
[ "$output" = "test" ]
|
||||
}
|
||||
|
||||
Because the former will print the output when the test fails while the latter won't.
|
||||
Similarly, you should use `assert_success`/`assert_failure` instead of `[ "$status" -eq 0 ]` for return code checks.
|
||||
|
||||
Is there a mechanism to add file/test specific functionality to a common setup function?
|
||||
----------------------------------------------------------------------------------------
|
||||
|
||||
Often the setup consists of parts that are common between different files of a test suite and parts that are specific to each file.
|
||||
There is no suite wide setup functionality yet, so you should extract these common setup steps into their own file (e.g. `common-test-setup.sh`) and function (e.g. `commonSetup() {}`),
|
||||
which can be `source`d or `load`ed and call it in `setup_file` or `setup`.
|
||||
|
||||
How can I use helper libraries like bats-assert?
|
||||
------------------------------------------------
|
||||
|
||||
This is a short reproduction of https://github.com/ztombol/bats-docs.
|
||||
|
||||
At first, you should make sure the library is installed. This is usually done in the `test_helper/` folders alongside the `.bats` files, giving you a filesystem layout like this:
|
||||
|
||||
.. code-block::
|
||||
|
||||
test/
|
||||
test.bats
|
||||
test_helper/
|
||||
bats-support/
|
||||
bats-assert/
|
||||
|
||||
Next, you should load those helper libraries:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
setup() {
|
||||
load 'test_helper/bats-support/load' # this is required by bats-assert!
|
||||
load 'test_helper/bats-assert/load'
|
||||
}
|
||||
|
||||
Now, you should be able to use the functions from these helpers inside your tests, e.g.:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "test" {
|
||||
run echo test
|
||||
assert_output "test"
|
||||
}
|
||||
|
||||
Note that you obviously need to load the library before using it.
|
||||
If you need the library inside `setup_file` or `teardown_file` you need to load it in `setup_file`.
|
||||
|
||||
How to set a test timeout in bats?
|
||||
----------------------------------
|
||||
|
||||
Set the variable `$BATS_TEST_TIMEOUT` before `setup()` starts. This means you can set it either on the command line,
|
||||
in free code in the test file or in `setup_file()`.
|
||||
|
||||
How can I lint/shell-format my bats tests?
|
||||
------------------------------------------
|
||||
|
||||
Due to their custom syntax (`@test`), `.bats` files are not standard bash. This prevents most tools from working with bats.
|
||||
However, there is an alternative syntax `function_name { # @test` to declare tests in a bash compliant manner.
|
||||
|
||||
- shellcheck support since version 0.7
|
||||
- shfmt support since version 3.2.0 (using `-ln bats`)
|
||||
|
||||
|
||||
How can I check if a test failed/succeeded during teardown?
|
||||
-----------------------------------------------------------
|
||||
|
||||
You can check `BATS_TEST_COMPLETED` which will be set to 1 if the test was successful or empty if it was not.
|
||||
There is also `BATS_TEST_SKIPPED` which will be non-empty (contains the skip message or -1) when `skip` was called.
|
||||
|
||||
How can I setup/cleanup before/after all tests?
|
||||
-----------------------------------------------
|
||||
|
||||
Setup/cleanup before/after all tests can be achieved using the special `setup_suite` and `teardown_suite` functions.
|
||||
These functions must be placed into a dedicated `setup_suite.bash` file next to your `.bats` files.
|
||||
For more information check out the :ref:`setup and teardown section <setup and teardown: pre- and post-test hooks>`.
|
||||
@@ -0,0 +1,132 @@
|
||||
Gotchas
|
||||
=======
|
||||
|
||||
My test fails although I return true?
|
||||
-------------------------------------
|
||||
|
||||
Using `return 1` to signify `true` for a success as is done often in other languages does not mesh well with Bash's
|
||||
convention of using return code 0 to signify success and everything non-zero to indicate a failure.
|
||||
|
||||
Please adhere to this idiom while using bats, or you will constantly work against your environment.
|
||||
|
||||
My negated statement (e.g. ! true) does not fail the test, even when it should.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Bash deliberately excludes negated return values from causing a pipeline to exit (see bash's `-e` option).
|
||||
Use `run !` on Bats 1.5.0 and above. For older bats versions, use one of `! x || false` or `run` with `[ $status != 0 ]`.
|
||||
|
||||
If the negated command is the final statement in a test, that final statement's (negated) exit status will propagate through to the test's return code as usual.
|
||||
Negated statements of one of the correct forms mentioned above will explicitly fail the test when the pipeline returns true, regardless of where they occur in the test.
|
||||
|
||||
I cannot register a test multiple times via for loop.
|
||||
-----------------------------------------------------
|
||||
|
||||
The usual bats tests (`@test`) are preprocessed into functions.
|
||||
Wrapping them into a for loop only redeclares this function.
|
||||
|
||||
If you are interested in registering multiple calls to the same function, contribute your wishes to issue `#306 <https://github.com/bats-core/bats-core/issues/306>`_.
|
||||
|
||||
I cannot pass parameters to test or .bats files.
|
||||
------------------------------------------------
|
||||
|
||||
Especially while using bats via shebang:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/usr/bin/env bats
|
||||
|
||||
@test "test" {
|
||||
# ...
|
||||
}
|
||||
|
||||
You could be tempted to pass parameters to the test invocation like `./test.bats param1 param2`.
|
||||
However, bats does not support passing parameters to files or tests.
|
||||
If you need such a feature, please let us know about your usecase.
|
||||
|
||||
As a workaround you can use environment variables to pass parameters.
|
||||
|
||||
Why can't my function return results via a variable when using `run`?
|
||||
---------------------------------------------------------------------
|
||||
|
||||
The `run` function executes its command in a subshell which means the changes to variables won't be available in the calling shell.
|
||||
|
||||
If you want to test these functions, you should call them without `run`.
|
||||
|
||||
`run` doesn't fail, although the same command without `run` does.
|
||||
-----------------------------------------------------------------
|
||||
|
||||
`run` is a wrapper that always succeeds. The wrapped command's exit code is stored in `$status` and the stdout/stderr in `$output`.
|
||||
If you want to fail the test, you should explicitly check `$status` or omit `run`. See also `when not to use run <writing-tests.html#when-not-to-use-run>`_.
|
||||
|
||||
`load` won't load my `.sh` files.
|
||||
---------------------------------
|
||||
|
||||
`load` is intended as an internal helper function that always loads `.bash` files (by appending this suffix).
|
||||
If you want to load an `.sh` file, you can simple `source` it.
|
||||
|
||||
I can't lint/shell-format my bats tests.
|
||||
----------------------------------------
|
||||
|
||||
Bats uses a custom syntax for annotating tests (`@test`) that is not bash compliant.
|
||||
Therefore, standard bash tooling won't be able to interact directly with `.bats` files.
|
||||
Shellcheck supports bats' native syntax as of version 0.7.
|
||||
|
||||
Additionally, there is bash compatible syntax for tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
function bash_compliant_function_name_as_test_name { # @test
|
||||
# your code
|
||||
}
|
||||
|
||||
|
||||
The output (stdout/err) from commands under `run` is not visible in failed tests.
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
By default, `run` only stores stdout/stderr in `$output` (and `${lines[@]}`).
|
||||
If you want to see this output, you either should use bat-assert's assertions or have to print `$output` before the check that fails.
|
||||
|
||||
My piped command does not work under run.
|
||||
-----------------------------------------
|
||||
|
||||
Be careful with using pipes and with `run`. While your mind model of `run` might wrap the whole command behind it, bash's parser won't
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
run echo foo | grep bar
|
||||
|
||||
Won't `run (echo foo | grep bar)` but will `(run echo foo) | grep bar`. If you need to incorporate pipes, you either should do
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
run bash -c 'echo foo | grep bar'
|
||||
|
||||
or use a function to wrap the pipe in:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
fun_with_pipes() {
|
||||
echo foo | grep bar
|
||||
}
|
||||
|
||||
run fun_with_pipes
|
||||
|
||||
`[[ ]]` (or `(( ))` did not fail my test
|
||||
----------------------------------------
|
||||
|
||||
The `set -e` handling of `[[ ]]` and `(( ))` changed in Bash 4.1. Older versions, like 3.2 on MacOS,
|
||||
don't abort the test when they fail, unless they are the last command before the (test) function returns,
|
||||
making their exit code the return code.
|
||||
|
||||
`[ ]` does not suffer from this, but is no replacement for all `[[ ]]` usecases. Appending ` || false` will work in all cases.
|
||||
|
||||
Background tasks prevent the test run from terminating when finished
|
||||
--------------------------------------------------------------------
|
||||
|
||||
When running a task in background, it will inherit the opened FDs of the process it was forked from.
|
||||
This means that the background task forked from a Bats test will hold the FD for the pipe to the formatter that prints to the terminal,
|
||||
thus keeping it open until the background task finished.
|
||||
Due to implementation internals of Bats and bash, this pipe might be held in multiple FDs which all have to be closed by the background task.
|
||||
|
||||
You can use `close_non_std_fds from `test/fixtures/bats/issue-205.bats` in the background job to close all FDs except stdin, stdout and stderr, thus solving the problem.
|
||||
More details about the issue can be found in [#205](https://github.com/bats-core/bats-core/issues/205#issuecomment-973572596).
|
||||
@@ -0,0 +1,18 @@
|
||||
Welcome to bats-core's documentation!
|
||||
=====================================
|
||||
|
||||
Versions before v1.2.1 are documented over `there <https://github.com/bats-core/bats-core/blob/master/docs/versions.md>`_.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
tutorial
|
||||
installation
|
||||
usage
|
||||
docker-usage
|
||||
writing-tests
|
||||
gotchas
|
||||
faq
|
||||
warnings/index
|
||||
support-matrix
|
||||
@@ -0,0 +1,138 @@
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Linux: Distribition Package Manager
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Following Linux distributions provide Bats via their package manager:
|
||||
|
||||
* Arch Linux: `extra/bats <https://archlinux.org/packages/extra/any/bats/>`__
|
||||
* Alpine Linux: `bats <https://pkgs.alpinelinux.org/package/edge/main/x86/bats>`__
|
||||
* Debian Linux: `shells/bats <https://packages.debian.org/search?keywords=bats>`__
|
||||
* Fedora Linux: `rpms/bats <https://src.fedoraproject.org/rpms/bats>`__
|
||||
* Gentoo Linux `dev-util/bats <https://packages.gentoo.org/packages/dev-util/bats>`__
|
||||
* OpenSUSE Linux: `bats <https://software.opensuse.org/package/bats>`__
|
||||
* Ubuntu Linux `shells/bats <https://packages.ubuntu.com/search?keywords=bats>`__
|
||||
|
||||
**Note**: Bats versions pre 1.0 are from sstephenson's original project.
|
||||
Consider using one of the other installation methods below to get the latest Bats release.
|
||||
The test matrix above only applies to the latest Bats version.
|
||||
|
||||
If your favorite distribution is not listed above,
|
||||
you can try one of the following package managers or install from source.
|
||||
|
||||
MacOS: Homebrew
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
On macOS, you can install `Homebrew <https://brew.sh/>`__ if you haven't already,
|
||||
then run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ brew install bats-core
|
||||
|
||||
Any OS: npm
|
||||
^^^^^^^^^^^
|
||||
|
||||
You can install the `Bats npm package <https://www.npmjs.com/package/bats>`__ via:
|
||||
|
||||
.. code-block::
|
||||
|
||||
# To install globally:
|
||||
$ npm install -g bats
|
||||
|
||||
# To install into your project and save it as one of the "devDependencies" in
|
||||
# your package.json:
|
||||
$ npm install --save-dev bats
|
||||
|
||||
Any OS: Installing Bats from source
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Check out a copy of the Bats repository. Then, either add the Bats ``bin``
|
||||
directory to your ``$PATH``\ , or run the provided ``install.sh`` command with the
|
||||
location to the prefix in which you want to install Bats. For example, to
|
||||
install Bats into ``/usr/local``\ ,
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ git clone https://github.com/bats-core/bats-core.git
|
||||
$ cd bats-core
|
||||
$ ./install.sh /usr/local
|
||||
|
||||
|
||||
**Note:** You may need to run ``install.sh`` with ``sudo`` if you do not have
|
||||
permission to write to the installation prefix.
|
||||
|
||||
Windows: Installing Bats from source via Git Bash
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Check out a copy of the Bats repository and install it to ``$HOME``. This
|
||||
will place the ``bats`` executable in ``$HOME/bin``\ , which should already be
|
||||
in ``$PATH``.
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ git clone https://github.com/bats-core/bats-core.git
|
||||
$ cd bats-core
|
||||
$ ./install.sh $HOME
|
||||
|
||||
|
||||
Running Bats in Docker
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There is an official image on the Docker Hub:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ docker run -it bats/bats:latest --version
|
||||
|
||||
|
||||
Building a Docker image
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Check out a copy of the Bats repository, then build a container image:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ git clone https://github.com/bats-core/bats-core.git
|
||||
$ cd bats-core
|
||||
$ docker build --tag bats/bats:latest .
|
||||
|
||||
|
||||
This creates a local Docker image called ``bats/bats:latest`` based on `Alpine
|
||||
Linux <https://github.com/gliderlabs/docker-alpine/blob/master/docs/usage.md>`__
|
||||
(to push to private registries, tag it with another organisation, e.g.
|
||||
``my-org/bats:latest``\ ).
|
||||
|
||||
To run Bats' internal test suite (which is in the container image at
|
||||
``/opt/bats/test``\ ):
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ docker run -it bats/bats:latest /opt/bats/test
|
||||
|
||||
|
||||
To run a test suite from a directory called ``test`` in the current directory of
|
||||
your local machine, mount in a volume and direct Bats to its path inside the
|
||||
container:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ docker run -it -v "${PWD}:/code" bats/bats:latest test
|
||||
|
||||
|
||||
..
|
||||
|
||||
``/code`` is the working directory of the Docker image. "${PWD}/test" is the
|
||||
location of the test directory on the local machine.
|
||||
|
||||
|
||||
This is a minimal Docker image. If more tools are required this can be used as a
|
||||
base image in a Dockerfile using ``FROM <Docker image>``. In the future there may
|
||||
be images based on Debian, and/or with more tools installed (\ ``curl`` and ``openssl``\ ,
|
||||
for example). If you require a specific configuration please search and +1 an
|
||||
issue or `raise a new issue <https://github.com/bats-core/bats-core/issues>`__.
|
||||
|
||||
Further usage examples are in
|
||||
`the wiki <https://github.com/bats-core/bats-core/wiki/Docker-Usage-Examples>`__.
|
||||
@@ -0,0 +1,2 @@
|
||||
sphinxcontrib-programoutput
|
||||
recommonmark
|
||||
@@ -0,0 +1,26 @@
|
||||
Support Matrix
|
||||
==============
|
||||
|
||||
Supported Bash versions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following is a list of Bash versions that are currently supported by Bats and verified through automated tests:
|
||||
|
||||
* 3.2.57(1) (macOS's highest bundled version)
|
||||
* 4.0, 4.1, 4.2, 4.3, 4.4
|
||||
* 5.0, 5.1, 5.2
|
||||
|
||||
Supported Operating systems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following Operating Systems are supported and tested automatically (CI) or manually during development:
|
||||
|
||||
* Linux: Alpine (CI), Alma 8 (CI), Arch Linux (manual), Ubuntu 20.04/22.04 (CI)
|
||||
* FreeBSD: 11 (CI)
|
||||
* macOS: 11 (CI), 12 (CI)
|
||||
* Windows: Server 2019 (CI), 10 (manual)
|
||||
|
||||
* Git for Windows Bash (MSYS2 based)
|
||||
* Windows Subsystem for Linux
|
||||
* MSYS2
|
||||
* Cygwin
|
||||
@@ -0,0 +1,661 @@
|
||||
Tutorial
|
||||
========
|
||||
|
||||
This tutorial is intended for beginners with bats and possibly bash.
|
||||
Make sure to also read the list of gotchas and the faq.
|
||||
|
||||
For this tutorial we are assuming you already have a project in a git repository and want to add tests.
|
||||
Ultimately they should run in the CI environment but will also be started locally during development.
|
||||
|
||||
..
|
||||
TODO: link to example repository?
|
||||
|
||||
Quick installation
|
||||
------------------
|
||||
|
||||
Since we already have an existing git repository, it is very easy to include bats and its libraries as submodules.
|
||||
We are aiming for following filesystem structure:
|
||||
|
||||
.. code-block::
|
||||
|
||||
src/
|
||||
project.sh
|
||||
...
|
||||
test/
|
||||
bats/ <- submodule
|
||||
test_helper/
|
||||
bats-support/ <- submodule
|
||||
bats-assert/ <- submodule
|
||||
test.bats
|
||||
...
|
||||
|
||||
So we start from the project root:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
git submodule add https://github.com/bats-core/bats-core.git test/bats
|
||||
git submodule add https://github.com/bats-core/bats-support.git test/test_helper/bats-support
|
||||
git submodule add https://github.com/bats-core/bats-assert.git test/test_helper/bats-assert
|
||||
|
||||
Your first test
|
||||
---------------
|
||||
|
||||
Now we want to add our first test.
|
||||
|
||||
In the tutorial repository, we want to build up our project in a TDD fashion.
|
||||
Thus, we start with an empty project and our first test is to just run our (nonexistent) shell script.
|
||||
|
||||
We start by creating a new test file `test/test.bats`
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "can run our script" {
|
||||
./project.sh
|
||||
}
|
||||
|
||||
and run it by
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✗ can run our script
|
||||
(in test file test/test.bats, line 2)
|
||||
`./project.sh' failed with status 127
|
||||
/tmp/bats-run-19605/bats.19627.src: line 2: ./project.sh: No such file or directory
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Okay, our test is red. Obviously, the project.sh doesn't exist, so we create the file `src/project.sh`:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
mkdir src/
|
||||
echo '#!/usr/bin/env bash' > src/project.sh
|
||||
chmod a+x src/project.sh
|
||||
|
||||
A new test run gives us
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✗ can run our script
|
||||
(in test file test/test.bats, line 2)
|
||||
`./project.sh' failed with status 127
|
||||
/tmp/bats-run-19605/bats.19627.src: line 2: ./project.sh: No such file or directory
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Oh, we still used the wrong path. No problem, we just need to use the correct path to `project.sh`.
|
||||
Since we're still in the same directory as when we started `bats`, we can simply do:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "can run our script" {
|
||||
./src/project.sh
|
||||
}
|
||||
|
||||
and get:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✓ can run our script
|
||||
|
||||
1 test, 0 failures
|
||||
|
||||
Yesss! But that victory feels shallow: What if somebody less competent than us starts bats from another directory?
|
||||
|
||||
Let's do some setup
|
||||
-------------------
|
||||
|
||||
The obvious solution to becoming independent of `$PWD` is using some fixed anchor point in the filesystem.
|
||||
We can use the path to the test file itself as an anchor and rely on the internal project structure.
|
||||
Since we are lazy people and want to treat our project's files as first class citizens in the executable world, we will also put them on the `$PATH`.
|
||||
Our new `test/test.bats` now looks like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
setup() {
|
||||
# get the containing directory of this file
|
||||
# use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0,
|
||||
# as those will point to the bats executable's location or the preprocessed file respectively
|
||||
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
|
||||
# make executables in src/ visible to PATH
|
||||
PATH="$DIR/../src:$PATH"
|
||||
}
|
||||
|
||||
@test "can run our script" {
|
||||
# notice the missing ./
|
||||
# As we added src/ to $PATH, we can omit the relative path to `src/project.sh`.
|
||||
project.sh
|
||||
}
|
||||
|
||||
still giving us:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✓ can run our script
|
||||
|
||||
1 test, 0 failures
|
||||
|
||||
It still works as expected. This is because the newly added `setup` function put the absolute path to `src/` onto `$PATH`.
|
||||
This setup function is automatically called before each test.
|
||||
Therefore, our test could execute `project.sh` directly, without using a (relative) path.
|
||||
|
||||
.. important::
|
||||
|
||||
The `setup` function will be called before each individual test in the file.
|
||||
Each file can only define one setup function for all tests in the file.
|
||||
However, the setup functions can differ between different files.
|
||||
|
||||
Dealing with output
|
||||
-------------------
|
||||
|
||||
Okay, we have a green test but our executable does not do anything useful.
|
||||
To keep things simple, let us start with an error message. Our new `src/project.sh` now reads:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "Welcome to our project!"
|
||||
|
||||
echo "NOT IMPLEMENTED!" >&2
|
||||
exit 1
|
||||
|
||||
And gives is this test output:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✗ can run our script
|
||||
(in test file test/test.bats, line 11)
|
||||
`project.sh' failed
|
||||
Welcome to our project!
|
||||
NOT IMPLEMENTED!
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Okay, our test failed, because we now exit with 1 instead of 0.
|
||||
Additionally, we see the stdout and stderr of the failing program.
|
||||
|
||||
Our goal now is to retarget our test and check that we get the welcome message.
|
||||
bats-assert gives us some help with this, so we should now load it (and its dependency bats-support),
|
||||
so we change `test/test.bats` to
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
setup() {
|
||||
load 'test_helper/bats-support/load'
|
||||
load 'test_helper/bats-assert/load'
|
||||
# ... the remaining setup is unchanged
|
||||
|
||||
# get the containing directory of this file
|
||||
# use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0,
|
||||
# as those will point to the bats executable's location or the preprocessed file respectively
|
||||
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
|
||||
# make executables in src/ visible to PATH
|
||||
PATH="$DIR/../src:$PATH"
|
||||
}
|
||||
|
||||
@test "can run our script" {
|
||||
run project.sh # notice `run`!
|
||||
assert_output 'Welcome to our project!'
|
||||
}
|
||||
|
||||
which gives us the following test output:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ LANG=C ./test/bats/bin/bats test/test.bats
|
||||
✗ can run our script
|
||||
(from function `assert_output' in file test/test_helper/bats-assert/src/assert_output.bash, line 194,
|
||||
in test file test/test.bats, line 14)
|
||||
`assert_output 'Welcome to our project!'' failed
|
||||
|
||||
-- output differs --
|
||||
expected (1 lines):
|
||||
Welcome to our project!
|
||||
actual (2 lines):
|
||||
Welcome to our project!
|
||||
NOT IMPLEMENTED!
|
||||
--
|
||||
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
The first change in this output is the failure description. We now fail on assert_output instead of the call itself.
|
||||
We prefixed our call to `project.sh` with `run`, which is a function provided by bats that executes the command it gets passed as parameters.
|
||||
Then, `run` sucks up the stdout and stderr of the command it ran and stores it in `$output`, stores the exit code in `$status` and returns 0.
|
||||
This means `run` never fails the test and won't generate any context/output in the log of a failed test on its own.
|
||||
|
||||
Marking the test as failed and printing context information is up to the consumers of `$status` and `$output`.
|
||||
`assert_output` is such a consumer, it compares `$output` to the parameter it got and tells us quite succinctly that it did not match in this case.
|
||||
|
||||
For our current test we don't care about any other output or the error message, so we want it gone.
|
||||
`grep` is always at our fingertips, so we tape together this ramshackle construct
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
run project.sh 2>&1 | grep Welcome
|
||||
|
||||
which gives us the following test result:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✗ can run our script
|
||||
(in test file test/test.bats, line 13)
|
||||
`run project.sh | grep Welcome' failed
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Huh, what is going on? Why does it fail the `run` line again?
|
||||
|
||||
This is a common mistake that can happen when our mind parses the file differently than the bash parser.
|
||||
`run` is just a function, so the pipe won't actually be forwarded into the function. Bash reads this as `(run project.sh) | grep Welcome`,
|
||||
instead of our intended `run (project.sh | grep Welcome)`.
|
||||
|
||||
Unfortunately, the latter is not valid bash syntax, so we have to work around it, e.g. by using a function:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
get_projectsh_welcome_message() {
|
||||
project.sh 2>&1 | grep Welcome
|
||||
}
|
||||
|
||||
@test "Check welcome message" {
|
||||
run get_projectsh_welcome_message
|
||||
assert_output 'Welcome to our project!'
|
||||
}
|
||||
|
||||
Now our test passes again but having to write a function each time we want only a partial match does not accommodate our laziness.
|
||||
Isn't there an app for that? Maybe we should look at the documentation?
|
||||
|
||||
Partial matching can be enabled with the --partial option (-p for short). When used, the assertion fails if the expected substring is not found in $output.
|
||||
|
||||
-- the documentation for `assert_output <https://github.com/bats-core/bats-assert#partial-matching>`_
|
||||
|
||||
Okay, so maybe we should try that:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "Check welcome message" {
|
||||
run project.sh
|
||||
assert_output --partial 'Welcome to our project!'
|
||||
}
|
||||
|
||||
Aaannnd ... the test stays green. Yay!
|
||||
|
||||
There are many other asserts and options but this is not the place for all of them.
|
||||
Skimming the documentation of `bats-assert <https://github.com/bats-core/bats-assert>`_ will give you a good idea what you can do.
|
||||
You should also have a look at the other helper libraries `here <https://github.com/bats-core>`_ like `bats-file <https://github.com/bats-core/bats-file>`_,
|
||||
to avoid reinventing the wheel.
|
||||
|
||||
|
||||
Cleaning up your mess
|
||||
---------------------
|
||||
|
||||
Often our setup or tests leave behind some artifacts that clutter our test environment.
|
||||
You can define a `teardown` function which will be called after each test, regardless whether it failed or not.
|
||||
|
||||
For example, we now want our project.sh to only show the welcome message on the first invocation.
|
||||
So we change our test to this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test "Show welcome message on first invocation" {
|
||||
run project.sh
|
||||
assert_output --partial 'Welcome to our project!'
|
||||
|
||||
run project.sh
|
||||
refute_output --partial 'Welcome to our project!'
|
||||
}
|
||||
|
||||
This test fails as expected:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✗ Show welcome message on first invocation
|
||||
(from function `refute_output' in file test/test_helper/bats-assert/src/refute_output.bash, line 189,
|
||||
in test file test/test.bats, line 17)
|
||||
`refute_output --partial 'Welcome to our project!'' failed
|
||||
|
||||
-- output should not contain substring --
|
||||
substring (1 lines):
|
||||
Welcome to our project!
|
||||
output (2 lines):
|
||||
Welcome to our project!
|
||||
NOT IMPLEMENTED!
|
||||
--
|
||||
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Now, to get the test green again, we want to store the information that we already ran in the file `/tmp/bats-tutorial-project-ran`,
|
||||
so our `src/project.sh` becomes:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
FIRST_RUN_FILE=/tmp/bats-tutorial-project-ran
|
||||
|
||||
if [[ ! -e "$FIRST_RUN_FILE" ]]; then
|
||||
echo "Welcome to our project!"
|
||||
touch "$FIRST_RUN_FILE"
|
||||
fi
|
||||
|
||||
echo "NOT IMPLEMENTED!" >&2
|
||||
exit 1
|
||||
|
||||
And our test says:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✓ Show welcome message on first invocation
|
||||
|
||||
1 test, 0 failures
|
||||
|
||||
Nice, we're done, or are we? Running the test again now gives:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
✗ Show welcome message on first invocation
|
||||
(from function `assert_output' in file test/test_helper/bats-assert/src/assert_output.bash, line 186,
|
||||
in test file test/test.bats, line 14)
|
||||
`assert_output --partial 'Welcome to our project!'' failed
|
||||
|
||||
-- output does not contain substring --
|
||||
substring : Welcome to our project!
|
||||
output : NOT IMPLEMENTED!
|
||||
--
|
||||
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Now the first assert failed, because of the leftover `$FIRST_RUN_FILE` from the last test run.
|
||||
|
||||
Luckily, bats offers the `teardown` function, which can take care of that, we add the following code to `test/test.bats`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
teardown() {
|
||||
rm -f /tmp/bats-tutorial-project-ran
|
||||
}
|
||||
|
||||
Now running the test again first give us the same error, as the teardown has not run yet.
|
||||
On the second try we get a clean `/tmp` folder again and our test passes consistently now.
|
||||
|
||||
It is worth noting that we could do this `rm` in the test code itself but it would get skipped on failures.
|
||||
|
||||
.. important::
|
||||
|
||||
A test ends at its first failure. None of the subsequent commands in this test will be executed.
|
||||
The `teardown` function runs after each individual test in a file, regardless of test success or failure.
|
||||
Similarly to `setup`, each `.bats` file can have its own `teardown` function which will be the same for all tests in the file.
|
||||
|
||||
Test what you can
|
||||
-----------------
|
||||
|
||||
Sometimes tests rely on the environment to provide infrastructure that is needed for the test.
|
||||
If not all test environments provide this infrastructure but we still want to test on them,
|
||||
it would be unhelpful to get errors on parts that are not testable.
|
||||
|
||||
Bats provides you with the `skip` command which can be used in `setup` and `test`.
|
||||
|
||||
.. tip::
|
||||
|
||||
You should `skip` as early as you know it does not make sense to continue.
|
||||
|
||||
In our example project we rewrite the welcome message test to `skip` instead of doing cleanup:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
teardown() {
|
||||
: # Look Ma! No cleanup!
|
||||
}
|
||||
|
||||
@test "Show welcome message on first invocation" {
|
||||
if [[ -e /tmp/bats-tutorial-project-ran ]]; then
|
||||
skip 'The FIRST_RUN_FILE already exists'
|
||||
fi
|
||||
|
||||
run project.sh
|
||||
assert_output --partial 'Welcome to our project!'
|
||||
|
||||
run project.sh
|
||||
refute_output --partial 'Welcome to our project!'
|
||||
}
|
||||
|
||||
The first test run still works due to the cleanup from the last round. However, our second run gives us:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/test.bats
|
||||
- Show welcome message on first invocation (skipped: The FIRST_RUN_FILE already exists)
|
||||
|
||||
1 test, 0 failures, 1 skipped
|
||||
|
||||
.. important::
|
||||
|
||||
Skipped tests won't fail a test suite and are counted separately.
|
||||
No test command after `skip` will be executed. If an error occurs before `skip`, the test will fail.
|
||||
An optional reason can be passed to `skip` and will be printed in the test output.
|
||||
|
||||
Setting up a multifile test suite
|
||||
---------------------------------
|
||||
|
||||
With a growing project, putting all tests into one file becomes unwieldy.
|
||||
For our example project, we will extract functionality into the additional file `src/helper.sh`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_is_first_run() {
|
||||
local FIRST_RUN_FILE=/tmp/bats-tutorial-project-ran
|
||||
if [[ ! -e "$FIRST_RUN_FILE" ]]; then
|
||||
touch "$FIRST_RUN_FILE"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
This allows for testing it separately in a new file `test/helper.bats`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
setup() {
|
||||
load 'test_helper/common-setup'
|
||||
_common_setup
|
||||
|
||||
source "$PROJECT_ROOT/src/helper.sh"
|
||||
}
|
||||
|
||||
teardown() {
|
||||
rm -f "$NON_EXISTANT_FIRST_RUN_FILE"
|
||||
rm -f "$EXISTING_FIRST_RUN_FILE"
|
||||
}
|
||||
|
||||
@test "Check first run" {
|
||||
NON_EXISTANT_FIRST_RUN_FILE=$(mktemp -u) # only create the name, not the file itself
|
||||
|
||||
assert _is_first_run
|
||||
refute _is_first_run
|
||||
refute _is_first_run
|
||||
|
||||
EXISTING_FIRST_RUN_FILE=$(mktemp)
|
||||
refute _is_first_run
|
||||
refute _is_first_run
|
||||
}
|
||||
|
||||
Since the setup function would have duplicated much of the other files', we split that out into the file `test/test_helper/common-setup.bash`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_common_setup() {
|
||||
load 'test_helper/bats-support/load'
|
||||
load 'test_helper/bats-assert/load'
|
||||
# get the containing directory of this file
|
||||
# use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0,
|
||||
# as those will point to the bats executable's location or the preprocessed file respectively
|
||||
PROJECT_ROOT="$( cd "$( dirname "$BATS_TEST_FILENAME" )/.." >/dev/null 2>&1 && pwd )"
|
||||
# make executables in src/ visible to PATH
|
||||
PATH="$PROJECT_ROOT/src:$PATH"
|
||||
}
|
||||
|
||||
with the following `setup` in `test/test.bats`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
setup() {
|
||||
load 'test_helper/common-setup'
|
||||
_common_setup
|
||||
}
|
||||
|
||||
Please note, that we gave our helper the extension `.bash`, which is automatically appended by `load`.
|
||||
|
||||
.. important::
|
||||
|
||||
`load` automatically tries to append `.bash` to its argument.
|
||||
|
||||
In our new `test/helper.bats` we can see, that loading `.sh` is simply done via `source`.
|
||||
|
||||
.. tip::
|
||||
|
||||
Avoid using `load` and `source` outside of any functions.
|
||||
If there is an error in the test file's "free code", the diagnostics are much worse than for code in `setup` or `@test`.
|
||||
|
||||
With the new changes in place, we can run our tests again. However, our previous run command does not include the new file.
|
||||
You could add the new file to the parameter list, e.g. by running `./test/bats/bin/bats test/*.bats`.
|
||||
However, bats also can handle directories:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/
|
||||
✓ Check first run
|
||||
- Show welcome message on first invocation (skipped: The FIRST_RUN_FILE already exists)
|
||||
|
||||
2 tests, 0 failures, 1 skipped
|
||||
|
||||
In this mode, bats will pick up all `.bats` files in the directory it was given. There is an additional `-r` switch that will recursively search for more `.bats` files.
|
||||
However, in our project layout this would pick up the test files of bats itself from `test/bats/test`. We don't have test subfolders anyways, so we can do without `-r`.
|
||||
|
||||
|
||||
Avoiding costly repeated setups
|
||||
-------------------------------
|
||||
|
||||
We already have seen the `setup` function in use, which is called before each test.
|
||||
Sometimes our setup is very costly, such as booting up a service just for testing.
|
||||
If we can reuse the same setup across multiple tests, we might want to do only one setup before all these tests.
|
||||
|
||||
This usecase is exactly what the `setup_file` function was created for.
|
||||
It can be defined per file and will run before all tests of the respective file.
|
||||
Similarly, we have `teardown_file`, which will run after all tests of the file, even when you abort a test run or a test failed.
|
||||
|
||||
As an example, we want to add an echo server capability to our project. First, we add the following `server.bats` to our suite:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
setup_file() {
|
||||
load 'test_helper/common-setup'
|
||||
_common_setup
|
||||
PORT=$(project.sh start-echo-server 2>&1 >/dev/null)
|
||||
export PORT
|
||||
}
|
||||
|
||||
@test "server is reachable" {
|
||||
nc -z localhost "$PORT"
|
||||
}
|
||||
|
||||
Which will obviously fail:
|
||||
|
||||
Note that `export PORT` to make it visible to the test!
|
||||
Running this gives us:
|
||||
|
||||
..
|
||||
TODO: Update this example with fixed test name reporting from setup_file? (instead of "✗ ")
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/server.bats
|
||||
✗
|
||||
(from function `setup_file' in test file test/server.bats, line 4)
|
||||
`PORT=$(project.sh start-echo-server >/dev/null 2>&1)' failed
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Now that we got our red test, we need to get it green again.
|
||||
Our new `project.sh` now ends with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
case $1 in
|
||||
start-echo-server)
|
||||
echo "Starting echo server"
|
||||
PORT=2000
|
||||
ncat -l $PORT -k -c 'xargs -n1 echo' 2>/dev/null & # don't keep open this script's stderr
|
||||
echo $! > /tmp/project-echo-server.pid
|
||||
echo "$PORT" >&2
|
||||
;;
|
||||
*)
|
||||
echo "NOT IMPLEMENTED!" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
and the tests now say
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ LANG=C ./test/bats/bin/bats test/server.bats
|
||||
✓ server is reachable
|
||||
|
||||
1 test, 0 failures
|
||||
|
||||
However, running this a second time gives:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./test/bats/bin/bats test/server.bats
|
||||
✗ server is reachable
|
||||
(in test file test/server.bats, line 14)
|
||||
`nc -z -w 2 localhost "$PORT"' failed
|
||||
2000
|
||||
Ncat: bind to :::2000: Address already in use. QUITTING.
|
||||
nc: port number invalid: 2000
|
||||
Ncat: bind to :::2000: Address already in use. QUITTING.
|
||||
|
||||
1 test, 1 failure
|
||||
|
||||
Obviously, we did not turn off our server after testing.
|
||||
This is a task for `teardown_file` in `server.bats`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
teardown_file() {
|
||||
project.sh stop-echo-server
|
||||
}
|
||||
|
||||
Our `project.sh` should also get the new command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
stop-echo-server)
|
||||
kill "$(< "/tmp/project-echo-server.pid")"
|
||||
rm /tmp/project-echo-server.pid
|
||||
;;
|
||||
|
||||
Now starting our tests again will overwrite the .pid file with the new instance's, so we have to do manual cleanup once.
|
||||
From now on, our test should clean up after itself.
|
||||
|
||||
.. note::
|
||||
|
||||
`teardown_file` will run regardless of tests failing or succeeding.
|
||||
@@ -0,0 +1,114 @@
|
||||
# Usage
|
||||
|
||||
Bats comes with two manual pages. After installation you can view them with `man
|
||||
1 bats` (usage manual) and `man 7 bats` (writing test files manual). Also, you
|
||||
can view the available command line options that Bats supports by calling Bats
|
||||
with the `-h` or `--help` options. These are the options that Bats currently
|
||||
supports:
|
||||
|
||||
``` eval_rst
|
||||
.. program-output:: ../../bin/bats --help
|
||||
```
|
||||
|
||||
To run your tests, invoke the `bats` interpreter with one or more paths to test
|
||||
files ending with the `.bats` extension, or paths to directories containing test
|
||||
files. (`bats` will only execute `.bats` files at the top level of each
|
||||
directory; it will not recurse unless you specify the `-r` flag.)
|
||||
|
||||
Test cases from each file are run sequentially and in isolation. If all the test
|
||||
cases pass, `bats` exits with a `0` status code. If there are any failures,
|
||||
`bats` exits with a `1` status code.
|
||||
|
||||
When you run Bats from a terminal, you'll see output as each test is performed,
|
||||
with a check-mark next to the test's name if it passes or an "X" if it fails.
|
||||
|
||||
```text
|
||||
$ bats addition.bats
|
||||
✓ addition using bc
|
||||
✓ addition using dc
|
||||
|
||||
2 tests, 0 failures
|
||||
```
|
||||
|
||||
If Bats is not connected to a terminal—in other words, if you run it from a
|
||||
continuous integration system, or redirect its output to a file—the results are
|
||||
displayed in human-readable, machine-parsable [TAP format][tap-format].
|
||||
|
||||
You can force TAP output from a terminal by invoking Bats with the `--formatter tap`
|
||||
option.
|
||||
|
||||
```text
|
||||
$ bats --formatter tap addition.bats
|
||||
1..2
|
||||
ok 1 addition using bc
|
||||
ok 2 addition using dc
|
||||
```
|
||||
|
||||
With `--formatter junit`, it is possible
|
||||
to output junit-compatible report files.
|
||||
|
||||
```text
|
||||
$ bats --formatter junit addition.bats
|
||||
1..2
|
||||
ok 1 addition using bc
|
||||
ok 2 addition using dc
|
||||
```
|
||||
|
||||
If you have your own formatter, you can use an absolute path to the executable
|
||||
to use it:
|
||||
|
||||
```bash
|
||||
$ bats --formatter /absolute/path/to/my-formatter addition.bats
|
||||
addition using bc WORKED
|
||||
addition using dc FAILED
|
||||
```
|
||||
|
||||
You can also generate test report files via `--report-formatter` which accepts
|
||||
the same options as `--formatter`. By default, the file is stored in the current
|
||||
workdir. However, it may be placed elsewhere by specifying the `--output` flag.
|
||||
|
||||
```text
|
||||
$ bats --report-formatter junit addition.bats --output /tmp
|
||||
1..2
|
||||
ok 1 addition using bc
|
||||
ok 2 addition using dc
|
||||
|
||||
$ cat /tmp/report.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites time="0.073">
|
||||
<testsuite name="addition.bats" tests="2" failures="0" errors="0" skipped="0">
|
||||
<testcase classname="addition.bats" name="addition using bc" time="0.034" />
|
||||
<testcase classname="addition.bats" name="addition using dc" time="0.039" />
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
```
|
||||
|
||||
## Parallel Execution
|
||||
|
||||
``` eval_rst
|
||||
.. versionadded:: 1.0.0
|
||||
```
|
||||
|
||||
By default, Bats will execute your tests serially. However, Bats supports
|
||||
parallel execution of tests (provided you have [GNU parallel][gnu-parallel] or
|
||||
a compatible replacement installed) using the `--jobs` parameter. This can
|
||||
result in your tests completing faster (depending on your tests and the testing
|
||||
hardware).
|
||||
|
||||
Ordering of parallelised tests is not guaranteed, so this mode may break suites
|
||||
with dependencies between tests (or tests that write to shared locations). When
|
||||
enabling `--jobs` for the first time be sure to re-run bats multiple times to
|
||||
identify any inter-test dependencies or non-deterministic test behaviour.
|
||||
|
||||
When parallelizing, the results of a file only become visible after it has been finished.
|
||||
You can use `--no-parallelize-across-files` to get immediate output at the cost of reduced
|
||||
overall parallelity, as parallelization will only happen within files and files will be run
|
||||
sequentially.
|
||||
|
||||
If you have files where tests within the file would interfere with each other, you can use
|
||||
`--no-parallelize-within-files` to disable parallelization within all files.
|
||||
If you want more fine-grained control, you can `export BATS_NO_PARALLELIZE_WITHIN_FILE=true` in `setup_file()`
|
||||
or outside any function to disable parallelization only within the containing file.
|
||||
|
||||
[tap-format]: https://testanything.org
|
||||
[gnu-parallel]: https://www.gnu.org/software/parallel/
|
||||
@@ -0,0 +1,17 @@
|
||||
BW01: `run`'s command `<command>` exited with code 127, indicating 'Command not found'. Use run's return code checks, e.g. `run -127`, to fix this message.
|
||||
===========================================================================================================================================================
|
||||
|
||||
Due to `run`'s default behavior of always succeeding, errors in the command string can remain hidden from the user, e.g.[here](https://github.com/bats-core/bats-core/issues/578).
|
||||
As a proxy for this problem, the return code is checked for value 127 ("Command not found").
|
||||
|
||||
How to fix
|
||||
----------
|
||||
|
||||
If your command should actually return code 127, then you can simply use `run -127 <your command>` to state your intent and the message will go away.
|
||||
|
||||
If your command should not return 127, you should fix the problem with the command.
|
||||
Take a careful look at the command string in the warning message, to see if it contains code that you did not intend to run.
|
||||
|
||||
If your command should sometimes return 127, but never 0, you can use `run ! <your command>`.
|
||||
|
||||
If your command can sometimes return 127 and sometimes 0, the please submit an issue.
|
||||
@@ -0,0 +1,46 @@
|
||||
BW02: <feature> requires at least BATS_VERSION=<version>. Use `bats_require_minimum_version <version>` to fix this message.
|
||||
===========================================================================================================================
|
||||
|
||||
Using a feature that is only available starting with a certain version can be a problem when your tests also run on older versions of Bats.
|
||||
In most cases, running this code in older versions will generate an error due to a missing command.
|
||||
However, in cases like `run`'s where old version simply take all parameters as command to execute, the failure can be silent.
|
||||
|
||||
How to fix BW02
|
||||
---------------
|
||||
|
||||
When you encounter this warning, you can simply guard your code with `bats_require_minimum_version <version>` as the message says.
|
||||
For example, consider the following code:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test test {
|
||||
bats_require_minimum_version 1.5.0
|
||||
# pre 1.5.0 the flag --separate-stderr would be interpreted as command to run
|
||||
run --separate-stderr some-command
|
||||
[ $output = "blablabla" ]
|
||||
}
|
||||
|
||||
|
||||
The call to `bats_require_minimum_version` can be put anywhere before the warning generating command, even in `setup`, `setup_file`, or even outside any function.
|
||||
This can be used to give fine control over the version dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@test test {
|
||||
bats_require_minimum_version 1.5.0
|
||||
# pre 1.5.0 the flag --separate-stderr would be interpreted as command to run
|
||||
run --separate-stderr some-command
|
||||
[ $output = "blablabla" ]
|
||||
}
|
||||
|
||||
@test test2 {
|
||||
run some-other-command # no problem executing on earlier version
|
||||
}
|
||||
|
||||
|
||||
If the above code is executed on a system with a `BATS_VERSION` pre 1.5.0, the first test will fail on `bats_require_minimum_version 1.5.0`.
|
||||
|
||||
Instances:
|
||||
----------
|
||||
|
||||
- run's non command parameters like `--keep-empty-lines` are only available since 1.5.0
|
||||
@@ -0,0 +1,15 @@
|
||||
BW03: `setup_suite` is visible to test file '<path>', but was not executed. It belongs into 'setup_suite.bash' to be picked up automatically.
|
||||
=============================================================================================================================================
|
||||
|
||||
In contrast to the other setup functions, `setup_suite` must not be defined in `*.bats` files but in `setup_suite.bash`.
|
||||
When a file is executed and sees `setup_suite` defined but not run before the tests, this warning will be printed.
|
||||
|
||||
How to fix BW03
|
||||
---------------
|
||||
|
||||
The fix depends on your actual intention. There are basically two cases:
|
||||
|
||||
1. You want a setup before all tests and accidentally put `setup_suite` into a test file instead of `setup_suite.bash`.
|
||||
Simply move `setup_suite` (and `teardown_suite`!) into `setup_suite.bash`.
|
||||
2. You did not mean to run a setup before any test but need to defined a function named `setup_suite` in your test file.
|
||||
In this case, you can silence this warning by assigning `BATS_SETUP_SUITE_COMPLETED='suppress BW03'`.
|
||||
@@ -0,0 +1,28 @@
|
||||
Warnings
|
||||
========
|
||||
|
||||
Starting with version 1.7.0 Bats shows warnings about issues it found during the test run.
|
||||
They are printed on stderr after all other output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
BW01.bats
|
||||
✓ Trigger BW01
|
||||
|
||||
1 test, 0 failures
|
||||
|
||||
|
||||
The following warnings were encountered during tests:
|
||||
BW01: `run`'s command `=0 actually-intended-command with some args` exited with code 127, indicating 'Command not found'. Use run's return code checks, e.g. `run -127`, to fix this message.
|
||||
(from function `run' in file lib/bats-core/test_functions.bash, line 299,
|
||||
in test file test/fixtures/warnings/BW01.bats, line 3)
|
||||
|
||||
A warning will not make a successful run fail but should be investigated and taken seriously, since it hints at a possible error.
|
||||
|
||||
Currently, Bats emits the following warnings:
|
||||
|
||||
.. toctree::
|
||||
|
||||
BW01
|
||||
BW02
|
||||
BW03
|
||||
@@ -0,0 +1,614 @@
|
||||
# Writing tests
|
||||
|
||||
Each Bats test file is evaluated _n+1_ times, where _n_ is the number of
|
||||
test cases in the file. The first run counts the number of test cases,
|
||||
then iterates over the test cases and executes each one in its own
|
||||
process.
|
||||
|
||||
For more details about how Bats evaluates test files, see [Bats Evaluation
|
||||
Process][bats-eval] on the wiki.
|
||||
|
||||
For sample test files, see [examples](https://github.com/bats-core/bats-core/tree/master/docs/examples).
|
||||
|
||||
[bats-eval]: https://github.com/bats-core/bats-core/wiki/Bats-Evaluation-Process
|
||||
|
||||
## Tagging tests
|
||||
|
||||
Starting with version 1.8.0, Bats comes with a tagging system that allows users
|
||||
to categorize their tests and filter according to those categories.
|
||||
|
||||
Each test has a list of tags attached to it. Without specification, this list is empty.
|
||||
Tags can be defined in two ways. The first being `# bats test_tags=`:
|
||||
|
||||
```bash
|
||||
# bats test_tags=tag:1, tag:2, tag:3
|
||||
@test "first test" {
|
||||
# ...
|
||||
}
|
||||
|
||||
@test "second test" {
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
These tags (`tag:1`, `tag:2`, `tag:3`) will be attached to the test `first test`.
|
||||
The second test will have no tags attached. Values defined in the `# bats test_tags=`
|
||||
directive will be assigned to the next `@test` that is being encountered in the
|
||||
file and forgotten after that. Only the value of the last `# bats test_tags=` directive
|
||||
before a given test will be used.
|
||||
|
||||
Sometimes, we want to give all tests in a file a set of the same tags. This can
|
||||
be achieved via `# bats file_tags=`. They will be added to all tests in the file
|
||||
after that directive. An additional `# bats file_tags=` directive will override
|
||||
the previously defined values:
|
||||
|
||||
```bash
|
||||
@test "Zeroth test" {
|
||||
# will have no tags
|
||||
}
|
||||
|
||||
# bats file_tags=a:b
|
||||
# bats test_tags=c:d
|
||||
|
||||
@test "First test" {
|
||||
# will be tagged a:b, c:d
|
||||
}
|
||||
|
||||
# bats file_tags=
|
||||
|
||||
@test "Second test" {
|
||||
# will have no tags
|
||||
}
|
||||
```
|
||||
|
||||
Tags are case sensitive and must only consist of alphanumeric characters and `_`,
|
||||
`-`, or `:`. They must not contain whitespaces!
|
||||
The colon is intended as a separator for (recursive) namespacing.
|
||||
|
||||
Tag lists must be separated by commas and are allowed to contain whitespace.
|
||||
They must not contain empty tags like `test_tags=,b` (first tag is empty),
|
||||
`test_tags=a,,c`, `test_tags=a, ,c` (second tag is only whitespace/empty),
|
||||
`test_tags=a,b,` (third tag is empty).
|
||||
|
||||
Every tag starting with `bats:` (case insensitive!) is reserved for Bats'
|
||||
internal use.
|
||||
|
||||
### Special tags
|
||||
|
||||
#### Focusing on tests with `bats:focus` tag
|
||||
|
||||
If a test with the tag `bats:focus` is encountered in a test suite,
|
||||
all other tests will be filtered out and only those tagged with this tag will be executed.
|
||||
|
||||
In focus mode, the exit code of successful runs will be overridden to 1 to prevent CI from silently running on a subset of tests due to an accidentally committed `bats:focus` tag.
|
||||
Should you require the true exit code, e.g. for a `git bisect` operation, you can disable this behavior by setting
|
||||
`BATS_NO_FAIL_FOCUS_RUN=1` when running `bats`, but make sure not to commit this to CI!
|
||||
|
||||
### Filtering execution
|
||||
|
||||
Tags can be used for more finegrained filtering of which tests to run via `--filter-tags`.
|
||||
This accepts a comma separated list of tags. Only tests that match all of these
|
||||
tags will be executed. For example, `bats --filter-tags a,b,c` will pick up tests
|
||||
with tags `a,b,c`, but not tests that miss one or more of those tags.
|
||||
|
||||
Additionally, you can specify negative tags via `bats --filter-tags a,!b,c`,
|
||||
which now won't match tests with tags `a,b,c`, due to the `b`, but will select `a,c`.
|
||||
To put it more formally, `--filter-tags` is a boolean conjunction.
|
||||
|
||||
To allow for more complex queries, you can specify multiple `--filter-tags`.
|
||||
A test will be executed, if it matches at least one of them.
|
||||
This means multiple `--filter-tags` form a boolean disjunction.
|
||||
|
||||
A query of `--filter-tags a,!b --filter-tags b,c` can be translated to:
|
||||
Execute only tests that (have tag a, but not tag b) or (have tag b and c).
|
||||
|
||||
An empty tag list matches tests without tags.
|
||||
|
||||
## Comment syntax
|
||||
|
||||
External tools (like `shellcheck`, `shfmt`, and various IDE's) may not support
|
||||
the standard `.bats` syntax. Because of this, we provide a valid `bash`
|
||||
alternative:
|
||||
|
||||
```bash
|
||||
function invoking_foo_without_arguments_prints_usage { #@test
|
||||
run foo
|
||||
[ "$status" -eq 1 ]
|
||||
[ "${lines[0]}" = "usage: foo <filename>" ]
|
||||
}
|
||||
```
|
||||
|
||||
When using this syntax, the function name will be the title in the result output
|
||||
and the value checked when using `--filter`.
|
||||
|
||||
## `run`: Test other commands
|
||||
|
||||
Many Bats tests need to run a command and then make assertions about its exit
|
||||
status and output. Bats includes a `run` helper that invokes its arguments as a
|
||||
command, saves the exit status and output into special global variables, and
|
||||
then returns with a `0` status code so you can continue to make assertions in
|
||||
your test case.
|
||||
|
||||
For example, let's say you're testing that the `foo` command, when passed a
|
||||
nonexistent filename, exits with a `1` status code and prints an error message.
|
||||
|
||||
```bash
|
||||
@test "invoking foo with a nonexistent file prints an error" {
|
||||
run foo nonexistent_filename
|
||||
[ "$status" -eq 1 ]
|
||||
[ "$output" = "foo: no such file 'nonexistent_filename'" ]
|
||||
[ "$BATS_RUN_COMMAND" = "foo nonexistent_filename" ]
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The `$status` variable contains the status code of the command, the
|
||||
`$output` variable contains the combined contents of the command's standard
|
||||
output and standard error streams, and the `$BATS_RUN_COMMAND` string contains the
|
||||
command and command arguments passed to `run` for execution.
|
||||
|
||||
If invoked with one of the following as the first argument, `run`
|
||||
will perform an implicit check on the exit status of the invoked command:
|
||||
|
||||
```pre
|
||||
-N expect exit status N (0-255), fail if otherwise
|
||||
! expect nonzero exit status (1-255), fail if command succeeds
|
||||
```
|
||||
|
||||
We can then write the above more elegantly as:
|
||||
|
||||
```bash
|
||||
@test "invoking foo with a nonexistent file prints an error" {
|
||||
run -1 foo nonexistent_filename
|
||||
[ "$output" = "foo: no such file 'nonexistent_filename'" ]
|
||||
}
|
||||
```
|
||||
|
||||
A third special variable, the `$lines` array, is available for easily accessing
|
||||
individual lines of output. For example, if you want to test that invoking `foo`
|
||||
without any arguments prints usage information on the first line:
|
||||
|
||||
```bash
|
||||
@test "invoking foo without arguments prints usage" {
|
||||
run -1 foo
|
||||
[ "${lines[0]}" = "usage: foo <filename>" ]
|
||||
}
|
||||
```
|
||||
|
||||
__Note:__ The `run` helper executes its argument(s) in a subshell, so if
|
||||
writing tests against environmental side-effects like a variable's value
|
||||
being changed, these changes will not persist after `run` completes.
|
||||
|
||||
By default `run` leaves out empty lines in `${lines[@]}`. Use
|
||||
`run --keep-empty-lines` to retain them.
|
||||
|
||||
Additionally, you can use `--separate-stderr` to split stdout and stderr
|
||||
into `$output`/`$stderr` and `${lines[@]}`/`${stderr_lines[@]}`.
|
||||
|
||||
All additional parameters to run should come before the command.
|
||||
If you want to run a command that starts with `-`, prefix it with `--` to
|
||||
prevent `run` from parsing it as an option.
|
||||
|
||||
### When not to use `run`
|
||||
|
||||
In case you only need to check the command succeeded, it is better to not use `run`, since the following code
|
||||
|
||||
```bash
|
||||
run -0 command args ...
|
||||
```
|
||||
|
||||
is equivalent to
|
||||
|
||||
```bash
|
||||
command args ...
|
||||
```
|
||||
|
||||
(because bats sets `set -e` for all tests).
|
||||
|
||||
__Note__: In contrast to the above, testing that a command failed is best done via
|
||||
|
||||
```bash
|
||||
run ! command args ...
|
||||
```
|
||||
|
||||
because
|
||||
|
||||
```bash
|
||||
! command args ...
|
||||
```
|
||||
|
||||
will only fail the test if it is the last command and thereby determines the test function's exit code.
|
||||
This is due to Bash's decision to (counterintuitively?) not trigger `set -e` on `!` commands.
|
||||
(See also [the associated gotcha](https://bats-core.readthedocs.io/en/stable/gotchas.html#my-negated-statement-e-g-true-does-not-fail-the-test-even-when-it-should))
|
||||
|
||||
|
||||
### `run` and pipes
|
||||
|
||||
Don't fool yourself with pipes when using `run`. Bash parses the pipe outside of `run`, not internal to its command. Take this example:
|
||||
|
||||
```bash
|
||||
run command args ... | jq -e '.limit == 42'
|
||||
```
|
||||
|
||||
Here, `jq` receives no input (which is captured by `run`),
|
||||
executes no filters, and always succeeds, so the test does not work as
|
||||
expected.
|
||||
|
||||
Instead use a Bash subshell:
|
||||
|
||||
```bash
|
||||
run bash -c "command args ... | jq -e '.limit == 42'"
|
||||
```
|
||||
|
||||
This subshell is a fresh Bash environment, and will only inherit variables
|
||||
and functions that are exported into it.
|
||||
|
||||
```bash
|
||||
limit() { jq -e '.limit == 42'; }
|
||||
export -f limit
|
||||
run bash -c "command args ... | limit"
|
||||
```
|
||||
|
||||
|
||||
## `load`: Share common code
|
||||
|
||||
You may want to share common code across multiple test files. Bats
|
||||
includes a convenient `load` command for sourcing a Bash source files
|
||||
relative to the current test file and from absolute paths.
|
||||
|
||||
For example, if you have a Bats test in `test/foo.bats`, the command
|
||||
|
||||
```bash
|
||||
load test_helper.bash
|
||||
```
|
||||
|
||||
will source the script `test/test_helper.bash` in your test file (limitations
|
||||
apply, see below). This can be useful for sharing functions to set up your
|
||||
environment or load fixtures. `load` delegates to Bash's `source` command after
|
||||
resolving paths.
|
||||
|
||||
If `load` encounters errors - e.g. because the targeted source file
|
||||
errored - it will print a message with the failing library and Bats
|
||||
exits.
|
||||
|
||||
To allow to use `load` in conditions `bats_load_safe` has been added.
|
||||
`bats_load_safe` prints a message and returns `1` if a source file cannot be
|
||||
loaded instead of exiting Bats.
|
||||
Aside from that `bats_load_safe` acts exactly like `load`.
|
||||
|
||||
As pointed out by @iatrou in https://www.tldp.org/LDP/abs/html/declareref.html,
|
||||
using the `declare` builtin restricts scope of a variable. Thus, since actual
|
||||
`source`-ing is performed in context of the `load` function, `declare`d symbols
|
||||
will _not_ be made available to callers of `load`.
|
||||
|
||||
### `load` argument resolution
|
||||
|
||||
`load` supports the following arguments:
|
||||
|
||||
- absolute paths
|
||||
- relative paths (to the current test file)
|
||||
|
||||
> For backwards compatibility `load` first searches for a file ending in
|
||||
> `.bash` (e.g. `load test_helper` searches for `test_helper.bash` before
|
||||
> it looks for `test_helper`). This behaviour is deprecated and subject to
|
||||
> change, please use exact filenames instead.
|
||||
|
||||
If `argument` is an absolute path `load` tries to determine the load
|
||||
path directly.
|
||||
|
||||
If `argument` is a relative path or a name `load` looks for a matching
|
||||
path in the directory of the current test.
|
||||
|
||||
## `bats_load_library`: Load system wide libraries
|
||||
|
||||
Some libraries are installed on the system, e.g. by `npm` or `brew`.
|
||||
These should not be `load`ed, as their path depends on the installation method.
|
||||
Instead, one should use `bats_load_library` together with setting
|
||||
`BATS_LIB_PATH`, a `PATH`-like colon-delimited variable.
|
||||
|
||||
`bats_load_library` has two modes of resolving requests:
|
||||
|
||||
1. by relative path from the `BATS_LIB_PATH` to a file in the library
|
||||
2. by library name, expecting libraries to have a `load.bash` entrypoint
|
||||
|
||||
For example if your `BATS_LIB_PATH` is set to
|
||||
`~/.bats/libs:/usr/lib/bats`, then `bats_load_library test_helper`
|
||||
would look for existing files with the following paths:
|
||||
|
||||
- `~/.bats/libs/test_helper`
|
||||
- `~/.bats/libs/test_helper/load.bash`
|
||||
- `/usr/lib/bats/test_helper`
|
||||
- `/usr/lib/bats/test_helper/load.bash`
|
||||
|
||||
The first existing file in this list will be sourced.
|
||||
|
||||
If you want to load only part of a library or the entry point is not named `load.bash`,
|
||||
you have to include it in the argument:
|
||||
`bats_load_library library_name/file_to_load` will try
|
||||
|
||||
- `~/.bats/libs/library_name/file_to_load`
|
||||
- `~/.bats/libs/library_name/file_to_load/load.bash`
|
||||
- `/usr/lib/bats/library_name/file_to_load`
|
||||
- `/usr/lib/bats/library_name/file_to_load/load.bash`
|
||||
|
||||
Apart from the changed lookup rules, `bats_load_library` behaves like `load`.
|
||||
|
||||
__Note:__ As seen above `load.bash` is the entry point for libraries and
|
||||
meant to load more files from its directory or other libraries.
|
||||
|
||||
__Note:__ Obviously, the actual `BATS_LIB_PATH` is highly dependent on the environment.
|
||||
To maintain a uniform location across systems, (distribution) package maintainers
|
||||
are encouraged to use `/usr/lib/bats/` as the install path for libraries where possible.
|
||||
However, if the package manager has another preferred location, like `npm` or `brew`,
|
||||
you should use this instead.
|
||||
|
||||
## `skip`: Easily skip tests
|
||||
|
||||
Tests can be skipped by using the `skip` command at the point in a test you wish
|
||||
to skip.
|
||||
|
||||
```bash
|
||||
@test "A test I don't want to execute for now" {
|
||||
skip
|
||||
run foo
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
```
|
||||
|
||||
Optionally, you may include a reason for skipping:
|
||||
|
||||
```bash
|
||||
@test "A test I don't want to execute for now" {
|
||||
skip "This command will return zero soon, but not now"
|
||||
run foo
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
```
|
||||
|
||||
Or you can skip conditionally:
|
||||
|
||||
```bash
|
||||
@test "A test which should run" {
|
||||
if [ foo != bar ]; then
|
||||
skip "foo isn't bar"
|
||||
fi
|
||||
|
||||
run foo
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
```
|
||||
|
||||
__Note:__ `setup` and `teardown` hooks still run for skipped tests.
|
||||
|
||||
## `setup` and `teardown`: Pre- and post-test hooks
|
||||
|
||||
You can define special `setup` and `teardown` functions, which run before and
|
||||
after each test case, respectively. Use these to load fixtures, set up your
|
||||
environment, and clean up when you're done.
|
||||
|
||||
You can also define `setup_file` and `teardown_file`, which will run once before
|
||||
the first test's `setup` and after the last test's `teardown` for the containing
|
||||
file. Variables that are exported in `setup_file` will be visible to all following
|
||||
functions (`setup`, the test itself, `teardown`, `teardown_file`).
|
||||
|
||||
Similarly, there is `setup_suite` (and `teardown_suite`) which run once before (and
|
||||
after) all tests of the test run.
|
||||
|
||||
__Note:__ As `setup_suite` and `teardown_suite` are intended for all files in a suite,
|
||||
they must be defined in a separate `setup_suite.bash` file. Automatic discovery works
|
||||
by searching for `setup_suite.bash` in the folder of the first `*.bats` file of the suite.
|
||||
If this automatism does not work for your usecase, you can work around by specifying
|
||||
`--setup-suite-file` on the `bats` command. If you have a `setup_suite.bash`, it must define
|
||||
`setup_suite`! However, defining `teardown_suite` is optional.
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<details>
|
||||
<summary>Example of setup/{,_file,_suite} (and teardown{,_file,_suite}) call order</summary>
|
||||
For example the following call order would result from two files (file 1 with
|
||||
tests 1 and 2, and file 2 with test3) with a corresponding `setup_suite.bash` file being tested:
|
||||
|
||||
```text
|
||||
setup_suite # from setup_suite.bash
|
||||
setup_file # from file 1, on entering file 1
|
||||
setup
|
||||
test1
|
||||
teardown
|
||||
setup
|
||||
test2
|
||||
teardown
|
||||
teardown_file # from file 1, on leaving file 1
|
||||
setup_file # from file 2, on enter file 2
|
||||
setup
|
||||
test3
|
||||
teardown
|
||||
teardown_file # from file 2, on leaving file 2
|
||||
teardown_suite # from setup_suite.bash
|
||||
```
|
||||
|
||||
</details>
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
Note that the `teardown*` functions can fail a test, if their return code is nonzero.
|
||||
This means, using `return 1` or having the last command in teardown fail, will
|
||||
fail the teardown. Unlike `@test`, failing commands within `teardown` won't
|
||||
trigger failure as ERREXIT is disabled.
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<details>
|
||||
<summary>Example of different teardown failure modes</summary>
|
||||
|
||||
```bash
|
||||
teardown() {
|
||||
false # this will fail the test, as it determines the return code
|
||||
}
|
||||
|
||||
teardown() {
|
||||
false # this won't fail the test ...
|
||||
echo some more code # ... and this will be executed too!
|
||||
}
|
||||
|
||||
teardown() {
|
||||
return 1 # this will fail the test, but the rest won't be executed
|
||||
echo some more code
|
||||
}
|
||||
|
||||
teardown() {
|
||||
if true; then
|
||||
false # this will also fail the test, as it is the last command in this function
|
||||
else
|
||||
true
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
## `bats_require_minimum_version <Bats version number>`
|
||||
|
||||
Added in [v1.7.0](https://github.com/bats-core/bats-core/releases/tag/v1.7.0)
|
||||
|
||||
Code for newer versions of Bats can be incompatible with older versions.
|
||||
In the best case this will lead to an error message and a failed test suite.
|
||||
In the worst case, the tests will pass erroneously, potentially masking a failure.
|
||||
|
||||
Use `bats_require_minimum_version <Bats version number>` to avoid this.
|
||||
It communicates in a concise manner, that you intend the following code to be run
|
||||
under the given Bats version or higher.
|
||||
|
||||
Additionally, this function will communicate the current Bats version floor to
|
||||
subsequent code, allowing e.g. Bats' internal warning to give more informed warnings.
|
||||
|
||||
__Note__: By default, calling `bats_require_minimum_version` with versions before
|
||||
Bats 1.7.0 will fail regardless of the required version as the function is not
|
||||
available. However, you can use the
|
||||
[bats-backports plugin](https://github.com/bats-core/bats-backports) to make
|
||||
your code usable with older versions, e.g. during migration while your CI system
|
||||
is not yet upgraded.
|
||||
|
||||
## Code outside of test cases
|
||||
|
||||
In general you should avoid code outside tests, because each test file will be evaluated many times.
|
||||
However, there are situations in which this might be useful, e.g. when you want to check for dependencies
|
||||
and fail immediately if they're not present.
|
||||
|
||||
In general, you should avoid printing outside of `@test`, `setup*` or `teardown*` functions.
|
||||
Have a look at section [printing to the terminal](#printing-to-the-terminal) for more details.
|
||||
## File descriptor 3 (read this if Bats hangs)
|
||||
|
||||
Bats makes a separation between output from the code under test and output that
|
||||
forms the TAP stream (which is produced by Bats internals). This is done in
|
||||
order to produce TAP-compliant output. In the [Printing to the
|
||||
terminal](#printing-to-the-terminal) section, there are details on how to use
|
||||
file descriptor 3 to print custom text properly.
|
||||
|
||||
A side effect of using file descriptor 3 is that, under some circumstances, it
|
||||
can cause Bats to block and execution to seem dead without reason. This can
|
||||
happen if a child process is spawned in the background from a test. In this
|
||||
case, the child process will inherit file descriptor 3. Bats, as the parent
|
||||
process, will wait for the file descriptor to be closed by the child process
|
||||
before continuing execution. If the child process takes a lot of time to
|
||||
complete (eg if the child process is a `sleep 100` command or a background
|
||||
service that will run indefinitely), Bats will be similarly blocked for the same
|
||||
amount of time.
|
||||
|
||||
**To prevent this from happening, close FD 3 explicitly when running any command
|
||||
that may launch long-running child processes**, e.g. `command_name 3>&-` .
|
||||
|
||||
## Printing to the terminal
|
||||
|
||||
Bats produces output compliant with [version 12 of the TAP protocol](https://testanything.org/tap-specification.html). The
|
||||
produced TAP stream is by default piped to a pretty formatter for human
|
||||
consumption, but if Bats is called with the `-t` flag, then the TAP stream is
|
||||
directly printed to the console.
|
||||
|
||||
This has implications if you try to print custom text to the terminal. As
|
||||
mentioned in [File descriptor 3](#file-descriptor-3-read-this-if-bats-hangs),
|
||||
bats provides a special file descriptor, `&3`, that you should use to print
|
||||
your custom text. Here are some detailed guidelines to refer to:
|
||||
|
||||
- Printing **from within a test function**:
|
||||
- First you should consider if you want the text to be always visible or only
|
||||
when the test fails. Text that is output directly to stdout or stderr (file
|
||||
descriptor 1 or 2), ie `echo 'text'` is considered part of the test function
|
||||
output and is printed only on test failures for diagnostic purposes,
|
||||
regardless of the formatter used (TAP or pretty).
|
||||
- To have text printed unconditionally from within a test function you need to
|
||||
redirect the output to file descriptor 3, eg `echo 'text' >&3`. This output
|
||||
will become part of the TAP stream. You are encouraged to prepend text printed
|
||||
this way with a hash (eg `echo '# text' >&3`) in order to produce 100% TAP compliant
|
||||
output. Otherwise, depending on the 3rd-party tools you use to analyze the
|
||||
TAP stream, you can encounter unexpected behavior or errors.
|
||||
|
||||
- Printing **from within the `setup*` or `teardown*` functions**: The same hold
|
||||
true as for printing with test functions.
|
||||
|
||||
- Printing **outside test or `setup*`/`teardown*` functions**:
|
||||
- You should avoid printing in free code: Due to the multiple executions
|
||||
contexts (`setup_file`, multiple `@test`s) of test files, output
|
||||
will be printed more than once.
|
||||
|
||||
- Regardless of where text is redirected to (stdout, stderr or file descriptor 3)
|
||||
text is immediately visible in the terminal, as it is not piped into the formatter.
|
||||
|
||||
- Text printed to stdout may interfere with formatters as it can
|
||||
make output non-compliant with the TAP spec. The reason for this is that
|
||||
such output will be produced before the [_plan line_][tap-plan] is printed,
|
||||
contrary to the spec that requires the _plan line_ to be either the first or
|
||||
the last line of the output.
|
||||
|
||||
- Due to internal pipes/redirects, output to stderr is always printed first.
|
||||
|
||||
[tap-plan]: https://testanything.org/tap-specification.html#the-plan
|
||||
|
||||
## Special variables
|
||||
|
||||
There are several global variables you can use to introspect on Bats tests:
|
||||
|
||||
- `$BATS_RUN_COMMAND` is the run command used in your test case.
|
||||
- `$BATS_TEST_FILENAME` is the fully expanded path to the Bats test file.
|
||||
- `$BATS_TEST_DIRNAME` is the directory in which the Bats test file is located.
|
||||
- `$BATS_TEST_NAMES` is an array of function names for each test case.
|
||||
- `$BATS_TEST_NAME` is the name of the function containing the current test case.
|
||||
- `BATS_TEST_NAME_PREFIX` will be prepended to the description of each test on
|
||||
stdout and in reports.
|
||||
- `$BATS_TEST_DESCRIPTION` is the description of the current test case.
|
||||
- `BATS_TEST_RETRIES` is the maximum number of additional attempts that will be
|
||||
made on a failed test before it is finally considered failed.
|
||||
The default of 0 means the test must pass on the first attempt.
|
||||
- `BATS_TEST_TIMEOUT` is the number of seconds after which a test (including setup)
|
||||
will be aborted and marked as failed. Updates to this value in `setup()` or `@test`
|
||||
cannot change the running timeout countdown, so the latest useful update location
|
||||
is `setup_file()`.
|
||||
- `$BATS_TEST_NUMBER` is the (1-based) index of the current test case in the test file.
|
||||
- `$BATS_SUITE_TEST_NUMBER` is the (1-based) index of the current test case in the test suite (over all files).
|
||||
- `$BATS_TEST_TAGS` the tags of the current test.
|
||||
- `$BATS_TMPDIR` is the base temporary directory used by bats to create its
|
||||
temporary files / directories.
|
||||
(default: `$TMPDIR`. If `$TMPDIR` is not set, `/tmp` is used.)
|
||||
- `$BATS_RUN_TMPDIR` is the location to the temporary directory used by bats to
|
||||
store all its internal temporary files during the tests.
|
||||
(default: `$BATS_TMPDIR/bats-run-$BATS_ROOT_PID-XXXXXX`)
|
||||
- `$BATS_FILE_EXTENSION` (default: `bats`) specifies the extension of test files that should be found when running a suite (via `bats [-r] suite_folder/`)
|
||||
- `$BATS_SUITE_TMPDIR` is a temporary directory common to all tests of a suite.
|
||||
Could be used to create files required by multiple tests.
|
||||
- `$BATS_FILE_TMPDIR` is a temporary directory common to all tests of a test file.
|
||||
Could be used to create files required by multiple tests in the same test file.
|
||||
- `$BATS_TEST_TMPDIR` is a temporary directory unique for each test.
|
||||
Could be used to create files required only for specific tests.
|
||||
- `$BATS_VERSION` is the version of Bats running the test.
|
||||
|
||||
## Libraries and Add-ons
|
||||
|
||||
Bats supports loading external assertion libraries and helpers. Those under `bats-core` are officially supported libraries (integration tests welcome!):
|
||||
|
||||
- <https://github.com/bats-core/bats-assert> - common assertions for Bats
|
||||
- <https://github.com/bats-core/bats-support> - supporting library for Bats test helpers
|
||||
- <https://github.com/bats-core/bats-file> - common filesystem assertions for Bats
|
||||
- <https://github.com/bats-core/bats-detik> - e2e tests of applications in K8s environments
|
||||
|
||||
and some external libraries, supported on a "best-effort" basis:
|
||||
|
||||
- <https://github.com/ztombol/bats-docs> (still relevant? Requires review)
|
||||
- <https://github.com/grayhemp/bats-mock> (as per #147)
|
||||
- <https://github.com/jasonkarns/bats-mock> (how is this different from grayhemp/bats-mock?)
|
||||