kibi-swipl-linux-x64-gnu 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (550) hide show
  1. package/README.md +29 -0
  2. package/bin/swipl +0 -0
  3. package/bin/swipl-win +0 -0
  4. package/build-manifest.json +70 -0
  5. package/lib/cmake/swipl/SWIPLConfig.cmake +21 -0
  6. package/lib/cmake/swipl/SWIPLConfigVersion.cmake +65 -0
  7. package/lib/cmake/swipl/SWIPLTargets-release.cmake +28 -0
  8. package/lib/cmake/swipl/SWIPLTargets.cmake +109 -0
  9. package/lib/swipl/ABI +1 -0
  10. package/lib/swipl/LICENSE +41 -0
  11. package/lib/swipl/README.md +116 -0
  12. package/lib/swipl/app/README.md +25 -0
  13. package/lib/swipl/app/app.pl +87 -0
  14. package/lib/swipl/app/pack.pl +350 -0
  15. package/lib/swipl/app/qlf.pl +521 -0
  16. package/lib/swipl/app/splfr.pl +177 -0
  17. package/lib/swipl/app/sys.pl +310 -0
  18. package/lib/swipl/bin/swipl.home +1 -0
  19. package/lib/swipl/boot/apply.pl +73 -0
  20. package/lib/swipl/boot/attvar.pl +344 -0
  21. package/lib/swipl/boot/autoload.pl +1226 -0
  22. package/lib/swipl/boot/bags.pl +283 -0
  23. package/lib/swipl/boot/dcg.pl +388 -0
  24. package/lib/swipl/boot/dicts.pl +193 -0
  25. package/lib/swipl/boot/dwim.pl +485 -0
  26. package/lib/swipl/boot/engines.pl +152 -0
  27. package/lib/swipl/boot/expand.pl +1628 -0
  28. package/lib/swipl/boot/gc.pl +65 -0
  29. package/lib/swipl/boot/history.pl +304 -0
  30. package/lib/swipl/boot/init.pl +4682 -0
  31. package/lib/swipl/boot/iri.pl +64 -0
  32. package/lib/swipl/boot/license.pl +390 -0
  33. package/lib/swipl/boot/load.pl +81 -0
  34. package/lib/swipl/boot/messages.pl +2521 -0
  35. package/lib/swipl/boot/packs.pl +306 -0
  36. package/lib/swipl/boot/predopts.pl +154 -0
  37. package/lib/swipl/boot/qlf.pl +141 -0
  38. package/lib/swipl/boot/rc.pl +263 -0
  39. package/lib/swipl/boot/syspred.pl +1634 -0
  40. package/lib/swipl/boot/tabling.pl +2321 -0
  41. package/lib/swipl/boot/threads.pl +42 -0
  42. package/lib/swipl/boot/toplevel.pl +2248 -0
  43. package/lib/swipl/boot/topvars.pl +261 -0
  44. package/lib/swipl/boot.prc +0 -0
  45. package/lib/swipl/cmake/swipl.cmake +131 -0
  46. package/lib/swipl/customize/README.md +23 -0
  47. package/lib/swipl/customize/edit +101 -0
  48. package/lib/swipl/customize/init.pl +164 -0
  49. package/lib/swipl/demo/README.md +33 -0
  50. package/lib/swipl/demo/likes.pl +44 -0
  51. package/lib/swipl/doc/packages/examples/chr/bool.chr +281 -0
  52. package/lib/swipl/doc/packages/examples/chr/chrdif.chr +87 -0
  53. package/lib/swipl/doc/packages/examples/chr/chrfreeze.chr +6 -0
  54. package/lib/swipl/doc/packages/examples/chr/family.chr +116 -0
  55. package/lib/swipl/doc/packages/examples/chr/fib.chr +24 -0
  56. package/lib/swipl/doc/packages/examples/chr/fibonacci.chr +31 -0
  57. package/lib/swipl/doc/packages/examples/chr/gcd.chr +28 -0
  58. package/lib/swipl/doc/packages/examples/chr/leq.chr +34 -0
  59. package/lib/swipl/doc/packages/examples/chr/listdom.chr +138 -0
  60. package/lib/swipl/doc/packages/examples/chr/primes.chr +29 -0
  61. package/lib/swipl/doc/packages/examples/http/README.md +98 -0
  62. package/lib/swipl/doc/packages/examples/http/calc.pl +92 -0
  63. package/lib/swipl/doc/packages/examples/http/demo_body.pl +232 -0
  64. package/lib/swipl/doc/packages/examples/http/demo_client.pl +165 -0
  65. package/lib/swipl/doc/packages/examples/http/demo_daemon.pl +38 -0
  66. package/lib/swipl/doc/packages/examples/http/demo_files.pl +50 -0
  67. package/lib/swipl/doc/packages/examples/http/demo_hello.pl +15 -0
  68. package/lib/swipl/doc/packages/examples/http/demo_login.pl +280 -0
  69. package/lib/swipl/doc/packages/examples/http/demo_openid.pl +177 -0
  70. package/lib/swipl/doc/packages/examples/http/demo_pwp.pl +20 -0
  71. package/lib/swipl/doc/packages/examples/http/demo_rest.pl +56 -0
  72. package/lib/swipl/doc/packages/examples/http/demo_threads.pl +52 -0
  73. package/lib/swipl/doc/packages/examples/http/linux-init-script +126 -0
  74. package/lib/swipl/doc/packages/examples/http/pwp/context.pwp +23 -0
  75. package/lib/swipl/doc/packages/examples/http/pwp/index.pwp +25 -0
  76. package/lib/swipl/doc/packages/examples/http/pwp/pwp1.pwp +12 -0
  77. package/lib/swipl/doc/packages/examples/http/pwp/pwp2.pwp +10 -0
  78. package/lib/swipl/doc/packages/examples/http/pwp/pwp3.pwp +25 -0
  79. package/lib/swipl/doc/packages/examples/http/pwp/pwp4.pwp +23 -0
  80. package/lib/swipl/doc/packages/examples/http/pwp/pwp5.pwp +11 -0
  81. package/lib/swipl/doc/packages/examples/http/pwp/pwp6.pwp +3 -0
  82. package/lib/swipl/doc/packages/examples/http/pwp/pwp7.pwp +3 -0
  83. package/lib/swipl/doc/packages/examples/http/pwp/pwp8.pwp +3 -0
  84. package/lib/swipl/doc/packages/examples/http/pwp/pwpdb.pl +12 -0
  85. package/lib/swipl/doc/packages/examples/http/systemd-script.service +18 -0
  86. package/lib/swipl/doc/packages/examples/http/upstart-script.conf +20 -0
  87. package/lib/swipl/doc/packages/examples/plunit/read.pl +17 -0
  88. package/lib/swipl/doc/packages/examples/plunit/simple.pl +33 -0
  89. package/lib/swipl/doc/packages/examples/ssl/client.pl +83 -0
  90. package/lib/swipl/doc/packages/examples/ssl/etc/README +52 -0
  91. package/lib/swipl/doc/packages/examples/ssl/etc/client/client-cert.p12 +0 -0
  92. package/lib/swipl/doc/packages/examples/ssl/etc/client/client-cert.pem +85 -0
  93. package/lib/swipl/doc/packages/examples/ssl/etc/client/client-key.pem +30 -0
  94. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/cacert.pem +82 -0
  95. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/careq.pem +18 -0
  96. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/crlnumber +1 -0
  97. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/index.txt +3 -0
  98. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/index.txt.attr +1 -0
  99. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/newcerts/9DC08797A0F63F7C.pem +85 -0
  100. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/newcerts/9DC08797A0F63F7D.pem +85 -0
  101. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/private/cakey.pem +30 -0
  102. package/lib/swipl/doc/packages/examples/ssl/etc/demoCA/serial +1 -0
  103. package/lib/swipl/doc/packages/examples/ssl/etc/server/server-cert.pem +85 -0
  104. package/lib/swipl/doc/packages/examples/ssl/etc/server/server-key.pem +30 -0
  105. package/lib/swipl/doc/packages/examples/ssl/https.pl +267 -0
  106. package/lib/swipl/doc/packages/examples/ssl/server.pl +106 -0
  107. package/lib/swipl/include/SWI-Prolog.h +1544 -0
  108. package/lib/swipl/include/SWI-Stream.h +537 -0
  109. package/lib/swipl/include/Yap/YapInterface.h +283 -0
  110. package/lib/swipl/include/sicstus/sicstus.h +452 -0
  111. package/lib/swipl/lib/x86_64-linux/cgi.so +0 -0
  112. package/lib/swipl/lib/x86_64-linux/crypt.so +0 -0
  113. package/lib/swipl/lib/x86_64-linux/crypto4pl.so +0 -0
  114. package/lib/swipl/lib/x86_64-linux/double_metaphone.so +0 -0
  115. package/lib/swipl/lib/x86_64-linux/files.so +0 -0
  116. package/lib/swipl/lib/x86_64-linux/hashstream.so +0 -0
  117. package/lib/swipl/lib/x86_64-linux/http_stream.so +0 -0
  118. package/lib/swipl/lib/x86_64-linux/isub.so +0 -0
  119. package/lib/swipl/lib/x86_64-linux/json.so +0 -0
  120. package/lib/swipl/lib/x86_64-linux/libswipl.so.10 +0 -0
  121. package/lib/swipl/lib/x86_64-linux/mallocinfo.so +0 -0
  122. package/lib/swipl/lib/x86_64-linux/md54pl.so +0 -0
  123. package/lib/swipl/lib/x86_64-linux/memfile.so +0 -0
  124. package/lib/swipl/lib/x86_64-linux/ntriples.so +0 -0
  125. package/lib/swipl/lib/x86_64-linux/pcre4pl.so +0 -0
  126. package/lib/swipl/lib/x86_64-linux/porter_stem.so +0 -0
  127. package/lib/swipl/lib/x86_64-linux/process.so +0 -0
  128. package/lib/swipl/lib/x86_64-linux/prolog_stream.so +0 -0
  129. package/lib/swipl/lib/x86_64-linux/rdf_db.so +0 -0
  130. package/lib/swipl/lib/x86_64-linux/readutil.so +0 -0
  131. package/lib/swipl/lib/x86_64-linux/rlimit.so +0 -0
  132. package/lib/swipl/lib/x86_64-linux/sched.so +0 -0
  133. package/lib/swipl/lib/x86_64-linux/sgml2pl.so +0 -0
  134. package/lib/swipl/lib/x86_64-linux/sha4pl.so +0 -0
  135. package/lib/swipl/lib/x86_64-linux/snowball.so +0 -0
  136. package/lib/swipl/lib/x86_64-linux/socket.so +0 -0
  137. package/lib/swipl/lib/x86_64-linux/ssl4pl.so +0 -0
  138. package/lib/swipl/lib/x86_64-linux/streaminfo.so +0 -0
  139. package/lib/swipl/lib/x86_64-linux/syslog.so +0 -0
  140. package/lib/swipl/lib/x86_64-linux/time.so +0 -0
  141. package/lib/swipl/lib/x86_64-linux/turtle.so +0 -0
  142. package/lib/swipl/lib/x86_64-linux/uid.so +0 -0
  143. package/lib/swipl/lib/x86_64-linux/unix.so +0 -0
  144. package/lib/swipl/lib/x86_64-linux/uri.so +0 -0
  145. package/lib/swipl/lib/x86_64-linux/websocket.so +0 -0
  146. package/lib/swipl/lib/x86_64-linux/zlib4pl.so +0 -0
  147. package/lib/swipl/library/INDEX.pl +1020 -0
  148. package/lib/swipl/library/aggregate.pl +755 -0
  149. package/lib/swipl/library/ansi_term.pl +653 -0
  150. package/lib/swipl/library/apply.pl +426 -0
  151. package/lib/swipl/library/apply_macros.pl +497 -0
  152. package/lib/swipl/library/arithmetic.pl +320 -0
  153. package/lib/swipl/library/assoc.pl +522 -0
  154. package/lib/swipl/library/atom.pl +169 -0
  155. package/lib/swipl/library/backcomp.pl +688 -0
  156. package/lib/swipl/library/base32.pl +291 -0
  157. package/lib/swipl/library/base64.pl +441 -0
  158. package/lib/swipl/library/broadcast.pl +161 -0
  159. package/lib/swipl/library/build/cmake.pl +137 -0
  160. package/lib/swipl/library/build/conan.pl +232 -0
  161. package/lib/swipl/library/build/make.pl +168 -0
  162. package/lib/swipl/library/build/tools.pl +825 -0
  163. package/lib/swipl/library/charsio.pl +195 -0
  164. package/lib/swipl/library/check.pl +1097 -0
  165. package/lib/swipl/library/check_installation.pl +912 -0
  166. package/lib/swipl/library/clp/INDEX.pl +157 -0
  167. package/lib/swipl/library/clp/bounds.pl +2036 -0
  168. package/lib/swipl/library/clp/clp_distinct.pl +263 -0
  169. package/lib/swipl/library/clp/clp_events.pl +92 -0
  170. package/lib/swipl/library/clp/clpb.pl +1896 -0
  171. package/lib/swipl/library/clp/clpfd.pl +7906 -0
  172. package/lib/swipl/library/clp/simplex.pl +1580 -0
  173. package/lib/swipl/library/codesio.pl +182 -0
  174. package/lib/swipl/library/coinduction.pl +183 -0
  175. package/lib/swipl/library/console_input.pl +289 -0
  176. package/lib/swipl/library/csv.pl +611 -0
  177. package/lib/swipl/library/ctypes.pl +161 -0
  178. package/lib/swipl/library/date.pl +370 -0
  179. package/lib/swipl/library/dcg/INDEX.pl +35 -0
  180. package/lib/swipl/library/dcg/basics.pl +514 -0
  181. package/lib/swipl/library/dcg/high_order.pl +227 -0
  182. package/lib/swipl/library/debug.pl +499 -0
  183. package/lib/swipl/library/dialect/bim.pl +186 -0
  184. package/lib/swipl/library/dialect/commons.pl +77 -0
  185. package/lib/swipl/library/dialect/eclipse/test_util_iso.pl +355 -0
  186. package/lib/swipl/library/dialect/hprolog/format.pl +44 -0
  187. package/lib/swipl/library/dialect/hprolog.pl +314 -0
  188. package/lib/swipl/library/dialect/ifprolog.pl +1317 -0
  189. package/lib/swipl/library/dialect/iso/iso_predicates.pl +277 -0
  190. package/lib/swipl/library/dialect/sicstus/README.TXT +1 -0
  191. package/lib/swipl/library/dialect/sicstus/arrays.pl +121 -0
  192. package/lib/swipl/library/dialect/sicstus/block.pl +278 -0
  193. package/lib/swipl/library/dialect/sicstus/lists.pl +167 -0
  194. package/lib/swipl/library/dialect/sicstus/ordsets.pl +52 -0
  195. package/lib/swipl/library/dialect/sicstus/sockets.pl +174 -0
  196. package/lib/swipl/library/dialect/sicstus/system.pl +262 -0
  197. package/lib/swipl/library/dialect/sicstus/terms.pl +57 -0
  198. package/lib/swipl/library/dialect/sicstus/timeout.pl +92 -0
  199. package/lib/swipl/library/dialect/sicstus.pl +582 -0
  200. package/lib/swipl/library/dialect/sicstus4/aggregate.pl +60 -0
  201. package/lib/swipl/library/dialect/sicstus4/between.pl +62 -0
  202. package/lib/swipl/library/dialect/sicstus4/clpfd.pl +75 -0
  203. package/lib/swipl/library/dialect/sicstus4/file_systems.pl +413 -0
  204. package/lib/swipl/library/dialect/sicstus4/lists.pl +274 -0
  205. package/lib/swipl/library/dialect/sicstus4/ordsets.pl +54 -0
  206. package/lib/swipl/library/dialect/sicstus4/samsort.pl +86 -0
  207. package/lib/swipl/library/dialect/sicstus4/sets.pl +124 -0
  208. package/lib/swipl/library/dialect/sicstus4/sockets.pl +164 -0
  209. package/lib/swipl/library/dialect/sicstus4/system.pl +80 -0
  210. package/lib/swipl/library/dialect/sicstus4/terms.pl +89 -0
  211. package/lib/swipl/library/dialect/sicstus4/timeout.pl +43 -0
  212. package/lib/swipl/library/dialect/sicstus4/types.pl +103 -0
  213. package/lib/swipl/library/dialect/sicstus4.pl +200 -0
  214. package/lib/swipl/library/dialect/swi/syspred_options.pl +250 -0
  215. package/lib/swipl/library/dialect/xsb/README.md +20 -0
  216. package/lib/swipl/library/dialect/xsb/basics.pl +318 -0
  217. package/lib/swipl/library/dialect/xsb/consult.pl +87 -0
  218. package/lib/swipl/library/dialect/xsb/curr_sym.pl +57 -0
  219. package/lib/swipl/library/dialect/xsb/error_handler.pl +111 -0
  220. package/lib/swipl/library/dialect/xsb/gensym.pl +53 -0
  221. package/lib/swipl/library/dialect/xsb/gpp.pl +138 -0
  222. package/lib/swipl/library/dialect/xsb/intern.pl +48 -0
  223. package/lib/swipl/library/dialect/xsb/lists.pl +47 -0
  224. package/lib/swipl/library/dialect/xsb/machine.pl +295 -0
  225. package/lib/swipl/library/dialect/xsb/ordsets.pl +53 -0
  226. package/lib/swipl/library/dialect/xsb/setof.pl +54 -0
  227. package/lib/swipl/library/dialect/xsb/source.pl +308 -0
  228. package/lib/swipl/library/dialect/xsb/standard.pl +169 -0
  229. package/lib/swipl/library/dialect/xsb/storage.pl +70 -0
  230. package/lib/swipl/library/dialect/xsb/string.pl +76 -0
  231. package/lib/swipl/library/dialect/xsb/thread.pl +62 -0
  232. package/lib/swipl/library/dialect/xsb/timed_call.pl +158 -0
  233. package/lib/swipl/library/dialect/xsb.pl +688 -0
  234. package/lib/swipl/library/dialect/yap/README.TXT +8 -0
  235. package/lib/swipl/library/dialect/yap.pl +283 -0
  236. package/lib/swipl/library/dialect.pl +123 -0
  237. package/lib/swipl/library/dicts.pl +399 -0
  238. package/lib/swipl/library/dif.pl +426 -0
  239. package/lib/swipl/library/edinburgh.pl +138 -0
  240. package/lib/swipl/library/edit.pl +783 -0
  241. package/lib/swipl/library/error.pl +495 -0
  242. package/lib/swipl/library/exceptions.pl +231 -0
  243. package/lib/swipl/library/explain.pl +543 -0
  244. package/lib/swipl/library/ext/RDF/INDEX.pl +25 -0
  245. package/lib/swipl/library/ext/RDF/rdf.pl +450 -0
  246. package/lib/swipl/library/ext/RDF/rdf_parser.pl +649 -0
  247. package/lib/swipl/library/ext/RDF/rdf_triple.pl +448 -0
  248. package/lib/swipl/library/ext/RDF/rdf_write.pl +701 -0
  249. package/lib/swipl/library/ext/RDF/rewrite_term.pl +177 -0
  250. package/lib/swipl/library/ext/chr/chr/a_star.pl +80 -0
  251. package/lib/swipl/library/ext/chr/chr/binomialheap.pl +142 -0
  252. package/lib/swipl/library/ext/chr/chr/builtins.pl +629 -0
  253. package/lib/swipl/library/ext/chr/chr/chr_compiler_errors.pl +179 -0
  254. package/lib/swipl/library/ext/chr/chr/chr_compiler_options.pl +382 -0
  255. package/lib/swipl/library/ext/chr/chr/chr_compiler_utility.pl +338 -0
  256. package/lib/swipl/library/ext/chr/chr/chr_debug.pl +59 -0
  257. package/lib/swipl/library/ext/chr/chr/chr_hashtable_store.pl +425 -0
  258. package/lib/swipl/library/ext/chr/chr/chr_integertable_store.pl +139 -0
  259. package/lib/swipl/library/ext/chr/chr/chr_messages.pl +176 -0
  260. package/lib/swipl/library/ext/chr/chr/chr_op.pl +53 -0
  261. package/lib/swipl/library/ext/chr/chr/chr_runtime.pl +1016 -0
  262. package/lib/swipl/library/ext/chr/chr/chr_translate.pl +25424 -0
  263. package/lib/swipl/library/ext/chr/chr/clean_code.pl +252 -0
  264. package/lib/swipl/library/ext/chr/chr/find.pl +78 -0
  265. package/lib/swipl/library/ext/chr/chr/guard_entailment.pl +19432 -0
  266. package/lib/swipl/library/ext/chr/chr/listmap.pl +108 -0
  267. package/lib/swipl/library/ext/chr/chr/pairlist.pl +78 -0
  268. package/lib/swipl/library/ext/chr/chr.pl +686 -0
  269. package/lib/swipl/library/ext/clib/INDEX.pl +158 -0
  270. package/lib/swipl/library/ext/clib/cgi.pl +86 -0
  271. package/lib/swipl/library/ext/clib/crypt.pl +44 -0
  272. package/lib/swipl/library/ext/clib/filesex.pl +644 -0
  273. package/lib/swipl/library/ext/clib/hash_stream.pl +119 -0
  274. package/lib/swipl/library/ext/clib/mallocinfo.pl +138 -0
  275. package/lib/swipl/library/ext/clib/md5.pl +68 -0
  276. package/lib/swipl/library/ext/clib/memfile.pl +61 -0
  277. package/lib/swipl/library/ext/clib/process.pl +573 -0
  278. package/lib/swipl/library/ext/clib/prolog_server.pl +157 -0
  279. package/lib/swipl/library/ext/clib/prolog_stream.pl +80 -0
  280. package/lib/swipl/library/ext/clib/rlimit.pl +54 -0
  281. package/lib/swipl/library/ext/clib/sched.pl +85 -0
  282. package/lib/swipl/library/ext/clib/sha.pl +162 -0
  283. package/lib/swipl/library/ext/clib/socket.pl +1102 -0
  284. package/lib/swipl/library/ext/clib/streaminfo.pl +103 -0
  285. package/lib/swipl/library/ext/clib/streampool.pl +136 -0
  286. package/lib/swipl/library/ext/clib/syslog.pl +180 -0
  287. package/lib/swipl/library/ext/clib/time.pl +194 -0
  288. package/lib/swipl/library/ext/clib/udp_broadcast.pl +975 -0
  289. package/lib/swipl/library/ext/clib/uid.pl +220 -0
  290. package/lib/swipl/library/ext/clib/unix.pl +317 -0
  291. package/lib/swipl/library/ext/clib/uri.pl +530 -0
  292. package/lib/swipl/library/ext/clib/uuid.pl +207 -0
  293. package/lib/swipl/library/ext/http/http/INDEX.pl +266 -0
  294. package/lib/swipl/library/ext/http/http/README.md +34 -0
  295. package/lib/swipl/library/ext/http/http/ax.pl +189 -0
  296. package/lib/swipl/library/ext/http/http/dcg_basics.pl +49 -0
  297. package/lib/swipl/library/ext/http/http/graphql.pl +1367 -0
  298. package/lib/swipl/library/ext/http/http/html_decl.pl +416 -0
  299. package/lib/swipl/library/ext/http/http/html_head.pl +654 -0
  300. package/lib/swipl/library/ext/http/http/html_quasiquotations.pl +120 -0
  301. package/lib/swipl/library/ext/http/http/html_write.pl +1425 -0
  302. package/lib/swipl/library/ext/http/http/htmx.pl +139 -0
  303. package/lib/swipl/library/ext/http/http/http_authenticate.pl +364 -0
  304. package/lib/swipl/library/ext/http/http/http_client.pl +412 -0
  305. package/lib/swipl/library/ext/http/http/http_cookie.pl +245 -0
  306. package/lib/swipl/library/ext/http/http/http_cors.pl +176 -0
  307. package/lib/swipl/library/ext/http/http/http_digest.pl +820 -0
  308. package/lib/swipl/library/ext/http/http/http_dirindex.pl +296 -0
  309. package/lib/swipl/library/ext/http/http/http_dispatch.pl +1552 -0
  310. package/lib/swipl/library/ext/http/http/http_dyn_workers.pl +214 -0
  311. package/lib/swipl/library/ext/http/http/http_error.pl +126 -0
  312. package/lib/swipl/library/ext/http/http/http_exception.pl +225 -0
  313. package/lib/swipl/library/ext/http/http/http_files.pl +163 -0
  314. package/lib/swipl/library/ext/http/http/http_header.pl +2820 -0
  315. package/lib/swipl/library/ext/http/http/http_hook.pl +106 -0
  316. package/lib/swipl/library/ext/http/http/http_host.pl +204 -0
  317. package/lib/swipl/library/ext/http/http/http_load.pl +113 -0
  318. package/lib/swipl/library/ext/http/http/http_log.pl +738 -0
  319. package/lib/swipl/library/ext/http/http/http_multipart_plugin.pl +232 -0
  320. package/lib/swipl/library/ext/http/http/http_open.pl +1821 -0
  321. package/lib/swipl/library/ext/http/http/http_openid.pl +1561 -0
  322. package/lib/swipl/library/ext/http/http/http_parameters.pl +504 -0
  323. package/lib/swipl/library/ext/http/http/http_path.pl +380 -0
  324. package/lib/swipl/library/ext/http/http/http_proxy.pl +80 -0
  325. package/lib/swipl/library/ext/http/http/http_pwp.pl +351 -0
  326. package/lib/swipl/library/ext/http/http/http_redis_plugin.pl +332 -0
  327. package/lib/swipl/library/ext/http/http/http_server.pl +105 -0
  328. package/lib/swipl/library/ext/http/http/http_server_files.pl +126 -0
  329. package/lib/swipl/library/ext/http/http/http_server_health.pl +186 -0
  330. package/lib/swipl/library/ext/http/http/http_session.pl +1040 -0
  331. package/lib/swipl/library/ext/http/http/http_sgml_plugin.pl +137 -0
  332. package/lib/swipl/library/ext/http/http/http_stream.pl +376 -0
  333. package/lib/swipl/library/ext/http/http/http_unix_daemon.pl +989 -0
  334. package/lib/swipl/library/ext/http/http/http_wrapper.pl +559 -0
  335. package/lib/swipl/library/ext/http/http/hub.pl +600 -0
  336. package/lib/swipl/library/ext/http/http/js_write.pl +461 -0
  337. package/lib/swipl/library/ext/http/http/mimepack.pl +224 -0
  338. package/lib/swipl/library/ext/http/http/mimetype.pl +276 -0
  339. package/lib/swipl/library/ext/http/http/term_html.pl +797 -0
  340. package/lib/swipl/library/ext/http/http/thread_httpd.pl +1181 -0
  341. package/lib/swipl/library/ext/http/http/web/css/dirindex.css +24 -0
  342. package/lib/swipl/library/ext/http/http/web/css/openid.css +57 -0
  343. package/lib/swipl/library/ext/http/http/web/icons/back.png +0 -0
  344. package/lib/swipl/library/ext/http/http/web/icons/c.png +0 -0
  345. package/lib/swipl/library/ext/http/http/web/icons/compressed.png +0 -0
  346. package/lib/swipl/library/ext/http/http/web/icons/folder.png +0 -0
  347. package/lib/swipl/library/ext/http/http/web/icons/generic.png +0 -0
  348. package/lib/swipl/library/ext/http/http/web/icons/layout.png +0 -0
  349. package/lib/swipl/library/ext/http/http/web/icons/openid-logo-square.png +0 -0
  350. package/lib/swipl/library/ext/http/http/web/icons/openid-logo-tiny.png +0 -0
  351. package/lib/swipl/library/ext/http/http/websocket.pl +729 -0
  352. package/lib/swipl/library/ext/http/http/yadis.pl +205 -0
  353. package/lib/swipl/library/ext/json/INDEX.pl +36 -0
  354. package/lib/swipl/library/ext/json/http/INDEX.pl +16 -0
  355. package/lib/swipl/library/ext/json/http/http_json.pl +490 -0
  356. package/lib/swipl/library/ext/json/http/js_grammar.pl +53 -0
  357. package/lib/swipl/library/ext/json/http/json.pl +48 -0
  358. package/lib/swipl/library/ext/json/http/json_convert.pl +48 -0
  359. package/lib/swipl/library/ext/json/json.pl +1215 -0
  360. package/lib/swipl/library/ext/json/json_convert.pl +681 -0
  361. package/lib/swipl/library/ext/json/json_grammar.pl +349 -0
  362. package/lib/swipl/library/ext/json/json_rpc_client.pl +423 -0
  363. package/lib/swipl/library/ext/json/json_rpc_common.pl +104 -0
  364. package/lib/swipl/library/ext/json/json_rpc_server.pl +489 -0
  365. package/lib/swipl/library/ext/json/json_schema.pl +2111 -0
  366. package/lib/swipl/library/ext/nlp/INDEX.pl +15 -0
  367. package/lib/swipl/library/ext/nlp/double_metaphone.pl +86 -0
  368. package/lib/swipl/library/ext/nlp/isub.pl +162 -0
  369. package/lib/swipl/library/ext/nlp/porter_stem.pl +50 -0
  370. package/lib/swipl/library/ext/nlp/snowball.pl +97 -0
  371. package/lib/swipl/library/ext/pcre/INDEX.pl +17 -0
  372. package/lib/swipl/library/ext/pcre/pcre.pl +974 -0
  373. package/lib/swipl/library/ext/plunit/INDEX.pl +20 -0
  374. package/lib/swipl/library/ext/plunit/plunit.pl +2631 -0
  375. package/lib/swipl/library/ext/plunit/test_wizard.pl +249 -0
  376. package/lib/swipl/library/ext/semweb/semweb/INDEX.pl +288 -0
  377. package/lib/swipl/library/ext/semweb/semweb/rdf11.pl +2106 -0
  378. package/lib/swipl/library/ext/semweb/semweb/rdf11_containers.pl +299 -0
  379. package/lib/swipl/library/ext/semweb/semweb/rdf_cache.pl +278 -0
  380. package/lib/swipl/library/ext/semweb/semweb/rdf_compare.pl +132 -0
  381. package/lib/swipl/library/ext/semweb/semweb/rdf_db.pl +3468 -0
  382. package/lib/swipl/library/ext/semweb/semweb/rdf_edit.pl +1145 -0
  383. package/lib/swipl/library/ext/semweb/semweb/rdf_http_plugin.pl +274 -0
  384. package/lib/swipl/library/ext/semweb/semweb/rdf_library.pl +1021 -0
  385. package/lib/swipl/library/ext/semweb/semweb/rdf_litindex.pl +1035 -0
  386. package/lib/swipl/library/ext/semweb/semweb/rdf_ntriples.pl +422 -0
  387. package/lib/swipl/library/ext/semweb/semweb/rdf_persistency.pl +1576 -0
  388. package/lib/swipl/library/ext/semweb/semweb/rdf_portray.pl +182 -0
  389. package/lib/swipl/library/ext/semweb/semweb/rdf_prefixes.pl +681 -0
  390. package/lib/swipl/library/ext/semweb/semweb/rdf_sandbox.pl +153 -0
  391. package/lib/swipl/library/ext/semweb/semweb/rdf_turtle.pl +54 -0
  392. package/lib/swipl/library/ext/semweb/semweb/rdf_turtle_write.pl +1587 -0
  393. package/lib/swipl/library/ext/semweb/semweb/rdf_zlib_plugin.pl +52 -0
  394. package/lib/swipl/library/ext/semweb/semweb/rdfa.pl +1510 -0
  395. package/lib/swipl/library/ext/semweb/semweb/rdfs.pl +475 -0
  396. package/lib/swipl/library/ext/semweb/semweb/sparql_client.pl +643 -0
  397. package/lib/swipl/library/ext/semweb/semweb/turtle.pl +455 -0
  398. package/lib/swipl/library/ext/sgml/DTD/HTML4.dcl +88 -0
  399. package/lib/swipl/library/ext/sgml/DTD/HTML4.dtd +1092 -0
  400. package/lib/swipl/library/ext/sgml/DTD/HTML4.soc +6 -0
  401. package/lib/swipl/library/ext/sgml/DTD/HTML5.dtd +906 -0
  402. package/lib/swipl/library/ext/sgml/DTD/HTMLlat1.ent +195 -0
  403. package/lib/swipl/library/ext/sgml/DTD/HTMLspec.ent +77 -0
  404. package/lib/swipl/library/ext/sgml/DTD/HTMLsym.ent +241 -0
  405. package/lib/swipl/library/ext/sgml/INDEX.pl +64 -0
  406. package/lib/swipl/library/ext/sgml/c14n2.pl +203 -0
  407. package/lib/swipl/library/ext/sgml/iso_639.pl +631 -0
  408. package/lib/swipl/library/ext/sgml/pwp.pl +705 -0
  409. package/lib/swipl/library/ext/sgml/sgml.pl +815 -0
  410. package/lib/swipl/library/ext/sgml/sgml_write.pl +1003 -0
  411. package/lib/swipl/library/ext/sgml/xpath.pl +620 -0
  412. package/lib/swipl/library/ext/sgml/xsdp_types.pl +232 -0
  413. package/lib/swipl/library/ext/ssl/INDEX.pl +60 -0
  414. package/lib/swipl/library/ext/ssl/crypto.pl +1015 -0
  415. package/lib/swipl/library/ext/ssl/http/INDEX.pl +5 -0
  416. package/lib/swipl/library/ext/ssl/http/http_ssl_plugin.pl +296 -0
  417. package/lib/swipl/library/ext/ssl/saml.pl +609 -0
  418. package/lib/swipl/library/ext/ssl/ssl.pl +647 -0
  419. package/lib/swipl/library/ext/ssl/xmldsig.pl +391 -0
  420. package/lib/swipl/library/ext/ssl/xmlenc.pl +354 -0
  421. package/lib/swipl/library/ext/zlib/INDEX.pl +8 -0
  422. package/lib/swipl/library/ext/zlib/zlib.pl +112 -0
  423. package/lib/swipl/library/fastrw.pl +105 -0
  424. package/lib/swipl/library/files.pl +80 -0
  425. package/lib/swipl/library/gensym.pl +111 -0
  426. package/lib/swipl/library/git.pl +1027 -0
  427. package/lib/swipl/library/hashtable.pl +365 -0
  428. package/lib/swipl/library/heaps.pl +252 -0
  429. package/lib/swipl/library/hotfix.pl +239 -0
  430. package/lib/swipl/library/http/jquery.pl +103 -0
  431. package/lib/swipl/library/http/web/js/jquery-3.6.0.min.js +2 -0
  432. package/lib/swipl/library/increval.pl +217 -0
  433. package/lib/swipl/library/intercept.pl +263 -0
  434. package/lib/swipl/library/iostream.pl +237 -0
  435. package/lib/swipl/library/iri_scheme/file.pl +70 -0
  436. package/lib/swipl/library/lazy_lists.pl +481 -0
  437. package/lib/swipl/library/listing.pl +1362 -0
  438. package/lib/swipl/library/lists.pl +860 -0
  439. package/lib/swipl/library/lynx/INDEX.pl +14 -0
  440. package/lib/swipl/library/lynx/format.pl +380 -0
  441. package/lib/swipl/library/lynx/html_style.pl +129 -0
  442. package/lib/swipl/library/lynx/html_text.pl +865 -0
  443. package/lib/swipl/library/lynx/pldoc_style.pl +87 -0
  444. package/lib/swipl/library/macros.pl +451 -0
  445. package/lib/swipl/library/main.pl +1200 -0
  446. package/lib/swipl/library/make.pl +197 -0
  447. package/lib/swipl/library/modules.pl +129 -0
  448. package/lib/swipl/library/nb_rbtrees.pl +267 -0
  449. package/lib/swipl/library/nb_set.pl +203 -0
  450. package/lib/swipl/library/obfuscate.pl +115 -0
  451. package/lib/swipl/library/occurs.pl +241 -0
  452. package/lib/swipl/library/operators.pl +182 -0
  453. package/lib/swipl/library/option.pl +388 -0
  454. package/lib/swipl/library/optparse.pl +966 -0
  455. package/lib/swipl/library/ordsets.pl +518 -0
  456. package/lib/swipl/library/oset.pl +160 -0
  457. package/lib/swipl/library/pairs.pl +187 -0
  458. package/lib/swipl/library/persistency.pl +713 -0
  459. package/lib/swipl/library/pio.pl +47 -0
  460. package/lib/swipl/library/portray_text.pl +277 -0
  461. package/lib/swipl/library/pprint.pl +940 -0
  462. package/lib/swipl/library/predicate_options.pl +975 -0
  463. package/lib/swipl/library/prolog_autoload.pl +233 -0
  464. package/lib/swipl/library/prolog_breakpoints.pl +396 -0
  465. package/lib/swipl/library/prolog_clause.pl +1104 -0
  466. package/lib/swipl/library/prolog_code.pl +416 -0
  467. package/lib/swipl/library/prolog_codewalk.pl +1248 -0
  468. package/lib/swipl/library/prolog_colour.pl +3301 -0
  469. package/lib/swipl/library/prolog_colour.qlf +0 -0
  470. package/lib/swipl/library/prolog_config.pl +154 -0
  471. package/lib/swipl/library/prolog_coverage.pl +1333 -0
  472. package/lib/swipl/library/prolog_debug.pl +404 -0
  473. package/lib/swipl/library/prolog_deps.pl +675 -0
  474. package/lib/swipl/library/prolog_evaluable.pl +234 -0
  475. package/lib/swipl/library/prolog_format.pl +219 -0
  476. package/lib/swipl/library/prolog_history.pl +161 -0
  477. package/lib/swipl/library/prolog_jiti.pl +333 -0
  478. package/lib/swipl/library/prolog_locale.pl +61 -0
  479. package/lib/swipl/library/prolog_metainference.pl +307 -0
  480. package/lib/swipl/library/prolog_pack.pl +3906 -0
  481. package/lib/swipl/library/prolog_profile.pl +346 -0
  482. package/lib/swipl/library/prolog_qlfmake.pl +533 -0
  483. package/lib/swipl/library/prolog_source.pl +1188 -0
  484. package/lib/swipl/library/prolog_stack.pl +794 -0
  485. package/lib/swipl/library/prolog_trace.pl +365 -0
  486. package/lib/swipl/library/prolog_versions.pl +347 -0
  487. package/lib/swipl/library/prolog_wrap.pl +164 -0
  488. package/lib/swipl/library/prolog_xref.pl +3090 -0
  489. package/lib/swipl/library/prolog_xref.qlf +0 -0
  490. package/lib/swipl/library/pure_input.pl +266 -0
  491. package/lib/swipl/library/qpforeign.pl +695 -0
  492. package/lib/swipl/library/qsave.pl +1516 -0
  493. package/lib/swipl/library/quasi_quotations.pl +300 -0
  494. package/lib/swipl/library/quintus.pl +437 -0
  495. package/lib/swipl/library/random.pl +459 -0
  496. package/lib/swipl/library/rbtrees.pl +1153 -0
  497. package/lib/swipl/library/readln.pl +256 -0
  498. package/lib/swipl/library/readutil.pl +304 -0
  499. package/lib/swipl/library/record.pl +544 -0
  500. package/lib/swipl/library/rwlocks.pl +172 -0
  501. package/lib/swipl/library/sandbox.pl +1384 -0
  502. package/lib/swipl/library/semweb/dc.rdfs +198 -0
  503. package/lib/swipl/library/semweb/eor.rdfs +95 -0
  504. package/lib/swipl/library/semweb/owl.owl +287 -0
  505. package/lib/swipl/library/semweb/rdf_library.ttl +90 -0
  506. package/lib/swipl/library/semweb/rdfs.rdfs +251 -0
  507. package/lib/swipl/library/settings.pl +755 -0
  508. package/lib/swipl/library/shell.pl +462 -0
  509. package/lib/swipl/library/shlib.pl +670 -0
  510. package/lib/swipl/library/solution_sequences.pl +439 -0
  511. package/lib/swipl/library/sort.pl +119 -0
  512. package/lib/swipl/library/statistics.pl +541 -0
  513. package/lib/swipl/library/streams.pl +118 -0
  514. package/lib/swipl/library/strings.pl +469 -0
  515. package/lib/swipl/library/system.pl +95 -0
  516. package/lib/swipl/library/tables.pl +381 -0
  517. package/lib/swipl/library/tableutil.pl +771 -0
  518. package/lib/swipl/library/tabling.pl +42 -0
  519. package/lib/swipl/library/terms.pl +457 -0
  520. package/lib/swipl/library/theme/auto.pl +61 -0
  521. package/lib/swipl/library/theme/dark.pl +455 -0
  522. package/lib/swipl/library/theme/light.pl +45 -0
  523. package/lib/swipl/library/thread.pl +810 -0
  524. package/lib/swipl/library/thread_pool.pl +508 -0
  525. package/lib/swipl/library/threadutil.pl +574 -0
  526. package/lib/swipl/library/tty.pl +316 -0
  527. package/lib/swipl/library/ugraphs.pl +644 -0
  528. package/lib/swipl/library/unicode/INDEX.pl +6 -0
  529. package/lib/swipl/library/unicode/blocks.pl +414 -0
  530. package/lib/swipl/library/url.pl +1129 -0
  531. package/lib/swipl/library/utf8.pl +145 -0
  532. package/lib/swipl/library/varnumbers.pl +221 -0
  533. package/lib/swipl/library/vm.pl +251 -0
  534. package/lib/swipl/library/wfs.pl +205 -0
  535. package/lib/swipl/library/when.pl +263 -0
  536. package/lib/swipl/library/writef.pl +278 -0
  537. package/lib/swipl/library/www_browser.pl +251 -0
  538. package/lib/swipl/library/yall.pl +574 -0
  539. package/lib/swipl/library/zip.pl +211 -0
  540. package/lib/swipl/swipl.home +1 -0
  541. package/lib/vendor/libcrypto.so.3 +0 -0
  542. package/lib/vendor/libpcre2-8.so.0 +0 -0
  543. package/lib/vendor/libssl.so.3 +0 -0
  544. package/lib/vendor/libz.so.1 +0 -0
  545. package/licenses/OpenSSL-LICENSE.txt +177 -0
  546. package/licenses/PCRE2-COPYING +5 -0
  547. package/licenses/README.md +12 -0
  548. package/licenses/SWI-Prolog-LICENSE +41 -0
  549. package/licenses/zlib-LICENSE +22 -0
  550. package/package.json +27 -0
@@ -0,0 +1,2631 @@
1
+ /* Part of SWI-Prolog
2
+
3
+ Author: Jan Wielemaker
4
+ E-mail: J.Wielemaker@vu.nl
5
+ WWW: http://www.swi-prolog.org
6
+ Copyright (c) 2006-2025, University of Amsterdam
7
+ VU University Amsterdam
8
+ CWI, Amsterdam
9
+ SWI-Prolog Solutions b.v.
10
+ All rights reserved.
11
+
12
+ Redistribution and use in source and binary forms, with or without
13
+ modification, are permitted provided that the following conditions
14
+ are met:
15
+
16
+ 1. Redistributions of source code must retain the above copyright
17
+ notice, this list of conditions and the following disclaimer.
18
+
19
+ 2. Redistributions in binary form must reproduce the above copyright
20
+ notice, this list of conditions and the following disclaimer in
21
+ the documentation and/or other materials provided with the
22
+ distribution.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
+ POSSIBILITY OF SUCH DAMAGE.
36
+ */
37
+
38
+ :- module(plunit,
39
+ [ set_test_options/1, % +Options
40
+ begin_tests/1, % +Name
41
+ begin_tests/2, % +Name, +Options
42
+ end_tests/1, % +Name
43
+ run_tests/0, % Run all tests
44
+ run_tests/1, % +Tests
45
+ run_tests/2, % +Tests, +Options
46
+ load_test_files/1, % +Options
47
+ running_tests/0, % Prints currently running test
48
+ current_test/5, % ?Unit,?Test,?Line,?Body,?Options
49
+ current_test_unit/2, % ?Unit,?Options
50
+ test_report/1 % +What
51
+ ]).
52
+
53
+ /** <module> Unit Testing
54
+
55
+ Unit testing environment for SWI-Prolog and SICStus Prolog. For usage,
56
+ please visit https://www.swi-prolog.org/pldoc/package/plunit.
57
+ */
58
+
59
+ :- autoload(library(statistics), [call_time/2]).
60
+ :- autoload(library(apply),
61
+ [maplist/3, include/3, maplist/2, foldl/4, partition/4]).
62
+ :- autoload(library(lists), [member/2, append/2, flatten/2, append/3]).
63
+ :- autoload(library(option), [ option/3, option/2, select_option/3 ]).
64
+ :- autoload(library(ordsets), [ord_intersection/3]).
65
+ :- autoload(library(error), [must_be/2, domain_error/2]).
66
+ :- autoload(library(aggregate), [aggregate_all/3]).
67
+ :- autoload(library(streams), [with_output_to/3]).
68
+ :- autoload(library(ansi_term), [ansi_format/3]).
69
+ :- if(exists_source(library(time))).
70
+ :- autoload(library(time), [call_with_time_limit/2]).
71
+ :- endif.
72
+
73
+ :- public
74
+ unit_module/2.
75
+
76
+ :- meta_predicate
77
+ valid_options(1, +),
78
+ count(0, -).
79
+
80
+ /*******************************
81
+ * CONDITIONAL COMPILATION *
82
+ *******************************/
83
+
84
+ swi :- catch(current_prolog_flag(dialect, swi), _, fail).
85
+ sicstus :- catch(current_prolog_flag(dialect, sicstus), _, fail).
86
+
87
+ throw_error(Error_term,Impldef) :-
88
+ throw(error(Error_term,context(Impldef,_))).
89
+
90
+ :- set_prolog_flag(generate_debug_info, false).
91
+ current_test_flag(optimise, Value) =>
92
+ current_prolog_flag(optimise, Value).
93
+ current_test_flag(occurs_check, Value) =>
94
+ ( current_prolog_flag(plunit_occurs_check, Value0)
95
+ -> Value = Value0
96
+ ; current_prolog_flag(occurs_check, Value)
97
+ ).
98
+ current_test_flag(Name, Value), atom(Name) =>
99
+ atom_concat(plunit_, Name, Flag),
100
+ current_prolog_flag(Flag, Value).
101
+ current_test_flag(Name, Value), var(Name) =>
102
+ global_test_option(Opt, _, _Type, _Default),
103
+ functor(Opt, Name, 1),
104
+ current_test_flag(Name, Value).
105
+
106
+ set_test_flag(Name, Value) :-
107
+ Opt =.. [Name, Value],
108
+ global_test_option(Opt),
109
+ !,
110
+ atom_concat(plunit_, Name, Flag),
111
+ set_prolog_flag(Flag, Value).
112
+ set_test_flag(Name, _) :-
113
+ domain_error(test_flag, Name).
114
+
115
+ current_test_flags(Flags) :-
116
+ findall(Flag, current_test_flag(Flag), Flags).
117
+
118
+ current_test_flag(Opt) :-
119
+ current_test_flag(Name, Value),
120
+ Opt =.. [Name, Value].
121
+
122
+ % ensure expansion to avoid tracing
123
+ goal_expansion(forall(C,A),
124
+ \+ (C, \+ A)).
125
+ goal_expansion(current_module(Module,File),
126
+ module_property(Module, file(File))).
127
+
128
+
129
+ /*******************************
130
+ * IMPORTS *
131
+ *******************************/
132
+
133
+ :- initialization init_flags.
134
+
135
+ init_flags :-
136
+ ( global_test_option(Option, _Value, Type, Default),
137
+ Default \== (-),
138
+ Option =.. [Name,_],
139
+ atom_concat(plunit_, Name, Flag),
140
+ flag_type(Type, FlagType),
141
+ create_prolog_flag(Flag, Default, [type(FlagType), keep(true)]),
142
+ fail
143
+ ; true
144
+ ).
145
+
146
+ flag_type(boolean, FlagType) => FlagType = boolean.
147
+ flag_type(Type, FlagType), Type = oneof(Atoms), maplist(atom, Atoms) =>
148
+ FlagType = Type.
149
+ flag_type(oneof(_), FlagType) => FlagType = term.
150
+ flag_type(positive_integer, FlagType) => FlagType = integer.
151
+ flag_type(number, FlagType) => FlagType = float.
152
+
153
+
154
+
155
+ %! set_test_options(+Options)
156
+ %
157
+ % Specifies how to deal with test suites. Defined options are:
158
+ %
159
+ % - load(+Load)
160
+ % Whether or not the tests must be loaded. Values are
161
+ % `never`, `always`, `normal` (only if not optimised)
162
+ %
163
+ % - run(+When)
164
+ % When the tests are run. Values are `manual`, `make`
165
+ % or make(all).
166
+ %
167
+ % - format(+Mode)
168
+ % Currently one of `tty` or `log`. `tty` uses terminal
169
+ % control to overwrite successful tests, allowing the
170
+ % user to see the currently running tests and output
171
+ % from failed tests. This is the default of the output
172
+ % is a tty. `log` prints a full log of the executed
173
+ % tests and their result and is intended for non-interactive
174
+ % usage.
175
+ %
176
+ % - output(+When)
177
+ % If `always`, emit all output as it is produced, if `never`,
178
+ % suppress all output and if `on_failure`, emit the output
179
+ % if the test fails.
180
+ %
181
+ % - show_blocked(+Bool)
182
+ % Show individual blocked tests during the report.
183
+ %
184
+ % - occurs_check(+Mode)
185
+ % Defines the default for the `occurs_check` flag during
186
+ % testing.
187
+ %
188
+ % - cleanup(+Bool)
189
+ % If `true` (default =false), cleanup report at the end
190
+ % of run_tests/1. Used to improve cooperation with
191
+ % memory debuggers such as dmalloc.
192
+ %
193
+ % - jobs(Num)
194
+ % Number of jobs to use for concurrent testing. Default
195
+ % is one, implying sequential testing.
196
+ %
197
+ % - timeout(+Seconds)
198
+ % Set timeout for each individual test. This acts as a
199
+ % default that may be overuled at the level of units or
200
+ % individual tests. A timeout of 0 or negative is handled
201
+ % as _inifinite_.
202
+
203
+ set_test_options(Options) :-
204
+ flatten([Options], List),
205
+ maplist(set_test_option, List).
206
+
207
+ set_test_option(sto(true)) =>
208
+ print_message(warning, plunit(sto(true))).
209
+ set_test_option(jobs(Jobs)) =>
210
+ must_be(positive_integer, Jobs),
211
+ set_test_option_flag(jobs(Jobs)).
212
+ set_test_option(Option),
213
+ compound(Option), global_test_option(Option) =>
214
+ set_test_option_flag(Option).
215
+ set_test_option(Option) =>
216
+ domain_error(option, Option).
217
+
218
+ global_test_option(Opt) :-
219
+ global_test_option(Opt, Value, Type, _Default),
220
+ must_be(Type, Value).
221
+
222
+ global_test_option(load(Load), Load, oneof([never,always,normal]), normal).
223
+ global_test_option(output(Cond), Cond, oneof([always,on_failure]), on_failure).
224
+ global_test_option(format(Feedback), Feedback, oneof([tty,log]), tty).
225
+ global_test_option(silent(Silent), Silent, boolean, false).
226
+ global_test_option(show_blocked(Blocked), Blocked, boolean, false).
227
+ global_test_option(run(When), When, oneof([manual,make,make(all)]), make).
228
+ global_test_option(occurs_check(Mode), Mode, oneof([false,true,error]), -).
229
+ global_test_option(cleanup(Bool), Bool, boolean, true).
230
+ global_test_option(jobs(Count), Count, positive_integer, 1).
231
+ global_test_option(timeout(Number), Number, number, 3600).
232
+
233
+ set_test_option_flag(Option) :-
234
+ Option =.. [Name, Value],
235
+ set_test_flag(Name, Value).
236
+
237
+ %! loading_tests
238
+ %
239
+ % True if tests must be loaded.
240
+
241
+ loading_tests :-
242
+ current_test_flag(load, Load),
243
+ ( Load == always
244
+ -> true
245
+ ; Load == normal,
246
+ \+ current_test_flag(optimise, true)
247
+ ).
248
+
249
+ /*******************************
250
+ * MODULE *
251
+ *******************************/
252
+
253
+ :- thread_local
254
+ loading_unit/4. % Unit, Module, File, OldSource
255
+ :- dynamic
256
+ current_unit/4, % Unit, Module, Context, Options
257
+ test_file_for/2. % ?TestFile, ?PrologFile
258
+
259
+ %! begin_tests(+UnitName:atom) is det.
260
+ %! begin_tests(+UnitName:atom, Options) is det.
261
+ %
262
+ % Start a test-unit. UnitName is the name of the test set. the
263
+ % unit is ended by :- end_tests(UnitName).
264
+
265
+ begin_tests(Unit) :-
266
+ begin_tests(Unit, []).
267
+
268
+ begin_tests(Unit, Options) :-
269
+ must_be(atom, Unit),
270
+ map_sto_option(Options, Options1),
271
+ valid_options(test_set_option, Options1),
272
+ make_unit_module(Unit, Name),
273
+ source_location(File, Line),
274
+ begin_tests(Unit, Name, File:Line, Options1).
275
+
276
+ map_sto_option(Options0, Options) :-
277
+ select_option(sto(Mode), Options0, Options1),
278
+ !,
279
+ map_sto(Mode, Flag),
280
+ Options = [occurs_check(Flag)|Options1].
281
+ map_sto_option(Options, Options).
282
+
283
+ map_sto(rational_trees, Flag) => Flag = false.
284
+ map_sto(finite_trees, Flag) => Flag = true.
285
+ map_sto(Mode, _) => domain_error(sto, Mode).
286
+
287
+
288
+ :- if(swi).
289
+ begin_tests(Unit, Name, File:Line, Options) :-
290
+ loading_tests,
291
+ !,
292
+ '$set_source_module'(Context, Context),
293
+ ( current_unit(Unit, Name, Context, Options)
294
+ -> true
295
+ ; retractall(current_unit(Unit, Name, _, _)),
296
+ assert(current_unit(Unit, Name, Context, Options))
297
+ ),
298
+ '$set_source_module'(Old, Name),
299
+ '$declare_module'(Name, test, Context, File, Line, false),
300
+ discontiguous(Name:'unit test'/4),
301
+ '$set_predicate_attribute'(Name:'unit test'/4, trace, false),
302
+ discontiguous(Name:'unit body'/2),
303
+ asserta(loading_unit(Unit, Name, File, Old)).
304
+ begin_tests(Unit, Name, File:_Line, _Options) :-
305
+ '$set_source_module'(Old, Old),
306
+ asserta(loading_unit(Unit, Name, File, Old)).
307
+
308
+ :- else.
309
+
310
+ % we cannot use discontiguous as a goal in SICStus Prolog.
311
+
312
+ user:term_expansion((:- begin_tests(Set)),
313
+ [ (:- begin_tests(Set)),
314
+ (:- discontiguous(test/2)),
315
+ (:- discontiguous('unit body'/2)),
316
+ (:- discontiguous('unit test'/4))
317
+ ]).
318
+
319
+ begin_tests(Unit, Name, File:_Line, Options) :-
320
+ loading_tests,
321
+ !,
322
+ ( current_unit(Unit, Name, _, Options)
323
+ -> true
324
+ ; retractall(current_unit(Unit, Name, _, _)),
325
+ assert(current_unit(Unit, Name, -, Options))
326
+ ),
327
+ asserta(loading_unit(Unit, Name, File, -)).
328
+ begin_tests(Unit, Name, File:_Line, _Options) :-
329
+ asserta(loading_unit(Unit, Name, File, -)).
330
+
331
+ :- endif.
332
+
333
+ %! end_tests(+Name) is det.
334
+ %
335
+ % Close a unit-test module.
336
+ %
337
+ % @tbd Run tests/clean module?
338
+ % @tbd End of file?
339
+
340
+ end_tests(Unit) :-
341
+ loading_unit(StartUnit, _, _, _),
342
+ !,
343
+ ( Unit == StartUnit
344
+ -> once(retract(loading_unit(StartUnit, _, _, Old))),
345
+ '$set_source_module'(_, Old)
346
+ ; throw_error(context_error(plunit_close(Unit, StartUnit)), _)
347
+ ).
348
+ end_tests(Unit) :-
349
+ throw_error(context_error(plunit_close(Unit, -)), _).
350
+
351
+ %! make_unit_module(+Name, -ModuleName) is det.
352
+ %! unit_module(+Name, -ModuleName) is det.
353
+
354
+ :- if(swi).
355
+
356
+ unit_module(Unit, Module) :-
357
+ atom_concat('plunit_', Unit, Module).
358
+
359
+ make_unit_module(Unit, Module) :-
360
+ unit_module(Unit, Module),
361
+ ( current_module(Module),
362
+ \+ current_unit(_, Module, _, _),
363
+ predicate_property(Module:H, _P),
364
+ \+ predicate_property(Module:H, imported_from(_M))
365
+ -> throw_error(permission_error(create, plunit, Unit),
366
+ 'Existing module')
367
+ ; true
368
+ ).
369
+
370
+ :- else.
371
+
372
+ :- dynamic
373
+ unit_module_store/2.
374
+
375
+ unit_module(Unit, Module) :-
376
+ unit_module_store(Unit, Module),
377
+ !.
378
+
379
+ make_unit_module(Unit, Module) :-
380
+ prolog_load_context(module, Module),
381
+ assert(unit_module_store(Unit, Module)).
382
+
383
+ :- endif.
384
+
385
+ /*******************************
386
+ * EXPANSION *
387
+ *******************************/
388
+
389
+ %! expand_test(+Name, +Options, +Body, -Clause) is det.
390
+ %
391
+ % Expand test(Name, Options) :- Body into a clause for
392
+ % 'unit test'/4 and 'unit body'/2.
393
+
394
+ expand_test(Name, Options0, Body,
395
+ [ 'unit test'(Name, Line, Options, Module:'unit body'(Id, Vars)),
396
+ ('unit body'(Id, Vars) :- !, Body)
397
+ ]) :-
398
+ source_location(_File, Line),
399
+ prolog_load_context(module, Module),
400
+ ( prolog_load_context(variable_names, Bindings)
401
+ -> true
402
+ ; Bindings = []
403
+ ),
404
+ atomic_list_concat([Name, '@line ', Line], Id),
405
+ term_variables(Options0, OptionVars0), sort(OptionVars0, OptionVars),
406
+ term_variables(Body, BodyVars0), sort(BodyVars0, BodyVars),
407
+ ord_intersection(OptionVars, BodyVars, VarList),
408
+ Vars =.. [vars|VarList],
409
+ ( is_list(Options0) % allow for single option without list
410
+ -> Options1 = Options0
411
+ ; Options1 = [Options0]
412
+ ),
413
+ maplist(expand_option(Bindings), Options1, Options2),
414
+ join_true_options(Options2, Options3),
415
+ map_sto_option(Options3, Options4),
416
+ valid_options(test_option, Options4),
417
+ valid_test_mode(Options4, Options).
418
+
419
+ expand_option(_, Var, _) :-
420
+ var(Var),
421
+ !,
422
+ throw_error(instantiation_error,_).
423
+ expand_option(Bindings, Cmp, true(Cond)) :-
424
+ cmp(Cmp),
425
+ !,
426
+ var_cmp(Bindings, Cmp, Cond).
427
+ expand_option(_, error(X), throws(error(X, _))) :- !.
428
+ expand_option(_, exception(X), throws(X)) :- !. % SICStus 4 compatibility
429
+ expand_option(_, error(F,C), throws(error(F,C))) :- !. % SICStus 4 compatibility
430
+ expand_option(_, true, true(true)) :- !.
431
+ expand_option(_, O, O).
432
+
433
+ cmp(_ == _).
434
+ cmp(_ = _).
435
+ cmp(_ =@= _).
436
+ cmp(_ =:= _).
437
+
438
+ var_cmp(Bindings, Expr, cmp(Name, Expr)) :-
439
+ arg(_, Expr, Var),
440
+ var(Var),
441
+ member(Name=V, Bindings),
442
+ V == Var,
443
+ !.
444
+ var_cmp(_, Expr, Expr).
445
+
446
+ join_true_options(Options0, Options) :-
447
+ partition(true_option, Options0, True, Rest),
448
+ True \== [],
449
+ !,
450
+ maplist(arg(1), True, Conds0),
451
+ flatten(Conds0, Conds),
452
+ Options = [true(Conds)|Rest].
453
+ join_true_options(Options, Options).
454
+
455
+ true_option(true(_)).
456
+
457
+ valid_test_mode(Options0, Options) :-
458
+ include(test_mode, Options0, Tests),
459
+ ( Tests == []
460
+ -> Options = [true([true])|Options0]
461
+ ; Tests = [_]
462
+ -> Options = Options0
463
+ ; throw_error(plunit(incompatible_options, Tests), _)
464
+ ).
465
+
466
+ test_mode(true(_)).
467
+ test_mode(all(_)).
468
+ test_mode(set(_)).
469
+ test_mode(fail).
470
+ test_mode(throws(_)).
471
+
472
+
473
+ %! expand(+Term, -Clauses) is semidet.
474
+
475
+ expand(end_of_file, _) :-
476
+ loading_unit(Unit, _, _, _),
477
+ !,
478
+ end_tests(Unit), % warn?
479
+ fail.
480
+ expand((:-end_tests(_)), _) :-
481
+ !,
482
+ fail.
483
+ expand(_Term, []) :-
484
+ \+ loading_tests.
485
+ expand((test(Name) :- Body), Clauses) :-
486
+ !,
487
+ expand_test(Name, [], Body, Clauses).
488
+ expand((test(Name, Options) :- Body), Clauses) :-
489
+ !,
490
+ expand_test(Name, Options, Body, Clauses).
491
+ expand(test(Name), _) :-
492
+ !,
493
+ throw_error(existence_error(body, test(Name)), _).
494
+ expand(test(Name, _Options), _) :-
495
+ !,
496
+ throw_error(existence_error(body, test(Name)), _).
497
+
498
+ :- multifile
499
+ system:term_expansion/2.
500
+
501
+ system:term_expansion(Term, Expanded) :-
502
+ ( loading_unit(_, _, File, _)
503
+ -> source_location(ThisFile, _),
504
+ ( File == ThisFile
505
+ -> true
506
+ ; source_file_property(ThisFile, included_in(File, _))
507
+ ),
508
+ expand(Term, Expanded)
509
+ ).
510
+
511
+
512
+ /*******************************
513
+ * OPTIONS *
514
+ *******************************/
515
+
516
+ %! valid_options(:Pred, +Options) is det.
517
+ %
518
+ % Verify Options to be a list of valid options according to
519
+ % Pred.
520
+ %
521
+ % @error `type_error` or `instantiation_error`.
522
+
523
+ valid_options(Pred, Options) :-
524
+ must_be(list, Options),
525
+ verify_options(Options, Pred).
526
+
527
+ verify_options([], _).
528
+ verify_options([H|T], Pred) :-
529
+ ( call(Pred, H)
530
+ -> verify_options(T, Pred)
531
+ ; throw_error(domain_error(Pred, H), _)
532
+ ).
533
+
534
+ valid_options(Pred, Options0, Options, Rest) :-
535
+ must_be(list, Options0),
536
+ partition(Pred, Options0, Options, Rest).
537
+
538
+ %! test_option(+Option) is semidet.
539
+ %
540
+ % True if Option is a valid option for test(Name, Options).
541
+
542
+ test_option(Option) :-
543
+ test_set_option(Option),
544
+ !.
545
+ test_option(true(_)).
546
+ test_option(fail).
547
+ test_option(throws(_)).
548
+ test_option(all(_)).
549
+ test_option(set(_)).
550
+ test_option(nondet).
551
+ test_option(fixme(_)).
552
+ test_option(forall(X)) :-
553
+ must_be(callable, X).
554
+ test_option(timeout(Seconds)) :-
555
+ must_be(number, Seconds).
556
+
557
+ %! test_option(+Option) is semidet.
558
+ %
559
+ % True if Option is a valid option for :- begin_tests(Name,
560
+ % Options).
561
+
562
+ test_set_option(blocked(X)) :-
563
+ must_be(ground, X).
564
+ test_set_option(condition(X)) :-
565
+ must_be(callable, X).
566
+ test_set_option(setup(X)) :-
567
+ must_be(callable, X).
568
+ test_set_option(cleanup(X)) :-
569
+ must_be(callable, X).
570
+ test_set_option(occurs_check(V)) :-
571
+ must_be(oneof([false,true,error]), V).
572
+ test_set_option(concurrent(V)) :-
573
+ must_be(boolean, V),
574
+ print_message(informational, plunit(concurrent)).
575
+ test_set_option(timeout(Seconds)) :-
576
+ must_be(number, Seconds).
577
+
578
+ /*******************************
579
+ * UTIL *
580
+ *******************************/
581
+
582
+ :- meta_predicate
583
+ reify_tmo(0, -, +),
584
+ reify(0, -),
585
+ capture_output(0,-),
586
+ capture_output(0,-,+),
587
+ got_messages(0,-).
588
+
589
+ %! reify_tmo(:Goal, -Result, +Options) is det.
590
+
591
+ :- if(current_predicate(call_with_time_limit/2)).
592
+ reify_tmo(Goal, Result, Options) :-
593
+ option(timeout(Time), Options),
594
+ Time > 0,
595
+ !,
596
+ reify(call_with_time_limit(Time, Goal), Result0),
597
+ ( Result0 = throw(time_limit_exceeded)
598
+ -> Result = throw(time_limit_exceeded(Time))
599
+ ; Result = Result0
600
+ ).
601
+ :- endif.
602
+ reify_tmo(Goal, Result, _Options) :-
603
+ reify(Goal, Result).
604
+
605
+ %! reify(:Goal, -Result) is det.
606
+ %
607
+ % Call Goal and unify Result with one of `true`, `false` or
608
+ % `throw(E)`.
609
+
610
+ reify(Goal, Result) :-
611
+ ( catch(Goal, E, true)
612
+ -> ( var(E)
613
+ -> Result = true
614
+ ; Result = throw(E)
615
+ )
616
+ ; Result = false
617
+ ).
618
+
619
+ %! capture_output(:Goal, -Output) is semidet.
620
+ %! capture_output(:Goal, -Output, +Options) is semidet.
621
+ %
622
+ % @arg Output is a pair `Msgs-String`, where `Msgs` is a boolean that
623
+ % is true if there were messages that require a non-zero exit status
624
+ % and Output contains the output as a string.
625
+
626
+ capture_output(Goal, Output) :-
627
+ current_test_flag(output, OutputMode),
628
+ capture_output(Goal, Output, [output(OutputMode)]).
629
+
630
+ capture_output(Goal, Msgs-Output, Options) :-
631
+ option(output(How), Options, always),
632
+ ( How == always
633
+ -> call(Goal),
634
+ Msgs = false % irrelavant
635
+ ; with_output_to(string(Output), got_messages(Goal, Msgs),
636
+ [ capture([user_output, user_error]),
637
+ color(true)
638
+ ])
639
+ ).
640
+
641
+ %! got_messages(:Goal, -Result)
642
+
643
+ got_messages(Goal, Result) :-
644
+ ( current_prolog_flag(on_warning, status)
645
+ ; current_prolog_flag(on_error, status)
646
+ ), !,
647
+ nb_delete(plunit_got_message),
648
+ setup_call_cleanup(
649
+ asserta(( user:thread_message_hook(_Term, Kind, _Lines) :-
650
+ got_message(Kind), fail), Ref),
651
+ Goal,
652
+ erase(Ref)),
653
+ ( nb_current(plunit_got_message, true)
654
+ -> Result = true
655
+ ; Result = false
656
+ ).
657
+ got_messages(Goal, false) :-
658
+ call(Goal).
659
+
660
+ :- public got_message/1.
661
+ got_message(warning) :-
662
+ current_prolog_flag(on_warning, status), !,
663
+ nb_setval(plunit_got_message, true).
664
+ got_message(error) :-
665
+ current_prolog_flag(on_error, status), !,
666
+ nb_setval(plunit_got_message, true).
667
+
668
+
669
+ /*******************************
670
+ * RUNNING TOPLEVEL *
671
+ *******************************/
672
+
673
+ :- dynamic
674
+ output_streams/2, % Output, Error
675
+ test_count/1, % Count
676
+ passed/5, % Unit, Test, Line, Det, Time
677
+ failed/5, % Unit, Test, Line, Reason, Time
678
+ timeout/5, % Unit, Test, Line, Limit, Time
679
+ failed_assertion/7, % Unit, Test, Line, ALoc, STO, Reason, Goal
680
+ blocked/4, % Unit, Test, Line, Reason
681
+ fixme/5, % Unit, Test, Line, Reason, Status
682
+ running/5, % Unit, Test, Line, STO, Thread
683
+ forall_failures/2. % Nth, Failures
684
+
685
+ %! run_tests is semidet.
686
+ %! run_tests(+TestSet) is semidet.
687
+ %! run_tests(+TestSet, +Options) is semidet.
688
+ %
689
+ % Run tests and report about the results. The predicate run_tests/0
690
+ % runs all known tests that are not blocked. The predicate run_tests/1
691
+ % takes a specification of tests to run.
692
+ %
693
+ % The predicate run_tests/2 is synchronized. Concurrent testing may
694
+ % be achieved using the relevant options. See
695
+ % set_test_options/1. Options are passed to set_test_options/1. In
696
+ % addition the following options are processed:
697
+ %
698
+ % - summary(-Summary)
699
+ % Unify Summary do a dict holding the keys below. The value of
700
+ % these keys is an integer describing the number of tests. If
701
+ % this option is given, run_tests/2 does not fail if some tests
702
+ % failed.
703
+ %
704
+ % - total
705
+ % - passed
706
+ % - failed
707
+ % - timeout
708
+ % - blocked
709
+ %
710
+ % @arg TestSet is either a single specification or a list of
711
+ % specifications. Each single specification is either the name of a
712
+ % test-unit or a term <test-unit>:<test>, denoting a single test
713
+ % within a unit. If TestSet is `all`, all known tests are executed.
714
+
715
+ run_tests :-
716
+ run_tests(all).
717
+
718
+ run_tests(Set) :-
719
+ run_tests(Set, []).
720
+
721
+ run_tests(all, Options) :-
722
+ !,
723
+ findall(Unit, current_test_unit(Unit,_), Units),
724
+ run_tests(Units, Options).
725
+ run_tests(Set, Options) :-
726
+ valid_options(global_test_option, Options, Global, Rest),
727
+ current_test_flags(Old),
728
+ setup_call_cleanup(
729
+ set_test_options(Global),
730
+ ( flatten([Set], List),
731
+ maplist(runnable_tests, List, Units),
732
+ with_mutex(plunit, run_tests_sync(Units, Rest))
733
+ ),
734
+ set_test_options(Old)).
735
+
736
+ run_tests_sync(Units0, Options) :-
737
+ cleanup,
738
+ count_tests(Units0, Units, Count),
739
+ asserta(test_count(Count)),
740
+ save_output_state,
741
+ setup_call_cleanup(
742
+ setup_trap_assertions(Ref),
743
+ call_time(setup_jobs_and_run_units(Count, Units, Summary, Options),
744
+ Time),
745
+ report_and_cleanup(Ref, Time, Options)),
746
+ ( option(summary(Summary), Options)
747
+ -> true
748
+ ; test_summary_passed(Summary) % fail if some test failed
749
+ ).
750
+
751
+ setup_jobs_and_run_units(Count, Units, Summary, Options) :-
752
+ setup_call_cleanup(
753
+ setup_jobs(Count),
754
+ ( run_units(Units, Options),
755
+ test_summary(_All, Summary)
756
+ ),
757
+ cleanup_jobs).
758
+
759
+ %! report_and_cleanup(+Ref, +Time, +Options)
760
+ %
761
+ % Undo changes to the environment (trapping assertions), report the
762
+ % results and cleanup.
763
+
764
+ report_and_cleanup(Ref, Time, Options) :-
765
+ cleanup_trap_assertions(Ref),
766
+ report(Time, Options),
767
+ cleanup_after_test.
768
+
769
+
770
+ %! run_units_and_check_errors(+Units, +Options) is semidet.
771
+ %
772
+ % Run all test units and succeed if all tests passed.
773
+
774
+ run_units(Units, _Options) :-
775
+ maplist(schedule_unit, Units),
776
+ job_wait(_).
777
+
778
+ %! runnable_tests(+Spec, -Plan) is det.
779
+ %
780
+ % Change a Unit+Test spec into a plain `Unit:Tests` lists, where
781
+ % blocked tests or tests whose condition fails are already removed.
782
+ % Each test in `Tests` is a term `@(Test,Line)`, which serves as a
783
+ % unique identifier of the test.
784
+
785
+ :- det(runnable_tests/2).
786
+ runnable_tests(Spec, Unit:RunnableTests) :-
787
+ unit_from_spec(Spec, Unit, Tests, Module, UnitOptions),
788
+ ( option(blocked(Reason), UnitOptions)
789
+ -> info(plunit(blocked(unit(Unit, Reason)))),
790
+ RunnableTests = []
791
+ ; \+ condition(Module, unit(Unit), UnitOptions)
792
+ -> RunnableTests = []
793
+ ; var(Tests)
794
+ -> findall(TestID,
795
+ runnable_test(Unit, _Test, Module, TestID),
796
+ RunnableTests)
797
+ ; flatten([Tests], TestList),
798
+ findall(TestID,
799
+ ( member(Test, TestList),
800
+ runnable_test(Unit,Test,Module, TestID)
801
+ ),
802
+ RunnableTests)
803
+ ).
804
+
805
+ runnable_test(Unit, Name, Module, @(Test,Line)) :-
806
+ current_test(Unit, Name, Line, _Body, TestOptions),
807
+ ( option(blocked(Reason), TestOptions)
808
+ -> Test = blocked(Name, Reason)
809
+ ; condition(Module, test(Unit,Name,Line), TestOptions),
810
+ Test = Name
811
+ ).
812
+
813
+ unit_from_spec(Unit0:Tests0, Unit, Tests, Module, Options), atom(Unit0) =>
814
+ Unit = Unit0,
815
+ Tests = Tests0,
816
+ ( current_unit(Unit, Module, _Supers, Options)
817
+ -> true
818
+ ; throw_error(existence_error(unit_test, Unit), _)
819
+ ).
820
+ unit_from_spec(Unit0, Unit, _, Module, Options), atom(Unit0) =>
821
+ Unit = Unit0,
822
+ ( current_unit(Unit, Module, _Supers, Options)
823
+ -> true
824
+ ; throw_error(existence_error(unit_test, Unit), _)
825
+ ).
826
+
827
+ %! count_tests(+Units0, -Units, -Count) is det.
828
+ %
829
+ % Count the number of tests to run. A forall(Generator, Test) counts
830
+ % as a single test. During the execution, the concrete tests of the
831
+ % _forall_ are considered "sub tests".
832
+
833
+ count_tests(Units0, Units, Count) :-
834
+ count_tests(Units0, Units, 0, Count).
835
+
836
+ count_tests([], T, C0, C) =>
837
+ T = [],
838
+ C = C0.
839
+ count_tests([_:[]|T0], T, C0, C) =>
840
+ count_tests(T0, T, C0, C).
841
+ count_tests([Unit:Tests|T0], T, C0, C) =>
842
+ partition(is_blocked, Tests, Blocked, Use),
843
+ maplist(assert_blocked(Unit), Blocked),
844
+ ( Use == []
845
+ -> count_tests(T0, T, C0, C)
846
+ ; length(Use, N),
847
+ C1 is C0+N,
848
+ T = [Unit:Use|T1],
849
+ count_tests(T0, T1, C1, C)
850
+ ).
851
+
852
+ is_blocked(@(blocked(_,_),_)) => true.
853
+ is_blocked(_) => fail.
854
+
855
+ assert_blocked(Unit, @(blocked(Test, Reason), Line)) =>
856
+ assert(blocked(Unit, Test, Line, Reason)).
857
+
858
+ %! run_unit(+Unit) is det.
859
+ %
860
+ % Run a single test unit. Unit is a term Unit:Tests, where Tests is a
861
+ % list of tests to run.
862
+
863
+ run_unit(_Unit:[]) =>
864
+ true.
865
+ run_unit(Unit:Tests) =>
866
+ unit_module(Unit, Module),
867
+ unit_options(Unit, UnitOptions),
868
+ ( setup(Module, unit(Unit), UnitOptions)
869
+ -> begin_unit(Unit),
870
+ call_time(run_unit_2(Unit, Tests), Time),
871
+ test_summary(Unit, Summary),
872
+ end_unit(Unit, Summary.put(time, Time)),
873
+ cleanup(Module, UnitOptions)
874
+ ; job_info(end(unit(Unit, _{error:setup_failed})))
875
+ ).
876
+
877
+ begin_unit(Unit) :-
878
+ job_info(begin(unit(Unit))),
879
+ job_feedback(informational, begin(Unit)).
880
+
881
+ end_unit(Unit, Summary) :-
882
+ job_info(end(unit(Unit, Summary))),
883
+ job_feedback(informational, end(Unit, Summary)).
884
+
885
+ run_unit_2(Unit, Tests) :-
886
+ forall(member(Test, Tests),
887
+ run_test(Unit, Test)).
888
+
889
+
890
+ unit_options(Unit, Options) :-
891
+ current_unit(Unit, _Module, _Supers, Options).
892
+
893
+
894
+ cleanup :-
895
+ set_flag(plunit_test, 1),
896
+ retractall(output_streams(_,_)),
897
+ retractall(test_count(_)),
898
+ retractall(passed(_, _, _, _, _)),
899
+ retractall(failed(_, _, _, _, _)),
900
+ retractall(timeout(_, _, _, _, _)),
901
+ retractall(failed_assertion(_, _, _, _, _, _, _)),
902
+ retractall(blocked(_, _, _, _)),
903
+ retractall(fixme(_, _, _, _, _)),
904
+ retractall(running(_,_,_,_,_)),
905
+ retractall(forall_failures(_,_)).
906
+
907
+ cleanup_after_test :-
908
+ ( current_test_flag(cleanup, true)
909
+ -> cleanup
910
+ ; true
911
+ ).
912
+
913
+
914
+ %! run_tests_in_files(+Files:list) is det.
915
+ %
916
+ % Run all test-units that appear in the given Files.
917
+
918
+ run_tests_in_files(Files) :-
919
+ findall(Unit, unit_in_files(Files, Unit), Units),
920
+ ( Units == []
921
+ -> true
922
+ ; run_tests(Units)
923
+ ).
924
+
925
+ unit_in_files(Files, Unit) :-
926
+ is_list(Files),
927
+ !,
928
+ member(F, Files),
929
+ absolute_file_name(F, Source,
930
+ [ file_type(prolog),
931
+ access(read),
932
+ file_errors(fail)
933
+ ]),
934
+ unit_file(Unit, Source).
935
+
936
+
937
+ /*******************************
938
+ * HOOKING MAKE/0 *
939
+ *******************************/
940
+
941
+ %! make_run_tests(+Files)
942
+ %
943
+ % Called indirectly from make/0 after Files have been reloaded.
944
+
945
+ make_run_tests(Files) :-
946
+ current_test_flag(run, When),
947
+ ( When == make
948
+ -> run_tests_in_files(Files)
949
+ ; When == make(all)
950
+ -> run_tests
951
+ ; true
952
+ ).
953
+
954
+ /*******************************
955
+ * ASSERTION HANDLING *
956
+ *******************************/
957
+
958
+ :- if(swi).
959
+
960
+ :- dynamic prolog:assertion_failed/2.
961
+
962
+ setup_trap_assertions(Ref) :-
963
+ asserta((prolog:assertion_failed(Reason, Goal) :-
964
+ test_assertion_failed(Reason, Goal)),
965
+ Ref).
966
+
967
+ cleanup_trap_assertions(Ref) :-
968
+ erase(Ref).
969
+
970
+ test_assertion_failed(Reason, Goal) :-
971
+ thread_self(Me),
972
+ running(Unit, Test, Line, Progress, Me),
973
+ ( catch(get_prolog_backtrace(10, Stack), _, fail),
974
+ assertion_location(Stack, AssertLoc)
975
+ -> true
976
+ ; AssertLoc = unknown
977
+ ),
978
+ report_failed_assertion(Unit:Test, Line, AssertLoc,
979
+ Progress, Reason, Goal),
980
+ assert_cyclic(failed_assertion(Unit, Test, Line, AssertLoc,
981
+ Progress, Reason, Goal)).
982
+
983
+ assertion_location(Stack, File:Line) :-
984
+ append(_, [AssertFrame,CallerFrame|_], Stack),
985
+ prolog_stack_frame_property(AssertFrame,
986
+ predicate(prolog_debug:assertion/1)),
987
+ !,
988
+ prolog_stack_frame_property(CallerFrame, location(File:Line)).
989
+
990
+ report_failed_assertion(UnitTest, Line, AssertLoc,
991
+ Progress, Reason, Goal) :-
992
+ print_message(
993
+ error,
994
+ plunit(failed_assertion(UnitTest, Line, AssertLoc,
995
+ Progress, Reason, Goal))).
996
+
997
+ :- else.
998
+
999
+ setup_trap_assertions(_).
1000
+ cleanup_trap_assertions(_).
1001
+
1002
+ :- endif.
1003
+
1004
+
1005
+ /*******************************
1006
+ * RUNNING A TEST *
1007
+ *******************************/
1008
+
1009
+ %! run_test(+Unit, +Test) is det.
1010
+ %
1011
+ % Run a single test.
1012
+
1013
+ run_test(Unit, @(Test,Line)) :-
1014
+ unit_module(Unit, Module),
1015
+ Module:'unit test'(Test, Line, TestOptions, Body),
1016
+ unit_options(Unit, UnitOptions),
1017
+ run_test(Unit, Test, Line, UnitOptions, TestOptions, Body).
1018
+
1019
+ %! run_test(+Unit, +Name, +Line, +UnitOptions, +Options, +Body)
1020
+ %
1021
+ % Deals with forall(Generator, Test)
1022
+
1023
+ run_test(Unit, Name, Line, UnitOptions, Options, Body) :-
1024
+ option(forall(Generator), Options),
1025
+ !,
1026
+ unit_module(Unit, Module),
1027
+ start_test(Unit, @(Name,Line), Nth),
1028
+ State = state(0),
1029
+ call_time(forall(Module:Generator, % may become concurrent
1030
+ ( incr_forall(State, I),
1031
+ run_test_once6(Unit, Name,
1032
+ forall(Generator, Nth-I), Line,
1033
+ UnitOptions, Options, Body)
1034
+ )),
1035
+ Time),
1036
+ arg(1, State, Generated),
1037
+ progress(Unit:Name, Nth, forall(end, Nth, Generated), Time).
1038
+ run_test(Unit, Name, Line, UnitOptions, Options, Body) :-
1039
+ start_test(Unit, @(Name,Line), Nth),
1040
+ run_test_once6(Unit, Name, Nth, Line, UnitOptions, Options, Body).
1041
+
1042
+ start_test(_Unit, _TestID, Nth) :-
1043
+ flag(plunit_test, Nth, Nth+1).
1044
+
1045
+ incr_forall(State, I) :-
1046
+ arg(1, State, I0),
1047
+ I is I0+1,
1048
+ nb_setarg(1, State, I).
1049
+
1050
+ %! run_test_once6(+Unit, +Name, +Progress, +Line, +UnitOptions,
1051
+ %! +Options, +Body)
1052
+ %
1053
+ % Inherit the `timeout` and `occurs_check` option (Global -> Unit -> Test).
1054
+
1055
+ run_test_once6(Unit, Name, Progress, Line, UnitOptions, Options, Body) :-
1056
+ current_test_flag(timeout, DefTimeOut),
1057
+ current_test_flag(occurs_check, DefOccurs),
1058
+ inherit_option(timeout, Options, [UnitOptions], DefTimeOut, Options1),
1059
+ inherit_option(occurs_check, Options1, [UnitOptions], DefOccurs, Options2),
1060
+ run_test_once(Unit, Name, Progress, Line, Options2, Body).
1061
+
1062
+ inherit_option(Name, Options0, Chain, Default, Options) :-
1063
+ Term =.. [Name,_Value],
1064
+ ( option(Term, Options0)
1065
+ -> Options = Options0
1066
+ ; member(Opts, Chain),
1067
+ option(Term, Opts)
1068
+ -> Options = [Term|Options0]
1069
+ ; Default == (-)
1070
+ -> Options = Options0
1071
+ ; Opt =.. [Name,Default],
1072
+ Options = [Opt|Options0]
1073
+ ).
1074
+
1075
+ %! run_test_once(+Unit, +Name, +Progress, +Line, +Options, +Body)
1076
+ %
1077
+ % Deal with occurs_check, i.e., running the test multiple times with different
1078
+ % unification settings wrt. the occurs check.
1079
+
1080
+ run_test_once(Unit, Name, Progress, Line, Options, Body) :-
1081
+ option(occurs_check(Occurs), Options),
1082
+ !,
1083
+ begin_test(Unit, Name, Line, Progress),
1084
+ current_prolog_flag(occurs_check, Old),
1085
+ setup_call_cleanup(
1086
+ set_prolog_flag(occurs_check, Occurs),
1087
+ capture_output(run_test_6(Unit, Name, Line, Options, Body, Result),
1088
+ Output),
1089
+ set_prolog_flag(occurs_check, Old)),
1090
+ end_test(Unit, Name, Line, Progress),
1091
+ report_result(Result, Progress, Output, Options).
1092
+ run_test_once(Unit, Name, Progress, Line, Options, Body) :-
1093
+ begin_test(Unit, Name, Line, Progress),
1094
+ capture_output(run_test_6(Unit, Name, Line, Options, Body, Result),
1095
+ Output),
1096
+ end_test(Unit, Name, Line, Progress),
1097
+ report_result(Result, Progress, Output, Options).
1098
+
1099
+ %! report_result(+Result, +Progress, +Output, +Options) is det.
1100
+
1101
+ :- det(report_result/4).
1102
+ report_result(failure(Unit, Name, Line, How, Time),
1103
+ Progress, Output, Options) =>
1104
+ failure(Unit, Name, Progress, Line, How, Time, Output, Options).
1105
+ report_result(success(Unit, Name, Line, Determinism, Time),
1106
+ Progress, Output, Options) =>
1107
+ success(Unit, Name, Progress, Line, Determinism, Time, Output, Options).
1108
+ report_result(setup_failed(Unit, Name, Line, Time, Output, Result),
1109
+ Progress, _Output, Options) =>
1110
+ failure(Unit, Name, Progress, Line,
1111
+ setup_failed(Result), Time, Output, Options).
1112
+
1113
+ %! run_test_6(+Unit, +Name, +Line, +Options, :Body, -Result) is det.
1114
+ %
1115
+ % 6th step of the tests. Deals with tests that must be ignored
1116
+ % (blocked, conditions fails), setup and cleanup at the test level.
1117
+ % Result is one of:
1118
+ %
1119
+ % - failure(Unit, Name, Line, How, Time)
1120
+ % How is one of:
1121
+ % - succeeded
1122
+ % - Exception
1123
+ % - time_limit_exceeded(Limit)
1124
+ % - cmp_error(Cmp, E)
1125
+ % - wrong_answer(Cmp)
1126
+ % - failed
1127
+ % - no_exception
1128
+ % - wrong_error(Expect, E)
1129
+ % - wrong_answer(Expected, Bindings)
1130
+ % - success(Unit, Name, Line, Determinism, Time)
1131
+ % - setup_failed(Unit, Name, Line)
1132
+
1133
+ run_test_6(Unit, Name, Line, Options, Body, Result) :-
1134
+ option(setup(Setup), Options),
1135
+ !,
1136
+ unit_module(Unit, Module),
1137
+ capture_output(call_time(reify(call_ex(Module, Setup), SetupResult),
1138
+ Time),
1139
+ Output),
1140
+ ( SetupResult == true
1141
+ -> run_test_7(Unit, Name, Line, Options, Body, Result),
1142
+ cleanup(Module, Options)
1143
+ ; Result = setup_failed(Unit, Name, Line, Time, Output, SetupResult)
1144
+ ).
1145
+ run_test_6(Unit, Name, Line, Options, Body, Result) :-
1146
+ unit_module(Unit, Module),
1147
+ run_test_7(Unit, Name, Line, Options, Body, Result),
1148
+ cleanup(Module, Options).
1149
+
1150
+ %! run_test_7(+Unit, +Name, +Line, +Options, :Body, -Result) is det.
1151
+ %
1152
+ % This step deals with the expected outcome of the test. It runs
1153
+ % the actual test and then compares the result to the outcome.
1154
+ % There are two main categories: dealing with a single result and
1155
+ % all results.
1156
+
1157
+ run_test_7(Unit, Name, Line, Options, Body, Result) :-
1158
+ option(true(Cmp), Options), % expected success
1159
+ !,
1160
+ unit_module(Unit, Module),
1161
+ call_time(reify_tmo(call_det(Module:Body, Det), Result0, Options), Time),
1162
+ ( Result0 == true
1163
+ -> cmp_true(Cmp, Module, CmpResult),
1164
+ ( CmpResult == []
1165
+ -> Result = success(Unit, Name, Line, Det, Time)
1166
+ ; Result = failure(Unit, Name, Line, CmpResult, Time)
1167
+ )
1168
+ ; Result0 == false
1169
+ -> Result = failure(Unit, Name, Line, failed, Time)
1170
+ ; Result0 = throw(E2)
1171
+ -> Result = failure(Unit, Name, Line, throw(E2), Time)
1172
+ ).
1173
+ run_test_7(Unit, Name, Line, Options, Body, Result) :-
1174
+ option(fail, Options), % expected failure
1175
+ !,
1176
+ unit_module(Unit, Module),
1177
+ call_time(reify_tmo(Module:Body, Result0, Options), Time),
1178
+ ( Result0 == true
1179
+ -> Result = failure(Unit, Name, Line, succeeded, Time)
1180
+ ; Result0 == false
1181
+ -> Result = success(Unit, Name, Line, true, Time)
1182
+ ; Result0 = throw(E)
1183
+ -> Result = failure(Unit, Name, Line, throw(E), Time)
1184
+ ).
1185
+ run_test_7(Unit, Name, Line, Options, Body, Result) :-
1186
+ option(throws(Expect), Options), % Expected error
1187
+ !,
1188
+ unit_module(Unit, Module),
1189
+ call_time(reify_tmo(Module:Body, Result0, Options), Time),
1190
+ ( Result0 == true
1191
+ -> Result = failure(Unit, Name, Line, no_exception, Time)
1192
+ ; Result0 == false
1193
+ -> Result = failure(Unit, Name, Line, failed, Time)
1194
+ ; Result0 = throw(E)
1195
+ -> ( match_error(Expect, E)
1196
+ -> Result = success(Unit, Name, Line, true, Time)
1197
+ ; Result = failure(Unit, Name, Line, wrong_error(Expect, E), Time)
1198
+ )
1199
+ ).
1200
+ run_test_7(Unit, Name, Line, Options, Body, Result) :-
1201
+ option(all(Answer), Options), % all(Bindings)
1202
+ !,
1203
+ nondet_test(all(Answer), Unit, Name, Line, Options, Body, Result).
1204
+ run_test_7(Unit, Name, Line, Options, Body, Result) :-
1205
+ option(set(Answer), Options), % set(Bindings)
1206
+ !,
1207
+ nondet_test(set(Answer), Unit, Name, Line, Options, Body, Result).
1208
+
1209
+ %! non_det_test(+Expected, +Unit, +Name, +Line, +Options, +Body, -Result)
1210
+ %
1211
+ % Run tests on non-deterministic predicates.
1212
+
1213
+ nondet_test(Expected, Unit, Name, Line, Options, Body, Result) :-
1214
+ unit_module(Unit, Module),
1215
+ result_vars(Expected, Vars),
1216
+ ( call_time(reify_tmo(findall(Vars, Module:Body, Bindings),
1217
+ Result0, Options), Time)
1218
+ -> ( Result0 == true
1219
+ -> ( nondet_compare(Expected, Bindings, Unit, Name, Line)
1220
+ -> Result = success(Unit, Name, Line, true, Time)
1221
+ ; Result = failure(Unit, Name, Line,
1222
+ [wrong_answer(Expected, Bindings)], Time)
1223
+ )
1224
+ ; Result0 = throw(E)
1225
+ -> Result = failure(Unit, Name, Line, throw(E), Time)
1226
+ )
1227
+ ).
1228
+
1229
+ cmp_true([], _, L) =>
1230
+ L = [].
1231
+ cmp_true([Cmp|T], Module, L) =>
1232
+ E = error(Formal,_),
1233
+ cmp_goal(Cmp, Goal),
1234
+ ( catch(Module:Goal, E, true)
1235
+ -> ( var(Formal)
1236
+ -> cmp_true(T, Module, L)
1237
+ ; L = [cmp_error(Cmp,E)|L1],
1238
+ cmp_true(T, Module, L1)
1239
+ )
1240
+ ; L = [wrong_answer(Cmp)|L1],
1241
+ cmp_true(T, Module, L1)
1242
+ ).
1243
+
1244
+ cmp_goal(cmp(_Var, Expr), Goal) => Goal = Expr.
1245
+ cmp_goal(Expr, Goal) => Goal = Expr.
1246
+
1247
+
1248
+ %! result_vars(+Expected, -Vars) is det.
1249
+ %
1250
+ % Create a term v(V1, ...) containing all variables at the left
1251
+ % side of the comparison operator on Expected.
1252
+
1253
+ result_vars(Expected, Vars) :-
1254
+ arg(1, Expected, CmpOp),
1255
+ arg(1, CmpOp, Vars).
1256
+
1257
+ %! nondet_compare(+Expected, +Bindings, +Unit, +Name, +Line) is semidet.
1258
+ %
1259
+ % Compare list/set results for non-deterministic predicates.
1260
+ %
1261
+ % @tbd Properly report errors
1262
+ % @bug Sort should deal with equivalence on the comparison
1263
+ % operator.
1264
+
1265
+ nondet_compare(all(Cmp), Bindings, _Unit, _Name, _Line) :-
1266
+ cmp(Cmp, _Vars, Op, Values),
1267
+ cmp_list(Values, Bindings, Op).
1268
+ nondet_compare(set(Cmp), Bindings0, _Unit, _Name, _Line) :-
1269
+ cmp(Cmp, _Vars, Op, Values0),
1270
+ sort(Bindings0, Bindings),
1271
+ sort(Values0, Values),
1272
+ cmp_list(Values, Bindings, Op).
1273
+
1274
+ cmp_list([], [], _Op).
1275
+ cmp_list([E0|ET], [V0|VT], Op) :-
1276
+ call(Op, E0, V0),
1277
+ cmp_list(ET, VT, Op).
1278
+
1279
+ %! cmp(+CmpTerm, -Left, -Op, -Right) is det.
1280
+
1281
+ cmp(Var == Value, Var, ==, Value).
1282
+ cmp(Var =:= Value, Var, =:=, Value).
1283
+ cmp(Var = Value, Var, =, Value).
1284
+ :- if(swi).
1285
+ cmp(Var =@= Value, Var, =@=, Value).
1286
+ :- else.
1287
+ :- if(sicstus).
1288
+ cmp(Var =@= Value, Var, variant, Value). % variant/2 is the same =@=
1289
+ :- endif.
1290
+ :- endif.
1291
+
1292
+
1293
+ %! call_det(:Goal, -Det) is nondet.
1294
+ %
1295
+ % True if Goal succeeded. Det is unified to =true= if Goal left
1296
+ % no choicepoints and =false= otherwise.
1297
+
1298
+ :- if((swi;sicstus)).
1299
+ call_det(Goal, Det) :-
1300
+ call_cleanup(Goal,Det0=true),
1301
+ ( var(Det0) -> Det = false ; Det = true ).
1302
+ :- else.
1303
+ call_det(Goal, true) :-
1304
+ call(Goal).
1305
+ :- endif.
1306
+
1307
+ %! match_error(+Expected, +Received) is semidet.
1308
+ %
1309
+ % True if the Received errors matches the expected error. Matching
1310
+ % is based on subsumes_term/2.
1311
+
1312
+ match_error(Expect, Rec) :-
1313
+ subsumes_term(Expect, Rec).
1314
+
1315
+ %! setup(+Module, +Context, +Options) is semidet.
1316
+ %
1317
+ % Call the setup handler and fail if it cannot run for some
1318
+ % reason. The condition handler is similar, but failing is not
1319
+ % considered an error. Context is one of
1320
+ %
1321
+ % - unit(Unit)
1322
+ % If it is the setup handler for a unit
1323
+ % - test(Unit,Name,Line)
1324
+ % If it is the setup handler for a test
1325
+
1326
+ setup(Module, Context, Options) :-
1327
+ option(setup(Setup), Options),
1328
+ !,
1329
+ capture_output(reify(call_ex(Module, Setup), Result), Output),
1330
+ ( Result == true
1331
+ -> true
1332
+ ; print_message(error,
1333
+ plunit(error(setup, Context, Output, Result))),
1334
+ fail
1335
+ ).
1336
+ setup(_,_,_).
1337
+
1338
+ %! condition(+Module, +Context, +Options) is semidet.
1339
+ %
1340
+ % Evaluate the test or test unit condition.
1341
+
1342
+ condition(Module, Context, Options) :-
1343
+ option(condition(Cond), Options),
1344
+ !,
1345
+ capture_output(reify(call_ex(Module, Cond), Result), Output),
1346
+ ( Result == true
1347
+ -> true
1348
+ ; Result == false
1349
+ -> fail
1350
+ ; print_message(error,
1351
+ plunit(error(condition, Context, Output, Result))),
1352
+ fail
1353
+ ).
1354
+ condition(_, _, _).
1355
+
1356
+
1357
+ %! call_ex(+Module, +Goal)
1358
+ %
1359
+ % Call Goal in Module after applying goal expansion.
1360
+
1361
+ call_ex(Module, Goal) :-
1362
+ Module:(expand_goal(Goal, GoalEx),
1363
+ GoalEx).
1364
+
1365
+ %! cleanup(+Module, +Options) is det.
1366
+ %
1367
+ % Call the cleanup handler and succeed. Failure or error of the
1368
+ % cleanup handler is reported, but tests continue normally.
1369
+
1370
+ cleanup(Module, Options) :-
1371
+ option(cleanup(Cleanup), Options, true),
1372
+ ( catch(call_ex(Module, Cleanup), E, true)
1373
+ -> ( var(E)
1374
+ -> true
1375
+ ; print_message(warning, E)
1376
+ )
1377
+ ; print_message(warning, goal_failed(Cleanup, '(cleanup handler)'))
1378
+ ).
1379
+
1380
+ success(Unit, Name, Progress, Line, Det, Time, _Output, Options) :-
1381
+ memberchk(fixme(Reason), Options),
1382
+ !,
1383
+ ( ( Det == true
1384
+ ; memberchk(nondet, Options)
1385
+ )
1386
+ -> progress(Unit:Name, Progress, fixme(passed), Time),
1387
+ Ok = passed
1388
+ ; progress(Unit:Name, Progress, fixme(nondet), Time),
1389
+ Ok = nondet
1390
+ ),
1391
+ flush_output(user_error),
1392
+ assert(fixme(Unit, Name, Line, Reason, Ok)).
1393
+ success(Unit, Name, Progress, Line, _, Time, Output, Options) :-
1394
+ failed_assertion(Unit, Name, Line, _,Progress,_,_),
1395
+ !,
1396
+ failure(Unit, Name, Progress, Line, assertion, Time, Output, Options).
1397
+ success(Unit, Name, Progress, Line, _, Time, Output, Options) :-
1398
+ Output = true-_,
1399
+ !,
1400
+ failure(Unit, Name, Progress, Line, message, Time, Output, Options).
1401
+ success(Unit, Name, Progress, Line, Det, Time, _Output, Options) :-
1402
+ assert(passed(Unit, Name, Line, Det, Time)),
1403
+ ( ( Det == true
1404
+ ; memberchk(nondet, Options)
1405
+ )
1406
+ -> progress(Unit:Name, Progress, passed, Time)
1407
+ ; unit_file(Unit, File),
1408
+ print_message(warning, plunit(nondet(File:Line, Unit:Name, Progress)))
1409
+ ).
1410
+
1411
+ %! failure(+Unit, +Name, +Progress, +Line,
1412
+ %! +How, +Time, +Output, +Options) is det.
1413
+ %
1414
+ % Test failed. Report the error.
1415
+
1416
+ failure(Unit, Name, Progress, Line, _, Time, _Output, Options),
1417
+ memberchk(fixme(Reason), Options) =>
1418
+ assert(fixme(Unit, Name, Line, Reason, failed)),
1419
+ progress(Unit:Name, Progress, fixme(failed), Time).
1420
+ failure(Unit, Name, Progress, Line, time_limit_exceeded(Limit), Time,
1421
+ Output, Options) =>
1422
+ assert_cyclic(timeout(Unit, Name, Line, Limit, Time)),
1423
+ progress(Unit:Name, Progress, timeout(Limit), Time),
1424
+ report_failure(Unit, Name, Progress, Line, timeout(Limit), Time, Output, Options).
1425
+ failure(Unit, Name, Progress, Line, E, Time, Output, Options) =>
1426
+ assert_cyclic(failed(Unit, Name, Line, E, Time)),
1427
+ progress(Unit:Name, Progress, failed, Time),
1428
+ report_failure(Unit, Name, Progress, Line, E, Time, Output, Options).
1429
+
1430
+ %! assert_cyclic(+Term) is det.
1431
+ %
1432
+ % Assert a possibly cyclic unit clause. Current SWI-Prolog
1433
+ % assert/1 does not handle cyclic terms, so we emulate this using
1434
+ % the recorded database.
1435
+ %
1436
+ % @tbd Implement cycle-safe assert and remove this.
1437
+
1438
+ :- if(swi).
1439
+ assert_cyclic(Term) :-
1440
+ acyclic_term(Term),
1441
+ !,
1442
+ assert(Term).
1443
+ assert_cyclic(Term) :-
1444
+ Term =.. [Functor|Args],
1445
+ recorda(cyclic, Args, Id),
1446
+ functor(Term, _, Arity),
1447
+ length(NewArgs, Arity),
1448
+ Head =.. [Functor|NewArgs],
1449
+ assert((Head :- recorded(_, Var, Id), Var = NewArgs)).
1450
+ :- else.
1451
+ :- if(sicstus).
1452
+ :- endif.
1453
+ assert_cyclic(Term) :-
1454
+ assert(Term).
1455
+ :- endif.
1456
+
1457
+
1458
+ /*******************************
1459
+ * JOBS *
1460
+ *******************************/
1461
+
1462
+ :- if(current_prolog_flag(threads, true)).
1463
+
1464
+ :- dynamic
1465
+ job_data/2, % Queue, Threads
1466
+ scheduled_unit/1.
1467
+
1468
+ schedule_unit(_:[]) :-
1469
+ !.
1470
+ schedule_unit(UnitAndTests) :-
1471
+ UnitAndTests = Unit:_Tests,
1472
+ job_data(Queue, _),
1473
+ !,
1474
+ assertz(scheduled_unit(Unit)),
1475
+ thread_send_message(Queue, unit(UnitAndTests)).
1476
+ schedule_unit(Unit) :-
1477
+ run_unit(Unit).
1478
+
1479
+ %! setup_jobs(+Count) is det.
1480
+ %
1481
+ % Setup threads for concurrent testing.
1482
+
1483
+ setup_jobs(Count) :-
1484
+ ( current_test_flag(jobs, Jobs0),
1485
+ integer(Jobs0)
1486
+ -> true
1487
+ ; current_prolog_flag(cpu_count, Jobs0)
1488
+ ),
1489
+ Jobs is min(Count, Jobs0),
1490
+ Jobs > 1,
1491
+ !,
1492
+ message_queue_create(Q, [alias(plunit_jobs)]),
1493
+ length(TIDs, Jobs),
1494
+ foldl(create_plunit_job(Q), TIDs, 1, _),
1495
+ asserta(job_data(Q, TIDs)),
1496
+ job_feedback(informational, jobs(Jobs)).
1497
+ setup_jobs(_) :-
1498
+ job_feedback(informational, jobs(1)).
1499
+
1500
+ create_plunit_job(Q, TID, N, N1) :-
1501
+ N1 is N + 1,
1502
+ atom_concat(plunit_job_, N, Alias),
1503
+ thread_create(plunit_job(Q), TID, [alias(Alias)]).
1504
+
1505
+ plunit_job(Queue) :-
1506
+ repeat,
1507
+ ( catch(thread_get_message(Queue, Job,
1508
+ [ timeout(10)
1509
+ ]),
1510
+ error(_,_), fail)
1511
+ -> job(Job),
1512
+ fail
1513
+ ; !
1514
+ ).
1515
+
1516
+ job(unit(Unit:Tests)) =>
1517
+ run_unit(Unit:Tests).
1518
+ job(test(Unit, Test)) =>
1519
+ run_test(Unit, Test).
1520
+
1521
+ cleanup_jobs :-
1522
+ retract(job_data(Queue, TIDSs)),
1523
+ !,
1524
+ message_queue_destroy(Queue),
1525
+ maplist(thread_join, TIDSs).
1526
+ cleanup_jobs.
1527
+
1528
+ %! job_wait(?Unit) is det.
1529
+ %
1530
+ % Wait for all test jobs to finish.
1531
+
1532
+ job_wait(Unit) :-
1533
+ thread_wait(\+ scheduled_unit(Unit),
1534
+ [ wait_preds([scheduled_unit/1]),
1535
+ timeout(1)
1536
+ ]),
1537
+ !.
1538
+ job_wait(Unit) :-
1539
+ job_data(_Queue, TIDs),
1540
+ member(TID, TIDs),
1541
+ thread_property(TID, status(running)),
1542
+ !,
1543
+ job_wait(Unit).
1544
+ job_wait(_).
1545
+
1546
+
1547
+ job_info(begin(unit(Unit))) =>
1548
+ print_message(silent, plunit(begin(Unit))).
1549
+ job_info(end(unit(Unit, Summary))) =>
1550
+ retractall(scheduled_unit(Unit)),
1551
+ print_message(silent, plunit(end(Unit, Summary))).
1552
+
1553
+ :- else. % No jobs
1554
+
1555
+ schedule_unit(Unit) :-
1556
+ run_unit(Unit).
1557
+
1558
+ setup_jobs(_) :-
1559
+ print_message(silent, plunit(jobs(1))).
1560
+ cleanup_jobs.
1561
+ job_wait(_).
1562
+ job_info(_).
1563
+
1564
+ :- endif.
1565
+
1566
+
1567
+
1568
+ /*******************************
1569
+ * REPORTING *
1570
+ *******************************/
1571
+
1572
+ %! begin_test(+Unit, +Test, +Line, +Progress) is det.
1573
+ %! end_test(+Unit, +Test, +Line, +Progress) is det.
1574
+ %
1575
+ % Maintain running/5 and report a test has started/is ended using
1576
+ % a =silent= message:
1577
+ %
1578
+ % * plunit(begin(Unit:Test, File:Line, Progress))
1579
+ % * plunit(end(Unit:Test, File:Line, Progress))
1580
+ %
1581
+ % @see message_hook/3 for intercepting these messages
1582
+
1583
+ begin_test(Unit, Test, Line, Progress) :-
1584
+ thread_self(Me),
1585
+ assert(running(Unit, Test, Line, Progress, Me)),
1586
+ unit_file(Unit, File),
1587
+ test_count(Total),
1588
+ job_feedback(information, begin(Unit:Test, File:Line, Progress/Total)).
1589
+
1590
+ end_test(Unit, Test, Line, Progress) :-
1591
+ thread_self(Me),
1592
+ retractall(running(_,_,_,_,Me)),
1593
+ unit_file(Unit, File),
1594
+ test_count(Total),
1595
+ job_feedback(information, end(Unit:Test, File:Line, Progress/Total)).
1596
+
1597
+ %! running_tests is det.
1598
+ %
1599
+ % Print the currently running test.
1600
+
1601
+ running_tests :-
1602
+ running_tests(Running),
1603
+ print_message(informational, plunit(running(Running))).
1604
+
1605
+ running_tests(Running) :-
1606
+ test_count(Total),
1607
+ findall(running(Unit:Test, File:Line, Progress/Total, Thread),
1608
+ ( running(Unit, Test, Line, Progress, Thread),
1609
+ unit_file(Unit, File)
1610
+ ), Running).
1611
+
1612
+
1613
+ %! current_test(?Unit, ?Test, ?Line, ?Body, ?Options) is nondet.
1614
+ %
1615
+ % True when a test with the specified properties is loaded.
1616
+
1617
+ current_test(Unit, Test, Line, Body, Options) :-
1618
+ current_unit(Unit, Module, _Supers, _UnitOptions),
1619
+ Module:'unit test'(Test, Line, Options, Body).
1620
+
1621
+ %! current_test_unit(?Unit, ?Options) is nondet.
1622
+ %
1623
+ % True when a Unit is a current unit test declared with Options.
1624
+
1625
+ current_test_unit(Unit, UnitOptions) :-
1626
+ current_unit(Unit, _Module, _Supers, UnitOptions).
1627
+
1628
+
1629
+ count(Goal, Count) :-
1630
+ aggregate_all(count, Goal, Count).
1631
+
1632
+ %! test_summary(?Unit, -Summary) is det.
1633
+ %
1634
+ % True when Summary is a dict that reports the main statistics
1635
+ % about the executed tests.
1636
+
1637
+ test_summary(Unit, Summary) :-
1638
+ count(failed(Unit, _0Test, _0Line, _Reason, _0Time), Failed),
1639
+ count(timeout(Unit, _0Test, _0Line, _Limit, _0Time), Timeout),
1640
+ count(passed(Unit, _0Test, _0Line, _Det, _0Time), Passed),
1641
+ count(blocked(Unit, _0Test, _0Line, _0Reason), Blocked),
1642
+ count(fixme(Unit, _0Test, _0Line, _0Reason, _0How), Fixme),
1643
+ test_count(Total),
1644
+ Summary = plunit{total:Total,
1645
+ passed:Passed,
1646
+ failed:Failed,
1647
+ timeout:Timeout,
1648
+ blocked:Blocked,
1649
+ fixme:Fixme}.
1650
+
1651
+ test_summary_passed(Summary) :-
1652
+ _{failed: 0} :< Summary.
1653
+
1654
+ %! report(+Time, +Options) is det.
1655
+ %
1656
+ % Print a summary of the tests that ran.
1657
+
1658
+ report(Time, _Options) :-
1659
+ test_summary(_, Summary),
1660
+ print_message(silent, plunit(Summary)),
1661
+ _{ passed:Passed,
1662
+ failed:Failed,
1663
+ timeout:Timeout,
1664
+ blocked:Blocked,
1665
+ fixme:Fixme
1666
+ } :< Summary,
1667
+ ( Passed+Failed+Timeout+Blocked+Fixme =:= 0
1668
+ -> info(plunit(no_tests))
1669
+ ; Failed+Timeout =:= 0
1670
+ -> report_blocked(Blocked),
1671
+ report_fixme,
1672
+ test_count(Total),
1673
+ info(plunit(all_passed(Total, Passed, Time)))
1674
+ ; report_blocked(Blocked),
1675
+ report_fixme,
1676
+ report_failed(Failed),
1677
+ report_timeout(Timeout),
1678
+ info(plunit(passed(Passed))),
1679
+ info(plunit(total_time(Time)))
1680
+ ).
1681
+
1682
+ report_blocked(0) =>
1683
+ true.
1684
+ report_blocked(Blocked) =>
1685
+ findall(blocked(Unit:Name, File:Line, Reason),
1686
+ ( blocked(Unit, Name, Line, Reason),
1687
+ unit_file(Unit, File)
1688
+ ),
1689
+ BlockedTests),
1690
+ info(plunit(blocked(Blocked, BlockedTests))).
1691
+
1692
+ report_failed(Failed) :-
1693
+ print_message(error, plunit(failed(Failed))).
1694
+
1695
+ report_timeout(Count) :-
1696
+ print_message(warning, plunit(timeout(Count))).
1697
+
1698
+ report_fixme :-
1699
+ report_fixme(_,_,_).
1700
+
1701
+ report_fixme(TuplesF, TuplesP, TuplesN) :-
1702
+ fixme(failed, TuplesF, Failed),
1703
+ fixme(passed, TuplesP, Passed),
1704
+ fixme(nondet, TuplesN, Nondet),
1705
+ print_message(informational, plunit(fixme(Failed, Passed, Nondet))).
1706
+
1707
+
1708
+ fixme(How, Tuples, Count) :-
1709
+ findall(fixme(Unit, Name, Line, Reason, How),
1710
+ fixme(Unit, Name, Line, Reason, How), Tuples),
1711
+ length(Tuples, Count).
1712
+
1713
+ report_failure(Unit, Name, Progress, Line, Error,
1714
+ Time, Output, _Options) =>
1715
+ test_count(Total),
1716
+ job_feedback(error, failed(Unit:Name, Progress/Total, Line,
1717
+ Error, Time, Output)).
1718
+
1719
+
1720
+ %! test_report(+What) is det.
1721
+ %
1722
+ % Produce reports on test results after the run. Currently only
1723
+ % supports `fixme` for What.
1724
+
1725
+ test_report(fixme) :-
1726
+ !,
1727
+ report_fixme(TuplesF, TuplesP, TuplesN),
1728
+ append([TuplesF, TuplesP, TuplesN], Tuples),
1729
+ print_message(informational, plunit(fixme(Tuples))).
1730
+ test_report(What) :-
1731
+ throw_error(domain_error(report_class, What), _).
1732
+
1733
+
1734
+ /*******************************
1735
+ * INFO *
1736
+ *******************************/
1737
+
1738
+ %! unit_file(+Unit, -File) is det.
1739
+ %! unit_file(?Unit, ?File) is nondet.
1740
+ %
1741
+ % True when the test unit Unit is defined in File.
1742
+
1743
+ unit_file(Unit, File), nonvar(Unit) =>
1744
+ unit_file_(Unit, File),
1745
+ !.
1746
+ unit_file(Unit, File) =>
1747
+ unit_file_(Unit, File).
1748
+
1749
+ unit_file_(Unit, File) :-
1750
+ current_unit(Unit, Module, _Context, _Options),
1751
+ module_property(Module, file(File)).
1752
+ unit_file_(Unit, PlFile) :-
1753
+ test_file_for(TestFile, PlFile),
1754
+ module_property(Module, file(TestFile)),
1755
+ current_unit(Unit, Module, _Context, _Options).
1756
+
1757
+
1758
+ /*******************************
1759
+ * FILES *
1760
+ *******************************/
1761
+
1762
+ %! load_test_files(+Options) is det.
1763
+ %
1764
+ % Load .plt test-files related to loaded source-files. Options is
1765
+ % currently ignored.
1766
+
1767
+ load_test_files(_Options) :-
1768
+ State = state(0,0),
1769
+ ( source_file(File),
1770
+ file_name_extension(Base, Old, File),
1771
+ Old \== plt,
1772
+ file_name_extension(Base, plt, TestFile),
1773
+ exists_file(TestFile),
1774
+ inc_arg(1, State),
1775
+ ( test_file_for(TestFile, File)
1776
+ -> true
1777
+ ; load_files(TestFile,
1778
+ [ if(changed),
1779
+ imports([])
1780
+ ]),
1781
+ inc_arg(2, State),
1782
+ asserta(test_file_for(TestFile, File))
1783
+ ),
1784
+ fail
1785
+ ; State = state(Total, Loaded),
1786
+ print_message(informational, plunit(test_files(Total, Loaded)))
1787
+ ).
1788
+
1789
+ inc_arg(Arg, State) :-
1790
+ arg(Arg, State, N0),
1791
+ N is N0+1,
1792
+ nb_setarg(Arg, State, N).
1793
+
1794
+
1795
+ /*******************************
1796
+ * MESSAGES *
1797
+ *******************************/
1798
+
1799
+ %! info(+Term)
1800
+ %
1801
+ % Runs print_message(Level, Term), where Level is one of `silent` or
1802
+ % `informational` (default).
1803
+
1804
+ info(Term) :-
1805
+ message_level(Level),
1806
+ print_message(Level, Term).
1807
+
1808
+ %! progress(+UnitTest, +Progress, +Result, +Time) is det.
1809
+ %
1810
+ % Test Unit:Name completed in Time. Result is the result and is one of
1811
+ %
1812
+ % - passed
1813
+ % - failed
1814
+ % - assertion
1815
+ % - nondet
1816
+ % - fixme(passed)
1817
+ % - fixme(nondet)
1818
+ % - fixme(failed)
1819
+ % - forall(end, Nth, FTotal)
1820
+ % Pseudo result for completion of a forall(Gen,Test) set. Mapped
1821
+ % to forall(FTotal, FFailed)
1822
+
1823
+ progress(UnitTest, _Progress, forall(end, Nth, FTotal), Time) =>
1824
+ ( retract(forall_failures(Nth, FFailed))
1825
+ -> true
1826
+ ; FFailed = 0
1827
+ ),
1828
+ test_count(Total),
1829
+ job_feedback(information, progress(UnitTest, forall(FTotal,FFailed), Nth/Total, Time)).
1830
+ progress(UnitTest, Progress, Result, Time), Progress = forall(_Gen, Nth-_I) =>
1831
+ with_mutex(plunit_forall_counter,
1832
+ update_forall_failures(Nth, Result)),
1833
+ test_count(Total),
1834
+ job_feedback(information, progress(UnitTest, Result, Progress/Total, Time)).
1835
+ progress(UnitTest, Progress, Result, Time) =>
1836
+ test_count(Total),
1837
+ job_feedback(information, progress(UnitTest, Result, Progress/Total, Time)).
1838
+
1839
+ update_forall_failures(_Nth, passed) =>
1840
+ true.
1841
+ update_forall_failures(Nth, _) =>
1842
+ ( retract(forall_failures(Nth, Failed0))
1843
+ -> true
1844
+ ; Failed0 = 0
1845
+ ),
1846
+ Failed is Failed0+1,
1847
+ asserta(forall_failures(Nth, Failed)).
1848
+
1849
+ message_level(Level) :-
1850
+ ( current_test_flag(silent, true)
1851
+ -> Level = silent
1852
+ ; Level = informational
1853
+ ).
1854
+
1855
+ locationprefix(File:Line) -->
1856
+ !,
1857
+ [ url(File:Line), ':'-[], nl, ' ' ].
1858
+ locationprefix(test(Unit,_Test,Line)) -->
1859
+ !,
1860
+ { unit_file(Unit, File) },
1861
+ locationprefix(File:Line).
1862
+ locationprefix(unit(Unit)) -->
1863
+ !,
1864
+ [ 'PL-Unit: unit ~w: '-[Unit] ].
1865
+ locationprefix(FileLine) -->
1866
+ { throw_error(type_error(locationprefix,FileLine), _) }.
1867
+
1868
+ :- discontiguous
1869
+ message//1.
1870
+ :- '$hide'(message//1).
1871
+
1872
+ message(error(context_error(plunit_close(Name, -)), _)) -->
1873
+ [ 'PL-Unit: cannot close unit ~w: no open unit'-[Name] ].
1874
+ message(error(context_error(plunit_close(Name, Start)), _)) -->
1875
+ [ 'PL-Unit: cannot close unit ~w: current unit is ~w'-[Name, Start] ].
1876
+ message(plunit(nondet(Pos, Test, Progress))) -->
1877
+ locationprefix(Pos),
1878
+ test_name(Test, Progress),
1879
+ [ ': Test succeeded with choicepoint'-[] ].
1880
+ message(error(plunit(incompatible_options, Tests), _)) -->
1881
+ [ 'PL-Unit: incompatible test-options: ~p'-[Tests] ].
1882
+ message(plunit(sto(true))) -->
1883
+ [ 'Option sto(true) is ignored. See `occurs_check` option.'-[] ].
1884
+ message(plunit(test_files(Total, Loaded))) -->
1885
+ [ 'Found ~D .plt test files, loaded ~D'-[Total, Loaded] ].
1886
+
1887
+ % Unit start/end
1888
+ message(plunit(jobs(1))) -->
1889
+ !.
1890
+ message(plunit(jobs(N))) -->
1891
+ [ 'Testing with ~D parallel jobs'-[N] ].
1892
+ message(plunit(begin(_Unit))) -->
1893
+ { tty_feedback },
1894
+ !.
1895
+ message(plunit(begin(Unit))) -->
1896
+ [ 'Start unit: ~w~n'-[Unit], flush ].
1897
+ message(plunit(end(_Unit, _Summary))) -->
1898
+ { tty_feedback },
1899
+ !.
1900
+ message(plunit(end(Unit, Summary))) -->
1901
+ ( {test_summary_passed(Summary)}
1902
+ -> [ 'End unit ~w: passed (~3f sec CPU)'-[Unit, Summary.time.cpu] ]
1903
+ ; [ ansi(error, 'End unit ~w: **FAILED (~3f sec CPU)', [Unit, Summary.time.cpu]) ]
1904
+ ).
1905
+ message(plunit(blocked(unit(Unit, Reason)))) -->
1906
+ [ 'PL-Unit: ~w blocked: ~w'-[Unit, Reason] ].
1907
+ message(plunit(running([]))) -->
1908
+ !,
1909
+ [ 'PL-Unit: no tests running' ].
1910
+ message(plunit(running([One]))) -->
1911
+ !,
1912
+ [ 'PL-Unit: running ' ],
1913
+ running(One).
1914
+ message(plunit(running(More))) -->
1915
+ !,
1916
+ [ 'PL-Unit: running tests:', nl ],
1917
+ running(More).
1918
+ message(plunit(fixme([]))) --> !.
1919
+ message(plunit(fixme(Tuples))) -->
1920
+ !,
1921
+ fixme_message(Tuples).
1922
+ message(plunit(total_time(Time))) -->
1923
+ [ 'Test run completed'-[] ],
1924
+ test_time(Time).
1925
+
1926
+ % Blocked tests
1927
+ message(plunit(blocked(1, Tests))) -->
1928
+ !,
1929
+ [ 'one test is blocked'-[] ],
1930
+ blocked_tests(Tests).
1931
+ message(plunit(blocked(N, Tests))) -->
1932
+ [ '~D tests are blocked'-[N] ],
1933
+ blocked_tests(Tests).
1934
+
1935
+ blocked_tests(Tests) -->
1936
+ { current_test_flag(show_blocked, true) },
1937
+ !,
1938
+ [':'-[]],
1939
+ list_blocked(Tests).
1940
+ blocked_tests(_) -->
1941
+ [ ' (use run_tests/2 with ', ansi(code, 'show_blocked(true)', []),
1942
+ ' for details)'-[]
1943
+ ].
1944
+
1945
+ list_blocked([]) --> !.
1946
+ list_blocked([blocked(Unit:Test, Pos, Reason)|T]) -->
1947
+ [nl],
1948
+ locationprefix(Pos),
1949
+ test_name(Unit:Test, -),
1950
+ [ ': ~w'-[Reason] ],
1951
+ list_blocked(T).
1952
+
1953
+ % fail/success
1954
+ message(plunit(no_tests)) -->
1955
+ !,
1956
+ [ 'No tests to run' ].
1957
+ message(plunit(all_passed(1, 1, Time))) -->
1958
+ !,
1959
+ [ 'test passed' ],
1960
+ test_time(Time).
1961
+ message(plunit(all_passed(Total, Total, Time))) -->
1962
+ !,
1963
+ [ 'All ~D tests passed'-[Total] ],
1964
+ test_time(Time).
1965
+ message(plunit(all_passed(Total, Count, Time))) -->
1966
+ !,
1967
+ { SubTests is Count-Total },
1968
+ [ 'All ~D (+~D sub-tests) tests passed'- [Total, SubTests] ],
1969
+ test_time(Time).
1970
+
1971
+ test_time(Time) -->
1972
+ { var(Time) }, !.
1973
+ test_time(Time) -->
1974
+ [ ' in ~3f seconds (~3f cpu)'-[Time.wall, Time.cpu] ].
1975
+
1976
+ message(plunit(passed(Count))) -->
1977
+ !,
1978
+ [ '~D tests passed'-[Count] ].
1979
+ message(plunit(failed(0))) -->
1980
+ !,
1981
+ [].
1982
+ message(plunit(failed(1))) -->
1983
+ !,
1984
+ [ '1 test failed'-[] ].
1985
+ message(plunit(failed(N))) -->
1986
+ [ '~D tests failed'-[N] ].
1987
+ message(plunit(timeout(0))) -->
1988
+ !,
1989
+ [].
1990
+ message(plunit(timeout(N))) -->
1991
+ [ '~D tests timed out'-[N] ].
1992
+ message(plunit(fixme(0,0,0))) -->
1993
+ [].
1994
+ message(plunit(fixme(Failed,0,0))) -->
1995
+ !,
1996
+ [ 'all ~D tests flagged FIXME failed'-[Failed] ].
1997
+ message(plunit(fixme(Failed,Passed,0))) -->
1998
+ [ 'FIXME: ~D failed; ~D passed'-[Failed, Passed] ].
1999
+ message(plunit(fixme(Failed,Passed,Nondet))) -->
2000
+ { TotalPassed is Passed+Nondet },
2001
+ [ 'FIXME: ~D failed; ~D passed; (~D nondet)'-
2002
+ [Failed, TotalPassed, Nondet] ].
2003
+
2004
+ message(plunit(begin(Unit:Test, _Location, Progress))) -->
2005
+ { tty_columns(SummaryWidth, _Margin),
2006
+ test_name_summary(Unit:Test, SummaryWidth, NameS),
2007
+ progress_string(Progress, ProgressS)
2008
+ },
2009
+ ( { tty_feedback,
2010
+ tty_clear_to_eol(CE)
2011
+ }
2012
+ -> [ at_same_line, '\r[~w] ~w ..~w'-[ProgressS, NameS,
2013
+ CE], flush ]
2014
+ ; { jobs(_) }
2015
+ -> [ '[~w] ~w ..'-[ProgressS, NameS] ]
2016
+ ; [ '[~w] ~w ..'-[ProgressS, NameS], flush ]
2017
+ ).
2018
+ message(plunit(end(_UnitTest, _Location, _Progress))) -->
2019
+ [].
2020
+ message(plunit(progress(_UnitTest, Status, _Progress, _Time))) -->
2021
+ { Status = forall(_Gen,_NthI)
2022
+ ; Status == assertion
2023
+ },
2024
+ !.
2025
+ message(plunit(progress(Unit:Test, Status, Progress, Time))) -->
2026
+ { jobs(_),
2027
+ !,
2028
+ tty_columns(SummaryWidth, Margin),
2029
+ test_name_summary(Unit:Test, SummaryWidth, NameS),
2030
+ progress_string(Progress, ProgressS),
2031
+ progress_tag(Status, Tag, _Keep, Style)
2032
+ },
2033
+ [ ansi(Style, '[~w] ~w ~`.t ~w (~3f sec)~*|',
2034
+ [ProgressS, NameS, Tag, Time.wall, Margin]) ].
2035
+ message(plunit(progress(_UnitTest, Status, _Progress, Time))) -->
2036
+ { tty_columns(_SummaryWidth, Margin),
2037
+ progress_tag(Status, Tag, _Keep, Style)
2038
+ },
2039
+ [ at_same_line, ansi(Style, '~`.t ~w (~3f sec)~*|',
2040
+ [Tag, Time.wall, Margin]) ],
2041
+ ( { tty_feedback }
2042
+ -> [flush]
2043
+ ; []
2044
+ ).
2045
+ message(plunit(failed(Unit:Test, Progress, Line, Failure, _Time, Output))) -->
2046
+ { unit_file(Unit, File) },
2047
+ locationprefix(File:Line),
2048
+ test_name(Unit:Test, Progress),
2049
+ [': '-[] ],
2050
+ failure(Failure),
2051
+ test_output(Output).
2052
+ message(plunit(timeout(Unit:Test, Progress, Line, Limit, Output))) -->
2053
+ { unit_file(Unit, File) },
2054
+ locationprefix(File:Line),
2055
+ test_name(Unit:Test, Progress),
2056
+ [': '-[] ],
2057
+ timeout(Limit),
2058
+ test_output(Output).
2059
+ :- if(swi).
2060
+ message(plunit(failed_assertion(Unit:Test, Line, AssertLoc,
2061
+ Progress, Reason, Goal))) -->
2062
+ { unit_file(Unit, File) },
2063
+ locationprefix(File:Line),
2064
+ test_name(Unit:Test, Progress),
2065
+ [ ': assertion'-[] ],
2066
+ assertion_location(AssertLoc, File),
2067
+ assertion_reason(Reason), ['\n\t'],
2068
+ assertion_goal(Unit, Goal).
2069
+
2070
+ assertion_location(File:Line, File) -->
2071
+ [ ' at line ~w'-[Line] ].
2072
+ assertion_location(File:Line, _) -->
2073
+ [ ' at ', url(File:Line) ].
2074
+ assertion_location(unknown, _) -->
2075
+ [].
2076
+
2077
+ assertion_reason(fail) -->
2078
+ !,
2079
+ [ ' failed'-[] ].
2080
+ assertion_reason(Error) -->
2081
+ { message_to_string(Error, String) },
2082
+ [ ' raised "~w"'-[String] ].
2083
+
2084
+ assertion_goal(Unit, Goal) -->
2085
+ { unit_module(Unit, Module),
2086
+ unqualify(Goal, Module, Plain)
2087
+ },
2088
+ [ 'Assertion: ~p'-[Plain] ].
2089
+
2090
+ unqualify(Var, _, Var) :-
2091
+ var(Var),
2092
+ !.
2093
+ unqualify(M:Goal, Unit, Goal) :-
2094
+ nonvar(M),
2095
+ unit_module(Unit, M),
2096
+ !.
2097
+ unqualify(M:Goal, _, Goal) :-
2098
+ callable(Goal),
2099
+ predicate_property(M:Goal, imported_from(system)),
2100
+ !.
2101
+ unqualify(Goal, _, Goal).
2102
+
2103
+ test_output(Msgs-String) -->
2104
+ { nonvar(Msgs) },
2105
+ !,
2106
+ test_output(String).
2107
+ test_output("") --> [].
2108
+ test_output(Output) -->
2109
+ [ ansi(code, '~N~s', [Output]) ].
2110
+
2111
+ :- endif.
2112
+ % Setup/condition errors
2113
+ message(plunit(error(Where, Context, _Output, throw(Exception)))) -->
2114
+ locationprefix(Context),
2115
+ { message_to_string(Exception, String) },
2116
+ [ 'error in ~w: ~w'-[Where, String] ].
2117
+ message(plunit(error(Where, Context, _Output, false))) -->
2118
+ locationprefix(Context),
2119
+ [ 'setup failed in ~w'-[Where] ].
2120
+
2121
+ % delayed output
2122
+ message(plunit(test_output(_, Output))) -->
2123
+ [ '~s'-[Output] ].
2124
+ % Interrupts (SWI)
2125
+ :- if(swi).
2126
+ message(interrupt(begin)) -->
2127
+ { thread_self(Me),
2128
+ running(Unit, Test, Line, Progress, Me),
2129
+ !,
2130
+ unit_file(Unit, File),
2131
+ restore_output_state
2132
+ },
2133
+ [ 'Interrupted test '-[] ],
2134
+ running(running(Unit:Test, File:Line, Progress, Me)),
2135
+ [nl],
2136
+ '$messages':prolog_message(interrupt(begin)).
2137
+ message(interrupt(begin)) -->
2138
+ '$messages':prolog_message(interrupt(begin)).
2139
+ :- endif.
2140
+
2141
+ message(concurrent) -->
2142
+ [ 'concurrent(true) at the level of units is currently ignored.', nl,
2143
+ 'See set_test_options/1 with jobs(Count) for concurrent testing.'
2144
+ ].
2145
+
2146
+ test_name(Name, forall(Generator, _Nth-I)/_Total) -->
2147
+ !,
2148
+ test_name(Name, -),
2149
+ [ ' (~d-th forall generator = '-[I],
2150
+ ansi(code, '~p', [Generator]), ')'-[]
2151
+ ].
2152
+ test_name(Name, _) -->
2153
+ !,
2154
+ [ 'test ', ansi(code, '~q', [Name]) ].
2155
+
2156
+ running(running(Unit:Test, File:Line, _Progress, Thread)) -->
2157
+ thread(Thread),
2158
+ [ '~q:~q at '-[Unit, Test], url(File:Line) ].
2159
+ running([H|T]) -->
2160
+ ['\t'], running(H),
2161
+ ( {T == []}
2162
+ -> []
2163
+ ; [nl], running(T)
2164
+ ).
2165
+
2166
+ thread(main) --> !.
2167
+ thread(Other) -->
2168
+ [' [~w] '-[Other] ].
2169
+
2170
+ :- if(swi).
2171
+ write_term(T, OPS) -->
2172
+ ['~W'-[T,OPS] ].
2173
+ :- else.
2174
+ write_term(T, _OPS) -->
2175
+ ['~q'-[T]].
2176
+ :- endif.
2177
+
2178
+ expected_got_ops_(Ex, E, OPS, Goals) -->
2179
+ [' Expected: '-[]], write_term(Ex, OPS), [nl],
2180
+ [' Got: '-[]], write_term(E, OPS), [],
2181
+ ( { Goals = [] } -> []
2182
+ ; [nl, ' with: '-[]], write_term(Goals, OPS), []
2183
+ ).
2184
+
2185
+
2186
+ failure(List) -->
2187
+ { is_list(List) },
2188
+ !,
2189
+ [ nl ],
2190
+ failures(List).
2191
+ failure(Var) -->
2192
+ { var(Var) },
2193
+ !,
2194
+ [ 'Unknown failure?' ].
2195
+ failure(succeeded(Time)) -->
2196
+ !,
2197
+ [ 'must fail but succeeded in ~2f seconds~n'-[Time] ].
2198
+ failure(wrong_error(Expected, Error)) -->
2199
+ !,
2200
+ { copy_term(Expected-Error, Ex-E, Goals),
2201
+ numbervars(Ex-E-Goals, 0, _),
2202
+ write_options(OPS)
2203
+ },
2204
+ [ 'wrong error'-[], nl ],
2205
+ expected_got_ops_(Ex, E, OPS, Goals).
2206
+ failure(wrong_answer(cmp(Var, Cmp))) -->
2207
+ { Cmp =.. [Op,Answer,Expected],
2208
+ !,
2209
+ copy_term(Expected-Answer, Ex-A, Goals),
2210
+ numbervars(Ex-A-Goals, 0, _),
2211
+ write_options(OPS)
2212
+ },
2213
+ [ 'wrong answer for ', ansi(code, '~w', [Var]),
2214
+ ' (compared using ~w)'-[Op], nl ],
2215
+ expected_got_ops_(Ex, A, OPS, Goals).
2216
+ failure(wrong_answer(Cmp)) -->
2217
+ { Cmp =.. [Op,Answer,Expected],
2218
+ !,
2219
+ copy_term(Expected-Answer, Ex-A, Goals),
2220
+ numbervars(Ex-A-Goals, 0, _),
2221
+ write_options(OPS)
2222
+ },
2223
+ [ 'wrong answer (compared using ~w)'-[Op], nl ],
2224
+ expected_got_ops_(Ex, A, OPS, Goals).
2225
+ failure(wrong_answer(CmpExpected, Bindings)) -->
2226
+ { ( CmpExpected = all(Cmp)
2227
+ -> Cmp =.. [_Op1,_,Expected],
2228
+ Got = Bindings,
2229
+ Type = all
2230
+ ; CmpExpected = set(Cmp),
2231
+ Cmp =.. [_Op2,_,Expected0],
2232
+ sort(Expected0, Expected),
2233
+ sort(Bindings, Got),
2234
+ Type = set
2235
+ )
2236
+ },
2237
+ [ 'wrong "~w" answer:'-[Type] ],
2238
+ [ nl, ' Expected: ~q'-[Expected] ],
2239
+ [ nl, ' Found: ~q'-[Got] ].
2240
+ :- if(swi).
2241
+ failure(cmp_error(_Cmp, Error)) -->
2242
+ { message_to_string(Error, Message) },
2243
+ [ 'Comparison error: ~w'-[Message] ].
2244
+ failure(throw(Error)) -->
2245
+ { Error = error(_,_),
2246
+ !,
2247
+ message_to_string(Error, Message)
2248
+ },
2249
+ [ 'received error: ~w'-[Message] ].
2250
+ :- endif.
2251
+ failure(message) -->
2252
+ !,
2253
+ [ 'Generated unexpected warning or error'-[] ].
2254
+ failure(setup_failed(throw(Error))) -->
2255
+ { Error = error(_,_),
2256
+ !,
2257
+ message_to_string(Error, Message)
2258
+ },
2259
+ [ 'test setup goal raised error: ~w'-[Message] ].
2260
+ failure(setup_failed(_)) -->
2261
+ !,
2262
+ [ 'test setup goal failed' ].
2263
+ failure(Why) -->
2264
+ [ '~p'-[Why] ].
2265
+
2266
+ failures([]) -->
2267
+ !.
2268
+ failures([H|T]) -->
2269
+ !,
2270
+ failure(H), [nl],
2271
+ failures(T).
2272
+
2273
+ timeout(Limit) -->
2274
+ [ 'Timeout exceeeded (~2f sec)'-[Limit] ].
2275
+
2276
+ fixme_message([]) --> [].
2277
+ fixme_message([fixme(Unit, _Name, Line, Reason, How)|T]) -->
2278
+ { unit_file(Unit, File) },
2279
+ fixme_message(File:Line, Reason, How),
2280
+ ( {T == []}
2281
+ -> []
2282
+ ; [nl],
2283
+ fixme_message(T)
2284
+ ).
2285
+
2286
+ fixme_message(Location, Reason, failed) -->
2287
+ [ 'FIXME: ~w: ~w'-[Location, Reason] ].
2288
+ fixme_message(Location, Reason, passed) -->
2289
+ [ 'FIXME: ~w: passed ~w'-[Location, Reason] ].
2290
+ fixme_message(Location, Reason, nondet) -->
2291
+ [ 'FIXME: ~w: passed (nondet) ~w'-[Location, Reason] ].
2292
+
2293
+
2294
+ write_options([ numbervars(true),
2295
+ quoted(true),
2296
+ portray(true),
2297
+ max_depth(100),
2298
+ attributes(portray)
2299
+ ]).
2300
+
2301
+ %! test_name_summary(+Term, +MaxLen, -Summary) is det.
2302
+ %
2303
+ % Given the test id, generate string that summarizes this in MaxLen
2304
+ % characters.
2305
+
2306
+ test_name_summary(Term, MaxLen, Summary) :-
2307
+ summary_string(Term, Text),
2308
+ atom_length(Text, Len),
2309
+ ( Len =< MaxLen
2310
+ -> Summary = Text
2311
+ ; End is MaxLen//2,
2312
+ Pre is MaxLen - End - 2,
2313
+ sub_string(Text, 0, Pre, _, PreText),
2314
+ sub_string(Text, _, End, 0, PostText),
2315
+ format(string(Summary), '~w..~w', [PreText,PostText])
2316
+ ).
2317
+
2318
+ summary_string(Unit:Test, String) =>
2319
+ summary_string(Test, String1),
2320
+ atomics_to_string([Unit, String1], :, String).
2321
+ summary_string(@(Name,Vars), String) =>
2322
+ format(string(String), '~W (using ~W)',
2323
+ [ Name, [numbervars(true), quoted(false)],
2324
+ Vars, [numbervars(true), portray(true), quoted(true)]
2325
+ ]).
2326
+ summary_string(Name, String) =>
2327
+ term_string(Name, String, [numbervars(true), quoted(false)]).
2328
+
2329
+ %! progress_string(+Progress, -S) is det.
2330
+ %
2331
+ % True when S is a string representation for the test progress.
2332
+
2333
+ progress_string(forall(_Vars, N-I)/Total, S) =>
2334
+ format(string(S), '~w-~w/~w', [N,I,Total]).
2335
+ progress_string(Progress, S) =>
2336
+ term_string(Progress, S).
2337
+
2338
+ %! progress_tag(+Status, -Tag, -Keep, -Style) is det.
2339
+ %
2340
+ % Given a progress status, determine the status tag, whether we must
2341
+ % preserve the line and the Style we must use to print the status
2342
+ % line.
2343
+
2344
+ progress_tag(passed, Tag, Keep, Style) =>
2345
+ Tag = passed, Keep = false, Style = comment.
2346
+ progress_tag(fixme(passed), Tag, Keep, Style) =>
2347
+ Tag = passed, Keep = false, Style = comment.
2348
+ progress_tag(fixme(_), Tag, Keep, Style) =>
2349
+ Tag = fixme, Keep = true, Style = warning.
2350
+ progress_tag(nondet, Tag, Keep, Style) =>
2351
+ Tag = '**NONDET', Keep = true, Style = warning.
2352
+ progress_tag(timeout(_Limit), Tag, Keep, Style) =>
2353
+ Tag = '**TIMEOUT', Keep = true, Style = warning.
2354
+ progress_tag(assertion, Tag, Keep, Style) =>
2355
+ Tag = '**FAILED', Keep = true, Style = error.
2356
+ progress_tag(failed, Tag, Keep, Style) =>
2357
+ Tag = '**FAILED', Keep = true, Style = error.
2358
+ progress_tag(forall(_,0), Tag, Keep, Style) =>
2359
+ Tag = passed, Keep = false, Style = comment.
2360
+ progress_tag(forall(_,_), Tag, Keep, Style) =>
2361
+ Tag = '**FAILED', Keep = true, Style = error.
2362
+
2363
+
2364
+ /*******************************
2365
+ * OUTPUT *
2366
+ *******************************/
2367
+
2368
+ save_output_state :-
2369
+ stream_property(Output, alias(user_output)),
2370
+ stream_property(Error, alias(user_error)),
2371
+ asserta(output_streams(Output, Error)).
2372
+
2373
+ restore_output_state :-
2374
+ output_streams(Output, Error),
2375
+ !,
2376
+ set_stream(Output, alias(user_output)),
2377
+ set_stream(Error, alias(user_error)).
2378
+ restore_output_state.
2379
+
2380
+
2381
+
2382
+ /*******************************
2383
+ * CONCURRENT STATUS *
2384
+ *******************************/
2385
+
2386
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2387
+ This part deals with interactive feedback when we are running multiple
2388
+ threads. The terminal window cannot work on top of the Prolog message
2389
+ infrastructure and (thus) we have to use more low-level means.
2390
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2391
+
2392
+ :- dynamic
2393
+ jobs/1, % Count
2394
+ job_window/1, % Count
2395
+ job_status_line/3. % Job, Format, Args
2396
+
2397
+ job_feedback(_, jobs(Jobs)) :-
2398
+ retractall(jobs(_)),
2399
+ Jobs > 1,
2400
+ asserta(jobs(Jobs)),
2401
+ tty_feedback,
2402
+ !,
2403
+ retractall(job_window(_)),
2404
+ asserta(job_window(Jobs)),
2405
+ retractall(job_status_line(_,_,_)),
2406
+ jobs_redraw.
2407
+ job_feedback(_, jobs(Jobs)) :-
2408
+ !,
2409
+ retractall(job_window(_)),
2410
+ info(plunit(jobs(Jobs))).
2411
+ job_feedback(_, Msg) :-
2412
+ job_window(_),
2413
+ !,
2414
+ with_mutex(plunit_feedback, job_feedback(Msg)).
2415
+ job_feedback(Level, Msg) :-
2416
+ print_message(Level, plunit(Msg)).
2417
+
2418
+ job_feedback(begin(Unit:Test, _Location, Progress)) =>
2419
+ tty_columns(SummaryWidth, _Margin),
2420
+ test_name_summary(Unit:Test, SummaryWidth, NameS),
2421
+ progress_string(Progress, ProgressS),
2422
+ tty_clear_to_eol(CE),
2423
+ job_format(comment, '\r[~w] ~w ..~w',
2424
+ [ProgressS, NameS, CE]),
2425
+ flush_output.
2426
+ job_feedback(end(_UnitTest, _Location, _Progress)) =>
2427
+ true.
2428
+ job_feedback(progress(_UnitTest, Status, _Progress, Time)) =>
2429
+ ( hide_progress(Status)
2430
+ -> true
2431
+ ; tty_columns(_SummaryWidth, Margin),
2432
+ progress_tag(Status, Tag, _Keep, Style),
2433
+ job_finish(Style, '~`.t ~w (~3f sec)~*|',
2434
+ [Tag, Time.wall, Margin])
2435
+ ).
2436
+ job_feedback(failed(UnitTest, Progress, Line, Error, Time, Output)) =>
2437
+ tty_columns(_SummaryWidth, Margin),
2438
+ progress_tag(failed, Tag, _Keep, Style),
2439
+ job_finish(Style, '~`.t ~w (~3f sec)~*|',
2440
+ [Tag, Time.wall, Margin]),
2441
+ print_test_output(Error, Output),
2442
+ ( ( Error = timeout(_) % Status line suffices
2443
+ ; Error == assertion % We will get an failed test later
2444
+ )
2445
+ -> true
2446
+ ; print_message(Style, plunit(failed(UnitTest, Progress, Line,
2447
+ Error, Time, "")))
2448
+ ),
2449
+ jobs_redraw.
2450
+ job_feedback(begin(_Unit)) => true.
2451
+ job_feedback(end(_Unit, _Summary)) => true.
2452
+
2453
+ hide_progress(assertion).
2454
+ hide_progress(forall(_,_)).
2455
+ hide_progress(failed).
2456
+ hide_progress(timeout(_)).
2457
+
2458
+ print_test_output(Error, _Msgs-Output) =>
2459
+ print_test_output(Error, Output).
2460
+ print_test_output(_, "") => true.
2461
+ print_test_output(assertion, Output) =>
2462
+ print_message(debug, plunit(test_output(error, Output))).
2463
+ print_test_output(message, Output) =>
2464
+ print_message(debug, plunit(test_output(error, Output))).
2465
+ print_test_output(_, Output) =>
2466
+ print_message(debug, plunit(test_output(informational, Output))).
2467
+
2468
+ %! jobs_redraw is det.
2469
+ %
2470
+ % Redraw the job window.
2471
+
2472
+ jobs_redraw :-
2473
+ job_window(N),
2474
+ !,
2475
+ tty_columns(_, Width),
2476
+ tty_header_line(Width),
2477
+ forall(between(1,N,Line), job_redraw_worker(Line)),
2478
+ tty_header_line(Width).
2479
+ jobs_redraw.
2480
+
2481
+ job_redraw_worker(Line) :-
2482
+ ( job_status_line(Line, Fmt, Args)
2483
+ -> ansi_format(comment, Fmt, Args)
2484
+ ; true
2485
+ ),
2486
+ nl.
2487
+
2488
+ %! job_format(+Style, +Fmt, +Args) is det.
2489
+ %! job_format(+Job, +Style, +Fmt, +Args, +Save) is det.
2490
+ %
2491
+ % Point should be below the status window. Format Fmt+Args in the
2492
+ % line Job using Style and return to the position below the window.
2493
+
2494
+ job_format(Style, Fmt, Args) :-
2495
+ job_self(Job),
2496
+ job_format(Job, Style, Fmt, Args, true).
2497
+
2498
+ %! job_finish(+Style, +Fmt, +Args) is det.
2499
+ %! job_finish(+Job, +Style, +Fmt, +Args) is det.
2500
+ %
2501
+ % Complete the status line for Job. This redraws the original
2502
+ % status line when we are using a job window.
2503
+
2504
+ job_finish(Style, Fmt, Args) :-
2505
+ job_self(Job),
2506
+ job_finish(Job, Style, Fmt, Args).
2507
+
2508
+ :- det(job_finish/4).
2509
+ job_finish(Job, Style, Fmt, Args) :-
2510
+ retract(job_status_line(Job, Fmt0, Args0)),
2511
+ !,
2512
+ string_concat(Fmt0, Fmt, Fmt1),
2513
+ append(Args0, Args, Args1),
2514
+ job_format(Job, Style, Fmt1, Args1, false).
2515
+
2516
+ :- det(job_format/5).
2517
+ job_format(Job, Style, Fmt, Args, Save) :-
2518
+ job_window(Jobs),
2519
+ Up is Jobs+2-Job,
2520
+ flush_output(user_output),
2521
+ tty_up_and_clear(Up),
2522
+ ansi_format(Style, Fmt, Args),
2523
+ ( Save == true
2524
+ -> retractall(job_status_line(Job, _, _)),
2525
+ asserta(job_status_line(Job, Fmt, Args))
2526
+ ; true
2527
+ ),
2528
+ tty_down_and_home(Up),
2529
+ flush_output(user_output).
2530
+
2531
+ :- det(job_self/1).
2532
+ job_self(Job) :-
2533
+ job_window(N),
2534
+ N > 1,
2535
+ thread_self(Me),
2536
+ split_string(Me, '_', '', [_,_,S]),
2537
+ number_string(Job, S).
2538
+
2539
+ %! feedback is semidet.
2540
+ %
2541
+ % provide feedback using the `tty` format, which reuses the current
2542
+ % output line if the test is successful.
2543
+
2544
+ tty_feedback :-
2545
+ has_tty,
2546
+ current_test_flag(format, tty).
2547
+
2548
+ has_tty :-
2549
+ stream_property(user_output, tty(true)).
2550
+
2551
+ tty_columns(SummaryWidth, Margin) :-
2552
+ tty_width(W),
2553
+ Margin is W-8,
2554
+ SummaryWidth is max(20,Margin-34).
2555
+
2556
+ tty_width(W) :-
2557
+ current_predicate(tty_size/2),
2558
+ catch(tty_size(_Rows, Cols), error(_,_), fail),
2559
+ Cols > 25,
2560
+ !,
2561
+ W = Cols.
2562
+ tty_width(80).
2563
+
2564
+ tty_header_line(Width) :-
2565
+ ansi_format(comment, '~N~`\u2015t~*|~n', [Width]).
2566
+
2567
+ :- if(current_predicate(tty_get_capability/3)).
2568
+ tty_clear_to_eol(S) :-
2569
+ getenv('TERM', _),
2570
+ catch(tty_get_capability(ce, string, S),
2571
+ error(_,_),
2572
+ fail),
2573
+ !.
2574
+ :- endif.
2575
+ tty_clear_to_eol('\e[K').
2576
+
2577
+ tty_up_and_clear(Lines) :-
2578
+ format(user_output, '\e[~dA\r\e[K', [Lines]).
2579
+
2580
+ tty_down_and_home(Lines) :-
2581
+ format(user_output, '\e[~dB\r', [Lines]).
2582
+
2583
+ :- if(swi).
2584
+
2585
+ :- multifile
2586
+ prolog:message/3,
2587
+ prolog:message_action/2.
2588
+
2589
+ prolog:message(Term) -->
2590
+ message(Term).
2591
+
2592
+ % prolog:message_action(+Term, +Kind)
2593
+
2594
+ prolog:message_action(make(done(Files)), _) :-
2595
+ make_run_tests(Files).
2596
+
2597
+ :- endif.
2598
+
2599
+ :- if(sicstus).
2600
+
2601
+ user:generate_message_hook(Message) -->
2602
+ message(Message),
2603
+ [nl]. % SICStus requires nl at the end
2604
+
2605
+ %! user:message_hook(+Severity, +Message, +Lines) is semidet.
2606
+ %
2607
+ % Redefine printing some messages. It appears SICStus has no way
2608
+ % to get multiple messages at the same line, so we roll our own.
2609
+ % As there is a lot pre-wired and checked in the SICStus message
2610
+ % handling we cannot reuse the lines. Unless I miss something ...
2611
+
2612
+ user:message_hook(informational, plunit(begin(Unit)), _Lines) :-
2613
+ format(user_error, '% PL-Unit: ~w ', [Unit]),
2614
+ flush_output(user_error).
2615
+ user:message_hook(informational, plunit(end(_Unit)), _Lines) :-
2616
+ format(user, ' done~n', []).
2617
+
2618
+ :- endif.
2619
+
2620
+ /*******************************
2621
+ * SUPPRESS AUTOLOAD WARNINGS *
2622
+ *******************************/
2623
+
2624
+ '$nowarn_autoload'(set_test_options/1, _).
2625
+ '$nowarn_autoload'(run_tests/0, _).
2626
+ '$nowarn_autoload'(run_tests/1, _).
2627
+ '$nowarn_autoload'(run_tests/2, _).
2628
+ '$nowarn_autoload'(running_tests/0, _).
2629
+ '$nowarn_autoload'(current_test/5, _).
2630
+ '$nowarn_autoload'(current_test_unit/2, _).
2631
+ '$nowarn_autoload'(test_report/1, _).