Files
dc/sas/sasjs/macros/mpe_assert_abort.test.sas
T
dc cface15b92
Build / Build-and-ng-test (pull_request) Successful in 5m5s
Lighthouse Checks / lighthouse (pull_request) Successful in 18m13s
Build / Build-and-test-development (pull_request) Successful in 28m43s
chore(deps): @sasjs/core 7.0.3 and require the abort message to match
Core 7.0.3 fills outstatus.errmsg on both platforms - the SASJS branch since
7.0.2, the Viya branch from the job result as of 7.0.3 - so a canceled call now
always carries the reason it was canceled.

That removes the last platform difference from the assertion: while Viya wrote a
blank errmsg, an expected message could only be checked on one platform and the
state alone had to stand in on the other.  A comparison against a message that
was never recorded now fails instead of passing silently, which is the point of
asking for it.
2026-10-31 18:09:13 +00:00

289 lines
7.0 KiB
SAS

/**
@file
@brief testing the mpe_assert_abort macro
@details The macro decides PASS/FAIL from the child's status row - STATE says
whether the child was canceled, ERRMSG holds the reason - so the cases can be
built as datasets instead of services: an abort with the expected message, an
abort with a different one, a completed call, a status dataset that does not
exist, a message past the old 256 character width, quotes, backslashes, and
the log extract that mp_abort appends to the message.
Each case asserts on the PASS/FAIL the macro recorded, so a regression in the
comparison fails here rather than silently passing an abort assertion in a
service test.
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mpe_assert_abort.sas
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
/** a status row as %mpe_execute leaves it: the job state and the message */
%macro mk_status(ds, state, msg);
/* the values come from the symbol table rather than from quoted text: a
message holding double quotes would otherwise end the literal early */
data &ds;
length state $20 uri $256 errmsg $32767 platform $10;
state=symget('state');
uri='';
errmsg=symget('msg');
platform='SASJS';
run;
%mend mk_status;
/**
* Test 1 - an abort whose message matches is a PASS
*/
%mk_status(work.st1, canceled, Invalid libds)
%mpe_assert_abort(
desc=an abort with the expected MSG,
outstatus=work.st1,
msg=Invalid libds,
outds=work.rc1
)
/**
* Test 2 - an abort for a different reason is a FAIL
*/
%mk_status(work.st2, canceled, Invalid libds)
%mpe_assert_abort(
desc=an abort with a different MSG,
outstatus=work.st2,
msg=Invalid filter,
outds=work.rc2
)
/**
* Test 3 - a completed call is a FAIL
*/
%mk_status(work.st3, completed, )
%mpe_assert_abort(
desc=a completed call,
outstatus=work.st3,
msg=0,
outds=work.rc3
)
/**
* Test 4 - a status dataset that does not exist fails the assertion, not the step
*/
%mpe_assert_abort(
desc=a status dataset that was never written,
outstatus=work.doesnotexist,
msg=0,
outds=work.rc4
)
/**
* Test 5 - a message longer than the old capture width is compared in full
*
* The status row carries the whole message, so a caller comparing a long one
* gets an answer rather than a silent 256 character cut.
*/
%let longmsg=;
data work.st5;
length state $20 errmsg $32767;
state='canceled';
errmsg=repeat('a clause that runs on ',30);
call symputx('longmsg',errmsg,'l');
run;
%mpe_assert_abort(
desc=an abort with a message past the old capture width,
outstatus=work.st5,
msg=%superq(longmsg),
outds=work.rc5
)
/**
* Test 6 - quotes in the message survive
*/
%mk_status(work.st6, canceled, %str(alpha "quoted" beta))
%mpe_assert_abort(
desc=a message holding double quotes,
outstatus=work.st6,
msg=%str(alpha "quoted" beta),
outds=work.rc6
)
/**
* Test 7 - the log extract mp_abort appends is not part of the message
*/
data work.st7;
length state $20 errmsg $32767;
state='canceled';
errmsg=cats('Invalid libds','0A0A'x,'Log Extract:','0A0A'x,'NOTE: a log line');
run;
%mpe_assert_abort(
desc=an abort with the appended log extract,
outstatus=work.st7,
msg=Invalid libds,
outds=work.rc7
)
/**
* Test 8 - a message that itself mentions the marker is not cut at it
*
* Only the two newlines before the marker identify the appended extract; a
* message that merely says "Log Extract:" keeps its text.
*/
data work.st8;
length state $20 errmsg $32767;
state='canceled';
errmsg='check the hook Log Extract: is mentioned here';
run;
%mpe_assert_abort(
desc=a message containing the extract marker,
outstatus=work.st8,
msg=%str(check the hook Log Extract: is mentioned here),
outds=work.rc8
)
/**
* Test 9 - a canceled call with no message fails a comparison it cannot support
*
* Core fills errmsg on both platforms now, so a blank one means the reason was
* never recorded - an expected message cannot be proved, and the assertion
* says so rather than passing on the state alone.
*/
%mk_status(work.st9, canceled, )
%mpe_assert_abort(
desc=a canceled call whose status row carries no message,
outstatus=work.st9,
msg=Invalid libds,
outds=work.rc9
)
/**
* Test 10 - backslashes in the message compare as they were raised
*/
%mk_status(work.st10, canceled, %str(C:\temp\share))
%mpe_assert_abort(
desc=a message holding backslashes,
outstatus=work.st10,
msg=%str(C:\temp\share),
outds=work.rc10
)
/**
* Test 11 - the doubled separator the escaping producer writes
*
* mp_abort doubles backslashes, so the appended extract arrives as a literal
* doubled pair rather than as characters.
*/
data work.st11;
length state $20 errmsg $32767;
state='canceled';
errmsg=cats('Invalid libds','\\n\\nLog Extract:\\n','NOTE: a log line');
run;
%mpe_assert_abort(
desc=an abort whose extract arrives doubled,
outstatus=work.st11,
msg=Invalid libds,
outds=work.rc11
)
/**
* Test 12 - the recorded results
*/
%macro getres(ds, var);
data _null_;
set &ds;
call symputx("&var",test_result,'g');
run;
%mend getres;
%getres(work.rc1, res_any)
%getres(work.rc2, res_other)
%getres(work.rc3, res_none)
%getres(work.rc4, res_noref)
%getres(work.rc5, res_long)
%getres(work.rc6, res_quotes)
%getres(work.rc7, res_logmark)
%getres(work.rc8, res_marker)
%getres(work.rc9, res_nomsg)
%getres(work.rc10, res_bslash)
%getres(work.rc11, res_doubled)
%mp_assert(
iftrue=("&res_any"="PASS"),
desc=%str(Checking an abort with the expected MSG passes),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_other"="FAIL"),
desc=%str(Checking an abort with a different MSG fails),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_none"="FAIL"),
desc=%str(Checking a completed call fails),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_noref"="FAIL"),
desc=%str(Checking a missing status dataset fails the assertion, not the step),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_long"="PASS"),
desc=%str(Checking an abort message past the old capture width matches in full),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_quotes"="PASS"),
desc=%str(Checking a message holding double quotes compares),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_logmark"="PASS"),
desc=%str(Checking the appended log extract is stripped),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_marker"="PASS"),
desc=%str(Checking a message containing the extract marker is not cut at it),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_nomsg"="FAIL"),
desc=%str(Checking a canceled call with no message fails the comparison),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_bslash"="PASS"),
desc=%str(Checking a message holding backslashes compares),
outds=work.test_results
)
%mp_assert(
iftrue=("&res_doubled"="PASS"),
desc=%str(Checking the doubled extract separator is stripped),
outds=work.test_results
)