Class: Hegel::TestCase
- Inherits:
-
Object
- Object
- Hegel::TestCase
- Defined in:
- lib/hegel/test_case.rb,
sig/hegel.rbs
Overview
Wraps one libhegel test-case handle: the native draw surface (#generate_integer, #start_span, #new_collection, and so on) every Hegel::Generator#do_draw is built on, plus the recording entry points a caller (or #draw) reaches for -- #draw_integer/#draw_boolean for the two primitive draws, #draw for a Hegel::Generator, #note for a message, and #assume/#reject to discard the case outright.
The native methods below intentionally do not record: a Hegel::Generator composing several of them (Hegel::Generators::ArrayGenerator drawing one element per loop iteration, say) must produce exactly one report entry for the whole compound value, not one per native call it happens to make. Only #draw_integer, #draw_boolean, #draw, and #note record, each exactly once per call, tagged :draw or :note so a rendered report can tell the two apart while keeping the call order they share (see #record_draw and #note, and Hegel::Report.assign_names, which numbers only the :draw entries).
Constant Summary collapse
- DEFAULT_DRAW_NAME =
#name_for's fallback when a draw has no better name (see below).
"draw"- DRAW_CALLER_DEPTH =
Frames from #name_for's own caller_locations call up to the user's own source line: #record_draw's call to #name_for (1), the public draw_integer/draw_boolean/draw call to #record_draw (2), and the user's own call to that public method (3). The same depth serves #draw as it does #draw_integer/#draw_boolean: #draw calls #record_draw only after Hegel::Generator#do_draw has already returned, so a generator's own frames (and any native calls it made) are off the stack by the time #record_draw runs, leaving the same three frames between #name_for and the user's own call site either way. Verified empirically (see test/hegel/test_runner.rb), not just reasoned about: Ruby's caller_locations counts real stack frames, and a wrong guess here would misname every drawn value, not just fail loudly.
3
Instance Attribute Summary collapse
-
#entries ⇒ Array[[:draw, String, untyped] | [:note, untyped]]?
readonly
The [:draw, name, value] / [:note, message] entries recorded so far, in call order, or nil when this instance was not built to record.
Instance Method Summary collapse
-
#assume(condition) ⇒ void
Discards this test case (see #reject) unless
conditionholds. -
#collection_free(collection) ⇒ Object
hegel_collection_free.
-
#collection_more(collection) ⇒ Boolean
hegel_collection_more: whether to draw another element into
collection. -
#collection_reject(collection, why: nil) ⇒ Object
hegel_collection_reject: tells libhegel the element most recently drawn under
collectionis invalid (a duplicate key or value, for Hegel::Generators::SetGenerator/HashGenerator), so the next #collection_more call offers another attempt at the same slot instead of treating the collection as one element closer to done. -
#draw(generator, label: nil) ⇒ Object
Draws
generator(a Hegel::Generator) and records the single value it produced, however many native callsgeneratormade to produce it. -
#draw_boolean(p = 0.5, label: nil) ⇒ Boolean
hegel_generate_boolean: true with probability
p(default 0.5). -
#draw_integer(min_value, max_value, label: nil) ⇒ Integer
hegel_generate_integer: an integer in [min_value, max_value].
-
#free_pools ⇒ void
Releases every pool #new_pool opened on this test case.
-
#generate_boolean(p = 0.5) ⇒ Boolean
hegel_generate_boolean, without recording.
-
#generate_bytes(min_size, max_size) ⇒ String
hegel_generate_bytes.
-
#generate_date(min_value, max_value) ⇒ Array[Integer]
hegel_generate_date, without recording.
-
#generate_datetime(min_date, min_time, max_date, max_time) ⇒ [Array[Integer], Array[Integer]]
hegel_generate_datetime, without recording.
-
#generate_float(width, min_value, max_value, allow_nan:, allow_infinity:, exclude_min:, exclude_max:, smallest_nonzero_magnitude:) ⇒ Float
hegel_generate_float.
-
#generate_integer(min_value, max_value) ⇒ Integer
hegel_generate_integer, without recording.
-
#generate_integer_big(min_value, max_value) ⇒ Integer
hegel_generate_integer_big, without recording.
-
#generate_ipv4 ⇒ String
hegel_generate_ipv4, returning the address's 4 raw bytes.
-
#generate_ipv6 ⇒ String
hegel_generate_ipv6, returning the address's 16 raw bytes.
-
#generate_string(generator) ⇒ String
hegel_generate_string against
generator(from #with_text_generator, #with_regex_generator, #with_email_generator, #with_url_generator, or #with_domain_generator). -
#generate_time(min_value, max_value) ⇒ Array[Integer]
hegel_generate_time, without recording.
-
#generate_uuid(version, has_version) ⇒ String
hegel_generate_uuid, returning 16 raw bytes.
-
#initialize(impl, ctx, handle, record: false) ⇒ TestCase
constructor
implandctxare carried alongsidehandleso each draw call can reach the same LibHegel implementation and context the run loop opened, without this class knowing anything about the native binding layer or the Fake. -
#new_collection(min_size, max_size) ⇒ Object
hegel_new_collection: Hegel::Generators::ArrayGenerator's own sizing primitive, paired with #collection_more and #collection_free.
-
#new_pool ⇒ Object
hegel_new_pool: opens a native pool handle and records it in @pools, so #free_pools can release it once this test case is done.
-
#new_state_machine(rule_names, invariant_names) ⇒ Object
hegel_new_state_machine: opens the state-machine handle Hegel::Stateful.run drives for the rest of one stateful test.
-
#note(message = nil) ⇒ void
Records
message(or, from the block form, its return value) for the eventual failure report, interleaved with draws in call order (see #record_draw and the :entries tag on #entries). -
#pool_add(pool) ⇒ Integer
hegel_pool_add: a fresh variable id from
pool, for the caller to associate with the value it just generated. -
#pool_free(pool) ⇒ nil
hegel_pool_free.
-
#pool_generate(pool, consume) ⇒ Integer
hegel_pool_generate: the variable id libhegel chose from
pool(and can shrink which one it chose),consumetrue removing it from the pool. -
#reject ⇒ bot
Discards this test case unconditionally, with no reason attached (the same shape as hegel-rust's own TestCase::reject; distinct from #collection_reject, which rejects one drawn element rather than the whole case).
-
#start_span(label) ⇒ Object
hegel_start_span, labelled with one of the Hegel::LibHegel:: HEGEL_LABEL_* constants.
-
#state_machine_free(state_machine) ⇒ nil
hegel_state_machine_free.
-
#state_machine_next_rule(state_machine) ⇒ Integer
hegel_state_machine_next_rule: the index (into the
rule_names#new_state_machine was given) of the next rule to run, or LibHegel::HEGEL_STATE_MACHINE_DONE once this test case's step budget is spent. -
#state_machine_rule_rejected(state_machine) ⇒ nil
hegel_state_machine_rule_rejected: tells libhegel the rule most recently returned by #state_machine_next_rule stopped early on a failed assumption, so it does not count toward the step budget.
-
#stop_span(discard: false) ⇒ Object
hegel_stop_span, closing the span #start_span most recently opened.
-
#string_generator_domain(max_length) ⇒ Object
hegel_string_generator_domain.
-
#string_generator_email ⇒ Object
hegel_string_generator_email.
-
#string_generator_free(generator) ⇒ nil
hegel_string_generator_free, for a handle built by #string_generator_regex, #string_generator_email, #string_generator_url, or #string_generator_domain.
-
#string_generator_regex(pattern, fullmatch, alphabet = nil) ⇒ Object
hegel_string_generator_regex.
-
#string_generator_url ⇒ Object
hegel_string_generator_url.
-
#target(value, label: "") ⇒ nil
hegel_target: records
valueas a numeric observation for libhegel's own hill-climbing between generation rounds, underlabel. -
#with_domain_generator(max_length:, &block) ⇒ void
Runs the block with a domain-name string generator handle built from
max_length(see #string_generator_domain), freed the same way as #with_regex_generator. -
#with_email_generator(&block) ⇒ void
Runs the block with an email-address string generator handle (see #string_generator_email), freed the same way as #with_regex_generator.
-
#with_regex_generator(pattern, fullmatch:, &block) ⇒ void
Runs the block with a regex-matching string generator handle built from +pattern+/+fullmatch+ (see #string_generator_regex), freeing it via #with_generator_handle whether the block returns or raises.
-
#with_text_generator(**kwargs, &block) ⇒ void
Runs the block with a text generator handle scoped to this one call, freeing it before returning.
-
#with_url_generator(&block) ⇒ void
Runs the block with a URL string generator handle (see #string_generator_url), freed the same way as #with_regex_generator.
Constructor Details
#initialize(impl, ctx, handle, record: false) ⇒ TestCase
impl and ctx are carried alongside handle so each draw call can
reach the same LibHegel implementation and context the run loop opened,
without this class knowing anything about the native binding layer or
the Fake.
record defaults to false: recording is Hegel::Runner's decision, made
only for the one, already-shrunk replay that produces a failure report
(see #record_draw for why every other iteration skips it).
51 52 53 54 55 56 57 58 |
# File 'lib/hegel/test_case.rb', line 51 def initialize(impl, ctx, handle, record: false) @impl = impl @ctx = ctx @handle = handle @record = record @entries = record ? [] : nil @pools = [] end |
Instance Attribute Details
#entries ⇒ Array[[:draw, String, untyped] | [:note, untyped]]? (readonly)
The [:draw, name, value] / [:note, message] entries recorded so far, in call order, or nil when this instance was not built to record. Hegel::Runner reads this once, after the block that owns this test case has run to completion or raised. One tagged list rather than a draws list and a separate notes list, so a note recorded between two draws stays between them in the report -- the same interleaving hegel-rust gets for free by sending both to one output callback.
67 68 69 |
# File 'lib/hegel/test_case.rb', line 67 def entries @entries end |
Instance Method Details
#assume(condition) ⇒ void
97 98 99 |
# File 'lib/hegel/test_case.rb', line 97 def assume(condition) reject unless condition end |
#collection_free(collection) ⇒ Object
hegel_collection_free.
253 254 255 |
# File 'lib/hegel/test_case.rb', line 253 def collection_free(collection) @impl.collection_free(@ctx, collection) end |
#collection_more(collection) ⇒ Boolean
hegel_collection_more: whether to draw another element into
collection.
239 240 241 |
# File 'lib/hegel/test_case.rb', line 239 def collection_more(collection) @impl.collection_more(@ctx, @handle, collection) end |
#collection_reject(collection, why: nil) ⇒ Object
hegel_collection_reject: tells libhegel the element most recently
drawn under collection is invalid (a duplicate key or value, for
Hegel::Generators::SetGenerator/HashGenerator), so the next
#collection_more call offers another attempt at the same slot instead
of treating the collection as one element closer to done.
248 249 250 |
# File 'lib/hegel/test_case.rb', line 248 def collection_reject(collection, why: nil) @impl.collection_reject(@ctx, @handle, collection, why) end |
#draw(generator, label: nil) ⇒ Object
Draws generator (a Hegel::Generator) and records the single value it
produced, however many native calls generator made to produce it.
label is threaded through to #record_draw the same way it is for
#draw_integer/#draw_boolean, wins over a recovered name the same way.
87 88 89 90 91 |
# File 'lib/hegel/test_case.rb', line 87 def draw(generator, label: nil) value = generator.do_draw(self) record_draw(label, value) value end |
#draw_boolean(p = 0.5, label: nil) ⇒ Boolean
hegel_generate_boolean: true with probability p (default 0.5).
77 78 79 80 81 |
# File 'lib/hegel/test_case.rb', line 77 def draw_boolean(p = 0.5, label: nil) value = generate_boolean(p) record_draw(label, value) value end |
#draw_integer(min_value, max_value, label: nil) ⇒ Integer
hegel_generate_integer: an integer in [min_value, max_value].
70 71 72 73 74 |
# File 'lib/hegel/test_case.rb', line 70 def draw_integer(min_value, max_value, label: nil) value = generate_integer(min_value, max_value) record_draw(label, value) value end |
#free_pools ⇒ void
This method returns an undefined value.
Releases every pool #new_pool opened on this test case. Hegel::Runner calls this exactly once, in the same place it frees the test-case handle itself, before that handle goes: docs/adr/0011 decides the test case is a pool's owner, not whichever rule happened to call Hegel::Stateful::Pool.new, since that code has no place of its own to free one.
416 417 418 |
# File 'lib/hegel/test_case.rb', line 416 def free_pools @pools.each { |pool| pool_free(pool) } end |
#generate_boolean(p = 0.5) ⇒ Boolean
hegel_generate_boolean, without recording. Hegel::Generators:: BooleanGenerator's own primitive; #draw_boolean is this plus recording.
168 169 170 |
# File 'lib/hegel/test_case.rb', line 168 def generate_boolean(p = 0.5) @impl.generate_boolean(@ctx, @handle, p, false, false) end |
#generate_bytes(min_size, max_size) ⇒ String
hegel_generate_bytes. A future Hegel::Generators::BinaryGenerator's own primitive, the bytes counterpart to #generate_string.
303 304 305 |
# File 'lib/hegel/test_case.rb', line 303 def generate_bytes(min_size, max_size) @impl.generate_bytes(@ctx, @handle, min_size, max_size) end |
#generate_date(min_value, max_value) ⇒ Array[Integer]
hegel_generate_date, without recording. Hegel::Generators:: DatesGenerator's own primitive. +min_value+/+max_value+ are each a [year, month, day] Array; the return value is the same shape.
456 457 458 |
# File 'lib/hegel/test_case.rb', line 456 def generate_date(min_value, max_value) @impl.generate_date(@ctx, @handle, min_value, max_value) end |
#generate_datetime(min_date, min_time, max_date, max_time) ⇒ [Array[Integer], Array[Integer]]
hegel_generate_datetime, without recording. Hegel::Generators:: DatetimesGenerator's own primitive. +min_date+/+max_date+ are each a [year, month, day] Array, +min_time+/+max_time+ each an [hour, minute, second, microsecond] Array; the return value is a [[year, month, day], [hour, minute, second, microsecond]] pair.
473 474 475 |
# File 'lib/hegel/test_case.rb', line 473 def generate_datetime(min_date, min_time, max_date, max_time) @impl.generate_datetime(@ctx, @handle, min_date, min_time, max_date, max_time) end |
#generate_float(width, min_value, max_value, allow_nan:, allow_infinity:, exclude_min:, exclude_max:, smallest_nonzero_magnitude:) ⇒ Float
hegel_generate_float. Hegel::Generators::FloatGenerator's own primitive.
174 175 176 177 178 |
# File 'lib/hegel/test_case.rb', line 174 def generate_float(width, min_value, max_value, allow_nan:, allow_infinity:, exclude_min:, exclude_max:, smallest_nonzero_magnitude:) @impl.generate_float(@ctx, @handle, width, min_value, max_value, allow_nan, allow_infinity, exclude_min, exclude_max, smallest_nonzero_magnitude) end |
#generate_integer(min_value, max_value) ⇒ Integer
hegel_generate_integer, without recording. Hegel::Generators:: IntegerGenerator's own primitive; #draw_integer is this plus recording.
154 155 156 |
# File 'lib/hegel/test_case.rb', line 154 def generate_integer(min_value, max_value) @impl.generate_integer(@ctx, @handle, min_value, max_value) end |
#generate_integer_big(min_value, max_value) ⇒ Integer
hegel_generate_integer_big, without recording. Hegel::Generators:: IntegerGenerator's own primitive for bounds outside int64_t's range, used instead of #generate_integer only then; see IntegerGenerator#do_draw.
161 162 163 |
# File 'lib/hegel/test_case.rb', line 161 def generate_integer_big(min_value, max_value) @impl.generate_integer_big(@ctx, @handle, min_value, max_value) end |
#generate_ipv4 ⇒ String
hegel_generate_ipv4, returning the address's 4 raw bytes. Converting to a caller-facing address type (IPAddr or similar) is left to the generator built on top of this call.
310 311 312 |
# File 'lib/hegel/test_case.rb', line 310 def generate_ipv4 @impl.generate_ipv4(@ctx, @handle) end |
#generate_ipv6 ⇒ String
hegel_generate_ipv6, returning the address's 16 raw bytes. Same division of labor as #generate_ipv4.
316 317 318 |
# File 'lib/hegel/test_case.rb', line 316 def generate_ipv6 @impl.generate_ipv6(@ctx, @handle) end |
#generate_string(generator) ⇒ String
hegel_generate_string against generator (from #with_text_generator,
#with_regex_generator, #with_email_generator, #with_url_generator, or
#with_domain_generator).
297 298 299 |
# File 'lib/hegel/test_case.rb', line 297 def generate_string(generator) @impl.generate_string(@ctx, @handle, generator) end |
#generate_time(min_value, max_value) ⇒ Array[Integer]
hegel_generate_time, without recording. Hegel::Generators:: TimesGenerator's own primitive. +min_value+/+max_value+ are each an [hour, minute, second, microsecond] Array; the return value is the same shape.
464 465 466 |
# File 'lib/hegel/test_case.rb', line 464 def generate_time(min_value, max_value) @impl.generate_time(@ctx, @handle, min_value, max_value) end |
#generate_uuid(version, has_version) ⇒ String
hegel_generate_uuid, returning 16 raw bytes. Hegel::Generators:: UuidsGenerator's own primitive; converting the bytes to the standard hex String is that generator's job, the same division of labor #generate_ipv4/#generate_ipv6 already follow.
324 325 326 |
# File 'lib/hegel/test_case.rb', line 324 def generate_uuid(version, has_version) @impl.generate_uuid(@ctx, @handle, version, has_version) end |
#new_collection(min_size, max_size) ⇒ Object
hegel_new_collection: Hegel::Generators::ArrayGenerator's own sizing primitive, paired with #collection_more and #collection_free.
233 234 235 |
# File 'lib/hegel/test_case.rb', line 233 def new_collection(min_size, max_size) @impl.new_collection(@ctx, @handle, min_size, max_size) end |
#new_pool ⇒ Object
hegel_new_pool: opens a native pool handle and records it in @pools, so #free_pools can release it once this test case is done. Recorded here, not by a second call a caller must remember to make, so a caller of Hegel::Stateful::Pool.new cannot forget it and leak the handle -- docs/adr/0011 has the ownership decision behind this.
378 379 380 381 382 |
# File 'lib/hegel/test_case.rb', line 378 def new_pool pool = @impl.new_pool(@ctx, @handle) @pools << pool pool end |
#new_state_machine(rule_names, invariant_names) ⇒ Object
hegel_new_state_machine: opens the state-machine handle Hegel::Stateful.run drives for the rest of one stateful test. Kept here rather than on that module, the same reason every other native call is a method on this class: Hegel::Stateful never touches @impl or
425 426 427 |
# File 'lib/hegel/test_case.rb', line 425 def new_state_machine(rule_names, invariant_names) @impl.new_state_machine(@ctx, @handle, rule_names, invariant_names) end |
#note(message = nil) ⇒ void
This method returns an undefined value.
Records message (or, from the block form, its return value) for the
eventual failure report, interleaved with draws in call order (see
#record_draw and the :entries tag on #entries). Takes exactly one of
message or a block; hegel-rust's own TestCase::note takes only a
message, so the block form is this binding's own addition, kept to
the same "note" name and String content once evaluated.
The block form exists to skip building the string on an iteration that will not record: Hegel::Runner.drive's own comment measured roughly 1000 iterations for a 20-test-case run that fails every time, and a stateful test's step loop calls #note once per step, so the avoided work is not incidental.
Validates before the #@record check, not after: checking only on the recording iteration would let a caller's mistake reach only the final replay instead of surfacing on the very first call.
message (or the block's value) is kept as given, not #to_s'd here --
the same reason #record_draw keeps a drawn value un-#inspect'd.
Hegel::Report does that formatting once, at report assembly, not on
every recording pass.
Decided simplification, unlike hegel-rust: this does not surface a note on every iteration under a higher verbosity. Two reasons. First, this binding runs with libhegel's own output callback set to NULL (Hegel::LibHegel::Real#run_start passes it, and says why), so there is no engine-printed line for a per-iteration note to line up with. Second, printing on every iteration would reintroduce the per-case cost the block form above exists to avoid.
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/hegel/test_case.rb', line 140 def note( = nil) = !.nil? if == block_given? raise Hegel::Error, "hegel: note requires exactly one of a message or a block" end return unless @record @entries << [:note, ? : yield] end |
#pool_add(pool) ⇒ Integer
hegel_pool_add: a fresh variable id from pool, for the caller to
associate with the value it just generated. Hegel::Stateful::Pool#add's
own primitive.
387 388 389 |
# File 'lib/hegel/test_case.rb', line 387 def pool_add(pool) @impl.pool_add(@ctx, @handle, pool) end |
#pool_free(pool) ⇒ nil
hegel_pool_free. Not called directly by a caller of Hegel::Stateful::Pool -- only #free_pools below, which Hegel::Runner calls once this test case is done -- but kept its own wrapper the same as every other native call this class exposes.
406 407 408 |
# File 'lib/hegel/test_case.rb', line 406 def pool_free(pool) @impl.pool_free(@ctx, pool) end |
#pool_generate(pool, consume) ⇒ Integer
hegel_pool_generate: the variable id libhegel chose from pool (and
can shrink which one it chose), consume true removing it from the
pool. Hegel::Stateful::Pool's two generators' own primitive. No
emptiness check here: the header documents HEGEL_E_ASSUME as this
call's own answer for an empty pool, and LibHegel.check! already
translates that to Hegel::AssumeFailed, the same as every other
assumption failure.
398 399 400 |
# File 'lib/hegel/test_case.rb', line 398 def pool_generate(pool, consume) @impl.pool_generate(@ctx, @handle, pool, consume) end |
#reject ⇒ bot
Discards this test case unconditionally, with no reason attached (the same shape as hegel-rust's own TestCase::reject; distinct from #collection_reject, which rejects one drawn element rather than the whole case). Raises Hegel::AssumeFailed, which Hegel::Runner.classify already translates to HEGEL_STATUS_INVALID -- that translation is not this method's concern.
107 108 109 |
# File 'lib/hegel/test_case.rb', line 107 def reject raise Hegel::AssumeFailed, "hegel: an assumption failed; this test case is discarded" end |
#start_span(label) ⇒ Object
hegel_start_span, labelled with one of the Hegel::LibHegel:: HEGEL_LABEL_* constants. Every compound Hegel::Generator (map, filter, arrays) opens one of these around its own draw; see #stop_span.
220 221 222 |
# File 'lib/hegel/test_case.rb', line 220 def start_span(label) @impl.start_span(@ctx, @handle, label) end |
#state_machine_free(state_machine) ⇒ nil
hegel_state_machine_free. Takes no test-case handle, unlike every
other #state_machine_* method here: the header documents a
state-machine handle as freeable through any handle of the same
test-case family, and LibHegel::Real#state_machine_free's own bind
reflects that by taking only ctx and the state-machine handle.
449 450 451 |
# File 'lib/hegel/test_case.rb', line 449 def state_machine_free(state_machine) @impl.state_machine_free(@ctx, state_machine) end |
#state_machine_next_rule(state_machine) ⇒ Integer
hegel_state_machine_next_rule: the index (into the rule_names
#new_state_machine was given) of the next rule to run, or
LibHegel::HEGEL_STATE_MACHINE_DONE once this test case's step budget
is spent.
433 434 435 |
# File 'lib/hegel/test_case.rb', line 433 def state_machine_next_rule(state_machine) @impl.state_machine_next_rule(@ctx, @handle, state_machine) end |
#state_machine_rule_rejected(state_machine) ⇒ nil
hegel_state_machine_rule_rejected: tells libhegel the rule most recently returned by #state_machine_next_rule stopped early on a failed assumption, so it does not count toward the step budget.
440 441 442 |
# File 'lib/hegel/test_case.rb', line 440 def state_machine_rule_rejected(state_machine) @impl.state_machine_rule_rejected(@ctx, @handle, state_machine) end |
#stop_span(discard: false) ⇒ Object
hegel_stop_span, closing the span #start_span most recently opened.
discard true marks it rejected (a filter predicate that did not
hold), so libhegel retries from before the span opened.
227 228 229 |
# File 'lib/hegel/test_case.rb', line 227 def stop_span(discard: false) @impl.stop_span(@ctx, @handle, discard) end |
#string_generator_domain(max_length) ⇒ Object
hegel_string_generator_domain. Public for the same reason #string_generator_regex is; reached only through #with_domain_generator otherwise.
358 359 360 |
# File 'lib/hegel/test_case.rb', line 358 def string_generator_domain(max_length) @impl.string_generator_domain(@ctx, max_length) end |
#string_generator_email ⇒ Object
hegel_string_generator_email. Public for the same reason #string_generator_regex is; reached only through #with_email_generator otherwise.
344 345 346 |
# File 'lib/hegel/test_case.rb', line 344 def string_generator_email @impl.string_generator_email(@ctx) end |
#string_generator_free(generator) ⇒ nil
hegel_string_generator_free, for a handle built by #string_generator_regex, #string_generator_email, #string_generator_url, or #string_generator_domain. Public for the same reason #string_generator_regex is: the layer-1 conformance test calls it directly to prove the delegation. #with_generator_handle below is what pairs it with one of the four constructors for a do_draw.
369 370 371 |
# File 'lib/hegel/test_case.rb', line 369 def string_generator_free(generator) @impl.string_generator_free(@ctx, generator) end |
#string_generator_regex(pattern, fullmatch, alphabet = nil) ⇒ Object
hegel_string_generator_regex. alphabet is an optional string
generator handle (from #with_text_generator), or nil (the default)
for the header's documented "no particular alphabet" case. Public,
like the three constructors below it, because
test/hegel/test_lib_hegel.rb's own layer-1 conformance test already
calls all four (and #string_generator_free) directly against the
Fake to prove this thin delegation reaches @impl correctly; a
Hegel::Generator's do_draw should reach it only through
#with_regex_generator instead.
337 338 339 |
# File 'lib/hegel/test_case.rb', line 337 def string_generator_regex(pattern, fullmatch, alphabet = nil) @impl.string_generator_regex(@ctx, pattern, fullmatch, alphabet) end |
#string_generator_url ⇒ Object
hegel_string_generator_url. Public for the same reason #string_generator_regex is; reached only through #with_url_generator otherwise.
351 352 353 |
# File 'lib/hegel/test_case.rb', line 351 def string_generator_url @impl.string_generator_url(@ctx) end |
#target(value, label: "") ⇒ nil
hegel_target: records value as a numeric observation for libhegel's
own hill-climbing between generation rounds, under label. Not
recorded to the eventual failure report -- hegel-rust's own
TestCase::target and hegel-java's own TestCase#target both leave an
observation out of their report too, so this sits in the same
"native surface that does not record" group as #generate_integer,
#generate_boolean, and #generate_float above, rather than beside
#draw_integer/#draw_boolean/#draw.
label defaults to "", matching hegel-go's own Target(value) and
hegel-java's own target(double). hegel-rust's tc.target(expr) reaches
a labelled call only because a macro rewrites it to
target_labelled(expr, "expr") at compile time, using the call's own
source text; Ruby has no such macro. Recovering a label from the call
site the way #name_for does for an unlabelled draw was rejected: it
would call caller_locations on every #target call, working against
this class's own per-case cost concern (see #note's own comment on
the same point), and it would make this default observably differ
from hegel-go's and hegel-java's.
value is passed through as given, not #to_f'd: hegel_target's
double-typed argument already accepts an Integer or a Float exactly
as given (checked directly against libhegel, not assumed from the
binding library's documentation alone), so converting here would only
add a second Ruby-side step ahead of the one the binding already
performs.
No argument validation here. hegel_target's own HEGEL_E_INVALID_ARG messages -- a label recorded twice, a non-finite value -- are already specific, and Hegel::LibHegel.check! already translates them to Hegel::Error the same way it does for every other hegel_* call this class makes. Writing the same check on this side would only give one mistake two messages to drift apart from each other.
213 214 215 |
# File 'lib/hegel/test_case.rb', line 213 def target(value, label: "") @impl.target(@ctx, @handle, value, label) end |
#with_domain_generator(max_length:, &block) ⇒ void
This method returns an undefined value.
Runs the block with a domain-name string generator handle built from
max_length (see #string_generator_domain), freed the same way as
#with_regex_generator.
290 291 292 |
# File 'lib/hegel/test_case.rb', line 290 def with_domain_generator(max_length:, &block) with_generator_handle(string_generator_domain(max_length), &block) end |
#with_email_generator(&block) ⇒ void
This method returns an undefined value.
Runs the block with an email-address string generator handle (see #string_generator_email), freed the same way as #with_regex_generator.
277 278 279 |
# File 'lib/hegel/test_case.rb', line 277 def with_email_generator(&block) with_generator_handle(string_generator_email, &block) end |
#with_regex_generator(pattern, fullmatch:, &block) ⇒ void
This method returns an undefined value.
Runs the block with a regex-matching string generator handle built from +pattern+/+fullmatch+ (see #string_generator_regex), freeing it via #with_generator_handle whether the block returns or raises.
271 272 273 |
# File 'lib/hegel/test_case.rb', line 271 def with_regex_generator(pattern, fullmatch:, &block) with_generator_handle(string_generator_regex(pattern, fullmatch), &block) end |
#with_text_generator(**kwargs, &block) ⇒ void
This method returns an undefined value.
Runs the block with a text generator handle scoped to this one call, freeing it before returning. See Hegel::Generators::TextGenerator for why this is built fresh per draw rather than cached on the generator instance. Named for what it builds (hegel_string_generator_text), to read the same way as #with_regex_generator/#with_email_generator/ #with_url_generator/#with_domain_generator below, each named for its own hegel_string_generator_* call.
264 265 266 |
# File 'lib/hegel/test_case.rb', line 264 def with_text_generator(**kwargs, &block) with_generator_handle(@impl.string_generator_text(@ctx, **kwargs), &block) end |
#with_url_generator(&block) ⇒ void
This method returns an undefined value.
Runs the block with a URL string generator handle (see #string_generator_url), freed the same way as #with_regex_generator.
283 284 285 |
# File 'lib/hegel/test_case.rb', line 283 def with_url_generator(&block) with_generator_handle(string_generator_url, &block) end |