summaryrefslogtreecommitdiffstats
path: root/kexi/tests/altertable
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/tests/altertable
downloadkoffice-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.kexibin0 -> 49150 bytes
-rw-r--r--kexi/tests/altertable/Makefile.am22
-rw-r--r--kexi/tests/altertable/README200
-rw-r--r--kexi/tests/altertable/TODO3
-rw-r--r--kexi/tests/altertable/alltypes.altertable109
-rw-r--r--kexi/tests/altertable/altertable.cpp716
-rw-r--r--kexi/tests/altertable/altertable.h63
-rw-r--r--kexi/tests/altertable/defaultvalues.altertable129
8 files changed, 1242 insertions, 0 deletions
diff --git a/kexi/tests/altertable/1.kexi b/kexi/tests/altertable/1.kexi
new file mode 100644
index 00000000..1165d90e
--- /dev/null
+++ b/kexi/tests/altertable/1.kexi
Binary files differ
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
+
+