diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/tests/altertable | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/tests/altertable')
-rw-r--r-- | kexi/tests/altertable/1.kexi | bin | 0 -> 49150 bytes | |||
-rw-r--r-- | kexi/tests/altertable/Makefile.am | 22 | ||||
-rw-r--r-- | kexi/tests/altertable/README | 200 | ||||
-rw-r--r-- | kexi/tests/altertable/TODO | 3 | ||||
-rw-r--r-- | kexi/tests/altertable/alltypes.altertable | 109 | ||||
-rw-r--r-- | kexi/tests/altertable/altertable.cpp | 716 | ||||
-rw-r--r-- | kexi/tests/altertable/altertable.h | 63 | ||||
-rw-r--r-- | kexi/tests/altertable/defaultvalues.altertable | 129 |
8 files changed, 1242 insertions, 0 deletions
diff --git a/kexi/tests/altertable/1.kexi b/kexi/tests/altertable/1.kexi Binary files differnew file mode 100644 index 00000000..1165d90e --- /dev/null +++ b/kexi/tests/altertable/1.kexi diff --git a/kexi/tests/altertable/Makefile.am b/kexi/tests/altertable/Makefile.am new file mode 100644 index 00000000..a2389007 --- /dev/null +++ b/kexi/tests/altertable/Makefile.am @@ -0,0 +1,22 @@ +include $(top_srcdir)/kexi/Makefile.global + +noinst_PROGRAMS = kexialtertabletest + +INCLUDES = -I$(top_srcdir)/kexi \ + -I$(top_srcdir)/kexi/widget \ + -I$(top_srcdir)/kexi/core \ + -I$(top_srcdir)/lib \ + $(all_includes) + +SUBDIRS = . + +METASOURCES = AUTO + +kexialtertabletest_SOURCES = altertable.cpp +kexialtertabletest_LDADD = $(LIB_QT) $(LIB_KDECORE) $(top_builddir)/kexi/kexidb/libkexidb.la \ + $(top_builddir)/kexi/kexiutils/libkexiutils.la \ + $(top_builddir)/kexi/main/libkeximain.la \ + $(top_builddir)/kexi/kexidb/parser/libkexidbparser.la \ + $(top_builddir)/kexi/widget/libkexiextendedwidgets.la +kexialtertabletest_LDFLAGS = $(all_libraries) $(KDE_RPATH) + diff --git a/kexi/tests/altertable/README b/kexi/tests/altertable/README new file mode 100644 index 00000000..1278a54d --- /dev/null +++ b/kexi/tests/altertable/README @@ -0,0 +1,200 @@ +=================================================== + README for the "altertable" test + Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl> +=================================================== + + +Invoking +-------- +"altertable" test requires <db_name>, <driver_name> and <alterscript> arguments + +The purpose of .altertable files +-------------------------------- +.altertable files are provoded to test a given use case of table altering. +It contains a set of commands mapped to a sequence of ALTER TABLE and other +SQL statements. The commands are mapped to AlterTableHandler::***Action objects, +what is equat to actions performed by the user during the table designing. + +Second purpose of the test is testing the Table Designer's GUI itself. +Whenever there is a bug in a the GUI, e.g. in the property editor, +the resulting schema can differ from expected, or there can be even a crash. +The suite already helped to find a few bugs in the GUI code. + + +How the test is performed, .alterscript file contents +----------------------------------------------------- + +The file can be consisted of many sections described below. The test can be built by: +a. requesting a table design to be opened in the Table designer, +b. specifying commands affecting the design, +c. then checking the actions sequence genrated by the "alter table machinery" + (it's a method that allocates AlterTableHandler::***Action objects and add them + using AlterTableHandler::addAction() to the alte table machinery. + The result is the same as user's actions); +d. then saving the design, +e. and finally checking the table data with the expected table contents. +Every comparison is performed line by line: obtained result is compared with expected one. + +2. Expected result of altering the table. + It's a full human-redable dump of table schema and its contents. + +Each section has a strictly defined format, so the test suite can combine commands into more complex sets. + + +Available commands of the test suite +------------------------------------ + +1. Top-level commands + +* openDatabase <filename> + Opens kexi database for tests. In fact the file is copied to a temporary file (with .tmp suffix) + and we're dealing with the copy, so the original could not be broken. Thus, tests can be reproduced. +#TODO: support server databases + Example use: openDatabase 1.kexi + +* designTable <tablename> \n <block> \n endDesign + Opens table in design mode. <block> contains one or more schema altering + commands described in 2. + +2. Commands for altering table fields (during the design mode, within "designTable" command): + +* insertField <rownumber(int)> <fieldname(string)> + Inserts a new table field with default properties (text type) and 'fieldname' name. + Note that the inserted field can *replace* an existing field. To avoid this, use + insertEmptyRow command before insertField to add an empty row. + Example use: insertField 2 abc + +* insertEmptyRow <rownumber(int)> + Inserts empty row before 'rownumber'. Rows below are moved down. + Example use: insertEmptyRow 2 + +* removeField <rownumber(int)> + Removes a table field at a specified row. + Example use: removeField 1 + +* changeFieldProperty <rownumber(int)> <propertyname(string)> <valuetype(string)> <value(string)> + Changes property of table field at a specified row. + 'valuetype' can be int, string, bool, double/float, bool/boolean, data, dateTime, time, + bytearray, longlong. + <value(string)> should be a string representation of the value. Special cases are: + byteArray: hexadecimal string like 'fd1a5c', dateTime: yyyy-mm-ddThh:mm:ss string + like '2005-11-05T12:34:56'. + Null values should be specified as <null> string. Empty string values should be specified as "". + 'type' property means a field datatype, where value can be any of the names + in KexiDB::Field::Type enum, written as string, e.g. "integer","text", "date", etc. + Example use: changeFieldProperty 1 type string date + +* i++ + Increases "i" variable by 1. This integer variable is initialized to 1 before test is executed. + Can be used as an argument for <rownumber(int)> for above field-related commands. + +* i=<number(int)> + Sets "i" variable to <number(int)>. + Example use: shows that using the variable instead of constants allows to insert + a command without a need for managing subsequent arguments. + i=3 + removeField i + insertField i textField + changeFieldProperty i type string text + i++ #i is now 4 + insertField i longTextField + changeFieldProperty i type string longText + +3. Commands related to altered (not saved) table schema: + +* showSchema [clipboard] + Shows schema dump as returned by KexiTableDesignerInterface::debugStringForCurrentTableSchema(). + Useful for creating "checkSchema" checks: Just paste the output to the test file. + You can use "clipboard" word to copy prepare the schema dump to clipboard. + +* checkSchema \n <block> \n endSchema + Checks validity of the not yet saved schema altered in the Table Designer using the + actions listed in p. 1. The <block> should end with "endSchema" line. + Between these lines there should be pasted a <block> - exact textual schema dump as returned + by KexiTableDesignerInterface::debugStringForCurrentTableSchema(). + The check compares lines returned from the Designer with the lines you provided, line by line. + You can use "showSchema" command to display the expected schema to the stderr and copy the text. + Every line contains up to three main sections <fieldname> <type> [<constraints>]. + The lines can be indented - trailing and leading whitespaces are ignored in comparison. + Example use: + checkSchema + textfield Text(200) + owner UNSIGNED Integer + booleanfield Boolean NOTNULL + endSchema + +4. Commands related to simplified list of Alter Table actions (simulated, before real saving): + +* showActions [clipboard] + Shows the list of simplified Alter Table actions that are result of commands related to table fields, + mentioned in 1. + You can use "clipboard" word to copy prepare the expected actions dump to clipboard. + +* checkActions \n <block> \n endActions + Checks validity of the list of simplified Alter Table actions. + The <block> should end with "endActions" line. + The check compares lines returned from the Designer with the lines you provided as <block>, line by line. + Textual dump of actions is obtained from KexiTableDesignerInterface::simulateAlterTableExecution(). + Every line contains section(s): <actionname> [(<fielddebugstring>)]. + Example use: + checkActions + Insert table field "textfield" at position 1 (textfield Text(200)) + Remove table field "model" + Insert table field "longtextfield" at position 3 (longtextfield Text(200)) + endActions + +5. Commands related to physical schema saving (altering) and checking its result + +* saveTableDesign + Executes the final Alter Table function. Table design will be altered and data should + be preserved. After this command it is usable to run "checkTableData" test to see + whether the data looks as expected. + +* showTableData [clipboard] + Shows current table contents in tab-separated CSV format (one row per record) + on the stderr; text is encoded in utf-8. The data is printed to the stderr. + If optional "clipboard" word is present, the data is copied to clipboard instead. + Table dumps can be sometimes large and hard to prepare by hand, so you can use + "clipboard" word to prepare the expected table dump by pasting the text to + a .altertable file. + For details about the output format in the description "checkTableData". + +* checkTableData \n <block> \n endTableData + Compares the current contents of table with expected contents, line by line. + The data has to be in tab-separated CSV format (one row per record); + text has to be encoded in utf-8 and enclosed in " quotes. + Column names should be included as a first row. + You can use showTableData command first and then copy the results to your test file for later. + Example use: + checkTableData + ID Name Surname + 1 John Wayne + 2 Al Pacino + endTableData + +6. Other commands. + +* closeWindow + Closes the currently opened table designer window without asking for saving changes. + +* stop + Stops processing immediately. For example, this can be inserted temporarily to stop testing + (with success result). This command is available in any place. + +* quit + Executes "closeWindow" command and quits the application (with success result). + +6. Comments + +Comments can be inserted by adding # on the left hand as in bash shell +or using /* and */ for multiple rows. Empty rows are ignored. + + +The result of executing the "altertable" test +--------------------------------------------- + +On errors, kexialtertabletest program will show an appropriate error message with line number +where the error encountered and stop executing the tests. + +A given "checkSchema" command should result in "Schema check for table 'foo': OK" message. +Entire test from a give .altertable file 'foo' should end with "Tests from file 'foo': OK" message. diff --git a/kexi/tests/altertable/TODO b/kexi/tests/altertable/TODO new file mode 100644 index 00000000..f54a4b50 --- /dev/null +++ b/kexi/tests/altertable/TODO @@ -0,0 +1,3 @@ +TODOs for the "altertable" test + +- support server databases diff --git a/kexi/tests/altertable/alltypes.altertable b/kexi/tests/altertable/alltypes.altertable new file mode 100644 index 00000000..70435a60 --- /dev/null +++ b/kexi/tests/altertable/alltypes.altertable @@ -0,0 +1,109 @@ +openDatabase 1.kexi + +/* + This test checks: + - creating table fields of all possible types + - adding new fields to the table with preserving the original content + Additionally: + - as "booleanField" field is type of bool, and by default + it is declared as NOT NULL, values for it are filled with "false". + - 3rd (original) field is removed before adding new fields + + Used tables: cars +*/ +designTable cars + i=3 + removeField i + insertField i textField + changeFieldProperty i type string text + i++ + insertField i longTextField + changeFieldProperty i type string longText + i++ + insertField i byteField + changeFieldProperty i type string byte + i++ + insertField i shortIntField + changeFieldProperty i type string shortInteger + i++ + insertField i intField + changeFieldProperty i type string integer + i++ + insertField i bigIntField + changeFieldProperty i type string bigInteger + i++ + insertField i booleanField + changeFieldProperty i type string boolean + i++ + insertField i dateField + changeFieldProperty i type string date + i++ + insertField i dateTimeField + changeFieldProperty i type string dateTime + i++ + insertField i timeField + changeFieldProperty i type string time + i++ + insertField i floatField + changeFieldProperty i type string float + i++ + insertField i doubleField + changeFieldProperty i type string double + i++ + insertField i blobField + changeFieldProperty i type string blob +endDesign + + showSchema + + checkSchema + id UNSIGNED Integer AUTOINC UNIQUE PKEY NOTNULL NOTEMPTY + owner UNSIGNED Integer + textfield Text(200) + longtextfield LongText + bytefield Byte + shortintfield ShortInteger + intfield Integer + bigintfield BigInteger + booleanfield Boolean NOTNULL DEFAULT=[bool]false + datefield Date + datetimefield DateTime + timefield Time + floatfield Float + doublefield Double + blobfield BLOB + endSchema + + showActions + + checkActions + Remove table field "model" + Insert table field "textfield" at position 2 (textfield Text(200)) + Insert table field "longtextfield" at position 3 (longtextfield LongText) + Insert table field "bytefield" at position 4 (bytefield Byte) + Insert table field "shortintfield" at position 5 (shortintfield ShortInteger) + Insert table field "intfield" at position 6 (intfield Integer) + Insert table field "bigintfield" at position 7 (bigintfield BigInteger) + Insert table field "booleanfield" at position 8 (booleanfield Boolean NOTNULL DEFAULT=[bool]false) + Insert table field "datefield" at position 9 (datefield Date) + Insert table field "datetimefield" at position 10 (datetimefield DateTime) + Insert table field "timefield" at position 11 (timefield Time) + Insert table field "floatfield" at position 12 (floatfield Float) + Insert table field "doublefield" at position 13 (doublefield Double) + Insert table field "blobfield" at position 14 (blobfield BLOB) + endActions + + saveTableDesign #executes Alter Table + + showTableData clipboard + stop + + checkTableData +"ID" "Car owner" "textField" "longTextField" "byteField" "shortIntField" "intField" "bigIntField" "booleanField" "dateField" "dateTimeField" "timeField" "floatField" "doubleField" "blobField" +1 2 false +2 2 false +3 3 false +5 4 false +6 3 false + endTableData + diff --git a/kexi/tests/altertable/altertable.cpp b/kexi/tests/altertable/altertable.cpp new file mode 100644 index 00000000..bf14bc00 --- /dev/null +++ b/kexi/tests/altertable/altertable.cpp @@ -0,0 +1,716 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "altertable.h" + +#include <unistd.h> + +#include <qapplication.h> +#include <qfile.h> +#include <qdir.h> +#include <qregexp.h> +#include <qclipboard.h> + +#include <kdebug.h> + +#include <main/keximainwindowimpl.h> +#include <core/kexiaboutdata.h> +#include <core/kexidialogbase.h> +#include <core/kexiviewbase.h> +#include <core/kexipartitem.h> +#include <core/kexitabledesignerinterface.h> +#include <core/kexiinternalpart.h> +#include <kexiutils/utils.h> +#include <koproperty/set.h> +#include <kexidb/connection.h> +#include <kexidb/utils.h> + +QString testFilename; +QFile testFile; +QTextStream testFileStream; +QStringList testFileLine; +uint testLineNumber = 0; +QString origDbFilename, dbFilename; +int variableI = 1; // simple variable 'i' support +int newArgc; +char** newArgv; +KexiMainWindowImpl* win = 0; +KexiProject* prj = 0; + +void showError(const QString& msg) +{ + QString msg_(msg); + msg_.prepend(QString("Error at line %1: ").arg(testLineNumber)); + kdDebug() << msg_ << endl; +} + +/* Reads a single line from testFileStream, fills testFileLine, updates testLineNumber + text in quotes is extracted, e.g. \"ab c\" is treat as one item "ab c" + Returns flas on failure (e.g. end of file). + Empty lines and lines or parts of lines with # (comments) are omitted. */ +tristate readLineFromTestFile(const QString& expectedCommandName = QString::null) +{ + QString s; + bool blockComment = false; + while (true) { + if (testFileStream.atEnd()) + return cancelled; + testLineNumber++; + s = testFileStream.readLine().stripWhiteSpace(); + if (blockComment) { + if (s.endsWith("*/")) + blockComment = false; + continue; + } + if (!blockComment && s.startsWith("/*")) { + blockComment = true; + continue; + } + if (s.startsWith("#")) + continue; //skip commented line + if (!s.isEmpty()) + break; + } + s.append(" "); //sentinel + QString item; + testFileLine.clear(); + const int len = s.length(); + bool skipWhiteSpace = true, quoted = false; + for (int i=0; i<len; i++) { + const QChar ch( s.ref(i) ); + if (skipWhiteSpace) { + if (ch=='#') + break; //eoln + if (ch==' ' || ch=='\t') + continue; + skipWhiteSpace = false; + if (ch=='\"') { + quoted = true; + continue; + } + item.append(ch); + } + else { + if ((quoted && ch=='\"') || (!quoted && (ch==' ' || ch=='\t'))) { //end of item + skipWhiteSpace = true; + quoted = false; + testFileLine.append( item ); + item = QString::null; + continue; + } + item.append(ch); + } + } + if (!expectedCommandName.isEmpty() && testFileLine[0]!=expectedCommandName) { + showError( QString("Invalid command '%1', expected '%2'") + .arg(testFileLine[0]).arg(expectedCommandName)); + return false; + } + if (quoted) { + showError( "Invalid contents" ); + return false; + } + return true; +} + +bool checkItemsNumber(int expectedNumberOfItems, int optionalNumberOfItems = -1) +{ + bool ok = expectedNumberOfItems==(int)testFileLine.count(); + if (optionalNumberOfItems>0) + ok = ok || optionalNumberOfItems==(int)testFileLine.count(); + if (!ok) { + QString msg = QString("Invalid number of args (%1) for command '%2', expected: %3") + .arg(testFileLine.count()).arg(testFileLine[0]).arg(expectedNumberOfItems); + if (optionalNumberOfItems>0) + msg.append( QString(" or %1").arg(optionalNumberOfItems) ); + showError( msg ); + return false; + } + return true; +} + +QVariant::Type typeNameToQVariantType(const QCString& name_) +{ + QCString name( name_.lower() ); + if (name=="string") + return QVariant::String; + if (name=="int") + return QVariant::Int; + if (name=="bool" || name=="boolean") + return QVariant::Bool; + if (name=="double" || name=="float") + return QVariant::Double; + if (name=="date") + return QVariant::Date; + if (name=="datetime") + return QVariant::DateTime; + if (name=="time") + return QVariant::Time; + if (name=="bytearray") + return QVariant::ByteArray; + if (name=="longlong") + return QVariant::LongLong; +//todo more types + showError(QString("Invalid type '%1'").arg(name_)); + return QVariant::Invalid; +} + +// casts string to QVariant +bool castStringToQVariant( const QString& string, const QCString& type, QVariant& result ) +{ + if (string.lower()=="<null>") { + result = QVariant(); + return true; + } + if (string=="\"\"") { + result = QString(""); + return true; + } + const QVariant::Type vtype = typeNameToQVariantType( type ); + bool ok; + result = KexiDB::stringToVariant( string, vtype, ok ); + return ok; +} + +// returns a number parsed from argument; if argument is i or i++, variableI is used +// 'ok' is set to false on failure +static int getNumber(const QString& argument, bool& ok) +{ + int result; + ok = true; + if (argument=="i" || argument=="i++") { + result = variableI; + if (argument=="i++") + variableI++; + } + else { + result = argument.toInt(&ok); + if (!ok) { + showError(QString("Invalid value '%1'").arg(argument)); + return -1; + } + } + return result; +} + +//--------------------------------------- + +AlterTableTester::AlterTableTester() + : QObject() + , m_finishedCopying(false) +{ + //copy the db file to a temp file + qInitNetworkProtocols(); + QPtrList<QNetworkOperation> list = m_copyOperator.copy( + "file://" + QDir::current().path() + "/" + origDbFilename, + "file://" + QDir::current().path() + "/" + dbFilename, false, false ); + connect(&m_copyOperator, SIGNAL(finished(QNetworkOperation*)), + this, SLOT(slotFinishedCopying(QNetworkOperation*))); +} + +AlterTableTester::~AlterTableTester() +{ + QFile(dbFilename).remove(); +} + +void AlterTableTester::slotFinishedCopying(QNetworkOperation* oper) +{ + if (oper->operation()==QNetworkProtocol::OpPut) + m_finishedCopying = true; +} + +bool AlterTableTester::changeFieldProperty(KexiTableDesignerInterface* designerIface) +{ + if (!checkItemsNumber(5)) + return false; + QVariant newValue; + QCString propertyName( testFileLine[2].latin1() ); + QCString propertyType( testFileLine[3].latin1() ); + QString propertyValueString(testFileLine[4]); + if (propertyName=="type") + newValue = (int)KexiDB::Field::typeForString(testFileLine[4]); + else { + if (!castStringToQVariant(propertyValueString, propertyType, newValue)) { + showError( QString("Could not set property '%1' value '%2' of type '%3'") + .arg(propertyName).arg(propertyValueString).arg(propertyType) ); + return false; + } + } + bool ok; + int row = getNumber(testFileLine[1], ok)-1; + if (!ok) + return false; + designerIface->changeFieldPropertyForRow( row, propertyName, newValue, 0, true ); + if (propertyName=="type") { + //clean subtype name, e.g. from "longText" to "LongText", because dropdown list is case-sensitive + QString realSubTypeName; + if (KexiDB::Field::BLOB == KexiDB::Field::typeForString(testFileLine[4])) +//! @todo hardcoded! + realSubTypeName = "image"; + else + realSubTypeName = KexiDB::Field::typeString( KexiDB::Field::typeForString(testFileLine[4]) ); + designerIface->changeFieldPropertyForRow( row, "subType", realSubTypeName, 0, true ); + } + return true; +} + +//helper +bool AlterTableTester::getSchemaDump(KexiDialogBase* dlg, QString& schemaDebugString) +{ + KexiTableDesignerInterface* designerIface + = dynamic_cast<KexiTableDesignerInterface*>( dlg->selectedView() ); + if (!designerIface) + return false; + + // Get the result + tristate result; + schemaDebugString = designerIface->debugStringForCurrentTableSchema(result); + if (true!=result) { + showError( QString("Loading modified schema failed. Result: %1") + .arg(~result ? "cancelled" : "false") ); + return false; + } + schemaDebugString.remove(QRegExp(",$")); //no need to have "," at the end of lines + return true; +} + +bool AlterTableTester::showSchema(KexiDialogBase* dlg, bool copyToClipboard) +{ + QString schemaDebugString; + if (!getSchemaDump(dlg, schemaDebugString)) + return false; + if (copyToClipboard) + QApplication::clipboard()->setText( schemaDebugString ); + else + kdDebug() << QString("Schema for '%1' table:\n").arg(dlg->partItem()->name()) + + schemaDebugString + "\nendSchema" << endl; + return true; +} + +bool AlterTableTester::checkInternal(KexiDialogBase* dlg, + QString& debugString, const QString& endCommand, bool skipColonsAndStripWhiteSpace) +{ + Q_UNUSED(dlg); + QTextStream resultStream(&debugString, IO_ReadOnly); + // Load expected result, compare + QString expectedLine, resultLine; + while (true) { + const bool testFileStreamAtEnd = testFileStream.atEnd(); + if (!testFileStreamAtEnd) { + testLineNumber++; + expectedLine = testFileStream.readLine(); + if (skipColonsAndStripWhiteSpace) { + expectedLine = expectedLine.stripWhiteSpace(); + expectedLine.remove(QRegExp(",$")); //no need to have "," at the end of lines + } + } + if (testFileStreamAtEnd || endCommand==expectedLine.stripWhiteSpace()) { + if (!resultStream.atEnd()) { + showError( "Test file ends unexpectedly." ); + return false; + } + break; + } + //test line loaded, load result + if (resultStream.atEnd()) { + showError( QString("Result ends unexpectedly. There is at least one additinal test line: '") + + expectedLine +"'" ); + return false; + } + resultLine = resultStream.readLine(); + if (skipColonsAndStripWhiteSpace) { + resultLine = resultLine.stripWhiteSpace(); + resultLine.remove(QRegExp(",$")); //no need to have "," at the end of lines + } + if (resultLine!=expectedLine) { + showError( + QString("Result differs from the expected:\nExpected: ") + +expectedLine+"\n????????: "+resultLine+"\n"); + return false; + } + } + return true; +} + +bool AlterTableTester::checkSchema(KexiDialogBase* dlg) +{ + QString schemaDebugString; + if (!getSchemaDump(dlg, schemaDebugString)) + return false; + bool result = checkInternal(dlg, schemaDebugString, "endSchema", true /*skipColonsAndStripWhiteSpace*/); + kdDebug() << QString("Schema check for table '%1': %2").arg(dlg->partItem()->name()) + .arg(result ? "OK" : "Failed") << endl; + return result; +} + +bool AlterTableTester::getActionsDump(KexiDialogBase* dlg, QString& actionsDebugString) +{ + KexiTableDesignerInterface* designerIface + = dynamic_cast<KexiTableDesignerInterface*>( dlg->selectedView() ); + if (!designerIface) + return false; + tristate result = designerIface->simulateAlterTableExecution(&actionsDebugString); + if (true!=result) { + showError( QString("Computing simplified actions for table '%1' failed.").arg(dlg->partItem()->name()) ); + return false; + } + return true; +} + +bool AlterTableTester::showActions(KexiDialogBase* dlg, bool copyToClipboard) +{ + QString actionsDebugString; + if (!getActionsDump(dlg, actionsDebugString)) + return false; + if (copyToClipboard) + QApplication::clipboard()->setText( actionsDebugString ); + else + kdDebug() << QString("Simplified actions for altering table '%1':\n").arg(dlg->partItem()->name()) + + actionsDebugString+"\n" << endl; + return true; +} + +bool AlterTableTester::checkActions(KexiDialogBase* dlg) +{ + QString actionsDebugString; + if (!getActionsDump(dlg, actionsDebugString)) + return false; + bool result = checkInternal(dlg, actionsDebugString, "endActions", true /*skipColonsAndStripWhiteSpace*/); + kdDebug() << QString("Actions check for table '%1': %2").arg(dlg->partItem()->name()) + .arg(result ? "OK" : "Failed") << endl; + return result; +} + +bool AlterTableTester::saveTableDesign(KexiDialogBase* dlg) +{ + KexiTableDesignerInterface* designerIface + = dynamic_cast<KexiTableDesignerInterface*>( dlg->selectedView() ); + if (!designerIface) + return false; + tristate result = designerIface->executeRealAlterTable(); + if (true!=result) { + showError( QString("Saving design of table '%1' failed.").arg(dlg->partItem()->name()) ); + return false; + } + return true; +} + +bool AlterTableTester::getTableDataDump(KexiDialogBase* dlg, QString& dataString) +{ + KexiTableDesignerInterface* designerIface + = dynamic_cast<KexiTableDesignerInterface*>( dlg->selectedView() ); + if (!designerIface) + return false; + + QMap<QString,QString> args; + QTextStream ts( &dataString, IO_WriteOnly ); + args["textStream"] = KexiUtils::ptrToString<QTextStream>( &ts ); + args["destinationType"]="file"; + args["delimiter"]="\t"; + args["textQuote"]="\""; + args["itemId"] = QString::number( + prj->dbConnection()->tableSchema( dlg->partItem()->name() )->id() ); + if (!KexiInternalPart::executeCommand("csv_importexport", win, "KexiCSVExport", &args)) { + showError( "Error exporting table contents." ); + return false; + } + return true; +} + +bool AlterTableTester::showTableData(KexiDialogBase* dlg, bool copyToClipboard) +{ + QString dataString; + if (!getTableDataDump(dlg, dataString)) + return false; + if (copyToClipboard) + QApplication::clipboard()->setText( dataString ); + else + kdDebug() << QString("Contents of table '%1':\n").arg(dlg->partItem()->name())+dataString+"\n" << endl; + return true; +} + +bool AlterTableTester::checkTableData(KexiDialogBase* dlg) +{ + QString dataString; + if (!getTableDataDump(dlg, dataString)) + return false; + bool result = checkInternal(dlg, dataString, "endTableData", false /*!skipColonsAndStripWhiteSpace*/); + kdDebug() << QString("Table '%1' contents: %2").arg(dlg->partItem()->name()) + .arg(result ? "OK" : "Failed") << endl; + return result; +} + +bool AlterTableTester::closeWindow(KexiDialogBase* dlg) +{ + if (!dlg) + return true; + QString name = dlg->partItem()->name(); + tristate result = true == win->closeDialog(dlg, true/*layoutTaskBar*/, true/*doNotSaveChanges*/); + kdDebug() << QString("Closing window for table '%1': %2").arg(name) + .arg(result==true ? "OK" : (result==false ? "Failed" : "Cancelled")) << endl; + return result == true; +} + +//! Processes test file +tristate AlterTableTester::run(bool &closeAppRequested) +{ + closeAppRequested = false; + while (!m_finishedCopying) + qApp->processEvents(300); + + kdDebug() << "Database copied to temporary: " << dbFilename << endl; + + if (!checkItemsNumber(2)) + return false; + + tristate res = win->openProject( dbFilename, 0 ); + if (true != res) + return res; + prj = win->project(); + + //open table in design mode + res = readLineFromTestFile("designTable"); + if (true != res) + return ~res; + + QString tableName(testFileLine[1]); + KexiPart::Item *item = prj->itemForMimeType("kexi/table", tableName); + if (!item) { + showError(QString("No such table '%1'").arg(tableName)); + return false; + } + bool openingCancelled; + KexiDialogBase* dlg = win->openObject(item, Kexi::DesignViewMode, openingCancelled); + if (!dlg) { + showError(QString("Could not open table '%1'").arg(item->name())); + return false; + } + KexiTableDesignerInterface* designerIface + = dynamic_cast<KexiTableDesignerInterface*>( dlg->selectedView() ); + if (!designerIface) + return false; + + //dramatic speedup: temporary hide the window and propeditor + QWidget * propeditor + = KexiUtils::findFirstChild<QWidget>(qApp->mainWidget(), "KexiPropertyEditorView"); + if (propeditor) + propeditor->hide(); + dlg->hide(); + + bool designTable = true; + while (!testFileStream.atEnd()) { + res = readLineFromTestFile(); + if (true != res) + return ~res; + QString command( testFileLine[0] ); + if (designTable) { + //subcommands available within "designTable" commands + if (command=="endDesign") { + if (!checkItemsNumber(1)) + return false; + //end of the design session: unhide the window and propeditor + dlg->show(); + if (propeditor) + propeditor->show(); + designTable = false; + continue; + } + else if (command=="removeField") { + if (!checkItemsNumber(2)) + return false; + bool ok; + int row = getNumber(testFileLine[1], ok)-1; + if (!ok) + return false; + designerIface->deleteRow( row, true ); + continue; + } + else if (command=="insertField") { + if (!checkItemsNumber(3)) + return false; + bool ok; + int row = getNumber(testFileLine[1], ok)-1; + if (!ok) + return false; + designerIface->insertField( row, testFileLine[2], true ); + continue; + } + else if (command=="insertEmptyRow") { + if (!checkItemsNumber(2)) + return false; + bool ok; + int row = getNumber(testFileLine[1], ok)-1; + if (!ok) + return false; + designerIface->insertEmptyRow( row, true ); + continue; + } + else if (command=="changeFieldProperty") { + if (!checkItemsNumber(5) || !changeFieldProperty(designerIface)) + return false; + continue; + } + else if (command.startsWith("i=")) { + bool ok; + variableI = command.mid(2).toInt(&ok); + if (!ok) { + showError(QString("Invalid variable initialization '%1'").arg(command)); + return false; + } + continue; + } + else if (command.startsWith("i++")) { + variableI++; + continue; + } + } + else { + //top-level commands available outside of "designTable" + if (command=="showSchema") { + if (!checkItemsNumber(1, 2) || !showSchema(dlg, testFileLine[1]=="clipboard")) + return false; + continue; + } + else if (command=="checkSchema") { + if (!checkItemsNumber(1) || !checkSchema(dlg)) + return false; + continue; + } + else if (command=="showActions") { + if (!checkItemsNumber(1, 2) || !showActions(dlg, testFileLine[1]=="clipboard")) + return false; + continue; + } + else if (command=="checkActions") { + if (!checkItemsNumber(1) || !checkActions(dlg)) + return false; + continue; + } + else if (command=="saveTableDesign") { + if (!checkItemsNumber(1) || !saveTableDesign(dlg)) + return false; + continue; + } + else if (command=="showTableData") { + if (!checkItemsNumber(1, 2) || !showTableData(dlg, testFileLine[1]=="clipboard")) + return false; + continue; + } + else if (command=="checkTableData") { + if (!checkItemsNumber(1) || !checkTableData(dlg)) + return false; + continue; + } + } + //common commands + if (command=="stop") { + if (!checkItemsNumber(1)) + return false; + kdDebug() << QString("Test STOPPED at line %1.").arg(testLineNumber) << endl; + break; + } + else if (command=="closeWindow") { + if (!checkItemsNumber(1) || !closeWindow(dlg)) + return false; + else + dlg = 0; + continue; + } + else if (command=="quit") { + if (!checkItemsNumber(1) || !closeWindow(dlg)) + return false; + closeAppRequested = true; + kdDebug() << QString("Quitting the application...") << endl; + break; + } + else { + showError( QString("No such command '%1'").arg(command) ); + return false; + } + } + return true; +} + +//--------------------------------------- + +int quit(int result) +{ + testFile.close(); + delete qApp; + if (newArgv) + delete [] newArgv; + return result; +} + +int main(int argc, char *argv[]) +{ + // args: <.altertable test filename> + if (argc < 2) { + kdWarning() << "Please specify test filename.\nOptions: \n" + "\t-close - closes the main window when test finishes" << endl; + return quit(1); + } + + // options: + const bool closeOnFinish = argc > 2 && 0==qstrcmp(argv[1], "-close"); + + // open test file + testFilename = argv[argc-1]; + testFile.setName(testFilename); + if (!testFile.open(IO_ReadOnly)) { + kdWarning() << QString("Opening test file %1 failed.").arg(testFilename) << endl; + return quit(1); + } + //load db name + testFileStream.setDevice( &testFile ); + tristate res = readLineFromTestFile("openDatabase"); + if (true != res) + return quit( ~res ? 0 : 1 ); + origDbFilename = testFileLine[1]; + dbFilename = origDbFilename + ".tmp"; + + newArgc = 2; + newArgv = new char*[newArgc]; + newArgv[0] = qstrdup(argv[0]); + newArgv[1] = qstrdup( "--skip-startup-dialog" ); + + KAboutData* aboutdata = Kexi::createAboutData(); + aboutdata->setProgramName( "Kexi Alter Table Test" ); + int result = KexiMainWindowImpl::create(newArgc, newArgv, aboutdata); + if (!qApp) + return quit(result); + + win = KexiMainWindowImpl::self(); + AlterTableTester tester; + //QObject::connect(win, SIGNAL(projectOpened()), &tester, SLOT(run())); + + bool closeAppRequested; + res = tester.run(closeAppRequested); + if (true != res) { + if (false == res) + kdWarning() << QString("Running test for file '%1' failed.").arg(testFilename) << endl; + return quit(res==false ? 1 : 0); + } + kdDebug() << QString("Tests from file '%1': OK").arg(testFilename) << endl; + result = (closeOnFinish || closeAppRequested) ? 0 : qApp->exec(); + quit(result); + return result; +} + +#include "altertable.moc" diff --git a/kexi/tests/altertable/altertable.h b/kexi/tests/altertable/altertable.h new file mode 100644 index 00000000..455c2bf5 --- /dev/null +++ b/kexi/tests/altertable/altertable.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef AlterTableTester_H +#define AlterTableTester_H + +#include <qurloperator.h> +#include <qnetwork.h> +#include <qnetworkprotocol.h> +#include <kexiutils/tristate.h> + +class KexiTableDesignerInterface; +class KexiDialogBase; + +class AlterTableTester : public QObject +{ + Q_OBJECT + public: + AlterTableTester(); + ~AlterTableTester(); + + tristate run(bool &closeAppRequested); + + protected slots: + void slotFinishedCopying(QNetworkOperation*); + + private: + bool changeFieldProperty(KexiTableDesignerInterface* designerIface); + bool getSchemaDump(KexiDialogBase* dlg, QString& schemaDebugString); + bool showSchema(KexiDialogBase* dlg, bool copyToClipboard); + bool checkSchema(KexiDialogBase* dlg); + bool getActionsDump(KexiDialogBase* dlg, QString& actionsDebugString); + bool showActions(KexiDialogBase* dlg, bool copyToClipboard); + bool checkActions(KexiDialogBase* dlg); + bool checkInternal(KexiDialogBase* dlg, QString& debugString, + const QString& endCommand, bool skipColons); + bool saveTableDesign(KexiDialogBase* dlg); + bool getTableDataDump(KexiDialogBase* dlg, QString& dataString); + bool showTableData(KexiDialogBase* dlg, bool copyToClipboard); + bool checkTableData(KexiDialogBase* dlg); + bool closeWindow(KexiDialogBase* dlg); + + QUrlOperator m_copyOperator; + bool m_finishedCopying; +}; + +#endif diff --git a/kexi/tests/altertable/defaultvalues.altertable b/kexi/tests/altertable/defaultvalues.altertable new file mode 100644 index 00000000..1ed27440 --- /dev/null +++ b/kexi/tests/altertable/defaultvalues.altertable @@ -0,0 +1,129 @@ +openDatabase 1.kexi + +/* + This test checks: + - creating table fields of all possible types with specific default values + - adding new fields to the table with preserving the original content + + All the existing columns are removed + + Used tables: cars +*/ + +designTable cars #initially there are 3rows + removeField 2 + removeField 2 + i=2 + insertField i textField + changeFieldProperty i type string text + changeFieldProperty i defaultValue string abc + i++ + insertField i longTextField + changeFieldProperty i type string longText + changeFieldProperty i defaultValue string def + i++ + insertField i byteField + changeFieldProperty i type string byte + changeFieldProperty i defaultValue int 11 + i++ + insertField i shortIntField + changeFieldProperty i type string shortInteger + changeFieldProperty i defaultValue int 22 + i++ + insertField i intField + changeFieldProperty i type string integer + changeFieldProperty i defaultValue int 333 + i++ + insertField i bigIntField + changeFieldProperty i type string bigInteger + changeFieldProperty i defaultValue longlong 1234567891011 + i++ + insertField i booleanField + changeFieldProperty i type string boolean + changeFieldProperty i defaultValue bool true + i++ + insertField i dateField + changeFieldProperty i type string date + changeFieldProperty i defaultValue date 2006-08-09 + i++ + insertField i dateTimeField + changeFieldProperty i type string dateTime + changeFieldProperty i defaultValue dateTime 2006-08-09T10:36:01 + i++ + insertField i timeField + changeFieldProperty i type string time + changeFieldProperty i defaultValue time 10:36:02 + i++ + insertField i floatField + changeFieldProperty i type string float + changeFieldProperty i defaultValue float 1.98 + i++ + insertField i doubleField + changeFieldProperty i type string double + changeFieldProperty i defaultValue double 3.1415926 + i++ + insertField i blobField + changeFieldProperty i type string blob + changeFieldProperty i defaultValue byteArray fdfeff +endDesign + + showSchema + + checkSchema + id UNSIGNED Integer AUTOINC UNIQUE PKEY NOTNULL NOTEMPTY + textfield Text(200) DEFAULT=[QString]abc, + longtextfield LongText DEFAULT=[QString]def, + bytefield Byte DEFAULT=[int]11, + shortintfield ShortInteger DEFAULT=[int]22, + intfield Integer DEFAULT=[int]333, + bigintfield BigInteger DEFAULT=[Q_LLONG]1234567891011, + booleanfield Boolean NOTNULL DEFAULT=[bool]true, + datefield Date DEFAULT=[QDate]2006-08-09, + datetimefield DateTime DEFAULT=[QDateTime]2006-08-09T10:36:01, + timefield Time DEFAULT=[QTime]10:36:02, + floatfield Float DEFAULT=[double]1.98, + doublefield Double DEFAULT=[double]3.1415926, + blobfield BLOB DEFAULT=[QByteArray]FDFEFF + endSchema + +# showActions clipboard + + checkActions +Remove table field "owner" +Remove table field "model" +Insert table field "textfield" at position 1 (textfield Text(200) DEFAULT=[QString]abc) +Insert table field "longtextfield" at position 2 (longtextfield LongText DEFAULT=[QString]def) +Insert table field "bytefield" at position 3 (bytefield Byte DEFAULT=[int]11) +Insert table field "shortintfield" at position 4 (shortintfield ShortInteger DEFAULT=[int]22) +Insert table field "intfield" at position 5 (intfield Integer DEFAULT=[int]333) +Insert table field "bigintfield" at position 6 (bigintfield BigInteger DEFAULT=[Q_LLONG]1234567891011) +Insert table field "booleanfield" at position 7 (booleanfield Boolean NOTNULL DEFAULT=[bool]true) +Insert table field "datefield" at position 8 (datefield Date DEFAULT=[QDate]2006-08-09) +Insert table field "datetimefield" at position 9 (datetimefield DateTime DEFAULT=[QDateTime]2006-08-09T10:36:01) +Insert table field "timefield" at position 10 (timefield Time DEFAULT=[QTime]10:36:02) +Insert table field "floatfield" at position 11 (floatfield Float DEFAULT=[double]1.98) +Insert table field "doublefield" at position 12 (doublefield Double DEFAULT=[double]3.1415926) +Insert table field "blobfield" at position 13 (blobfield BLOB DEFAULT=[QByteArray]FDFEFF) + endActions + +saveTableDesign #executes Alter Table + +#closeWindow + +#stop +#quit + +# copyTableDataToClipboard + showTableData clipboard +# stop + + checkTableData +"ID" "textField" "longTextField" "byteField" "shortIntField" "intField" "bigIntField" "booleanField" "dateField" "dateTimeField" "timeField" "floatField" "doubleField" "blobField" +1 "abc" "def" 11 22 333 1234567891011 true 2006-08-09 2006-08-09 10:36:01 10:36:02 1.98 3.1415926 "FDFEFF" +2 "abc" "def" 11 22 333 1234567891011 true 2006-08-09 2006-08-09 10:36:01 10:36:02 1.98 3.1415926 "FDFEFF" +3 "abc" "def" 11 22 333 1234567891011 true 2006-08-09 2006-08-09 10:36:01 10:36:02 1.98 3.1415926 "FDFEFF" +5 "abc" "def" 11 22 333 1234567891011 true 2006-08-09 2006-08-09 10:36:01 10:36:02 1.98 3.1415926 "FDFEFF" +6 "abc" "def" 11 22 333 1234567891011 true 2006-08-09 2006-08-09 10:36:01 10:36:02 1.98 3.1415926 "FDFEFF" + endTableData + + |