Module: Terminalwire::V2::Conformance
- Defined in:
- lib/terminalwire/v2/conformance.rb
Overview
Loads the language-neutral conformance corpus and resolves its typed sentinels into native Ruby values. The Go and Elixir runners do the equivalent. This is what lets one corpus validate every implementation.
Two file shapes live in the corpus:
* simple vector tables (negotiate/roundtrip/golden/validate/flow) — YAML/JSON,
with `$bin` base64 + `bytes_hex` sentinels;
* "tapes" (session) — S-expressions (see Sexp): recorded client<->server
interactions. Sexp is used for the tapes because it is trivial and
unambiguous to parse in every language and reads like a transcript.
Defined Under Namespace
Modules: Sexp
Class Method Summary collapse
-
.hex_to_bytes(hex) ⇒ Object
"a1 74 ff" -> binary string.
-
.load(category) ⇒ Object
Load every vector file in a category, dispatching by extension, and return a flat array of cases with sentinels resolved to native values.
-
.resolve(value) ⇒ Object
Recursively resolve { "$bin" => base64 } sentinels into binary strings.
- .root ⇒ Object
- .vectors_dir ⇒ Object
Class Method Details
.hex_to_bytes(hex) ⇒ Object
"a1 74 ff" -> binary string
67 68 69 |
# File 'lib/terminalwire/v2/conformance.rb', line 67 def hex_to_bytes(hex) hex.split.map { |byte| Integer(byte, 16) }.pack("C*") end |
.load(category) ⇒ Object
Load every vector file in a category, dispatching by extension, and return a flat array of cases with sentinels resolved to native values. Fails LOUDLY when the corpus is absent rather than silently running zero cases.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/terminalwire/v2/conformance.rb', line 35 def load(category) unless vectors_dir.directory? raise "conformance corpus not found at #{vectors_dir} — set TERMINALWIRE_CORPUS " \ "to the corpus directory (it ships in terminalwire/protocol). Without it " \ "the corpus specs would silently run zero cases." end Dir.glob(vectors_dir.join(category, "*.{yml,yaml,json,sexp}")).sort.flat_map do |path| case File.extname(path) when ".sexp" then Sexp.load(File.read(path)) # tapes (bin already resolved) when ".json" then resolve(JSON.parse(File.read(path))) else resolve(YAML.safe_load_file(path)) end end end |
.resolve(value) ⇒ Object
Recursively resolve { "$bin" => base64 } sentinels into binary strings.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/terminalwire/v2/conformance.rb', line 51 def resolve(value) case value when Hash if value.size == 1 && value.key?("$bin") Base64.decode64(value.fetch("$bin")).b else value.transform_values { |v| resolve(v) } end when Array value.map { |v| resolve(v) } else value end end |
.root ⇒ Object
22 23 24 25 26 |
# File 'lib/terminalwire/v2/conformance.rb', line 22 def root Pathname.new(ENV.fetch("TERMINALWIRE_CORPUS") do File.("../../../conformance", __dir__) end) end |
.vectors_dir ⇒ Object
28 29 30 |
# File 'lib/terminalwire/v2/conformance.rb', line 28 def vectors_dir root.join("vectors") end |