migrate to the new version of format
authorLiana.Bakradze <liana.bakradze@jetbrains.com>
Wed, 2 Nov 2016 14:18:40 +0000 (17:18 +0300)
committerliana.bakradze <liana.bakradze@jetbrains.com>
Thu, 17 Nov 2016 14:08:39 +0000 (17:08 +0300)
python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java
python/educational-core/student/student.iml
python/educational-core/student/testData/migration/3.xml [new file with mode: 0644]
python/educational-core/student/testData/migration/4.xml [new file with mode: 0644]
python/educational-core/student/testSrc/com/jetbrains/edu/learning/StudyMigrationTest.java [new file with mode: 0644]

index d0cd98e3c28cb959ce625ffc8580be22a7a725fc..b1ab9e68f83df8abbc8d859e715f7007921c5029 100644 (file)
@@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.vfs.LocalFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.hash.HashMap;
 import com.jetbrains.edu.learning.core.EduNames;
 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
@@ -71,7 +72,6 @@ public class StudySerializationUtils {
     public static final String MY_LINE = "myLine";
     public static final String MY_START = "myStart";
     public static final String MY_LENGTH = "myLength";
-    public static final String HINTS = "hints";
     public static final String HINT = "hint";
     public static final String AUTHOR_TITLED = "Author";
     public static final String FIRST_NAME = "first_name";
@@ -82,6 +82,13 @@ public class StudySerializationUtils {
     public static final String TASK_WINDOWS = "taskWindows";
     public static final String RESOURCE_PATH = "resourcePath";
     public static final String COURSE_DIRECTORY = "courseDirectory";
+    public static final String SUBTASK_INFO = "AnswerPlaceholderSubtaskInfo";
+    public static final String SUBTASK_INFOS = "subtaskInfos";
+    public static final String ADDITIONAL_HINTS = "additionalHints";
+    public static final String POSSIBLE_ANSWER = "possibleAnswer";
+    public static final String SELECTED = "selected";
+    public static final String TASK_TEXT = "taskText";
+    public static final String PLACEHOLDER_TEXT = "placeholderText";
 
     private Xml() {
     }
@@ -199,6 +206,31 @@ public class StudySerializationUtils {
       return state;
     }
 
+    public static Element convertToForthVersion(Element state) throws StudyUnrecognizedFormatException {
+      Element taskManagerElement = state.getChild(MAIN_ELEMENT);
+      Element courseElement = getChildWithName(taskManagerElement, COURSE).getChild(COURSE_TITLED);
+      for (Element lesson : getChildList(courseElement, LESSONS)) {
+        for (Element task : getChildList(lesson, TASK_LIST)) {
+          Map<String, Element> taskFiles = getChildMap(task, TASK_FILES);
+          for (Map.Entry<String, Element> entry : taskFiles.entrySet()) {
+            Element taskFileElement = entry.getValue();
+            for (Element placeholder : getChildList(taskFileElement, ANSWER_PLACEHOLDERS)) {
+              Element valueElement = new Element(SUBTASK_INFO);
+              addChildMap(placeholder, SUBTASK_INFOS, Collections.singletonMap(String.valueOf(0), valueElement));
+              for (String childName : ContainerUtil
+                .list(HINT, ADDITIONAL_HINTS, POSSIBLE_ANSWER, SELECTED, STATUS, TASK_TEXT)) {
+                Element child = getChildWithName(placeholder, childName);
+                valueElement.addContent(child.clone());
+              }
+              renameElement(getChildWithName(valueElement, TASK_TEXT), PLACEHOLDER_TEXT);
+            }
+          }
+        }
+      }
+
+      return state;
+    }
+
     public static String addStatus(XMLOutputter outputter,
                                    Map<String, String> placeholderTextToStatus,
                                    String taskStatus,
@@ -272,6 +304,20 @@ public class StudySerializationUtils {
       return addChildWithName(parent, name, listElement);
     }
 
+    public static Element addChildMap(Element parent, String name, Map<String, Element> value) {
+      Element mapElement = new Element(MAP);
+      for (Map.Entry<String, Element> entry : value.entrySet()) {
+        Element entryElement = new Element("entry");
+        mapElement.addContent(entryElement);
+        String key = entry.getKey();
+        entryElement.setAttribute("key", key);
+        Element valueElement = new Element("value");
+        valueElement.addContent(entry.getValue());
+        entryElement.addContent(valueElement);
+      }
+      return addChildWithName(parent, name, mapElement);
+    }
+
     public static List<Element> getChildList(Element parent, String name) throws StudyUnrecognizedFormatException {
       return getChildList(parent, name, false);
     }
index 64c61d4b637d0788b0f84ae7072fe9cdb90d70f0..eed7a8e9d6ff9ebbb79290344c9595f27b12d7dc 100644 (file)
@@ -140,8 +140,10 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, Dumb
           state = StudySerializationUtils.Xml.convertToSecondVersion(state);
         case 2:
           state = StudySerializationUtils.Xml.convertToThirdVersion(state, myProject);
+        case 3:
+          state = StudySerializationUtils.Xml.convertToForthVersion(state);
           //uncomment for future versions
-          //case 3:
+          //case 4:
           //state = StudySerializationUtils.Xml.convertToForthVersion(state, myProject);
       }
       XmlSerializer.deserializeInto(this, state.getChild(StudySerializationUtils.Xml.MAIN_ELEMENT));
index 830451861a0f3a2e9e57e37d16feb1209a075ec4..74bb142082e88b673906b05603498ce481bdc5ae 100644 (file)
@@ -5,6 +5,7 @@
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
       <excludeFolder url="file://$MODULE_DIR$/../../educational/interactive-learning/src/com/jetbrains/edu/learning/course" />
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="module" module-name="platform-api" />
     <orderEntry type="module" module-name="xml" />
     <orderEntry type="library" name="markdownj" level="project" />
+    <orderEntry type="module-library" scope="TEST">
+      <library name="JUnit4">
+        <CLASSES>
+          <root url="jar://$APPLICATION_HOME_DIR$/lib/junit-4.12.jar!/" />
+          <root url="jar://$APPLICATION_HOME_DIR$/lib/hamcrest-core-1.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module" module-name="testFramework" scope="TEST" />
   </component>
 </module>
\ No newline at end of file
diff --git a/python/educational-core/student/testData/migration/3.xml b/python/educational-core/student/testData/migration/3.xml
new file mode 100644 (file)
index 0000000..b347959
--- /dev/null
@@ -0,0 +1,110 @@
+<component name="StudySettings">
+  <StudyTaskManager>
+    <option name="course">
+      <Course>
+        <option name="adaptive" value="false"/>
+        <option name="authors">
+          <list>
+            <StepicUser>
+              <option name="email" value=""/>
+              <option name="firstName" value=""/>
+              <option name="id" value="-1"/>
+              <option name="lastName" value=""/>
+            </StepicUser>
+          </list>
+        </option>
+        <option name="courseDirectory" value="$APPLICATION_CONFIG_DIR$/courses/Introduction to Python"/>
+        <option name="courseMode" value="Study"/>
+        <option name="courseType" value="PyCharm"/>
+        <option name="description" value="Introduction course to Python"/>
+        <option name="id" value="238"/>
+        <option name="language" value="Python"/>
+        <option name="lessons">
+          <list>
+            <Lesson>
+              <option name="id" value="13416"/>
+              <option name="index" value="1"/>
+              <option name="name" value="Introduction"/>
+              <option name="updateDate"/>
+              <option name="taskList">
+                <list>
+                  <Task>
+                    <option name="index" value="1"/>
+                    <option name="name" value="Our first program"/>
+                    <option name="status" value="Solved"/>
+                    <option name="stepicId" value="98626"/>
+                    <option name="text"/>
+                    <option name="updateDate"/>
+                    <option name="taskFiles">
+                      <map>
+                        <entry key="hello_world.py">
+                          <value>
+                            <TaskFile>
+                              <option name="answerPlaceholders">
+                                <list>
+                                  <AnswerPlaceholder>
+                                    <option name="additionalHints">
+                                      <list>
+                                        <option value="hint 2"/>
+                                      </list>
+                                    </option>
+                                    <option name="hint" value="hint 1"/>
+                                    <option name="index" value="0"/>
+                                    <option name="initialState">
+                                      <MyInitialState>
+                                        <option name="length" value="14"/>
+                                        <option name="offset" value="32"/>
+                                      </MyInitialState>
+                                    </option>
+                                    <option name="length" value="5"/>
+                                    <option name="offset" value="32"/>
+                                    <option name="possibleAnswer" value="Liana"/>
+                                    <option name="selected" value="false"/>
+                                    <option name="status" value="Solved"/>
+                                    <option name="taskText" value="test text"/>
+                                    <option name="useLength" value="true"/>
+                                  </AnswerPlaceholder>
+                                </list>
+                              </option>
+                              <option name="highlightErrors" value="true"/>
+                              <option name="index" value="0"/>
+                              <option name="trackChanges" value="true"/>
+                              <option name="userCreated" value="false"/>
+                              <option name="name" value="hello_world.py"/>
+                              <option name="text" value="print(&quot;Hello, world! My name is type your name&quot;)&#10;"/>
+                            </TaskFile>
+                          </value>
+                        </entry>
+                      </map>
+                    </option>
+                  </Task>
+                </list>
+              </option>
+            </Lesson>
+          </list>
+        </option>
+        <option name="name" value="Introduction to Python"/>
+        <option name="updateDate"/>
+      </Course>
+    </option>
+    <option name="enableTestingFromSamples" value="true"/>
+    <option name="toolWindowMode" value="TEXT"/>
+    <option name="turnEditingMode" value="false"/>
+    <option name="user">
+      <StepicUser>
+        <option name="email" value=""/>
+        <option name="firstName" value=""/>
+        <option name="id" value="-1"/>
+        <option name="lastName" value=""/>
+      </StepicUser>
+    </option>
+    <option name="VERSION" value="3"/>
+    <option name="myUserTests">
+      <map/>
+    </option>
+    <option name="myInvisibleFiles">
+      <list/>
+    </option>
+    <option name="myShouldUseJavaFx" value="true"/>
+  </StudyTaskManager>
+</component>
\ No newline at end of file
diff --git a/python/educational-core/student/testData/migration/4.xml b/python/educational-core/student/testData/migration/4.xml
new file mode 100644 (file)
index 0000000..81b13fa
--- /dev/null
@@ -0,0 +1,130 @@
+<component name="StudySettings">
+  <StudyTaskManager>
+    <option name="course">
+      <Course>
+        <option name="adaptive" value="false"/>
+        <option name="authors">
+          <list>
+            <StepicUser>
+              <option name="email" value=""/>
+              <option name="firstName" value=""/>
+              <option name="id" value="-1"/>
+              <option name="lastName" value=""/>
+            </StepicUser>
+          </list>
+        </option>
+        <option name="courseDirectory" value="$APPLICATION_CONFIG_DIR$/courses/Introduction to Python"/>
+        <option name="courseMode" value="Study"/>
+        <option name="courseType" value="PyCharm"/>
+        <option name="description" value="Introduction course to Python"/>
+        <option name="id" value="238"/>
+        <option name="language" value="Python"/>
+        <option name="lessons">
+          <list>
+            <Lesson>
+              <option name="id" value="13416"/>
+              <option name="index" value="1"/>
+              <option name="name" value="Introduction"/>
+              <option name="updateDate"/>
+              <option name="taskList">
+                <list>
+                  <Task>
+                    <option name="index" value="1"/>
+                    <option name="name" value="Our first program"/>
+                    <option name="status" value="Solved"/>
+                    <option name="stepicId" value="98626"/>
+                    <option name="text"/>
+                    <option name="updateDate"/>
+                    <option name="taskFiles">
+                      <map>
+                        <entry key="hello_world.py">
+                          <value>
+                            <TaskFile>
+                              <option name="answerPlaceholders">
+                                <list>
+                                  <AnswerPlaceholder>
+                                    <option name="additionalHints">
+                                      <list>
+                                        <option value="hint 2"/>
+                                      </list>
+                                    </option>
+                                    <option name="hint" value="hint 1"/>
+                                    <option name="index" value="0"/>
+                                    <option name="initialState">
+                                      <MyInitialState>
+                                        <option name="length" value="14"/>
+                                        <option name="offset" value="32"/>
+                                      </MyInitialState>
+                                    </option>
+                                    <option name="length" value="5"/>
+                                    <option name="offset" value="32"/>
+                                    <option name="possibleAnswer" value="Liana"/>
+                                    <option name="selected" value="false"/>
+                                    <option name="status" value="Solved"/>
+                                    <option name="taskText" value="test text"/>
+                                    <option name="useLength" value="true"/>
+                                    <option name="subtaskInfos">
+                                      <map>
+                                        <entry key="0">
+                                          <value>
+                                            <AnswerPlaceholderSubtaskInfo>
+                                              <option name="hint" value="hint 1"/>
+                                              <option name="additionalHints">
+                                                <list>
+                                                  <option value="hint 2"/>
+                                                </list>
+                                              </option>
+                                              <option name="possibleAnswer" value="Liana"/>
+                                              <option name="selected" value="false"/>
+                                              <option name="status" value="Solved"/>
+                                              <option name="placeholderText" value="test text"/>
+                                            </AnswerPlaceholderSubtaskInfo>
+                                          </value>
+                                        </entry>
+                                      </map>
+                                    </option>
+                                  </AnswerPlaceholder>
+                                </list>
+                              </option>
+                              <option name="highlightErrors" value="true"/>
+                              <option name="index" value="0"/>
+                              <option name="trackChanges" value="true"/>
+                              <option name="userCreated" value="false"/>
+                              <option name="name" value="hello_world.py"/>
+                              <option name="text" value="print(&quot;Hello, world! My name is type your name&quot;)&#10;"/>
+                            </TaskFile>
+                          </value>
+                        </entry>
+                      </map>
+                    </option>
+                  </Task>
+                </list>
+              </option>
+            </Lesson>
+          </list>
+        </option>
+        <option name="name" value="Introduction to Python"/>
+        <option name="updateDate"/>
+      </Course>
+    </option>
+    <option name="enableTestingFromSamples" value="true"/>
+    <option name="toolWindowMode" value="TEXT"/>
+    <option name="turnEditingMode" value="false"/>
+    <option name="user">
+      <StepicUser>
+        <option name="email" value=""/>
+        <option name="firstName" value=""/>
+        <option name="id" value="-1"/>
+        <option name="lastName" value=""/>
+      </StepicUser>
+    </option>
+    <option name="VERSION" value="3"/>
+    <option name="myUserTests">
+      <map/>
+    </option>
+    <option name="myInvisibleFiles">
+      <list/>
+    </option>
+    <option name="myShouldUseJavaFx" value="true"/>
+  </StudyTaskManager>
+</component>
\ No newline at end of file
diff --git a/python/educational-core/student/testSrc/com/jetbrains/edu/learning/StudyMigrationTest.java b/python/educational-core/student/testSrc/com/jetbrains/edu/learning/StudyMigrationTest.java
new file mode 100644 (file)
index 0000000..2d21fd5
--- /dev/null
@@ -0,0 +1,26 @@
+package com.jetbrains.edu.learning;
+
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.testFramework.PlatformTestUtil;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+public class StudyMigrationTest {
+
+  @Test
+  public void testFromThirdToForth() throws JDOMException, IOException, StudySerializationUtils.StudyUnrecognizedFormatException {
+    Element element = JDOMUtil.load(new File(FileUtil.join(getTestDataPath(), "3.xml")));
+    Element actual = StudySerializationUtils.Xml.convertToForthVersion(element);
+    Element expected = JDOMUtil.load(new File(FileUtil.join(getTestDataPath()), "4.xml"));
+    PlatformTestUtil.assertElementsEqual(expected, actual);
+  }
+
+  protected String getTestDataPath() {
+    return FileUtil.join(PlatformTestUtil.getCommunityPath(), "python/educational-core/student/testData/migration");
+  }
+}