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"''";
202 counter += 2;
203 }
204 else if (c == L'\"')
205 {
206 out << L"""";
207 counter += 2;
208 }
209 else
210 {
211 if (c == L'<')
212 {
213 out << L"<";
214 }
215 else if (c == L'>')
216 {
217 out << L">";
218 }
219 else if (c == L'&')
220 {
221 out << L"&";
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\'>×" << 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> — called:</td><td>" << result.getCounter() << L" time" << tools::getPlural(result.getCounter()) << L"</td><td> — spent time:</td><td>" << result.getStringTime() << L"</td></tr>"
435 << L"<tr><td> — instrs:</td><td>" << instrs << L"</td><td> — covered:</td><td>" << percentInstrs << L"%</td><td>";
436
437 getDivPercent(out, percentInstrs);
438
439 out << L"</td></tr>"
440 << L"<tr><td> — branches:</td><td>" << branches << L"</td><td> — 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"\')\">▴</a>"
470 << L"<a id=\'but_2_" << id << L"\' class=\'buttonOrderDisable\' onclick=\"order(\'table" << tableid << "\'," << col << L",false,\'but_2_" << id << L"\')\">▾</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"<", 7);
488 }
489 else if (c == L'>')
490 {
491 pushEntity(buf, L">", 7);
492 }
493 else if (c == L'\'')
494 {
495 pushEntity(buf, L"'", 7);
496 }
497 else if (c == L'\"')
498 {
499 pushEntity(buf, L""", 7);
500 }
501 else if (c == L'&')
502 {
503 pushEntity(buf, L"&", 7);
504 }
505 else
506 {
507 buf.push_back(c);
508 }
509 }
510
511 return std::wstring(buf.begin(), buf.end());
512 }
513 }
514