1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 #include "CovHTMLCodePrinter.hxx"
17 #include "cover_tools.hxx"
18 #include "CoverModule.hxx"
19 
20 namespace coverage
21 {
22 
handleDefault(const std::wstring & seq)23 void CovHTMLCodePrinter::handleDefault(const std::wstring & seq)
24 {
25     addNewLineHeader();
26     count(seq);
27     out << L"<span class=\'scilabdefault\'>"
28         << replaceByEntities(seq)
29         << L"</span>";
30 }
31 
handleOperator(const std::wstring & seq)32 void CovHTMLCodePrinter::handleOperator(const std::wstring & seq)
33 {
34     addNewLineHeader();
35     count(seq);
36     out << L"<span class=\'scilaboperator\'>"
37         << replaceByEntities(seq)
38         << L"</span>";
39 }
40 
handleOpenClose(const std::wstring & seq)41 void CovHTMLCodePrinter::handleOpenClose(const std::wstring & seq)
42 {
43     addNewLineHeader();
44     count(seq);
45     out << L"<span class=\'scilabopenclose\'>"
46         << seq
47         << L"</span>";
48 }
49 
handleFunctionKwds(const std::wstring & seq)50 void CovHTMLCodePrinter::handleFunctionKwds(const std::wstring & seq)
51 {
52     addNewLineHeader();
53     count(seq);
54     if (seq == L"function" && isInsideKnownFunction())
55     {
56         const std::wstring did = L"d" + std::to_wstring(fnId);
57         const std::wstring fid = L"f" + std::to_wstring(fnId++);
58 
59         out << L"<a class=\'linkStats\' onmouseover=\"show(\'" << did << L"\',\'" << fid << L"\')\" onmouseout=\"hide(\'" << did << L"\')\">"
60             << L"<div id=\'" << did << L"\' class=\'functionStats\'>";
61 
62         getFunctionStats(out, getCurrentMacro(), getCurrentResult());
63 
64         out << L"</div>"
65             << L"<span id=\'" << fid << L"' class=\'scilabfkeyword\'>function</span></a>";
66     }
67     else
68     {
69         out << L"<span class=\'scilabfkeyword\'>"
70             << seq
71             << L"</span>";
72     }
73 }
74 
handleStructureKwds(const std::wstring & seq)75 void CovHTMLCodePrinter::handleStructureKwds(const std::wstring & seq)
76 {
77     addNewLineHeader();
78     count(seq);
79     out << L"<span class=\'scilabskeyword\'>"
80         << seq
81         << L"</span>";
82 }
83 
handleControlKwds(const std::wstring & seq)84 void CovHTMLCodePrinter::handleControlKwds(const std::wstring & seq)
85 {
86     addNewLineHeader();
87     count(seq);
88     out << L"<span class=\'scilabckeyword\'>"
89         << seq
90         << L"</span>";
91 }
92 
handleConstants(const std::wstring & seq)93 void CovHTMLCodePrinter::handleConstants(const std::wstring & seq)
94 {
95     addNewLineHeader();
96     count(seq);
97     out << L"<span class=\'scilabconstants\'>"
98         << seq
99         << L"</span>";
100 }
101 
handleCommands(const std::wstring & seq)102 void CovHTMLCodePrinter::handleCommands(const std::wstring & seq)
103 {
104     addNewLineHeader();
105     count(seq);
106     out << L"<span class=\'scilabcommand\'>"
107         << seq
108         << L"</span>";
109 }
110 
handleMacros(const std::wstring & seq)111 void CovHTMLCodePrinter::handleMacros(const std::wstring & seq)
112 {
113     addNewLineHeader();
114     count(seq);
115     out << L"<span class=\'scilabmacro\'>"
116         << seq
117         << L"</span>";
118 }
119 
handleFunctionName(const std::wstring & seq)120 void CovHTMLCodePrinter::handleFunctionName(const std::wstring & seq)
121 {
122     addNewLineHeader();
123     count(seq);
124     out << L"<span class=\'scilabfunctionid\'>"
125         << seq
126         << L"</span>";
127 }
128 
handleFunctionNameDec(const std::wstring & seq)129 void CovHTMLCodePrinter::handleFunctionNameDec(const std::wstring & seq)
130 {
131     addNewLineHeader();
132     count(seq);
133     out << L"<span class=\'scilabfunctionid\'>"
134         << seq
135         << L"</span>";
136 }
137 
handleName(const std::wstring & seq)138 void CovHTMLCodePrinter::handleName(const std::wstring & seq)
139 {
140     addNewLineHeader();
141     count(seq);
142     if (locals.find(seq) != locals.end())
143     {
144         out << L"<span class=\'scilabinputoutputargs\'>"
145             << seq
146             << L"</span>";
147     }
148     else
149     {
150         out << L"<span class=\'scilabid\'>"
151             << seq
152             << L"</span>";
153     }
154 }
155 
handleInOutArgsDec(const std::wstring & seq)156 void CovHTMLCodePrinter::handleInOutArgsDec(const std::wstring & seq)
157 {
158     locals.emplace(seq);
159     addNewLineHeader();
160     count(seq);
161     out << L"<span class=\'scilabinputoutputargs\'>"
162         << seq
163         << L"</span>";
164 }
165 
handleInOutArgs(const std::wstring & seq)166 void CovHTMLCodePrinter::handleInOutArgs(const std::wstring & seq)
167 {
168     addNewLineHeader();
169     count(seq);
170     out << L"<span class=\'scilabinputoutputargs\'>"
171         << seq
172         << L"</span>";
173 }
174 
handleNumber(const std::wstring & seq)175 void CovHTMLCodePrinter::handleNumber(const std::wstring & seq)
176 {
177     addNewLineHeader();
178     count(seq);
179     out << L"<span class=\'scilabnumber\'>"
180         << seq
181         << L"</span>";
182 }
183 
handleSpecial(const std::wstring & seq)184 void CovHTMLCodePrinter::handleSpecial(const std::wstring & seq)
185 {
186     addNewLineHeader();
187     count(seq);
188     out << L"<span class=\'scilabspecial\'>"
189         << seq
190         << L"</span>";
191 }
192 
handleString(const std::wstring & seq)193 void CovHTMLCodePrinter::handleString(const std::wstring & seq)
194 {
195     addNewLineHeader();
196     out << L"<span class=\'scilabstring\'>";
197     for (const auto c : seq)
198     {
199         if (c == L'\'')
200         {
201             out << L"&#0039;&#0039;";
202             counter += 2;
203         }
204         else if (c == L'\"')
205         {
206             out << L"&#0034;&#0034;";
207             counter += 2;
208         }
209         else
210         {
211             if (c == L'<')
212             {
213                 out << L"&#0060;";
214             }
215             else if (c == L'>')
216             {
217                 out << L"&#0062;";
218             }
219             else if (c == L'&')
220             {
221                 out << L"&#0038;";
222             }
223             else
224             {
225                 out << c;
226             }
227             ++counter;
228         }
229     }
230     out << L"</span>";
231 }
232 
handleNothing(const std::wstring & seq)233 void CovHTMLCodePrinter::handleNothing(const std::wstring & seq)
234 {
235     addNewLineHeader();
236     count(seq);
237     out << replaceByEntities(seq);
238 }
239 
handleField(const std::wstring & seq)240 void CovHTMLCodePrinter::handleField(const std::wstring & seq)
241 {
242     addNewLineHeader();
243     count(seq);
244     out << L"<span class=\'scilabfield\'>"
245         << seq
246         << L"</span>";
247 }
248 
handleComment(const std::wstring & seq)249 void CovHTMLCodePrinter::handleComment(const std::wstring & seq)
250 {
251     addNewLineHeader();
252     count(seq);
253     out << L"<span class=\'scilabcomment\'>"
254         << replaceByEntities(seq)
255         << L"</span>";
256 }
257 
handleNewLine()258 void CovHTMLCodePrinter::handleNewLine()
259 {
260     bool printed = false;
261     if (lineCount)
262     {
263         if (last && isInsideKnownFunction())
264         {
265             if (last->isCommentExp())
266             {
267                 out << L"</pre></td><td></td>\n";
268             }
269             else
270             {
271                 if (getCurrentResult().getNanoTime())
272                 {
273                     if (last->isFunctionDec())
274                     {
275                         out << L"</pre></td><td style=\'background-color: rgba(83, 232, 37, 1);\' class=\'time\'>" << getCurrentResult().getStringTime() << L"</td>\n";
276                     }
277                     else
278                     {
279                         unsigned int R = 255 - 83;
280                         unsigned int G = 255 - 232;
281                         unsigned int B = 255 - 37;
282                         const double ratio = getCurrentResult().getTimeRatio(last);
283                         R = 255 - (unsigned int)std::round((double)R * ratio);
284                         G = 255 - (unsigned int)std::round((double)G * ratio);
285                         B = 255 - (unsigned int)std::round((double)B * ratio);
286                         const std::wstring color = L"rgba(" + std::to_wstring(R) + L"," + std::to_wstring(G) + L"," + std::to_wstring(B) + L",1);";
287                         const uint64_t time = getCurrentResult().getNanoTime(last);
288                         if (time)
289                         {
290                             out << L"</pre></td><td style=\'background-color: " << color << L"\' class=\'time\'>" << getCurrentResult().getStringTime(time) << L"</td>\n";
291                         }
292                         else
293                         {
294                             out << L"</pre></td><td></td>\n";
295                         }
296                     }
297                 }
298                 else
299                 {
300                     out << L"</pre></td><td></td>\n";
301                 }
302             }
303 
304             if (last->isIfExp())
305             {
306                 const std::vector<uint64_t> stats = getCurrentResult().getBranchesStats(last);
307                 if (!stats.empty())
308                 {
309                     const uint64_t total = stats[0] + stats[1];
310                     double thenbr = stats[0];
311                     double elsebr = stats[1];
312                     if (total)
313                     {
314                         thenbr = std::round(100 * thenbr / (double)total);
315                         elsebr = 100 - thenbr;
316                     }
317                     const std::wstring thencls = stats[0] == 0 ? L"null_stats" : L"stats";
318                     const std::wstring elsecls = stats[1] == 0 ? L"null_stats" : L"stats";
319 
320                     out << L"<td class=\'" << thencls << L"\'>" << thenbr << L"%</td><td class=\'" << elsecls << L"\'>" << elsebr << L"%</td>\n</tr>\n";
321                     printed = true;
322                 }
323             }
324             else if (last->isForExp() || last->isWhileExp())
325             {
326                 uint64_t count;
327                 if (getCurrentResult().getLoopStats(last, count))
328                 {
329                     std::wstring loopcls = count == 0 ? L"null_stats" : L"stats";
330                     out << L"<td class=\'" << loopcls << L"\' colspan=\'2\'>&#xD7;" << count << L"</td>\n</tr>\n";
331                     printed = true;
332                 }
333             }
334 
335             if (!printed)
336             {
337                 out << L"<td></td><td></td></tr>\n";
338                 printed = true;
339             }
340         }
341         if (!printed)
342         {
343             out << L"</pre></td><td></td><td></td><td></td></tr>\n";
344         }
345         out.flush();
346     }
347 
348     last = nullptr;
349     isNewLine = true;
350 }
351 
handleExpStart(const ast::Exp * e)352 void CovHTMLCodePrinter::handleExpStart(const ast::Exp * e)
353 {
354     current = e;
355     if (!last && !e->isSeqExp())
356     {
357         last = e;
358     }
359     if (e->isFunctionDec())
360     {
361         const std::wstring & name = static_cast<const ast::FunctionDec *>(e)->getSymbol().getName();
362         const Location & loc = static_cast<const ast::FunctionDec *>(e)->getBody().getLocation();
363         MacroLoc ml(name, loc);
364         auto i = results.find(ml);
365         if (i != results.end())
366         {
367             fnStack.emplace(ml, &i->second);
368         }
369         else
370         {
371             fnStack.emplace(ml, nullptr);
372         }
373     }
374 }
375 
handleExpEnd(const ast::Exp * e)376 void CovHTMLCodePrinter::handleExpEnd(const ast::Exp * e)
377 {
378     if (e->isFunctionDec())
379     {
380         fnStack.pop();
381     }
382 }
383 
addNewLineHeader()384 void CovHTMLCodePrinter::addNewLineHeader()
385 {
386     if (isNewLine)
387     {
388         const std::size_t indent = getIndentSize();
389         out << L"<tr class=\'";
390         if (current && isInsideKnownFunction())
391         {
392             if (current->isCommentExp())
393             {
394                 out << L"none";
395             }
396             else if (current->isFunctionDec())
397             {
398                 out << (getCurrentResult().getCounter() ? L"cover" : L"uncover");
399             }
400             else if (current->isCaseExp())
401             {
402                 out << (getCurrentResult().isCovered(static_cast<const ast::CaseExp *>(current)->getTest()) ? L"cover" : L"uncover");
403             }
404             else
405             {
406                 out << (getCurrentResult().isCovered(current) ? L"cover" : L"uncover");
407             }
408         }
409         else
410         {
411             out << L"none";
412         }
413         ++lineCount;
414         out <<  L"\' id=\'L" << lineCount << L"\'>\n"
415             << L"<td class=\'num\'><a href=\'#L" << lineCount << L"\'>" << lineCount << L"</a></td>\n"
416             << L"<td class=\'src\'><pre>" << std::wstring(indent, L' ');
417 
418         counter = indent;
419         isNewLine = false;
420     }
421     current = nullptr;
422 }
423 
getFunctionStats(std::wostringstream & out,const MacroLoc & ml,const CoverResult & result)424 void CovHTMLCodePrinter::getFunctionStats(std::wostringstream & out, const MacroLoc & ml, const CoverResult & result)
425 {
426     const CoverMacroInfo & info = result.getInfo();
427     const std::size_t instrs = info.instrsCount;
428     const unsigned int percentInstrs = result.getCovInstrsPercent();
429     const std::size_t branches = info.branchesCount;
430     const unsigned int percentBranches = result.getCovBranchesPercent();
431 
432     out << L"<table class=\'functionInfo\'>"
433         << L"<tr><td colspan=\'5\'>Macro <span class=\'scilabfunctionid\'>" << ml.name << L"</span>:</td></tr>"
434         << L"<tr><td>&nbsp;&mdash;&nbsp;called:</td><td>" << result.getCounter() << L" time" << tools::getPlural(result.getCounter()) << L"</td><td>&nbsp;&mdash;&nbsp;spent time:</td><td>" << result.getStringTime() << L"</td></tr>"
435         << L"<tr><td>&nbsp;&mdash;&nbsp;instrs:</td><td>" << instrs << L"</td><td>&nbsp;&mdash;&nbsp;covered:</td><td>" << percentInstrs << L"%</td><td>";
436 
437     getDivPercent(out, percentInstrs);
438 
439     out << L"</td></tr>"
440         << L"<tr><td>&nbsp;&mdash;&nbsp;branches:</td><td>" << branches << L"</td><td>&nbsp;&mdash;&nbsp;covered:</td><td>" << percentBranches << L"%</td><td>";
441 
442     getDivPercent(out, percentBranches);
443 
444     out << L"</td></tr>"
445         << L"</table>";
446 }
447 
getDivPercent(std::wostringstream & out,const unsigned int percent)448 void CovHTMLCodePrinter::getDivPercent(std::wostringstream & out, const unsigned int percent)
449 {
450     if (percent == 0)
451     {
452         out << L"<div class=\'fullPercent\'><div class=\'filledPercent2\' style=\'width:" << (100 - percent) << L"%;\'></div></div>";
453     }
454     else if (percent == 100)
455     {
456         out << L"<div class=\'fullPercent\'><div class=\'filledPercent1\' style=\'width:" << percent << L"%;\'></div></div>";
457     }
458     else
459     {
460         out << L"<div class=\'fullPercent\'><div class=\'filledPercent1\' style=\'width:" << percent << L"%;\'></div><div class=\'filledPercent2\' style=\'width:" << (100 - percent) << L"%;\'></div></div>";
461     }
462 }
463 
getOrderButton(const unsigned int tableid,const unsigned int id,const unsigned int col,const bool enabled)464 std::wstring CovHTMLCodePrinter::getOrderButton(const unsigned int tableid, const unsigned int id, const unsigned int col, const bool enabled)
465 {
466     std::wostringstream wos;
467     const std::wstring str = enabled ?  L"buttonOrderEnable" : L"buttonOrderDisable";
468     wos << L"<span class=\'groupButton\'>"
469         << L"<a id=\'but_1_" << id << L"\' class=\'" << str << L"\' onclick=\"order(\'table" << tableid << L"\'," << col << L",true,\'but_1_" << id << L"\')\">&#x25B4;</a>"
470         << L"<a id=\'but_2_" << id << L"\' class=\'buttonOrderDisable\' onclick=\"order(\'table" << tableid << "\'," << col << L",false,\'but_2_" << id << L"\')\">&#x25BE;</a>"
471         << L"</span>";
472 
473     return wos.str();
474 }
475 
replaceByEntities(const std::wstring & seq)476 std::wstring CovHTMLCodePrinter::replaceByEntities(const std::wstring & seq)
477 {
478     std::vector<wchar_t> buf;
479     // if seq contains 100 chars and there are 8 special chars
480     // then it will contain after the loop 148 chars.
481     // So we should avoid the buf resizment.
482     buf.reserve(1.5 * seq.length());
483     for (auto c : seq)
484     {
485         if (c == L'<')
486         {
487             pushEntity(buf, L"&#0060;", 7);
488         }
489         else if (c == L'>')
490         {
491             pushEntity(buf, L"&#0062;", 7);
492         }
493         else if (c == L'\'')
494         {
495             pushEntity(buf, L"&#0039;", 7);
496         }
497         else if (c == L'\"')
498         {
499             pushEntity(buf, L"&#0034;", 7);
500         }
501         else if (c == L'&')
502         {
503             pushEntity(buf, L"&#0038;", 7);
504         }
505         else
506         {
507             buf.push_back(c);
508         }
509     }
510 
511     return std::wstring(buf.begin(), buf.end());
512 }
513 }
514