Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mp_derivedvarcheck.test.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Testing mp_derivedvarcheck macro
4
5 <h4> SAS Macros </h4>
6 @li mddl_derivedvars.sas
7 @li mp_assertcols.sas
8 @li mp_assertdsobs.sas
9 @li mp_assertscope.sas
10 @li mp_derivedvarcheck.sas
11
12**/
13
14/* one row per rule, plus the rows that must survive the scan */
15%mddl_derivedvars(libds=work.cases)
16
17data work.payload;
18 length var_logic $4000;
19 /* a complete SAS program with no literal semicolon anywhere in the source -
20 every character rule passes and only the function name gives it away */
21 var_logic="dosubl(cats('data _null_',byte(59),'data work.pwn',byte(59)
22 ,'run',byte(59)))";
23run;
24
25proc sql;
26insert into work.cases
27 set libref='WORK',dsn='CLASS',var_nm='ok_band',var_deps='AGE'
28 ,var_type='C',var_len=8,var_fmt='',var_logic="ifc(AGE>13,'TEEN','JUNIOR')"
29 ,active=1;
30insert into work.cases
31 set libref='WORK',dsn='CLASS',var_nm='ok_literal',var_deps='AGE'
32 ,var_type='C',var_len=8,var_fmt=''
33 ,var_logic="ifc(AGE>13,'DOSUBL(','NO')",active=1;
34insert into work.cases
35 set libref='WORK',dsn='CLASS',var_nm='ok_label',var_deps='AGE'
36 ,var_type='N',var_len=8,var_fmt='best12.',var_logic='AGE*2'
37 ,var_label='Age - doubled',active=1;
38/* a line break in the label is flattened to a space rather than refused, so a
39 control table that carries a wrapped label keeps working */
40insert into work.cases
41 set libref='WORK',dsn='CLASS',var_nm='ok_multiline',var_deps='AGE'
42 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE*3'
43 ,var_label='line one'||byte(10)||'line two',active=1;
44insert into work.cases
45 set libref='WORK',dsn='CLASS',var_nm='bad name',var_deps='AGE'
46 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE',active=1;
47insert into work.cases
48 set libref='WORK',dsn='CLASS',var_nm='1st',var_deps='AGE'
49 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE',active=1;
50insert into work.cases
51 set libref='WORK',dsn='CLASS',var_nm='_n_',var_deps='AGE'
52 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE',active=1;
53insert into work.cases
54 set libref='WORK',dsn='CLASS',var_nm='reserved_nm',var_deps='AGE'
55 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE',active=1;
56insert into work.cases
57 set libref='WORK',dsn='CLASS',var_nm='collides',var_deps='AGE'
58 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE',active=1;
59insert into work.cases
60 set libref='WORK',dsn='CLASS',var_nm='bad_type',var_deps='AGE'
61 ,var_type='X',var_len=8,var_fmt='',var_logic='AGE',active=1;
62insert into work.cases
63 set libref='WORK',dsn='CLASS',var_nm='bad_len',var_deps='AGE'
64 ,var_type='N',var_len=9,var_fmt='',var_logic='AGE',active=1;
65insert into work.cases
66 set libref='WORK',dsn='CLASS',var_nm='bad_fmt',var_deps='AGE'
67 ,var_type='N',var_len=8,var_fmt='best12.;x',var_logic='AGE',active=1;
68insert into work.cases
69 set libref='WORK',dsn='CLASS',var_nm='bad_label',var_deps='AGE'
70 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE'
71 ,var_label='bell'||byte(1)||'here',active=1;
72insert into work.cases
73 set libref='WORK',dsn='CLASS',var_nm='semicolon',var_deps='AGE'
74 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE;',active=1;
75insert into work.cases
76 set libref='WORK',dsn='CLASS',var_nm='comment',var_deps='AGE'
77 ,var_type='N',var_len=8,var_fmt='',var_logic='AGE /* x */',active=1;
78insert into work.cases
79 (libref,dsn,var_nm,var_deps,var_type,var_len,var_fmt,var_logic,active)
80 select 'WORK','CLASS','pwn','','N',8,'',var_logic,1 from work.payload;
81/* the file system is refused in both directions - assigning a fileref,
82 copying a file and deleting one are all names in the expression */
83insert into work.cases
84 set libref='WORK',dsn='CLASS',var_nm='fs_name',var_deps='AGE'
85 ,var_type='N',var_len=8,var_fmt=''
86 ,var_logic="filename('c1','/tmp/x.txt')",active=1;
87insert into work.cases
88 set libref='WORK',dsn='CLASS',var_nm='fs_del',var_deps='AGE'
89 ,var_type='N',var_len=8,var_fmt='',var_logic="fdelete('c1')",active=1;
90insert into work.cases
91 set libref='WORK',dsn='CLASS',var_nm='fs_copy',var_deps='AGE'
92 ,var_type='N',var_len=8,var_fmt=''
93 ,var_logic="fcopy('c1','c2')",active=1;
94quit;
95
96%mp_assertscope(SNAPSHOT)
97%mp_derivedvarcheck(
98 inds=work.cases,
99 outds=work.fails,
100 physlist=%str(AGE SEX COLLIDES),
101 reserved=%str(RESERVED_NM),
102 denyfuncs=%str(mydeniedfunc)
103)
104
105/* 19 rows: 4 valid, 15 that break a rule */
106%mp_assertdsobs(work.fails,
107 desc=One row is reported per invalid definition,
108 test=EQUALS 15,
109 outds=work.test_results
110)
111
112%mp_assertcols(work.fails,
113 desc=The output carries NAME and REASON,
114 cols=NAME REASON,
115 test=ALL,
116 outds=work.test_results
117)
118
119data work.chk;
120 set work.fails;
121 where name in ('OK_BAND','OK_LITERAL','OK_LABEL','OK_MULTILINE');
122run;
123
124%mp_assertdsobs(work.chk,
125 desc=No valid definition is reported,
126 test=EQUALS 0,
127 outds=work.test_results
128)
129
130data work.chk2;
131 set work.fails;
132 where missing(reason);
133run;
134
135%mp_assertdsobs(work.chk2,
136 desc=Every reported row carries a reason,
137 test=EQUALS 0,
138 outds=work.test_results
139)
140
141/* the two rules that need a list from the caller are skipped when it is not
142 supplied - the other thirteen still fire */
143%mp_derivedvarcheck(
144 inds=work.cases,
145 outds=work.fails2
146)
147
148%mp_assertdsobs(work.fails2,
149 desc=The optional lists change only their own rules,
150 test=EQUALS 13,
151 outds=work.test_results
152)
153
154/* denyfuncs adds to the built-in list rather than replacing it: the same row
155 is clean without it, refused with it, and a built-in name is still refused */
156%mddl_derivedvars(libds=work.cases2)
157
158proc sql;
159insert into work.cases2
160 set libref='WORK',dsn='CLASS',var_nm='sitefunc',var_deps='AGE'
161 ,var_type='N',var_len=8,var_fmt='',var_logic='MYDENIEDFUNC(AGE)',active=1;
162insert into work.cases2
163 set libref='WORK',dsn='CLASS',var_nm='builtin',var_deps='AGE'
164 ,var_type='N',var_len=8,var_fmt='',var_logic='sleep(AGE)',active=1;
165quit;
166
167%mp_derivedvarcheck(
168 inds=work.cases2,
169 outds=work.fails4,
170 denyfuncs=%str(MYDENIEDFUNC)
171)
172
173%mp_assertdsobs(work.fails4,
174 desc=denyfuncs adds a name without dropping the built-in list,
175 test=EQUALS 2,
176 outds=work.test_results
177)
178
179%mp_derivedvarcheck(
180 inds=work.cases2,
181 outds=work.fails5
182)
183
184%mp_assertdsobs(work.fails5,
185 desc=Without denyfuncs only the built-in name is refused,
186 test=EQUALS 1,
187 outds=work.test_results
188)
189
190%mp_assertscope(COMPARE,ignorelist=_SASJS_WEBOUT_HEADERS,
191 outds=work.test_results
192)