Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mp_rowhash.test.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Testing mp_rowhash.sas macro
4 @details The mp_rowhash macro generates DATA step statements that compute a
5 deterministic row-level MD5 hash. These tests exercise the versioned seed,
6 character and numeric hashing rules, variable ordering, sensitivity to
7 whitespace, and reproducibility.
8
9 <h4> SAS Macros </h4>
10 @li mp_rowhash.sas
11 @li mp_assert.sas
12 @li mp_assertscope.sas
13
14**/
15
16%mp_assertscope(SNAPSHOT)
17
18/* test 1 - versioned seed only (no input variables) */
19data _null_;
20 length actual expected $32;
21 actual='';
22 %mp_rowhash(md5_col=actual)
23 expected=put(md5('DC HASH v2'),$hex32.);
24 call symputx('t1_actual',actual);
25 call symputx('t1_expected',expected);
26run;
27%mp_assertscope(COMPARE,ignorelist=T1_ACTUAL T1_EXPECTED)
28%mp_assert(
29 iftrue=("&t1_actual"="&t1_expected"),
30 desc=Versioned seed is returned when no variables are supplied,
31 outds=work.test_results
32)
33
34/* test 2 - single character variable reference */
35data _null_;
36 length c1 $1 actual expected $32;
37 length state digest $16 pair $32;
38 c1='A';
39 actual='';
40 %mp_rowhash(md5_col=actual, cvars=c1)
41 state=md5('DC HASH v2');
42 digest=md5(trimn(c1));
43 pair=state||digest;
44 expected=put(md5(pair),$hex32.);
45 call symputx('t2_actual',actual);
46 call symputx('t2_expected',expected);
47run;
48%mp_assert(
49 iftrue=("&t2_actual"="&t2_expected"),
50 desc=Single character variable hash matches reference construction,
51 outds=work.test_results
52)
53
54/* test 3 - single numeric variable reference */
55data _null_;
56 length actual expected $32;
57 length state digest $16 numtext $64 pair $32;
58 n1=42;
59 actual='';
60 %mp_rowhash(md5_col=actual, nvars=n1)
61 state=md5('DC HASH v2');
62 /* multiply-by-one matches the internal normalisation */
63 normal=n1*1;
64 numtext=put(normal,binary64.);
65 digest=md5(trim(numtext));
66 pair=state||digest;
67 expected=put(md5(pair),$hex32.);
68 call symputx('t3_actual',actual);
69 call symputx('t3_expected',expected);
70run;
71%mp_assert(
72 iftrue=("&t3_actual"="&t3_expected"),
73 desc=Single numeric variable hash matches reference construction,
74 outds=work.test_results
75)
76
77/* test 4 - order of cvars affects the resulting hash */
78data _null_;
79 length c1 c2 $1 h1 h2 $32;
80 c1='A';
81 c2='B';
82 h1='';
83 %mp_rowhash(md5_col=h1, cvars=c1 c2)
84 h2='';
85 %mp_rowhash(md5_col=h2, cvars=c2 c1)
86 call symputx('t4_h1',h1);
87 call symputx('t4_h2',h2);
88run;
89%mp_assert(
90 iftrue=("&t4_h1" ne "&t4_h2"),
91 desc=Order of cvars changes the resulting hash,
92 outds=work.test_results
93)
94
95/* test 5 - order of nvars affects the resulting hash */
96data _null_;
97 length h1 h2 $32;
98 n1=1;
99 n2=2;
100 h1='';
101 %mp_rowhash(md5_col=h1, nvars=n1 n2)
102 h2='';
103 %mp_rowhash(md5_col=h2, nvars=n2 n1)
104 call symputx('t5_h1',h1);
105 call symputx('t5_h2',h2);
106run;
107%mp_assert(
108 iftrue=("&t5_h1" ne "&t5_h2"),
109 desc=Order of nvars changes the resulting hash,
110 outds=work.test_results
111)
112
113/* test 6 - identical rows produce identical hashes */
114data work.test6;
115 length c $5 n 8;
116 c='ABC';
117 n=42;
118 output;
119 output;
120run;
121
122data work.test6_hashed;
123 set work.test6;
124 length hash $32;
125 %mp_rowhash(md5_col=hash, cvars=c, nvars=n)
126run;
127
128proc sql noprint;
129 select count(distinct hash) into: t6_distinct trimmed
130 from work.test6_hashed;
131quit;
132
133%mp_assert(
134 iftrue=(&t6_distinct=1),
135 desc=Identical rows produce identical hashes,
136 outds=work.test_results
137)
138
139/* test 7 - different rows produce different hashes */
140data work.test7;
141 length c $5 n 8;
142 c='ABC';
143 n=42;
144 output;
145 c='ABD';
146 n=42;
147 output;
148run;
149
150data work.test7_hashed;
151 set work.test7;
152 length hash $32;
153 %mp_rowhash(md5_col=hash, cvars=c, nvars=n)
154run;
155
156proc sql noprint;
157 select count(distinct hash) into: t7_distinct trimmed
158 from work.test7_hashed;
159quit;
160
161%mp_assert(
162 iftrue=(&t7_distinct=2),
163 desc=Different rows produce different hashes,
164 outds=work.test_results
165)
166
167/* test 8 - leading blanks in character variables are retained */
168data work.test8;
169 length c $5;
170 c=' f';
171 output;
172 c='f';
173 output;
174run;
175
176data work.test8_hashed;
177 set work.test8;
178 length hash $32;
179 %mp_rowhash(md5_col=hash, cvars=c)
180run;
181
182proc sql noprint;
183 select count(distinct hash) into: t8_distinct trimmed
184 from work.test8_hashed;
185quit;
186
187%mp_assert(
188 iftrue=(&t8_distinct=2),
189 desc=Leading blanks are retained in character hashes,
190 outds=work.test_results
191)
192
193
194