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;
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";
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() {
}
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,
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);
}
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));
<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
--- /dev/null
+<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("Hello, world! My name is type your name") "/>
+ </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
--- /dev/null
+<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("Hello, world! My name is type your name") "/>
+ </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
--- /dev/null
+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");
+ }
+}