ivprogAssessment.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { Decimal } from 'decimal.js';
  2. import line_i18n from 'line-i18n'
  3. import { IVProgProcessor } from "./../processor/ivprogProcessor";
  4. import { InputTest } from "./../util/inputTest";
  5. import { OutputTest } from "./../util/outputTest";
  6. import { DOMConsole} from "./../io/domConsole";
  7. import * as LocalizedStringsService from "../services/localizedStringsService";
  8. import { Config } from "../util/config";
  9. const LocalizedStrings = LocalizedStringsService.getInstance();
  10. const list_joiner = LocalizedStrings.getUI("text_join_assessment_outputs");
  11. const StringTypes = line_i18n.StringTypes;
  12. export class IVProgAssessment {
  13. constructor (ast_code, testCases, domConsole) {
  14. this.ast_code = ast_code;
  15. this.testCases = testCases;
  16. this.domConsole = domConsole;
  17. }
  18. runTest () {
  19. const outerRef = this;
  20. try {
  21. // loop test cases and show messages through domconsole
  22. const partialTests = this.testCases.map( (t, name) => {
  23. return outerRef.partialEvaluateTestCase(new IVProgProcessor(outerRef.ast_code), t.input, t.output, name);
  24. });
  25. const testResult = partialTests.reduce((acc, curr) => acc.then(curr), Promise.resolve(0));
  26. return testResult.then(function (total) {
  27. const grade = total / outerRef.testCases.length;
  28. const channel = grade == 1 ? DOMConsole.INFO : DOMConsole.ERR;
  29. outerRef.writeToConsole(channel, StringTypes.MESSAGE, "test_suite_grade", (grade * 100).toFixed(2));
  30. return Promise.resolve(grade)
  31. }).catch(err => {
  32. outerRef.domConsole.err("Erro inesperado durante o cálculo da nota.");// try and show error messages through domconsole
  33. outerRef.domConsole.err(err.message);
  34. return Promise.resolve(0);
  35. });
  36. } catch (error) {
  37. outerRef.domConsole.err("Erro inesperado durante a execução do programa");// try and show error messages through domconsole
  38. outerRef.domConsole.err(error.message);
  39. return Promise.resolve(0);
  40. }
  41. }
  42. evaluateTestCase (prog, inputList, expectedOutputs, name, accumulator) {
  43. const outerThis = this;
  44. const input = new InputTest(inputList);
  45. const output = new OutputTest();
  46. prog.registerInput(input);
  47. prog.registerOutput(output);
  48. const startTime = Date.now()
  49. return prog.interpretAST().then( _ => {
  50. const millis = Date.now() - startTime;
  51. if (input.inputList.length !== input.index) {
  52. outerThis.showErrorMessage('test_case_few_reads', name+1);
  53. outerThis.showInfoMessage('test_case_duration', millis);
  54. return Promise.resolve(accumulator);
  55. } else if (output.list.length != expectedOutputs.length) {
  56. outerThis.showErrorMessage('test_case_failed', name + 1, inputList.join(list_joiner),
  57. expectedOutputs.join(list_joiner), output.list.join(list_joiner));
  58. outerThis.showInfoMessage('test_case_duration', millis);
  59. // must check for a partial match of the generated output
  60. const numMatchedOutputs = output.list.reduce((acc, actualOutput, index) => {
  61. if(outerThis.checkOutputValues(actualOutput, expectedOutputs[index])) {
  62. return acc + 1;
  63. } else {
  64. return acc;
  65. }
  66. }, 0);
  67. const maxLength = Math.max(expectedOutputs.length, output.list.length);
  68. return Promise.resolve(accumulator + (numMatchedOutputs/maxLength));
  69. } else {
  70. const isOk = outerThis.checkOutputLists(output.list, expectedOutputs);
  71. if(!isOk) {
  72. outerThis.showErrorMessage('test_case_failed', name + 1, inputList.join(list_joiner),
  73. expectedOutputs.join(list_joiner), output.list.join(list_joiner));
  74. outerThis.showInfoMessage('test_case_duration', millis);
  75. return Promise.resolve(accumulator);
  76. } else {
  77. outerThis.showInfoMessage('test_case_success', name + 1);
  78. outerThis.showInfoMessage('test_case_duration', millis);
  79. return Promise.resolve(accumulator + 1);
  80. }
  81. }
  82. }).catch( error => {
  83. outerThis.showErrorMessage('test_case_failed_exception', name + 1, error.message);
  84. return Promise.resolve(accumulator);
  85. });
  86. }
  87. partialEvaluateTestCase (prog, inputList, expectedOutputs, name) {
  88. return this.evaluateTestCase.bind(this, prog, inputList, expectedOutputs, name);
  89. }
  90. checkOutputLists (actualOutputs, expectedOutputs) {
  91. for (let i = 0; i < actualOutputs.length; i++) {
  92. const outValue = actualOutputs[i];
  93. const expectedValue = expectedOutputs[i];
  94. if(!this.checkOutputValues(outValue, expectedValue)) {
  95. return false;
  96. }
  97. }
  98. return true;
  99. }
  100. checkOutputValues (actualValue, expectedValue) {
  101. let castNumberA = parseFloat(actualValue);
  102. if(!Number.isNaN(castNumberA)) {
  103. let castNumberB = parseFloat(expectedValue);
  104. if(Number.isNaN(castNumberB)) {
  105. return false;
  106. }
  107. castNumberA = new Decimal(castNumberA);
  108. castNumberB = new Decimal(castNumberB);
  109. const decimalPlaces = Math.min(castNumberB.dp(), Config.decimalPlaces);
  110. castNumberA = new Decimal(castNumberA.toFixed(decimalPlaces, Decimal.ROUND_FLOOR));
  111. castNumberB = new Decimal(castNumberB.toFixed(decimalPlaces, Decimal.ROUND_FLOOR));
  112. const aEqualsB = castNumberA.eq(castNumberB);
  113. if (!aEqualsB) {
  114. return false;
  115. }
  116. } else if(actualValue != expectedValue) {
  117. return false;
  118. }
  119. return true;
  120. }
  121. showErrorMessage (errorID, ...args) {
  122. this.domConsole.err(LocalizedStrings.getError(errorID, args));
  123. }
  124. showInfoMessage (msgID, ...args) {
  125. this.domConsole.info(LocalizedStrings.getMessage(msgID, args));
  126. }
  127. writeToConsole (channel, msgType, msgID, ...args) {
  128. let msg = LocalizedStrings.getString(msgID, msgType);
  129. msg = LocalizedStrings.processString(msg, args);
  130. switch(channel) {
  131. case DOMConsole.ERR: {
  132. this.domConsole.err(msg);
  133. break;
  134. }
  135. case DOMConsole.INFO: {
  136. this.domConsole.info(msg);
  137. break;
  138. }
  139. case DOMConsole.USER: {
  140. this.domConsole.write(msg);
  141. break;
  142. }
  143. }
  144. }
  145. }