[Ktutorial-commits] SF.net SVN: ktutorial:[172] trunk/ktutorial/ktutorial-editor
Status: Alpha
Brought to you by:
danxuliu
From: <dan...@us...> - 2010-03-21 01:03:49
|
Revision: 172 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=172&view=rev Author: danxuliu Date: 2010-03-21 01:03:42 +0000 (Sun, 21 Mar 2010) Log Message: ----------- Fix unescaped sequences in Javascript code when the source string contained quote, tabulator or new line characters. Also ensure that generated function and variable names contain only letters, digits or underscores. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-03-19 19:06:00 UTC (rev 171) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-03-21 01:03:42 UTC (rev 172) @@ -81,14 +81,14 @@ out() << "//Error: Tutorial without name!\n"; } else { out() << "tutorial.tutorialInformationAsObject().setName(t.i18n(\"" - << tutorial->name() <<"\"));\n"; + << escape(tutorial->name()) <<"\"));\n"; } if (tutorial->description().isEmpty()) { out() << "//Error: Tutorial without description!\n"; } else { out() << "tutorial.tutorialInformationAsObject().setDescription(" - << "t.i18n(\"" << tutorial->description() <<"\"));\n"; + << "t.i18n(\"" << escape(tutorial->description()) <<"\"));\n"; } mOut << "\n"; @@ -131,14 +131,14 @@ out() << "//Step " << step->id() << "\n"; QString stepVariable = toLowerCamelCase(step->id()) + "Step"; - out() << stepVariable << " = ktutorial.newStep(\"" << step->id() + out() << stepVariable << " = ktutorial.newStep(\"" << escape(step->id()) << "\");\n"; if (step->text().isEmpty()) { out() << "//Error: Step without text!\n"; } else { out() << stepVariable << ".setText(t.i18nc(\"@info\", \"" - << step->text() << "\"));\n"; + << escape(step->text()) << "\"));\n"; } mOut << '\n'; @@ -218,8 +218,8 @@ if (reaction->triggerType() == Reaction::OptionSelected && reaction->responseType() == Reaction::NextStep) { out() << "step.addOption(ktutorial.newOption(\"" - << reaction->optionName() << "\"), \"" << reaction->nextStepId() - << "\");\n"; + << escape(reaction->optionName()) << "\"), \"" + << escape(reaction->nextStepId()) << "\");\n"; return; } @@ -229,8 +229,8 @@ toUpperCamelCase(reaction->optionName()) + "OptionSelected"; out() << "step.addOption(ktutorial.newOption(\"" - << reaction->optionName() << "\"), self, \"" << functionName - << "()\");\n"; + << escape(reaction->optionName()) << "\"), self, \"" + << functionName << "()\");\n"; addFunction(functionName, reaction->customCode()); return; } @@ -242,7 +242,7 @@ if (reaction->responseType() == Reaction::NextStep) { out() << "step.addWaitFor(" << variableName << ", \"" - << reaction->nextStepId() << "\");\n"; + << escape(reaction->nextStepId()) << "\");\n"; return; } @@ -313,8 +313,8 @@ out() << variable << " = ktutorial.newWaitFor(\"WaitForEvent\");\n"; out() << variable << ".setEvent(ktutorial.findObject(\"" - << waitForEvent->receiverName() << "\"), \"" - << waitForEvent->eventName() << "\");\n"; + << escape(waitForEvent->receiverName()) << "\"), \"" + << escape(waitForEvent->eventName()) << "\");\n"; return variable; } @@ -356,8 +356,8 @@ out() << variable << " = ktutorial.newWaitFor(\"WaitForSignal\");\n"; out() << variable << ".setSignal(ktutorial.findObject(\"" - << waitForSignal->emitterName() << "\"), \"" - << waitForSignal->signalName() << "\");\n"; + << escape(waitForSignal->emitterName()) << "\"), \"" + << escape(waitForSignal->signalName()) << "\");\n"; return variable; } @@ -407,6 +407,14 @@ return variable + QString().setNum(mVariables.value(variable)); } +QString JavascriptExporter::escape(QString text) { + text.replace('\n', "\\n"); + text.replace('\t', "\\t"); + text.replace('"', "\\\""); + + return text; +} + QString JavascriptExporter::toIndentedCode(const QString& code) { if (code.isEmpty()) { return ""; @@ -439,11 +447,12 @@ return lowerCamelCase; } -QString JavascriptExporter::toUpperCamelCase(const QString& text) const { +QString JavascriptExporter::toUpperCamelCase(QString text) const { if (text.isEmpty()) { return ""; } + text.replace(QRegExp("[^\\w ]"), ""); QStringList words = text.split(' ', QString::SkipEmptyParts); QString upperCamelCase; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-03-19 19:06:00 UTC (rev 171) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-03-21 01:03:42 UTC (rev 172) @@ -263,6 +263,16 @@ QString addVariable(const QString& variable); /** + * Returns the same text, but with Javascript escape sequences where needed. + * Some special characters (new line, tab and quotes) are written as their + * escape squence. + * + * @param text The text to escape. + * @return The Javascript text. + */ + QString escape(QString text); + + /** * Returns the same code, but with each line indented and ending in a new * line. * @@ -273,6 +283,8 @@ /** * Returns the lowerCamelCase version of the given text. + * Note that the returned text contains only letters, digits or underscores. + * Any other character is removed. * * @param text The string to get its lowerCamelCase version. * @return The lowerCamelCase version of the text. @@ -281,11 +293,13 @@ /** * Returns the UpperCamelCase version of the given text. + * Note that the returned text contains only letters, digits or underscores. + * Any other character is removed. * * @param text The string to get its UpperCamelCase version. * @return The UpperCamelCase version of the text. */ - QString toUpperCamelCase(const QString& text) const; + QString toUpperCamelCase(QString text) const; }; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-03-19 19:06:00 UTC (rev 171) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-03-21 01:03:42 UTC (rev 172) @@ -57,11 +57,13 @@ void testTutorialLicense(); void testTutorialInformation(); + void testTutorialInformationWithEscapeSequences(); void testTutorialSetupCode(); void testTutorialTearDownCode(); void testTutorialWithSeveralSteps(); void testStep(); + void testStepWithEscapeSequences(); void testStepSetupCode(); void testStepSetupCodeWithReactions(); void testStepTearDownCode(); @@ -69,17 +71,23 @@ void testStepWithSeveralReactions(); void testReactionOptionNextStep(); + void testReactionOptionNextStepWithEscapeSequences(); void testReactionOptionNextStepWithoutOptionNameOrStepId(); void testReactionOptionCustomCode(); + void testReactionOptionCustomCodeWithEscapeSequences(); void testReactionOptionCustomCodeWithoutOptionNameOrCustomCode(); void testReactionConditionNextStep(); + void testReactionConditionNextStepWithEscapeSequences(); void testReactionConditionNextStepWithoutConditionOrStepId(); void testReactionConditionCustomCode(); + void testReactionConditionCustomCodeWithEscapeSequences(); void testReactionConditionCustomCodeWithoutConditionOrCustomCode(); void testWaitForEvent(); + void testWaitForEventWithEscapeSequences(); void testWaitForEventWithoutReceiverNameOrEventName(); void testWaitForSignal(); + void testWaitForSignalWithEscapeSequences(); void testWaitForSignalWithoutEmitterNameOrSignalName(); void testWaitForComposed(); void testWaitForComposedWithInvalidChildWaitFor(); @@ -126,6 +134,25 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testTutorialInformationWithEscapeSequences() { + Tutorial tutorial; + tutorial.setName("The \"name\""); + tutorial.setDescription("The\tdescription\nwith \"escape\" sequences"); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +"t = Kross.module(\"kdetranslation\");\n" +"\n" +"tutorial.tutorialInformationAsObject().setName(t.i18n(\"The \\\"name\\\"\"));\n" +"tutorial.tutorialInformationAsObject().setDescription(\ +t.i18n(\"The\\tdescription\\nwith \\\"escape\\\" sequences\"));\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testTutorialSetupCode() { Tutorial tutorial; tutorial.setCustomSetupCode("The custom setup\ncode"); @@ -278,6 +305,29 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testStepWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The \"id\""); + step->setText("The\ttext\nwith \"escape\" sequences"); + tutorial.addStep(step); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +"//Step The \"id\"\n" +"theIdStep = ktutorial.newStep(\"The \\\"id\\\"\");\n" +"theIdStep.setText(t.i18nc(\"@info\", \ +\"The\\ttext\\nwith \\\"escape\\\" sequences\"));\n" +"\n" +"tutorial.addStep(theIdStep);\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testStepSetupCode() { Tutorial tutorial; Step* step = new Step(); @@ -477,6 +527,35 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testReactionOptionNextStepWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::OptionSelected); + reaction->setOptionName("The \"option\" name"); + reaction->setResponseType(Reaction::NextStep); + reaction->setNextStepId("Another \"step\""); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" step.addOption(ktutorial.newOption(\"The \\\"option\\\" name\"), \ +\"Another \\\"step\\\"\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest:: testReactionOptionNextStepWithoutOptionNameOrStepId() { Tutorial tutorial; @@ -553,6 +632,40 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testReactionOptionCustomCodeWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::OptionSelected); + reaction->setOptionName("The \"option\" name"); + reaction->setResponseType(Reaction::CustomCode); + reaction->setCustomCode("The custom\ncode"); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" step.addOption(ktutorial.newOption(\"The \\\"option\\\" name\"), self, \ +\"theIdStepTheOptionNameOptionSelected()\");\n" +"}\n" +CONNECT_STEP_SETUP +"function theIdStepTheOptionNameOptionSelected() {\n" +" The custom\n" +" code\n" +"}\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest:: testReactionOptionCustomCodeWithoutOptionNameOrCustomCode() { Tutorial tutorial; @@ -638,6 +751,46 @@ } void JavascriptExporterTest:: + testReactionConditionNextStepWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForSignal* waitForSignal = new WaitForSignal(); + waitForSignal->setEmitterName("The \"emitter\" name"); + waitForSignal->setSignalName("\"theSignalName\"(Argument1Type, " + "Argument2Type)"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForSignal); + reaction->setResponseType(Reaction::NextStep); + reaction->setNextStepId("Another \"step\""); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" waitForTheSignalNameByTheEmitterName = \ +ktutorial.newWaitFor(\"WaitForSignal\");\n" +" waitForTheSignalNameByTheEmitterName.setSignal(\ +ktutorial.findObject(\"The \\\"emitter\\\" name\"), \ +\"\\\"theSignalName\\\"(Argument1Type, Argument2Type)\");\n" +" step.addWaitFor(waitForTheSignalNameByTheEmitterName, \ +\"Another \\\"step\\\"\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest:: testReactionConditionNextStepWithoutConditionOrStepId() { Tutorial tutorial; Step* step = new Step(); @@ -726,6 +879,51 @@ } void JavascriptExporterTest:: + testReactionConditionCustomCodeWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForSignal* waitForSignal = new WaitForSignal(); + waitForSignal->setEmitterName("The \"emitter\" name"); + waitForSignal->setSignalName("\"theSignalName\"(Argument1Type, " + "Argument2Type)"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForSignal); + reaction->setResponseType(Reaction::CustomCode); + reaction->setCustomCode("The custom\ncode"); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" waitForTheSignalNameByTheEmitterName = \ +ktutorial.newWaitFor(\"WaitForSignal\");\n" +" waitForTheSignalNameByTheEmitterName.setSignal(\ +ktutorial.findObject(\"The \\\"emitter\\\" name\"), \ +\"\\\"theSignalName\\\"(Argument1Type, Argument2Type)\");\n" +" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \ +\"theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n" +"}\n" +CONNECT_STEP_SETUP +"function theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n" +" The custom\n" +" code\n" +"}\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest:: testReactionConditionCustomCodeWithoutConditionOrCustomCode() { Tutorial tutorial; Step* step = new Step(); @@ -817,6 +1015,43 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForEventWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForEvent* waitForEvent = new WaitForEvent(); + waitForEvent->setReceiverName("The \"receiver\" name"); + waitForEvent->setEventName("\"TheEventName\""); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForEvent); + reaction->setResponseType(Reaction::NextStep); + reaction->setNextStepId("Another step"); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" waitForTheEventNameInTheReceiverName = \ +ktutorial.newWaitFor(\"WaitForEvent\");\n" +" waitForTheEventNameInTheReceiverName.setEvent(\ +ktutorial.findObject(\"The \\\"receiver\\\" name\"), \ +\"\\\"TheEventName\\\"\");\n" +" step.addWaitFor(waitForTheEventNameInTheReceiverName, \"Another step\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testWaitForEventWithoutReceiverNameOrEventName() { Tutorial tutorial; Step* step = new Step(); @@ -899,6 +1134,44 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForSignalWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForSignal* waitForSignal = new WaitForSignal(); + waitForSignal->setEmitterName("The \"emitter\" name"); + waitForSignal->setSignalName("\"theSignalName\"(Argument1Type, " + "Argument2Type)"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForSignal); + reaction->setResponseType(Reaction::NextStep); + reaction->setNextStepId("Another step"); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" waitForTheSignalNameByTheEmitterName = \ +ktutorial.newWaitFor(\"WaitForSignal\");\n" +" waitForTheSignalNameByTheEmitterName.setSignal(\ +ktutorial.findObject(\"The \\\"emitter\\\" name\"), \ +\"\\\"theSignalName\\\"(Argument1Type, Argument2Type)\");\n" +" step.addWaitFor(waitForTheSignalNameByTheEmitterName, \"Another step\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testWaitForSignalWithoutEmitterNameOrSignalName() { Tutorial tutorial; Step* step = new Step(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |