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_METHOD_NAMES =
The method names that reach #record_draw: #draw_integer, #draw_boolean, and #draw below. Hegel::DrawName.for takes this as an argument rather than knowing the list itself, so that class -- not DrawName -- stays the one place a fourth draw method needs to be added.
[:draw, :draw_integer, :draw_boolean].freeze
- 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).
57 58 59 60 61 62 63 64 |
# File 'lib/hegel/test_case.rb', line 57 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.
73 74 75 |
# File 'lib/hegel/test_case.rb', line 73 def entries @entries end |
Instance Method Details
#assume(condition) ⇒ void
103 104 105 |
# File 'lib/hegel/test_case.rb', line 103 def assume(condition) reject unless condition end |
#collection_free(collection) ⇒ Object
hegel_collection_free.
259 260 261 |
# File 'lib/hegel/test_case.rb', line 259 def collection_free(collection) @impl.collection_free(@ctx, collection) end |
#collection_more(collection) ⇒ Boolean
hegel_collection_more: whether to draw another element into
collection.
245 246 247 |
# File 'lib/hegel/test_case.rb', line 245 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.
254 255 256 |
# File 'lib/hegel/test_case.rb', line 254 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.
93 94 95 96 97 |
# File 'lib/hegel/test_case.rb', line 93 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).
83 84 85 86 87 |
# File 'lib/hegel/test_case.rb', line 83 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].
76 77 78 79 80 |
# File 'lib/hegel/test_case.rb', line 76 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.
422 423 424 |
# File 'lib/hegel/test_case.rb', line 422 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.
174 175 176 |
# File 'lib/hegel/test_case.rb', line 174 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.
309 310 311 |
# File 'lib/hegel/test_case.rb', line 309 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.
462 463 464 |
# File 'lib/hegel/test_case.rb', line 462 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.
479 480 481 |
# File 'lib/hegel/test_case.rb', line 479 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.
180 181 182 183 184 |
# File 'lib/hegel/test_case.rb', line 180 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.
160 161 162 |
# File 'lib/hegel/test_case.rb', line 160 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.
167 168 169 |
# File 'lib/hegel/test_case.rb', line 167 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.
316 317 318 |
# File 'lib/hegel/test_case.rb', line 316 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.
322 323 324 |
# File 'lib/hegel/test_case.rb', line 322 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).
303 304 305 |
# File 'lib/hegel/test_case.rb', line 303 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.
470 471 472 |
# File 'lib/hegel/test_case.rb', line 470 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.
330 331 332 |
# File 'lib/hegel/test_case.rb', line 330 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.
239 240 241 |
# File 'lib/hegel/test_case.rb', line 239 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.
384 385 386 387 388 |
# File 'lib/hegel/test_case.rb', line 384 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
431 432 433 |
# File 'lib/hegel/test_case.rb', line 431 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.
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/hegel/test_case.rb', line 146 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.
393 394 395 |
# File 'lib/hegel/test_case.rb', line 393 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.
412 413 414 |
# File 'lib/hegel/test_case.rb', line 412 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.
404 405 406 |
# File 'lib/hegel/test_case.rb', line 404 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.
113 114 115 |
# File 'lib/hegel/test_case.rb', line 113 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.
226 227 228 |
# File 'lib/hegel/test_case.rb', line 226 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.
455 456 457 |
# File 'lib/hegel/test_case.rb', line 455 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.
439 440 441 |
# File 'lib/hegel/test_case.rb', line 439 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.
446 447 448 |
# File 'lib/hegel/test_case.rb', line 446 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.
233 234 235 |
# File 'lib/hegel/test_case.rb', line 233 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.
364 365 366 |
# File 'lib/hegel/test_case.rb', line 364 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.
350 351 352 |
# File 'lib/hegel/test_case.rb', line 350 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.
375 376 377 |
# File 'lib/hegel/test_case.rb', line 375 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.
343 344 345 |
# File 'lib/hegel/test_case.rb', line 343 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.
357 358 359 |
# File 'lib/hegel/test_case.rb', line 357 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.
219 220 221 |
# File 'lib/hegel/test_case.rb', line 219 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.
296 297 298 |
# File 'lib/hegel/test_case.rb', line 296 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.
283 284 285 |
# File 'lib/hegel/test_case.rb', line 283 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.
277 278 279 |
# File 'lib/hegel/test_case.rb', line 277 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.
270 271 272 |
# File 'lib/hegel/test_case.rb', line 270 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.
289 290 291 |
# File 'lib/hegel/test_case.rb', line 289 def with_url_generator(&block) with_generator_handle(string_generator_url, &block) end |