datahash/test/test1.cpp

Go to the documentation of this file.
00001 /*
00002  * testDathash1.cpp
00003  *
00004  * Copyright (C) 2008  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Test for the datahash routines.
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "datahash/datahash.h"  // always include our own header file first!
00036 
00037 #include <fstream>
00038 
00039 #include "common/wave_ex.h"
00040 #include "datahash/datahash_text.h"
00041 #include "datahash/datahash_util.h"
00042 #include "perf/perf.h"
00043 
00044 
00045 
00046 static const char * s_filename          = "testhash-1.txt";
00047 
00048 struct key_value_t {
00049         const char *    key;
00050         const char *    value;
00051 };
00052 
00053 
00054 static const key_value_t s_funkyLines[] = {
00055     { "funky",          "This is a funky line! [] @/^\\$() _~`<>,. { } | += --- \t yup!" },
00056     { "greek",          "Μπορῶ νὰ φάω σπασμένα γυαλιὰ χωρὶς νὰ πάθω τίποτα." },
00057     { "frenchProvencal","Pòdi manjar de veire, me nafrariá pas." },
00058     { "georgian",       "მინას ვჭამ და არა მტკივა." },
00059     { "macedonian",     "Можам да јадам стакло, а не ме штета." },
00060     { "japanese",       "私はガラスを食べられます。それは私を傷つけません。" },
00061     { "chinese",        "我能吞下玻璃而不伤身体。" },
00062 
00063     // keep this last
00064     { NULL, NULL }
00065 };
00066 
00067 
00068 ////////////////////////////////////////////////////////////////////////////////
00069 //
00070 //      static helper methods
00071 //
00072 ////////////////////////////////////////////////////////////////////////////////
00073 
00074 static void
00075 addSubhash
00076 (
00077 IN Datahash * h,
00078 IN const char * key
00079 )
00080 {
00081         ASSERT(h, "null");
00082         ASSERT(key, "null");
00083 
00084         smart_ptr<Datahash> subhash = Datahash::create();
00085         ASSERT(subhash, "out of memory");
00086 
00087         h->insert(key, subhash);
00088 }
00089 
00090 
00091 
00092 static void
00093 addToSubhash
00094 (
00095 IN Datahash * h,
00096 IN const char * hashname,
00097 IN const char * key,
00098 IN const char * value
00099 )
00100 {
00101         ASSERT(h, "null");
00102         ASSERT(hashname, "null");
00103         ASSERT(key, "null");
00104         ASSERT(value, "null");
00105 
00106         DPRINTF("Verify add...");
00107         smart_ptr<Datahash> sub = getSubhash(h, hashname);
00108         ASSERT(sub, "null");
00109 
00110         DPRINTF("  add 2...");
00111         sub->insert(key, value);
00112 }
00113 
00114 
00115 
00116 static void
00117 verifyBadAdd
00118 (
00119 IN Datahash * h,
00120 IN const char * key,
00121 IN const char * value
00122 )
00123 {
00124         ASSERT(h, "null");
00125         ASSERT(key, "null");
00126         ASSERT(value, "null");
00127 
00128         DPRINTF("Verify bad...");
00129         bool caughtException = false;
00130         try {
00131                 h->insert(key, value);
00132         } catch (std::exception& e) {
00133                 DPRINTF("Caught good exception: %s", e.what());
00134                 caughtException = true;
00135         }
00136 
00137         if (!caughtException) {
00138                 WAVE_EX(wex);
00139                 wex << "Illegal add-to-hash of key='" << key << "' and value='";
00140                 wex << value << "' should have thrown exception but did not!";
00141         }
00142 }
00143 
00144 
00145 
00146 static void
00147 writeHash
00148 (
00149 IN const Datahash * hash
00150 )
00151 {
00152         ASSERT(hash, "null");
00153 
00154         std::ofstream outfile(s_filename);
00155         if (!outfile.good()) {
00156                 WAVE_EX(wex);
00157                 wex << "Failed to open file for writing: " << s_filename;
00158         }
00159 
00160         writeHashToStream(hash, outfile);
00161 }
00162 
00163 
00164 
00165 static void
00166 verifySubhash
00167 (
00168 IN const Datahash * h,
00169 IN const char * name
00170 )
00171 {
00172         ASSERT(h, "null");
00173         ASSERT(name, "null");
00174 
00175         smart_ptr<Datahash> sub = getSubhash(h, name);
00176         ASSERT(sub, "null");
00177 }
00178 
00179 
00180 
00181 static void
00182 verifySubhashValue
00183 (
00184 IN const Datahash * h,
00185 IN const char * name,
00186 IN const char * key,
00187 IN const char * value
00188 )
00189 {
00190         ASSERT(h, "null");
00191         ASSERT(name, "null");
00192         ASSERT(key, "null");
00193         ASSERT(value, "null");
00194 
00195         smart_ptr<Datahash> sub = getSubhash(h, name);
00196         ASSERT(sub, "null");
00197 
00198         Datahash::iterator_t i;
00199         sub->getIterator(key, i);
00200         std::string k;
00201         hash_value_t hv;
00202         while (sub->getNextElement(i, k, hv)) {
00203                 if (eHashDataType_String != hv.type) {
00204                         continue;       // skip this non-string entry
00205                 }
00206                 const char * val = hv.text.c_str();
00207                 if (!strcmp(val, value))
00208                         return;
00209         }
00210 
00211         WAVE_EX(wex);
00212         wex << "Failed to find value '" << value << "' for key '" << key;
00213         wex << "' in subhash '" << name << "'";
00214 }
00215 
00216 
00217 
00218 static void
00219 verifyMissing
00220 (
00221 IN const Datahash * h,
00222 IN const char * key
00223 )
00224 {
00225         ASSERT(h, "null");
00226         ASSERT(key, "null");
00227 
00228         bool caughtException = false;
00229         try {
00230                 getString(h, key);
00231         } catch (std::exception& e) {
00232                 DPRINTF("Caught good exception: %s", e.what());
00233                 caughtException = true;
00234         }
00235 
00236         if (!caughtException) {
00237                 WAVE_EX(wex);
00238                 wex << "Should have failed to find key '" << key << "' ";
00239                 wex << "in hash, but no exception was thrown!";
00240         }
00241 }
00242 
00243 
00244 
00245 static void
00246 doTest
00247 (
00248 void
00249 )
00250 {
00251         // create a new, nested hash
00252         smart_ptr<Datahash> hash = Datahash::create();
00253         ASSERT(hash, "out of memory");
00254         DPRINTF("here...");
00255         addSubhash(hash, "foo");
00256         addSubhash(hash, "bar");
00257 
00258         DPRINTF("Here 2...");
00259         addToSubhash(hash, "bar", "text", "This is long, long text!  Yessir.");
00260 
00261         DPRINTF("Here 3...");
00262         addToSubhash(hash, "foo", "key1", "value1");
00263         addToSubhash(hash, "foo", "key1", "value2");
00264         addToSubhash(hash, "foo", "key1", "value3");
00265 
00266         // verify failure
00267         verifyBadAdd(hash, "key-1", "value-1");
00268         verifyBadAdd(hash, "0key", "value-1");
00269         verifyBadAdd(hash, "유리를", "value-2");     // korean
00270         verifyBadAdd(hash, "Можам", "value-3");            // macedonian
00271         // add a funky line to a deeper subhash
00272         smart_ptr<Datahash> subhash = getSubhash(hash, "foo");
00273         addSubhash(subhash, "xyz");
00274         for (const key_value_t * p = s_funkyLines; p->key; ++p) {
00275                 addToSubhash(subhash, "xyz", p->key, p->value);
00276         }
00277 
00278         // write to file
00279         writeHash(hash);
00280 
00281         // resurrect from file in new hash
00282         smart_ptr<Datahash> hash2 = readHashFromTextFile(s_filename);
00283         ASSERT(hash2, "failed to read hash?");
00284 
00285         // verify everything is there
00286         verifySubhash(hash2, "bar");
00287         verifySubhashValue(hash2, "bar", "text",
00288                 "This is long, long text!  Yessir.");
00289 
00290         verifySubhash(hash2, "foo");
00291         verifySubhashValue(hash2, "foo", "key1", "value1");
00292         verifySubhashValue(hash2, "foo", "key1", "value2");
00293         verifySubhashValue(hash2, "foo", "key1", "value3");
00294 
00295         smart_ptr<Datahash> subhash2 = getSubhash(hash2, "foo");
00296         verifySubhash(subhash2, "xyz");
00297         for (const key_value_t * p = s_funkyLines; p->key; ++p) {
00298                 verifySubhashValue(subhash2, "xyz", p->key, p->value);
00299         }
00300 
00301         // verify stuff is NOT there!
00302         verifyMissing(hash2, "key");
00303         verifyMissing(subhash2, "key1");
00304 }
00305 
00306 
00307 
00308 ////////////////////////////////////////////////////////////////////////////////
00309 //
00310 //      entry point
00311 //
00312 ////////////////////////////////////////////////////////////////////////////////
00313 
00314 int
00315 main
00316 (
00317 IN int argc,
00318 IN const char * argv[]
00319 )
00320 {
00321         int retval = 0;
00322         try {
00323                 perf::Timer timer("overall timer");
00324                 doTest();
00325 
00326         } catch (std::exception& e) {
00327                 DPRINTF("Exception: %s", e.what());
00328                 retval = 1;
00329         } catch (...) {
00330                 DPRINTF("Unknown exception!");
00331                 retval = 2;
00332         }
00333         DPRINTF("here (end)");
00334         perf::dumpTimingSummary(std::cerr);
00335 
00336         return retval;
00337 }
00338