Autogenerated HTML docs for v2.47.0-318-g04eaf
[git-htmldocs.git] / technical / unit-tests.html
blob231d55512f9091dbaa04a1cfa9ee9e7bb37ed69d
1 <!DOCTYPE html>
2 <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
3 <head>
4 <meta charset="UTF-8"/>
5 <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
6 <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7 <meta name="generator" content="Asciidoctor 2.0.20"/>
8 <title>Unit Testing</title>
9 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"/>
10 <style>
11 /*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
12 /* Uncomment the following line when using as a custom stylesheet */
13 /* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
14 html{font-family:sans-serif;-webkit-text-size-adjust:100%}
15 a{background:none}
16 a:focus{outline:thin dotted}
17 a:active,a:hover{outline:0}
18 h1{font-size:2em;margin:.67em 0}
19 b,strong{font-weight:bold}
20 abbr{font-size:.9em}
21 abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
22 dfn{font-style:italic}
23 hr{height:0}
24 mark{background:#ff0;color:#000}
25 code,kbd,pre,samp{font-family:monospace;font-size:1em}
26 pre{white-space:pre-wrap}
27 q{quotes:"\201C" "\201D" "\2018" "\2019"}
28 small{font-size:80%}
29 sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
30 sup{top:-.5em}
31 sub{bottom:-.25em}
32 img{border:0}
33 svg:not(:root){overflow:hidden}
34 figure{margin:0}
35 audio,video{display:inline-block}
36 audio:not([controls]){display:none;height:0}
37 fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
38 legend{border:0;padding:0}
39 button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
40 button,input{line-height:normal}
41 button,select{text-transform:none}
42 button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
43 button[disabled],html input[disabled]{cursor:default}
44 input[type=checkbox],input[type=radio]{padding:0}
45 button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
46 textarea{overflow:auto;vertical-align:top}
47 table{border-collapse:collapse;border-spacing:0}
48 *,::before,::after{box-sizing:border-box}
49 html,body{font-size:100%}
50 body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
51 a:hover{cursor:pointer}
52 img,object,embed{max-width:100%;height:auto}
53 object,embed{height:100%}
54 img{-ms-interpolation-mode:bicubic}
55 .left{float:left!important}
56 .right{float:right!important}
57 .text-left{text-align:left!important}
58 .text-right{text-align:right!important}
59 .text-center{text-align:center!important}
60 .text-justify{text-align:justify!important}
61 .hide{display:none}
62 img,object,svg{display:inline-block;vertical-align:middle}
63 textarea{height:auto;min-height:50px}
64 select{width:100%}
65 .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
66 div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
67 a{color:#2156a5;text-decoration:underline;line-height:inherit}
68 a:hover,a:focus{color:#1d4b8f}
69 a img{border:0}
70 p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
71 p aside{font-size:.875em;line-height:1.35;font-style:italic}
72 h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
73 h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
74 h1{font-size:2.125em}
75 h2{font-size:1.6875em}
76 h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
77 h4,h5{font-size:1.125em}
78 h6{font-size:1em}
79 hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
80 em,i{font-style:italic;line-height:inherit}
81 strong,b{font-weight:bold;line-height:inherit}
82 small{font-size:60%;line-height:inherit}
83 code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
84 ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
85 ul,ol{margin-left:1.5em}
86 ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
87 ul.circle{list-style-type:circle}
88 ul.disc{list-style-type:disc}
89 ul.square{list-style-type:square}
90 ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}
91 ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
92 dl dt{margin-bottom:.3125em;font-weight:bold}
93 dl dd{margin-bottom:1.25em}
94 blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
95 blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
96 @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
97 h1{font-size:2.75em}
98 h2{font-size:2.3125em}
99 h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
100 h4{font-size:1.4375em}}
101 table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
102 table thead,table tfoot{background:#f7f8f7}
103 table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
104 table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
105 table tr.even,table tr.alt{background:#f8f8f7}
106 table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
107 h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
108 h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
109 .center{margin-left:auto;margin-right:auto}
110 .stretch{width:100%}
111 .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
112 .clearfix::after,.float-group::after{clear:both}
113 :not(pre).nobreak{word-wrap:normal}
114 :not(pre).nowrap{white-space:nowrap}
115 :not(pre).pre-wrap{white-space:pre-wrap}
116 :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
117 pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
118 pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
119 pre>code{display:block}
120 pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
121 em em{font-style:normal}
122 strong strong{font-weight:400}
123 .keyseq{color:rgba(51,51,51,.8)}
124 kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
125 .keyseq kbd:first-child{margin-left:0}
126 .keyseq kbd:last-child{margin-right:0}
127 .menuseq,.menuref{color:#000}
128 .menuseq b:not(.caret),.menuref{font-weight:inherit}
129 .menuseq{word-spacing:-.02em}
130 .menuseq b.caret{font-size:1.25em;line-height:.8}
131 .menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
132 b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
133 b.button::before{content:"[";padding:0 3px 0 2px}
134 b.button::after{content:"]";padding:0 2px 0 3px}
135 p a>code:hover{color:rgba(0,0,0,.9)}
136 #header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
137 #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
138 #header::after,#content::after,#footnotes::after,#footer::after{clear:both}
139 #content{margin-top:1.25em}
140 #content::before{content:none}
141 #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
142 #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
143 #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
144 #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
145 #header .details span:first-child{margin-left:-.125em}
146 #header .details span.email a{color:rgba(0,0,0,.85)}
147 #header .details br{display:none}
148 #header .details br+span::before{content:"\00a0\2013\00a0"}
149 #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
150 #header .details br+span#revremark::before{content:"\00a0|\00a0"}
151 #header #revnumber{text-transform:capitalize}
152 #header #revnumber::after{content:"\00a0"}
153 #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
154 #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
155 #toc>ul{margin-left:.125em}
156 #toc ul.sectlevel0>li>a{font-style:italic}
157 #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
158 #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
159 #toc li{line-height:1.3334;margin-top:.3334em}
160 #toc a{text-decoration:none}
161 #toc a:active{text-decoration:underline}
162 #toctitle{color:#7a2518;font-size:1.2em}
163 @media screen and (min-width:768px){#toctitle{font-size:1.375em}
164 body.toc2{padding-left:15em;padding-right:0}
165 #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
166 #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
167 #toc.toc2>ul{font-size:.9em;margin-bottom:0}
168 #toc.toc2 ul ul{margin-left:0;padding-left:1em}
169 #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
170 body.toc2.toc-right{padding-left:0;padding-right:15em}
171 body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
172 @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
173 #toc.toc2{width:20em}
174 #toc.toc2 #toctitle{font-size:1.375em}
175 #toc.toc2>ul{font-size:.95em}
176 #toc.toc2 ul ul{padding-left:1.25em}
177 body.toc2.toc-right{padding-left:0;padding-right:20em}}
178 #content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
179 #content #toc>:first-child{margin-top:0}
180 #content #toc>:last-child{margin-bottom:0}
181 #footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
182 #footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
183 #content{margin-bottom:.625em}
184 .sect1{padding-bottom:.625em}
185 @media screen and (min-width:768px){#content{margin-bottom:1.25em}
186 .sect1{padding-bottom:1.25em}}
187 .sect1:last-child{padding-bottom:0}
188 .sect1+.sect1{border-top:1px solid #e7e7e9}
189 #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
190 #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
191 #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
192 #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
193 #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
194 details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
195 details{margin-left:1.25rem}
196 details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
197 details>summary::-webkit-details-marker{display:none}
198 details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
199 details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
200 details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
201 .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
202 table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
203 .paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
204 .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
205 .admonitionblock>table td.icon{text-align:center;width:80px}
206 .admonitionblock>table td.icon img{max-width:none}
207 .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
208 .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
209 .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
210 .exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
211 .sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
212 .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
213 .exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0}
214 .exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
215 .literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
216 @media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
217 @media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
218 .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
219 .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
220 .listingblock>.content{position:relative}
221 .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
222 .listingblock:hover code[data-lang]::before{display:block}
223 .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
224 .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
225 .listingblock pre.highlightjs{padding:0}
226 .listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
227 .listingblock pre.prettyprint{border-width:0}
228 .prettyprint{background:#f7f7f8}
229 pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
230 pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
231 pre.prettyprint li code[data-lang]::before{opacity:1}
232 pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
233 table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
234 table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
235 table.linenotable td.code{padding-left:.75em}
236 table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
237 pre.pygments span.linenos{display:inline-block;margin-right:.75em}
238 .quoteblock{margin:0 1em 1.25em 1.5em;display:table}
239 .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
240 .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
241 .quoteblock blockquote{margin:0;padding:0;border:0}
242 .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
243 .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
244 .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
245 .verseblock{margin:0 1em 1.25em}
246 .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
247 .verseblock pre strong{font-weight:400}
248 .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
249 .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
250 .quoteblock .attribution br,.verseblock .attribution br{display:none}
251 .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
252 .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
253 .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
254 .quoteblock.abstract{margin:0 1em 1.25em;display:block}
255 .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
256 .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
257 .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
258 .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
259 .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
260 p.tableblock:last-child{margin-bottom:0}
261 td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
262 td.tableblock>.content>:last-child{margin-bottom:-1.25em}
263 table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
264 table.grid-all>*>tr>*{border-width:1px}
265 table.grid-cols>*>tr>*{border-width:0 1px}
266 table.grid-rows>*>tr>*{border-width:1px 0}
267 table.frame-all{border-width:1px}
268 table.frame-ends{border-width:1px 0}
269 table.frame-sides{border-width:0 1px}
270 table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
271 table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
272 table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
273 table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
274 table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
275 th.halign-left,td.halign-left{text-align:left}
276 th.halign-right,td.halign-right{text-align:right}
277 th.halign-center,td.halign-center{text-align:center}
278 th.valign-top,td.valign-top{vertical-align:top}
279 th.valign-bottom,td.valign-bottom{vertical-align:bottom}
280 th.valign-middle,td.valign-middle{vertical-align:middle}
281 table thead th,table tfoot th{font-weight:bold}
282 tbody tr th{background:#f7f8f7}
283 tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
284 p.tableblock>code:only-child{background:none;padding:0}
285 p.tableblock{font-size:1em}
286 ol{margin-left:1.75em}
287 ul li ol{margin-left:1.5em}
288 dl dd{margin-left:1.125em}
289 dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
290 li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
291 ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
292 ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
293 ul.unstyled,ol.unstyled{margin-left:0}
294 li>p:empty:only-child::before{content:"";display:inline-block}
295 ul.checklist>li>p:first-child{margin-left:-1em}
296 ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
297 ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
298 ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
299 ul.inline>li{margin-left:1.25em}
300 .unstyled dl dt{font-weight:400;font-style:normal}
301 ol.arabic{list-style-type:decimal}
302 ol.decimal{list-style-type:decimal-leading-zero}
303 ol.loweralpha{list-style-type:lower-alpha}
304 ol.upperalpha{list-style-type:upper-alpha}
305 ol.lowerroman{list-style-type:lower-roman}
306 ol.upperroman{list-style-type:upper-roman}
307 ol.lowergreek{list-style-type:lower-greek}
308 .hdlist>table,.colist>table{border:0;background:none}
309 .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
310 td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
311 td.hdlist1{font-weight:bold;padding-bottom:1.25em}
312 td.hdlist2{word-wrap:anywhere}
313 .literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
314 .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
315 .colist td:not([class]):first-child img{max-width:none}
316 .colist td:not([class]):last-child{padding:.25em 0}
317 .thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
318 .imageblock.left{margin:.25em .625em 1.25em 0}
319 .imageblock.right{margin:.25em 0 1.25em .625em}
320 .imageblock>.title{margin-bottom:0}
321 .imageblock.thumb,.imageblock.th{border-width:6px}
322 .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
323 .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
324 .image.left{margin-right:.625em}
325 .image.right{margin-left:.625em}
326 a.image{text-decoration:none;display:inline-block}
327 a.image object{pointer-events:none}
328 sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
329 sup.footnote a,sup.footnoteref a{text-decoration:none}
330 sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
331 #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
332 #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
333 #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
334 #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
335 #footnotes .footnote:last-of-type{margin-bottom:0}
336 #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
337 div.unbreakable{page-break-inside:avoid}
338 .big{font-size:larger}
339 .small{font-size:smaller}
340 .underline{text-decoration:underline}
341 .overline{text-decoration:overline}
342 .line-through{text-decoration:line-through}
343 .aqua{color:#00bfbf}
344 .aqua-background{background:#00fafa}
345 .black{color:#000}
346 .black-background{background:#000}
347 .blue{color:#0000bf}
348 .blue-background{background:#0000fa}
349 .fuchsia{color:#bf00bf}
350 .fuchsia-background{background:#fa00fa}
351 .gray{color:#606060}
352 .gray-background{background:#7d7d7d}
353 .green{color:#006000}
354 .green-background{background:#007d00}
355 .lime{color:#00bf00}
356 .lime-background{background:#00fa00}
357 .maroon{color:#600000}
358 .maroon-background{background:#7d0000}
359 .navy{color:#000060}
360 .navy-background{background:#00007d}
361 .olive{color:#606000}
362 .olive-background{background:#7d7d00}
363 .purple{color:#600060}
364 .purple-background{background:#7d007d}
365 .red{color:#bf0000}
366 .red-background{background:#fa0000}
367 .silver{color:#909090}
368 .silver-background{background:#bcbcbc}
369 .teal{color:#006060}
370 .teal-background{background:#007d7d}
371 .white{color:#bfbfbf}
372 .white-background{background:#fafafa}
373 .yellow{color:#bfbf00}
374 .yellow-background{background:#fafa00}
375 span.icon>.fa{cursor:default}
376 a span.icon>.fa{cursor:inherit}
377 .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
378 .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
379 .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
380 .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
381 .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
382 .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
383 .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
384 .conum[data-value] *{color:#fff!important}
385 .conum[data-value]+b{display:none}
386 .conum[data-value]::after{content:attr(data-value)}
387 pre .conum[data-value]{position:relative;top:-.125em}
388 b.conum *{color:inherit!important}
389 .conum:not([data-value]):empty{display:none}
390 dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
391 h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
392 p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
393 p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem}
394 p{margin-bottom:1.25rem}
395 .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
396 .exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
397 .print-only{display:none!important}
398 @page{margin:1.25cm .75cm}
399 @media print{*{box-shadow:none!important;text-shadow:none!important}
400 html{font-size:80%}
401 a{color:inherit!important;text-decoration:underline!important}
402 a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
403 a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
404 abbr[title]{border-bottom:1px dotted}
405 abbr[title]::after{content:" (" attr(title) ")"}
406 pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
407 thead{display:table-header-group}
408 svg{max-width:100%}
409 p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
410 h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
411 #header,#content,#footnotes,#footer{max-width:none}
412 #toc,.sidebarblock,.exampleblock>.content{background:none!important}
413 #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
414 body.book #header{text-align:center}
415 body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
416 body.book #header .details{border:0!important;display:block;padding:0!important}
417 body.book #header .details span:first-child{margin-left:0!important}
418 body.book #header .details br{display:block}
419 body.book #header .details br+span::before{content:none!important}
420 body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
421 body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
422 .listingblock code[data-lang]::before{display:block}
423 #footer{padding:0 .9375em}
424 .hide-on-print{display:none!important}
425 .print-only{display:block!important}
426 .hide-for-print{display:none!important}
427 .show-for-print{display:inherit!important}}
428 @media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
429 .sect1{padding:0!important}
430 .sect1+.sect1{border:0}
431 #footer{background:none}
432 #footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
433 @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
434 </style>
435 </head>
436 <body class="article">
437 <div id="header">
438 <h1>Unit Testing</h1>
439 <div class="details">
440 <span id="revdate">2024-11-22</span>
441 </div>
442 </div>
443 <div id="content">
444 <div id="preamble">
445 <div class="sectionbody">
446 <div class="paragraph">
447 <p>In our current testing environment, we spend a significant amount of effort
448 crafting end-to-end tests for error conditions that could easily be captured by
449 unit tests (or we simply forgo some hard-to-setup and rare error conditions).
450 Unit tests additionally provide stability to the codebase and can simplify
451 debugging through isolation. Writing unit tests in pure C, rather than with our
452 current shell/test-tool helper setup, simplifies test setup, simplifies passing
453 data around (no shell-isms required), and reduces testing runtime by not
454 spawning a separate process for every test invocation.</p>
455 </div>
456 <div class="paragraph">
457 <p>We believe that a large body of unit tests, living alongside the existing test
458 suite, will improve code quality for the Git project.</p>
459 </div>
460 </div>
461 </div>
462 <div class="sect1">
463 <h2 id="_definitions">Definitions</h2>
464 <div class="sectionbody">
465 <div class="paragraph">
466 <p>For the purposes of this document, we&#8217;ll use <strong>test framework</strong> to refer to
467 projects that support writing test cases and running tests within the context
468 of a single executable. <strong>Test harness</strong> will refer to projects that manage
469 running multiple executables (each of which may contain multiple test cases) and
470 aggregating their results.</p>
471 </div>
472 <div class="paragraph">
473 <p>In reality, these terms are not strictly defined, and many of the projects
474 discussed below contain features from both categories.</p>
475 </div>
476 <div class="paragraph">
477 <p>For now, we will evaluate projects solely on their framework features. Since we
478 are relying on having TAP output (see below), we can assume that any framework
479 can be made to work with a harness that we can choose later.</p>
480 </div>
481 </div>
482 </div>
483 <div class="sect1">
484 <h2 id="_summary">Summary</h2>
485 <div class="sectionbody">
486 <div class="paragraph">
487 <p>We believe the best way forward is to implement a custom TAP framework for the
488 Git project. We use a version of the framework originally proposed in
489 <a href="https://lore.kernel.org/git/c902a166-98ce-afba-93f2-ea6027557176@gmail.com/">1</a>.</p>
490 </div>
491 <div class="paragraph">
492 <p>See the <a href="#framework-selection">Framework Selection</a> section below for the
493 rationale behind this decision.</p>
494 </div>
495 </div>
496 </div>
497 <div class="sect1">
498 <h2 id="_choosing_a_test_harness">Choosing a test harness</h2>
499 <div class="sectionbody">
500 <div class="paragraph">
501 <p>During upstream discussion, it was occasionally noted that <code>prove</code> provides many
502 convenient features, such as scheduling slower tests first, or re-running
503 previously failed tests.</p>
504 </div>
505 <div class="paragraph">
506 <p>While we already support the use of <code>prove</code> as a test harness for the shell
507 tests, it is not strictly required. The t/Makefile allows running shell tests
508 directly (though with interleaved output if parallelism is enabled). Git
509 developers who wish to use <code>prove</code> as a more advanced harness can do so by
510 setting DEFAULT_TEST_TARGET=prove in their config.mak.</p>
511 </div>
512 <div class="paragraph">
513 <p>We will follow a similar approach for unit tests: by default the test
514 executables will be run directly from the t/Makefile, but <code>prove</code> can be
515 configured with DEFAULT_UNIT_TEST_TARGET=prove.</p>
516 </div>
517 </div>
518 </div>
519 <div class="sect1">
520 <h2 id="framework-selection">Framework selection</h2>
521 <div class="sectionbody">
522 <div class="paragraph">
523 <p>There are a variety of features we can use to rank the candidate frameworks, and
524 those features have different priorities:</p>
525 </div>
526 <div class="ulist">
527 <ul>
528 <li>
529 <p>Critical features: we probably won&#8217;t consider a framework without these</p>
530 <div class="ulist">
531 <ul>
532 <li>
533 <p>Can we legally / easily use the project?</p>
534 <div class="ulist">
535 <ul>
536 <li>
537 <p><a href="#license">License</a></p>
538 </li>
539 <li>
540 <p><a href="#vendorable-or-ubiquitous">Vendorable or ubiquitous</a></p>
541 </li>
542 <li>
543 <p><a href="#maintainable-extensible">Maintainable / extensible</a></p>
544 </li>
545 <li>
546 <p><a href="#major-platform-support">Major platform support</a></p>
547 </li>
548 </ul>
549 </div>
550 </li>
551 <li>
552 <p>Does the project support our bare-minimum needs?</p>
553 <div class="ulist">
554 <ul>
555 <li>
556 <p><a href="#tap-support">TAP support</a></p>
557 </li>
558 <li>
559 <p><a href="#diagnostic-output">Diagnostic output</a></p>
560 </li>
561 <li>
562 <p><a href="#runtime-skippable-tests">Runtime-skippable tests</a></p>
563 </li>
564 </ul>
565 </div>
566 </li>
567 </ul>
568 </div>
569 </li>
570 <li>
571 <p>Nice-to-have features:</p>
572 <div class="ulist">
573 <ul>
574 <li>
575 <p><a href="#parallel-execution">Parallel execution</a></p>
576 </li>
577 <li>
578 <p><a href="#mock-support">Mock support</a></p>
579 </li>
580 <li>
581 <p><a href="#signal-error-handling">Signal &amp; error-handling</a></p>
582 </li>
583 </ul>
584 </div>
585 </li>
586 <li>
587 <p>Tie-breaker stats</p>
588 <div class="ulist">
589 <ul>
590 <li>
591 <p><a href="#project-kloc">Project KLOC</a></p>
592 </li>
593 <li>
594 <p><a href="#adoption">Adoption</a></p>
595 </li>
596 </ul>
597 </div>
598 </li>
599 </ul>
600 </div>
601 <div class="sect2">
602 <h3 id="license">License</h3>
603 <div class="paragraph">
604 <p>We must be able to legally use the framework in connection with Git. As Git is
605 licensed only under GPLv2, we must eliminate any LGPLv3, GPLv3, or Apache 2.0
606 projects.</p>
607 </div>
608 </div>
609 <div class="sect2">
610 <h3 id="vendorable-or-ubiquitous">Vendorable or ubiquitous</h3>
611 <div class="paragraph">
612 <p>We want to avoid forcing Git developers to install new tools just to run unit
613 tests. Any prospective frameworks and harnesses must either be vendorable
614 (meaning, we can copy their source directly into Git&#8217;s repository), or so
615 ubiquitous that it is reasonable to expect that most developers will have the
616 tools installed already.</p>
617 </div>
618 </div>
619 <div class="sect2">
620 <h3 id="maintainable-extensible">Maintainable / extensible</h3>
621 <div class="paragraph">
622 <p>It is unlikely that any pre-existing project perfectly fits our needs, so any
623 project we select will need to be actively maintained and open to accepting
624 changes. Alternatively, assuming we are vendoring the source into our repo, it
625 must be simple enough that Git developers can feel comfortable making changes as
626 needed to our version.</p>
627 </div>
628 <div class="paragraph">
629 <p>In the comparison table below, "True" means that the framework seems to have
630 active developers, that it is simple enough that Git developers can make changes
631 to it, and that the project seems open to accepting external contributions (or
632 that it is vendorable). "Partial" means that at least one of the above
633 conditions holds.</p>
634 </div>
635 </div>
636 <div class="sect2">
637 <h3 id="major-platform-support">Major platform support</h3>
638 <div class="paragraph">
639 <p>At a bare minimum, unit-testing must work on Linux, MacOS, and Windows.</p>
640 </div>
641 <div class="paragraph">
642 <p>In the comparison table below, "True" means that it works on all three major
643 platforms with no issues. "Partial" means that there may be annoyances on one or
644 more platforms, but it is still usable in principle.</p>
645 </div>
646 </div>
647 <div class="sect2">
648 <h3 id="tap-support">TAP support</h3>
649 <div class="paragraph">
650 <p>The <a href="https://testanything.org/">Test Anything Protocol</a> is a text-based interface
651 that allows tests to communicate with a test harness. It is already used by
652 Git&#8217;s integration test suite. Supporting TAP output is a mandatory feature for
653 any prospective test framework.</p>
654 </div>
655 <div class="paragraph">
656 <p>In the comparison table below, "True" means this is natively supported.
657 "Partial" means TAP output must be generated by post-processing the native
658 output.</p>
659 </div>
660 <div class="paragraph">
661 <p>Frameworks that do not have at least Partial support will not be evaluated
662 further.</p>
663 </div>
664 </div>
665 <div class="sect2">
666 <h3 id="diagnostic-output">Diagnostic output</h3>
667 <div class="paragraph">
668 <p>When a test case fails, the framework must generate enough diagnostic output to
669 help developers find the appropriate test case in source code in order to debug
670 the failure.</p>
671 </div>
672 </div>
673 <div class="sect2">
674 <h3 id="runtime-skippable-tests">Runtime-skippable tests</h3>
675 <div class="paragraph">
676 <p>Test authors may wish to skip certain test cases based on runtime circumstances,
677 so the framework should support this.</p>
678 </div>
679 </div>
680 <div class="sect2">
681 <h3 id="parallel-execution">Parallel execution</h3>
682 <div class="paragraph">
683 <p>Ideally, we will build up a significant collection of unit test cases, most
684 likely split across multiple executables. It will be necessary to run these
685 tests in parallel to enable fast develop-test-debug cycles.</p>
686 </div>
687 <div class="paragraph">
688 <p>In the comparison table below, "True" means that individual test cases within a
689 single test executable can be run in parallel. We assume that executable-level
690 parallelism can be handled by the test harness.</p>
691 </div>
692 </div>
693 <div class="sect2">
694 <h3 id="mock-support">Mock support</h3>
695 <div class="paragraph">
696 <p>Unit test authors may wish to test code that interacts with objects that may be
697 inconvenient to handle in a test (e.g. interacting with a network service).
698 Mocking allows test authors to provide a fake implementation of these objects
699 for more convenient tests.</p>
700 </div>
701 </div>
702 <div class="sect2">
703 <h3 id="signal-error-handling">Signal &amp; error handling</h3>
704 <div class="paragraph">
705 <p>The test framework should fail gracefully when test cases are themselves buggy
706 or when they are interrupted by signals during runtime.</p>
707 </div>
708 </div>
709 <div class="sect2">
710 <h3 id="project-kloc">Project KLOC</h3>
711 <div class="paragraph">
712 <p>The size of the project, in thousands of lines of code as measured by
713 <a href="https://dwheeler.com/sloccount/">sloccount</a> (rounded up to the next multiple of
714 1,000). As a tie-breaker, we probably prefer a project with fewer LOC.</p>
715 </div>
716 </div>
717 <div class="sect2">
718 <h3 id="adoption">Adoption</h3>
719 <div class="paragraph">
720 <p>As a tie-breaker, we prefer a more widely-used project. We use the number of
721 GitHub / GitLab stars to estimate this.</p>
722 </div>
723 </div>
724 <div class="sect2">
725 <h3 id="_comparison">Comparison</h3>
726 <table class="tableblock frame-all grid-all" style="width: 33%;">
727 <colgroup>
728 <col style="width: 7.6923%;"/>
729 <col style="width: 7.6923%;"/>
730 <col style="width: 7.6923%;"/>
731 <col style="width: 7.6923%;"/>
732 <col style="width: 7.6923%;"/>
733 <col style="width: 7.6923%;"/>
734 <col style="width: 7.6923%;"/>
735 <col style="width: 7.6923%;"/>
736 <col style="width: 7.6923%;"/>
737 <col style="width: 7.6923%;"/>
738 <col style="width: 7.6923%;"/>
739 <col style="width: 7.6923%;"/>
740 <col style="width: 7.6924%;"/>
741 </colgroup>
742 <thead>
743 <tr>
744 <th class="tableblock halign-left valign-top">Framework</th>
745 <th class="tableblock halign-left valign-top"><a href="#license">License</a></th>
746 <th class="tableblock halign-left valign-top"><a href="#vendorable-or-ubiquitous">Vendorable or ubiquitous</a></th>
747 <th class="tableblock halign-left valign-top"><a href="#maintainable-extensible">Maintainable / extensible</a></th>
748 <th class="tableblock halign-left valign-top"><a href="#major-platform-support">Major platform support</a></th>
749 <th class="tableblock halign-left valign-top"><a href="#tap-support">TAP support</a></th>
750 <th class="tableblock halign-left valign-top"><a href="#diagnostic-output">Diagnostic output</a></th>
751 <th class="tableblock halign-left valign-top"><a href="#runtime&#8212;&#8203;skippable-tests">Runtime- skippable tests</a></th>
752 <th class="tableblock halign-left valign-top"><a href="#parallel-execution">Parallel execution</a></th>
753 <th class="tableblock halign-left valign-top"><a href="#mock-support">Mock support</a></th>
754 <th class="tableblock halign-left valign-top"><a href="#signal-error-handling">Signal &amp; error handling</a></th>
755 <th class="tableblock halign-left valign-top"><a href="#project-kloc">Project KLOC</a></th>
756 <th class="tableblock halign-left valign-top"><a href="#adoption">Adoption</a></th>
757 </tr>
758 </thead>
759 <tbody>
760 <tr>
761 <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://lore.kernel.org/git/c902a166-98ce-afba-93f2-ea6027557176@gmail.com/">Custom Git impl.</a></p></td>
762 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#GPL v2#</p></td>
763 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
764 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
765 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
766 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
767 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
768 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
769 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
770 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
771 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
772 <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
773 <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
774 </tr>
775 <tr>
776 <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/silentbicycle/greatest">Greatest</a></p></td>
777 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#ISC#</p></td>
778 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
779 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
780 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
781 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
782 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
783 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
784 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
785 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
786 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
787 <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
788 <td class="tableblock halign-left valign-top"><p class="tableblock">1400</p></td>
789 </tr>
790 <tr>
791 <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/Snaipe/Criterion">Criterion</a></p></td>
792 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#MIT#</p></td>
793 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
794 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
795 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
796 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
797 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
798 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
799 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
800 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
801 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
802 <td class="tableblock halign-left valign-top"><p class="tableblock">19</p></td>
803 <td class="tableblock halign-left valign-top"><p class="tableblock">1800</p></td>
804 </tr>
805 <tr>
806 <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/rra/c-tap-harness/">C TAP</a></p></td>
807 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#Expat#</p></td>
808 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
809 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
810 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
811 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
812 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
813 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
814 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
815 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
816 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
817 <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
818 <td class="tableblock halign-left valign-top"><p class="tableblock">33</p></td>
819 </tr>
820 <tr>
821 <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://libcheck.github.io/check/">Check</a></p></td>
822 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#LGPL v2.1#</p></td>
823 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
824 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
825 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
826 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
827 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
828 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
829 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
830 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
831 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
832 <td class="tableblock halign-left valign-top"><p class="tableblock">17</p></td>
833 <td class="tableblock halign-left valign-top"><p class="tableblock">973</p></td>
834 </tr>
835 <tr>
836 <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/clar-test/clar">Clar</a></p></td>
837 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#ISC#</p></td>
838 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
839 <td class="tableblock halign-left valign-top"><p class="tableblock">[yellow-background]#Partial#</p></td>
840 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
841 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
842 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
843 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
844 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
845 <td class="tableblock halign-left valign-top"><p class="tableblock">[red-background]#False#</p></td>
846 <td class="tableblock halign-left valign-top"><p class="tableblock">[lime-background]#True#</p></td>
847 <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
848 <td class="tableblock halign-left valign-top"><p class="tableblock">192</p></td>
849 </tr>
850 </tbody>
851 </table>
852 </div>
853 <div class="sect2">
854 <h3 id="_additional_framework_candidates">Additional framework candidates</h3>
855 <div class="paragraph">
856 <p>Several suggested frameworks have been eliminated from consideration:</p>
857 </div>
858 <div class="ulist">
859 <ul>
860 <li>
861 <p>Incompatible licenses:</p>
862 <div class="ulist">
863 <ul>
864 <li>
865 <p><a href="https://github.com/zorgnax/libtap">libtap</a> (LGPL v3)</p>
866 </li>
867 <li>
868 <p><a href="https://cmocka.org/">cmocka</a> (Apache 2.0)</p>
869 </li>
870 </ul>
871 </div>
872 </li>
873 <li>
874 <p>Missing source: <a href="https://www.kindahl.net/mytap/doc/index.html">MyTap</a></p>
875 </li>
876 <li>
877 <p>No TAP support:</p>
878 <div class="ulist">
879 <ul>
880 <li>
881 <p><a href="https://nemequ.github.io/munit/">µnit</a></p>
882 </li>
883 <li>
884 <p><a href="https://github.com/google/cmockery">cmockery</a></p>
885 </li>
886 <li>
887 <p><a href="https://github.com/lpabon/cmockery2">cmockery2</a></p>
888 </li>
889 <li>
890 <p><a href="https://github.com/ThrowTheSwitch/Unity">Unity</a></p>
891 </li>
892 <li>
893 <p><a href="https://github.com/siu/minunit">minunit</a></p>
894 </li>
895 <li>
896 <p><a href="https://cunit.sourceforge.net/">CUnit</a></p>
897 </li>
898 </ul>
899 </div>
900 </li>
901 </ul>
902 </div>
903 </div>
904 </div>
905 </div>
906 <div class="sect1">
907 <h2 id="_milestones">Milestones</h2>
908 <div class="sectionbody">
909 <div class="ulist">
910 <ul>
911 <li>
912 <p>Add useful tests of library-like code</p>
913 </li>
914 <li>
915 <p>Integrate with
916 <a href="https://lore.kernel.org/git/20230502211454.1673000-1-calvinwan@google.com/">stdlib
917 work</a></p>
918 </li>
919 <li>
920 <p>Run alongside regular <code>make</code> <code>test</code> target</p>
921 </li>
922 </ul>
923 </div>
924 </div>
925 </div>
926 </div>
927 <div id="footer">
928 <div id="footer-text">
929 Last updated 2024-09-19 10:48:31 +0900
930 </div>
931 </div>
932 </body>
933 </html>