From 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- libksieve/tests/parsertest.cpp | 667 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 667 insertions(+) create mode 100644 libksieve/tests/parsertest.cpp (limited to 'libksieve/tests/parsertest.cpp') diff --git a/libksieve/tests/parsertest.cpp b/libksieve/tests/parsertest.cpp new file mode 100644 index 000000000..e2ea0fd39 --- /dev/null +++ b/libksieve/tests/parsertest.cpp @@ -0,0 +1,667 @@ +/* -*- c++ -*- + tests/parsertest.cpp + + This file is part of the testsuite of KSieve, + the KDE internet mail/usenet news message filtering library. + Copyright (c) 2003 Marc Mutz + + KSieve is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KSieve 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ +#include +#include +using KSieve::Parser; + +#include +#include + +#include // qstrlen +#include + +#include +using std::cout; +using std::cerr; +using std::endl; + +#include + +enum BuilderMethod { + TaggedArgument, + StringArgument, + NumberArgument, + CommandStart, + CommandEnd, + TestStart, + TestEnd, + TestListStart, + TestListEnd, + BlockStart, + BlockEnd, + StringListArgumentStart, + StringListEntry, + StringListArgumentEnd, + HashComment, + BracketComment, + Error, + Finished +}; + +static const unsigned int MAX_RESPONSES = 100; + +struct TestCase { + const char * name; + const char * script; + struct Response { + BuilderMethod method; + const char * string; + bool boolean; + } responses[MAX_RESPONSES]; +} testCases[] = { + + // + // single commands: + // + + { "Null script", + 0, + { { Finished, 0, false } } + }, + + { "Empty script", + "", + { { Finished, 0, false } } + }, + + { "WS-only script", + " \t\n\r\n", + { { Finished, 0, false } } + }, + + { "Bare hash comment", + "#comment", + { { HashComment, "comment", false }, + { Finished, 0, false } } + }, + + { "Bare bracket comment", + "/*comment*/", + { { BracketComment, "comment", false }, + { Finished, 0, false } } + }, + + { "Bare command", + "command;", + { { CommandStart, "command", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "Bare command - missing semicolon", + "command", + { { CommandStart, "command", false }, + { Error, "MissingSemicolonOrBlock", false } } + }, + + { "surrounded by bracket comments", + "/*comment*/command/*comment*/;/*comment*/", + { { BracketComment, "comment", false }, + { CommandStart, "command", false }, + { BracketComment, "comment", false }, + { CommandEnd, 0, false }, + { BracketComment, "comment", false }, + { Finished, 0, false } } + }, + + { "surrounded by hash comments", + "#comment\ncommand#comment\n;#comment", + { { HashComment, "comment", false }, + { CommandStart, "command", false }, + { HashComment, "comment", false }, + { CommandEnd, 0, false }, + { HashComment, "comment", false }, + { Finished, 0, false } } + }, + + { "single tagged argument", + "command :tag;", + { { CommandStart, "command", false }, + { TaggedArgument, "tag", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single tagged argument - missing semicolon", + "command :tag", + { { CommandStart, "command", false }, + { TaggedArgument, "tag", false }, + { Error, "MissingSemicolonOrBlock", false } } + }, + + { "single string argument - quoted string", + "command \"string\";", + { { CommandStart, "command", false }, + { StringArgument, "string", false /*quoted*/ }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single string argument - multi-line string", + "command text:\nstring\n.\n;", + { { CommandStart, "command", false }, + { StringArgument, "string", true /*multiline*/ }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single number argument - 100", + "command 100;", + { { CommandStart, "command", false }, + { NumberArgument, "100 ", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single number argument - 100k", + "command 100k;", + { { CommandStart, "command", false }, + { NumberArgument, "102400k", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single number argument - 100M", + "command 100M;", + { { CommandStart, "command", false }, + { NumberArgument, "104857600M", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single number argument - 2G", + "command 2G;", + { { CommandStart, "command", false }, + { NumberArgument, "2147483648G", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + +#if SIZEOF_UNSIGNED_LONG == 8 +# define ULONG_MAX_STRING "18446744073709551615" +# define ULONG_MAXP1_STRING "18446744073709551616" +#elif SIZEOF_UNSIGNED_LONG == 4 +# define ULONG_MAX_STRING "4294967295" +# define ULONG_MAXP1_STRING "4G" +#else +# error sizeof( unsigned long ) != 4 && sizeof( unsigned long ) != 8 ??? +#endif + + { "single number argument - ULONG_MAX + 1", + "command " ULONG_MAXP1_STRING ";", + { { CommandStart, "command", false }, + { Error, "NumberOutOfRange", false } } + }, + + { "single number argument - ULONG_MAX", + "command " ULONG_MAX_STRING ";", + { { CommandStart, "command", false }, + { NumberArgument, ULONG_MAX_STRING " ", false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single one-element string list argument - quoted string", + "command [\"string\"];", + { { CommandStart, "command", false }, + { StringListArgumentStart, 0, false }, + { StringListEntry, "string", false /*quoted*/ }, + { StringListArgumentEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single one-element string list argument - multi-line string", + "command [text:\nstring\n.\n];", + { { CommandStart, "command", false }, + { StringListArgumentStart, 0, false }, + { StringListEntry, "string", true /*multiline*/ }, + { StringListArgumentEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single two-element string list argument - quoted strings", + "command [\"string\",\"string\"];", + { { CommandStart, "command", false }, + { StringListArgumentStart, 0, false }, + { StringListEntry, "string", false /*quoted*/ }, + { StringListEntry, "string", false /*quoted*/ }, + { StringListArgumentEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single two-element string list argument - multi-line strings", + "command [text:\nstring\n.\n,text:\nstring\n.\n];", + { { CommandStart, "command", false }, + { StringListArgumentStart, 0, false }, + { StringListEntry, "string", true /*multiline*/ }, + { StringListEntry, "string", true /*multiline*/ }, + { StringListArgumentEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single two-element string list argument - quoted + multi-line strings", + "command [\"string\",text:\nstring\n.\n];", + { { CommandStart, "command", false }, + { StringListArgumentStart, 0, false }, + { StringListEntry, "string", false /*quoted*/ }, + { StringListEntry, "string", true /*multiline*/ }, + { StringListArgumentEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single two-element string list argument - multi-line + quoted strings", + "command [text:\nstring\n.\n,\"string\"];", + { { CommandStart, "command", false }, + { StringListArgumentStart, 0, false }, + { StringListEntry, "string", true /*multiline*/ }, + { StringListEntry, "string", false /*quoted*/ }, + { StringListArgumentEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "single bare test argument", + "command test;", + { { CommandStart, "command", false }, + { TestStart, "test", false }, + { TestEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "one-element test list argument", + "command(test);", + { { CommandStart, "command", false }, + { TestListStart, 0, false }, + { TestStart, "test", false }, + { TestEnd, 0, false }, + { TestListEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "two-element test list argument", + "command(test,test);", + { { CommandStart, "command", false }, + { TestListStart, 0, false }, + { TestStart, "test", false }, + { TestEnd, 0, false }, + { TestStart, "test", false }, + { TestEnd, 0, false }, + { TestListEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "zero-element block", + "command{}", + { { CommandStart, "command", false }, + { BlockStart, 0, false }, + { BlockEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "one-element block", + "command{command;}", + { { CommandStart, "command", false }, + { BlockStart, 0, false }, + { CommandStart, "command", false }, + { CommandEnd, 0, false }, + { BlockEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "two-element block", + "command{command;command;}", + { { CommandStart, "command", false }, + { BlockStart, 0, false }, + { CommandStart, "command", false }, + { CommandEnd, 0, false }, + { CommandStart, "command", false }, + { CommandEnd, 0, false }, + { BlockEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + + { "command with a test with a test with a test", + "command test test test;", + { { CommandStart, "command", false }, + { TestStart, "test", false }, + { TestStart, "test", false }, + { TestStart, "test", false }, + { TestEnd, 0, false }, + { TestEnd, 0, false }, + { TestEnd, 0, false }, + { CommandEnd, 0, false }, + { Finished, 0, false } } + }, + +}; + +static const int numTestCases = sizeof testCases / sizeof *testCases ; + +// Prints out the parse tree in XML-like format. For visual inspection +// (manual tests). +class PrintingScriptBuilder : public KSieve::ScriptBuilder { +public: + PrintingScriptBuilder() + : KSieve::ScriptBuilder(), indent( 0 ) + { + write( "" ); + } +private: + int indent; + void write( const char * msg ) { + for ( int i = 2*indent ; i > 0 ; --i ) + cout << " "; + cout << msg << endl; + } + void write( const QCString & key, const QString & value ) { + if ( value.isEmpty() ) { + write( "<" + key + "/>" ); + return; + } + write( "<" + key + ">" ); + ++indent; + write( value.utf8().data() ); + --indent; + write( "" ); + } +}; + + +// verifes that methods get called with expected arguments (and in +// expected sequence) as specified by the TestCase. For automated +// tests. +class VerifyingScriptBuilder : public KSieve::ScriptBuilder { +public: + VerifyingScriptBuilder( const TestCase & testCase ) + : KSieve::ScriptBuilder(), + mNextResponse( 0 ), mTestCase( testCase ), mOk( true ) + { + } + virtual ~VerifyingScriptBuilder() {} + + bool ok() const { return mOk; } + + void taggedArgument( const QString & tag ) { + checkIs( TaggedArgument ); + checkEquals( tag ); + ++mNextResponse; + } + void stringArgument( const QString & string, bool multiline, const QString & /*fixme*/ ) { + checkIs( StringArgument ); + checkEquals( string ); + checkEquals( multiline ); + ++mNextResponse; + } + void numberArgument( unsigned long number, char quantifier ) { + checkIs( NumberArgument ); + checkEquals( QString::number( number ) + ( quantifier ? quantifier : ' ' ) ); + ++mNextResponse; + } + void commandStart( const QString & identifier ) { + checkIs( CommandStart ); + checkEquals( identifier ); + ++mNextResponse; + } + void commandEnd() { + checkIs( CommandEnd ); + ++mNextResponse; + } + void testStart( const QString & identifier ) { + checkIs( TestStart ); + checkEquals( identifier ); + ++mNextResponse; + } + void testEnd() { + checkIs( TestEnd ); + ++mNextResponse; + } + void testListStart() { + checkIs( TestListStart ); + ++mNextResponse; + } + void testListEnd() { + checkIs( TestListEnd ); + ++mNextResponse; + } + void blockStart() { + checkIs( BlockStart ); + ++mNextResponse; + } + void blockEnd() { + checkIs( BlockEnd ); + ++mNextResponse; + } + void stringListArgumentStart() { + checkIs( StringListArgumentStart ); + ++mNextResponse; + } + void stringListEntry( const QString & string, bool multiLine, const QString & /*fixme*/ ) { + checkIs( StringListEntry ); + checkEquals( string ); + checkEquals( multiLine ); + ++mNextResponse; + } + void stringListArgumentEnd() { + checkIs( StringListArgumentEnd ); + ++mNextResponse; + } + void hashComment( const QString & comment ) { + checkIs( HashComment ); + checkEquals( comment ); + ++mNextResponse; + } + void bracketComment( const QString & comment ) { + checkIs( BracketComment ); + checkEquals( comment ); + ++mNextResponse; + } + void lineFeed() { + // FIXME + } + void error( const KSieve::Error & error ) { + checkIs( Error ); + checkEquals( QString( KSieve::Error::typeToString( error.type() ) ) ); + ++mNextResponse; + } + void finished() { + checkIs( Finished ); + //++mNextResponse (no!) + } + +private: + const TestCase::Response & currentResponse() const { + assert( mNextResponse <= MAX_RESPONSES ); + return mTestCase.responses[mNextResponse]; + } + + void checkIs( BuilderMethod m ) { + if ( currentResponse().method != m ) { + cerr << " expected method " << (int)currentResponse().method + << ", got " << (int)m; + mOk = false; + } + } + + void checkEquals( const QString & s ) { + if ( s != QString::fromUtf8( currentResponse().string ) ) { + cerr << " expected string arg \"" + << ( currentResponse().string ? currentResponse().string : "" ) + << "\", got \"" << ( s.isNull() ? "" : s.utf8().data() ) << "\""; + mOk = false; + } + } + void checkEquals( bool b ) { + if ( b != currentResponse().boolean ) { + cerr << " expected boolean arg <" << currentResponse().boolean + << ">, got <" << b << ">"; + mOk = false; + } + } + + unsigned int mNextResponse; + const TestCase & mTestCase; + bool mOk; +}; + + +int main( int argc, char * argv[] ) { + + if ( argc == 2 ) { // manual test + + const char * scursor = argv[1]; + const char * const send = argv[1] + qstrlen( argv[1] ); + + Parser parser( scursor, send ); + PrintingScriptBuilder psb; + parser.setScriptBuilder( &psb ); + if ( parser.parse() ) + cout << "ok" << endl; + else + cout << "bad" << endl; + + + } else if ( argc == 1 ) { // automated test + bool success = true; + for ( int i = 0 ; i < numTestCases ; ++i ) { + const TestCase & t = testCases[i]; + cerr << t.name << ":"; + VerifyingScriptBuilder v( t ); + Parser p( t.script, t.script + qstrlen( t.script ) ); + p.setScriptBuilder( &v ); + const bool ok = p.parse(); + if ( v.ok() ) + if ( ok ) + cerr << " ok"; + else + cerr << " xfail"; + else + success = false; + cerr << endl; + } + if ( !success ) + exit( 1 ); + + } else { // usage error + cerr << "usage: parsertest [ ]" << endl; + exit( 1 ); + } + + return 0; +} -- cgit v1.2.1