tigerbeetle 0.0.40 → 0.17.8

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 (293) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +0 -25
  3. data/README.md +670 -80
  4. data/docs/migration.md +201 -0
  5. data/sig/tigerbeetle.rbs +271 -0
  6. data/src/ext/tigerbeetle/extconf.rb +47 -0
  7. data/src/ext/tigerbeetle/lib/aarch64-linux-gnu.2.27/libtb_client.so +0 -0
  8. data/src/ext/tigerbeetle/lib/aarch64-linux-musl/libtb_client.so +0 -0
  9. data/src/ext/tigerbeetle/lib/aarch64-macos/libtb_client.dylib +0 -0
  10. data/src/ext/tigerbeetle/lib/x86_64-linux-gnu.2.27/libtb_client.so +0 -0
  11. data/src/ext/tigerbeetle/lib/x86_64-linux-musl/libtb_client.so +0 -0
  12. data/src/ext/tigerbeetle/lib/x86_64-macos/libtb_client.dylib +0 -0
  13. data/src/ext/tigerbeetle/lib/x86_64-windows/tb_client.dll +0 -0
  14. data/src/ext/tigerbeetle/rb_tb_gen.h +458 -0
  15. data/{ext/tb_client/tigerbeetle/src/clients/rust/assets → src/ext/tigerbeetle}/tb_client.h +18 -16
  16. data/src/ext/tigerbeetle/tigerbeetle.c +310 -0
  17. data/src/tigerbeetle/bindings.rb +347 -0
  18. data/src/tigerbeetle/client.rb +129 -0
  19. data/src/tigerbeetle/completion_dispatcher.rb +108 -0
  20. data/src/tigerbeetle/id.rb +40 -0
  21. data/src/tigerbeetle/tb.rb +3 -0
  22. data/src/tigerbeetle/version.rb +3 -0
  23. data/src/tigerbeetle.rb +39 -0
  24. metadata +33 -350
  25. data/CHANGELOG.md +0 -162
  26. data/ext/tb_client/extconf.rb +0 -41
  27. data/ext/tb_client/tigerbeetle/LICENSE +0 -177
  28. data/ext/tb_client/tigerbeetle/build.zig +0 -2296
  29. data/ext/tb_client/tigerbeetle/src/aof.zig +0 -1000
  30. data/ext/tb_client/tigerbeetle/src/build/fetch.zig +0 -112
  31. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +0 -808
  32. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +0 -1283
  33. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +0 -1704
  34. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +0 -341
  35. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +0 -1450
  36. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +0 -1659
  37. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +0 -406
  38. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +0 -1092
  39. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +0 -286
  40. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +0 -158
  41. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +0 -229
  42. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +0 -110
  43. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +0 -386
  44. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +0 -34
  45. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +0 -281
  46. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +0 -312
  47. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +0 -138
  48. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +0 -466
  49. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +0 -157
  50. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +0 -90
  51. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +0 -203
  52. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +0 -79
  53. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +0 -542
  54. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +0 -109
  55. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +0 -86
  56. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +0 -370
  57. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +0 -386
  58. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +0 -167
  59. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +0 -126
  60. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +0 -996
  61. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +0 -748
  62. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +0 -3238
  63. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +0 -1718
  64. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +0 -190
  65. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +0 -104
  66. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +0 -75
  67. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +0 -522
  68. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +0 -267
  69. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +0 -3
  70. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +0 -379
  71. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +0 -131
  72. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +0 -63
  73. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +0 -588
  74. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +0 -73
  75. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +0 -106
  76. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +0 -305
  77. data/ext/tb_client/tigerbeetle/src/config.zig +0 -296
  78. data/ext/tb_client/tigerbeetle/src/constants.zig +0 -790
  79. data/ext/tb_client/tigerbeetle/src/copyhound.zig +0 -202
  80. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +0 -72
  81. data/ext/tb_client/tigerbeetle/src/direction.zig +0 -120
  82. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +0 -158
  83. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +0 -156
  84. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +0 -252
  85. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +0 -313
  86. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +0 -87
  87. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +0 -63
  88. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +0 -47
  89. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +0 -28
  90. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +0 -61
  91. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +0 -169
  92. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +0 -46
  93. data/ext/tb_client/tigerbeetle/src/ewah.zig +0 -445
  94. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +0 -128
  95. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +0 -171
  96. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +0 -179
  97. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +0 -662
  98. data/ext/tb_client/tigerbeetle/src/io/common.zig +0 -155
  99. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +0 -1093
  100. data/ext/tb_client/tigerbeetle/src/io/linux.zig +0 -1880
  101. data/ext/tb_client/tigerbeetle/src/io/test.zig +0 -1005
  102. data/ext/tb_client/tigerbeetle/src/io/windows.zig +0 -1598
  103. data/ext/tb_client/tigerbeetle/src/io.zig +0 -34
  104. data/ext/tb_client/tigerbeetle/src/iops.zig +0 -134
  105. data/ext/tb_client/tigerbeetle/src/list.zig +0 -236
  106. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +0 -848
  107. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +0 -179
  108. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +0 -424
  109. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +0 -420
  110. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +0 -2114
  111. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +0 -185
  112. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +0 -1146
  113. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +0 -1102
  114. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +0 -200
  115. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +0 -1495
  116. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +0 -739
  117. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +0 -166
  118. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +0 -754
  119. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +0 -1294
  120. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +0 -510
  121. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +0 -1241
  122. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +0 -628
  123. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +0 -247
  124. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +0 -116
  125. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +0 -543
  126. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +0 -938
  127. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +0 -293
  128. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +0 -359
  129. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +0 -99
  130. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +0 -17
  131. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +0 -962
  132. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +0 -617
  133. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +0 -84
  134. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +0 -1500
  135. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +0 -149
  136. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +0 -7
  137. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +0 -865
  138. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +0 -607
  139. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +0 -843
  140. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +0 -90
  141. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +0 -40
  142. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +0 -629
  143. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +0 -933
  144. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +0 -534
  145. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +0 -469
  146. data/ext/tb_client/tigerbeetle/src/message_bus.zig +0 -1219
  147. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +0 -936
  148. data/ext/tb_client/tigerbeetle/src/message_pool.zig +0 -343
  149. data/ext/tb_client/tigerbeetle/src/multiversion.zig +0 -2195
  150. data/ext/tb_client/tigerbeetle/src/queue.zig +0 -390
  151. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +0 -201
  152. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +0 -1356
  153. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +0 -496
  154. data/ext/tb_client/tigerbeetle/src/repl.zig +0 -1034
  155. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +0 -973
  156. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +0 -1866
  157. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +0 -304
  158. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +0 -227
  159. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +0 -658
  160. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +0 -466
  161. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +0 -1058
  162. data/ext/tb_client/tigerbeetle/src/scripts.zig +0 -105
  163. data/ext/tb_client/tigerbeetle/src/shell.zig +0 -1195
  164. data/ext/tb_client/tigerbeetle/src/stack.zig +0 -260
  165. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +0 -911
  166. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +0 -2079
  167. data/ext/tb_client/tigerbeetle/src/state_machine.zig +0 -4872
  168. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +0 -288
  169. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +0 -3128
  170. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +0 -82
  171. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +0 -157
  172. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +0 -292
  173. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +0 -65
  174. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +0 -1414
  175. data/ext/tb_client/tigerbeetle/src/stdx/huge_page_allocator.zig +0 -115
  176. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +0 -92
  177. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +0 -677
  178. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +0 -336
  179. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +0 -511
  180. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +0 -112
  181. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +0 -1163
  182. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +0 -142
  183. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +0 -361
  184. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +0 -275
  185. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +0 -295
  186. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +0 -436
  187. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +0 -48
  188. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +0 -402
  189. data/ext/tb_client/tigerbeetle/src/storage.zig +0 -489
  190. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +0 -180
  191. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +0 -146
  192. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +0 -53
  193. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +0 -61
  194. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +0 -76
  195. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +0 -110
  196. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +0 -412
  197. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +0 -331
  198. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +0 -458
  199. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +0 -1198
  200. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +0 -128
  201. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +0 -181
  202. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +0 -144
  203. data/ext/tb_client/tigerbeetle/src/testing/id.zig +0 -97
  204. data/ext/tb_client/tigerbeetle/src/testing/io.zig +0 -317
  205. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +0 -126
  206. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +0 -533
  207. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +0 -154
  208. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +0 -389
  209. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +0 -1247
  210. data/ext/tb_client/tigerbeetle/src/testing/table.zig +0 -249
  211. data/ext/tb_client/tigerbeetle/src/testing/time.zig +0 -98
  212. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +0 -212
  213. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +0 -26
  214. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +0 -579
  215. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +0 -39
  216. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +0 -214
  217. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +0 -34
  218. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +0 -785
  219. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +0 -543
  220. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +0 -181
  221. data/ext/tb_client/tigerbeetle/src/tidy.zig +0 -1449
  222. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +0 -227
  223. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +0 -1069
  224. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +0 -1422
  225. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +0 -1658
  226. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +0 -518
  227. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +0 -36
  228. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +0 -646
  229. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +0 -958
  230. data/ext/tb_client/tigerbeetle/src/time.zig +0 -236
  231. data/ext/tb_client/tigerbeetle/src/trace/event.zig +0 -745
  232. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +0 -462
  233. data/ext/tb_client/tigerbeetle/src/trace.zig +0 -556
  234. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +0 -321
  235. data/ext/tb_client/tigerbeetle/src/vopr.zig +0 -1785
  236. data/ext/tb_client/tigerbeetle/src/vortex.zig +0 -101
  237. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +0 -473
  238. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +0 -208
  239. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +0 -43
  240. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +0 -768
  241. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +0 -532
  242. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +0 -338
  243. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +0 -1019
  244. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +0 -279
  245. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +0 -1381
  246. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +0 -315
  247. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +0 -1460
  248. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +0 -757
  249. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +0 -797
  250. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +0 -2586
  251. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +0 -308
  252. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +0 -1777
  253. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +0 -715
  254. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +0 -185
  255. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +0 -333
  256. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +0 -12356
  257. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +0 -416
  258. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +0 -165
  259. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +0 -2928
  260. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +0 -1075
  261. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +0 -1603
  262. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +0 -484
  263. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +0 -405
  264. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +0 -355
  265. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +0 -29
  266. data/ext/tb_client/tigerbeetle/src/vsr.zig +0 -1727
  267. data/lib/tb_client/shared_lib.rb +0 -66
  268. data/lib/tb_client.rb +0 -282
  269. data/lib/tigerbeetle/account.rb +0 -38
  270. data/lib/tigerbeetle/account_balance.rb +0 -23
  271. data/lib/tigerbeetle/account_filter.rb +0 -31
  272. data/lib/tigerbeetle/atomic_counter.rb +0 -14
  273. data/lib/tigerbeetle/client.rb +0 -214
  274. data/lib/tigerbeetle/converters/account.rb +0 -63
  275. data/lib/tigerbeetle/converters/account_balance.rb +0 -31
  276. data/lib/tigerbeetle/converters/account_filter.rb +0 -32
  277. data/lib/tigerbeetle/converters/base.rb +0 -35
  278. data/lib/tigerbeetle/converters/create_accounts_result.rb +0 -21
  279. data/lib/tigerbeetle/converters/create_transfers_result.rb +0 -21
  280. data/lib/tigerbeetle/converters/query_filter.rb +0 -33
  281. data/lib/tigerbeetle/converters/time.rb +0 -23
  282. data/lib/tigerbeetle/converters/transfer.rb +0 -64
  283. data/lib/tigerbeetle/converters/uint_128.rb +0 -24
  284. data/lib/tigerbeetle/converters.rb +0 -12
  285. data/lib/tigerbeetle/error.rb +0 -4
  286. data/lib/tigerbeetle/id.rb +0 -30
  287. data/lib/tigerbeetle/platforms.rb +0 -9
  288. data/lib/tigerbeetle/query_filter.rb +0 -31
  289. data/lib/tigerbeetle/request.rb +0 -7
  290. data/lib/tigerbeetle/transfer.rb +0 -40
  291. data/lib/tigerbeetle/version.rb +0 -4
  292. data/lib/tigerbeetle.rb +0 -13
  293. data/tigerbeetle.gemspec +0 -60
@@ -1,1414 +0,0 @@
1
- //! The purpose of `flags` is to define standard behavior for parsing CLI arguments and provide
2
- //! a specific parsing library, implementing this behavior.
3
- //!
4
- //! These are TigerBeetle CLI guidelines:
5
- //!
6
- //! - The main principle is robustness --- make operator errors harder to make.
7
- //! - For production usage, avoid defaults.
8
- //! - Thoroughly validate options.
9
- //! - In particular, check that no options are repeated.
10
- //! - Use only long options (`--addresses`).
11
- //! - Exception: `-h/--help` is allowed.
12
- //! - Use `--key=value` syntax for an option with an argument.
13
- //! Don't use `--key value`, as that can be ambiguous (e.g., `--key --verbose`).
14
- //! - Use subcommand syntax when appropriate.
15
- //! - Use positional arguments when appropriate.
16
- //!
17
- //! Design choices for this particular `flags` library:
18
- //!
19
- //! - Be a 80% solution. Parsing arguments is a surprisingly vast topic: auto-generated help,
20
- //! bash completions, typo correction. Rather than providing a definitive solution, `flags`
21
- //! is just one possible option. It is ok to re-implement arg parsing in a different way, as long
22
- //! as the CLI guidelines are observed.
23
- //!
24
- //! - No auto-generated help. Zig doesn't expose doc comments through `@typeInfo`, so its hard to
25
- //! implement auto-help nicely. Additionally, fully hand-crafted `--help` message can be of
26
- //! higher quality.
27
- //!
28
- //! - Fatal errors. It might be "cleaner" to use `try` to propagate the error to the caller, but
29
- //! during early CLI parsing, it is much simpler to terminate the process directly and save the
30
- //! caller the hassle of propagating errors. The `fatal` function is public, to allow the caller
31
- //! to run additional validation or parsing using the same error reporting mechanism.
32
- //!
33
- //! - Concise DSL. Most cli parsing is done for ad-hoc tools like benchmarking, where the ability to
34
- //! quickly add a new argument is valuable. As this is a 80% solution, production code may use
35
- //! more verbose approach if it gives better UX.
36
- //!
37
- //! - Caller manages ArgsIterator. ArgsIterator owns the backing memory of the args, so we let the
38
- //! caller to manage the lifetime. The caller should be skipping program name.
39
-
40
- const std = @import("std");
41
- const stdx = @import("stdx.zig");
42
- const builtin = @import("builtin");
43
- const assert = std.debug.assert;
44
-
45
- /// Format and print an error message to stderr, then exit with an exit code of 1.
46
- fn fatal(comptime fmt_string: []const u8, args: anytype) noreturn {
47
- const stderr = std.io.getStdErr().writer();
48
- stderr.print("error: " ++ fmt_string ++ "\n", args) catch {};
49
- // NB: this status must match vsr.FatalReason.cli, but it would be wrong for flags to depend on
50
- // vsr. The right way would be to parametrize flags by this behavior, and let the caller inject
51
- // the implementation of fatal function, but let's be pragmatic here and just match the behavior
52
- // manually.
53
- std.process.exit(1);
54
- }
55
-
56
- /// Parse CLI arguments for subcommands specified as Zig `struct` or `union(enum)`:
57
- ///
58
- /// ```
59
- /// const CLIArgs = union(enum) {
60
- /// start: struct { addresses: []const u8, replica: u32 },
61
- /// format: struct {
62
- /// verbose: bool = false,
63
- /// @"--": void,
64
- /// path: []const u8,
65
- /// },
66
- ///
67
- /// pub const help =
68
- /// \\ tigerbeetle start --addresses=<addresses> --replica=<replica>
69
- /// \\ tigerbeetle format [--verbose] <path>
70
- /// }
71
- ///
72
- /// const cli_args = parse_commands(&args, CLIArgs);
73
- /// ```
74
- ///
75
- /// `@"--"` field is treated specially, it delineates positional arguments.
76
- ///
77
- /// If `pub const help` declaration is present, it is used to implement `-h/--help` argument.
78
- ///
79
- /// Value parsing can be customized on per-type basis via `parse_flag_value` customization point.
80
- pub fn parse(args: *std.process.ArgIterator, comptime CLIArgs: type) CLIArgs {
81
- comptime assert(CLIArgs != void);
82
- assert(args.skip()); // Discard executable name.
83
- return parse_flags(args, CLIArgs);
84
- }
85
-
86
- fn parse_commands(args: *std.process.ArgIterator, comptime Commands: type) Commands {
87
- comptime assert(@typeInfo(Commands) == .@"union");
88
- comptime assert(std.meta.fields(Commands).len >= 2);
89
-
90
- const first_arg = args.next() orelse fatal(
91
- "subcommand required, expected {s}",
92
- .{comptime fields_to_comma_list(Commands)},
93
- );
94
-
95
- // NB: help must be declared as *pub* const to be visible here.
96
- if (@hasDecl(Commands, "help")) {
97
- if (std.mem.eql(u8, first_arg, "-h") or std.mem.eql(u8, first_arg, "--help")) {
98
- std.io.getStdOut().writeAll(Commands.help) catch std.process.exit(1);
99
- std.process.exit(0);
100
- }
101
- }
102
-
103
- inline for (comptime std.meta.fields(Commands)) |field| {
104
- comptime assert(std.mem.indexOfScalar(u8, field.name, '_') == null);
105
- if (std.mem.eql(u8, first_arg, field.name)) {
106
- return @unionInit(Commands, field.name, parse_flags(args, field.type));
107
- }
108
- }
109
- fatal("unknown subcommand: '{s}'", .{first_arg});
110
- }
111
-
112
- fn parse_flags(args: *std.process.ArgIterator, comptime Flags: type) Flags {
113
- @setEvalBranchQuota(5_000);
114
-
115
- if (Flags == void) {
116
- if (args.next()) |arg| {
117
- fatal("unexpected argument: '{s}'", .{arg});
118
- }
119
- return {};
120
- }
121
-
122
- if (@typeInfo(Flags) == .@"union") {
123
- return parse_commands(args, Flags);
124
- }
125
-
126
- assert(@typeInfo(Flags) == .@"struct");
127
-
128
- const fields = std.meta.fields(Flags);
129
- comptime var fields_named, const fields_positional, const fields_extended =
130
- for (fields, 0..) |field, index| {
131
- if (std.mem.eql(u8, field.name, "--")) {
132
- assert(field.type == void);
133
- break .{
134
- fields[0..index].*,
135
- fields[index + 1 ..].*,
136
- index == fields.len - 1,
137
- };
138
- }
139
- } else .{
140
- fields[0..fields.len].*,
141
- [_]std.builtin.Type.StructField{},
142
- false,
143
- };
144
-
145
- comptime {
146
- if (fields_positional.len == 0) {
147
- assert(fields.len == fields_named.len + @intFromBool(fields_extended));
148
- } else {
149
- assert(fields.len == fields_named.len + 1 + fields_positional.len);
150
- assert(!fields_extended);
151
- }
152
-
153
- // When parsing named arguments, we must consider longer arguments first, such that
154
- // `--foo-bar=92` is not confused for a misspelled `--foo=92`. Using `std.sort` for
155
- // comptime-only values does not work, so open-code insertion sort, and comptime assert
156
- // order during the actual parsing.
157
- for (fields_named[0..], 0..) |*field_right, i| {
158
- for (fields_named[0..i]) |*field_left| {
159
- if (field_left.name.len < field_right.name.len) {
160
- std.mem.swap(std.builtin.Type.StructField, field_left, field_right);
161
- }
162
- }
163
- }
164
-
165
- for (fields_named) |field| {
166
- switch (@typeInfo(field.type)) {
167
- .bool => {
168
- // Boolean flags must have a default.
169
- assert(field.defaultValue() != null);
170
- assert(field.defaultValue().? == false);
171
- },
172
- .optional => |optional| {
173
- // Optional flags must have a default.
174
- assert(field.defaultValue() != null);
175
- assert(field.defaultValue().? == null);
176
-
177
- assert_valid_value_type(optional.child);
178
- },
179
- else => {
180
- assert_valid_value_type(field.type);
181
- },
182
- }
183
- }
184
-
185
- var optional_tail: bool = false;
186
- for (fields_positional) |field| {
187
- if (field.defaultValue() == null) {
188
- if (optional_tail) @panic("optional positional arguments must be trailing");
189
- } else {
190
- optional_tail = true;
191
- }
192
- switch (@typeInfo(field.type)) {
193
- .optional => |optional| {
194
- // optional flags should have a default
195
- assert(field.defaultValue() != null);
196
- assert(field.defaultValue().? == null);
197
- assert_valid_value_type(optional.child);
198
- },
199
- else => {
200
- assert_valid_value_type(field.type);
201
- },
202
- }
203
- }
204
- }
205
-
206
- var counts: std.enums.EnumFieldStruct(std.meta.FieldEnum(Flags), u32, 0) = .{};
207
- var result: Flags = undefined;
208
- var parsed_positional = false;
209
- next_arg: while (args.next()) |arg| {
210
- comptime var field_len_prev = std.math.maxInt(usize);
211
- inline for (fields_named) |field| {
212
- const flag = comptime flag_name(field);
213
-
214
- comptime assert(field_len_prev >= field.name.len);
215
- field_len_prev = field.name.len;
216
- if (std.mem.startsWith(u8, arg, flag)) {
217
- if (parsed_positional) {
218
- fatal("unexpected trailing option: '{s}'", .{arg});
219
- }
220
-
221
- @field(counts, field.name) += 1;
222
- const flag_value = parse_flag(field.type, flag, arg);
223
- @field(result, field.name) = flag_value;
224
- continue :next_arg;
225
- }
226
- }
227
-
228
- if (fields_positional.len > 0) {
229
- assert(!fields_extended);
230
- counts.@"--" += 1;
231
- switch (counts.@"--" - 1) {
232
- inline 0...fields_positional.len - 1 => |field_index| {
233
- const field = fields_positional[field_index];
234
- const flag = comptime flag_name_positional(field);
235
-
236
- if (arg.len == 0) fatal("{s}: empty argument", .{flag});
237
- // Prevent ambiguity between a flag and positional argument value. We could add
238
- // support for bare ` -- ` as a disambiguation mechanism once we have a real
239
- // use-case.
240
- if (arg[0] == '-') fatal("unexpected argument: '{s}'", .{arg});
241
- parsed_positional = true;
242
-
243
- @field(result, field.name) =
244
- parse_value(field.type, flag, arg);
245
- continue :next_arg;
246
- },
247
- else => {}, // Fall-through to the unexpected argument error.
248
- }
249
- } else {
250
- if (fields_extended) {
251
- if (std.mem.eql(u8, arg, "--")) {
252
- break;
253
- } else {
254
- fatal("unexpected argument: '{s}'; expected '-- ...'", .{arg});
255
- }
256
- }
257
- }
258
-
259
- fatal("unexpected argument: '{s}'", .{arg});
260
- }
261
- if (!fields_extended) assert(args.next() == null);
262
-
263
- inline for (fields_named) |field| {
264
- const flag = flag_name(field);
265
- switch (@field(counts, field.name)) {
266
- 0 => if (field.defaultValue()) |default| {
267
- @field(result, field.name) = default;
268
- } else {
269
- fatal("{s}: argument is required", .{flag});
270
- },
271
- 1 => {},
272
- else => fatal("{s}: duplicate argument", .{flag}),
273
- }
274
- }
275
-
276
- if (fields_positional.len > 0) {
277
- assert(counts.@"--" <= fields_positional.len);
278
- inline for (fields_positional, 0..) |field, field_index| {
279
- if (field_index >= counts.@"--") {
280
- const flag = comptime flag_name_positional(field);
281
- if (field.defaultValue()) |default| {
282
- @field(result, field.name) = default;
283
- } else {
284
- fatal("{s}: argument is required", .{flag});
285
- }
286
- }
287
- }
288
- }
289
-
290
- return result;
291
- }
292
-
293
- fn assert_valid_value_type(comptime T: type) void {
294
- comptime {
295
- if (T == []const u8 or T == [:0]const u8 or @typeInfo(T) == .int) return;
296
- if (@hasDecl(T, "parse_flag_value")) return;
297
-
298
- if (@typeInfo(T) == .@"enum") {
299
- const info = @typeInfo(T).@"enum";
300
- assert(info.is_exhaustive);
301
- assert(info.fields.len >= 2);
302
- return;
303
- }
304
-
305
- @compileError("flags: unsupported type: " ++ @typeName(T));
306
- }
307
- }
308
-
309
- /// Parse, e.g., `--cluster=123` into `123` integer
310
- fn parse_flag(comptime T: type, flag: []const u8, arg: [:0]const u8) T {
311
- assert(flag[0] == '-' and flag[1] == '-');
312
-
313
- if (T == bool) {
314
- if (std.mem.eql(u8, arg, flag)) {
315
- // Bool argument may not have a value.
316
- return true;
317
- }
318
- }
319
-
320
- const value = parse_flag_split_value(flag, arg);
321
- assert(value.len > 0);
322
- return parse_value(T, flag, value);
323
- }
324
-
325
- /// Splits the value part from a `--arg=value` syntax.
326
- fn parse_flag_split_value(flag: []const u8, arg: [:0]const u8) [:0]const u8 {
327
- assert(flag[0] == '-' and flag[1] == '-');
328
- assert(std.mem.startsWith(u8, arg, flag));
329
-
330
- const value = arg[flag.len..];
331
- if (value.len == 0) {
332
- fatal("{s}: expected value separator '='", .{flag});
333
- }
334
- if (value[0] != '=') {
335
- fatal(
336
- "{s}: expected value separator '=', but found '{c}' in '{s}'",
337
- .{ flag, value[0], arg },
338
- );
339
- }
340
- if (value.len == 1) fatal("{s}: argument requires a value", .{flag});
341
- return value[1..];
342
- }
343
-
344
- fn parse_value(comptime T: type, flag: []const u8, value: [:0]const u8) T {
345
- assert((flag[0] == '-' and flag[1] == '-') or flag[0] == '<');
346
- assert(value.len > 0);
347
-
348
- const V = switch (@typeInfo(T)) {
349
- .optional => |optional| optional.child,
350
- else => T,
351
- };
352
-
353
- if (V == []const u8 or V == [:0]const u8) return value;
354
- if (V == bool) return parse_value_bool(flag, value);
355
- if (@typeInfo(V) == .int) return parse_value_int(V, flag, value);
356
- if (@typeInfo(V) == .@"enum") return parse_value_enum(V, flag, value);
357
- if (@hasDecl(V, "parse_flag_value")) {
358
-
359
- // Contracts:
360
- // - Input string is guaranteed to be not empty.
361
- // - Output diagnostic must point to statically-allocated data.
362
- // - Diagnostic must start with a lower case letter.
363
- // - Diagnostic must end with a ':' (it will be concatenated with original input).
364
- // - (static_diagnostic != null) iff error.InvalidFlagValue is returned.
365
- const parse_flag_value: fn (
366
- string: []const u8,
367
- static_diagnostic: *?[]const u8,
368
- ) error{InvalidFlagValue}!V = V.parse_flag_value;
369
-
370
- var diagnostic: ?[]const u8 = null;
371
- if (parse_flag_value(value, &diagnostic)) |result| {
372
- assert(diagnostic == null);
373
- return result;
374
- } else |err| switch (err) {
375
- error.InvalidFlagValue => {
376
- const message = diagnostic.?;
377
- assert(std.ascii.isLower(message[0]));
378
- assert(message[message.len - 1] == ':');
379
- fatal("{s}: {s} '{s}'", .{ flag, message, value });
380
- },
381
- }
382
- }
383
- comptime unreachable;
384
- }
385
-
386
- /// Parse string value into an integer, providing a nice error message for the user.
387
- fn parse_value_int(comptime T: type, flag: []const u8, value: [:0]const u8) T {
388
- assert((flag[0] == '-' and flag[1] == '-') or flag[0] == '<');
389
-
390
- // Support only unsigned integers, as a conservative choice.
391
- comptime assert(@typeInfo(T).int.signedness == .unsigned);
392
- return std.fmt.parseUnsigned(T, value, 10) catch |err| {
393
- switch (err) {
394
- error.Overflow => fatal(
395
- "{s}: value exceeds {d}-bit {s} integer: '{s}'",
396
- .{ flag, @typeInfo(T).int.bits, @tagName(@typeInfo(T).int.signedness), value },
397
- ),
398
- error.InvalidCharacter => fatal(
399
- "{s}: expected an integer value, but found '{s}' (invalid digit)",
400
- .{ flag, value },
401
- ),
402
- }
403
- };
404
- }
405
-
406
- fn parse_value_bool(flag: []const u8, value: [:0]const u8) bool {
407
- return switch (parse_value_enum(
408
- enum {
409
- true,
410
- false,
411
- },
412
- flag,
413
- value,
414
- )) {
415
- .true => true,
416
- .false => false,
417
- };
418
- }
419
-
420
- fn parse_value_enum(comptime E: type, flag: []const u8, value: [:0]const u8) E {
421
- assert((flag[0] == '-' and flag[1] == '-') or flag[0] == '<');
422
- comptime assert(@typeInfo(E).@"enum".is_exhaustive);
423
-
424
- return std.meta.stringToEnum(E, value) orelse fatal(
425
- "{s}: expected one of {s}, but found '{s}'",
426
- .{ flag, comptime fields_to_comma_list(E), value },
427
- );
428
- }
429
-
430
- fn fields_to_comma_list(comptime E: type) []const u8 {
431
- comptime {
432
- const field_count = std.meta.fields(E).len;
433
- assert(field_count >= 2);
434
-
435
- var result: []const u8 = "";
436
- for (std.meta.fields(E), 0..) |field, field_index| {
437
- const separator = switch (field_index) {
438
- 0 => "",
439
- else => ", ",
440
- field_count - 1 => if (field_count == 2) " or " else ", or ",
441
- };
442
- result = result ++ separator ++ "'" ++ field.name ++ "'";
443
- }
444
- return result;
445
- }
446
- }
447
-
448
- fn flag_name(comptime field: std.builtin.Type.StructField) []const u8 {
449
- return comptime blk: {
450
- assert(!std.mem.eql(u8, field.name, "-"));
451
- assert(!std.mem.eql(u8, field.name, "--"));
452
-
453
- var result: []const u8 = "--";
454
- var index = 0;
455
- while (std.mem.indexOfScalar(u8, field.name[index..], '_')) |i| {
456
- result = result ++ field.name[index..][0..i] ++ "-";
457
- index = index + i + 1;
458
- }
459
- result = result ++ field.name[index..];
460
- break :blk result;
461
- };
462
- }
463
-
464
- test flag_name {
465
- const field = @typeInfo(struct { statsd: bool }).@"struct".fields[0];
466
- try std.testing.expectEqualStrings(flag_name(field), "--statsd");
467
- }
468
-
469
- fn flag_name_positional(comptime field: std.builtin.Type.StructField) []const u8 {
470
- comptime assert(std.mem.indexOfScalar(u8, field.name, '_') == null);
471
- return "<" ++ field.name ++ ">";
472
- }
473
-
474
- /// Fuzz parse_flag_value function:
475
- ///
476
- /// - Check that ok cases return a value.
477
- /// - Check that err cases return an error with a properly formatted diagnostics.
478
- /// - Check that the diagnostic contains specified substring
479
- /// - Random tests with the input alphabet seeded from explicit cases.
480
- /// - Random tests with uniform input.
481
- pub fn parse_flag_value_fuzz(
482
- comptime T: type,
483
- parse_flag_value: fn ([]const u8, *?[]const u8) error{InvalidFlagValue}!T,
484
- cases: struct {
485
- ok: []const struct { []const u8, T },
486
- err: []const struct { []const u8, []const u8 },
487
- },
488
- ) !void {
489
- comptime assert(T.parse_flag_value == parse_flag_value);
490
-
491
- const test_count = 50_000;
492
- const string_size_max = 32;
493
-
494
- const gpa = std.testing.allocator;
495
- var prng = stdx.PRNG.from_seed_testing();
496
-
497
- for (cases.ok) |case| {
498
- const string, const want = case;
499
- assert(string.len > 0);
500
-
501
- var diagnostic: ?[]const u8 = null;
502
- const got = try parse_flag_value(string, &diagnostic);
503
- assert(diagnostic == null);
504
- try std.testing.expectEqual(want, got);
505
- }
506
-
507
- for (cases.err) |case| {
508
- const string, const want_message = case;
509
- assert(string.len > 0); // Empty value are rejected early.
510
-
511
- var diagnostic: ?[]const u8 = null;
512
- if (parse_flag_value(string, &diagnostic)) |value| {
513
- std.debug.print("expected an error, got value: input='{s}', value={}", .{
514
- string,
515
- value,
516
- });
517
- return error.TestUnexpectedResult;
518
- } else |err| switch (err) {
519
- error.InvalidFlagValue => {
520
- try parse_flag_value_check_diagnostic(string, diagnostic);
521
- if (stdx.cut(diagnostic.?, want_message) == null) {
522
- std.debug.print(
523
- "expected diagnostic to contain substring='{s}' diagnostic='{s}'",
524
- .{ want_message, diagnostic.? },
525
- );
526
- return error.TestUnexpectedResult;
527
- }
528
- },
529
- }
530
- }
531
-
532
- var corpus: std.ArrayListUnmanaged(u8) = .empty;
533
- defer corpus.deinit(gpa);
534
-
535
- for (cases.ok) |case| try corpus.appendSlice(gpa, case[0]);
536
- for (cases.err) |case| try corpus.appendSlice(gpa, case[0]);
537
- for (0..5) |_| try corpus.append(gpa, prng.int(u8));
538
-
539
- std.mem.sort(u8, corpus.items, {}, std.sort.asc(u8));
540
-
541
- const alphabet = unique(corpus.items);
542
-
543
- var string_buffer: [string_size_max]u8 = @splat(0);
544
- for (0..test_count) |_| {
545
- const string_size = prng.range_inclusive(usize, 1, string_size_max);
546
- const string = string_buffer[0..string_size];
547
- assert(string.len > 0);
548
- if (prng.boolean()) {
549
- for (string) |*c| c.* = alphabet[prng.index(alphabet)];
550
- } else {
551
- for (string) |*c| c.* = prng.int(u8);
552
- }
553
-
554
- var diagnostic: ?[]const u8 = null;
555
- if (parse_flag_value(string, &diagnostic)) |_| {
556
- assert(diagnostic == null);
557
- } else |err| switch (err) {
558
- error.InvalidFlagValue => try parse_flag_value_check_diagnostic(string, diagnostic),
559
- }
560
- }
561
- }
562
-
563
- fn parse_flag_value_check_diagnostic(string: []const u8, diagnostic: ?[]const u8) !void {
564
- const message = diagnostic orelse {
565
- std.debug.print("expected a diagnostic: string='{s}'", .{string});
566
- return error.TestUnexpectedResult;
567
- };
568
- if (!(message.len > 0 and
569
- std.ascii.isLower(message[0]) and
570
- message[message.len - 1] == ':'))
571
- {
572
- std.debug.print("wrong diagnostic format: string='{s}' diagnostic='{s}'", .{
573
- string,
574
- message,
575
- });
576
- return error.TestUnexpectedResult;
577
- }
578
- }
579
-
580
- fn unique(sorted: []u8) []u8 {
581
- assert(sorted.len > 0);
582
-
583
- var count: usize = 1;
584
- for (1..sorted.len) |index| {
585
- assert(sorted[count - 1] <= sorted[index]);
586
- if (sorted[count - 1] == sorted[index]) {
587
- // Duplicate! Skip to the next index.
588
- } else {
589
- sorted[count] = sorted[index];
590
- count += 1;
591
- }
592
- }
593
-
594
- return sorted[0..count];
595
- }
596
-
597
- // CLI parsing makes a liberal use of `fatal`, so testing it within the process is impossible. We
598
- // test it out of process by:
599
- // - using Zig compiler to build this very file as an executable in a temporary directory,
600
- // - running the following main with various args and capturing stdout, stderr, and the exit code.
601
- // - asserting that the captured values are correct.
602
- // For production builds, don't include the main function.
603
- // This is `if __name__ == "__main__":` at comptime!
604
- pub const main =
605
- if (@import("root") != @This()) {} else struct {
606
- const CLIArgs = union(enum) {
607
- empty,
608
- prefix: struct {
609
- foo: u8 = 0,
610
- foo_bar: u8 = 0,
611
- opt: bool = false,
612
- option: bool = false,
613
- },
614
- positional: struct {
615
- flag: bool = false,
616
-
617
- @"--": void,
618
- p1: []const u8,
619
- p2: []const u8,
620
- p3: ?u32 = null,
621
- p4: ?u32 = null,
622
- },
623
- extended: struct {
624
- flag: bool = false,
625
- @"--": void,
626
- },
627
- required: struct {
628
- foo: u8,
629
- bar: u8,
630
- },
631
- values: struct {
632
- int: u32 = 0,
633
- size: stdx.ByteSize = .{ .value = 0 },
634
- boolean: bool = false,
635
- path: []const u8 = "not-set",
636
- optional: ?[]const u8 = null,
637
- choice: enum { marlowe, shakespeare } = .marlowe,
638
- },
639
- subcommand: union(enum) {
640
- pub const help =
641
- \\subcommand help
642
- \\
643
- ;
644
-
645
- c1: struct { a: bool = false },
646
- c2: struct { b: bool = false },
647
- },
648
-
649
- pub const help =
650
- \\ flags-test-program [flags]
651
- \\
652
- ;
653
- };
654
-
655
- fn main() !void {
656
- var gpa_allocator = std.heap.GeneralPurposeAllocator(.{}){};
657
- const gpa = gpa_allocator.allocator();
658
-
659
- var args = try std.process.argsWithAllocator(gpa);
660
- defer args.deinit();
661
-
662
- const cli_args = parse(&args, CLIArgs);
663
-
664
- const stdout = std.io.getStdOut();
665
- const out_stream = stdout.writer();
666
- switch (cli_args) {
667
- .empty => try out_stream.print("empty\n", .{}),
668
- .prefix => |values| {
669
- try out_stream.print("foo: {}\n", .{values.foo});
670
- try out_stream.print("foo-bar: {}\n", .{values.foo_bar});
671
- try out_stream.print("opt: {}\n", .{values.opt});
672
- try out_stream.print("option: {}\n", .{values.option});
673
- },
674
- .positional => |values| {
675
- try out_stream.print("p1: {s}\n", .{values.p1});
676
- try out_stream.print("p2: {s}\n", .{values.p2});
677
- try out_stream.print("p3: {?}\n", .{values.p3});
678
- try out_stream.print("p4: {?}\n", .{values.p4});
679
- try out_stream.print("flag: {}\n", .{values.flag});
680
- },
681
- .extended => |values| {
682
- try out_stream.print("flag: {}\n", .{values.flag});
683
- while (args.next()) |arg| try out_stream.print("arg: {s}\n", .{arg});
684
- },
685
- .required => |required| {
686
- try out_stream.print("foo: {}\n", .{required.foo});
687
- try out_stream.print("bar: {}\n", .{required.bar});
688
- },
689
- .values => |values| {
690
- try out_stream.print("int: {}\n", .{values.int});
691
- try out_stream.print("size: {}\n", .{values.size.bytes()});
692
- try out_stream.print("boolean: {}\n", .{values.boolean});
693
- try out_stream.print("path: {s}\n", .{values.path});
694
- try out_stream.print("optional: {?s}\n", .{values.optional});
695
- try out_stream.print("choice: {?s}\n", .{@tagName(values.choice)});
696
- },
697
- .subcommand => |values| {
698
- switch (values) {
699
- .c1 => |c1| try out_stream.print("c1.a: {}\n", .{c1.a}),
700
- .c2 => |c2| try out_stream.print("c2.b: {}\n", .{c2.b}),
701
- }
702
- },
703
- }
704
- }
705
- }.main;
706
-
707
- test "flags" {
708
- const Snap = stdx.Snap;
709
- const module_path = "src/stdx";
710
- const snap = Snap.snap_fn(module_path);
711
-
712
- const T = struct {
713
- const T = @This();
714
-
715
- gpa: std.mem.Allocator,
716
- tmp_dir: std.testing.TmpDir,
717
- output_buf: std.ArrayList(u8),
718
- flags_exe_buf: *[std.fs.max_path_bytes]u8,
719
- flags_exe: []const u8,
720
-
721
- fn init(gpa: std.mem.Allocator) !T {
722
- // TODO: Avoid std.posix.getenv() as it currently causes a linker error on windows.
723
- // See: https://github.com/ziglang/zig/issues/8456
724
- const zig_exe = try std.process.getEnvVarOwned(gpa, "ZIG_EXE"); // Set by build.zig
725
- defer gpa.free(zig_exe);
726
-
727
- var tmp_dir = std.testing.tmpDir(.{});
728
- errdefer tmp_dir.cleanup();
729
-
730
- const tmp_dir_path = try std.fs.path.join(gpa, &.{
731
- ".zig-cache",
732
- "tmp",
733
- &tmp_dir.sub_path,
734
- });
735
- defer gpa.free(tmp_dir_path);
736
-
737
- const output_buf = std.ArrayList(u8).init(gpa);
738
- errdefer output_buf.deinit();
739
-
740
- const flags_exe_buf = try gpa.create([std.fs.max_path_bytes]u8);
741
- errdefer gpa.destroy(flags_exe_buf);
742
-
743
- { // Compile this file as an executable!
744
- const path_relative = try std.fs.path.join(gpa, &.{
745
- module_path,
746
- @src().file,
747
- });
748
- defer gpa.free(path_relative);
749
-
750
- const this_file = try std.fs.cwd().realpath(
751
- path_relative,
752
- flags_exe_buf,
753
- );
754
- const argv = [_][]const u8{ zig_exe, "build-exe", this_file };
755
- const exec_result = try std.process.Child.run(.{
756
- .allocator = gpa,
757
- .argv = &argv,
758
- .cwd = tmp_dir_path,
759
- });
760
- defer gpa.free(exec_result.stdout);
761
- defer gpa.free(exec_result.stderr);
762
-
763
- if (exec_result.term.Exited != 0) {
764
- std.debug.print("{s}{s}", .{ exec_result.stdout, exec_result.stderr });
765
- return error.FailedToCompile;
766
- }
767
- }
768
-
769
- const flags_exe = try tmp_dir.dir.realpath(
770
- "flags" ++ comptime builtin.target.exeFileExt(),
771
- flags_exe_buf,
772
- );
773
-
774
- const sanity_check = try std.fs.openFileAbsolute(flags_exe, .{});
775
- sanity_check.close();
776
-
777
- return .{
778
- .gpa = gpa,
779
- .tmp_dir = tmp_dir,
780
- .output_buf = output_buf,
781
- .flags_exe_buf = flags_exe_buf,
782
- .flags_exe = flags_exe,
783
- };
784
- }
785
-
786
- fn deinit(t: *T) void {
787
- t.gpa.destroy(t.flags_exe_buf);
788
- t.output_buf.deinit();
789
- t.tmp_dir.cleanup();
790
- t.* = undefined;
791
- }
792
-
793
- fn check(t: *T, cli: []const []const u8, want: Snap) !void {
794
- const argv = try t.gpa.alloc([]const u8, cli.len + 1);
795
- defer t.gpa.free(argv);
796
-
797
- argv[0] = t.flags_exe;
798
- for (argv[1..], 0..) |*arg, i| {
799
- arg.* = cli[i];
800
- }
801
- if (cli.len > 0) {
802
- assert(argv[argv.len - 1].ptr == cli[cli.len - 1].ptr);
803
- }
804
-
805
- const exec_result = try std.process.Child.run(.{
806
- .allocator = t.gpa,
807
- .argv = argv,
808
- });
809
- defer t.gpa.free(exec_result.stdout);
810
- defer t.gpa.free(exec_result.stderr);
811
-
812
- t.output_buf.clearRetainingCapacity();
813
-
814
- if (exec_result.term.Exited != 0) {
815
- try t.output_buf.writer().print("status: {}\n", .{exec_result.term.Exited});
816
- }
817
- if (exec_result.stdout.len > 0) {
818
- try t.output_buf.writer().print("stdout:\n{s}", .{exec_result.stdout});
819
- }
820
- if (exec_result.stderr.len > 0) {
821
- try t.output_buf.writer().print("stderr:\n{s}", .{exec_result.stderr});
822
- }
823
-
824
- try want.diff(t.output_buf.items);
825
- }
826
- };
827
-
828
- var t = try T.init(std.testing.allocator);
829
- defer t.deinit();
830
-
831
- // Test-cases are roughly in the source order of the corresponding features.
832
-
833
- try t.check(&.{"empty"}, snap(@src(),
834
- \\stdout:
835
- \\empty
836
- \\
837
- ));
838
-
839
- try t.check(&.{}, snap(@src(),
840
- \\status: 1
841
- \\stderr:
842
- \\error: subcommand required, expected 'empty', 'prefix', 'positional', 'extended', 'required', 'values', or 'subcommand'
843
- \\
844
- ));
845
-
846
- try t.check(&.{"-h"}, snap(@src(),
847
- \\stdout:
848
- \\ flags-test-program [flags]
849
- \\
850
- ));
851
-
852
- try t.check(&.{"--help"}, snap(@src(),
853
- \\stdout:
854
- \\ flags-test-program [flags]
855
- \\
856
- ));
857
-
858
- try t.check(&.{""}, snap(@src(),
859
- \\status: 1
860
- \\stderr:
861
- \\error: unknown subcommand: ''
862
- \\
863
- ));
864
-
865
- try t.check(&.{"bogus"}, snap(@src(),
866
- \\status: 1
867
- \\stderr:
868
- \\error: unknown subcommand: 'bogus'
869
- \\
870
- ));
871
-
872
- try t.check(&.{"--int=92"}, snap(@src(),
873
- \\status: 1
874
- \\stderr:
875
- \\error: unknown subcommand: '--int=92'
876
- \\
877
- ));
878
-
879
- try t.check(&.{ "empty", "--help" }, snap(@src(),
880
- \\status: 1
881
- \\stderr:
882
- \\error: unexpected argument: '--help'
883
- \\
884
- ));
885
-
886
- try t.check(&.{ "prefix", "--foo=92" }, snap(@src(),
887
- \\stdout:
888
- \\foo: 92
889
- \\foo-bar: 0
890
- \\opt: false
891
- \\option: false
892
- \\
893
- ));
894
-
895
- try t.check(&.{ "prefix", "--foo-bar=92" }, snap(@src(),
896
- \\stdout:
897
- \\foo: 0
898
- \\foo-bar: 92
899
- \\opt: false
900
- \\option: false
901
- \\
902
- ));
903
-
904
- try t.check(&.{ "prefix", "--foo-baz=92" }, snap(@src(),
905
- \\status: 1
906
- \\stderr:
907
- \\error: --foo: expected value separator '=', but found '-' in '--foo-baz=92'
908
- \\
909
- ));
910
-
911
- try t.check(&.{ "prefix", "--opt" }, snap(@src(),
912
- \\stdout:
913
- \\foo: 0
914
- \\foo-bar: 0
915
- \\opt: true
916
- \\option: false
917
- \\
918
- ));
919
-
920
- try t.check(&.{ "prefix", "--option" }, snap(@src(),
921
- \\stdout:
922
- \\foo: 0
923
- \\foo-bar: 0
924
- \\opt: false
925
- \\option: true
926
- \\
927
- ));
928
-
929
- try t.check(&.{ "prefix", "--optx" }, snap(@src(),
930
- \\status: 1
931
- \\stderr:
932
- \\error: --opt: expected value separator '=', but found 'x' in '--optx'
933
- \\
934
- ));
935
-
936
- try t.check(&.{ "positional", "x", "y" }, snap(@src(),
937
- \\stdout:
938
- \\p1: x
939
- \\p2: y
940
- \\p3: null
941
- \\p4: null
942
- \\flag: false
943
- \\
944
- ));
945
-
946
- try t.check(&.{ "positional", "x", "y", "1" }, snap(@src(),
947
- \\stdout:
948
- \\p1: x
949
- \\p2: y
950
- \\p3: 1
951
- \\p4: null
952
- \\flag: false
953
- \\
954
- ));
955
-
956
- try t.check(&.{ "positional", "x", "y", "1", "2" }, snap(@src(),
957
- \\stdout:
958
- \\p1: x
959
- \\p2: y
960
- \\p3: 1
961
- \\p4: 2
962
- \\flag: false
963
- \\
964
- ));
965
-
966
- try t.check(&.{"positional"}, snap(@src(),
967
- \\status: 1
968
- \\stderr:
969
- \\error: <p1>: argument is required
970
- \\
971
- ));
972
-
973
- try t.check(&.{ "positional", "x" }, snap(@src(),
974
- \\status: 1
975
- \\stderr:
976
- \\error: <p2>: argument is required
977
- \\
978
- ));
979
-
980
- try t.check(&.{ "positional", "x", "y", "z" }, snap(@src(),
981
- \\status: 1
982
- \\stderr:
983
- \\error: <p3>: expected an integer value, but found 'z' (invalid digit)
984
- \\
985
- ));
986
-
987
- try t.check(&.{ "positional", "x", "y", "1", "2", "3" }, snap(@src(),
988
- \\status: 1
989
- \\stderr:
990
- \\error: unexpected argument: '3'
991
- \\
992
- ));
993
-
994
- try t.check(&.{ "positional", "" }, snap(@src(),
995
- \\status: 1
996
- \\stderr:
997
- \\error: <p1>: empty argument
998
- \\
999
- ));
1000
-
1001
- try t.check(&.{ "positional", "x", "--flag" }, snap(@src(),
1002
- \\status: 1
1003
- \\stderr:
1004
- \\error: unexpected trailing option: '--flag'
1005
- \\
1006
- ));
1007
-
1008
- try t.check(&.{ "positional", "x", "--flag", "y" }, snap(@src(),
1009
- \\status: 1
1010
- \\stderr:
1011
- \\error: unexpected trailing option: '--flag'
1012
- \\
1013
- ));
1014
-
1015
- try t.check(&.{ "positional", "--flag", "x", "y" }, snap(@src(),
1016
- \\stdout:
1017
- \\p1: x
1018
- \\p2: y
1019
- \\p3: null
1020
- \\p4: null
1021
- \\flag: true
1022
- \\
1023
- ));
1024
-
1025
- try t.check(&.{ "positional", "--", "x", "y" }, snap(@src(),
1026
- \\status: 1
1027
- \\stderr:
1028
- \\error: unexpected argument: '--'
1029
- \\
1030
- ));
1031
-
1032
- try t.check(&.{ "positional", "--flak", "x", "y" }, snap(@src(),
1033
- \\status: 1
1034
- \\stderr:
1035
- \\error: unexpected argument: '--flak'
1036
- \\
1037
- ));
1038
-
1039
- try t.check(&.{ "required", "--foo=1", "--bar=2" }, snap(@src(),
1040
- \\stdout:
1041
- \\foo: 1
1042
- \\bar: 2
1043
- \\
1044
- ));
1045
-
1046
- try t.check(&.{ "required", "--surprise" }, snap(@src(),
1047
- \\status: 1
1048
- \\stderr:
1049
- \\error: unexpected argument: '--surprise'
1050
- \\
1051
- ));
1052
-
1053
- try t.check(&.{ "required", "--foo=1" }, snap(@src(),
1054
- \\status: 1
1055
- \\stderr:
1056
- \\error: --bar: argument is required
1057
- \\
1058
- ));
1059
-
1060
- try t.check(&.{ "required", "--foo=1", "--bar=2", "--foo=3" }, snap(@src(),
1061
- \\status: 1
1062
- \\stderr:
1063
- \\error: --foo: duplicate argument
1064
- \\
1065
- ));
1066
-
1067
- try t.check(&.{
1068
- "values",
1069
- "--int=92",
1070
- "--size=1GiB",
1071
- "--boolean",
1072
- "--path=/home",
1073
- "--optional=some",
1074
- "--choice=shakespeare",
1075
- }, snap(@src(),
1076
- \\stdout:
1077
- \\int: 92
1078
- \\size: 1073741824
1079
- \\boolean: true
1080
- \\path: /home
1081
- \\optional: some
1082
- \\choice: shakespeare
1083
- \\
1084
- ));
1085
-
1086
- try t.check(&.{"values"}, snap(@src(),
1087
- \\stdout:
1088
- \\int: 0
1089
- \\size: 0
1090
- \\boolean: false
1091
- \\path: not-set
1092
- \\optional: null
1093
- \\choice: marlowe
1094
- \\
1095
- ));
1096
-
1097
- try t.check(&.{ "values", "--boolean=true" }, snap(@src(),
1098
- \\stdout:
1099
- \\int: 0
1100
- \\size: 0
1101
- \\boolean: true
1102
- \\path: not-set
1103
- \\optional: null
1104
- \\choice: marlowe
1105
- \\
1106
- ));
1107
-
1108
- try t.check(&.{ "values", "--boolean=false" }, snap(@src(),
1109
- \\stdout:
1110
- \\int: 0
1111
- \\size: 0
1112
- \\boolean: false
1113
- \\path: not-set
1114
- \\optional: null
1115
- \\choice: marlowe
1116
- \\
1117
- ));
1118
-
1119
- try t.check(&.{ "values", "--boolean=foo" }, snap(@src(),
1120
- \\status: 1
1121
- \\stderr:
1122
- \\error: --boolean: expected one of 'true' or 'false', but found 'foo'
1123
- \\
1124
- ));
1125
-
1126
- try t.check(&.{ "values", "--int" }, snap(@src(),
1127
- \\status: 1
1128
- \\stderr:
1129
- \\error: --int: expected value separator '='
1130
- \\
1131
- ));
1132
-
1133
- try t.check(&.{ "values", "--int:" }, snap(@src(),
1134
- \\status: 1
1135
- \\stderr:
1136
- \\error: --int: expected value separator '=', but found ':' in '--int:'
1137
- \\
1138
- ));
1139
-
1140
- try t.check(&.{ "values", "--int=" }, snap(@src(),
1141
- \\status: 1
1142
- \\stderr:
1143
- \\error: --int: argument requires a value
1144
- \\
1145
- ));
1146
-
1147
- try t.check(&.{ "values", "--int=-92" }, snap(@src(),
1148
- \\status: 1
1149
- \\stderr:
1150
- \\error: --int: expected an integer value, but found '-92' (invalid digit)
1151
- \\
1152
- ));
1153
-
1154
- try t.check(&.{ "values", "--int=_92" }, snap(@src(),
1155
- \\status: 1
1156
- \\stderr:
1157
- \\error: --int: expected an integer value, but found '_92' (invalid digit)
1158
- \\
1159
- ));
1160
-
1161
- try t.check(&.{ "values", "--int=92_" }, snap(@src(),
1162
- \\status: 1
1163
- \\stderr:
1164
- \\error: --int: expected an integer value, but found '92_' (invalid digit)
1165
- \\
1166
- ));
1167
-
1168
- try t.check(&.{ "values", "--int=92" }, snap(@src(),
1169
- \\stdout:
1170
- \\int: 92
1171
- \\size: 0
1172
- \\boolean: false
1173
- \\path: not-set
1174
- \\optional: null
1175
- \\choice: marlowe
1176
- \\
1177
- ));
1178
-
1179
- try t.check(&.{ "values", "--int=900_200" }, snap(@src(),
1180
- \\stdout:
1181
- \\int: 900200
1182
- \\size: 0
1183
- \\boolean: false
1184
- \\path: not-set
1185
- \\optional: null
1186
- \\choice: marlowe
1187
- \\
1188
- ));
1189
-
1190
- try t.check(&.{ "values", "--int=XCII" }, snap(@src(),
1191
- \\status: 1
1192
- \\stderr:
1193
- \\error: --int: expected an integer value, but found 'XCII' (invalid digit)
1194
- \\
1195
- ));
1196
-
1197
- try t.check(&.{ "values", "--int=44444444444444444444" }, snap(@src(),
1198
- \\status: 1
1199
- \\stderr:
1200
- \\error: --int: value exceeds 32-bit unsigned integer: '44444444444444444444'
1201
- \\
1202
- ));
1203
-
1204
- try t.check(&.{ "values", "--int=-0" }, snap(@src(),
1205
- \\status: 1
1206
- \\stderr:
1207
- \\error: --int: expected an integer value, but found '-0' (invalid digit)
1208
- \\
1209
- ));
1210
-
1211
- try t.check(&.{ "values", "--int=+0" }, snap(@src(),
1212
- \\status: 1
1213
- \\stderr:
1214
- \\error: --int: expected an integer value, but found '+0' (invalid digit)
1215
- \\
1216
- ));
1217
-
1218
- try t.check(&.{ "values", "--size=-0" }, snap(@src(),
1219
- \\status: 1
1220
- \\stderr:
1221
- \\error: --size: expected a size, but found: '-0'
1222
- \\
1223
- ));
1224
-
1225
- try t.check(&.{ "values", "--size=+0" }, snap(@src(),
1226
- \\status: 1
1227
- \\stderr:
1228
- \\error: --size: expected a size, but found: '+0'
1229
- \\
1230
- ));
1231
-
1232
- try t.check(&.{ "values", "--size=_1000KiB" }, snap(@src(),
1233
- \\status: 1
1234
- \\stderr:
1235
- \\error: --size: expected a size, but found: '_1000KiB'
1236
- \\
1237
- ));
1238
-
1239
- try t.check(&.{ "values", "--size=1000_KiB" }, snap(@src(),
1240
- \\status: 1
1241
- \\stderr:
1242
- \\error: --size: expected a size, but found: '1000_KiB'
1243
- \\
1244
- ));
1245
-
1246
- try t.check(&.{ "values", "--size=1_000KiB" }, snap(@src(),
1247
- \\stdout:
1248
- \\int: 0
1249
- \\size: 1024000
1250
- \\boolean: false
1251
- \\path: not-set
1252
- \\optional: null
1253
- \\choice: marlowe
1254
- \\
1255
- ));
1256
-
1257
- try t.check(&.{ "values", "--size=3MiB" }, snap(@src(),
1258
- \\stdout:
1259
- \\int: 0
1260
- \\size: 3145728
1261
- \\boolean: false
1262
- \\path: not-set
1263
- \\optional: null
1264
- \\choice: marlowe
1265
- \\
1266
- ));
1267
-
1268
- try t.check(&.{ "values", "--size=44444444444444444444" }, snap(@src(),
1269
- \\status: 1
1270
- \\stderr:
1271
- \\error: --size: value exceeds 64-bit unsigned integer: '44444444444444444444'
1272
- \\
1273
- ));
1274
-
1275
- try t.check(&.{ "values", "--size=100000000000000000" }, snap(@src(),
1276
- \\stdout:
1277
- \\int: 0
1278
- \\size: 100000000000000000
1279
- \\boolean: false
1280
- \\path: not-set
1281
- \\optional: null
1282
- \\choice: marlowe
1283
- \\
1284
- ));
1285
-
1286
- try t.check(&.{ "values", "--size=100000000000000000kib" }, snap(@src(),
1287
- \\status: 1
1288
- \\stderr:
1289
- \\error: --size: size in bytes exceeds 64-bit unsigned integer: '100000000000000000kib'
1290
- \\
1291
- ));
1292
-
1293
- try t.check(&.{ "values", "--size=3bogus" }, snap(@src(),
1294
- \\status: 1
1295
- \\stderr:
1296
- \\error: --size: invalid unit in size, needed KiB, MiB, GiB or TiB: '3bogus'
1297
- \\
1298
- ));
1299
-
1300
- try t.check(&.{ "values", "--size=MiB" }, snap(@src(),
1301
- \\status: 1
1302
- \\stderr:
1303
- \\error: --size: expected a size, but found: 'MiB'
1304
- \\
1305
- ));
1306
-
1307
- try t.check(&.{ "values", "--path=" }, snap(@src(),
1308
- \\status: 1
1309
- \\stderr:
1310
- \\error: --path: argument requires a value
1311
- \\
1312
- ));
1313
-
1314
- try t.check(&.{ "values", "--optional=" }, snap(@src(),
1315
- \\status: 1
1316
- \\stderr:
1317
- \\error: --optional: argument requires a value
1318
- \\
1319
- ));
1320
-
1321
- try t.check(&.{ "values", "--choice=molière" }, snap(@src(),
1322
- \\status: 1
1323
- \\stderr:
1324
- \\error: --choice: expected one of 'marlowe' or 'shakespeare', but found 'molière'
1325
- \\
1326
- ));
1327
-
1328
- try t.check(&.{"subcommand"}, snap(@src(),
1329
- \\status: 1
1330
- \\stderr:
1331
- \\error: subcommand required, expected 'c1' or 'c2'
1332
- \\
1333
- ));
1334
- try t.check(&.{ "subcommand", "c1", "--a" }, snap(@src(),
1335
- \\stdout:
1336
- \\c1.a: true
1337
- \\
1338
- ));
1339
- try t.check(&.{ "subcommand", "c2", "--b" }, snap(@src(),
1340
- \\stdout:
1341
- \\c2.b: true
1342
- \\
1343
- ));
1344
- try t.check(&.{ "subcommand", "c1", "--b" }, snap(@src(),
1345
- \\status: 1
1346
- \\stderr:
1347
- \\error: unexpected argument: '--b'
1348
- \\
1349
- ));
1350
- try t.check(&.{ "subcommand", "c2", "--a" }, snap(@src(),
1351
- \\status: 1
1352
- \\stderr:
1353
- \\error: unexpected argument: '--a'
1354
- \\
1355
- ));
1356
- try t.check(&.{ "subcommand", "--help" }, snap(@src(),
1357
- \\stdout:
1358
- \\subcommand help
1359
- \\
1360
- ));
1361
- try t.check(&.{ "subcommand", "-h" }, snap(@src(),
1362
- \\stdout:
1363
- \\subcommand help
1364
- \\
1365
- ));
1366
-
1367
- try t.check(&.{"extended"}, snap(@src(),
1368
- \\stdout:
1369
- \\flag: false
1370
- \\
1371
- ));
1372
- try t.check(&.{ "extended", "--" }, snap(@src(),
1373
- \\stdout:
1374
- \\flag: false
1375
- \\
1376
- ));
1377
- try t.check(&.{ "extended", "--flag", "--" }, snap(@src(),
1378
- \\stdout:
1379
- \\flag: true
1380
- \\
1381
- ));
1382
- try t.check(&.{ "extended", "a" }, snap(@src(),
1383
- \\status: 1
1384
- \\stderr:
1385
- \\error: unexpected argument: 'a'; expected '-- ...'
1386
- \\
1387
- ));
1388
- try t.check(&.{ "extended", "--", "a" }, snap(@src(),
1389
- \\stdout:
1390
- \\flag: false
1391
- \\arg: a
1392
- \\
1393
- ));
1394
- try t.check(&.{ "extended", "--flag", "--", "a" }, snap(@src(),
1395
- \\stdout:
1396
- \\flag: true
1397
- \\arg: a
1398
- \\
1399
- ));
1400
- try t.check(&.{ "extended", "--", "a", "b" }, snap(@src(),
1401
- \\stdout:
1402
- \\flag: false
1403
- \\arg: a
1404
- \\arg: b
1405
- \\
1406
- ));
1407
- try t.check(&.{ "extended", "--flag", "--", "a", "b" }, snap(@src(),
1408
- \\stdout:
1409
- \\flag: true
1410
- \\arg: a
1411
- \\arg: b
1412
- \\
1413
- ));
1414
- }