assessment_result.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import StringDiff from "./../../util/string_diff";
  2. import { LocalizedStrings } from "./../../services/localizedStringsService";
  3. export class OutputAssessmentResult {
  4. static get PAGE_TEMPLATE () {
  5. return `<!DOCTYPE html>
  6. <html>
  7. <head>
  8. <meta http-equiv='content-type' content='text/html; charset=UTF-8'>
  9. <link rel='stylesheet' href='css/ivprog-assessment.css' type='text/css'/>
  10. </head>
  11. <body>
  12. :assessment-result:
  13. </body>
  14. </html>`;
  15. }
  16. static get DETAIL_TEMPLATE () {
  17. return `<div class='details-body'>
  18. <div class='details-header'>
  19. <h2>:test-name:</h2>
  20. <p>:time-label:: <span>:time:ms</span></p>
  21. <p>:grade-label:: <span>:grade:%</span></p>
  22. </div>
  23. <div>
  24. <h3>:input-label:</h3>
  25. <ul>
  26. <li>:input-list:</li>
  27. </ul>
  28. </div>
  29. <div>
  30. <h3>:output-label:</h3>
  31. :output-result:
  32. </div>
  33. </div>`;
  34. }
  35. static get ASSISTANT_TEMPLATE () {
  36. return `<div class='details-body'>
  37. <div class='assistant-div-left'>
  38. <h1>Desempenho</h1>
  39. <p style='padding-left:0.5rem;'>:performance-text:</p>
  40. </div>
  41. <div class='assistant-div-right'>
  42. <h1>Sugestões</h1>
  43. <p style='padding-left:0.5rem;'>:suggestion-text:</p>
  44. </div>
  45. </div>`;
  46. }
  47. static get OUPUT_TABLE_TEMPLATE () {
  48. return `<div class='detaisl-div-table'>
  49. <table class='assessment-output-table'>
  50. <tr>
  51. <th>:expected-label:</th>
  52. <th>:generated-label:</th>
  53. <th>:result-label:</th>
  54. </tr>
  55. :results:
  56. </table>
  57. </div>`;
  58. }
  59. static get OUTPUT_TEMPLATE () {
  60. return `<tr><td class=':class-expected:'>$0</td>
  61. <td class=':class-generated:'>$1</td>
  62. <td class=':class-result:'>$2</td></tr>`;
  63. }
  64. static get EMPTY_OUTPUT_TEMPLATE () {
  65. return `<div class='assessment-popup'><img class='assessment-empty-output' src='img/empty.svg'>
  66. <span class='assessment-popuptext'>$0</span></div>`;
  67. }
  68. static get FAILED_TEMPLATE () {
  69. return `<p class='assessment-failed-execution'><span class='assessment-failed-case'>✗</span>$0</p>`;
  70. }
  71. static get INPUT_INFO_TEMPLATE () {
  72. return `<span class='$0'>$1</span>`;
  73. }
  74. // Status code - it is not grade related!
  75. // 0 - Succesful execution
  76. // 1 - failed execution
  77. constructor (
  78. name,
  79. status,
  80. inputs,
  81. result,
  82. store,
  83. time,
  84. tags,
  85. error_msg = "",
  86. error_id = ""
  87. ) {
  88. this.name = name;
  89. this.status = status;
  90. this.inputs = inputs;
  91. this.results = result;
  92. this.store = store;
  93. this.time = time;
  94. this.error_msg = error_msg;
  95. this.tags = tags;
  96. this.error_id = error_id;
  97. }
  98. get grade () {
  99. if (this.results == null) {
  100. return 0;
  101. }
  102. return (
  103. this.results.reduce((prev, val) => prev + val.grade, 0) /
  104. this.results.length
  105. );
  106. }
  107. prepareResults () {
  108. let template = OutputAssessmentResult.DETAIL_TEMPLATE;
  109. const grade = (this.grade * 100).toFixed(2);
  110. const time = this.time || "-";
  111. template = template.replace(
  112. ":test-name:",
  113. LocalizedStrings.getUI("assessment-detail-title", [this.name + 1])
  114. );
  115. template = template.replace(
  116. ":time-label:",
  117. LocalizedStrings.getUI("assessment-detail-time-label")
  118. );
  119. template = template.replace(":time:", time);
  120. template = template.replace(
  121. ":grade-label:",
  122. LocalizedStrings.getUI("assessment-detail-grade-label")
  123. );
  124. template = template.replace(":grade:", grade);
  125. const input_spans = this.prepareInputList(this.inputs);
  126. template = template.replace(
  127. ":input-label:",
  128. LocalizedStrings.getUI("assessment-detail-input-label")
  129. );
  130. template = template.replace(":input-list:", input_spans);
  131. template = template.replace(
  132. ":output-label:",
  133. LocalizedStrings.getUI("assessment-detail-output-label")
  134. );
  135. if (this.status == 0) {
  136. const output_rows = this.results.map((result) => {
  137. if (result.type == "string") {
  138. return this.formatString(result);
  139. } else if (result.type == "number") {
  140. return this.formatNumber(result);
  141. } else {
  142. return this.formatBool(result);
  143. }
  144. }, this);
  145. template = template.replace(
  146. ":output-result:",
  147. this.prepareOutputTable(output_rows)
  148. );
  149. } else {
  150. let failed_text = OutputAssessmentResult.FAILED_TEMPLATE;
  151. failed_text = failed_text.replace("$0", this.error_msg);
  152. template = template.replace(":output-result:", failed_text);
  153. }
  154. return template;
  155. }
  156. prepareInputList (input_list) {
  157. const list = input_list.map((input) => {
  158. let template = OutputAssessmentResult.INPUT_INFO_TEMPLATE;
  159. template = template.replace("$1", input.value);
  160. if (input.read) {
  161. template = template.replace("$0", "assessment-input-read");
  162. } else {
  163. template = template.replace("$0", "assessment-input-unread");
  164. }
  165. return template;
  166. }, this);
  167. return list.join(LocalizedStrings.getUI("text_join_assessment_outputs"));
  168. }
  169. prepareOutputTable (output_rows) {
  170. let template = OutputAssessmentResult.OUPUT_TABLE_TEMPLATE;
  171. template = template.replace(
  172. ":expected-label:",
  173. LocalizedStrings.getUI("assessment-detail-expected-label")
  174. );
  175. template = template.replace(
  176. ":generated-label:",
  177. LocalizedStrings.getUI("assessment-detail-generated-label")
  178. );
  179. template = template.replace(
  180. ":result-label:",
  181. LocalizedStrings.getUI("assessment-detail-result-label")
  182. );
  183. template = template.replace(":results:", output_rows.join(""));
  184. return template;
  185. }
  186. generateOutput () {
  187. const assessment_result = this.prepareResults();
  188. let page = OutputAssessmentResult.PAGE_TEMPLATE;
  189. page = page.replace(":assessment-result:", assessment_result);
  190. page = page.replace(/(\r|\n|\t)/gm, "").replace(/> *</g, "><");
  191. return page;
  192. }
  193. generateAssistantOutput (performanceText,suggestionText) {
  194. let template = OutputAssessmentResult.ASSISTANT_TEMPLATE;
  195. template = template.replace(":performance-text:",performanceText);
  196. template = template.replace(":suggestion-text:",suggestionText);
  197. let page = OutputAssessmentResult.PAGE_TEMPLATE;
  198. page = page.replace(":assessment-result:", template);
  199. page = page.replace(/(\r|\n|\t)/gm, "").replace(/> *</g, "><");
  200. return page;
  201. }
  202. formatNumber (result) {
  203. const result_class =
  204. result.grade == 1
  205. ? "assessment-number-result"
  206. : "assessment-number-result-failed";
  207. const template = this.formatOutput(
  208. "assessment-number-expected",
  209. "assessment-number-generated",
  210. result_class,
  211. result
  212. );
  213. return template;
  214. }
  215. formatBool (result) {
  216. const result_class =
  217. result.grade == 1
  218. ? "assessment-bool-result"
  219. : "assessment-bool-result-failed";
  220. const template = this.formatOutput(
  221. "assessment-bool-expected",
  222. "assessment-bool-generated",
  223. result_class,
  224. result
  225. );
  226. return template;
  227. }
  228. formatOutput (expected_class, generated_class, result_class, result) {
  229. let template = OutputAssessmentResult.OUTPUT_TEMPLATE;
  230. template = template.replace(":class-expected:", expected_class);
  231. template = template.replace(":class-generated:", generated_class);
  232. template = template.replace(":class-result:", result_class);
  233. let expected_tmpl = result.expected;
  234. let generated_tmpl = result.generated;
  235. if (expected_tmpl == null) {
  236. expected_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace(
  237. "$0",
  238. LocalizedStrings.getMessage("assessment-empty-expected-tooltip")
  239. );
  240. } else if (generated_tmpl == null) {
  241. generated_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace(
  242. "$0",
  243. LocalizedStrings.getMessage("assessment-empty-generated-tooltip")
  244. );
  245. }
  246. template = template.replace("$0", expected_tmpl);
  247. template = template.replace("$1", generated_tmpl);
  248. const final_result = result.grade == 1 ? "✓" : "✗";
  249. template = template.replace("$2", final_result);
  250. return template;
  251. }
  252. formatString (result) {
  253. const expected_class = "assessment-string-expected";
  254. const generated_class = "assessment-string-generated";
  255. //const result_class = 'assessment-string-result';
  256. let template = OutputAssessmentResult.OUTPUT_TEMPLATE;
  257. template = template.replace(":class-expected:", expected_class);
  258. template = template.replace(":class-generated:", generated_class);
  259. //template = template.replace(":class-result:", result_class);
  260. const g_string = result.generated || "";
  261. const e_string = result.expected || "";
  262. // console.log("generated: ", g_string,"expected: ", e_string);
  263. let g_string_tmpl = g_string;
  264. let e_string_tmpl = e_string;
  265. if (result.generated == null) {
  266. g_string_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace(
  267. "$0",
  268. LocalizedStrings.getMessage("assessment-empty-generated-tooltip")
  269. );
  270. } else if (result.expected == null) {
  271. e_string_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace(
  272. "$0",
  273. LocalizedStrings.getMessage("assessment-empty-expected-tooltip")
  274. );
  275. }
  276. template = template.replace("$0", e_string_tmpl);
  277. template = template.replace("$1", g_string_tmpl);
  278. if (result.grade == 1) {
  279. template = template.replace("$2", "✓");
  280. template = template.replace(":class-result:", "assessment-string-result");
  281. } else {
  282. const diff = StringDiff(g_string, e_string);
  283. // console.log(diff);
  284. const diff_vec = diff.map(
  285. (part) => this.getDiffStringStyle(part[1], part[0]),
  286. this
  287. );
  288. const diff_string = diff_vec.reduce((prev, actual) => prev + actual, "");
  289. template = template.replace(
  290. "$2",
  291. "<span class='assessment-failed-case'>✗</span>" + diff_string
  292. );
  293. template = template.replace(":class-result:", "assessment-string-diff");
  294. }
  295. return template;
  296. }
  297. getDiffStringStyle (text, action) {
  298. const template = "<span class='$0'>$1</span>";
  299. // Fix missing whitespace when its a single element
  300. text = text.replace(/\s/g, "&#160;");
  301. switch (action) {
  302. case StringDiff.INSERT:
  303. return template.replace("$0", "stringdiff-insert").replace("$1", text);
  304. case StringDiff.DELETE:
  305. return template.replace("$0", "stringdiff-delete").replace("$1", text);
  306. case StringDiff.EQUAL:
  307. return template.replace("$0", "stringdiff-equal").replace("$1", text);
  308. }
  309. }
  310. }