import StringDiff from "./../../util/string_diff"; import { LocalizedStrings } from "./../../services/localizedStringsService"; export class OutputAssessmentResult { static get PAGE_TEMPLATE () { return ` :assessment-result: `; } static get DETAIL_TEMPLATE () { return `

:test-name:

:time-label:: :time:ms

:grade-label:: :grade:%

:input-label:

:output-label:

:output-result:
`; } static get OUPUT_TABLE_TEMPLATE () { return `
:results:
:expected-label: :generated-label: :result-label:
`; } static get OUTPUT_TEMPLATE () { return `$0 $1 $2`; } static get EMPTY_OUTPUT_TEMPLATE () { return `
$0
`; } static get FAILED_TEMPLATE () { return `

$0

`; } static get INPUT_INFO_TEMPLATE () { return `$1`; } // Status code - it is not grade related! // 0 - Succesful execution // 1 - failed execution constructor ( name, status, inputs, result, store, time, error_msg = "", error_id ) { this.name = name; this.status = status; this.inputs = inputs; this.results = result; this.store = store; this.time = time; this.error_msg = error_msg; this.error_id = error_id; } get grade () { if (this.results == null) { return 0; } return ( this.results.reduce((prev, val) => prev + val.grade, 0) / this.results.length ); } prepareResults () { let template = OutputAssessmentResult.DETAIL_TEMPLATE; const grade = (this.grade * 100).toFixed(2); const time = this.time || "-"; template = template.replace( ":test-name:", LocalizedStrings.getUI("assessment-detail-title", [this.name + 1]) ); template = template.replace( ":time-label:", LocalizedStrings.getUI("assessment-detail-time-label") ); template = template.replace(":time:", time); template = template.replace( ":grade-label:", LocalizedStrings.getUI("assessment-detail-grade-label") ); template = template.replace(":grade:", grade); const input_spans = this.prepareInputList(this.inputs); template = template.replace( ":input-label:", LocalizedStrings.getUI("assessment-detail-input-label") ); template = template.replace(":input-list:", input_spans); template = template.replace( ":output-label:", LocalizedStrings.getUI("assessment-detail-output-label") ); if (this.status == 0) { const output_rows = this.results.map((result) => { if (result.type == "string") { return this.formatString(result); } else if (result.type == "number") { return this.formatNumber(result); } else { return this.formatBool(result); } }, this); template = template.replace( ":output-result:", this.prepareOutputTable(output_rows) ); } else { let failed_text = OutputAssessmentResult.FAILED_TEMPLATE; failed_text = failed_text.replace("$0", this.error_msg); template = template.replace(":output-result:", failed_text); } return template; } prepareInputList (input_list) { const list = input_list.map((input) => { let template = OutputAssessmentResult.INPUT_INFO_TEMPLATE; template = template.replace("$1", input.value); if (input.read) { template = template.replace("$0", "assessment-input-read"); } else { template = template.replace("$0", "assessment-input-unread"); } return template; }, this); return list.join(LocalizedStrings.getUI("text_join_assessment_outputs")); } prepareOutputTable (output_rows) { let template = OutputAssessmentResult.OUPUT_TABLE_TEMPLATE; template = template.replace( ":expected-label:", LocalizedStrings.getUI("assessment-detail-expected-label") ); template = template.replace( ":generated-label:", LocalizedStrings.getUI("assessment-detail-generated-label") ); template = template.replace( ":result-label:", LocalizedStrings.getUI("assessment-detail-result-label") ); template = template.replace(":results:", output_rows.join("")); return template; } generateOutput () { const assessment_result = this.prepareResults(); let page = OutputAssessmentResult.PAGE_TEMPLATE; page = page.replace(":assessment-result:", assessment_result); page = page.replace(/(\r|\n|\t)/gm, "").replace(/> *<"); return page; } formatNumber (result) { const result_class = result.grade == 1 ? "assessment-number-result" : "assessment-number-result-failed"; const template = this.formatOutput( "assessment-number-expected", "assessment-number-generated", result_class, result ); return template; } formatBool (result) { const result_class = result.grade == 1 ? "assessment-bool-result" : "assessment-bool-result-failed"; const template = this.formatOutput( "assessment-bool-expected", "assessment-bool-generated", result_class, result ); return template; } formatOutput (expected_class, generated_class, result_class, result) { let template = OutputAssessmentResult.OUTPUT_TEMPLATE; template = template.replace(":class-expected:", expected_class); template = template.replace(":class-generated:", generated_class); template = template.replace(":class-result:", result_class); let expected_tmpl = result.expected; let generated_tmpl = result.generated; if (expected_tmpl == null) { expected_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace( "$0", LocalizedStrings.getMessage("assessment-empty-expected-tooltip") ); } else if (generated_tmpl == null) { generated_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace( "$0", LocalizedStrings.getMessage("assessment-empty-generated-tooltip") ); } template = template.replace("$0", expected_tmpl); template = template.replace("$1", generated_tmpl); const final_result = result.grade == 1 ? "✓" : "✗"; template = template.replace("$2", final_result); return template; } formatString (result) { const expected_class = "assessment-string-expected"; const generated_class = "assessment-string-generated"; //const result_class = 'assessment-string-result'; let template = OutputAssessmentResult.OUTPUT_TEMPLATE; template = template.replace(":class-expected:", expected_class); template = template.replace(":class-generated:", generated_class); //template = template.replace(":class-result:", result_class); const g_string = result.generated || ""; const e_string = result.expected || ""; // console.log("generated: ", g_string,"expected: ", e_string); let g_string_tmpl = g_string; let e_string_tmpl = e_string; if (result.generated == null) { g_string_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace( "$0", LocalizedStrings.getMessage("assessment-empty-generated-tooltip") ); } else if (result.expected == null) { e_string_tmpl = OutputAssessmentResult.EMPTY_OUTPUT_TEMPLATE.replace( "$0", LocalizedStrings.getMessage("assessment-empty-expected-tooltip") ); } template = template.replace("$0", e_string_tmpl); template = template.replace("$1", g_string_tmpl); if (result.grade == 1) { template = template.replace("$2", "✓"); template = template.replace(":class-result:", "assessment-string-result"); } else { const diff = StringDiff(g_string, e_string); // console.log(diff); const diff_vec = diff.map( (part) => this.getDiffStringStyle(part[1], part[0]), this ); const diff_string = diff_vec.reduce((prev, actual) => prev + actual, ""); template = template.replace( "$2", "" + diff_string ); template = template.replace(":class-result:", "assessment-string-diff"); } return template; } getDiffStringStyle (text, action) { const template = "$1"; // Fix missing whitespace when its a single element text = text.replace(/\s/g, " "); switch (action) { case StringDiff.INSERT: return template.replace("$0", "stringdiff-insert").replace("$1", text); case StringDiff.DELETE: return template.replace("$0", "stringdiff-delete").replace("$1", text); case StringDiff.EQUAL: return template.replace("$0", "stringdiff-equal").replace("$1", text); } } }