Created
August 26, 2023 20:06
-
-
Save pkoppstein/9b0f49a213a5b8083bab094ede06652d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Version 2023.08.25 | |
# This jq module defines filters for assertion checking. | |
# The module can be included or imported in the usual way, e.g. | |
# by including a line similar to the following at the top of your program file: | |
# include "assert" {search: "."}; | |
# By changing "keys_unsorted" to "keys", this module can also be used with gojq, | |
# the Go implementation of jq. | |
# Introduction | |
# The assertion filters defined here are designed so that assertion | |
# checking can be turned on or off. Since the run-time cost of having | |
# assertions is negligibly small when assertion checking is turned | |
# off, assertions intended for development or testing can be left in | |
# place, possibly even in production code. In addition, one can | |
# choose whether assertion violations should cause execution to | |
# terminate or to be reported using jq's `debug` or `stderr` filters. | |
# Highlights: | |
# * The input to every assertion filter is always passed through without alteration. | |
# * Assertion-checking is controlled by the jq global variable $assert and/or the environment | |
# variable $JQ_ASSERT as explained below; these variables also determine | |
# how assertion violations are reported. | |
# * Pinpointing the occurrence of an assertion violation by using $__loc__ is supported, | |
# provided your implementation of jq includes this filter. | |
# Details | |
# 1) If both $assert and the environment variable $JQ_ASSERT are set, then the value of | |
# $assert takes precedence. | |
# 2) If neither $assert nor $JQ_ASSERT is set, or if $assert is the JSON value `false`, | |
# then no assertion checking takes place. | |
# 3) If $assert is "debug" or "stderr" or any other value except the JSON value `false`, | |
# then violations are reported, respectively, using `debug`, `stderr` or `error`. | |
# 4) If $assert is unset, then the value of $JQ_ASSERT determines how violations are reported | |
# in the same way as described in (3) above. | |
# The assertion-checking filters defined here are as follows: | |
# | |
# assert(predicate) | |
# assert(predicate; msg) | |
# where: | |
# - msg determines the message that is printed as part of an assertion violation warning; | |
# it would typically be specified as a string, or the $__loc__ object if your jq supports it. | |
# - if msg is $__loc__, then the message will contain the file and line number defined by $__loc__, | |
# giving the location of the assertion; | |
# - if msg is a JSON object other than $__loc__, it will be used to construct a message | |
# showing the object's keys and values. | |
# Toy examples: | |
# With --arg assert stderr | |
# 101 | assert(. == false; $__loc__) | |
# yields: | |
# assertion violation @ <top-level>:90 => false | |
# 101 | |
# With --arg assert true | |
# 101 | 'assert(. == false; "Checking whether \(.) == false")' | |
# yields | |
# jq: error (at <unknown>): assertion violation @ Checking whether 101 == false => false | |
# With --arg assert true | |
# 101 | assert(. == false; $__loc__) | |
# yields: | |
# jq: error (at <unknown>): assertion violation @ <top-level>:90 => false | |
# With --arg assert debug | |
# 101 | assert(. == false; $__loc__) | |
# ["DEBUG:","assertion violation @ <top-level>:90 => false"] | |
# 101 | |
# With --arg assert debug | |
# 101 | assert(. == false; $__loc__ + {input: .}) | |
# ["DEBUG:","assertion violation @ file:<top-level>; line:106; input:101 => false"] | |
# 101 | |
##################################################################################### | |
# module {name: "assert"}; | |
# Is assertion-checking turned on? | |
def __assert__: | |
if $ARGS.named.assert == false then false | |
else ($ARGS.named | has("assert")) or env.JQ_ASSERT | |
end; | |
# Handle an assertion violation | |
def __assertion_violation__: | |
if $ARGS.named | has("assert") | |
then $ARGS.named.assert as $x | |
| if $x == "debug" then debug | |
elif $x == "stderr" then (tostring+"\n") | stderr | |
elif $x == false then . | |
else error | |
end | |
else env.JQ_ASSERT as $x | |
| if $x == "debug" then debug | |
elif $x == "stderr" then (tostring +"\n")|stderr | |
elif $x then error | |
else . | |
end | |
end; | |
def assert(exp; $msg): | |
def m: $msg | |
| if type == "object" | |
then if keys == ["file", "line"] then [.[]] | join(":") | |
else [keys_unsorted[] as $k | "\($k):\(.[$k])"] | join("; ") | |
end | |
else tostring | |
end; | |
if __assert__ then | |
(exp as $e | if $e then . else . as $in | "assertion violation @ \(m) => \($e)" | __assertion_violation__ | $in end) | |
else . end; | |
def assert(exp): | |
if __assert__ then | |
(exp as $e | if $e then . else . as $in | "assertion violation: \($e)" | __assertion_violation__ | $in end) | |
else . end; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment