Stmt: Introduce assert statement and related hooks

including two hooks called assertion_failure() and assertion_result() for
customization and tracking of assertion results.
This commit is contained in:
Arne Welzel 2023-06-05 19:13:14 +02:00
parent a25b1a9d59
commit 25ea678626
41 changed files with 635 additions and 3 deletions

View file

@ -942,6 +942,42 @@ type BacktraceElement: record {
## .. zeek:see:: backtrace print_backtrace
type Backtrace: vector of BacktraceElement;
## A hook that is invoked when an assert statement fails.
##
## If no such hook is implemented, a default reporter error message is
## logged similar to how scripting errors are reported.
##
## If assertion_failure hook handlers exist, the default reporter error
## message is suppressed to allow for customized error messaging.
##
## cond: The string representation of the condition.
##
## msg: Evaluated message as string given to the assert statement.
##
## bt: Backtrace of the assertion error. The top element will contain
## the location of the assert statement that failed.
##
## .. zeek:see:: assertion_result
type assertion_failure: hook(cond: string, msg: string, bt: Backtrace);
## A hook that is invoked with the result of every assert statement.
##
## This is a potentially expensive hook meant to be used by testing
## frameworks to summarize assert results. In a production setup,
## this hook is likely deterimental to performance.
##
## result: The result of evaluating **cond**.
##
## cond: The string representation of the condition.
##
## msg: Evaluated message as string given to the assert statement.
##
## bt: Backtrace of the assertion error. The top element will contain
## the location of the assert statement that failed.
##
## .. zeek:see:: assertion_failure
type assertion_result: hook(result: bool, cond: string, msg: string, bt: Backtrace);
# todo:: Do we still need these here? Can they move into the packet filter
# framework?
#

View file

@ -54,6 +54,7 @@ const char* stmt_name(StmtTag t)
"ZAM",
"ZAM-resumption",
"null",
"assert",
};
return stmt_names[int(t)];
@ -1864,6 +1865,134 @@ TraversalCode NullStmt::Traverse(TraversalCallback* cb) const
HANDLE_TC_STMT_POST(tc);
}
AssertStmt::AssertStmt(ExprPtr arg_cond, ExprPtr arg_msg)
: Stmt(STMT_ASSERT), cond(std::move(arg_cond)), msg(std::move(arg_msg))
{
if ( ! IsBool(cond->GetType()->Tag()) )
cond->Error("conditional must be boolean");
if ( msg && ! IsString(msg->GetType()->Tag()) )
msg->Error("message must be string");
}
ValPtr AssertStmt::Exec(Frame* f, StmtFlowType& flow)
{
RegisterAccess();
flow = FLOW_NEXT;
static auto assertion_failure_hook = id::find_func("assertion_failure");
static auto assertion_result_hook = id::find_func("assertion_result");
bool run_result_hook = assertion_result_hook && assertion_result_hook->HasEnabledBodies();
bool run_failure_hook = assertion_failure_hook && assertion_failure_hook->HasEnabledBodies();
auto assert_result = cond->Eval(f)->AsBool();
if ( assert_result && ! run_result_hook )
return Val::nil;
// Textual representation of cond from the AST.
static zeek::ODesc desc;
desc.Clear();
desc.SetShort(true);
desc.SetQuotes(true);
cond->Describe(&desc);
auto cond_val = zeek::make_intrusive<zeek::StringVal>(desc.Len(), (const char*)desc.Bytes());
zeek::StringValPtr msg_val = zeek::val_mgr->EmptyString();
if ( msg )
{
// Eval() may fail if expression assumes assert
// condition is F, but we still try to get it for
// the assertion_result hook.
try
{
msg_val = cast_intrusive<zeek::StringVal>(msg->Eval(f));
}
catch ( InterpreterException& e )
{
desc.Clear();
desc.Add("<error eval ");
msg->Describe(&desc);
desc.Add(">");
msg_val = zeek::make_intrusive<zeek::StringVal>(desc.Len(), (const char*)desc.Bytes());
}
}
VectorValPtr bt = nullptr;
if ( run_result_hook || run_failure_hook )
{
bt = get_current_script_backtrace();
auto assert_elem = make_backtrace_element("assert", MakeEmptyCallArgumentVector(),
GetLocationInfo());
bt->Insert(0, assert_elem);
}
if ( run_result_hook )
assertion_result_hook->Invoke(zeek::val_mgr->Bool(assert_result), cond_val, msg_val, bt);
if ( assert_result )
return Val::nil;
// Run the installed failure hooks, or log a default message.
if ( run_failure_hook )
assertion_failure_hook->Invoke(cond_val, msg_val, bt);
else
{
std::string reporter_msg = util::fmt("assertion failure: %s", cond_val->CheckString());
if ( msg_val->Len() > 0 )
reporter_msg += util::fmt(" (%s)", msg_val->CheckString());
reporter->PushLocation(GetLocationInfo());
reporter->Error("%s", reporter_msg.c_str());
reporter->PopLocation();
}
throw InterpreterException();
}
void AssertStmt::StmtDescribe(ODesc* d) const
{
Stmt::StmtDescribe(d);
// Quoting strings looks better when describing assert
// statements. So turn it on explicitly.
//
// E.g., md5_hash("") ends up as md5_hash() without quoting.
auto orig_quotes = d->WantQuotes();
d->SetQuotes(true);
cond->Describe(d);
if ( msg )
{
d->Add(",");
d->SP();
msg->Describe(d);
}
DescribeDone(d);
d->SetQuotes(orig_quotes);
}
TraversalCode AssertStmt::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreStmt(this);
HANDLE_TC_STMT_PRE(tc);
tc = cond->Traverse(cb);
HANDLE_TC_STMT_PRE(tc);
if ( msg )
{
tc = msg->Traverse(cb);
HANDLE_TC_STMT_PRE(tc);
}
tc = cb->PostStmt(this);
HANDLE_TC_STMT_POST(tc);
}
WhenInfo::WhenInfo(ExprPtr arg_cond, FuncType::CaptureList* arg_cl, bool arg_is_return)
: cond(std::move(arg_cond)), cl(arg_cl), is_return(arg_is_return)
{

View file

@ -544,6 +544,25 @@ private:
bool is_directive;
};
class AssertStmt final : public Stmt
{
public:
explicit AssertStmt(ExprPtr cond, ExprPtr msg = nullptr);
ValPtr Exec(Frame* f, StmtFlowType& flow) override;
void StmtDescribe(ODesc* d) const override;
TraversalCode Traverse(TraversalCallback* cb) const override;
// Optimization-related:
StmtPtr Duplicate() override;
private:
ExprPtr cond;
ExprPtr msg;
};
// A helper class for tracking all of the information associated with
// a "when" statement, and constructing the necessary components in support
// of lambda-style captures.

View file

@ -29,6 +29,7 @@ namespace detail
class CompositeHash;
class Frame;
class AssertStmt;
class CatchReturnStmt;
class ExprStmt;
class ForStmt;
@ -94,6 +95,7 @@ public:
const WhenStmt* AsWhenStmt() const;
const SwitchStmt* AsSwitchStmt() const;
const NullStmt* AsNullStmt() const;
const AssertStmt* AsAssertStmt() const;
void RegisterAccess() const
{

View file

@ -32,8 +32,9 @@ enum StmtTag
STMT_CPP, // compiled C++
STMT_ZAM, // a ZAM function body
STMT_ZAM_RESUMPTION, // resumes ZAM execution for "when" statements
STMT_NULL
#define NUM_STMTS (int(STMT_NULL) + 1)
STMT_NULL,
STMT_ASSERT,
#define NUM_STMTS (int(STMT_ASSERT) + 1)
};
enum StmtFlowType

View file

@ -7,7 +7,7 @@
%expect 211
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY TOK_ASSERT
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
%token TOK_BOOL TOK_BREAK TOK_CASE TOK_OPTION TOK_CONST
%token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_DEFAULT TOK_DELETE
@ -78,6 +78,7 @@
%type <captures> capture_list opt_captures when_captures
%type <when_clause> when_head when_start when_clause
%type <re_modes> TOK_PATTERN_END
%type <expr> opt_assert_msg
%{
#include <cstdlib>
@ -1802,6 +1803,11 @@ stmt:
script_coverage_mgr.DecIgnoreDepth();
}
| TOK_ASSERT expr opt_assert_msg ';'
{
$$ = new AssertStmt(IntrusivePtr{AdoptRef{}, $2}, {AdoptRef{}, $3});
}
| TOK_PRINT expr_list ';' opt_no_test
{
set_location(@1, @3);
@ -2228,6 +2234,13 @@ resolve_id:
}
;
opt_assert_msg:
',' expr
{ $$ = $2; }
|
{ $$ = nullptr; }
;
opt_no_test:
TOK_NO_TEST
{ $$ = true; }

View file

@ -321,6 +321,7 @@ add return TOK_ADD;
addr return TOK_ADDR;
any return TOK_ANY;
as return TOK_AS;
assert return TOK_ASSERT;
bool return TOK_BOOL;
break return TOK_BREAK;
case return TOK_CASE;

View file

@ -919,6 +919,12 @@ StmtPtr InitStmt::DoReduce(Reducer* c)
return ThisPtr();
}
StmtPtr AssertStmt::Duplicate()
{
// Is this right?
return SetSucc(new AssertStmt(cond->Duplicate(), msg ? msg->Duplicate() : nullptr));
}
StmtPtr WhenStmt::Duplicate()
{
FuncType::CaptureList* cl_dup = nullptr;

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 3: assertion failure: fmt("%s", 1) == "2" ("1" != "2")
fatal error: errors occurred while initializing

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 3: assertion failure: (coerce to_count("42") to double) == 42.5 (always failing)
fatal error: errors occurred while initializing

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 4: assertion failure: 1 == x (Expected x to be 1, have 2)
fatal error: errors occurred while initializing

View file

@ -0,0 +1,6 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 9: assertion failure: "ghi" in tbl ({
[abc] = 123,
[def] = 456
})
fatal error: errors occurred while initializing

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 10: assertion failure: r?$b (r$b is not set in [a=1234, b=<uninitialized>])
fatal error: errors occurred while initializing

View file

@ -0,0 +1,4 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
expression error in <...>/assert.zeek, line 10: field value missing (r$b)
error in <...>/assert.zeek, line 10: assertion failure: r?$b (<error eval fmt("r$b is not set trying anyway: %s", r$b)>)
fatal error: errors occurred while initializing

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 2: assertion failure: 1 == 2 (always false)
fatal error: failed to execute script statements at top-level scope

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert-error.zeek, line 3: message must be string (1234)

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert-error.zeek, line 3: syntax error, at or near ";"

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert-error.zeek, line 3: syntax error, at or near ","

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert-error.zeek, line 8: conditional must be boolean (1)

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -0,0 +1,7 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_failure, to_count("5") == 4, 5 is not 4
assert <...>/assert-hook.zeek:19
f <...>/assert-hook.zeek:23
g <...>/assert-hook.zeek:24
h <...>/assert-hook.zeek:28
zeek_init <none>:0

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
received termination signal

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_failure, terminate me!
zeek_done()

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_failure, calling exit!

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -0,0 +1,8 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_result T at <...>/assert-hook.zeek:24: md5_hash("") == "d41d8cd98f00b204e9800998ecf8427e"
assertion_result T at <...>/assert-hook.zeek:29: sha1_hash("") == "da39a3ee5e6b4b0d3255bfef95601890afd80709"
assertion_result F at <...>/assert-hook.zeek:34: sha1_hash("") == "wrong"
assertion_failure at <...>/assert-hook.zeek:34: sha1_hash("") == "wrong"
assertion_result F at <...>/assert-hook.zeek:39: md5_hash("") == "wrong"
assertion_failure at <...>/assert-hook.zeek:39: md5_hash("") == "wrong"
2 of 4 assertions failed

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
expression error in <...>/assert-hook.zeek, line 15: field value missing (get_current_packet_header()$ip)
expression error in <...>/assert-hook.zeek, line 17: field value missing (get_current_packet_header()$ip)

View file

@ -0,0 +1,7 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_result, T, 2 + 2 == 4, <error eval cat(get_current_packet_header()$ip)>, <...>/assert-hook.zeek, 15
assertion_result, T, 2 + 2 == 4, {"msg":"true and works"}, <...>/assert-hook.zeek, 16
assertion_result, F, 2 + 2 == 5, <error eval cat(get_current_packet_header()$ip)>, <...>/assert-hook.zeek, 17
assertion_failure, 2 + 2 == 5, <error eval cat(get_current_packet_header()$ip)>, <...>/assert-hook.zeek, 17
assertion_result, F, 2 + 2 == 5, {"msg":"false and works"}, <...>/assert-hook.zeek, 22
assertion_failure, 2 + 2 == 5, {"msg":"false and works"}, <...>/assert-hook.zeek, 22

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert-hook.zeek, line 12: assertion failure: 2 + 2 == 5 (this is false)
error in <...>/assert-hook.zeek, line 18: assertion failure: 2 + 2 == 5 (this is false)

View file

@ -0,0 +1,5 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_result, T, 2 + 2 == 4, this is true, <...>/assert-hook.zeek, 10
assertion_result, T, 2 + 2 == 4, {"msg":"this is also true"}, <...>/assert-hook.zeek, 11
assertion_result, F, 2 + 2 == 5, this is false, <...>/assert-hook.zeek, 12
assertion_result, F, 2 + 2 == 5, this is false, <...>/assert-hook.zeek, 18

View file

@ -0,0 +1 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
assertion_failure, 1 != 1, , <...>/assert-hook.zeek, 15

View file

@ -0,0 +1,13 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
f, lambda_<505728364269398358>
{
assert 0 < getpid(), fmt("my pid is funny: %s", getpid());
}
g, lambda_<8496146571423528161>
{
assert to_count("42") == 42;
}
test_function, test_function
{
assert 0 < getpid();
}

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert-top-level.zeek, line 5: assertion failure: getpid() == 0 (my pid greater 0? T)
fatal error: failed to execute script statements at top-level scope

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/assert.zeek, line 8: assertion failure: fmt("%s", 1) == "2"
fatal error: errors occurred while initializing

View file

@ -0,0 +1,27 @@
# @TEST-DOC: Assert statement wrong usage
#
# @TEST-EXEC-FAIL: zeek -b %INPUT
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
event zeek_init()
{
assert 1;
}
@TEST-START-NEXT
event zeek_init()
{
assert T, 1234;
}
@TEST-START-NEXT
event zeek_init()
{
assert;
}
@TEST-START-NEXT
event zeek_init()
{
assert T, "extra", "something";
}

View file

@ -0,0 +1,192 @@
# @TEST-DOC: Assert statement testing with assertion_failure and assertion_result implementation.
#
# @TEST-EXEC: zeek -b %INPUT >out
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
# Hook calls break after logging out some information.
hook assertion_failure(cond: string, msg: string, bt: Backtrace)
{
print "assertion_failure", cond, msg, bt[0]$file_location, bt[0]$line_location;
}
event zeek_init()
{
assert 1 != 1;
print "not reached";
}
@TEST-START-NEXT
# Test the backtrace location
hook assertion_failure(cond: string, msg: string, bt: Backtrace)
{
print "assertion_failure", cond, msg;
local indent = "";
for ( _, e in bt )
{
local file_name = e?$file_location ? e$file_location : "<none>";
local line_number = e?$line_location ? e$line_location : 0;
print fmt("%s%s %s:%s", indent, e$function_name, file_name, line_number);
indent = fmt("%s ", indent);
}
}
function f()
{
assert md5_hash("") == "d41d8cd98f00b204e9800998ecf8427e";
assert to_count("5") == 4, fmt("5 is not 4");
assert sha1_hash("") == "da39a3ee5e6b4b0d3255bfef95601890afd80709";
}
function g() { f(); }
function h() { g(); }
event zeek_init()
{
h();
print "not reached";
}
@TEST-START-NEXT
# Calling terminate() from the assertion hook.
redef exit_only_after_terminate = T;
hook assertion_failure(cond: string, msg: string, bt: Backtrace)
{
print "assertion_failure", msg;
terminate();
}
event zeek_init()
{
assert F, "terminate me!";
print "not reached";
}
event zeek_done()
{
print "zeek_done()";
assert zeek_is_terminating(), "zeek_done() should have zeek terminating";
}
@TEST-START-NEXT
# Calling exit() from the assertion hook.
redef exit_only_after_terminate = T;
hook assertion_failure(cond: string, msg: string, bt: Backtrace)
{
print "assertion_failure", msg;
exit(0); # in real tests use exit(1), this is to please btest.
}
event zeek_init()
{
assert F, "calling exit!";
print "not reached";
}
event zeek_done()
{
assert F, "zeek_done() not executed with exit()";
}
@TEST-START-NEXT
global assertion_failures = 0;
global assertions_total = 0;
hook assertion_failure(cond: string, msg: string, bt: Backtrace)
{
print fmt("assertion_failure at %s:%s: %s%s%s",
bt[0]$file_location, bt[0]$line_location,
cond, |msg| > 0 ? " - " : "", msg);
++assertion_failures;
}
hook assertion_result(result: bool, cond: string, msg: string, bt: Backtrace)
{
print fmt("assertion_result %s at %s:%s: %s%s%s",
result, bt[0]$file_location, bt[0]$line_location,
cond, |msg| > 0 ? " - " : "", msg);
++assertions_total;
}
event zeek_test()
{
assert md5_hash("") == "d41d8cd98f00b204e9800998ecf8427e";
}
event zeek_test()
{
assert sha1_hash("") == "da39a3ee5e6b4b0d3255bfef95601890afd80709";
}
event zeek_test()
{
assert sha1_hash("") == "wrong";
}
event zeek_test()
{
assert md5_hash("") == "wrong";
}
event zeek_init()
{
event zeek_test();
}
event zeek_done()
{
print fmt("%d of %d assertions failed", assertion_failures, assertions_total);
}
@TEST-START-NEXT
# Evaluating the msg expression can cause errors, see if we deal
# with that gracefully.
hook assertion_failure(cond: string, msg: string, bt: Backtrace)
{
print "assertion_failure", cond, msg, bt[0]$file_location, bt[0]$line_location;
}
hook assertion_result(result: bool, cond: string, msg: string, bt: Backtrace)
{
print "assertion_result", result, cond, msg, bt[0]$file_location, bt[0]$line_location;
}
event zeek_init()
{
assert 2 + 2 == 4, cat(get_current_packet_header()$ip);
assert 2 + 2 == 4, to_json([$msg="true and works"]);
assert 2 + 2 == 5, cat(get_current_packet_header()$ip);
}
event zeek_done()
{
assert 2 + 2 == 5, to_json([$msg="false and works"]);
assert 2 + 2 == 5, cat(get_current_packet_header()$ip);
}
@TEST-START-NEXT
# Only implementing assertion_result() falls back to default
# reporter errors.
hook assertion_result(result: bool, cond: string, msg: string, bt: Backtrace)
{
print "assertion_result", result, cond, msg, bt[0]$file_location, bt[0]$line_location;
}
event zeek_init()
{
assert 2 + 2 == 4, "this is true";
assert 2 + 2 == 4, to_json([$msg="this is also true"]);
assert 2 + 2 == 5, "this is false";
print "not reached";
}
event zeek_done()
{
assert 2 + 2 == 5, "this is false";
print "not reached";
}

View file

@ -0,0 +1,28 @@
# @TEST-DOC: Test Describe() of assert statement. Expressions may be canonicalized.
#
# @TEST-EXEC: zeek -b %INPUT >out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
function test_function()
{
assert getpid() > 0;
}
event zeek_init()
{
local f = function() {
assert getpid() > 0, fmt("my pid is funny: %s", getpid());
};
local g = function() {
assert to_count("42") == 42;
};
print "f", f;
f();
print "g", g;
g();
print "test_function", test_function;
test_function();
}

View file

@ -0,0 +1,5 @@
# @TEST-EXEC-FAIL: zeek -b %INPUT >out
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
assert getpid() > 0;
assert getpid() == 0, fmt("my pid greater 0? %s", getpid() > 0);

View file

@ -0,0 +1,75 @@
# @TEST-DOC: Assert statement behavior testing without an assertion_failure() hook.
#
# @TEST-EXEC-FAIL: unset ZEEK_ALLOW_INIT_ERRORS; zeek -b %INPUT >out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
event zeek_init()
{
assert fmt("%s", 1) == "2";
print "not reached";
}
@TEST-START-NEXT
event zeek_init()
{
assert fmt("%s", 1) == "2", fmt("\"%s\" != \"2\"", 1);
print "not reached";
}
@TEST-START-NEXT
event zeek_init()
{
assert to_count("42") == 42.5, "always failing";
print "not reached";
}
@TEST-START-NEXT
event zeek_init()
{
local x = 2;
assert x == 1, fmt("Expected x to be 1, have %s", x);
print "not reached";
}
@TEST-START-NEXT
event zeek_init()
{
local tbl: table[string] of string = [
["abc"] = "123",
["def"] = "456",
];
assert "abc" in tbl, cat(tbl);
assert "def" in tbl, cat(tbl);
assert "ghi" in tbl, cat(tbl);
}
@TEST-START-NEXT
type MyRecord: record {
a: count;
b: count &optional;
};
event zeek_init()
{
local r: MyRecord = [$a=1234];
assert ! r?$b, fmt("Unexpected r$b is set to %s", r$b);
assert r?$b, fmt("r$b is not set in %s", r);
}
@TEST-START-NEXT
type MyRecord: record {
a: count;
b: count &optional;
};
event zeek_init()
{
local r: MyRecord = [$a=1234];
assert ! r?$b, fmt("Unexpected r$b is set to %s", r$b);
assert r?$b, fmt("r$b is not set trying anyway: %s", r$b);
}
@TEST-START-NEXT
assert 1 == 1, "always true";
assert 1 == 2, "always false";
print "not reached";