Class: SpecGuard::RSpec::Linter::Result
- Inherits:
-
Data
- Object
- Data
- SpecGuard::RSpec::Linter::Result
- Defined in:
- lib/specguard/rspec/linter.rb
Overview
One annotation's verdict. problem is set when discovery could not
produce an intent at all; reasons when the schema rejected one.
They are mutually exclusive by construction.
intent is WHAT THE PAYLOAD PARSED TO, carried alongside the verdict
rather than left for a second parser to re-derive. It is nil when there
was no payload (any problem), and — like the port's intent key — it
is populated even when reasons is not empty: a schema-rejected
annotation did parse, and ok? already reports the verdict.
Constant Summary collapse
- MAX_INTENT_DEPTH =
The nesting budget a payload gets, well under
JSON.generate's default ceiling of 100.The margin is deliberate rather than tight. Both renderers WRAP the payload before generating it — JSONReporter in
findings[] -> finding -> intentand Formatter inspecs[] -> spec -> intent, three levels each — so a payload probed at the bare ceiling would be accepted here and still raise there. Budgeting 32 leaves either envelope room to grow without silently re-opening this hole.It costs nothing real: the schema admits four string values and nothing nested, so every payload a consumer could act on is depth 1. Anything deep enough to be refused here was already schema-invalid; this only decides whether its finding also carries the value.
32
Instance Attribute Summary collapse
-
#file ⇒ Object
readonly
Returns the value of attribute file.
-
#intent ⇒ Object
readonly
Returns the value of attribute intent.
-
#kind ⇒ Object
readonly
Returns the value of attribute kind.
-
#line ⇒ Object
readonly
Returns the value of attribute line.
-
#problem ⇒ Object
readonly
Returns the value of attribute problem.
-
#reasons ⇒ Object
readonly
Returns the value of attribute reasons.
Instance Method Summary collapse
- #failed? ⇒ Boolean
-
#initialize(file:, line:, kind: nil, problem: nil, reasons: [], intent: nil) ⇒ Result
constructor
A new instance of Result.
-
#line_scoped? ⇒ Boolean
A read failure is not line-scoped: nothing in the file was ever seen, and slice 1's
lineis a 0 sentinel rather than a location. - #location ⇒ Object
- #ok? ⇒ Boolean
-
#representable_intent ⇒ Object
The intent, but only when it is a value this gem can actually hand on — nil otherwise.
Constructor Details
#initialize(file:, line:, kind: nil, problem: nil, reasons: [], intent: nil) ⇒ Result
Returns a new instance of Result.
49 50 51 |
# File 'lib/specguard/rspec/linter.rb', line 49 def initialize(file:, line:, kind: nil, problem: nil, reasons: [], intent: nil) super end |
Instance Attribute Details
#file ⇒ Object (readonly)
Returns the value of attribute file
48 49 50 |
# File 'lib/specguard/rspec/linter.rb', line 48 def file @file end |
#intent ⇒ Object (readonly)
Returns the value of attribute intent
48 49 50 |
# File 'lib/specguard/rspec/linter.rb', line 48 def intent @intent end |
#kind ⇒ Object (readonly)
Returns the value of attribute kind
48 49 50 |
# File 'lib/specguard/rspec/linter.rb', line 48 def kind @kind end |
#line ⇒ Object (readonly)
Returns the value of attribute line
48 49 50 |
# File 'lib/specguard/rspec/linter.rb', line 48 def line @line end |
#problem ⇒ Object (readonly)
Returns the value of attribute problem
48 49 50 |
# File 'lib/specguard/rspec/linter.rb', line 48 def problem @problem end |
#reasons ⇒ Object (readonly)
Returns the value of attribute reasons
48 49 50 |
# File 'lib/specguard/rspec/linter.rb', line 48 def reasons @reasons end |
Instance Method Details
#failed? ⇒ Boolean
57 58 59 |
# File 'lib/specguard/rspec/linter.rb', line 57 def failed? !ok? end |
#line_scoped? ⇒ Boolean
A read failure is not line-scoped: nothing in the file was ever seen,
and slice 1's line is a 0 sentinel rather than a location. The
binary drops the line for exactly these findings (JSONFinding in
open-test-intent's cmd/validate-intent/report.go — "line is null
where a finding is not line-scoped, kind is null on a passing
finding"), and :0 is not somewhere a reader can go: anything
parsing file:line — CI annotations, editor quickfix, review
comments — would point at a line that does not exist.
This is what makes kind load-bearing rather than decorative.
The rule is a predicate rather than an inline comparison because it
has two renderers: CLI#report_failure prints file instead of
file:0, and JSONReporter emits "line": null for the same
findings. Spelling kind == Finding::KIND_READ in both would let one
of them keep emitting the sentinel after the rule changed here.
77 78 79 |
# File 'lib/specguard/rspec/linter.rb', line 77 def line_scoped? kind != Finding::KIND_READ end |
#location ⇒ Object
81 82 83 |
# File 'lib/specguard/rspec/linter.rb', line 81 def location line_scoped? ? "#{file}:#{line}" : file end |
#ok? ⇒ Boolean
53 54 55 |
# File 'lib/specguard/rspec/linter.rb', line 53 def ok? problem.nil? && reasons.empty? end |
#representable_intent ⇒ Object
The intent, but only when it is a value this gem can actually hand on — nil otherwise.
Parsing a payload is not the same as being able to REPRODUCE it, and Ruby draws that line in a place the validator does not. Three classes clear the binary's verdict AND then detonate at the point of USE:
- a lone LOW surrogate (
"\udc00Or") — the report parser may accept it and hand back a String whosevalid_encoding?is false, andJSON.generaterefuses that same value withsource sequence is illegal/malformed utf-8; - a non-finite Float — ValidatorBackend's parse options set
allow_nan: trueon the way IN, while generate's default isallow_nan: falseon the way OUT; - a container nested past the generator's
max_nesting— the same asymmetry, since those parse options also setmax_nesting: false.
The last two are the parse options' own doing. Relaxing the parse side without relaxing the generate side does not remove the failure, it MOVES it — out of the parser, where it costs one annotation its payload, and into the generator, where it costs the whole batch its document and its exit code. Admitting a value we cannot then emit is strictly worse than never admitting it.
So the question is ASKED rather than enumerated: hand the value to
the generator and see whether it comes back. A predicate that lists the
known-bad shapes is a list somebody has to keep complete, and the two
cases above are exactly what that list missed while covering the
first. JSON.generate is not an approximation of the oracle here, it
IS the call both renderers go on to make.
Answered here, once, because BOTH renderers need it and neither is the natural owner. Nothing is substituted — a repaired payload is one the author did not write, and shipping it is indistinguishable downstream from shipping the right one (KB SPGD-78). Unshippable means unannotated.
137 138 139 |
# File 'lib/specguard/rspec/linter.rb', line 137 def representable_intent intent unless unrepresentable?(intent) end |