SASUnit Examples  Version 1.5.0
_reporttcghtml.sas
Go to the documentation of this file.
1 
33 %macro _reporttcghtml(i_macroName=
34  ,i_macroLocation=
35  ,i_mCoverageName=
36  ,i_mCoverageLocation=
37  ,o_outputFile=
38  ,o_outputPath=
39  ,o_resVarName=
40  ,o_html=0
41  );
42 
43  %local l_MacroName;
44  %local l_MCoverageName;
45  %local l_linesize;
46  %local l_MissingLines;
47 
48  %let l_MacroName=%lowcase(&i_macroName.);
49  %let l_MCoverageName=%lowcase(&i_mCoverageName.);
50 
51  /*** Check existence of input files */
52  %IF (NOT %SYSFUNC(FILEEXIST(&i_mCoverageLocation./&l_MCoverageName.)) OR &l_MCoverageName=) %THEN %DO;
53  %PUT ERROR(SASUNIT): Input file with coverage data does not exist.;
54  %GOTO _macExit;
55  %END;
56  %IF (NOT %SYSFUNC(FILEEXIST(&i_macroLocation./&l_MacroName.)) OR &l_MacroName=) %THEN %DO;
57  %PUT ERROR(SASUNIT): Input file with macro code does not exist.;
58  %GOTO _macExit;
59  %END;
60 
61  /*** Read records from flat file and keep only those of given macro ***/
62  data WORK._MCoverage1 (where=(upcase (MacName)="%scan(%upcase(&l_MacroName.),1,.)"));
63  length MacName $40;
64  infile "&i_mCoverageLocation./&l_MCoverageName.";
65  input;
66  RecordType = input (scan (_INFILE_, 1, ' '), ??8.);
67  FirstLine = input (scan (_INFILE_, 2, ' '), ??8.);
68  LastLine = input (scan (_INFILE_, 3, ' '), ??8.);
69  MacName = scan (_INFILE_, 4, ' ');
70  run;
71 
72  /*** Keep only one record per combination of record type first_line and last_line ***/
73  proc sort data=WORK._MCoverage1 out=WORK._MCoverage3 nodupkey;
74  by Firstline RecordType LastLine;
75  run;
76 
77  /*** Get the covered rows of the macro ***/;
78  data WORK._MCoverage4;
79  set WORK._MCoverage3;
80 
81  /*** Keep value of last record the detect changes from one observation to the other ***/
82  lag_LastLine = lag (LastLine);
83  lag_FirstLine = lag (FirstLine);
84 
85  /*** Generate line numbers for covered contributing rows ***/;
86  /*** 2 3 5 MacName . will be converted to: ***/
87  /*** 2 3 5 MacName 2 ***/
88  /*** 2 3 5 MacName 3 ***/
89  /*** 2 3 5 MacName 4 ***/
90  /*** 2 3 5 MacName 5 ***/
91  if (RecordType in (2)) then do;
92  do _line_ = FirstLine to LastLine;
93  output;
94  end;
95  end;
96 
97  /*** Generate line numbers for non-contributing rows ***/
98  /*** 3 3 5 MacName . will be converted to: ***/
99  /*** 3 3 5 MacName 2 ***/
100  /*** 3 3 5 MacName 3 ***/
101  /*** 3 3 5 MacName 4 ***/
102  /*** 3 3 5 MacName 5 ***/
103  if (RecordType in (3)) then do;
104  do nonEx = FirstLine to LastLine;
105  output;
106  end;
107  end;
108  run;
109 
110  /*** Due to the order of check in above data step, line numbers are not sorted properly ***/
111  /*** Sort lines and generate a second data set with non-contributing rows ***/
112  proc sort data=WORK._MCoverage4 out=WORK._MCoverage5 NODUPKEY;
113  by _line_;
114  run;
115  proc sort data=WORK._MCoverage4 out=WORK._NonEx NODUPKEY;
116  by nonEx;
117  run;
118 
119  /*** Enumerate lines in source code file , flagging all lines before %macro statement with -1 ***/
120  data WORK.rowsOfInputFile;
121  length srcrow $300 nCounter 8;
122  retain srcrow " " nCounter -1;
123  infile "&i_macroLocation./&l_MacroName.";
124  input;
125  srcrow = _INFILE_;
126  if (index (upcase (srcrow), "%nrstr(%MACRO )%scan(%upcase(&l_MacroName.),1,.)")) then do;
127  nCounter=0;
128  end;
129  if (nCounter >= 0) then do;
130  nCounter=nCounter+1;
131  end;
132  run;
133 
134  /*** Read all lines not explicitly marked as covered ***/
135  /*** This can result in selecting no rows! So we need to ***/
136  /*** preassign a value to missinglines. Does zero sound okay? ***/
137  %let MissingLines=0;
138  %let l_MissingLines = 0;
139  proc sql noprint;
140  select distinct nCounter into :l_MissingLines separated by ' ' from WORK.rowsOfInputFile
141  where nCounter not in (select distinct _line_ from WORK._MCoverage5 where _line_ not eq .);
142  quit;
143 
144  /*** If there is an %if-statement with %do and %end an adjustment is made: ***/
145  /*** If the %if-expression is evaluated to false then the corresponding ***/
146  /*** %end is not marked as covered... therefore it is marked manually, ***/
147  /*** same procedure for %mend ***/
148 
149  data WORK.MCoverage /*(keep=srcrow nCounter covered srcRowCopy)*/;
150  length srcrow $300 nCounter 8 srcRowCopy $2048 inExecutedBlock 8 inExecutedMBlock 8;
151  retain srcrow " " nCounter -1 inExecutedBlock 0 inExecutedMBlock 0;
152  label srcrow="Macrostatements";
153  infile "&i_macroLocation./&l_MacroName.";
154  input;
155  if (index (upcase (_INFILE_), "%nrstr(%MACRO )%scan(%upcase(&l_MacroName.),1,.)")) then do;
156  if not(1 in (&l_MissingLines.)) then do;
157  inExecutedMBlock = inExecutedMBlock + 1;
158  end;
159  nCounter=0;
160  end;
161  if (nCounter >= 0) then do;
162  nCounter=nCounter+1;
163  end;
164  srcrow = cats ("", _INFILE_, "");
165  srcRowCopy = _INFILE_;
166  covered = 1;
167 
168  if (nCounter in (&l_MissingLines.)) then do;
169  srcrow = cats ("", _INFILE_, "");
170  covered = 0;
171  _temp_row = compress (upcase (_INFILE_));
172  if (length (_temp_row) > 4) then do;
173  if ( (substr (_temp_row,1,5) = '%END;') or (substr (_temp_row,1,5) = '%END ') ) then do;
174  srcrow = cats ("", _INFILE_, "");
175  if inExecutedBlock gt 0 then do;
176  covered = 1;
177  end;
178  inExecutedBlock = inExecutedBlock - 1;
179  end;
180  end;
181  if (length (_temp_row) > 4) then do;
182  if ( (substr (_temp_row,1,6) = '%MEND;') or (substr (_temp_row,1,5) = '%MEND ') ) then do;
183  srcrow = cats ("", _INFILE_, "");
184  if inExecutedMBlock gt 0 then do;
185  covered = 1;
186  end;
187  inExecutedMBlock = inExecutedMBlock - 1;
188  end;
189  end;
190  end;
191  else do;
192  _temp_row = compress (upcase (_INFILE_));
193  if ( (count (_temp_row,'%DO') gt 0) ) then do;
194  inExecutedBlock = inExecutedBlock + count (_temp_row,'%DO');
195  end;
196  if (length (_temp_row) > 4) then do;
197  if ( (substr (_temp_row,1,5) = '%END;') or (substr (_temp_row,1,5) = '%END ') ) then do;
198  inExecutedBlock = inExecutedBlock - 1;
199  end;
200  end;
201  if (length (_temp_row) > 4) then do;
202  if ( (substr (_temp_row,1,6) = '%MEND;') or (substr (_temp_row,1,5) = '%MEND ') ) then do;
203  inExecutedMBlock = inExecutedMBlock - 1;
204  end;
205  end;
206  end;
207  run;
208 
209  /*** Scan rows for comment lines ***/
210  DATA _commentLines;
211  SET Rowsofinputfile(rename=(srcrow=srcline));
212  RETAIN inComment oneLineComment endCommentNextLine commentStartsNextLine
213  ;
214 
215  IF _N_=1 THEN DO;
216  inComment = 0;
217  oneLineComment = 0;
218  endCommentNextLine = 0;
219  commentStartsNextLine = 0;
220  END;
221 
222  IF oneLineComment = 1 THEN DO;
223  inComment = 0;
224  oneLineComment = 0;
225  END;
226  IF endCommentNextLine = 1 THEN DO;
227  inComment = 0;
228  endCommentNextLine =0;
229  END;
230  IF commentStartsNextLine = 1 THEN DO;
231  inComment = 1;
232  commentStartsNextLine =0;
233  END;
234 
235 
236  IF NOT ((index(srcline, '/*') > 0) AND (index(srcline, '*/') > 0))THEN DO;
237  IF index(srcline, '*/') > 0 THEN DO;
238  endCommentNextLine = 1;
239  END;
240  ELSE DO;
241  IF (index(srcline, '/*') GT 0) THEN DO;
242  IF index(compress(srcline,, 's'),'/*') EQ 1 THEN DO;
243  inComment=1;
244  END;
245  commentStartsNextLine=1;
246  END;
247  END;
248  END;
249  ELSE DO;
250  IF index(compress(srcline,, 's'),'/*') EQ 1 AND index(compress(srcline,, 's'),'*/') EQ length(compress(srcline,, 's'))-1 THEN DO;
251  inComment=1;
252  oneLineComment=1;
253  END;
254  ELSE IF count(srcline,'*/') gt count(srcline,'/*') THEN DO;
255  endCommentNextLine = 1;
256  END;
257  END;
258  RUN;
259 
260  /*** Update WORK.MCoverage to flag the non contributing rows identified by MCOVERAGE OPTION ***/
261  proc sql noprint;
262  update WORK.MCoverage
263  set covered = -2
264  where nCounter in (select distinct nonEx from WORK._nonex where nonEx not eq .);
265  update WORK.MCoverage
266  set covered = -1
267  where nCounter in ((select distinct nCounter from _commentLines where inComment eq 1 or compress(compress(srcline),"0D"x) eq ''));
268  quit;
269 
270  /*** Get sets of rows of different different types: covered contributing, non-covered contributing and non contributing ***/
271  proc sql noprint;
272 
273  create table rowNumbersCovered as
274  select distinct nCounter as row from WORK.MCoverage where covered EQ 1;
275  create table rowNumbersNonCovered as
276  select distinct nCounter as row from WORK.MCoverage where covered EQ 0;
277  create table rowNumbersNonCbuting as
278  select distinct nCounter as row from WORK.MCoverage where covered LE -1;
279 
280  select count(*) into:ContributingLocCovered from rowNumbersCovered;
281  select count(*) into:ContributingLocNonCovered from rowNumbersNonCovered;
282  quit;
283 
284  /*** Calculate the percentage of covered contributing rows ***/
285  %let Coverage = %sysevalf (&ContributingLocCovered. / (&ContributingLocCovered. + &ContributingLocNonCovered.));
286  %let CoveragePCT = %sysfunc (putn (&Coverage., nlpct));
287 
288  %if "&o_resVarName." NE "" %then %do;
289  %let &o_resVarName. = %sysevalf(%sysfunc (round(&Coverage.,0.01))*100);
290  %end;
291 
292  data work._tcg_legend;
293  length dummy $3 Text $140;
294  dummy=" ";Text="^{unicode 25CF} ^{style tcgCoveredData &g_nls_reportAuton_018.}";output;
295  dummy=" ";Text="^{unicode 25CF} ^{style tcgNonCoveredData &g_nls_reportAuton_019.}";output;
296  dummy=" ";Text="^{unicode 25CF} ^{style tcgCommentData &g_nls_reportAuton_020.}";output;
297  dummy=" ";Text="^{unicode 25CF} ^{style tcgNonContribData &g_nls_reportAuton_021.}";output;
298  run;
299 
300  data work._tcg_report;
301  LENGTH outputRow pgmSourceColumn $2048 RowNumberOut $200;
302  SET WORK.MCoverage;
303  RowNumber = _N_;
304  outputRow = trim(srcRowCopy);
305  outputRow = tranwrd (outputRow,'^{','^[');
306  outputRow = tranwrd (outputRow,'}',']');
307  %_render_dataColumn (i_sourceColumn=RowNumber
308  ,i_format=Z5.
309  ,i_columnType=tcgCommentData
310  ,o_targetColumn=RowNumberOut
311  );
312  IF covered = -1 THEN DO;
313  %_render_dataColumn (i_sourceColumn=outputRow
314  ,i_columnType=tcgCommentData
315  ,o_targetColumn=pgmSourceColumn
316  );
317  END;
318  ELSE IF covered = 1 THEN DO;
319  %_render_dataColumn (i_sourceColumn=outputRow
320  ,i_columnType=tcgCoveredData
321  ,o_targetColumn=pgmSourceColumn
322  );
323  END;
324  ELSE IF covered = 0 THEN DO;
325  %_render_dataColumn (i_sourceColumn=outputRow
326  ,i_columnType=tcgNonCoveredData
327  ,o_targetColumn=pgmSourceColumn
328  );
329  END;
330  ELSE DO;
331  %_render_dataColumn (i_sourceColumn=outputRow
332  ,i_columnType=tcgNonContribData
333  ,o_targetColumn=pgmSourceColumn
334  );
335  END;
336  RUN;
337 
338  options nocenter;
339  title;footnote;
340 
341  title j=c "&g_nls_reportAuton_005.: &i_macroName";
342  title2 "&g_nls_reportAuton_016.: &CoveragePCT.";
343 
344  %if (&o_html.) %then %do;
345  ods html4 file="&o_outputPath./&o_outputFile..html"
346  (TITLE="&l_title.")
347  headtext='<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />'
348  metatext="http-equiv=""Content-Style-Type"" content=""text/css"" /><meta http-equiv=""Content-Language"" content=""&i_language."" /"
349  style=styles.SASUnit stylesheet=(URL="css/SAS_SASUnit.css")
350  encoding="&g_rep_encoding.";
351  %end;
352 
353  proc report data=work._tcg_legend nowd
354  style(report)=blindTable [borderwidth=0]
355  style(column)=blindData
356  style(lines) =blindData
357  style(header)=blindHeader;
358  columns dummy Text;
359 
360  compute before _page_;
361  line @1 "Color Legend:";
362  endcomp;
363  run;
364 
365  title;
366  %_reportFooter(o_html=&o_html.);
367 
368  *** Render separation line between legend and source code ***;
369  %if (&o_html.) %then %do;
370  ods html4 text="^{RAW <hr size=""1"">}";
371  %end;
372 
373  proc print data=work._tcg_report noobs
374  style(report)=blindTable [borderwidth=0]
375  style(column)=blindFixedFontData
376  style(header)=blindHeader;
377 
378  var RowNumberOut pgmSourceColumn;
379  run;
380 
381  %if (&o_html.) %then %do;
382  %_closeHtmlPage;
383  %end;
384 
385  options center;
386  title;footnote;
387  %_macExit:
388 %mend _reporttcghtml;