bool AMRecursiveDirectoryCompare::compareOneLevel(const QString &path1, const QString &path2) {
    QDir directory1(path1);
    QDir directory2(path2);
    directory1.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
    directory2.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);

    // Get a list of all direct subdirectories of this directory, and files it contains
    QFileInfoList directory1Entries = directory1.entryInfoList();
    QFileInfoList directory2Entries = directory2.entryInfoList();


    QHash<QString, QFileInfo> side1Files;
    QHash<QString, QFileInfo> side2Files;
    QStringList side1SubDirectories;
    QStringList side2SubDirectories;
    QStringList dualSideSubDirectories;
    QStringList onlySide1SubDirectories;
    QStringList onlySide2SubDirectories;
    QStringList newerSide1Files;
    QStringList newerSide2Files;
    QStringList unknownFiles;

    // Builds side 1 lists: adds files to file hash, appends directories to directory list
    for(int x = 0, size = directory1Entries.count(); x < size; x++)
    {
        bool excluded = false;
        for(int y = 0, sizeY = excludedRegExps_.count(); y < sizeY && !excluded; y++)
            if(excludedRegExps_.at(y).indexIn(directory1Entries.at(x).absoluteFilePath()) != -1)
                excluded = true;

        if(!excluded && directory1Entries.at(x).isFile())
        {
            side1Files.insert(directory1Entries.at(x).absoluteFilePath().remove(path1), directory1Entries.at(x));
        }
        else if(!excluded && directory1Entries.at(x).isDir())
        {
            side1SubDirectories.append(directory1Entries.at(x).absoluteFilePath().remove(path1));
        }
    }

    // Builds side 2 lists, while removing files it finds in both hashes from the list 1
    // hash
    for(int x = 0, size = directory2Entries.count(); x < size; x++) {
        QFileInfo currentSide2Entry = directory2Entries.at(x);

        bool excluded = false;
        for(int y = 0, sizeY = excludedRegExps_.count(); y < sizeY && !excluded; y++)
            if(excludedRegExps_.at(y).indexIn(currentSide2Entry.absoluteFilePath()) != -1)
                excluded = true;

        if(!excluded && currentSide2Entry.isFile())
        {
            if(side1Files.contains(currentSide2Entry.absoluteFilePath().remove(path2)))
            {
                QFileInfo side1Match = side1Files.value(currentSide2Entry.absoluteFilePath().remove(path2));
                if(side1Match.lastModified() < currentSide2Entry.lastModified()) {
                    if(side1Match.size() > currentSide2Entry.size() && !side1Match.fileName().endsWith(".db"))
                        unknownFiles.append(currentSide2Entry.absoluteFilePath().remove(path2));
                    else
                        newerSide2Files.append(currentSide2Entry.absoluteFilePath().remove(path2));
                }
                else if(currentSide2Entry.lastModified() < side1Match.lastModified()) {
                    if(currentSide2Entry.size() > side1Match.size() && !side1Match.fileName().endsWith(".db"))
                        unknownFiles.append(side1Match.absoluteFilePath().remove(path1));
                    else
                        newerSide1Files.append(side1Match.absoluteFilePath().remove(path1));
                }
                side1Files.remove(currentSide2Entry.absoluteFilePath().remove(path2));
            }
            else
            {
                side2Files.insert(currentSide2Entry.absoluteFilePath().remove(path2), currentSide2Entry);
            }


        }
        else if(!excluded && directory2Entries.at(x).isDir()) {
            side2SubDirectories.append(directory2Entries.at(x).absoluteFilePath().remove(path2));
        }
    }

    // Locates directories in their correct list
    for(int x = 0, size = side2SubDirectories.count(); x < size; x++) {
        if(side1SubDirectories.contains(side2SubDirectories.at(x))) {
            dualSideSubDirectories.append(side2SubDirectories.at(x));
            side1SubDirectories.removeAll(side2SubDirectories.at(x));
        }
        else
            onlySide2SubDirectories.append(side2SubDirectories.at(x));
    }
    onlySide1SubDirectories = side1SubDirectories;


    if (unknownFiles.count() > 0)
        qDebug() << QString("Found (%1) files for which the more up-to-date version cannot be determined, leading with %2.").arg(unknownFiles.count()).arg(unknownFiles.at(0));
    for (int x = 0, size = unknownFiles.count(); x < size; x++) {
        unknownFiles_.append(QDir::cleanPath(QString(".../%1").arg(unknownFiles.at(x))));
    }

    if (newerSide1Files.count() > 0)
        qDebug() << "Found newer files on side 1";
    for(int x = 0, size = newerSide1Files.count(); x < size; x++) {
        newerSide1Files_.append(QDir::cleanPath(QString("%1/%2").arg(path1).arg(newerSide1Files.at(x))));
    }

    if (newerSide2Files.count() > 0)
        qDebug() << "Found newer files on side 2";
    for(int x = 0, size = newerSide2Files.count(); x < size; x++) {
        newerSide2Files_.append(QDir::cleanPath(QString("%1/%2").arg(path2).arg(newerSide2Files.at(x))));
    }
    for(int x = 0, size = onlySide1SubDirectories.count(); x < size; x++)
        uniqueSide1Directories_.append(QDir::cleanPath(QString("%1/%2").arg(path1).arg(onlySide1SubDirectories.at(x))));
    for(int x = 0, size = onlySide2SubDirectories.count(); x < size; x++)
        uniqueSide2Directories_.append(QDir::cleanPath(QString("%1/%2").arg(path2).arg(onlySide2SubDirectories.at(x))));

    if(side1Files.count() > 0) {
        QHash<QString, QFileInfo>::const_iterator i = side1Files.constBegin();
        while (i != side1Files.constEnd()) {
            uniqueSide1Files_.append(QDir::cleanPath(QString("%1/%2").arg(path1).arg(i.key())));
            ++i;
        }
    }

    if(side2Files.count() > 0) {
        QHash<QString, QFileInfo>::const_iterator j = side2Files.constBegin();
        while (j != side2Files.constEnd()) {
            uniqueSide2Files_.append(QDir::cleanPath(QString("%1/%2").arg(path2).arg(j.key())));
            ++j;
        }
    }

    for(int x = 0, size = dualSideSubDirectories.count(); x < size; x++) {
        compareOneLevel(QDir::cleanPath(QString("%1/%2").arg(path1).arg(dualSideSubDirectories.at(x))), QDir::cleanPath(QString("%1/%2").arg(path2).arg(dualSideSubDirectories.at(x))));
    }



    return false;
}
Example #2
0
void KRenameTest::testBatchRenamer()
{
    writeTestHeader( "BatchRenamer" );

    // Testing the basic KRename tokens
    QString filename( " Test File name " );
    QString directory1( "krename" );
    QString directory2( "home" );
    
    RUN_TOKEN_TEST( "$ Test", "$", filename, filename );
    RUN_TOKEN_TEST( "& Test", "&", filename, filename.toUpper() );
    RUN_TOKEN_TEST( "% Test", "%", filename, filename.toLower() );
    RUN_TOKEN_TEST( "* Test", "*", filename, " Test File Name " );
    RUN_TOKEN_TEST( "# Test", "#", filename, QString::number( 0 ) );
    RUN_TOKEN_TEST( "## Test", "##", filename, QString().sprintf("%02i", 0 ) );
    RUN_TOKEN_TEST( "### Test", "###", filename, QString().sprintf("%03i", 0 ) );
    RUN_TOKEN_TEST( "#### Test", "####", filename, QString().sprintf("%04i", 0 ) );
    RUN_TOKEN_TEST( "##### Test", "#####", filename, QString().sprintf("%05i", 0 ) );
    RUN_TOKEN_TEST( "#{100;2} Test", "#{100;2}", filename, QString::number( 100 ) );
    RUN_TOKEN_TEST( "####{100;2} Test", "####{100;2}", filename, QString().sprintf("%04i", 100 ) );
    RUN_TOKEN_TEST( "####{2;2}## Test", "####{2;2}##", filename, 
		    QString().sprintf("%04i", 2 ) + QString().sprintf("%02i", 0 ));
    RUN_TOKEN_TEST( "[1] Test", "[1]", filename, QString( filename[0] ) );
    RUN_TOKEN_TEST( "[2] Test", "[2]", filename, QString( filename[1] )  );
    RUN_TOKEN_TEST( "[3] Test", "[3]", filename, QString( filename[2] ) );
    RUN_TOKEN_TEST( "[&4] Test", "[&4]", filename, QString( filename[3].toUpper()) );
    RUN_TOKEN_TEST( "[$4] Test", "[$4]", filename, QString( filename[3] ) );
    RUN_TOKEN_TEST( "[%4] Test", "[%4]", filename, QString( filename[3].toLower()) );
    RUN_TOKEN_TEST( "[*4] Test", "[*4]", filename, QString( filename[3].toUpper()) );
    RUN_TOKEN_TEST( "[4-] Test", "[4-]", filename, filename.right( filename.length() - 3 ) );
    RUN_TOKEN_TEST( "[&4-] Test", "[&4-]", filename, filename.right( filename.length() - 3 ).toUpper() );
    RUN_TOKEN_TEST( "[$4-] Test", "[$4-]", filename, filename.right( filename.length() - 3 ) );
    RUN_TOKEN_TEST( "[%4-] Test", "[%4-]", filename, filename.right( filename.length() - 3 ).toLower() );
    RUN_TOKEN_TEST( "[*4-] Test", "[*4-]", filename, "St File Name " );
    RUN_TOKEN_TEST( "[4-] Test", "[4-]", filename, filename.right( filename.length() - 3 ) );
    RUN_TOKEN_TEST( "[&4-[length]] Test", "[&4-[length]]", filename, filename.right( filename.length() - 3 ).toUpper() );
    RUN_TOKEN_TEST( "[$4-[length]] Test", "[$4-[length]]", filename, filename.right( filename.length() - 3 ) );
    RUN_TOKEN_TEST( "[%4-[length]] Test", "[%4-[length]]", filename, filename.right( filename.length() - 3 ).toLower() );
    RUN_TOKEN_TEST( "[*4-[length]] Test", "[*4-[length]]", filename, "St File Name " );
    RUN_TOKEN_TEST( "[trimmed;[4-]] Test", "[trimmed;[4-]]", filename, filename.right( filename.length() - 3 ).trimmed() );
    RUN_TOKEN_TEST( "[trimmed] Test", "[trimmed]", filename, filename.trimmed() );
    RUN_TOKEN_TEST( "[length] Test", "[length]", filename, QString::number( filename.length() ) );
    RUN_TOKEN_TEST( "[length-0] Test", "[length-0]", filename, QString::number( filename.length() ) );
    RUN_TOKEN_TEST( "[length-1] Test", "[length-1]", filename, QString::number( filename.length() - 1 ) );
    RUN_TOKEN_TEST( "[length-2] Test", "[length-2]", filename, QString::number( filename.length() - 2 ) );
    RUN_TOKEN_TEST( "[#length] Test", "[#length]", filename, QString::number( filename.length() ) );
    RUN_TOKEN_TEST( "[#length-0] Test", "[#length-0]", filename, QString::number( filename.length() ) );
    RUN_TOKEN_TEST( "[#length-1] Test", "[#length-1]", filename, QString::number( filename.length() - 1 ) );
    RUN_TOKEN_TEST( "[#length-2] Test", "[#length-2]", filename, QString::number( filename.length() - 2 ) );
    RUN_TOKEN_TEST( "[####length] Test", "[####length]", filename, QString().sprintf("%04i", filename.length() ) );
    RUN_TOKEN_TEST( "[####length-0] Test", "[####length-0]", filename, QString().sprintf("%04i", filename.length() ) );
    RUN_TOKEN_TEST( "[####length-1] Test", "[####length-1]", filename, QString().sprintf("%04i", filename.length() - 1) );
    RUN_TOKEN_TEST( "[####length-2] Test", "[####length-2]", filename, QString().sprintf("%04i", filename.length() - 2) );
    RUN_TOKEN_TEST( "[6-9] Test", "[6-9]", filename, filename.mid( 5, 4 ) );
    RUN_TOKEN_TEST( "[&6-9] Test", "[&6-9]", filename, filename.mid( 5, 4 ).toUpper() );
    RUN_TOKEN_TEST( "[$6-9] Test", "[$6-9]", filename, filename.mid( 5, 4 ) );
    RUN_TOKEN_TEST( "[%6-9] Test", "[%6-9]", filename, filename.mid( 5, 4 ).toLower() );
    RUN_TOKEN_TEST( "[*6-9] Test", "[*6-9]", filename, filename.mid( 5, 4 ) );
    RUN_TOKEN_TEST( "[trimmed;[6-9]] Test", "[trimmed;[6-9]]", filename, filename.mid( 5, 4 ).trimmed() );
    RUN_TOKEN_TEST( "[6;4] Test", "[6;4]", filename, filename.mid( 5, 4 ) );
    RUN_TOKEN_TEST( "[&6;4] Test", "[&6;4]", filename, filename.mid( 5, 4 ).toUpper() );
    RUN_TOKEN_TEST( "[$6;4] Test", "[$6;4]", filename, filename.mid( 5, 4 ) );
    RUN_TOKEN_TEST( "[%6;4] Test", "[%6;4]", filename, filename.mid( 5, 4 ).toLower() );
    RUN_TOKEN_TEST( "[*6;4] Test", "[*6;4]", filename, filename.mid( 5, 4 ) );
    RUN_TOKEN_TEST( "[1;1{[length]}] Test", "[1;1{[length]}]", filename,  "1" );    
    RUN_TOKEN_TEST( "[trimmed;[6;4]] Test", "[trimmed;[6;4]]", filename, filename.mid( 5, 4 ).trimmed() );
    RUN_TOKEN_TEST( "[trimmed; Hallo ] Test", "[trimmed; Hallo ]", filename, "Hallo" );
    RUN_TOKEN_TEST( "[dirname] Test", "[dirname]", filename, directory1 );
    RUN_TOKEN_TEST( "[&dirname] Test", "[&dirname]", filename, directory1.toUpper() );
    RUN_TOKEN_TEST( "[$dirname] Test", "[$dirname]", filename, directory1 );
    RUN_TOKEN_TEST( "[%dirname] Test", "[%dirname]", filename, directory1.toLower() );
    RUN_TOKEN_TEST( "[*dirname] Test", "[*dirname]", filename, "Krename" );
    RUN_TOKEN_TEST( "[trimmed;[dirname]] Test", "[trimmed;[dirname]]", filename, directory1 );
    RUN_TOKEN_TEST( "[dirname.] Test", "[dirname.]", filename, directory2 );
    RUN_TOKEN_TEST( "[&dirname.] Test", "[&dirname.]", filename, directory2.toUpper() );
    RUN_TOKEN_TEST( "[$dirname.] Test", "[$dirname.]", filename, directory2 );
    RUN_TOKEN_TEST( "[%dirname.] Test", "[%dirname.]", filename, directory2.toLower() );
    RUN_TOKEN_TEST( "[*dirname.] Test", "[*dirname.]", filename, "Home" );
    RUN_TOKEN_TEST( "[trimmed;[dirname.]] Test", "[trimmed;[dirname.]]", filename, directory2 );
    RUN_TOKEN_TEST( "[dirname..] Test", "[dirname..]", filename, "" );
    RUN_TOKEN_TEST( "[&dirname..] Test", "[&dirname..]", filename, "" );
    RUN_TOKEN_TEST( "[$dirname..] Test", "[$dirname..]", filename, "" );
    RUN_TOKEN_TEST( "[%dirname..] Test", "[%dirname..]", filename, "" );
    RUN_TOKEN_TEST( "[*dirname..] Test", "[*dirname..]", filename, "" );
    // TODO: This test has strange effects that only occur if [dirname..] is QString::null
    //RUN_TOKEN_TEST( "[trimmed;[dirname..]] Test", "[trimmed;[dirname..]]", filename, filename.trimmed() );
    RUN_TOKEN_TEST( "Complex Test1", "&[2-5]", filename, filename.toUpper() + "Test" );
    RUN_TOKEN_TEST( "Complex Test2", "%[2-5]", filename, filename.toLower() + "Test" );
    RUN_TOKEN_TEST( "Complex Test3", "$[2-5]", filename, filename + "Test" );
    RUN_TOKEN_TEST( "Complex Test4", "*[2-5]", filename, " Test File Name Test" );
    RUN_TOKEN_TEST( "Complex Test5", "[trimmed][2-5]", filename, filename.trimmed() + "Test" );
    RUN_TOKEN_TEST( "Complex Test6", "[&2-5]\\&[length-2]\\&[1;1{Hallo}]", filename, "TEST&14&H" );

    // Testing all special Characters in KRename
    RUN_TOKEN_TEST( "\\/ Test", "\\/", filename, "%2f" ); // this is displayed as a slash,
                                                          // unix filenames are not allowed
                                                          // to contain a slash
    RUN_TOKEN_TEST( "\\[ Test", "\\[", filename, "[" );
    RUN_TOKEN_TEST( "\\] Test", "\\]", filename, "]" );
    RUN_TOKEN_TEST( "\\$ Test", "\\$", filename, "$" );
    RUN_TOKEN_TEST( "\\* Test", "\\*", filename, "*" );
    RUN_TOKEN_TEST( "\\\\ Test", "\\\\", filename, "\\" );
    RUN_TOKEN_TEST( "\\& Test", "\\&", filename, "&" );
    RUN_TOKEN_TEST( "\\% Test", "\\%", filename, "%" );
    RUN_TOKEN_TEST( "\\# Test", "\\#", filename, "#" );

    // Testing filenames with special characters
    QString specialname("Test %1 File");
    RUN_TOKEN_TEST( "File [ Test", "$", specialname.arg( "[" ), specialname.arg( "[" ) );
    RUN_TOKEN_TEST( "File ] Test", "$", specialname.arg( "]" ), specialname.arg( "]" ) );
    RUN_TOKEN_TEST( "File $ Test", "$", specialname.arg( "$" ), specialname.arg( "$" ) );
    RUN_TOKEN_TEST( "File * Test", "$", specialname.arg( "*" ), specialname.arg( "*" ) );
    RUN_TOKEN_TEST( "File \\ Test", "$", specialname.arg( "\\" ), specialname.arg( "\\" ) );
    RUN_TOKEN_TEST( "File & Test", "$", specialname.arg( "&" ), specialname.arg( "&" ) );
    RUN_TOKEN_TEST( "File % Test", "$", specialname.arg( "%" ), specialname.arg( "%" ) );
    RUN_TOKEN_TEST( "File # Test", "$", specialname.arg( "#" ), specialname.arg( "#" ) );

    // load all plugins now
    //PluginLoader::instance()->loadPlugins( false ); // file plugins are not required

    // Testing system functions
    RUN_TOKEN_TEST( "Date Test", "[date]", filename, QDateTime::currentDateTime().toString( "dd-MM-yyyy") );
    RUN_TOKEN_TEST( "dd-MM-yyyy Date Test", "[date;dd-MM-yyyy]", 
                    filename, QDateTime::currentDateTime().toString( "dd-MM-yyyy") );
    RUN_TOKEN_TEST( "dd:MM:yyyy Date Test", "[date;dd:MM:yyyy]", 
                    filename, QDateTime::currentDateTime().toString( "dd:MM:yyyy") );
    RUN_TOKEN_TEST( "yy.mm.dd Date Test", "[date;yy.mm.dd]", 
                    filename, QDateTime::currentDateTime().toString( "yy.mm.dd") );
    RUN_TOKEN_TEST( "d Date Test", "[date;d]", filename, QDateTime::currentDateTime().toString( "d") );
    RUN_TOKEN_TEST( "dd Date Test", "[date;dd]", filename, QDateTime::currentDateTime().toString( "dd") );
    RUN_TOKEN_TEST( "ddd Date Test", "[date;ddd]", filename, QDateTime::currentDateTime().toString( "ddd") );
    RUN_TOKEN_TEST( "dddd Date Test", "[date;dddd]", filename, QDateTime::currentDateTime().toString( "dddd") );
    RUN_TOKEN_TEST( "M Date Test", "[date;M]", filename, QDateTime::currentDateTime().toString( "M") );
    RUN_TOKEN_TEST( "MM Date Test", "[date;MM]", filename, QDateTime::currentDateTime().toString( "MM") );
    RUN_TOKEN_TEST( "MMM Date Test", "[date;MMM]", filename, QDateTime::currentDateTime().toString( "MMM") );
    RUN_TOKEN_TEST( "MMMM Date Test", "[date;MMMM]", filename, QDateTime::currentDateTime().toString( "MMMM") );
    RUN_TOKEN_TEST( "yy Date Test", "[date;yy]", filename, QDateTime::currentDateTime().toString( "yy") );
    RUN_TOKEN_TEST( "yyyy Date Test", "[date;yyyy]", filename, QDateTime::currentDateTime().toString( "yyyy") );

    RUN_TOKEN_TEST( "h Date Test", "[date;h]", filename, QDateTime::currentDateTime().toString( "h") );
    RUN_TOKEN_TEST( "hh Date Test", "[date;hh]", filename, QDateTime::currentDateTime().toString( "hh") );
    RUN_TOKEN_TEST( "m Date Test", "[date;m]", filename, QDateTime::currentDateTime().toString( "m") );
    RUN_TOKEN_TEST( "mm Date Test", "[date;mm]", filename, QDateTime::currentDateTime().toString( "mm") );
    RUN_TOKEN_TEST( "s Date Test", "[date;s]", filename, QDateTime::currentDateTime().toString( "s") );
    RUN_TOKEN_TEST( "ss Date Test", "[date;ss]", filename, QDateTime::currentDateTime().toString( "ss") );
    // Current computers are to slow to compare two milliseconds as the instruction is longer than
    // a millisecond.
    //
    // RUN_TOKEN_TEST( "z Date Test", "[date;z]", filename, QDateTime::currentDateTime().toString( "z") );
    // RUN_TOKEN_TEST( "zzz Date Test", "[date;zzz]", filename, QDateTime::currentDateTime().toString( "zzz") );
    RUN_TOKEN_TEST( "ap Date Test", "[date;ap]", filename, QDateTime::currentDateTime().toString( "ap") );
    RUN_TOKEN_TEST( "AP Date Test", "[date;AP]", filename, QDateTime::currentDateTime().toString( "AP") );
    RUN_TOKEN_TEST( "Day Test", "[day]", filename, QDateTime::currentDateTime().toString( "dd") );
    RUN_TOKEN_TEST( "Month Test", "[month]", filename, QDateTime::currentDateTime().toString( "MM") );
    RUN_TOKEN_TEST( "Year Test", "[year]", filename, QDateTime::currentDateTime().toString( "yyyy") );
    RUN_TOKEN_TEST( "Hour Test", "[hour]", filename, QDateTime::currentDateTime().toString( "hh") );
    RUN_TOKEN_TEST( "Minute Test", "[minute]", filename, QDateTime::currentDateTime().toString( "mm") );
    RUN_TOKEN_TEST( "Second Test", "[second]", filename, QDateTime::currentDateTime().toString( "ss") );
    RUN_TOKEN_TEST( "Time Test", "[time]", filename, QDateTime::currentDateTime().toString( "hh-mm-ss") );

    // Testing numbering name, start, step, skip
    RUN_NUMBER_TESTS( "Numbers 0- Step 1", 0, 1, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 1- Step 1", 1, 1, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 2- Step 1", 2, 1, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers -2- Step 1", -2, 1, QList<int>() );

    RUN_NUMBER_TESTS( "Numbers 0- Step 2", 0, 2, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 1- Step 2", 1, 2, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 2- Step 2", 2, 2, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers -2- Step 2", -2, 2, QList<int>() );

    RUN_NUMBER_TESTS( "Numbers 0- Step 7", 0, 7, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 1- Step 7", 1, 7, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 2- Step 7", 2, 7, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers -2- Step 7", -2, 7, QList<int>() );

    RUN_NUMBER_TESTS( "Numbers 0- Step -3", 0, -3, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 1- Step -3", 1, -3, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers 2- Step -3", 2, -3, QList<int>() );
    RUN_NUMBER_TESTS( "Numbers -2- Step -3", -2, -3, QList<int>() );

    RUN_NUMBER_TESTS( "Skip 0- Step 1", 0, 1, QList<int>() << 1 << 2 << 3 << 4 << 89);
    RUN_NUMBER_TESTS( "Skip 1- Step 1", 1, 1, QList<int>() << 1 << 2 << 3 << 4 << 89);
    RUN_NUMBER_TESTS( "Skip 2- Step 1", 2, 1, QList<int>() << 1 << 2 << 3 << 4 << 89);
    RUN_NUMBER_TESTS( "Skip -2- Step 1", -2, 1, QList<int>() << 1 << 2 << 3 << 4 << 89);

    RUN_NUMBER_TESTS( "Skip 10- Step 79", 10, 79, QList<int>() << 1 << 2 << 3 << 4 << 89);
    RUN_NUMBER_TESTS( "Skip 10- Step -2", 10, -2, QList<int>() << 1 << 2 << 3 << 4 << 89);
    RUN_NUMBER_TESTS( "Skip 10- Step -1", 10, -1, QList<int>() << 1 << 2 << 3 << 4 << 89);

    // Test the find and replace feature of KRename
    RUN_REPLACE_TEST( "Replace: Spaces", "$", "Filename with spaces", "Filename_with_spaces", " ", "_", false );
    RUN_REPLACE_TEST( "Replace: Nothing", "$", "Filename", "Filename", " ", "_", false );
    RUN_REPLACE_TEST( "Replace: Word", "$", "Filename with spaces", "Filename HAS spaces", "with", "HAS", false );
    RUN_REPLACE_TEST( "Replace: $", "$", "Filename with $ and spaces", "Filename with ! and spaces", "$", "!", false );
    RUN_REPLACE_TEST( "Replace: &", "$", "Filename with & and spaces", "Filename with ! and spaces", "&", "!", false );
    RUN_REPLACE_TEST( "Replace: %", "$", "Filename with % and spaces", "Filename with ! and spaces", "%", "!", false );
    RUN_REPLACE_TEST( "Replace: *", "$", "Filename with * and spaces", "Filename with ! and spaces", "*", "!", false );
    RUN_REPLACE_TEST( "Replace: [", "$", "Filename with [ and spaces", "Filename with ! and spaces", "[", "!", false );
    RUN_REPLACE_TEST( "Replace: ]", "$", "Filename with ] and spaces", "Filename with ! and spaces", "]", "!", false );
    RUN_REPLACE_TEST( "Replace: #", "$", "Filename with # and spaces", "Filename with ! and spaces", "#", "!", false );
    RUN_REPLACE_TEST( "Replace: to $", "$", "Filename with spaces", "Filename $ spaces", "with", "$", false );
    RUN_REPLACE_TEST( "Replace: to &", "$", "Filename with spaces", "Filename & spaces", "with", "&", false );
    RUN_REPLACE_TEST( "Replace: to %", "$", "Filename with spaces", "Filename % spaces", "with", "%", false );
    RUN_REPLACE_TEST( "Replace: to *", "$", "Filename with spaces", "Filename * spaces", "with", "*", false );
    RUN_REPLACE_TEST( "Replace: to [", "$", "Filename with spaces", "Filename [ spaces", "with", "[", false );
    RUN_REPLACE_TEST( "Replace: to ]", "$", "Filename with spaces", "Filename ] spaces", "with", "]", false );
    RUN_REPLACE_TEST( "Replace: to #", "$", "Filename with spaces", "Filename # spaces", "with", "#", false );

    RUN_REPLACE_TEST( "RegExp: ?", "$", "Filename", "AAAAAAAAA", "[a-zA-z]?", "A", true );
    RUN_REPLACE_TEST( "RegExp: {1}", "$", "Filename", "AAAAAAAA", "[a-zA-z]{1}", "A", true );
    RUN_REPLACE_TEST( "RegExp: +", "$", "Filename", "A", "[a-zA-z]+", "A", true );
    RUN_REPLACE_TEST( "RegExp: \\d", "$", "Filename 123", "Filename NumberNumberNumber", "\\d", "Number", true );
    RUN_REPLACE_TEST( "RegExp: \\d+", "$", "Filename 123", "Filename Number", "\\d+", "Number", true );
    RUN_REPLACE_TEST( "RegExp: Match", "$", "Filename 123", "MATCHING", "[a-zA-z]* \\d{3}", "MATCHING", true );

    // TODO:
    // TODO: Manual Change Test

    // Regression tests
    // Caused an infinite loop
    RUN_TOKEN_TEST( "[1-2 [4-] Test", "[1-2 [4-]", filename, " " + filename.right( filename.length() - 3 ) );
    const char* regTemplate = "###{329;13";
    RUN_TOKEN_TEST( regTemplate, regTemplate, filename, "329" );
    RUN_TOKEN_TEST( "ABC {1", "ABC {1", filename, "ABC {1" );

    // Brackets appeared as \[ in the final result
    QString regressionName = "1-07 Take Flight (Wings) [Pocketman]";
    QString regressionExpect = "100-Take Flight (Wings) [Pocketman]";
    RUN_TOKEN_TEST( "1##-[$6-] Test", "1##-[$6-]", regressionName, regressionExpect );

    KRenameFile::List files;
    QStringList expected;
    QStringList expectedPaths;

    files << KRenameFile( KUrl("/home/foo/bar/subdir"), true, eSplitMode_FirstDot, 1 )
          << KRenameFile( KUrl("/home/foo"), true, eSplitMode_FirstDot, 1 )
          << KRenameFile( KUrl("/home/foo/bar"), true, eSplitMode_FirstDot, 1 )
          << KRenameFile( KUrl("/home/foo/bar/baz"), true, eSplitMode_FirstDot, 1 );
    expected << "SUBDIR" << "FOO" << "BAR" << "BAZ";
    expectedPaths << "/home/foo/bar" << "/home" << "/home/FOO" << "/home/FOO/BAR";

    RUN_KRENAME_MULTI_FILE_TEST( files, expected, expectedPaths, 
                                 "&", "Testing a directory hirarchy" );
}