hegeltest 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +103 -0
- data/README.md +72 -26
- data/Rakefile +81 -0
- data/docs/README.md +10 -0
- data/docs/adr/0014-name-a-drawn-value-only-when-the-draw-is-the-whole-assigned-value.md +74 -0
- data/docs/adr/0015-follow-the-hegeldev-interface-and-take-changes-upstream-first.md +101 -0
- data/docs/adr/0016-run-mutation-testing-with-mutineer.md +87 -0
- data/docs/adr/0017-raise-the-ruby-floor-to-3-4.md +43 -0
- data/docs/adr/0018-gate-mutation-testing-on-a-committed-baseline.md +74 -0
- data/docs/adr/0019-report-failures-from-the-cases-the-engine-stamps.md +70 -0
- data/docs/adr/0020-derive-span-labels-from-generator-names.md +64 -0
- data/docs/adr/0021-run-a-state-machine-in-rounds-with-its-own-step-count.md +59 -0
- data/docs/adr/0022-keep-microsecond-times-over-a-nanosecond-engine.md +45 -0
- data/docs/adr/0023-leave-unset-settings-to-the-engines-profile.md +50 -0
- data/docs/architecture.md +11 -6
- data/lib/hegel/draw_name.rb +24 -8
- data/lib/hegel/generator.rb +50 -9
- data/lib/hegel/generators.rb +134 -102
- data/lib/hegel/lib_hegel/real.rb +193 -94
- data/lib/hegel/lib_hegel.rb +30 -56
- data/lib/hegel/libhegel_version.rb +1 -1
- data/lib/hegel/report.rb +17 -8
- data/lib/hegel/runner.rb +153 -201
- data/lib/hegel/settings.rb +9 -14
- data/lib/hegel/state_machine.rb +15 -8
- data/lib/hegel/stateful/pool.rb +0 -2
- data/lib/hegel/stateful.rb +64 -36
- data/lib/hegel/syntax/methods.rb +3 -2
- data/lib/hegel/test_case.rb +29 -9
- data/lib/hegel/version.rb +1 -1
- data/lib/hegel.rb +11 -17
- data/lib/tasks/libhegel.rake +9 -2
- data/sig/hegel.rbs +60 -61
- data/skills/hegel-ruby/references/ruby/reference.md +147 -52
- metadata +12 -2
data/lib/hegel/lib_hegel.rb
CHANGED
|
@@ -62,8 +62,8 @@ module Hegel
|
|
|
62
62
|
|
|
63
63
|
# hegel_verbosity_t, named from hegel.h's enum of the same name. Passed
|
|
64
64
|
# to hegel_settings_set_verbosity.
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
HEGEL_VERBOSITY_NORMAL = 0
|
|
66
|
+
HEGEL_VERBOSITY_QUIET = 1
|
|
67
67
|
HEGEL_VERBOSITY_VERBOSE = 2
|
|
68
68
|
HEGEL_VERBOSITY_DEBUG = 3
|
|
69
69
|
|
|
@@ -86,58 +86,10 @@ module Hegel
|
|
|
86
86
|
HEGEL_HC_TEST_CASES_TOO_LARGE = 4
|
|
87
87
|
HEGEL_HC_LARGE_INITIAL_TEST_CASE = 8
|
|
88
88
|
|
|
89
|
-
# hegel_label_t, named from hegel.h's enum of the same name. Passed to
|
|
90
|
-
# hegel_start_span to identify what kind of structure a span groups.
|
|
91
|
-
# Copied through HEGEL_LABEL_SET_CHOICE (value 33). The header
|
|
92
|
-
# describes the last two, HEGEL_LABEL_FRESH_ID and
|
|
93
|
-
# HEGEL_LABEL_SET_CHOICE, as spans the engine opens itself around a
|
|
94
|
-
# hegel_pool_add / hegel_pool_generate call; a caller never passes
|
|
95
|
-
# either to hegel_start_span.
|
|
96
|
-
#
|
|
97
|
-
# The header documents that "Libraries may use any stable u64 to
|
|
98
|
-
# define their own spans." A caller building its own compound
|
|
99
|
-
# generator on top of this boundary can pick any u64 that does not
|
|
100
|
-
# collide with the reserved values below.
|
|
101
|
-
HEGEL_LABEL_LIST = 1
|
|
102
|
-
HEGEL_LABEL_LIST_ELEMENT = 2
|
|
103
|
-
HEGEL_LABEL_SET = 3
|
|
104
|
-
HEGEL_LABEL_SET_ELEMENT = 4
|
|
105
|
-
HEGEL_LABEL_MAP = 5
|
|
106
|
-
HEGEL_LABEL_MAP_ENTRY = 6
|
|
107
|
-
HEGEL_LABEL_TUPLE = 7
|
|
108
|
-
HEGEL_LABEL_ONE_OF = 8
|
|
109
|
-
HEGEL_LABEL_OPTIONAL = 9
|
|
110
|
-
HEGEL_LABEL_FIXED_DICT = 10
|
|
111
|
-
HEGEL_LABEL_FLAT_MAP = 11
|
|
112
|
-
HEGEL_LABEL_FILTER = 12
|
|
113
|
-
HEGEL_LABEL_MAPPED = 13
|
|
114
|
-
HEGEL_LABEL_SAMPLED_FROM = 14
|
|
115
|
-
HEGEL_LABEL_ENUM_VARIANT = 15
|
|
116
|
-
HEGEL_LABEL_FEATURE_FLAG = 16
|
|
117
|
-
HEGEL_LABEL_REGEX = 17
|
|
118
|
-
HEGEL_LABEL_EMAIL = 18
|
|
119
|
-
HEGEL_LABEL_URL = 19
|
|
120
|
-
HEGEL_LABEL_DOMAIN = 20
|
|
121
|
-
HEGEL_LABEL_DATE = 21
|
|
122
|
-
HEGEL_LABEL_TIME = 22
|
|
123
|
-
HEGEL_LABEL_DATETIME = 23
|
|
124
|
-
HEGEL_LABEL_UUID = 24
|
|
125
|
-
HEGEL_LABEL_IP_ADDRESS = 25
|
|
126
|
-
HEGEL_LABEL_INTEGER = 26
|
|
127
|
-
HEGEL_LABEL_FLOAT = 27
|
|
128
|
-
HEGEL_LABEL_BOOLEAN = 28
|
|
129
|
-
HEGEL_LABEL_BYTES = 29
|
|
130
|
-
HEGEL_LABEL_STRING = 30
|
|
131
|
-
HEGEL_LABEL_STATEFUL_RULE = 31
|
|
132
|
-
HEGEL_LABEL_FRESH_ID = 32
|
|
133
|
-
HEGEL_LABEL_SET_CHOICE = 33
|
|
134
|
-
|
|
135
89
|
# HEGEL_STATE_MACHINE_DONE, named from hegel.h's #define of the same
|
|
136
|
-
# name.
|
|
137
|
-
#
|
|
138
|
-
|
|
139
|
-
# that raw sentinel is returned rather than translated to nil.
|
|
140
|
-
HEGEL_STATE_MACHINE_DONE = -1
|
|
90
|
+
# name, INT64_MIN. hegel_state_machine_next_group writes it once the
|
|
91
|
+
# machine is done, and hegel_state_machine_next_rule once the round is.
|
|
92
|
+
HEGEL_STATE_MACHINE_DONE = -(2**63)
|
|
141
93
|
|
|
142
94
|
# hegel_new_collection's max_size accepts UINT64_MAX to mean "no upper
|
|
143
95
|
# bound", in the header's own words. Ruby has no fixed-width integer
|
|
@@ -162,7 +114,7 @@ module Hegel
|
|
|
162
114
|
generate_boolean generate_integer generate_integer_big
|
|
163
115
|
run_result run_result_free run_result_status run_result_error
|
|
164
116
|
run_result_failure_count run_result_failure failure_free failure_origin
|
|
165
|
-
failure_reproduction_blob
|
|
117
|
+
failure_reproduction_blob failure_caveat run_start_blob test_case_should_capture
|
|
166
118
|
start_span stop_span
|
|
167
119
|
new_collection collection_more collection_reject collection_free
|
|
168
120
|
generate_float
|
|
@@ -172,10 +124,11 @@ module Hegel
|
|
|
172
124
|
generate_ipv4 generate_ipv6 generate_uuid
|
|
173
125
|
generate_date generate_time generate_datetime
|
|
174
126
|
settings_set_phases settings_set_suppress_health_check settings_set_report_multiple_failures
|
|
175
|
-
settings_set_database_key
|
|
127
|
+
settings_set_database_key
|
|
176
128
|
target
|
|
177
129
|
new_pool pool_add pool_generate pool_free
|
|
178
|
-
new_state_machine state_machine_next_rule state_machine_rule_rejected
|
|
130
|
+
new_state_machine state_machine_next_group state_machine_next_rule state_machine_rule_rejected
|
|
131
|
+
state_machine_should_check_invariant state_machine_free
|
|
179
132
|
].freeze
|
|
180
133
|
|
|
181
134
|
module_function
|
|
@@ -234,6 +187,27 @@ module Hegel
|
|
|
234
187
|
MESSAGE
|
|
235
188
|
end
|
|
236
189
|
|
|
190
|
+
# A span label is an opaque u64 that names the generator which opened
|
|
191
|
+
# the span. The engine treats two spans with one label as draws of one
|
|
192
|
+
# generator, and swaps or reorders them when it shrinks. hegel.h defines
|
|
193
|
+
# hegel_label_from_name as 64-bit FNV-1a over the name's bytes and lets
|
|
194
|
+
# a binding compute it itself. hegel_label_combine is the same hash over
|
|
195
|
+
# each label's eight little-endian bytes in order, which hegel-rust
|
|
196
|
+
# computes the same way. Computing both here saves a native call per
|
|
197
|
+
# generator built.
|
|
198
|
+
def label_from_name(name)
|
|
199
|
+
fnv1a(name.b.bytes)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def label_combine(labels)
|
|
203
|
+
fnv1a(labels.pack("Q<*").bytes)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def fnv1a(bytes)
|
|
207
|
+
bytes.reduce(0xcbf29ce484222325) { |hash, byte| ((hash ^ byte) * 0x100000001b3) & 0xffff_ffff_ffff_ffff }
|
|
208
|
+
end
|
|
209
|
+
private_class_method :fnv1a
|
|
210
|
+
|
|
237
211
|
# hegel_generate_integer_big's own documented convention for
|
|
238
212
|
# min_value/max_value/out_value: two's-complement little-endian signed
|
|
239
213
|
# byte buffers. Pure Ruby arithmetic, no native marshalling, so this is
|
|
@@ -5,5 +5,5 @@ module Hegel
|
|
|
5
5
|
# Hegel::VERSION (the gem's own release): hegel-go and hegel-typescript keep
|
|
6
6
|
# the two separate too, so bumping the pinned engine can land as its own
|
|
7
7
|
# commit without also releasing a new gem version.
|
|
8
|
-
LIBHEGEL_VERSION = "0.
|
|
8
|
+
LIBHEGEL_VERSION = "0.45.0"
|
|
9
9
|
end
|
data/lib/hegel/report.rb
CHANGED
|
@@ -14,11 +14,14 @@ module Hegel
|
|
|
14
14
|
# the generation phase's own counts up to that failure's first
|
|
15
15
|
# appearance (see Hegel::Runner::GenerationStats), not the shrink
|
|
16
16
|
# phase's. +entries+ is the [:draw, name, value] / [:note, message] list
|
|
17
|
-
# Hegel::TestCase recorded on the
|
|
17
|
+
# Hegel::TestCase recorded on the stamped case that produced this
|
|
18
18
|
# failure, in call order, still un-#inspect'd/un-#to_s'd (see
|
|
19
19
|
# Hegel::TestCase#record_draw and #note for why). +blob+ is the string
|
|
20
|
-
# Hegel.test(reproduce_failure:) accepts to replay this same failure
|
|
21
|
-
|
|
20
|
+
# Hegel.test(reproduce_failure:) accepts to replay this same failure, or
|
|
21
|
+
# nil when the engine produced none. +caveat+ is the engine's own account
|
|
22
|
+
# of how reliably a nondeterministic failure reproduced, or nil for a
|
|
23
|
+
# deterministic one.
|
|
24
|
+
Failure = Struct.new(:test_cases, :discarded, :entries, :blob, :caveat)
|
|
22
25
|
|
|
23
26
|
module_function
|
|
24
27
|
|
|
@@ -50,8 +53,11 @@ module Hegel
|
|
|
50
53
|
|
|
51
54
|
# Renders one failure's block: its "Falsified after" header, its
|
|
52
55
|
# entries in call order (:draw #inspect'd, :note #to_s'd -- both here,
|
|
53
|
-
# on report assembly, not when Hegel::TestCase recorded them),
|
|
54
|
-
#
|
|
56
|
+
# on report assembly, not when Hegel::TestCase recorded them), the
|
|
57
|
+
# engine's caveat when it gave one, and how to reproduce it when there is
|
|
58
|
+
# a blob. hegel-rust prints the caveat as a "note:" line and leaves the
|
|
59
|
+
# reproduction line out for a failure with no blob, and this report does
|
|
60
|
+
# the same. A :note shares the :draw lines' 2-space indent
|
|
55
61
|
# deliberately: both belong to the same block, and a different indent
|
|
56
62
|
# would read as a different kind of thing instead of the same
|
|
57
63
|
# call-order list.
|
|
@@ -67,9 +73,12 @@ module Hegel
|
|
|
67
73
|
lines << " #{message}"
|
|
68
74
|
end
|
|
69
75
|
end
|
|
70
|
-
lines
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
lines.push("", "note: #{failure.caveat}") if failure.caveat
|
|
77
|
+
if failure.blob
|
|
78
|
+
lines << ""
|
|
79
|
+
lines << "To reproduce this failure, pass the blob below to Hegel.test:"
|
|
80
|
+
lines << " reproduce_failure: #{failure.blob.inspect}"
|
|
81
|
+
end
|
|
73
82
|
lines.join("\n")
|
|
74
83
|
end
|
|
75
84
|
|