SASUnit Examples  Version 1.2.1
_sasunit_reporttcghtml.sas
Go to the documentation of this file.
1 
25 /* change history
26  13.02.2013 KL Lange Zeilen umgebrochen
27 */
28 
29 %macro _sasunit_reporttcghtml(
30  i_macroName=
31  ,i_macroLocation=
32  ,i_mCoverageName=
33  ,i_mCoverageLocation=
34  ,o_outputFile=
35  ,o_outputPath=
36  ,o_resVarName=
37  );
38 
39  %local l_MacroName;
40  %local l_MCoverageName;
41  %local l_linesize;
42 
43  %let l_MacroName=%lowcase(&i_macroName.);
44  %let l_MCoverageName=%lowcase(&i_mCoverageName.);
45 
46  /*** Check existence of input files */
47  %IF (NOT %SYSFUNC(FILEEXIST(&i_mCoverageLocation./&l_MCoverageName.)) OR &l_MCoverageName=) %THEN %DO;
48  %PUT ERROR: Input file with coverage data does not exist.;
49  %GOTO _macExit;
50  %END;
51  %IF (NOT %SYSFUNC(FILEEXIST(&i_macroLocation./&l_MacroName.)) OR &l_MacroName=) %THEN %DO;
52  %PUT ERROR: Input file with macro code does not exist.;
53  %GOTO _macExit;
54  %END;
55 
56  /*** Read records from flat file and keep only those of given macro ***/
57  data WORK._MCoverage1 (where=(upcase (MacName)="%scan(%upcase(&l_MacroName.),1,.)"));
58  length MacName $40;
59  infile "&i_mCoverageLocation./&l_MCoverageName.";
60  input;
61  RecordType = input (scan (_INFILE_, 1, ' '), ??8.);
62  FirstLine = input (scan (_INFILE_, 2, ' '), ??8.);
63  LastLine = input (scan (_INFILE_, 3, ' '), ??8.);
64  MacName = scan (_INFILE_, 4, ' ');
65  run;
66 
67  /*** Keep only one record per combination of record type first_line and last_line ***/
68  proc sort data=WORK._MCoverage1 out=WORK._MCoverage3 nodupkey;
69  by Firstline RecordType LastLine;
70  run;
71 
72  /*** Get the covered rows of the macro ***/;
73  data WORK._MCoverage4;
74  set WORK._MCoverage3;
75 
76  /*** Keep value of last record the detect changes from one observation to the other ***/
77  lag_LastLine = lag (LastLine);
78  lag_FirstLine = lag (FirstLine);
79 
80  /*** Generate line numbers for covered contributing rows ***/;
81  /*** 2 3 5 MacName . will be converted to: ***/
82  /*** 2 3 5 MacName 2 ***/
83  /*** 2 3 5 MacName 3 ***/
84  /*** 2 3 5 MacName 4 ***/
85  /*** 2 3 5 MacName 5 ***/
86  if (RecordType in (2)) then do;
87  do _line_ = FirstLine to LastLine;
88  output;
89  end;
90  end;
91 
92  /*** Generate line numbers for non-contributing rows ***/
93  /*** 3 3 5 MacName . will be converted to: ***/
94  /*** 3 3 5 MacName 2 ***/
95  /*** 3 3 5 MacName 3 ***/
96  /*** 3 3 5 MacName 4 ***/
97  /*** 3 3 5 MacName 5 ***/
98  if (RecordType in (3)) then do;
99  do nonEx = FirstLine to LastLine;
100  output;
101  end;
102  end;
103  run;
104 
105  /*** Due to the order of check in above data step, line numbers are not sorted properly ***/
106  /*** Sort lines and generate a second data set with non-contributing rows ***/
107  proc sort data=WORK._MCoverage4 out=WORK._MCoverage5 NODUPKEY;
108  by _line_;
109  run;
110  proc sort data=WORK._MCoverage4 out=WORK._NonEx NODUPKEY;
111  by nonEx;
112  run;
113 
114  /*** Enumerate lines in source code file , flagging all lines before %macro statement with -1 ***/
115  data WORK.rowsOfInputFile;
116  length srcrow $300 nCounter 8;
117  retain srcrow " " nCounter -1;
118  infile "&i_macroLocation./&l_MacroName.";
119  input;
120  srcrow = _INFILE_;
121  if (index (upcase (srcrow), "%nrstr(%MACRO )%scan(%upcase(&l_MacroName.),1,.)")) then do;
122  nCounter=0;
123  end;
124  if (nCounter >= 0) then do;
125  nCounter=nCounter+1;
126  end;
127  run;
128 
129  /*** Read all lines not explicitly marked as covered ***/
130  proc sql noprint;
131  select distinct nCounter into :MissingLines separated by ' ' from WORK.rowsOfInputFile
132  where nCounter not in (select distinct _line_ from WORK._MCoverage5 where _line_ not eq .);
133  quit;
134 
135  /*** If there is an %if-statement with %do and %end an adjustment is made: ***/
136  /*** If the %if-expression is evaluated to false then the corresponding ***/
137  /*** %end is not marked as covered... therefore it is marked manually, ***/
138  /*** same procedure for %mend ***/
139 
140  data WORK.MCoverage /*(keep=srcrow nCounter covered srcRowCopy)*/;
141  length srcrow $300 nCounter 8 srcRowCopy $2048 inExecutedBlock 8 inExecutedMBlock 8;
142  retain srcrow " " nCounter -1 inExecutedBlock 0 inExecutedMBlock 0;
143  label srcrow="Macrostatements";
144  infile "&i_macroLocation./&l_MacroName.";
145  input;
146  if (index (upcase (_INFILE_), "%nrstr(%MACRO )%scan(%upcase(&l_MacroName.),1,.)")) then do;
147  if not(1 in (&MissingLines.)) then do;
148  inExecutedMBlock = inExecutedMBlock + 1;
149  end;
150  nCounter=0;
151  end;
152  if (nCounter >= 0) then do;
153  nCounter=nCounter+1;
154  end;
155  srcrow = cats ("", _INFILE_, "");
156  srcRowCopy = _INFILE_;
157  covered = 1;
158 
159  if (nCounter in (&MissingLines.)) then do;
160  srcrow = cats ("", _INFILE_, "");
161  covered = 0;
162  _temp_row = compress (upcase (_INFILE_));
163  if (length (_temp_row) > 4) then do;
164  if ( (substr (_temp_row,1,5) = '%END;') or (substr (_temp_row,1,5) = '%END ') ) then do;
165  srcrow = cats ("", _INFILE_, "");
166  if inExecutedBlock gt 0 then do;
167  covered = 1;
168  end;
169  inExecutedBlock = inExecutedBlock - 1;
170  end;
171  end;
172  if (length (_temp_row) > 4) then do;
173  if ( (substr (_temp_row,1,6) = '%MEND;') or (substr (_temp_row,1,5) = '%MEND ') ) then do;
174  srcrow = cats ("", _INFILE_, "");
175  if inExecutedMBlock gt 0 then do;
176  covered = 1;
177  end;
178  inExecutedMBlock = inExecutedMBlock - 1;
179  end;
180  end;
181  end;
182  else do;
183  _temp_row = compress (upcase (_INFILE_));
184  if ( (count (_temp_row,'%DO') gt 0) ) then do;
185  inExecutedBlock = inExecutedBlock + count (_temp_row,'%DO');
186  end;
187  if (length (_temp_row) > 4) then do;
188  if ( (substr (_temp_row,1,5) = '%END;') or (substr (_temp_row,1,5) = '%END ') ) then do;
189  inExecutedBlock = inExecutedBlock - 1;
190  end;
191  end;
192  if (length (_temp_row) > 4) then do;
193  if ( (substr (_temp_row,1,6) = '%MEND;') or (substr (_temp_row,1,5) = '%MEND ') ) then do;
194  inExecutedMBlock = inExecutedMBlock - 1;
195  end;
196  end;
197  end;
198  run;
199 
200  /*** Scan rows for comment lines ***/
201  DATA _commentLines;
202  SET Rowsofinputfile(rename=(srcrow=srcline));
203  RETAIN inComment oneLineComment endCommentNextLine commentStartsNextLine
204  ;
205 
206  IF _N_=1 THEN DO;
207  inComment = 0;
208  oneLineComment = 0;
209  endCommentNextLine = 0;
210  commentStartsNextLine = 0;
211  END;
212 
213  IF oneLineComment = 1 THEN DO;
214  inComment = 0;
215  oneLineComment = 0;
216  END;
217  IF endCommentNextLine = 1 THEN DO;
218  inComment = 0;
219  endCommentNextLine =0;
220  END;
221  IF commentStartsNextLine = 1 THEN DO;
222  inComment = 1;
223  commentStartsNextLine =0;
224  END;
225 
226 
227  IF NOT ((index(srcline, '/*') > 0) AND (index(srcline, '*/') > 0))THEN DO;
228  IF index(srcline, '*/') > 0 THEN DO;
229  endCommentNextLine = 1;
230  END;
231  ELSE DO;
232  IF (index(srcline, '/*') GT 0) THEN DO;
233  IF index(compress(srcline,, 's'),'/*') EQ 1 THEN DO;
234  inComment=1;
235  END;
236  commentStartsNextLine=1;
237  END;
238  END;
239  END;
240  ELSE DO;
241  IF index(compress(srcline,, 's'),'/*') EQ 1 AND index(compress(srcline,, 's'),'*/') EQ length(compress(srcline,, 's'))-1 THEN DO;
242  inComment=1;
243  oneLineComment=1;
244  END;
245  ELSE IF count(srcline,'*/') gt count(srcline,'/*') THEN DO;
246  endCommentNextLine = 1;
247  END;
248  END;
249  RUN;
250 
251  /*** Update WORK.MCoverage to flag the non contributing rows identified by MCOVERAGE OPTION ***/
252  proc sql noprint;
253  update MCoverage
254  set covered = -2
255  where nCounter in (select distinct nonEx from WORK._nonex where nonEx not eq .);
256  update MCoverage
257  set covered = -1
258  where nCounter in ((select distinct nCounter from _commentLines where inComment eq 1 or compress(compress(srcline),"0D"x) eq ''));
259  quit;
260 
261  /*** Get sets of rows of different different types: covered contributing, non-covered contributing and non contributing ***/
262  proc sql noprint;
263 
264  create table rowNumbersCovered as
265  select distinct nCounter as row from WORK.MCoverage where covered EQ 1;
266  create table rowNumbersNonCovered as
267  select distinct nCounter as row from WORK.MCoverage where covered EQ 0;
268  create table rowNumbersNonCbuting as
269  select distinct nCounter as row from WORK.MCoverage where covered LE -1;
270 
271  select count(*) into:ContributingLocCovered from rowNumbersCovered;
272  select count(*) into:ContributingLocNonCovered from rowNumbersNonCovered;
273  quit;
274 
275  /*** Calculate the percentage of covered contributing rows ***/
276  %let Coverage = %sysevalf (&ContributingLocCovered. / (&ContributingLocCovered. + &ContributingLocNonCovered.));
277  %let CoveragePCT = %sysfunc (putn (&Coverage., nlpct));
278 
279  %if "&o_resVarName." NE "" %then %do;
280  %let &o_resVarName. = %sysevalf(%sysfunc (round(&Coverage.,0.01))*100);
281  %end;
282 
283  /*** Print the result *****************************************************/
284  /* Save the value of the LINESIZE system option */
285  %LET l_linesize = %sysfunc(getoption(linesize,keyword));
286  OPTIONS LINESIZE=MAX;
287  TITLE1;
288 
289  DATA _null_;
290  LENGTH outputRow $2048;
291  FILE "&o_outputPath./&o_outputFile." RECFM=P;
292  SET MCoverage END=eof;
293  outputRow = put(_N_,Z6.)||' '||srcRowCopy;
294  IF _n_=1 THEN DO;
295  /*HTML-Header*/
296  PUT '<html>';
297  PUT '<head>';
298  PUT '<meta http-equiv="Content-Language" content="de">';
299  PUT '<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">';
300  PUT '<link href="sasunit.css" rel="stylesheet" type="text/css">';
301  PUT "<title>&g_nls_reportAuton_017. &i_macroName.</title>";
302  PUT '</head>';
303  /*HTML-Body*/
304  PUT '<body>';
305  PUT '<h1>'"&g_nls_reportAuton_005.: &i_macroName"'</h1>';
306  PUT '<h2>'"&g_nls_reportAuton_016.: &CoveragePCT."'</h2>';
307  PUT '<h3>Color Legend:</h3>';
308  PUT '<ul>';
309  PUT ' <li><span style="color:#00BE00">'"&g_nls_reportAuton_018."'</span></li>';
310  PUT ' <li><span style="color:#FF8020">'"&g_nls_reportAuton_019."'</span></li>';
311  PUT ' <li><span style="color:#828282">'"&g_nls_reportAuton_020."'</span></li>';
312  PUT ' <li><span style="color:#8020FF">'"&g_nls_reportAuton_021."'</span></li>';
313  PUT '</ul>';
314  PUT '<hr /><pre><code>';
315  END;
316 
317  IF covered = -1 THEN DO;
318  PUT '<span style="color:#828282">' outputRow '</span>';
319  END;
320  ELSE IF covered = 1 THEN DO;
321  PUT '<span style="color:#00BE00">' outputRow '</span>';
322  END;
323  ELSE IF covered = 0 THEN DO;
324  PUT '<span style="color:#FF8020">' outputRow '</span>';
325  END;
326  ELSE DO;
327  PUT '<span style="color:#8020FF">' outputRow '</span>';
328  END;
329  IF eof=1 THEN DO;
330  /*HTML-Close*/
331  PUT '</code></pre>';
332  PUT '</body>';
333  PUT '</html>';
334  END;
335  RUN;
336  /* reset option linesize*/
337  OPTIONS &l_linesize.;
338 
339  %_macExit:
340 %mend _sasunit_reporttcghtml;