BinaryReaderTest.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "../BinaryReader.h"
00025 #include "../Extensions/QueryExtension.h"
00026 #include "../Extensions/QueryHitsExtension.h"
00027 #include "Imports.cpp"
00028 
00029 namespace Protocols {
00030 namespace Gnutella {
00031 namespace Packets {
00032 namespace Testing {
00033 
00034 class BinaryReaderTest : public CppUnit::TestFixture
00035 {
00036     CPPUNIT_TEST_SUITE (BinaryReaderTest);
00037     CPPUNIT_TEST (testReadUuid);
00038     CPPUNIT_TEST (testReadGgepBlockEmpty);
00039     CPPUNIT_TEST (testReadGgepBlockOneUnknownGgep);
00040     CPPUNIT_TEST (testReadGgepBlockOneUnknownGgepLongData);
00041     CPPUNIT_TEST (testReadGgepBlockTwoUnknownGgeps);
00042     CPPUNIT_TEST (testReadIPv4Address);
00043     CPPUNIT_TEST (testReadQueryExtensionOneXml);
00044     CPPUNIT_TEST (testReadQueryExtensionOneHuge);
00045     CPPUNIT_TEST (testReadQueryExtensionOneGgepBlock);
00046     CPPUNIT_TEST (testReadQueryExtensionOneUnknown);
00047     CPPUNIT_TEST (testReadQueryExtensionMixed);
00048     CPPUNIT_TEST (testReadQueryExtensionHugeZero);
00049     CPPUNIT_TEST (testReadMinSpeed);
00050     CPPUNIT_TEST (testReadResultSetOneResultOneUrn);
00051     CPPUNIT_TEST (testReadResultSetOneResultOneGgepBlock);
00052     CPPUNIT_TEST (testReadResultSetOneResultOnePlainData);
00053     CPPUNIT_TEST (testReadResultSetOneResultMixedData);
00054     CPPUNIT_TEST (testReadResultSetTwoResults);
00055     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsAllSet);
00056     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsPushNotSet);
00057     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsBusyNotSet);
00058     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsHaveUploadedNotSet);
00059     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsUploadSpeedNotSet);
00060     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsGgepNotSet);
00061     CPPUNIT_TEST (testReadQueryHitsDataCheckFlagsNoneSet);
00062     CPPUNIT_TEST (testReadQueryHitsDataNoGgepBlockNoXmlData);
00063     CPPUNIT_TEST (testReadQueryHitsDataXmlData);
00064     CPPUNIT_TEST (testReadQueryHitsDataGgepBlock);
00065     CPPUNIT_TEST (testReadQueryHitsDataGgepBlockXmlData);
00066     CPPUNIT_TEST (testReadQueryHitsDataGgepBlockXmlDataOther);
00067     CPPUNIT_TEST_SUITE_END();
00068 
00069 public:
00070     void scenarioReadUuid (const QByteArray &rawUuid,
00071                            uint l, ushort w1, ushort w2, uchar b1, uchar b2,
00072                            uchar b3, uchar b4, uchar b5, uchar b6, uchar b7,
00073                            uchar b8)
00074     {
00075         QUuid uuid (l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8);
00076         BinaryReader reader (rawUuid);
00077         QUuid readUuid = reader.readUuid();
00078         CPPUNIT_ASSERT (uuid == readUuid);
00079         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00080     }
00081 
00082     void testReadUuid()
00083     {
00084         scenarioReadUuid (QByteArray ("\x67\xc8\x77\x0b\x44\xf1\x41\x0a"
00085                                       "\xab\x9a\xf9\xb5\x44\x6f\x13\xee", 16),
00086                           0x67c8770b, 0x44f1, 0x410a,
00087                           0xab, 0x9a, 0xf9, 0xb5, 0x44, 0x6f, 0x13, 0xee);
00088         scenarioReadUuid (QByteArray ("\x00\x00\x11\x11\xff\xff\xaa\xaa"
00089                                       "\xab\xab\xf9\xb5\x44\x00\xee\xff", 16),
00090                           0x00001111, 0xffff, 0xaaaa,
00091                           0xab, 0xab, 0xf9, 0xb5, 0x44, 0x00, 0xee, 0xff);
00092         scenarioReadUuid (QByteArray ("\x11\x11\x11\x11\x33\x33\x55\x55"
00093                                       "\xee\xff\x22\x44\x66\x88\x00\xcc", 16),
00094                           0x11111111, 0x3333, 0x5555,
00095                           0xee, 0xff, 0x22, 0x44, 0x66, 0x88, 0x00, 0xcc);
00096     }
00097 
00098     void scenarioReadGgepBlock (QByteArray rawGgepBlock,
00099                                 const GgepBlock &block)
00100     {
00101         BinaryReader reader (rawGgepBlock);
00102         GgepBlock readBlock = reader.readGgepBlock();
00103         CPPUNIT_ASSERT (block == readBlock);
00104         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00105     }
00106 
00108     void testReadGgepBlockEmpty()
00109     {
00110         scenarioReadGgepBlock (QByteArray(), GgepBlock());
00111     }
00112 
00113     void testReadGgepBlockOneUnknownGgep()
00114     {
00115         QByteArray id ("UNKN");
00116         QByteArray data ("fortest");
00117         // Manually build raw data.
00118         QByteArray rawBytes;
00119         // GGEP magic byte:
00120         rawBytes.append (static_cast <char> (0xC3));
00121         // First extension header:
00122         rawBytes.append (Ggep::LastExtension | id.length()); // flags
00123         rawBytes.append (id); // id
00124         rawBytes.append (0x40 | data.length()); // datalength
00125         // First extension data:
00126         rawBytes.append (data);
00127         // Prepare the block that should be read.
00128         GgepBlock block;
00129         block.addExtension (Ggeps::Unknown (id, data));
00130         scenarioReadGgepBlock (rawBytes, block);
00131     }
00132 
00133     void testReadGgepBlockOneUnknownGgepLongData()
00134     {
00135         QByteArray id ("UNKN");
00136         QByteArray data (64, '1');
00137         // Manually build raw data.
00138         QByteArray rawBytes;
00139         // GGEP magic byte:
00140         rawBytes.append (static_cast <char> (0xC3));
00141         // First extension header:
00142         rawBytes.append (Ggep::LastExtension | id.length());        // flags
00143         rawBytes.append (id);                                       // id
00144         // 2 bytes data length:
00145         rawBytes.append (static_cast <char> (0x80 | (64 >> 6)));
00146         rawBytes.append (static_cast <char> (0x40 | (64 & 0x3F)));
00147         // First extension data:
00148         rawBytes.append (data);
00149         // Prepare the block that should be read.
00150         GgepBlock block;
00151         block.addExtension (Ggeps::Unknown (id, data));
00152         scenarioReadGgepBlock (rawBytes, block);
00153     }
00154 
00155     void testReadGgepBlockTwoUnknownGgeps()
00156     {
00157         QByteArray id1 ("UNKN");
00158         QByteArray data1 ("fortest");
00159         QByteArray id2 ("unkn");
00160         QByteArray data2 ("fortest2");
00161         // Manually build raw data.
00162         QByteArray rawBytes;
00163         // GGEP magic byte:
00164         rawBytes.append (static_cast <char> (0xC3));
00165         // First extension header:
00166         rawBytes.append (id1.length()); // flags
00167         rawBytes.append (id1); // id
00168         rawBytes.append (0x40 | data1.length()); // datalength
00169         // First extension data:
00170         rawBytes.append (data1);
00171         // Second extension header:
00172         rawBytes.append (Ggep::LastExtension | id2.length()); // flags
00173         rawBytes.append (id2); // id
00174         rawBytes.append (0x40 | data2.length()); // datalength
00175         // Second extension data:
00176         rawBytes.append (data2);
00177         // Prepare the block that should be read.
00178         GgepBlock block;
00179         block.addExtension (Ggeps::Unknown (id1, data1));
00180         block.addExtension (Ggeps::Unknown (id2, data2));
00181         scenarioReadGgepBlock (rawBytes, block);
00182     }
00183 
00184     void scenarioReadIPv4Address (quint32 address)
00185     {
00186         QByteArray  rawBytes;
00187         uchar       byte;
00188         // BigEndian
00189         rawBytes.append (byte = (address & 0xff000000) >> 24);
00190         rawBytes.append (byte = (address & 0x00ff0000) >> 16);
00191         rawBytes.append (byte = (address & 0x0000ff00) >> 8);
00192         rawBytes.append (byte = address & 0x000000ff);
00193         BinaryReader    reader (rawBytes);
00194         CPPUNIT_ASSERT (reader.readIPv4Address().toIPv4Address() == address);
00195         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00196     }
00197     // Maybe I should make several func to 1 scenario each, but I'm not sure
00198     // how to deal with it.
00199     void testReadIPv4Address ()
00200     {
00201         scenarioReadIPv4Address (0x7f000001);   // 127.0.0.1
00202         scenarioReadIPv4Address (0xc0a80148);   // 192.168.1.72
00203         scenarioReadIPv4Address (0x55d63cb9);   // 85.214.60.185
00204         scenarioReadIPv4Address (0x00000000);   // 0.0.0.0
00205     }
00206 
00207     void scenarioReadQueryExtension(QByteArray rawBytes,
00208                                     const QueryData &extension)
00209     {
00210         BinaryReader reader (rawBytes);
00211         CPPUNIT_ASSERT (reader.readQueryData() == extension);
00212         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00213     }
00214 
00215     void testReadQueryExtensionOneXml()
00216     {
00217         QueryData       extension;
00218         extension.xmlList += QByteArray ("<xmltest/>");
00219         scenarioReadQueryExtension (QByteArray ("<xmltest/>"), extension);
00220     }
00221 
00222     void testReadQueryExtensionOneHuge()
00223     {
00224         QueryData       extension;
00225         extension.urnList += QByteArray ("urn: hugetest");
00226         scenarioReadQueryExtension (QByteArray ("urn: hugetest"), extension);
00227     }
00228 
00229     void testReadQueryExtensionOneUnknown()
00230     {
00231         QueryData       extension;
00232         extension.unknownList += QByteArray ("dunnotest");
00233         scenarioReadQueryExtension (QByteArray ("dunnotest"), extension);
00234     }
00235 
00236     void testReadQueryExtensionOneGgepBlock()
00237     {
00238         QueryData       extension;
00239         extension.ggepBlock =  GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00240         scenarioReadQueryExtension (QByteArray ("\xC3\x84UNKN\107fortest", 14), extension);
00241     }
00242 
00243     void testReadQueryExtensionMixed()
00244     {
00245         QueryData       extension;
00246         extension.xmlList += QByteArray ("<xmltest/>");
00247         extension.xmlList += QByteArray ("{xmltest2/}");
00248         extension.urnList  += QByteArray ("urn: hugetest");
00249         extension.unknownList  += QByteArray ("dunnotest");
00250         extension.ggepBlock = GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00251         scenarioReadQueryExtension (QByteArray ("<xmltest/>\x1c\144unnotest\x1curn: hugetest\x1c{xmltest2/}\x1c\xC3\x84UNKN\107fortest"), extension);
00252     }
00253 
00255     void testReadQueryExtensionHugeZero()
00256     {
00257         QueryData       extension;
00258         extension.urnList += QByteArray ("urn: hugetest");
00259         scenarioReadQueryExtension (QByteArray ("urn: hugetest\0", 14), extension);
00260     }
00261 
00262     void scenarioReadMinSpeed(bool f1,bool f2,bool f3,bool f4,bool f5,bool f6, uchar byte)
00263     {
00264         QByteArray  rawBytes;
00265         uchar flags = 0x80;
00266         if(f2) flags |= 0x40;
00267         if(f3) flags |= 0x20;
00268         if(f4) flags |= 0x10;
00269         if(f5) flags |= 0x08;
00270         if(f6) flags |= 0x04;
00271         rawBytes.append (flags);
00272         rawBytes.append (byte);
00273         BinaryReader reader (rawBytes);
00274         if(f1)
00275             CPPUNIT_ASSERT (reader.readMinSpeed() == MinSpeed (f1,f2,f3,f4,f5,f6,byte));
00276         else
00277             CPPUNIT_ASSERT (reader.readMinSpeed() == MinSpeed());
00278         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00279     }
00280 
00281     void testReadMinSpeed()
00282     {
00283         scenarioReadMinSpeed (true, true, true, true, true, true, '\110');
00284         scenarioReadMinSpeed (true, true, true, true, true, false, '\110');
00285         scenarioReadMinSpeed (true, true, true, true, false, false, '\110');
00286         scenarioReadMinSpeed (true, true, true, false, false, false, '\110');
00287         scenarioReadMinSpeed (true, true, false, false, false, false, '\110');
00288         scenarioReadMinSpeed (true, false, false, false, false, false, '\110');
00289     }
00290 
00297     void scenarioReadResultSet(const ResultData &resultData,
00298                                const QByteArray &bytes, int number)
00299     {
00300         QByteArray rawBytes ("\x11\x22\x33\x44\x33\x44\x55\x66TAOCP\0",14);
00301         rawBytes.append (bytes);
00302         ResultSet rs;
00303         Result result;
00304         result.fileIndex = 0x44332211;
00305         result.fileSize = 0x66554433;
00306         result.fullFileName = "TAOCP";
00307         result.resultData = resultData;
00308         for(int i=0;i<number;++i)
00309             rs.append (result);
00310         for(int i=0;i<number-1;++i)
00311             rawBytes.append (rawBytes);
00312         BinaryReader reader (rawBytes);
00313         CPPUNIT_ASSERT (rs == reader.readQueryHitsResultSet(number));
00314         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00315     }
00316 
00317     void testReadResultSetOneResultOneUrn()
00318     {
00319         ResultData resultData;
00320         resultData.urnList.append ("urn:test");
00321         QByteArray rawBytes ("urn:test\0", 9);
00322         scenarioReadResultSet (resultData, rawBytes, 1);
00323     }
00324     void testReadResultSetOneResultOneGgepBlock()
00325     {
00326         ResultData resultData;
00327         resultData.ggepBlock = GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00328         QByteArray rawBytes ("\xC3\x84UNKN\107fortest\0", 15);
00329         scenarioReadResultSet (resultData, rawBytes, 1);
00330     }
00331     void testReadResultSetOneResultOnePlainData()
00332     {
00333         ResultData resultData;
00334         resultData.unknownList.append ("plain:test");
00335         QByteArray rawBytes ("plain:test\0", 11);
00336         scenarioReadResultSet (resultData, rawBytes, 1);
00337     }
00338     void testReadResultSetOneResultMixedData()
00339     {
00340         ResultData resultData;
00341         resultData.unknownList.append ("plain:test");
00342         resultData.ggepBlock = GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00343         resultData.urnList.append ("urn:test");
00344         resultData.xmlList.append ("<book></book>");
00345         QByteArray rawBytes ("plain:test\x1curn:test\x1c<book></book>\x1c\xC3\x84UNKN\107fortest\0", 49);
00346         scenarioReadResultSet (resultData, rawBytes, 1);
00347     }
00348     void testReadResultSetTwoResults()
00349     {
00350         scenarioReadResultSet (ResultData(), QByteArray("\0", 1), 2);
00351     }
00352 
00353     void scenarioReadQueryHitsDataCheckFlags (bool ggep, bool uploadSpeed,
00354                                               bool haveUploaded, bool busy,
00355                                               bool push, const char flags[2])
00356     {
00357         QueryHitsData hitsData;
00358         if (ggep)
00359             hitsData.ggepBlock.addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00360         hitsData.flagUploadSpeed = uploadSpeed;
00361         hitsData.flagHaveUploaded = haveUploaded;
00362         hitsData.flagBusy = busy;
00363         hitsData.flagPush = push;
00364 
00365         QByteArray rawBytes = hitsData.vendorCode.toBytes();
00366         rawBytes += "\x02"; // Only flags in open vendor area.
00367         rawBytes += flags; // The two bytes of flags.
00368         if (ggep) // GGEP block bytes if any.
00369             rawBytes += QByteArray ("\xC3\x84UNKN\107fortest");
00370         rawBytes += QByteArray (16, '\0'); // Null serventId.
00371 
00372         BinaryReader reader (rawBytes);
00373         QueryHitsData readHitsData = reader.readQueryHitsData();
00374 
00375         CPPUNIT_ASSERT (hitsData == readHitsData);
00376     }
00377 
00378     void testReadQueryHitsDataCheckFlagsAllSet()
00379     {
00380         scenarioReadQueryHitsDataCheckFlags (true, true, true, true, true,
00381                                              "\x3d\x3d");
00382     }
00383 
00384     void testReadQueryHitsDataCheckFlagsPushNotSet()
00385     {
00386         scenarioReadQueryHitsDataCheckFlags (true, true, true, true, false,
00387                                              "\x3c\x3d");
00388     }
00389 
00390     void testReadQueryHitsDataCheckFlagsBusyNotSet()
00391     {
00392         scenarioReadQueryHitsDataCheckFlags (true, true, true, false, true,
00393                                              "\x3d\x39");
00394     }
00395 
00396     void testReadQueryHitsDataCheckFlagsHaveUploadedNotSet()
00397     {
00398         scenarioReadQueryHitsDataCheckFlags (true, true, false, true, true,
00399                                              "\x3d\x35");
00400     }
00401 
00402     void testReadQueryHitsDataCheckFlagsUploadSpeedNotSet()
00403     {
00404         scenarioReadQueryHitsDataCheckFlags (true, false, true, true, true,
00405                                              "\x3d\x2d");
00406     }
00407 
00408     void testReadQueryHitsDataCheckFlagsGgepNotSet()
00409     {
00410         scenarioReadQueryHitsDataCheckFlags (false, true, true, true, true,
00411                                              "\x3d\x1d");
00412     }
00413 
00414     void testReadQueryHitsDataCheckFlagsNoneSet()
00415     {
00416         scenarioReadQueryHitsDataCheckFlags (false, false, false, false, false,
00417                                              "\x3c\x01");
00418     }
00419 
00420     void scenarioReadQueryHitsData(QueryHitsData &hitsData,QByteArray &bytes)
00421     {
00422         //hitsData.vendorCode   =   VendorCode();
00423         hitsData.flagUploadSpeed = false;
00424         hitsData.flagHaveUploaded = false;
00425         hitsData.flagBusy = false;
00426         hitsData.flagPush = false;
00427         hitsData.serventId  =   QUuid (0x11111111, 0x3333, 0x5555, 0xee, 0xff,
00428                                  0x22, 0x44, 0x66, 0x88, 0x00, 0xcc);
00429         QByteArray rawBytes ("\x11\x11\x11\x11\x33\x33\x55\x55\xee\xff\x22\x44\x66\x88\0\xcc", 16);
00430         bytes.append (rawBytes);
00431         BinaryReader reader (bytes);
00432         CPPUNIT_ASSERT (hitsData == reader.readQueryHitsData());
00433         CPPUNIT_ASSERT (reader.hasReadAll() && !reader.hasReadPastEnd());
00434     }
00435 
00436     void testReadQueryHitsDataNoQHD()
00437     {
00439         // all other fields that have not been set.
00440     }
00441 
00442     void testReadQueryHitsDataNoGgepBlockNoXmlData()
00443     {
00444         QueryHitsData hitsData;
00445         QByteArray rawBytes ("UNKN\x02\x20\x0", 7);
00446         scenarioReadQueryHitsData (hitsData, rawBytes);
00447     }
00448 
00449     void testReadQueryHitsDataXmlData()
00450     {
00451         QueryHitsData hitsData;
00452         hitsData.xmlData = QByteArray("<xmltest/>");
00453         QByteArray rawBytes ("UNKN\x04\x20\x0\xb\x0<xmltest/>\0", 20);
00454         scenarioReadQueryHitsData (hitsData, rawBytes);
00455     }
00456     void testReadQueryHitsDataGgepBlock()
00457     {
00458         QueryHitsData hitsData;
00459         hitsData.ggepBlock = GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00460         QByteArray rawBytes ("UNKN\x02\x20\x20\xC3\x84UNKN\107fortest", 21);
00461         scenarioReadQueryHitsData (hitsData, rawBytes);
00462     }
00463     void testReadQueryHitsDataGgepBlockXmlData()
00464     {
00465         QueryHitsData hitsData;
00466         hitsData.xmlData = QByteArray("<xmltest/>");
00467         hitsData.ggepBlock = GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00468         QByteArray rawBytes ("UNKN\x04\x20\x20\xb\x0\xC3\x84UNKN\107fortest<xmltest/>\0", 34);
00469         scenarioReadQueryHitsData (hitsData, rawBytes);
00470     }
00471     void testReadQueryHitsDataGgepBlockXmlDataOther()
00472     {
00473         QueryHitsData hitsData;
00474         hitsData.privateVendor.append(QByteArray("vendor1"));
00475         hitsData.privateVendor.append(QByteArray("vendor2"));
00476         hitsData.xmlData = QByteArray("<xmltest/>");
00477         hitsData.ggepBlock = GgepBlock().addExtension (Ggeps::Unknown ("UNKN", "fortest"));
00478         QByteArray rawBytes ("UNKN\x04\x20\x20\xb\x0vendor1\xC3\x84UNKN\107fortestvendor2<xmltest/>\0", 48);
00479         scenarioReadQueryHitsData (hitsData, rawBytes);
00480     }
00481 };
00482 
00483 CPPUNIT_TEST_SUITE_REGISTRATION(BinaryReaderTest);
00484 
00485 } // namespace Testing
00486 } // namespace Packets
00487 } // namespace Gnutella
00488 } // namespace Protocols
00489