hegeltest 0.3.4-aarch64-linux → 0.4.1-aarch64-linux

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -0
  3. data/README.ja.md +408 -0
  4. data/README.md +208 -102
  5. data/Rakefile +6 -3
  6. data/docs/README.md +11 -0
  7. data/docs/adr/0027-report-each-runs-test-location-from-the-callers-frame.md +63 -0
  8. data/docs/adr/0028-expose-settings-profiles-as-a-keyword-and-module-functions.md +91 -0
  9. data/docs/adr/0029-keep-notes-local-and-defer-run-error-kinds.md +72 -0
  10. data/docs/adr/0030-represent-a-duration-as-integer-nanoseconds.md +48 -0
  11. data/docs/adr/0031-take-the-alphabet-options-from-hegel-rust.md +52 -0
  12. data/docs/adr/0032-suppress-span-closes-while-an-abandoned-recursion-attempt-unwinds.md +147 -0
  13. data/docs/adr/0033-cache-compiled-grammars-for-the-length-of-a-run.md +80 -0
  14. data/docs/adr/0034-repeat-a-test-body-with-a-ruby-side-indent.md +120 -0
  15. data/docs/adr/0035-defer-concurrent-state-machines-and-the-engine-printer.md +136 -0
  16. data/docs/adr/0036-follow-rubys-unicode-version.md +50 -0
  17. data/docs/adr/0037-send-a-maximum-at-the-engine-default-sentinel-as-no-bound.md +48 -0
  18. data/docs/architecture.md +16 -1
  19. data/lib/hegel/errors.rb +24 -0
  20. data/lib/hegel/generator.rb +52 -25
  21. data/lib/hegel/generators.rb +715 -45
  22. data/lib/hegel/grammar_cache.rb +36 -0
  23. data/lib/hegel/lib_hegel/real.rb +333 -19
  24. data/lib/hegel/lib_hegel.rb +63 -6
  25. data/lib/hegel/libhegel/libhegel-linux-arm64.so +0 -0
  26. data/lib/hegel/libhegel_version.rb +1 -1
  27. data/lib/hegel/report.rb +13 -10
  28. data/lib/hegel/runner.rb +61 -27
  29. data/lib/hegel/settings.rb +92 -16
  30. data/lib/hegel/state_machine.rb +17 -4
  31. data/lib/hegel/stateful/pool.rb +52 -0
  32. data/lib/hegel/stateful.rb +2 -2
  33. data/lib/hegel/syntax/methods.rb +99 -15
  34. data/lib/hegel/test_case.rb +259 -37
  35. data/lib/hegel/test_location.rb +49 -0
  36. data/lib/hegel/version.rb +1 -1
  37. data/lib/hegel.rb +21 -5
  38. data/sig/hegel.rbs +300 -42
  39. data/skills/hegel-ruby/references/ruby/reference.md +463 -41
  40. metadata +15 -1
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "runner"
4
+
5
+ module Hegel
6
+ # Where a Hegel.test call lives, in the four pieces
7
+ # hegel_settings_set_test_location takes. Under Antithesis the engine
8
+ # reports each run's verdict as the assertion
9
+ # "<class_name>::<function> passes properties" at file:begin_line, so two
10
+ # calls that share a class_name and a function share one assertion.
11
+ TestLocation = Data.define(:file, :begin_line, :class_name, :function)
12
+
13
+ class TestLocation
14
+ # Matches the label prefix Ruby 3.4 puts on a frame inside a block, so
15
+ # that the method underneath names the test.
16
+ BLOCK_PREFIX = /\A(?:block(?: \(\d+ levels\))? in )+/
17
+
18
+ # Matches "Class#method" and "Class.method". Greedy, so a namespaced
19
+ # class keeps its "::" and a "#<Class:0x...>" label splits at its last
20
+ # separator.
21
+ METHOD_LABEL = /\A(.+)[#.]([^#.]+)\z/
22
+
23
+ # The first of +locations+ that is the caller's own, by the same rule
24
+ # Runner.origin_for uses to name a failure (see ADR 0012), so a wrapper in
25
+ # this gem, a gem, or the standard library is not named as the test.
26
+ # +locations+ is never empty, because the frame of Hegel.test's own caller
27
+ # exists even at the top of a script.
28
+ def self.from_locations(locations)
29
+ location = locations.find { |candidate| !Runner.infrastructure?(candidate.path) } || locations.first
30
+ path = location.absolute_path || location.path
31
+ root = File.join(Dir.pwd, "")
32
+ file = path.start_with?(root) ? path.delete_prefix(root) : path
33
+ class_name, function = names(location.label, file, location.lineno)
34
+ new(file: file, begin_line: location.lineno, class_name: class_name, function: function)
35
+ end
36
+
37
+ # [class_name, function] for a frame +label+. A frame with no enclosing
38
+ # method (a script body, or an RSpec example, whose block sits at the top
39
+ # of its file) has no name of its own, so it takes its file and line:
40
+ # that keeps two examples in one file from sharing one assertion.
41
+ def self.names(label, file, lineno)
42
+ match = METHOD_LABEL.match(label.sub(BLOCK_PREFIX, ""))
43
+ return match.captures if match
44
+
45
+ [file.delete_suffix(".rb"), "line #{lineno}"]
46
+ end
47
+ private_class_method :names
48
+ end
49
+ end
data/lib/hegel/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hegel
4
- VERSION = "0.3.4"
4
+ VERSION = "0.4.1"
5
5
  end
data/lib/hegel.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require_relative "hegel/version"
4
4
  require_relative "hegel/errors"
5
5
  require_relative "hegel/runner"
6
+ require_relative "hegel/test_location"
6
7
  require_relative "hegel/generator"
7
8
  require_relative "hegel/generators"
8
9
  require_relative "hegel/syntax/methods"
@@ -28,6 +29,13 @@ module Hegel
28
29
  # assertion failure rather than as a Hegel-specific one. Raises
29
30
  # Hegel::Error for a run-level failure instead of a property failure.
30
31
  #
32
+ # +profile+ names the settings profile the run starts from: one of the
33
+ # engine's shipped profiles, one in hegel.toml, or one registered with
34
+ # Hegel::Settings.register_profile. Left nil, the run starts from the
35
+ # default profile. A keyword passed alongside still beats the profile, and
36
+ # report_multiple_failures is always passed, so a profile's value for it
37
+ # never applies (see docs/adr/0028). An unknown name raises Hegel::Error.
38
+ #
31
39
  # +test_cases+, +seed+, +derandomize+, +verbosity+, +phases+, and
32
40
  # +suppress_health_check+ all default to nil, which means the same thing
33
41
  # for each of them: do not call the matching libhegel setter, and let the
@@ -54,6 +62,11 @@ module Hegel
54
62
  # keyword above: see Hegel::Runner.run's own comment for why it is always
55
63
  # passed.
56
64
  #
65
+ # +stop_on_first_failure+, +print_blob+, +show_statistics+,
66
+ # +nondeterminism_strictness+, and +backend+ default to nil, so the engine's
67
+ # profile decides as it does for +test_cases+; they follow hegel-rust's
68
+ # Settings.
69
+ #
57
70
  # +output+ (default $stderr) is where a failure report is written; a
58
71
  # caller passes its own IO to capture that report instead (tests do).
59
72
  #
@@ -66,13 +79,16 @@ module Hegel
66
79
  # real engine. Ordinary callers never pass it. Its default expression
67
80
  # (#default_impl) only runs when +impl+ is not given, so a test that does
68
81
  # pass one never opens the native library at all.
69
- def test(test_cases: nil, seed: nil, derandomize: nil, verbosity: nil, database: nil, database_key: nil,
70
- phases: nil, suppress_health_check: nil, report_multiple_failures: false, output: $stderr,
82
+ def test(profile: nil, test_cases: nil, seed: nil, derandomize: nil, verbosity: nil, database: nil, database_key: nil,
83
+ phases: nil, suppress_health_check: nil, report_multiple_failures: false, stop_on_first_failure: nil,
84
+ print_blob: nil, show_statistics: nil, nondeterminism_strictness: nil, backend: nil, output: $stderr,
71
85
  reproduce_failure: nil, impl: default_impl, &block)
72
- Runner.run(impl: impl, test_cases: test_cases, seed: seed, derandomize: derandomize, verbosity: verbosity,
86
+ Runner.run(impl: impl, profile: profile, test_cases: test_cases, seed: seed, derandomize: derandomize, verbosity: verbosity,
73
87
  database: database, database_key: database_key, phases: phases, suppress_health_check: suppress_health_check,
74
- report_multiple_failures: report_multiple_failures, output: output, reproduce_failure: reproduce_failure,
75
- &block)
88
+ report_multiple_failures: report_multiple_failures, stop_on_first_failure: stop_on_first_failure,
89
+ print_blob: print_blob, show_statistics: show_statistics, nondeterminism_strictness: nondeterminism_strictness,
90
+ backend: backend, output: output, reproduce_failure: reproduce_failure,
91
+ test_location: TestLocation.from_locations(caller_locations(1)), &block)
76
92
  end
77
93
 
78
94
  # The Hegel::LibHegel::Real instance #test uses by default, built once and