Browse Source

Merge branch 'improveAutoOuputGeneration' of LInE/ivprog into master

Lucas de Souza 5 years ago
parent
commit
95dbb289b5
8 changed files with 195 additions and 37 deletions
  1. 39 3
      css/ivprog-visual-1.0.css
  2. 3 1
      i18n/en/ui.json
  3. 3 1
      i18n/es/ui.json
  4. 3 1
      i18n/pt/message.json
  5. 3 1
      i18n/pt/ui.json
  6. 100 29
      js/iassign-integration-functions.js
  7. 3 1
      js/main.js
  8. 41 0
      js/util/auto_gen_output.js

+ 39 - 3
css/ivprog-visual-1.0.css

@@ -390,9 +390,6 @@ div.buttons_manage_columns {
 	padding: 3px;
 }
 
-.ui.button_add_case {
-	margin-top: 10px;
-}
 .accordion {
 	margin: auto;
 }
@@ -1018,4 +1015,43 @@ div.ui.checkbox.transition.visible {
 .circular.inverted.teal.question.icon {
 	font-size: 12px;
 	margin-left: 10px;
+}
+
+.table_buttons {
+	width: 100%;
+	margin-top: 10px;
+}
+.table_buttons .right_align {
+	text-align: right;
+}
+.text_area_output, .text_area_input {
+	width: 80%;
+}
+.tabular .item {
+	font-size: 1.1em;
+}
+.tabular.menu {
+	margin-top: 1em !important;
+}
+.ui.bottom.attached.tab.segment, .tabular.menu {
+	margin-left: 1em !important;
+	margin-right: 1em !important;
+}
+
+.ui.blue.table thead tr:first-child > th {
+     position: sticky !important;
+     top: 0;
+     z-index: 2;
+}
+
+.ui.bottom.attached.tab.segment.tab_algorithm {
+	height: 90%;
+}
+
+.ui.segment.settings_topic h3 {
+	margin-bottom: 20px;
+}
+
+.settings_topic .content_segment_settings {
+	margin-left: 40px;
 }

+ 3 - 1
i18n/en/ui.json

@@ -142,5 +142,7 @@
   "text_ivprog_version":"Version",
   "text_teacher_filter": "Filter",
   "text_teacher_filter_active": "Activate",
-  "text_teacher_filter_help": "When filter is activated, all iVProg modifications will be blocked."
+  "text_teacher_filter_help": "When filter is activated, all iVProg modifications will be blocked.",
+  "text_teacher_generate_outputs": "Generate outputs",
+  "text_teacher_generate_outputs_algorithm": "Before generate outputs, create an algorithm!"
 }

+ 3 - 1
i18n/es/ui.json

@@ -141,5 +141,7 @@
   "text_ivprog_version":"Version",
   "text_teacher_filter": "Filter",
   "text_teacher_filter_active": "Activate",
-  "text_teacher_filter_help": "When filter is activated, all iVProg modifications will be blocked."
+  "text_teacher_filter_help": "When filter is activated, all iVProg modifications will be blocked.",
+  "text_teacher_generate_outputs": "Generate outputs",
+  "text_teacher_generate_outputs_algorithm": "Before generate outputs, create an algorithm!"
 }

+ 3 - 1
i18n/pt/message.json

@@ -2,5 +2,7 @@
   "test_case_success": "Caso de teste $0: OK",
   "test_case_duration": "Levou $0ms",
   "test_suite_grade": "A sua solução alcançou $0% da nota.",
-  "awaiting_input_message": "O seu programa está em execução e aguardando uma entrada! Digite algo e pressione ENTER..."
+  "awaiting_input_message": "O seu programa está em execução e aguardando uma entrada! Digite algo e pressione ENTER...",
+  "testcase_autogen_unused_input": "O caso de teste $0 possui mais entradas do que as leituras feitas no programa.",
+  "testcase_autogen_empty": "O caso de teste $0 não gerou qualquer saída."
 }

+ 3 - 1
i18n/pt/ui.json

@@ -116,5 +116,7 @@
   "text_teacher_filter": "Filtro",
   "text_teacher_filter_active": "Ativado",
   "text_teacher_filter_help": "Ao ativar o filtro, as modificações do iVProg estarão bloqueadas.",
-  "text_join_assessment_outputs": " ; "
+  "text_join_assessment_outputs": " ; ",
+  "text_teacher_generate_outputs": "Gerar saídas",
+  "text_teacher_generate_outputs_algorithm": "Antes de gerar as saídas, elabore um algoritmo!"
 }

+ 100 - 29
js/iassign-integration-functions.js

@@ -401,11 +401,18 @@ function iassingIntegration () {
 // Função para preparar a interface para o professor criar atividade:
 function prepareActivityCreation () {
 
-  $('.add_accordion').addClass('accordion');
-
-  $('.default_visual_title').toggle();
-  $('.default_visual_title').append('<span>'+LocalizedStrings.getUI('text_teacher_algorithm')+'</span>');
-  $('.height_100').removeClass('height_100');
+  var menuTab = $('<div class="ui top attached tabular menu">'
+        + '<a class="item active" data-tab="testcases">' + LocalizedStrings.getUI('text_teacher_test_case') + '</a>'
+        + '<a class="item" data-tab="algorithm">' + LocalizedStrings.getUI('text_teacher_algorithm') + '</a>'
+        + '<a class="item" data-tab="settings">' + LocalizedStrings.getUI('text_teacher_config') + '</a>'
+        + '</div>'
+        + '<div class="ui bottom attached tab segment active tab_test_cases" data-tab="testcases"></div>'
+        + '<div class="ui bottom attached tab segment tab_algorithm" data-tab="algorithm"></div>'
+        + '<div class="ui bottom attached tab segment tab_settings" data-tab="settings"></div>');
+
+  menuTab.insertBefore('.add_accordion');
+  $('.tabular.menu .item').tab();
+  
   $('.main_title').remove();
   $('.ui.accordion').addClass('styled');
   
@@ -413,21 +420,21 @@ function prepareActivityCreation () {
 
   $('<div class="ui checkbox"><input type="checkbox" name="include_algo" class="include_algo" tabindex="0" class="hidden"><label>'+LocalizedStrings.getUI('text_teacher_algorithm_include')+'</label></div>').insertAfter('.content_margin');
   
-  var cases_test_div = $('<div class="ui accordion styled"><div class="active title"><i class="dropdown icon"></i>'+LocalizedStrings.getUI('text_teacher_test_case')+'</div><div class="active content"></div></div>');
+  var cases_test_div = $('<div></div>');
 
-  cases_test_div.insertBefore('.accordion');
+  $('.tab_test_cases').append(cases_test_div);
 
-  var config_div = $('<div class="ui accordion styled"><div class="title"><i class="dropdown icon"></i>'+LocalizedStrings.getUI('text_teacher_config')+'</div><div class="content"></div></div>');
+  var config_div = $('<div></div>');
 
-  config_div.insertAfter(cases_test_div);
-
-  $('.ui.accordion').accordion();
+  $('.tab_settings').append(config_div);
 
   $('.ui.checkbox').checkbox();
 
-  prepareTableSettings(config_div.find('.content'));
+  $('.tab_algorithm').append($('.add_accordion'));
+
+  prepareTableSettings(config_div);
 
-  prepareTableTestCases(cases_test_div.find('.content'));
+  prepareTableTestCases(cases_test_div);
 
   if (inIframe()) {
       $('.ui.styled.accordion').css('width', '96%');
@@ -441,11 +448,75 @@ function prepareTableTestCases (div_el) {
 
   div_el.append(table_el);
 
-  div_el.append('<button class="ui teal labeled icon button button_add_case"><i class="plus icon"></i>'+LocalizedStrings.getUI('text_teacher_test_case_add')+'</button>');
+  var table_buttons = '<table class="table_buttons"><tr><td>'
+    + '<button class="ui teal labeled icon button button_add_case"><i class="plus icon"></i>'+LocalizedStrings.getUI('text_teacher_test_case_add')+'</button>'
+    + '</td><td class="right_align">'
+    + '<button class="ui orange labeled icon button button_generate_outputs"><i class="sign-in icon"></i>'+LocalizedStrings.getUI('text_teacher_generate_outputs')+'</button>'
+    + '</td></tr></table>';
+
+  div_el.append(table_buttons);
+
+  div_el.append($('<div class="ui basic modal"><div class="content"><p>Olá</p></div><div class="actions"><div class="ui green ok inverted button">Fechar</div></div></div>'));
 
   $('.button_add_case').on('click', function(e) {
     addTestCase();
   });
+  $('.button_generate_outputs').on('click', function(e) {
+    generateOutputs();
+  });
+}
+
+function showAlert (msg) {
+  $('.ui.basic.modal .content').html('<h3>'+msg+'</h3>');
+  $('.ui.basic.modal').modal('show');
+}
+
+function generateOutputs () {
+  if (window.program_obj.functions.length == 1 && window.program_obj.functions[0].commands.length == 0) {
+    showAlert(LocalizedStrings.getUI('text_teacher_generate_outputs_algorithm'));
+    return;
+  }
+  // código:
+  var code_teacher = window.generator();
+  // array com as entradas já inseridas:
+  var test_cases = JSON.parse(prepareTestCases().replace('"testcases" :', ''));
+  ivprogCore.autoGenerateTestCaseOutput(code_teacher, test_cases).catch(function (error) {
+    showAlert("Houve um erro durante a execução do seu programa: "+error.message);
+  });
+  
+}
+
+function outputGenerated (test_cases) {
+  var fields = $('.text_area_output');
+  /*for (var i = 0; i < test_cases.length; i++) {
+    $(fields[i]).val('');
+    for (var j = 0; j < test_cases[i].output.length; j++) {
+      $(fields[i]).val($(fields[i]).val() + test_cases[i].output[j]);
+      if (j < test_cases[i].output.length - 1) {
+        $(fields[i]).val($(fields[i]).val() + '\n');
+      }
+    }
+    $(fields[i]).attr('rows', test_cases[i].output.length);
+  }*/
+  animateOutput(fields, test_cases, 0);
+
+  
+}
+
+function animateOutput (list, test_cases, index) {
+  if (list.length == index) return;
+  $(list[index]).val('');
+  for (var j = 0; j < test_cases[index].output.length; j++) {
+    $(list[index]).val($(list[index]).val() + test_cases[index].output[j]);
+    if (j < test_cases[index].output.length - 1) {
+      $(list[index]).val($(list[index]).val() + '\n');
+    }
+  }
+  $(list[index]).attr('rows', test_cases[index].output.length);
+
+  $(list[index]).effect('highlight', null, 50, function() {
+    animateOutput(list, test_cases, index + 1);
+  });
 }
 
 var hist = false;
@@ -520,23 +591,23 @@ function updateTestCaseCounter () {
 
 function prepareTableSettings (div_el) {
 
-  div_el.append('<h4 class="ui header">'+LocalizedStrings.getUI('text_config_programming')+'</h4>');
-  div_el.append('<form name="settings_programming_type"><div class="ui stackable five column grid">'
+  div_el.append('<div class="ui segment settings_topic"><h3 class="ui header"><i class="window maximize outline icon"></i><div class="content">'+LocalizedStrings.getUI('text_config_programming')+'</div></h3>'
+    +'<div class="content content_segment_settings"><form name="settings_programming_type"><div class="ui stackable five column grid">'
     +'<div class="column"><div class="ui radio"><input type="radio" name="programming_type" id="programming_textual" value="textual" tabindex="0" class="hidden small"><label for="programming_textual">'+LocalizedStrings.getUI('text_config_programming_textual')+'</label></div></div>'
     +'<div class="column"><div class="ui radio"><input type="radio" name="programming_type" id="programming_visual" value="visual" checked tabindex="0" class="hidden small"><label for="programming_visual">'+LocalizedStrings.getUI('text_config_programming_visual')+'</label></div></div>'
-    +'</div></form>');
+    +'</div></form></div></div>');
 
-  div_el.append('<h4 class="ui header">'+LocalizedStrings.getUI('text_teacher_data_types')+'</h4>');
-  div_el.append('<form name="settings_data_types"><div class="ui stackable five column grid">'
+  div_el.append('<div class="ui segment settings_topic"><h3 class="ui header"><i class="qrcode icon"></i><div class="content">'+LocalizedStrings.getUI('text_teacher_data_types')+'</div></h3>'
+    +'<div class="content content_segment_settings"><form name="settings_data_types"><div class="ui stackable five column grid">'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="integer_data_type" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('type_integer')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="real_data_type" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('type_real')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="text_data_type" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('type_text')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="boolean_data_type" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('type_boolean')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="void_data_type" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('type_void')+'</label></div></div>'
-    +'</div></form>');
+    +'</div></form></div></div>');
 
-  div_el.append('<h4 class="ui header">'+LocalizedStrings.getUI('text_teacher_commands')+'</h4>');
-  div_el.append('<form name="settings_commands"><div class="ui stackable three column grid">'
+  div_el.append('<div class="ui segment settings_topic"><h3 class="ui header"><i class="code icon"></i><div class="content">'+LocalizedStrings.getUI('text_teacher_commands')+'</div></h3>'
+    +'<div class="content content_segment_settings"><form name="settings_commands"><div class="ui stackable three column grid">'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="commands_read" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_read_var')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="commands_write" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_write_var')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="commands_comment" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_comment')+'</label></div></div>'
@@ -547,18 +618,18 @@ function prepareTableSettings (div_el) {
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="commands_while" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_whiletrue')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="commands_dowhile" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_dowhiletrue')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="commands_switch" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_switch')+'</label></div></div>'
-    +'</div></form>');
+    +'</div></form></div></div>');
 
-  div_el.append('<h4 class="ui header">'+LocalizedStrings.getUI('text_teacher_functions')+'</h4>');
-  div_el.append('<form name="settings_functions"><div class="ui stackable one column grid">'
+  div_el.append('<div class="ui segment settings_topic"><h3 class="ui header"><i class="terminal icon"></i><div class="content">'+LocalizedStrings.getUI('text_teacher_functions')+'</div></h3>'
+    +'<div class="content content_segment_settings"><form name="settings_functions"><div class="ui stackable one column grid">'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="functions_creation" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_teacher_create_functions')+'</label></div></div>'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="functions_move" checked tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_teacher_create_movement_functions')+'</label></div></div>'
-    +'</div></form>');
+    +'</div></form></div></div>');
 
-  div_el.append('<h4 class="ui header">'+LocalizedStrings.getUI('text_teacher_filter')+'<i class="circular inverted teal question icon"></i></h4>');
-  div_el.append('<form name="settings_filter"><div class="ui stackable one column grid">'
+  div_el.append('<div class="ui segment settings_topic"><h3 class="ui header"><i class="filter icon"></i><div class="content">'+LocalizedStrings.getUI('text_teacher_filter')+'</div><i class="circular inverted teal question icon"></i></h3>'
+    +'<div class="content content_segment_settings"><form name="settings_filter"><div class="ui stackable one column grid">'
     +'<div class="column"><div class="ui checkbox"><input type="checkbox" name="filter_active" tabindex="0" class="hidden small"><label>'+LocalizedStrings.getUI('text_teacher_filter_active')+'</label></div></div>'
-    +'</div></form>');
+    +'</div></form></div></div>');
 
   $('.circular.inverted.teal.question.icon').popup({
     content : LocalizedStrings.getUI("text_teacher_filter_help"),

+ 3 - 1
js/main.js

@@ -7,6 +7,7 @@ import { i18nHelper } from "./services/i18nHelper";
 import { ActionTypes, getLogs, getLogsAsString, registerClick, registerUserEvent, parseLogs } from "./services/userLog";
 import { prepareActivityToStudentHelper, autoEval } from "./util/iassignHelpers";
 import * as CodeEditorAll from "./visualUI/text_editor";
+import {autoGenerateTestCaseOutput} from './util/auto_gen_output';
 
 const CodeEditor = {
   setCode: CodeEditorAll.setCode,
@@ -36,5 +37,6 @@ export {
   registerUserEvent,
   parseLogs,
   ActionTypes,
-  CodeEditor
+  CodeEditor,
+  autoGenerateTestCaseOutput
 }

+ 41 - 0
js/util/auto_gen_output.js

@@ -0,0 +1,41 @@
+import {SemanticAnalyser} from './../processor/semantic/semanticAnalyser';
+import {IVProgProcessor} from './../processor/ivprogProcessor';
+import { InputTest } from './inputTest';
+import { OutputTest } from './outputTest';
+import { LocalizedStrings } from './../services/localizedStringsService'
+
+export function autoGenerateTestCaseOutput (program_text, testCases) {
+  let copyTestCases = testCases.map((test) => Object.assign({}, test));
+  try {
+    const program = SemanticAnalyser.analyseFromSource(program_text);
+    const resultList = testCases.map((test, id) => {
+      const input = new InputTest(test.input);
+      const output = new OutputTest();
+      const exec =  new IVProgProcessor(program);
+      exec.registerInput(input);
+      exec.registerOutput(output);
+      return exec.interpretAST().then(_ => {
+        return {id: id, program: exec};
+      });
+    });
+    return Promise.all(resultList).then(result_final => {
+      for(let i = 0; i < result_final.length; ++i) {
+        const result = result_final[i];
+        const output = result.program.output.list;
+        const input = result.program.input;
+        if(input.index != input.inputList.length) {
+          window.showAlert(LocalizedStrings.getMessage("testcase_autogen_unused_input", [result.id+1]));
+          return Promise.resolve(false);
+        }
+        if(output.length == 0) {
+          window.showAlert(LocalizedStrings.getMessage("testcase_autogen_empty", [result.id+1]));
+        }
+        copyTestCases[result.id].output = output;
+      }
+      window.outputGenerated(copyTestCases);
+      return Promise.resolve(true);
+    });
+  }catch (error) {
+    return Promise.reject(error)
+  }
+}