[Ktutorial-commits] SF.net SVN: ktutorial:[164] trunk/ktutorial/ktutorial-editor
Status: Alpha
Brought to you by:
danxuliu
From: <dan...@us...> - 2010-03-19 04:46:23
|
Revision: 164 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=164&view=rev Author: danxuliu Date: 2010-03-19 04:46:11 +0000 (Fri, 19 Mar 2010) Log Message: ----------- Add JavascriptExporter to write the Javascript code used by KTutorial to create a tutorial. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/serialization/ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-16 06:24:53 UTC (rev 163) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164) @@ -2,6 +2,7 @@ # In order to work, they must be compiled using -fPIC add_definitions("-fPIC") +add_subdirectory(serialization) add_subdirectory(view) include_directories(${KDE4_INCLUDES}) @@ -24,7 +25,7 @@ # As everything but a tiny initialization code is in a library, the build system # for the tests can be easily set up. kde4_add_library(ktutorial_editor ${ktutorial_editor_SRCS}) -target_link_libraries(ktutorial_editor ktutorial_editor_view) +target_link_libraries(ktutorial_editor ktutorial_editor_serialization ktutorial_editor_view) kde4_add_executable(ktutorial-editor main.cpp) target_link_libraries(ktutorial-editor ktutorial_editor ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS}) Added: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164) @@ -0,0 +1,9 @@ +include_directories(${KDE4_INCLUDES}) + +set(ktutorial_editor_serialization_SRCS + JavascriptExporter.cpp +) + +kde4_add_library(ktutorial_editor_serialization ${ktutorial_editor_serialization_SRCS}) + +target_link_libraries(ktutorial_editor_serialization ktutorial_editor ${KDE4_LIBS}) Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt ___________________________________________________________________ Added: svn:executable + * Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-03-19 04:46:11 UTC (rev 164) @@ -0,0 +1,455 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "JavascriptExporter.h" + +#include <QRegExp> +#include <QStringList> + +#include "../Reaction.h" +#include "../Step.h" +#include "../Tutorial.h" +#include "../WaitForComposed.h" +#include "../WaitForEvent.h" +#include "../WaitForNot.h" +#include "../WaitForSignal.h" + +//public: + +JavascriptExporter::JavascriptExporter(): mIndentationLevel(0) { +} + +QString JavascriptExporter::exportTutorial(Tutorial* tutorial) { + QString code; + mOut.setString(&code); + + writeLicense(tutorial); + out() << "t = Kross.module(\"kdetranslation\");\n\n"; + writeInformation(tutorial); + writeSetup(tutorial); + writeTearDown(tutorial); + + foreach (Step* step, tutorial->steps()) { + writeStep(step); + } + + mOut.setString(0); + return code; +} + +//private: + +void JavascriptExporter::writeLicense(Tutorial* tutorial) { + if (tutorial->licenseText().isEmpty()) { + return; + } + + QStringList lines = tutorial->licenseText().split('\n'); + int maximumLineLength = 0; + foreach (QString line, lines) { + if (line.size() > maximumLineLength) { + maximumLineLength = line.size(); + } + } + + out() << "/****" << QString('*').repeated(maximumLineLength) << "****\n"; + foreach (QString line, lines) { + int numberOfSpaces = maximumLineLength - line.length(); + QString filling = QString(' ').repeated(numberOfSpaces); + out() << " * " + line + filling + " *\n"; + } + out() << " ****" << QString('*').repeated(maximumLineLength) << "****/\n\n"; +} + +void JavascriptExporter::writeInformation(Tutorial* tutorial) { + if (tutorial->name().isEmpty()) { + out() << "//Error: Tutorial without name!\n"; + } else { + out() << "tutorial.tutorialInformationAsObject().setName(t.i18n(\"" + << tutorial->name() <<"\"));\n"; + } + + if (tutorial->description().isEmpty()) { + out() << "//Error: Tutorial without description!\n"; + } else { + out() << "tutorial.tutorialInformationAsObject().setDescription(" + << "t.i18n(\"" << tutorial->description() <<"\"));\n"; + } + + mOut << "\n"; +} + +void JavascriptExporter::writeSetup(Tutorial* tutorial) { + if (tutorial->customSetupCode().isEmpty()) { + return; + } + + out() << "function tutorialSetup(tutorial) {\n"; + mIndentationLevel++; + mOut << toIndentedCode(tutorial->customSetupCode()); + mIndentationLevel--; + out() << "}\n"; + out() << "connect(tutorial, \"setup(QObject*)\",\n" + << " this, \"tutorialSetup(QObject*)\");\n\n"; +} + +void JavascriptExporter::writeTearDown(Tutorial* tutorial) { + if (tutorial->customTearDownCode().isEmpty()) { + return; + } + + out() << "function tutorialTearDown(tutorial) {\n"; + mIndentationLevel++; + mOut << toIndentedCode(tutorial->customTearDownCode()); + mIndentationLevel--; + out() << "}\n"; + out() << "connect(tutorial, \"tearDown(QObject*)\",\n" + << " this, \"tutorialTearDown(QObject*)\");\n\n"; +} + +void JavascriptExporter::writeStep(Step* step) { + if (step->id().isEmpty()) { + out() << "//Error: Step without id!\n\n"; + return; + } + + out() << "//Step " << step->id() << "\n"; + + QString stepVariable = toLowerCamelCase(step->id()) + "Step"; + out() << stepVariable << " = ktutorial.newStep(\"" << step->id() + << "\");\n"; + + if (step->text().isEmpty()) { + out() << "//Error: Step without text!\n"; + } else { + out() << stepVariable << ".setText(t.i18nc(\"@info\", \"" + << step->text() << "\"));\n"; + } + mOut << '\n'; + + writeSetup(step); + writeTearDown(step); + + out() << "tutorial.addStep(" << stepVariable << ");\n\n"; +} + +void JavascriptExporter::writeSetup(Step* step) { + if (step->customSetupCode().isEmpty() && step->reactions().count() == 0) { + return; + } + + QString stepVariable = toLowerCamelCase(step->id()) + "Step"; + out() << "function " << stepVariable << "Setup(step) {\n"; + mIndentationLevel++; + + for (int i=0; i<step->reactions().count(); ++i) { + Reaction* reaction = step->reactions()[i]; + writeReaction(step, reaction); + + if (i<step->reactions().count() - 1 || + !step->customSetupCode().isEmpty()) { + mOut << '\n'; + } + } + + mOut << toIndentedCode(step->customSetupCode()); + mIndentationLevel--; + out() << "}\n"; + out() << "connect(" << stepVariable << ", \"setup(QObject*)\",\n" + << " this, \"" << stepVariable << "Setup(QObject*)\");\n\n"; + + foreach (QString function, mPendingFunctions) { + mOut << function << '\n'; + } + mPendingFunctions.clear(); + mVariables.clear(); +} + +void JavascriptExporter::writeTearDown(Step* step) { + if (step->customTearDownCode().isEmpty()) { + return; + } + + QString stepVariable = toLowerCamelCase(step->id()) + "Step"; + out() << "function " << stepVariable << "TearDown(step) {\n"; + mIndentationLevel++; + mOut << toIndentedCode(step->customTearDownCode()); + mIndentationLevel--; + out() << "}\n"; + out() << "connect(" << stepVariable << ", \"tearDown(QObject*)\",\n" + << " this, \"" << stepVariable << "TearDown(QObject*)\");\n\n"; +} + +void JavascriptExporter::writeReaction(Step* step, Reaction* reaction) { + if (reaction->triggerType() == Reaction::ConditionMet && + !reaction->waitFor()) { + out() << "//Error: WaitFor not set!\n"; + return; + } + + if (reaction->triggerType() == Reaction::OptionSelected && + reaction->optionName().isEmpty()) { + out() << "//Error: Option without name!\n"; + return; + } + + if (reaction->responseType() == Reaction::NextStep && + reaction->nextStepId().isEmpty()) { + out() << "//Error: Next step id not set!\n"; + return; + } + + if (reaction->triggerType() == Reaction::OptionSelected && + reaction->responseType() == Reaction::NextStep) { + out() << "step.addOption(ktutorial.newOption(\"" + << reaction->optionName() << "\"), \"" << reaction->nextStepId() + << "\");\n"; + return; + } + + if (reaction->triggerType() == Reaction::OptionSelected && + reaction->responseType() == Reaction::CustomCode) { + QString functionName = toLowerCamelCase(step->id()) + "Step" + + toUpperCamelCase(reaction->optionName()) + + "OptionSelected"; + out() << "step.addOption(ktutorial.newOption(\"" + << reaction->optionName() << "\"), self, \"" << functionName + << "()\");\n"; + addFunction(functionName, reaction->customCode()); + return; + } + + QString variableName = writeWaitFor(reaction->waitFor()); + if (variableName.isEmpty()) { + return; + } + + if (reaction->responseType() == Reaction::NextStep) { + out() << "step.addWaitFor(" << variableName << ", \"" + << reaction->nextStepId() << "\");\n"; + return; + } + + QString functionName = toLowerCamelCase(step->id()) + "Step" + + toUpperCamelCase(variableName) + "ConditionMet"; + out() << "step.addWaitFor(" << variableName << ", self, \"" + << functionName << "()\");\n"; + addFunction(functionName, reaction->customCode()); +} + +QString JavascriptExporter::writeWaitFor(WaitFor* waitFor) { + if (qobject_cast<WaitForComposed*>(waitFor)) { + return writeWaitFor(static_cast<WaitForComposed*>(waitFor)); + } + if (qobject_cast<WaitForEvent*>(waitFor)) { + return writeWaitFor(static_cast<WaitForEvent*>(waitFor)); + } + if (qobject_cast<WaitForNot*>(waitFor)) { + return writeWaitFor(static_cast<WaitForNot*>(waitFor)); + } + if (qobject_cast<WaitForSignal*>(waitFor)) { + return writeWaitFor(static_cast<WaitForSignal*>(waitFor)); + } + + return ""; +} + +QString JavascriptExporter::writeWaitFor(WaitForComposed* waitForComposed) { + QString type; + if (waitForComposed->compositionType() == WaitForComposed::And) { + type = "And"; + } else if (waitForComposed->compositionType() == WaitForComposed::Or) { + type = "Or"; + } + + QStringList childVariables; + foreach (WaitFor* waitFor, waitForComposed->waitFors()) { + childVariables.append(writeWaitFor(waitFor)); + mOut << '\n'; + } + + QString variable = addVariable("waitFor" + type); + out() << variable << " = ktutorial.newWaitFor(\"WaitFor" << type + << "\");\n"; + foreach (QString childVariable, childVariables) { + if (!childVariable.isEmpty()) { + out() << variable << ".add(" << childVariable << ");\n"; + } + } + + return variable; +} + +QString JavascriptExporter::writeWaitFor(WaitForEvent* waitForEvent) { + if (waitForEvent->receiverName().isEmpty()) { + out() << "//Error: WaitForEvent without receiver name!\n"; + return ""; + } + + if (waitForEvent->eventName().isEmpty()) { + out() << "//Error: WaitForEvent without event name!\n"; + return ""; + } + + QString variable = "waitFor" + toUpperCamelCase(waitForEvent->eventName()) + + "In" + toUpperCamelCase(waitForEvent->receiverName()); + variable = addVariable(variable); + + out() << variable << " = ktutorial.newWaitFor(\"WaitForEvent\");\n"; + out() << variable << ".setEvent(ktutorial.findObject(\"" + << waitForEvent->receiverName() << "\"), \"" + << waitForEvent->eventName() << "\");\n"; + + return variable; +} + +QString JavascriptExporter::writeWaitFor(WaitForNot* waitForNot) { + if (!waitForNot->negatedWaitFor()) { + out() << "//Error: WaitForNot without negated WaitFor!\n"; + return ""; + } + + QString variable = addVariable("waitForNot"); + QString negatedVariable = writeWaitFor(waitForNot->negatedWaitFor()); + + mOut << '\n'; + out() << variable << " = ktutorial.newWaitFor(\"WaitForNot\");\n"; + if (!negatedVariable.isEmpty()) { + out() << variable << ".setNegatedWaitFor(" << negatedVariable << ");\n"; + } + + return variable; +} + +QString JavascriptExporter::writeWaitFor(WaitForSignal* waitForSignal) { + if (waitForSignal->emitterName().isEmpty()) { + out() << "//Error: WaitForSignal without emitter name!\n"; + return ""; + } + + if (waitForSignal->signalName().isEmpty()) { + out() << "//Error: WaitForSignal without signal name!\n"; + return ""; + } + + QString signalName = waitForSignal->signalName(); + signalName.remove(QRegExp("\\(.*")); + QString variable = "waitFor" + toUpperCamelCase(signalName) + + "By" + toUpperCamelCase(waitForSignal->emitterName()); + variable = addVariable(variable); + + out() << variable << " = ktutorial.newWaitFor(\"WaitForSignal\");\n"; + out() << variable << ".setSignal(ktutorial.findObject(\"" + << waitForSignal->emitterName() << "\"), \"" + << waitForSignal->signalName() << "\");\n"; + + return variable; +} + +QTextStream& JavascriptExporter::out() { + mOut << indentation(); + return mOut; +} + +QString JavascriptExporter::indentation() { + QString text; + for (int i=0; i<mIndentationLevel; ++i) { + text += " "; + } + + return text; +} + +void JavascriptExporter::addFunction(const QString& functionName, + const QString& code) { + int previousIndentationLevel = mIndentationLevel; + mIndentationLevel = 0; + + QString function; + function += "function " + functionName + "() {\n"; + mIndentationLevel++; + if (code.isEmpty()) { + function += toIndentedCode("//Error: No code set!\n"); + } else { + function += toIndentedCode(code); + } + mIndentationLevel--; + function += "}\n"; + + mPendingFunctions.append(function); + + mIndentationLevel = previousIndentationLevel; +} + +QString JavascriptExporter::addVariable(const QString& variable) { + if (!mVariables.contains(variable)) { + mVariables.insert(variable, 1); + return variable; + } + + mVariables.insert(variable, mVariables.value(variable) + 1); + return variable + QString().setNum(mVariables.value(variable)); +} + +QString JavascriptExporter::toIndentedCode(const QString& code) { + if (code.isEmpty()) { + return ""; + } + + QString indentedCode; + + QStringList lines = code.split('\n'); + for (int i=0; i<lines.count()-1; ++i) { + indentedCode += indentation() + lines[i] + '\n'; + } + + //If the code ends with '\n', the splitted code will contain an empty end + //element that should be ignored + if (!code.endsWith('\n')) { + indentedCode += indentation() + lines[lines.count()-1] + '\n'; + } + + return indentedCode; +} + +QString JavascriptExporter::toLowerCamelCase(const QString& text) const { + if (text.isEmpty()) { + return ""; + } + + QString lowerCamelCase = toUpperCamelCase(text); + lowerCamelCase[0] = lowerCamelCase[0].toLower(); + + return lowerCamelCase; +} + +QString JavascriptExporter::toUpperCamelCase(const QString& text) const { + if (text.isEmpty()) { + return ""; + } + + QStringList words = text.split(' ', QString::SkipEmptyParts); + + QString upperCamelCase; + for (int i=0; i<words.count(); ++i) { + words[i][0] = words[i][0].toUpper(); + upperCamelCase += words[i]; + } + + return upperCamelCase; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-03-19 04:46:11 UTC (rev 164) @@ -0,0 +1,292 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef JAVASCRIPTEXPORTER_H +#define JAVASCRIPTEXPORTER_H + +#include <QHash> +#include <QStringList> +#include <QTextStream> + +class Reaction; +class Step; +class Tutorial; +class WaitFor; +class WaitForComposed; +class WaitForEvent; +class WaitForNot; +class WaitForSignal; + +/** + * Exporter of tutorials to Javascript code. + * The generated Javascript code can be read by KTutorial from a tutorial script + * file to create and initialize a KTutorial::Tutorial from it. + * + * The general structure of the code is: + * -License (if any) + * -Tutorial information + * -Tutorial setup (if any) + * -Tutorial tear down (if any) + * -Steps + * + * For each step, the following structure is used: + * -Step initialization (id and text) + * -Step setup + * -Reactions (if any) + * -Custom setup code (if any) + * -Functions for each custom code response in the reactions (if any) + * -Step tear down (if any) + * + * If some necessary data is missing (for example, the id in a step), a comment + * explaining the error is written instead of the code for that element. + */ +class JavascriptExporter { +public: + + /** + * Creates a new JavascriptExporter. + */ + JavascriptExporter(); + + /** + * Exports the tutorial to Javascript code. + * + * @param tutorial The tutorial to export. + * @return The Javascript code. + */ + QString exportTutorial(Tutorial* tutorial); + +private: + + /** + * The text stream to write the Javascript code to. + */ + QTextStream mOut; + + /** + * The full code for the functions pending to be written. + */ + QStringList mPendingFunctions; + + /** + * Register for variable names and the number of times that it was used. + */ + QHash<QString, int> mVariables; + + /** + * The curren indentation level. + * Increment and decrement it when entering and exiting a code block. + */ + int mIndentationLevel; + + /** + * Writes the commented license text. + * Nothing is written if there is no license. + * + * @param tutorial The tutorial to write its license. + */ + void writeLicense(Tutorial* tutorial); + + /** + * Writes the name and description code of a tutorial. + * An error message is written if the name or the tutorial is missing. + * + * @param tutorial The tutorial to write its name and description code. + */ + void writeInformation(Tutorial* tutorial); + + /** + * Writes the setup function of a tutorial and its custom code. + * Nothing is written if there is no setup code. + * + * @param tutorial The tutorial to write its setup function. + */ + void writeSetup(Tutorial* tutorial); + + /** + * Writes the tear down function of a tutorial and its custom code. + * Nothing is written if there is no tear down code. + * + * @param tutorial The tutorial to write its tear down function. + */ + void writeTearDown(Tutorial* tutorial); + + /** + * Writes the full code (step creation, setup, tear down and adding to the + * tutorial) of a step. + * If the step id isn't set, an error message is written instead. + * + * @param step The step to write its code. + */ + void writeStep(Step* step); + + /** + * Writes the setup code (including setting up reactions) of a Step. + * Nothing is written if there is no custom setup code and no reactions. + * + * After the setup code all the pending functions added by custom code + * responses in reactions are written. + * + * @param step The step to write its setup code. + */ + void writeSetup(Step* step); + + /** + * Writes the tear down code of a Step. + * Nothing is written if there is no tear down code. + * + * @param step The step to write its tear down code. + */ + void writeTearDown(Step* step); + + /** + * Writes the reaction code. + * An error message is written if the WaitFor, the option name or the next + * step id is not set (and the trigger/response type needed them). + * + * @param step The step that the reaction is part of. + * @param reaction The reaction to write its code. + */ + void writeReaction(Step* step, Reaction* reaction); + + /** + * Writes the code to create and set a WaitFor. + * + * @param waitFor The WaitFor. + * @return The name of the variable that holds the WaitFor, or an empty + * string if the WaitFor data is invalid. + */ + QString writeWaitFor(WaitFor* waitFor); + + /** + * Writes the code to create and set a WaitForComposed. + * The code for the child WaitFors is added before the code for the + * WaitForComposed. + * + * @param waitForComposed The WaitForComposed. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(WaitForComposed* waitForComposed); + + /** + * Writes the code to create and set a WaitForEvent. + * If the receiver name or the event name aren't set, an error message is + * written instead, and an empty string returned. + * + * @param waitForEvent The WaitForEvent. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(WaitForEvent* waitForEvent); + + /** + * Writes the code to create and set a WaitForNot. + * If the negated WaitFor isn't set, an error message is written instead, + * and an empty string returned. + * + * @param waitForNot The WaitForNot. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(WaitForNot* waitForNot); + + /** + * Writes the code to create and set a WaitForSignal. + * If the emitter name or the signal name aren't set, an error message is + * written instead, and an empty string returned. + * + * @param waitForSignal The WaitForSignal. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(WaitForSignal* waitForSignal); + + /** + * Returns the output stream after adding the identation text. + * It is used as a shortcut to "mOut << indentation()". Use it to output any + * line that has no previous indentation. + * + * Use mOut directly to output empty new lines, pending functions, or code + * returned by indentedText + * + * @return The output stream. + */ + QTextStream& out(); + + /** + * Returns the current indentation text. + * Each level of indentation are four blank spaces. + * + @return The current indentation text. + */ + QString indentation(); + + /** + * Adds a new function to mPendingFunctions. + * The body will be automatically indented. + * + * It is used to queue the writting of functions with custom code specified + * in reactions, as reactions are written into the setup function of its + * step. + * + * @param functionName The name of the function. + * @param code The body of the function. + */ + void addFunction(const QString& functionName, const QString& code); + + /** + * Returns a unique variable name for the given variable name. + * The same variable name may be used by several WaitFors in the same step + * setup (for example, two WaitForAnd would have the same variable name). + * When a variable is added, it is ensured that there are no other variables + * with the same name. If there are, a fixed unique variable name is + * returned. + * + * The register of variables must be cleared after exiting the step setup + * generation to avoid unneeded renaming of variables in other step setups. + * + * @param variable The variable to add. + * @return The unique variable name. + */ + QString addVariable(const QString& variable); + + /** + * Returns the same code, but with each line indented and ending in a new + * line. + * + * @param code The code to indent. + * @return The indented code. + */ + QString toIndentedCode(const QString& code); + + /** + * Returns the lowerCamelCase version of the given text. + * + * @param text The string to get its lowerCamelCase version. + * @return The lowerCamelCase version of the text. + */ + QString toLowerCamelCase(const QString& text) const; + + /** + * Returns the UpperCamelCase version of the given text. + * + * @param text The string to get its UpperCamelCase version. + * @return The UpperCamelCase version of the text. + */ + QString toUpperCamelCase(const QString& text) const; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-16 06:24:53 UTC (rev 163) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164) @@ -1,3 +1,4 @@ +add_subdirectory(serialization) add_subdirectory(view) # Used by kde4_add_unit_test to set the full path to test executables Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164) @@ -0,0 +1,26 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${ktutorial-editor_SOURCE_DIR}/src/serialization ${ktutorial-editor_BINARY_DIR}/src/serialization ${KDE4_INCLUDES}) + +MACRO(UNIT_TESTS) + FOREACH(_className ${ARGN}) + set(_testName ${_className}Test) + kde4_add_unit_test(${_testName} TESTNAME ktutorial-editor-unit-${_testName} ${_testName}.cpp) + target_link_libraries(${_testName} ktutorial_editor ktutorial_editor_serialization ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + JavascriptExporter +) + +MACRO(MEM_TESTS) + FOREACH(_testname ${ARGN}) + add_test(ktutorial-editor-unit-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) + ENDFOREACH(_testname) +ENDMACRO(MEM_TESTS) + +mem_tests( + JavascriptExporter +) Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt ___________________________________________________________________ Added: svn:executable + * Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-03-19 04:46:11 UTC (rev 164) @@ -0,0 +1,1167 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "JavascriptExporter.h" + +#include "../Reaction.h" +#include "../Step.h" +#include "../Tutorial.h" +#include "../WaitForComposed.h" +#include "../WaitForEvent.h" +#include "../WaitForNot.h" +#include "../WaitForSignal.h" + +#define TUTORIAL_EMPTY_INFORMATION_CODE \ +"t = Kross.module(\"kdetranslation\");\n"\ +"\n"\ +"//Error: Tutorial without name!\n"\ +"//Error: Tutorial without description!\n"\ +"\n" + +#define STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE \ +"//Step The id\n"\ +"theIdStep = ktutorial.newStep(\"The id\");\n"\ +"//Error: Step without text!\n"\ +"\n" + +#define CONNECT_STEP_SETUP \ +"connect(theIdStep, \"setup(QObject*)\",\n"\ +" this, \"theIdStepSetup(QObject*)\");\n"\ +"\n" + +#define STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE \ +"tutorial.addStep(theIdStep);\n"\ +"\n" + +class JavascriptExporterTest: public QObject { +Q_OBJECT + +private slots: + + void testTutorialLicense(); + void testTutorialInformation(); + void testTutorialSetupCode(); + void testTutorialTearDownCode(); + void testTutorialWithSeveralSteps(); + + void testStep(); + void testStepSetupCode(); + void testStepSetupCodeWithReactions(); + void testStepTearDownCode(); + void testStepWithoutId(); + void testStepWithSeveralReactions(); + + void testReactionOptionNextStep(); + void testReactionOptionNextStepWithoutOptionNameOrStepId(); + void testReactionOptionCustomCode(); + void testReactionOptionCustomCodeWithoutOptionNameOrCustomCode(); + void testReactionConditionNextStep(); + void testReactionConditionNextStepWithoutConditionOrStepId(); + void testReactionConditionCustomCode(); + void testReactionConditionCustomCodeWithoutConditionOrCustomCode(); + + void testWaitForEvent(); + void testWaitForEventWithoutReceiverNameOrEventName(); + void testWaitForSignal(); + void testWaitForSignalWithoutEmitterNameOrSignalName(); + void testWaitForComposed(); + void testWaitForComposedWithInvalidChildWaitFor(); + void testWaitForNot(); + void testWaitForNotWithInvalidNegatedWaitFor(); + void testWaitForNotWithoutNegatedWaitFor(); + +}; + +void JavascriptExporterTest::testTutorialLicense() { + Tutorial tutorial; + tutorial.setLicenseText("The license text, which should be\nwrapped"); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +"/*****************************************\n" +" * The license text, which should be *\n" +" * wrapped *\n" +" *****************************************/\n" +"\n" +TUTORIAL_EMPTY_INFORMATION_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testTutorialInformation() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + 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 description\"));\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testTutorialSetupCode() { + Tutorial tutorial; + tutorial.setCustomSetupCode("The custom setup\ncode"); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +"function tutorialSetup(tutorial) {\n" +" The custom setup\n" +" code\n" +"}\n" +"connect(tutorial, \"setup(QObject*)\",\n" +" this, \"tutorialSetup(QObject*)\");\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testTutorialTearDownCode() { + Tutorial tutorial; + tutorial.setCustomTearDownCode("The custom tear down\ncode"); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +"function tutorialTearDown(tutorial) {\n" +" The custom tear down\n" +" code\n" +"}\n" +"connect(tutorial, \"tearDown(QObject*)\",\n" +" this, \"tutorialTearDown(QObject*)\");\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testTutorialWithSeveralSteps() { + Tutorial tutorial; + + Step* step1 = new Step(); + step1->setId("The id1"); + step1->setText("The text1"); + tutorial.addStep(step1); + + WaitForSignal* waitForSignal1 = new WaitForSignal(); + waitForSignal1->setEmitterName("The emitter name"); + waitForSignal1->setSignalName("theSignalName(Argument1Type)"); + + Reaction* reaction1 = new Reaction(); + reaction1->setTriggerType(Reaction::ConditionMet); + reaction1->setWaitFor(waitForSignal1); + reaction1->setResponseType(Reaction::CustomCode); + reaction1->setCustomCode("The custom\ncode1"); + step1->addReaction(reaction1); + + Step* step2 = new Step(); + step2->setId("The id2"); + step2->setText("The text2"); + tutorial.addStep(step2); + + WaitForSignal* waitForSignal2 = new WaitForSignal(); + waitForSignal2->setEmitterName("The emitter name"); + waitForSignal2->setSignalName("theSignalName(Argument1Type)"); + + Reaction* reaction2 = new Reaction(); + reaction2->setTriggerType(Reaction::ConditionMet); + reaction2->setWaitFor(waitForSignal2); + reaction2->setResponseType(Reaction::CustomCode); + reaction2->setCustomCode("The custom\ncode2"); + step2->addReaction(reaction2); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +"//Step The id1\n" +"theId1Step = ktutorial.newStep(\"The id1\");\n" +"theId1Step.setText(t.i18nc(\"@info\", \"The text1\"));\n" +"\n" +"function theId1StepSetup(step) {\n" +" waitForTheSignalNameByTheEmitterName = \ +ktutorial.newWaitFor(\"WaitForSignal\");\n" +" waitForTheSignalNameByTheEmitterName.setSignal(\ +ktutorial.findObject(\"The emitter name\"), \ +\"theSignalName(Argument1Type)\");\n" +" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \ +\"theId1StepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n" +"}\n" +"connect(theId1Step, \"setup(QObject*)\",\n" +" this, \"theId1StepSetup(QObject*)\");\n" +"\n" +"function theId1StepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n" +" The custom\n" +" code1\n" +"}\n" +"\n" +"tutorial.addStep(theId1Step);\n" +"\n" +"//Step The id2\n" +"theId2Step = ktutorial.newStep(\"The id2\");\n" +"theId2Step.setText(t.i18nc(\"@info\", \"The text2\"));\n" +"\n" +"function theId2StepSetup(step) {\n" +" waitForTheSignalNameByTheEmitterName = \ +ktutorial.newWaitFor(\"WaitForSignal\");\n" +" waitForTheSignalNameByTheEmitterName.setSignal(\ +ktutorial.findObject(\"The emitter name\"), \ +\"theSignalName(Argument1Type)\");\n" +" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \ +\"theId2StepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n" +"}\n" +"connect(theId2Step, \"setup(QObject*)\",\n" +" this, \"theId2StepSetup(QObject*)\");\n" +"\n" +"function theId2StepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n" +" The custom\n" +" code2\n" +"}\n" +"\n" +"tutorial.addStep(theId2Step);\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStep() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + step->setText("The text"); + 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 text\"));\n" +"\n" +"tutorial.addStep(theIdStep);\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStepSetupCode() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + step->setCustomSetupCode("The custom setup\ncode"); + tutorial.addStep(step); + + 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" +" The custom setup\n" +" code\n" +"}\n" +"connect(theIdStep, \"setup(QObject*)\",\n" +" this, \"theIdStepSetup(QObject*)\");\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStepSetupCodeWithReactions() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + step->setCustomSetupCode("The custom setup\ncode"); + 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" +" The custom setup\n" +" code\n" +"}\n" +"connect(theIdStep, \"setup(QObject*)\",\n" +" this, \"theIdStepSetup(QObject*)\");\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStepTearDownCode() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + step->setCustomTearDownCode("The custom tear down\ncode"); + tutorial.addStep(step); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepTearDown(step) {\n" +" The custom tear down\n" +" code\n" +"}\n" +"connect(theIdStep, \"tearDown(QObject*)\",\n" +" this, \"theIdStepTearDown(QObject*)\");\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStepWithoutId() { + Tutorial tutorial; + Step* step = new Step(); + step->setText("The text"); + step->setCustomSetupCode("The custom setup\ncode"); + step->setCustomTearDownCode("The custom tear down\ncode"); + 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 +"//Error: Step without id!\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStepWithSeveralReactions() { + 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)"); + + Reaction* reaction1 = new Reaction(); + reaction1->setTriggerType(Reaction::ConditionMet); + reaction1->setWaitFor(waitForSignal); + reaction1->setResponseType(Reaction::CustomCode); + reaction1->setCustomCode("The custom\ncode1"); + step->addReaction(reaction1); + + Reaction* reaction2 = new Reaction(); + reaction2->setTriggerType(Reaction::OptionSelected); + reaction2->setOptionName("The option name"); + reaction2->setResponseType(Reaction::CustomCode); + reaction2->setCustomCode("The custom\ncode2"); + step->addReaction(reaction2); + + 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)\");\n" +" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \ +\"theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n" +"\n" +" step.addOption(ktutorial.newOption(\"The option name\"), self, \ +\"theIdStepTheOptionNameOptionSelected()\");\n" +"}\n" +CONNECT_STEP_SETUP +"function theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n" +" The custom\n" +" code1\n" +"}\n" +"\n" +"function theIdStepTheOptionNameOptionSelected() {\n" +" The custom\n" +" code2\n" +"}\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testReactionOptionNextStep() { + 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; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::OptionSelected); + reaction->setResponseType(Reaction::NextStep); + 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" +" //Error: Option without name!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); + + reaction->setOptionName("The option name"); + + exportedTutorial = exporter.exportTutorial(&tutorial); + + expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" //Error: Next step id not set!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testReactionOptionCustomCode() { + 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; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::OptionSelected); + reaction->setResponseType(Reaction::CustomCode); + 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" +" //Error: Option without name!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); + + reaction->setOptionName("The option name"); + + exportedTutorial = exporter.exportTutorial(&tutorial); + + 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" +" //Error: No code set!\n" +"}\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testReactionConditionNextStep() { + 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(); + step->setId("The id"); + tutorial.addStep(step); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setResponseType(Reaction::NextStep); + 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" +" //Error: WaitFor not set!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); + + WaitForSignal* waitForSignal = new WaitForSignal(); + waitForSignal->setEmitterName("The emitter name"); + waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)"); + reaction->setWaitFor(waitForSignal); + + exportedTutorial = exporter.exportTutorial(&tutorial); + + expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" //Error: Next step id not set!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testReactionConditionCustomCode() { + 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(); + step->setId("The id"); + tutorial.addStep(step); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setResponseType(Reaction::CustomCode); + 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" +" //Error: WaitFor not set!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); + + WaitForSignal* waitForSignal = new WaitForSignal(); + waitForSignal->setEmitterName("The emitter name"); + waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)"); + reaction->setWaitFor(waitForSignal); + + exportedTutorial = exporter.exportTutorial(&tutorial); + + 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" +" //Error: No code set!\n" +"}\n" +"\n" +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testWaitForEvent() { + 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(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForEvent* waitForEvent = new WaitForEvent(); + + 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" +" //Error: WaitForEvent without receiver name!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); + + waitForEvent->setReceiverName("The receiver name"); + + exportedTutorial = exporter.exportTutorial(&tutorial); + + expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" //Error: WaitForEvent without event name!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testWaitForSignal() { + 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.e... [truncated message content] |