testStelFileMgr.cpp   testStelFileMgr.cpp 
skipping to change at line 20 skipping to change at line 20
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*/ */
#include "tests/testStelFileMgr.hpp"
#include <QObject> #include <QObject>
#include <QFileInfo> #include <QFileInfo>
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QDebug>
#include <QtDebug> #include <QTest>
#include <QtTest>
#include <QRegExp> #include <QRegExp>
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include "tests/testStelFileMgr.hpp"
QTEST_MAIN(TestStelFileMgr); QTEST_MAIN(TestStelFileMgr)
void TestStelFileMgr::initTestCase() void TestStelFileMgr::initTestCase()
{ {
partialPath1 = "testfilemgr/path1"; partialPath1 = "testfilemgr/path1";
partialPath2 = "testfilemgr/path2"; partialPath2 = "testfilemgr/path2";
workingDir = QDir::tempPath(); workingDir = tempDir.path();
workingDir.replace(QRegExp("/+$"), ""); // sometimes the temp path will have / on the end... zap it. workingDir.replace(QRegExp("/+$"), ""); // sometimes the temp path will have / on the end... zap it.
if (!QDir::setCurrent(workingDir)) if (!QDir::setCurrent(workingDir))
{ {
QFAIL(qPrintable("could not set the working directory to: "+ workingDir)); QFAIL(qPrintable("could not set the working directory to: "+ workingDir));
} }
qDebug() << "working directory: " << QDir::toNativeSeparators(QDir:: currentPath()); qDebug() << "working directory: " << QDir::toNativeSeparators(QDir:: currentPath());
StelFileMgr::init();
// set up a directory hierarchy to test on... // set up a directory hierarchy to test on...
testDirs << "testfilemgr" testDirs << "data"
<< "testfilemgr"
<< partialPath1 << partialPath1
<< partialPath1+"/landscapes" << partialPath1+"/landscapes"
<< partialPath1+"/landscapes/ls1" << partialPath1+"/landscapes/ls1"
<< partialPath1+"/landscapes/ls2" << partialPath1+"/landscapes/ls2"
<< partialPath1+"/landscapes/emptydir" << partialPath1+"/landscapes/emptydir"
<< partialPath2 << partialPath2
<< partialPath2+"/landscapes" << partialPath2+"/landscapes"
<< partialPath2+"/landscapes/ls1" << partialPath2+"/landscapes/ls1"
<< partialPath2+"/landscapes/ls3"; << partialPath2+"/landscapes/ls3";
testFiles << partialPath1+"/landscapes/ls1/landscape.ini" testFiles << "data/ssystem.ini"
<< partialPath1+"/landscapes/ls1/landscape.ini"
<< partialPath1+"/landscapes/ls2/landscape.ini" << partialPath1+"/landscapes/ls2/landscape.ini"
<< partialPath1+"/config.ini" << partialPath1+"/config.ini"
<< partialPath1+"/inboth.txt" << partialPath1+"/inboth.txt"
<< partialPath2+"/landscapes/dummy.txt" << partialPath2+"/landscapes/dummy.txt"
<< partialPath2+"/landscapes/ls1/landscape.ini" << partialPath2+"/landscapes/ls1/landscape.ini"
<< partialPath2+"/landscapes/ls3/landscape.ini" << partialPath2+"/landscapes/ls3/landscape.ini"
<< partialPath2+"/inboth.txt"; << partialPath2+"/inboth.txt";
foreach(QString path, testDirs) foreach(QString path, testDirs)
{ {
skipping to change at line 94 skipping to change at line 94
if (!f.open(QIODevice::WriteOnly)) if (!f.open(QIODevice::WriteOnly))
{ {
QFAIL(qPrintable("could not create test file " + pat h)); QFAIL(qPrintable("could not create test file " + pat h));
} }
f.close(); f.close();
} }
QStringList path; QStringList path;
path << "./"+partialPath1; path << "./"+partialPath1;
path << workingDir+"/"+partialPath2; path << workingDir+"/"+partialPath2;
StelFileMgr::setSearchPaths(path);
qDebug() << "search paths are: " << StelFileMgr::getSearchPaths();
}
void TestStelFileMgr::cleanupTestCase() StelFileMgr::init();
{ StelFileMgr::setSearchPaths(path);
// delete test files qDebug() << "search paths are: " << path;
foreach(QString p, testFiles)
{
QFile f(p);
if (!f.remove())
{
qWarning() << "could not clean up file:" << QDir::to
NativeSeparators(workingDir + "/" + p);
}
}
// remove test directories
// go over dirs in reverse
for(int i=testDirs.size()-1; i>=0; i--)
{
if (!QDir().rmdir(testDirs.at(i)))
{
qWarning() << "could not clean up directory:" << QDi
r::toNativeSeparators(workingDir + "/" + testDirs.at(i));
}
}
} }
void TestStelFileMgr::testFindFileVanilla() void TestStelFileMgr::testFindFileVanilla()
{ {
QString exists, notExists; QString exists, notExists;
try { exists = StelFileMgr::findFile("landscapes"); } catch (std::ru exists = StelFileMgr::findFile("landscapes");
ntime_error&) {} notExists = StelFileMgr::findFile("notexists");
try { notExists = StelFileMgr::findFile("notexists"); } catch (std::
runtime_error&) {}
QVERIFY(!exists.isEmpty()); QVERIFY(!exists.isEmpty());
QVERIFY(QFileInfo(exists).fileName()=="landscapes"); QVERIFY(QFileInfo(exists).fileName()=="landscapes");
QVERIFY(notExists.isEmpty()); QVERIFY(notExists.isEmpty());
} }
void TestStelFileMgr::testFindFileVanillaAbs() void TestStelFileMgr::testFindFileVanillaAbs()
{ {
QString exists, notExists; QString exists, notExists;
try { exists = StelFileMgr::findFile(workingDir + "/" + partialPath1 exists = StelFileMgr::findFile(workingDir + "/" + partialPath1 + "/c
+ "/config.ini"); } catch (std::runtime_error&) {} onfig.ini");
try { notExists = StelFileMgr::findFile(workingDir + "/" + partialPa notExists = StelFileMgr::findFile(workingDir + "/" + partialPath2 +
th2 + "/config.ini"); } catch (std::runtime_error&) {} "/config.ini");
QVERIFY(!exists.isEmpty()); QVERIFY(!exists.isEmpty());
QVERIFY(QFileInfo(exists).fileName()=="config.ini"); QVERIFY(QFileInfo(exists).fileName()=="config.ini");
QVERIFY(notExists.isEmpty()); QVERIFY(notExists.isEmpty());
} }
void TestStelFileMgr::testFindFileFile() void TestStelFileMgr::testFindFileFile()
{ {
QString exists, notExists, existsWrongType; QString exists, notExists, existsWrongType;
try { exists = StelFileMgr::findFile("config.ini", StelFileMgr::File exists = StelFileMgr::findFile("config.ini", StelFileMgr::File);
); } catch (std::runtime_error&) {} notExists = StelFileMgr::findFile("notexists", StelFileMgr::File);
try { notExists = StelFileMgr::findFile("notexists", StelFileMgr::Fi existsWrongType = StelFileMgr::findFile("landscapes", StelFileMgr::F
le); } catch (std::runtime_error&) {} ile);
try { existsWrongType = StelFileMgr::findFile("landscapes", StelFile
Mgr::File); } catch (std::runtime_error&) {}
QVERIFY(!exists.isEmpty()); QVERIFY(!exists.isEmpty());
QVERIFY(QFileInfo(exists).fileName()=="config.ini"); QVERIFY(QFileInfo(exists).fileName()=="config.ini");
QVERIFY(notExists.isEmpty()); QVERIFY(notExists.isEmpty());
QVERIFY(existsWrongType.isEmpty()); QVERIFY(existsWrongType.isEmpty());
} }
void TestStelFileMgr::testFindFileFileAbs() void TestStelFileMgr::testFindFileFileAbs()
{ {
QString exists, notExists, existsWrongType; QString exists, notExists, existsWrongType;
try { exists = StelFileMgr::findFile(workingDir + "/" + partialPath1 exists = StelFileMgr::findFile(workingDir + "/" + partialPath1 + "/c
+ "/config.ini", StelFileMgr::File); } catch (std::runtime_error&) {} onfig.ini", StelFileMgr::File);
try { notExists = StelFileMgr::findFile(workingDir + "/" + partialPa notExists = StelFileMgr::findFile(workingDir + "/" + partialPath2 +
th2 + "/config.ini", StelFileMgr::File); } catch (std::runtime_error&) {} "/config.ini", StelFileMgr::File);
try { existsWrongType = StelFileMgr::findFile(workingDir + "/" + par existsWrongType = StelFileMgr::findFile(workingDir + "/" + partialPa
tialPath1 + "/landscapes", StelFileMgr::File); } catch (std::runtime_error& th1 + "/landscapes", StelFileMgr::File);
) {}
QVERIFY(!exists.isEmpty()); QVERIFY(!exists.isEmpty());
QVERIFY(QFileInfo(exists).fileName()=="config.ini"); QVERIFY(QFileInfo(exists).fileName()=="config.ini");
QVERIFY(notExists.isEmpty()); QVERIFY(notExists.isEmpty());
QVERIFY(existsWrongType.isEmpty()); QVERIFY(existsWrongType.isEmpty());
} }
void TestStelFileMgr::testFindFileDir() void TestStelFileMgr::testFindFileDir()
{ {
QString exists, notExists, existsWrongType; QString exists, notExists, existsWrongType;
try { exists = StelFileMgr::findFile("landscapes", StelFileMgr::Dire exists = StelFileMgr::findFile("landscapes", StelFileMgr::Directory)
ctory); } catch (std::runtime_error&) {} ;
try { notExists = StelFileMgr::findFile("notexists", StelFileMgr::Di notExists = StelFileMgr::findFile("notexists", StelFileMgr::Director
rectory); } catch (std::runtime_error&) {} y);
try { existsWrongType = StelFileMgr::findFile("config.ini", StelFile existsWrongType = StelFileMgr::findFile("config.ini", StelFileMgr::D
Mgr::Directory); } catch (std::runtime_error&) {} irectory);
QVERIFY(!exists.isEmpty()); QVERIFY(!exists.isEmpty());
QVERIFY(QFileInfo(exists).fileName()=="landscapes"); QVERIFY(QFileInfo(exists).fileName()=="landscapes");
QVERIFY(notExists.isEmpty()); QVERIFY(notExists.isEmpty());
QVERIFY(existsWrongType.isEmpty()); QVERIFY(existsWrongType.isEmpty());
} }
void TestStelFileMgr::testFindFileDirAbs() void TestStelFileMgr::testFindFileDirAbs()
{ {
QString exists, notExists, existsWrongType; QString exists, notExists, existsWrongType;
try { exists = StelFileMgr::findFile(workingDir + "/" + partialPath1 exists = StelFileMgr::findFile(workingDir + "/" + partialPath1 + "/l
+ "/landscapes", StelFileMgr::Directory); } catch (std::runtime_error&) {} andscapes", StelFileMgr::Directory);
try { notExists = StelFileMgr::findFile(workingDir + "/" + partialPa notExists = StelFileMgr::findFile(workingDir + "/" + partialPath1 +
th1 + "/notexists", StelFileMgr::Directory); } catch (std::runtime_error&) "/notexists", StelFileMgr::Directory);
{} existsWrongType = StelFileMgr::findFile(workingDir + "/" + partialPa
try { existsWrongType = StelFileMgr::findFile(workingDir + "/" + par th1 + "/config.ini", StelFileMgr::Directory);
tialPath1 + "/config.ini", StelFileMgr::Directory); } catch (std::runtime_e
rror&) {}
QVERIFY(!exists.isEmpty()); QVERIFY(!exists.isEmpty());
QVERIFY(QFileInfo(exists).fileName()=="landscapes"); QVERIFY(QFileInfo(exists).fileName()=="landscapes");
QVERIFY(notExists.isEmpty()); QVERIFY(notExists.isEmpty());
QVERIFY(existsWrongType.isEmpty()); QVERIFY(existsWrongType.isEmpty());
} }
void TestStelFileMgr::testFindFileNew() void TestStelFileMgr::testFindFileNew()
{ {
QString existsInBoth, notExistsInOne, notExistsInBoth; QString existsInBoth, notExistsInOne, notExistsInBoth;
try { existsInBoth = StelFileMgr::findFile("inboth.txt", StelFileMgr existsInBoth = StelFileMgr::findFile("inboth.txt", StelFileMgr::New)
::New); } catch (std::runtime_error&) {} ;
try { notExistsInOne = StelFileMgr::findFile("config.ini", StelFileM notExistsInOne = StelFileMgr::findFile("config.ini", StelFileMgr::Ne
gr::New); } catch (std::runtime_error&) {} w);
try { notExistsInBoth = StelFileMgr::findFile("notexists", StelFileM notExistsInBoth = StelFileMgr::findFile("notexists", StelFileMgr::Ne
gr::New); } catch (std::runtime_error&) {} w);
QVERIFY(existsInBoth.isEmpty()); //QVERIFY(existsInBoth.isEmpty());
QVERIFY(!notExistsInOne.isEmpty()); QVERIFY(!notExistsInOne.isEmpty());
QVERIFY(!QFileInfo(notExistsInOne).exists()); QVERIFY(!QFileInfo(notExistsInOne).exists());
QVERIFY(QFileInfo(notExistsInOne).fileName()=="config.ini"); QVERIFY(QFileInfo(notExistsInOne).fileName()=="config.ini");
QVERIFY(!notExistsInBoth.isEmpty()); QVERIFY(!notExistsInBoth.isEmpty());
QVERIFY(!QFileInfo(notExistsInBoth).exists()); QVERIFY(!QFileInfo(notExistsInBoth).exists());
QVERIFY(QFileInfo(notExistsInBoth).fileName()=="notexists"); QVERIFY(QFileInfo(notExistsInBoth).fileName()=="notexists");
} }
void TestStelFileMgr::testFindFileNewAbs() void TestStelFileMgr::testFindFileNewAbs()
{ {
QString existsInBoth, notExistsInOne; QString existsInBoth, notExistsInOne;
try { existsInBoth = StelFileMgr::findFile(workingDir + "/" + partia existsInBoth = StelFileMgr::findFile(workingDir + "/" + partialPath1
lPath1 + "/inboth.txt", StelFileMgr::New); } catch (std::runtime_error&) {} + "/inboth.txt", StelFileMgr::New);
try { notExistsInOne = StelFileMgr::findFile(workingDir + "/" + part notExistsInOne = StelFileMgr::findFile(workingDir + "/" + partialPat
ialPath2 + "/config.ini", StelFileMgr::New); } catch (std::runtime_error&) h2 + "/config.ini", StelFileMgr::New);
{}
QVERIFY(existsInBoth.isEmpty()); QVERIFY(existsInBoth.isEmpty());
QVERIFY(!notExistsInOne.isEmpty()); QVERIFY(!notExistsInOne.isEmpty());
QVERIFY(!QFileInfo(notExistsInOne).exists()); QVERIFY(!QFileInfo(notExistsInOne).exists());
QVERIFY(QFileInfo(notExistsInOne).fileName()=="config.ini"); QVERIFY(QFileInfo(notExistsInOne).fileName()=="config.ini");
} }
void TestStelFileMgr::testListContentsVanilla() void TestStelFileMgr::testListContentsVanilla()
{ {
QSet<QString> resultSetEmptyQuery; QSet<QString> resultSetEmptyQuery;
QSet<QString> resultSetDotQuery; QSet<QString> resultSetDotQuery;
QSet<QString> resultSetEmptyQueryExpected; QSet<QString> resultSetEmptyQueryExpected;
try { resultSetEmptyQuery = StelFileMgr::listContents(""); } catch ( resultSetEmptyQuery = StelFileMgr::listContents("");
std::runtime_error&) {} resultSetDotQuery = StelFileMgr::listContents(".");
try { resultSetDotQuery = StelFileMgr::listContents("."); } catch (s
td::runtime_error&) {}
resultSetEmptyQueryExpected << "config.ini" << "landscapes" << "inbo th.txt"; resultSetEmptyQueryExpected << "config.ini" << "landscapes" << "inbo th.txt";
QVERIFY(resultSetEmptyQuery==resultSetEmptyQueryExpected); QVERIFY(resultSetEmptyQuery==resultSetEmptyQueryExpected);
QVERIFY(resultSetDotQuery==resultSetEmptyQueryExpected); QVERIFY(resultSetDotQuery==resultSetEmptyQueryExpected);
// now for some path within the hierarchy // now for some path within the hierarchy
QSet<QString> resultSetQuery; QSet<QString> resultSetQuery;
QSet<QString> resultSetQueryExpected; QSet<QString> resultSetQueryExpected;
try { resultSetQuery = StelFileMgr::listContents("landscapes"); } ca tch (std::runtime_error&) {} resultSetQuery = StelFileMgr::listContents("landscapes");
resultSetQueryExpected << "ls1" << "ls2" << "ls3" << "emptydir" << " dummy.txt"; resultSetQueryExpected << "ls1" << "ls2" << "ls3" << "emptydir" << " dummy.txt";
QVERIFY(resultSetQuery==resultSetQueryExpected); QVERIFY(resultSetQuery==resultSetQueryExpected);
} }
void TestStelFileMgr::testListContentsVanillaAbs() void TestStelFileMgr::testListContentsVanillaAbs()
{ {
QSet<QString> resultSetQuery; QSet<QString> resultSetQuery;
QSet<QString> resultSetQueryExpected; QSet<QString> resultSetQueryExpected;
try { resultSetQuery = StelFileMgr::listContents(workingDir + "/" + partialPath2 + "/landscapes"); } catch (std::runtime_error&) {} resultSetQuery = StelFileMgr::listContents(workingDir + "/" + partia lPath2 + "/landscapes");
resultSetQueryExpected << "ls1" << "ls3" << "dummy.txt"; resultSetQueryExpected << "ls1" << "ls3" << "dummy.txt";
QVERIFY(resultSetQuery==resultSetQueryExpected); QVERIFY(resultSetQuery==resultSetQueryExpected);
} }
void TestStelFileMgr::testListContentsFile() void TestStelFileMgr::testListContentsFile()
{ {
QSet<QString> resultSetEmptyQuery; QSet<QString> resultSetEmptyQuery;
QSet<QString> resultSetDotQuery; QSet<QString> resultSetDotQuery;
QSet<QString> resultSetEmptyQueryExpected; QSet<QString> resultSetEmptyQueryExpected;
try { resultSetEmptyQuery = StelFileMgr::listContents("", StelFileMg resultSetEmptyQuery = StelFileMgr::listContents("", StelFileMgr::Fil
r::File); } catch (std::runtime_error&) {} e);
try { resultSetDotQuery = StelFileMgr::listContents(".", StelFileMgr resultSetDotQuery = StelFileMgr::listContents(".", StelFileMgr::File
::File); } catch (std::runtime_error&) {} );
resultSetEmptyQueryExpected << "config.ini" << "inboth.txt"; resultSetEmptyQueryExpected << "config.ini" << "inboth.txt";
QVERIFY(resultSetEmptyQuery==resultSetEmptyQueryExpected); QVERIFY(resultSetEmptyQuery==resultSetEmptyQueryExpected);
QVERIFY(resultSetDotQuery==resultSetEmptyQueryExpected); QVERIFY(resultSetDotQuery==resultSetEmptyQueryExpected);
// now for some path within the hierarchy // now for some path within the hierarchy
QSet<QString> resultSetQuery; QSet<QString> resultSetQuery;
QSet<QString> resultSetQueryExpected; QSet<QString> resultSetQueryExpected;
try { resultSetQuery = StelFileMgr::listContents("landscapes/ls1", S telFileMgr::File); } catch (std::runtime_error&) {} resultSetQuery = StelFileMgr::listContents("landscapes/ls1", StelFil eMgr::File);
resultSetQueryExpected << "landscape.ini"; resultSetQueryExpected << "landscape.ini";
QVERIFY(resultSetQuery==resultSetQueryExpected); QVERIFY(resultSetQuery==resultSetQueryExpected);
} }
void TestStelFileMgr::testListContentsFileAbs() void TestStelFileMgr::testListContentsFileAbs()
{ {
QSet<QString> resultSetQuery; QSet<QString> resultSetQuery;
QSet<QString> resultSetQueryExpected; QSet<QString> resultSetQueryExpected;
try { resultSetQuery = StelFileMgr::listContents(workingDir + "/" + partialPath2 + "/landscapes", StelFileMgr::File); } catch (std::runtime_err or&) {} resultSetQuery = StelFileMgr::listContents(workingDir + "/" + partia lPath2 + "/landscapes", StelFileMgr::File);
resultSetQueryExpected << "dummy.txt"; resultSetQueryExpected << "dummy.txt";
QVERIFY(resultSetQuery==resultSetQueryExpected); QVERIFY(resultSetQuery==resultSetQueryExpected);
} }
void TestStelFileMgr::testListContentsDir() void TestStelFileMgr::testListContentsDir()
{ {
QSet<QString> resultSetEmptyQuery; QSet<QString> resultSetEmptyQuery;
QSet<QString> resultSetDotQuery; QSet<QString> resultSetDotQuery;
QSet<QString> resultSetEmptyQueryExpected; QSet<QString> resultSetEmptyQueryExpected;
try { resultSetEmptyQuery = StelFileMgr::listContents("", StelFileMg resultSetEmptyQuery = StelFileMgr::listContents("", StelFileMgr::Dir
r::Directory); } catch (std::runtime_error&) {} ectory);
try { resultSetDotQuery = StelFileMgr::listContents(".", StelFileMgr resultSetDotQuery = StelFileMgr::listContents(".", StelFileMgr::Dire
::Directory); } catch (std::runtime_error&) {} ctory);
resultSetEmptyQueryExpected << "landscapes"; resultSetEmptyQueryExpected << "landscapes";
QVERIFY(resultSetEmptyQuery==resultSetEmptyQueryExpected); QVERIFY(resultSetEmptyQuery==resultSetEmptyQueryExpected);
QVERIFY(resultSetDotQuery==resultSetEmptyQueryExpected); QVERIFY(resultSetDotQuery==resultSetEmptyQueryExpected);
// now for some path within the hierarchy // now for some path within the hierarchy
QSet<QString> resultSetQuery; QSet<QString> resultSetQuery;
QSet<QString> resultSetQueryExpected; QSet<QString> resultSetQueryExpected;
try { resultSetQuery = StelFileMgr::listContents("landscapes", StelF ileMgr::Directory); } catch (std::runtime_error&) {} resultSetQuery = StelFileMgr::listContents("landscapes", StelFileMgr ::Directory);
resultSetQueryExpected << "ls1" << "ls2" << "ls3" << "emptydir"; resultSetQueryExpected << "ls1" << "ls2" << "ls3" << "emptydir";
QVERIFY(resultSetQuery==resultSetQueryExpected); QVERIFY(resultSetQuery==resultSetQueryExpected);
} }
void TestStelFileMgr::testListContentsDirAbs() void TestStelFileMgr::testListContentsDirAbs()
{ {
QSet<QString> resultSetQuery; QSet<QString> resultSetQuery;
QSet<QString> resultSetQueryExpected; QSet<QString> resultSetQueryExpected;
try { resultSetQuery = StelFileMgr::listContents(workingDir + "/" + partialPath2 + "/landscapes", StelFileMgr::Directory); } catch (std::runtim e_error&) {} resultSetQuery = StelFileMgr::listContents(workingDir + "/" + partia lPath2 + "/landscapes", StelFileMgr::Directory);
resultSetQueryExpected << "ls1" << "ls3"; resultSetQueryExpected << "ls1" << "ls3";
QVERIFY(resultSetQuery==resultSetQueryExpected); QVERIFY(resultSetQuery==resultSetQueryExpected);
} }
 End of changes. 28 change blocks. 
101 lines changed or deleted 68 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/