CalcAssemblerTest.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/calctest/CalcAssemblerTest.cpp#5 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2004-2009 SQLstream, Inc.
00006 // Copyright (C) 2009-2009 LucidEra, Inc.
00007 //
00008 // This program is free software; you can redistribute it and/or modify it
00009 // under the terms of the GNU General Public License as published by the Free
00010 // Software Foundation; either version 2 of the License, or (at your option)
00011 // any later version approved by The Eigenbase Project.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "fennel/common/CommonPreamble.h"
00024 #include "fennel/test/TestBase.h"
00025 #include "fennel/common/TraceSource.h"
00026 
00027 #include "fennel/tuple/TupleDataWithBuffer.h"
00028 #include "fennel/tuple/TuplePrinter.h"
00029 #include "fennel/calculator/CalcCommon.h"
00030 #include "fennel/calculator/CalcAssembler.h"
00031 #include "fennel/calculator/StringToHex.h"
00032 #include "fennel/common/FennelExcn.h"
00033 
00034 #include <boost/test/test_tools.hpp>
00035 
00036 #include <fstream.h>
00037 #include <strstream.h>
00038 #include <iomanip.h>
00039 
00040 using namespace fennel;
00041 
00042 bool verbose = false;
00043 bool showProgram = true;
00044 
00045 /* --- defining this indicates we expect full arithmetic exceptions --- */
00046 #define USING_NOISY_ARITHMETIC    (1)
00047 /* #define USING_NOISY_ARITHMETIC    (1) */
00048 
00049 template <typename T>
00050 class RegisterTestInfo
00051 {
00052 public:
00053     enum ERegisterCheck {
00054         EINVALID = -1,
00055         ENULL = 0,
00056         EVALID = 1
00057     };
00058 
00059     explicit
00060     RegisterTestInfo(string desc, TProgramCounter pc):
00061         mDesc(desc), mCheckValue(EINVALID), mPC(pc)
00062     {
00063     }
00064 
00065     explicit
00066     RegisterTestInfo(string desc, T v, TProgramCounter pc):
00067         mDesc(desc), mValue(v), mCheckValue(EVALID), mPC(pc)
00068     {
00069     }
00070 
00071     explicit
00072     RegisterTestInfo(string desc, T* pV, TProgramCounter pc):
00073         mDesc(desc), mPC(pc)
00074     {
00075         if (pV == NULL) {
00076             mCheckValue = ENULL;
00077         } else {
00078             mValue = *pV;
00079             mCheckValue = EVALID;
00080         }
00081     }
00082 
00083     void setTupleDatum(TupleDatum& datum)
00084     {
00085         switch (mCheckValue) {
00086         case EINVALID:
00087             // Nothing to set
00088             break;
00089         case ENULL:
00090             // Set to NULL
00091             datum.pData = NULL;
00092             break;
00093         case EVALID:
00094             assert(datum.pData != NULL);
00095             (*reinterpret_cast<T*>(const_cast<PBuffer>(datum.pData))) = mValue;
00096              break;
00097         default:
00098             permAssert(false);
00099         }
00100     }
00101 
00102     bool checkTupleDatum(TupleDatum& datum)
00103     {
00104         switch (mCheckValue) {
00105         case EINVALID:
00106             // Nothing to check against, okay
00107             return true;
00108         case ENULL:
00109             // Check for null
00110             return (datum.pData == NULL);
00111         case EVALID:
00112             if (datum.pData == NULL) {
00113                 return false;
00114             }
00115             return (*reinterpret_cast<const T*>(datum.pData) == mValue);
00116         default:
00117             permAssert(false);
00118         }
00119     }
00120 
00121     string toString()
00122     {
00123         ostringstream ostr("");
00124         switch (mCheckValue) {
00125         case EINVALID:
00126             break;
00127         case ENULL:
00128             ostr << "(NULL) for test ";
00129             break;
00130         case EVALID:
00131             ostr << "(" << mValue << ") for test ";
00132              break;
00133         default:
00134             permAssert(false);
00135         }
00136 
00137         ostr << "'" << mDesc << "'" << " at PC=" << mPC;
00138         return ostr.str();
00139     }
00140 
00141     ~RegisterTestInfo() {}
00142 
00143     // Description of this test
00144     string          mDesc;
00145 
00146     // Expected value of this register
00147     T mValue;
00148 
00149     // Should we check the value?  Is it suppose to be NULL?
00150     ERegisterCheck  mCheckValue;
00151 
00152     // PC associated with setting this register
00153     TProgramCounter mPC;
00154 };
00155 
00156 class CalcChecker
00157 {
00158 public:
00159     virtual ~CalcChecker() {}
00160     virtual bool checkResult(Calculator& calc, TupleData& output) = 0;
00161 };
00162 
00163 template <typename T>
00164 class CalcTestInfo : public CalcChecker
00165 {
00166 public:
00167     explicit
00168     CalcTestInfo(StandardTypeDescriptorOrdinal type)
00169         : typeOrdinal(type) {}
00170     virtual ~CalcTestInfo() {}
00171 
00172     void add(string desc, T* pV, TProgramCounter pc, uint line = 0)
00173     {
00174         if (line) {
00175             ostringstream ostr("");
00176             ostr << " Line: " << line;
00177             desc += ostr.str();
00178         }
00179         mOutRegInfo.push_back(RegisterTestInfo<T>(desc, pV, pc));
00180     }
00181 
00182     void add(string desc, T v, TProgramCounter pc, uint line = 0)
00183     {
00184         if (line) {
00185             ostringstream ostr("");
00186             ostr << " Line: " << line;
00187             desc += ostr.str();
00188         }
00189         mOutRegInfo.push_back(RegisterTestInfo<T>(desc, v, pc));
00190     }
00191 
00192     void addRegister(string desc, TProgramCounter pc)
00193     {
00194         mOutRegInfo.push_back(RegisterTestInfo<T>(desc, pc));
00195     }
00196 
00197     void addWarning(const char* msg, TProgramCounter pc)
00198     {
00199         mWarnings.push_back(CalcMessage(msg, pc));
00200     }
00201 
00202     void add(string desc, const char* error, TProgramCounter pc, uint line = 0)
00203     {
00204         if (line) {
00205             ostringstream ostr("");
00206             ostr << " Line: " << line;
00207             desc += ostr.str();
00208         }
00209         addRegister(desc, pc);
00210         if (error != NULL) {
00211             addWarning(error, pc);
00212         }
00213     }
00214 
00215     void setTupleData(TupleData& tuple)
00216     {
00217         assert(tuple.size() == mOutRegInfo.size());
00218 
00219         // Check type of output registers and value
00220         for (uint i = 0; i < tuple.size(); i++) {
00221             mOutRegInfo[i].setTupleDatum(tuple[i]);
00222         }
00223     }
00224 
00225     virtual bool checkResult(Calculator& calc, TupleData& outputTuple)
00226     {
00227         TupleDescriptor outputTupleDesc = calc.getOutputRegisterDescriptor();
00228         // Verify the output descriptor
00229         assert(outputTupleDesc.size() == outputTuple.size());
00230 
00231         // Check number of output registers
00232         if (outputTupleDesc.size() != mOutRegInfo.size()) {
00233             ostringstream message("");
00234             message << "Mismatch of output register number: Expected ";
00235             message << outputTupleDesc.size();
00236             message << ", Actual " << mOutRegInfo.size();
00237             BOOST_ERROR(message.str());
00238             return false;
00239         }
00240 
00241         // Check type of output registers and value
00242         for (uint i = 0; i < outputTupleDesc.size(); i++) {
00243             if (outputTupleDesc[i].pTypeDescriptor->getOrdinal() !=
00244                 static_cast<StoredTypeDescriptor::Ordinal>(typeOrdinal))
00245             {
00246                 ostringstream message("");
00247                 message << "Type ordinal mismatch: Expected ";
00248                 message << outputTupleDesc[i].pTypeDescriptor->getOrdinal();
00249                 message << ", Actual";
00250                 message << static_cast<StoredTypeDescriptor::Ordinal>(
00251                     typeOrdinal);
00252                 BOOST_ERROR(message.str());
00253                 return false;
00254             }
00255 
00256             if (!mOutRegInfo[i].checkTupleDatum(outputTuple[i])) {
00257                 ostringstream message("");
00258                 message << "Tuple datum mismatch: Register " << i
00259                         << " should be " << mOutRegInfo[i].toString()
00260                         << ".";
00261                 BOOST_ERROR(message.str());
00262                 return false;
00263             }
00264         }
00265 
00266         // Check warnings
00267         if (calc.mWarnings.size() != mWarnings.size()) {
00268             ostringstream message("");
00269             message << "# of warnings should be " << mWarnings.size()
00270                     << " not " << calc.mWarnings.size();
00271             BOOST_ERROR(message.str());
00272             return false;
00273         }
00274 
00275         for (uint i = 0; i < mWarnings.size(); i++) {
00276             if (calc.mWarnings[i].pc != mWarnings[i].pc) {
00277                 ostringstream message("");
00278                 message << "Warning expected at PC=" << mWarnings[i].pc
00279                         << ". Got warning at PC="
00280                         << calc.mWarnings[i].pc;
00281                 BOOST_ERROR(message.str());
00282                 return false;
00283             }
00284 
00285             if (strcmp(calc.mWarnings[i].str, mWarnings[i].str)) {
00286                 ostringstream message("");
00287                 message << "Message should be |" << mWarnings[i].str
00288                         << "| not |" << calc.mWarnings[i].str << "| at PC="
00289                         << mWarnings[i].pc ;
00290                 BOOST_ERROR(message.str());
00291                 return false;
00292             }
00293         }
00294 
00295         return true;
00296     }
00297 
00298 public:
00299     // Vector of expected output register values
00300     vector< RegisterTestInfo<T> > mOutRegInfo;
00301 
00302     // Vector of expected warnings
00303     deque<CalcMessage> mWarnings;
00304 
00305     StandardTypeDescriptorOrdinal typeOrdinal;
00306 };
00307 
00308 class CalcAssemblerTestCase
00309 {
00310 public:
00311     static const uint MAX_WIDTH = 512;
00312 
00313     explicit
00314     CalcAssemblerTestCase(uint line, const char* desc, const char* code)
00315         : mDescription(desc), mProgram(code), mAssemblerError(NULL),
00316           mInputTuple(NULL), mExpectedOutputTuple(NULL), mInputBuf(NULL),
00317           mExpOutputBuf(NULL), mFailed(false), mAssembled(false),
00318           mID(++testID), mLine(line), mCalc(0)
00319     {
00320     }
00321 
00322     ~CalcAssemblerTestCase()
00323     {
00324         if (mInputTuple) {
00325             delete mInputTuple;
00326         }
00327         if (mExpectedOutputTuple) {
00328             delete mExpectedOutputTuple;
00329         }
00330         if (mInputBuf) {
00331             delete[] mInputBuf;
00332         }
00333         if (mExpOutputBuf) {
00334             delete[] mExpOutputBuf;
00335         }
00336     }
00337 
00338     static uint getFailedNumber()
00339     {
00340         return nFailed;
00341     }
00342 
00343     static uint getPassedNumber()
00344     {
00345         return nPassed;
00346     }
00347 
00348     static uint getTestNumber()
00349     {
00350         return testID;
00351     }
00352 
00353     void fail(const char *exp, const char* actual)
00354     {
00355         assert(exp);
00356         assert(actual);
00357         assert(mDescription);
00358         ostringstream message("");
00359         message << "test " << mID << " failed: | ";
00360         message << mDescription << " | Got \"" << actual << "\" | ";
00361         message << "Expected \"" << exp << "\" | line " << mLine;
00362         BOOST_ERROR(message.str());
00363         mFailed = true;
00364         nFailed++;
00365     }
00366 
00367     void passed(const char *exp, const char* actual)
00368     {
00369         assert(exp);
00370         assert(actual);
00371         assert(mDescription);
00372         if (verbose) {
00373             ostringstream message("");
00374             message << "test " << mID << " passed: | ";
00375             message << mDescription << " | Got \"" << actual << "\" | ";
00376             message << "Expected \"" << exp << "\" | line " << mLine;
00377             BOOST_MESSAGE(message.str());
00378         }
00379         nPassed++;
00380     }
00381 
00382     bool assemble()
00383     {
00384         assert(!mFailed && !mAssembled);
00385         assert(mProgram != NULL);
00386         try {
00387             mCalc.outputRegisterByReference(false);
00388             mCalc.assemble(mProgram);
00389 
00390             TupleDescriptor inputTupleDesc = mCalc.getInputRegisterDescriptor();
00391             TupleDescriptor outputTupleDesc =
00392                 mCalc.getOutputRegisterDescriptor();
00393 
00394             mInputTuple = CalcAssembler::createTupleData(
00395                 inputTupleDesc, &mInputBuf);
00396             mExpectedOutputTuple = CalcAssembler::createTupleData(
00397                 outputTupleDesc, &mExpOutputBuf);
00398 
00399             // Successfully assembled the test program
00400             mAssembled = true;
00401 
00402             if (mAssemblerError) {
00403                 // Hmmm, we were expecting an error while assembling
00404                 // What happened?
00405                 string errorStr = "Error assembling program: ";
00406                 errorStr += mAssemblerError;
00407                 fail(errorStr.c_str(), "Program assembled.");
00408             }
00409         } catch (CalcAssemblerException& ex) {
00410             if (mAssemblerError) {
00411                 // We are expecting an error
00412                 // Things okay
00413 
00414                 // Let's check if the error message is kind of what we expected
00415                 if (ex.getMessage().find(mAssemblerError) == string::npos) {
00416                     // Error message doesn't have the expected string
00417                     fail(mAssemblerError, ex.getMessage().c_str());
00418                 } else {
00419                     // Error message is okay
00420                     passed(mAssemblerError, ex.getMessage().c_str());
00421                 }
00422             } else {
00423                 string errorStr = "Error assembling program: ";
00424                 errorStr += ex.getMessage();
00425                 fail("Success assembling program", errorStr.c_str());
00426 
00427                 if (showProgram) {
00428                     // Dump out program
00429                     ostringstream prog("");
00430                     prog << "Program Code: " << endl;
00431                     prog << ex.getCode() << endl;
00432                     prog << "Program Snippet: " << endl;
00433                     prog << ex.getCodeSnippet() << endl;
00434                     BOOST_MESSAGE(prog.str());
00435                 }
00436             }
00437         }
00438 
00439         // Everything good?
00440         return (mAssembled && !mFailed);
00441     }
00442 
00443     static string tupleToString(
00444         TupleDescriptor const& tupleDesc,
00445         TupleData* tuple)
00446     {
00447         assert(tuple != NULL);
00448         ostringstream ostr("");
00449         TuplePrinter tuplePrinter;
00450         tuplePrinter.print(ostr, tupleDesc, *tuple);
00451         return ostr.str();
00452     }
00453 
00454     bool test(CalcChecker* pChecker = NULL)
00455     {
00456         assert(mAssembled);
00457         bool res = true;
00458 
00459         TupleDescriptor inputTupleDesc = mCalc.getInputRegisterDescriptor();
00460         TupleDescriptor outputTupleDesc = mCalc.getOutputRegisterDescriptor();
00461 
00462         FixedBuffer* outputBuf;
00463         TupleData* outputTuple = CalcAssembler::createTupleData(
00464             outputTupleDesc, &outputBuf);
00465 
00466         mCalc.bind(mInputTuple, outputTuple);
00467 
00468         mCalc.exec();
00469 
00470         string instr = tupleToString(inputTupleDesc, mInputTuple);
00471         string outstr = tupleToString(outputTupleDesc, outputTuple);
00472         string expoutstr = tupleToString(outputTupleDesc, mExpectedOutputTuple);
00473 
00474         if (pChecker == NULL) {
00475             // For now, let's just use the string representation of
00476             // the tuples for comparison
00477             res = (expoutstr == outstr);
00478 
00479             // Make sure there are no warnings
00480             if (!mCalc.mWarnings.empty()) {
00481                 res = false;
00482                 fail(expoutstr.c_str(), "Calculator warnings");
00483 //TEMP LATER
00484 //for (uint i=0; i < mCalc.mWarnings.size(); i++) {
00485 //printf( "Calc warning [%s]\n", mCalc.mWarnings[i].str );
00486 //}
00487             }
00488         } else {
00489             res = pChecker->checkResult(mCalc, *outputTuple);
00490         }
00491 
00492         if (res) {
00493             // Everything good and matches
00494             string resStr = instr + " -> " + outstr;
00495             passed(expoutstr.c_str(), resStr.c_str());
00496         } else {
00497             string errorStr = "Calculator result: " ;
00498             errorStr += instr + " -> " + outstr;
00499             fail(expoutstr.c_str(), errorStr.c_str());
00500         }
00501 
00502         delete outputTuple;
00503         delete[] outputBuf;
00504         return res;
00505     }
00506 
00507     void expectAssemblerError(const char* err)
00508     {
00509         mAssemblerError = err;
00510     }
00511 
00512     void   writeMaxData(TupleDatum &datum, uint typeOrdinal);
00513     void   writeMinData(TupleDatum &datum, uint typeOrdinal);
00514     string toLiteralString(TupleDatum &datum, uint typeOrdinal);
00515 
00516     void setTupleDatumMax(TupleDatum& datum, TupleAttributeDescriptor& desc)
00517     {
00518         StoredTypeDescriptor::Ordinal type = desc.pTypeDescriptor->getOrdinal();
00519         writeMaxData(datum, type);
00520     }
00521 
00522     void setTupleDatumMin(TupleDatum& datum, TupleAttributeDescriptor& desc)
00523     {
00524         StoredTypeDescriptor::Ordinal type = desc.pTypeDescriptor->getOrdinal();
00525         writeMinData(datum, type);
00526     }
00527 
00528     void setTupleDatumNull(TupleDatum& datum)
00529     {
00530         datum.pData = NULL;
00531     }
00532 
00533     template <typename T>
00534     void setTupleDatum(TupleDatum& datum, T value)
00535     {
00536         *(reinterpret_cast<T*>(const_cast<PBuffer>(datum.pData))) = value;
00537     }
00538 
00539     template <typename T>
00540     void setTupleDatum(
00541         TupleDatum& datum,
00542         TupleAttributeDescriptor& desc,
00543         T* buf,
00544         uint buflen)
00545     {
00546         assert(buf != NULL);
00547         StoredTypeDescriptor::Ordinal type = desc.pTypeDescriptor->getOrdinal();
00548 
00549         T* ptr = reinterpret_cast<T*>(const_cast<PBuffer>(datum.pData));
00550         switch (type) {
00551         case STANDARD_TYPE_CHAR:
00552         case STANDARD_TYPE_BINARY:
00553             // Fixed length storage
00554             assert(buflen <= datum.cbData);
00555             memset((void*) ptr, 0, datum.cbData); // Fill with 0
00556             memcpy((void*) ptr, buf, buflen);
00557             break;
00558 
00559         case STANDARD_TYPE_VARCHAR:
00560         case STANDARD_TYPE_VARBINARY:
00561             // Variable length storage
00562             assert(buflen <= desc.cbStorage);
00563             memset((void*)ptr, 'I', desc.cbStorage); // Fill with junk
00564             memcpy((void*)ptr, buf, buflen);
00565             datum.cbData = buflen;
00566             break;
00567 
00568         default:
00569             permAssert(false);
00570         }
00571     }
00572 
00573     void setInputMin(uint index)
00574     {
00575         assert(mInputTuple != NULL);
00576         assert(index < mInputTuple->size());
00577         TupleDescriptor inputTupleDesc = mCalc.getInputRegisterDescriptor();
00578         setTupleDatumMin((*mInputTuple)[index], inputTupleDesc[index]);
00579     }
00580 
00581     void setInputMax(uint index)
00582     {
00583         assert(mInputTuple != NULL);
00584         assert(index < mInputTuple->size());
00585         TupleDescriptor inputTupleDesc = mCalc.getInputRegisterDescriptor();
00586         setTupleDatumMax((*mInputTuple)[index], inputTupleDesc[index]);
00587     }
00588 
00589     void setInputNull(uint index)
00590     {
00591         assert(mInputTuple != NULL);
00592         assert(index < mInputTuple->size());
00593         setTupleDatumNull((*mInputTuple)[index]);
00594     }
00595 
00596     template <typename T>
00597     void setInput(uint index, T value)
00598     {
00599         assert(mInputTuple != NULL);
00600         assert(index < mInputTuple->size());
00601         setTupleDatum((*mInputTuple)[index], value);
00602     }
00603 
00604     template <typename T>
00605     void setInput(uint index, T* buf, uint buflen)
00606     {
00607         assert(mInputTuple != NULL);
00608         assert(index < mInputTuple->size());
00609         TupleDescriptor inputTupleDesc = mCalc.getInputRegisterDescriptor();
00610         setTupleDatum(
00611             (*mInputTuple)[index],
00612             inputTupleDesc[index],
00613             buf,
00614             buflen);
00615     }
00616 
00617     string getInput(uint index)
00618     {
00619         assert(mInputTuple != NULL);
00620         assert(index < mInputTuple->size());
00621         TupleDescriptor inputTupleDesc = mCalc.getInputRegisterDescriptor();
00622         return toLiteralString(
00623             (*mInputTuple)[index],
00624             inputTupleDesc[index].pTypeDescriptor->getOrdinal());
00625     }
00626 
00627     TupleData* getInputTuple()
00628     {
00629         return mInputTuple;
00630     }
00631 
00632     /* Functions for setting the expected output */
00633     void setExpectedOutputNull(uint index)
00634     {
00635         assert(mExpectedOutputTuple != NULL);
00636         assert(index < mExpectedOutputTuple->size());
00637         setTupleDatumNull((*mExpectedOutputTuple)[index]);
00638     }
00639 
00640     void setExpectedOutputMax(uint index)
00641     {
00642         assert(mExpectedOutputTuple != NULL);
00643         assert(index < mExpectedOutputTuple->size());
00644         TupleDescriptor outputTupleDesc = mCalc.getOutputRegisterDescriptor();
00645         setTupleDatumMax(
00646             (*mExpectedOutputTuple)[index],
00647             outputTupleDesc[index]);
00648     }
00649     void setExpectedOutputMin(uint index)
00650     {
00651         assert(mExpectedOutputTuple != NULL);
00652         assert(index < mExpectedOutputTuple->size());
00653         TupleDescriptor outputTupleDesc = mCalc.getOutputRegisterDescriptor();
00654         setTupleDatumMin(
00655             (*mExpectedOutputTuple)[index],
00656             outputTupleDesc[index]);
00657     }
00658 
00659     template <typename T>
00660     void setExpectedOutput(uint index, T value)
00661     {
00662         assert(mExpectedOutputTuple != NULL);
00663         assert(index < mExpectedOutputTuple->size());
00664         setTupleDatum((*mExpectedOutputTuple)[index], value);
00665     }
00666 
00667     template <typename T>
00668     void setExpectedOutput(uint index, T* buf, uint buflen)
00669     {
00670         assert(mExpectedOutputTuple != NULL);
00671         assert(index < mExpectedOutputTuple->size());
00672         TupleDescriptor outputTupleDesc = mCalc.getOutputRegisterDescriptor();
00673         setTupleDatum(
00674             (*mExpectedOutputTuple)[index],
00675             outputTupleDesc[index],
00676             buf,
00677             buflen);
00678     }
00679 
00680     string getExpectedOutput(uint index)
00681     {
00682         assert(mExpectedOutputTuple != NULL);
00683         assert(index < mExpectedOutputTuple->size());
00684         TupleDescriptor outputTupleDesc = mCalc.getOutputRegisterDescriptor();
00685         return toLiteralString(
00686             (*mExpectedOutputTuple)[index],
00687             outputTupleDesc[index].pTypeDescriptor->getOrdinal());
00688     }
00689 
00690     TupleData* getExpectedOutputTuple()
00691     {
00692         return mExpectedOutputTuple;
00693     }
00694 
00695     bool failed()
00696     {
00697         return mFailed;
00698     }
00699 
00700 protected:
00701     const char* mDescription;
00702     const char* mProgram;
00703     const char* mAssemblerError;
00704     TupleData* mInputTuple;
00705     TupleData* mExpectedOutputTuple;
00706     FixedBuffer* mInputBuf;
00707     FixedBuffer* mExpOutputBuf;
00708     bool mFailed;
00709     bool mAssembled;
00710     uint mID;
00711     uint mLine;
00712 
00713     Calculator mCalc;
00714     static uint testID;
00715     static uint nFailed;
00716     static uint nPassed;
00717 };
00718 
00719 uint CalcAssemblerTestCase::testID = 0;
00720 uint CalcAssemblerTestCase::nFailed = 0;
00721 uint CalcAssemblerTestCase::nPassed = 0;
00722 
00723 class CalcAssemblerTest : virtual public TestBase, public TraceSource
00724 {
00725 protected:
00726     void testAdd();
00727 
00728     void testBool();
00729     void testPointer();
00730     void testReturn();
00731     void testJump();
00732     void testExtended();
00733 
00734     void testLiteralBinding();
00735 
00736     void testInvalidPrograms();
00737     void testStandardTypes();
00738 
00739     void testComments();
00740 
00741     void testBoolInstructions(StandardTypeDescriptorOrdinal type);
00742 
00743     template <typename T>
00744     void testNativeInstructions(StandardTypeDescriptorOrdinal type);
00745 
00746     template <typename T>
00747     void testIntegralNativeInstructions(StandardTypeDescriptorOrdinal type);
00748 
00749     string getTypeString(StandardTypeDescriptorOrdinal type, uint arraylen = 0);
00750     string createRegisterString(string s, uint n, char c = ',');
00751     void addBinaryInstructions(
00752         ostringstream& ostr,
00753         string opcode,
00754         uint& outreg,
00755         uint n);
00756 
00757     void addUnaryInstructions(
00758         ostringstream& ostr,
00759         string opcode,
00760         uint& outreg,
00761         uint n);
00762 
00763 public:
00764     explicit CalcAssemblerTest()
00765         : TraceSource(shared_from_this(),"CalcAssemblerTest")
00766     {
00767         srand(time(NULL));
00768         CalcInit::instance();
00769         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testLiteralBinding);
00770         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testBool);
00771         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testPointer);
00772         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testAdd);
00773         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testReturn);
00774         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testJump);
00775         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testExtended);
00776         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testComments);
00777 
00778     // FIXME jvs 21-Mar-2006:  these still don't work on Win32
00779 #ifndef __MSVC__
00780         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testInvalidPrograms);
00781         FENNEL_UNIT_TEST_CASE(CalcAssemblerTest, testStandardTypes);
00782 #endif
00783     }
00784 
00785     virtual ~CalcAssemblerTest()
00786     {
00787     }
00788 
00789 };
00790 
00791 // Converts a tuple data to its literal string representation in the
00792 // assembler.
00793 // NOTE: This may be different from its normal string representation
00794 //       using the TuplePrinter.
00795 string CalcAssemblerTestCase::toLiteralString(
00796     TupleDatum &datum,
00797     uint typeOrdinal)
00798 {
00799     // NOTE jvs 25-May-2007:  casts to int64_t below are required
00800     // for a 64-bit build to pass
00801 
00802     ostringstream ostr("");
00803     if (datum.pData != NULL) {
00804         switch (typeOrdinal) {
00805         case STANDARD_TYPE_BOOL:
00806             if (*reinterpret_cast<const bool*>(datum.pData)) {
00807                 ostr << "1";
00808             } else {
00809                 ostr << "0";
00810             }
00811             break;
00812         case STANDARD_TYPE_INT_8:
00813             ostr << (int64_t) (*reinterpret_cast<const int8_t*>(datum.pData));
00814             break;
00815         case STANDARD_TYPE_UINT_8:
00816             ostr << (int64_t) (*reinterpret_cast<const uint8_t*>(datum.pData));
00817             break;
00818         case STANDARD_TYPE_INT_16:
00819             ostr << (int64_t) (*reinterpret_cast<const int16_t*>(datum.pData));
00820             break;
00821         case STANDARD_TYPE_UINT_16:
00822             ostr << (int64_t) (*reinterpret_cast<const uint16_t*>(datum.pData));
00823         break;
00824         case STANDARD_TYPE_INT_32:
00825             ostr << (int64_t) (*reinterpret_cast<const int32_t*>(datum.pData));
00826             break;
00827         case STANDARD_TYPE_UINT_32:
00828             ostr << (int64_t) (*reinterpret_cast<const uint32_t*>(datum.pData));
00829         break;
00830         case STANDARD_TYPE_INT_64:
00831             ostr << (*reinterpret_cast<const int64_t*>(datum.pData));
00832             break;
00833         case STANDARD_TYPE_UINT_64:
00834             ostr << (*reinterpret_cast<const uint64_t*>(datum.pData));
00835             break;
00836         case STANDARD_TYPE_REAL:
00837             ostr << (*reinterpret_cast<const float*>(datum.pData));
00838         break;
00839         case STANDARD_TYPE_DOUBLE:
00840             ostr << (*reinterpret_cast<const double*>(datum.pData));
00841             break;
00842         case STANDARD_TYPE_BINARY:
00843         case STANDARD_TYPE_CHAR:
00844         case STANDARD_TYPE_VARCHAR:
00845         case STANDARD_TYPE_VARBINARY:
00846             ostr << "0x";
00847             ostr << stringToHex(
00848                 (reinterpret_cast<const char*>(datum.pData)),
00849                 datum.cbData);
00850             break;
00851         default:
00852             permAssert(false);
00853         }
00854     }
00855     return ostr.str();
00856 }
00857 
00858 // Copied from TupleTest::writeMaxData
00859 void CalcAssemblerTestCase::writeMaxData(TupleDatum &datum, uint typeOrdinal)
00860 {
00861     PBuffer pData = const_cast<PBuffer>(datum.pData);
00862     switch (typeOrdinal) {
00863     case STANDARD_TYPE_BOOL:
00864         *(reinterpret_cast<bool *>(pData)) = true;
00865         break;
00866     case STANDARD_TYPE_INT_8:
00867         *(reinterpret_cast<int8_t *>(pData)) =
00868             std::numeric_limits<int8_t>::max();
00869         break;
00870     case STANDARD_TYPE_UINT_8:
00871         *(reinterpret_cast<uint8_t *>(pData)) =
00872             std::numeric_limits<uint8_t>::max();
00873         break;
00874     case STANDARD_TYPE_INT_16:
00875         *(reinterpret_cast<int16_t *>(pData)) =
00876             std::numeric_limits<int16_t>::max();
00877         break;
00878     case STANDARD_TYPE_UINT_16:
00879         *(reinterpret_cast<uint16_t *>(pData)) =
00880             std::numeric_limits<uint16_t>::max();
00881         break;
00882     case STANDARD_TYPE_INT_32:
00883         *(reinterpret_cast<int32_t *>(pData)) =
00884             std::numeric_limits<int32_t>::max();
00885         break;
00886     case STANDARD_TYPE_UINT_32:
00887         *(reinterpret_cast<uint32_t *>(pData)) =
00888             std::numeric_limits<uint32_t>::max();
00889         break;
00890     case STANDARD_TYPE_INT_64:
00891         *(reinterpret_cast<int64_t *>(pData)) =
00892             std::numeric_limits<int64_t>::max();
00893         break;
00894     case STANDARD_TYPE_UINT_64:
00895         *(reinterpret_cast<uint64_t *>(pData)) =
00896             std::numeric_limits<uint64_t>::max();
00897         break;
00898     case STANDARD_TYPE_REAL:
00899         *(reinterpret_cast<float *>(pData)) =
00900             std::numeric_limits<float>::max();
00901         break;
00902     case STANDARD_TYPE_DOUBLE:
00903         *(reinterpret_cast<double *>(pData)) =
00904             std::numeric_limits<double>::max();
00905         break;
00906     case STANDARD_TYPE_BINARY:
00907         memset(pData,0xFF,datum.cbData);
00908         break;
00909     case STANDARD_TYPE_CHAR:
00910         memset(pData,'z',datum.cbData);
00911         break;
00912     case STANDARD_TYPE_VARCHAR:
00913         datum.cbData = MAX_WIDTH;
00914         memset(pData,'z',datum.cbData);
00915         break;
00916     case STANDARD_TYPE_VARBINARY:
00917         datum.cbData = MAX_WIDTH;
00918         memset(pData,0xFF,datum.cbData);
00919         break;
00920     default:
00921         permAssert(false);
00922     }
00923 }
00924 
00925 // Copied from TupleTest::writeMinData
00926 void CalcAssemblerTestCase::writeMinData(TupleDatum &datum,uint typeOrdinal)
00927 {
00928     PBuffer pData = const_cast<PBuffer>(datum.pData);
00929     switch (typeOrdinal) {
00930     case STANDARD_TYPE_BOOL:
00931         *(reinterpret_cast<bool *>(pData)) = false;
00932         break;
00933     case STANDARD_TYPE_INT_8:
00934         *(reinterpret_cast<int8_t *>(pData)) =
00935             std::numeric_limits<int8_t>::min();
00936         break;
00937     case STANDARD_TYPE_UINT_8:
00938         *(reinterpret_cast<uint8_t *>(pData)) =
00939             std::numeric_limits<uint8_t>::min();
00940         break;
00941     case STANDARD_TYPE_INT_16:
00942         *(reinterpret_cast<int16_t *>(pData)) =
00943             std::numeric_limits<int16_t>::min();
00944         break;
00945     case STANDARD_TYPE_UINT_16:
00946         *(reinterpret_cast<uint16_t *>(pData)) =
00947             std::numeric_limits<uint16_t>::min();
00948         break;
00949     case STANDARD_TYPE_INT_32:
00950         *(reinterpret_cast<int32_t *>(pData)) =
00951             std::numeric_limits<int32_t>::min();
00952         break;
00953     case STANDARD_TYPE_UINT_32:
00954         *(reinterpret_cast<uint32_t *>(pData)) =
00955             std::numeric_limits<uint32_t>::min();
00956         break;
00957     case STANDARD_TYPE_INT_64:
00958         *(reinterpret_cast<int64_t *>(pData)) =
00959             std::numeric_limits<int64_t>::min();
00960         break;
00961     case STANDARD_TYPE_UINT_64:
00962         *(reinterpret_cast<uint64_t *>(pData)) =
00963             std::numeric_limits<uint64_t>::min();
00964         break;
00965     case STANDARD_TYPE_REAL:
00966         *(reinterpret_cast<float *>(pData)) =
00967             std::numeric_limits<float>::min();
00968         break;
00969     case STANDARD_TYPE_DOUBLE:
00970         *(reinterpret_cast<double *>(pData)) =
00971             std::numeric_limits<double>::min();
00972         break;
00973     case STANDARD_TYPE_BINARY:
00974         memset(pData,0,datum.cbData);
00975         break;
00976     case STANDARD_TYPE_CHAR:
00977         memset(pData,'A',datum.cbData);
00978         break;
00979     case STANDARD_TYPE_VARCHAR:
00980     case STANDARD_TYPE_VARBINARY:
00981         datum.cbData = 0;
00982         break;
00983     default:
00984         permAssert(false);
00985     }
00986 }
00987 
00988 string CalcAssemblerTest::getTypeString(
00989     StandardTypeDescriptorOrdinal type,
00990     uint arraylen)
00991 {
00992     string typestr = StandardTypeDescriptor::toString(type);
00993     if (StandardTypeDescriptor::isArray(type)) {
00994         ostringstream size("");
00995         size << "," << arraylen;
00996         typestr += size.str();
00997     }
00998     return typestr;
00999 }
01000 
01001 string CalcAssemblerTest::createRegisterString(
01002     string s,
01003     uint n,
01004     char c)
01005 {
01006     ostringstream ostr("");
01007     for (uint i = 0; i < n; i++) {
01008         if (i > 0) {
01009             ostr << c;
01010         }
01011         ostr << s;
01012     }
01013     return ostr.str();
01014 }
01015 
01016 void CalcAssemblerTest::addUnaryInstructions(
01017     ostringstream& ostr,
01018     string opcode,
01019     uint& outreg,
01020     uint n)
01021 {
01022     for (uint i = 0; i < n; i++) {
01023         ostr << opcode << " O" << outreg++ << ", I"
01024              << i << ";" << endl;
01025     }
01026 }
01027 
01028 void CalcAssemblerTest::addBinaryInstructions(
01029     ostringstream& ostr,
01030     string opcode,
01031     uint& outreg,
01032     uint n)
01033 {
01034     for (uint i = 0; i < n; i++) {
01035         for (uint j = 0; j < n; j++) {
01036             ostr << opcode << " O" << outreg++ << ", I"
01037                  << i << ", I" << j << ";" << endl;
01038         }
01039     }
01040 }
01041 
01042 template <typename T>
01043 void CalcAssemblerTest::testIntegralNativeInstructions(
01044     StandardTypeDescriptorOrdinal type)
01045 {
01046     string typestr = getTypeString(type, CalcAssemblerTestCase::MAX_WIDTH);
01047     uint inregs = 4;
01048 
01049     // Form instruction string
01050     ostringstream instostr("");
01051     uint outreg = 0;
01052     CalcTestInfo<T> expectedCalcOut(type);
01053     TProgramCounter pc = 0;
01054     T* pNULL = NULL;
01055     T  zero  = 0;
01056     T  min = std::numeric_limits<T>::min();
01057     T  max = std::numeric_limits<T>::max();
01058     T  mid = 10;
01059 
01060     const char* divbyzero = "22012";
01061 
01062     // Test MOD
01063     string modstr = string("MOD ") + typestr;
01064     addBinaryInstructions(instostr, "MOD", outreg, inregs);
01065     if (min != zero) {
01066         expectedCalcOut.add(
01067             modstr, (T) (min % min), pc++, __LINE__); // I0 % I0 (min % min)
01068     } else {
01069         expectedCalcOut.add(
01070             modstr, divbyzero, pc++, __LINE__);    // I0 % I0 (min % min)
01071     }
01072     expectedCalcOut.add(
01073         modstr, (T) (min % max), pc++, __LINE__);  // I0 % I1 (min % max)
01074     expectedCalcOut.add(
01075         modstr, pNULL,   pc++, __LINE__);          // I0 % I2 (min % NULL)
01076     expectedCalcOut.add(
01077         modstr, (T) (min % mid),  pc++, __LINE__); // I0 % I3 (min % 10)
01078 
01079     if (min != zero) {
01080         expectedCalcOut.add(
01081             modstr, (T) (max % min), pc++, __LINE__); // I1 % I0 (max % min)
01082     } else {
01083         expectedCalcOut.add(
01084             modstr, divbyzero, pc++, __LINE__);    // I1 % I0 (max % min)
01085     }
01086     expectedCalcOut.add(
01087         modstr, (T) (max % max), pc++, __LINE__);  // I1 % I1 (max % max)
01088     expectedCalcOut.add(
01089         modstr, pNULL,   pc++, __LINE__);          // I1 % I2 (max % NULL)
01090     expectedCalcOut.add(
01091         modstr, (T) (max % mid), pc++, __LINE__);  // I1 % I3 (max % 10)
01092 
01093     expectedCalcOut.add(
01094         modstr, pNULL, pc++, __LINE__);      // I2 % I0 (NULL % min)
01095     expectedCalcOut.add(
01096         modstr, pNULL, pc++, __LINE__);      // I2 % I1 (NULL % max)
01097     expectedCalcOut.add(
01098         modstr, pNULL, pc++, __LINE__);      // I2 % I2 (NULL % NULL)
01099     expectedCalcOut.add(
01100         modstr, pNULL, pc++, __LINE__);      // I2 % I3 (NULL % 10)
01101 
01102     if (min != zero) {
01103         expectedCalcOut.add(
01104             modstr, (T) (mid % min), pc++, __LINE__); // I3 % I0 (mid % min)
01105     } else {
01106         expectedCalcOut.add(
01107             modstr, divbyzero, pc++, __LINE__);    // I3 % I0 (mid % min)
01108     }
01109     expectedCalcOut.add(
01110         modstr, (T) (mid % max), pc++, __LINE__);  // I3 % I1 (10 % max)
01111     expectedCalcOut.add(
01112         modstr, pNULL, pc++, __LINE__);            // I3 % I2 (10 % NULL)
01113     expectedCalcOut.add(
01114         modstr, (T) (mid % mid), pc++, __LINE__);  // I3 % I3 (10 % 10)
01115 
01116     // Test AND
01117     string andstr = string("AND ") + typestr;
01118     addBinaryInstructions(instostr, "AND", outreg, inregs);
01119     expectedCalcOut.add(
01120         andstr, (T) (min&min), pc++, __LINE__);    // I0 & I0 (min & min)
01121     expectedCalcOut.add(
01122         andstr, (T) (min&max), pc++, __LINE__);    // I0 & I1 (min & max)
01123     expectedCalcOut.add(
01124         andstr, pNULL,   pc++, __LINE__);          // I0 & I2 (min & NULL)
01125     expectedCalcOut.add(
01126         andstr, (T) (min&mid),  pc++, __LINE__);   // I0 & I3 (min & 10)
01127 
01128     expectedCalcOut.add(
01129         andstr, (T) (max&min), pc++, __LINE__);    // I1 & I0 (max & min)
01130     expectedCalcOut.add(
01131         andstr, (T) (max&max), pc++, __LINE__);    // I1 & I1 (max & max)
01132     expectedCalcOut.add(
01133         andstr, pNULL,   pc++, __LINE__);          // I1 & I2 (max & NULL)
01134     expectedCalcOut.add(
01135         andstr, (T) (max&mid), pc++, __LINE__);    // I1 & I3 (max & 10)
01136 
01137     expectedCalcOut.add(
01138         andstr, pNULL, pc++, __LINE__);      // I2 & I0 (NULL & min)
01139     expectedCalcOut.add(
01140         andstr, pNULL, pc++, __LINE__);      // I2 & I1 (NULL & max)
01141     expectedCalcOut.add(
01142         andstr, pNULL, pc++, __LINE__);      // I2 & I2 (NULL & NULL)
01143     expectedCalcOut.add(
01144         andstr, pNULL, pc++, __LINE__);      // I2 & I3 (NULL & 10)
01145 
01146     expectedCalcOut.add(
01147         andstr, (T) (mid&min), pc++, __LINE__);    // I3 & I0 (10 & min)
01148     expectedCalcOut.add(
01149         andstr, (T) (mid&max), pc++, __LINE__);    // I3 & I1 (10 & max)
01150     expectedCalcOut.add(
01151         andstr, pNULL, pc++, __LINE__);            // I3 & I2 (10 & NULL)
01152     expectedCalcOut.add(
01153         andstr, (T) (mid&mid), pc++, __LINE__);    // I3 & I3 (10 & 10)
01154 
01155     // Test OR
01156     string orstr = string("OR ") + typestr;
01157     addBinaryInstructions(instostr, "OR", outreg, inregs);
01158     expectedCalcOut.add(
01159         orstr, (T) (min | min), pc++, __LINE__);  // I0 | I0 (min | min)
01160     expectedCalcOut.add(
01161         orstr, (T) (min | max), pc++, __LINE__);  // I0 | I1 (min | max)
01162     expectedCalcOut.add(
01163         orstr, pNULL,   pc++, __LINE__);          // I0 | I2 (min | NULL)
01164     expectedCalcOut.add(
01165         orstr, (T) (min | mid),  pc++, __LINE__); // I0 | I3 (min | 10)
01166 
01167     expectedCalcOut.add(
01168         orstr, (T) (max | min), pc++, __LINE__);  // I1 | I0 (max | min)
01169     expectedCalcOut.add(
01170         orstr, (T) (max | max), pc++, __LINE__);  // I1 | I1 (max | max)
01171     expectedCalcOut.add(
01172         orstr, pNULL,   pc++, __LINE__);          // I1 | I2 (max | NULL)
01173     expectedCalcOut.add(
01174         orstr, (T) (max | mid), pc++, __LINE__);  // I1 | I3 (max | 10)
01175 
01176     expectedCalcOut.add(
01177         orstr, pNULL, pc++, __LINE__);      // I2 | I0 (NULL | min)
01178     expectedCalcOut.add(
01179         orstr, pNULL, pc++, __LINE__);      // I2 | I1 (NULL | max)
01180     expectedCalcOut.add(
01181         orstr, pNULL, pc++, __LINE__);      // I2 | I2 (NULL | NULL)
01182     expectedCalcOut.add(
01183         orstr, pNULL, pc++, __LINE__);      // I2 | I3 (NULL | 10)
01184 
01185     expectedCalcOut.add(
01186         orstr, (T) (mid | min), pc++, __LINE__);  // I3 | I0 (10 | min)
01187     expectedCalcOut.add(
01188         orstr, (T) (mid | max), pc++, __LINE__);  // I3 | I1 (10 | max)
01189     expectedCalcOut.add(
01190         orstr, pNULL, pc++, __LINE__);            // I3 | I2 (10 | NULL)
01191     expectedCalcOut.add(
01192         orstr, (T) (mid | mid), pc++, __LINE__);  // I3 | I3 (10 | 10)
01193 
01194     // Test SHFL
01195     string shflstr = string("SHFL ") + typestr;
01196     addBinaryInstructions(instostr, "SHFL", outreg, inregs);
01197     expectedCalcOut.add(
01198         shflstr, (T) (min<<min), pc++, __LINE__);    // I0 << I0 (min << min)
01199     expectedCalcOut.add(
01200         shflstr, (T) (min<<max), pc++, __LINE__);    // I0 << I1 (min << max)
01201     expectedCalcOut.add(
01202         shflstr, pNULL,   pc++, __LINE__);           // I0 << I2 (min << NULL)
01203     expectedCalcOut.add(
01204         shflstr, (T) (min<<mid),  pc++, __LINE__);   // I0 << I3 (min << 10)
01205 
01206     expectedCalcOut.add(
01207         shflstr, (T) (max<<min), pc++, __LINE__);    // I1 << I0 (max << min)
01208     // NOTE jvs 28-Oct-2006:  I disabled the check for this because
01209     // shifting by more than the number of bits in the result
01210     // leads to test failure in g++ 4.1.2 optimized build.  I think
01211     // the reason is that the optimizer sees max<<max here and
01212     // does constant reduction, whereas when the calculator runs,
01213     // it can't do that.  And the computation it uses in the
01214     // constant reduction comes out different from the calculator.
01215     // I don't think we should be testing for this case because
01216     // doing something like (0xFFFFFFFF >> 50) gives a compiler
01217     // warning "right shift count >= width of type" anyway.
01218     expectedCalcOut.addRegister(shflstr, pc++);    // I1 << I1 (max << max)
01219     expectedCalcOut.add(
01220         shflstr, pNULL,   pc++, __LINE__);           // I1 << I2 (max << NULL)
01221     expectedCalcOut.add(
01222         shflstr, (T) (max<<mid), pc++, __LINE__);    // I1 << I3 (max << 10)
01223 
01224     expectedCalcOut.add(
01225         shflstr, pNULL, pc++, __LINE__);      // I2 << I0 (NULL << min)
01226     expectedCalcOut.add(
01227         shflstr, pNULL, pc++, __LINE__);      // I2 << I1 (NULL << max)
01228     expectedCalcOut.add(
01229         shflstr, pNULL, pc++, __LINE__);      // I2 << I2 (NULL << NULL)
01230     expectedCalcOut.add(
01231         shflstr, pNULL, pc++, __LINE__);      // I2 << I3 (NULL << 10)
01232 
01233     expectedCalcOut.add(
01234         shflstr, (T) (mid<<min), pc++, __LINE__);    // I3 << I0 (10 << min)
01235     expectedCalcOut.add(
01236         shflstr, (T) (mid<<max), pc++, __LINE__);    // I3 << I1 (10 << max)
01237     expectedCalcOut.add(
01238         shflstr, pNULL, pc++, __LINE__);             // I3 << I2 (10 << NULL)
01239     expectedCalcOut.add(
01240         shflstr, (T) (mid<<mid), pc++, __LINE__);    // I3 << I3 (10 << 10)
01241 
01242     // Test SHFR
01243     string shfrstr = string("SHFR ") + typestr;
01244     addBinaryInstructions(instostr, "SHFR", outreg, inregs);
01245     expectedCalcOut.add(
01246         shfrstr, (T) (min >> min), pc++, __LINE__);  // I0 >> I0 (min >> min)
01247     expectedCalcOut.add(
01248         shfrstr, (T) (min >> max), pc++, __LINE__);  // I0 >> I1 (min >> max)
01249     expectedCalcOut.add(
01250         shfrstr, pNULL,   pc++, __LINE__);           // I0 >> I2 (min >> NULL)
01251     expectedCalcOut.add(
01252         shfrstr, (T) (min >> mid),  pc++, __LINE__); // I0 >> I3 (min >> 10)
01253 
01254     expectedCalcOut.add(
01255         shfrstr, (T) (max >> min), pc++, __LINE__);  // I1 >> I0 (max >> min)
01256     // NOTE jvs 28-Oct-2006:  see corresponding note above on (max << max)
01257     expectedCalcOut.addRegister(shfrstr, pc++);    // I1 >> I1 (max >> max)
01258     expectedCalcOut.add(
01259         shfrstr, pNULL,   pc++, __LINE__);           // I1 >> I2 (max >> NULL)
01260     expectedCalcOut.add(
01261         shfrstr, (T) (max >> mid), pc++, __LINE__);  // I1 >> I3 (max >> 10)
01262 
01263     expectedCalcOut.add(
01264         shfrstr, pNULL, pc++, __LINE__);      // I2 >> I0 (NULL >> min)
01265     expectedCalcOut.add(
01266         shfrstr, pNULL, pc++, __LINE__);      // I2 >> I1 (NULL >> max)
01267     expectedCalcOut.add(
01268         shfrstr, pNULL, pc++, __LINE__);      // I2 >> I2 (NULL >> NULL)
01269     expectedCalcOut.add(
01270         shfrstr, pNULL, pc++, __LINE__);      // I2 >> I3 (NULL >> 10)
01271 
01272     expectedCalcOut.add(
01273         shfrstr, (T) (mid >> min), pc++, __LINE__);  // I3 >> I0 (10 >> min)
01274     expectedCalcOut.add(
01275         shfrstr, (T) (mid >> max), pc++, __LINE__);  // I3 >> I1 (10 >> max)
01276     expectedCalcOut.add(
01277         shfrstr, pNULL, pc++, __LINE__);             // I3 >> I2 (10 >> NULL)
01278     expectedCalcOut.add(
01279         shfrstr, (T) (mid >> mid), pc++, __LINE__);  // I3 >> I3 (10 >> 10)
01280 
01281     assert(outreg == static_cast<uint>(pc));
01282 
01283     // Form test string
01284     string testdesc = "testNativeInstructions: " + typestr;
01285     ostringstream testostr("");
01286 
01287     testostr << "I " << createRegisterString(typestr, inregs) << ";" << endl;
01288     testostr << "O " << createRegisterString(typestr, outreg) << ";" << endl;
01289     testostr << "T;" << endl;
01290 
01291     testostr << instostr.str();
01292 
01293     string teststr = testostr.str();
01294 
01295     CalcAssemblerTestCase testCase1(
01296         __LINE__, testdesc.c_str(),
01297         teststr.c_str());
01298     if (testCase1.assemble()) {
01299         testCase1.setInputMin(0);
01300         testCase1.setInputMax(1);
01301         testCase1.setInputNull(2);
01302         testCase1.template setInput<T>(3, mid);
01303         TupleData* outputTuple = testCase1.getExpectedOutputTuple();
01304         assert(outputTuple != NULL);
01305         expectedCalcOut.setTupleData(*outputTuple);
01306         testCase1.test(&expectedCalcOut);
01307     }
01308 
01309 }
01310 
01323 template <typename T>
01324 void CalcAssemblerTest::testNativeInstructions(
01325     StandardTypeDescriptorOrdinal type)
01326 {
01327     string typestr = getTypeString(type, CalcAssemblerTestCase::MAX_WIDTH);
01328     uint inregs = 4;
01329 
01330     // Form instruction string
01331     ostringstream instostr("");
01332     uint outreg = 0;
01333     CalcTestInfo<T> expectedCalcOut(type);
01334     TProgramCounter pc = 0;
01335     T* pNULL = NULL;
01336     T  zero  = 0;
01337     T  min = std::numeric_limits<T>::min();
01338     T  max = std::numeric_limits<T>::max();
01339     T  mid = 10;
01340 
01341 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01342     const char *overflow = "22003";
01343     const char *underflow = "22000";
01344 //    const char *invalid = "22023";
01345 #endif
01346     const char *divbyzero = "22012";
01347 
01348     // Test ADD
01349     addBinaryInstructions(instostr, "ADD", outreg, inregs);
01350     string addstr = string("ADD ") + typestr;
01351 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01352     if (std::numeric_limits<T>::is_signed
01353         && std::numeric_limits<T>::is_integer)
01354     {
01355         expectedCalcOut.add(
01356             addstr, overflow, pc++, __LINE__); // I0 + I0 (min + min)
01357     } else {
01358         expectedCalcOut.add(
01359             addstr, (T) (min + min), pc++, __LINE__); // I0 + I0 (min + min)
01360     }
01361 #else
01362     expectedCalcOut.add(
01363         addstr, (T) (min + min), pc++, __LINE__);  // I0 + I0 (min + min)
01364 #endif
01365     expectedCalcOut.add(
01366         addstr, (T) (min + max), pc++, __LINE__);  // I0 + I1 (min + max)
01367     expectedCalcOut.add(
01368         addstr, pNULL,   pc++, __LINE__);          // I0 + I2 (min + NULL)
01369     expectedCalcOut.add(
01370         addstr, (T) (min + mid),  pc++, __LINE__); // I0 + I3 (min + 10)
01371 
01372     expectedCalcOut.add(
01373         addstr, (T) (max + min), pc++, __LINE__);  // I1 + I0 (max + min)
01374 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01375     expectedCalcOut.add(
01376         addstr, overflow, pc++, __LINE__);         // I1 + I1 (max + max)
01377 #else
01378     expectedCalcOut.add(
01379         addstr, (T) (max + max), pc++, __LINE__);  // I1 + I1 (max + max)
01380 #endif
01381     expectedCalcOut.add(
01382         addstr, pNULL,   pc++, __LINE__);          // I1 + I2 (max + NULL)
01383 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01384     if (std::numeric_limits<T>::is_integer) {
01385         expectedCalcOut.add(
01386             addstr, overflow, pc++, __LINE__);         // I1 + I3 (max + 10)
01387     } else {
01388         expectedCalcOut.add(
01389             addstr, (T) (max + mid), pc++, __LINE__);  // I1 + I3 (max + 10)
01390     }
01391 #else
01392     expectedCalcOut.add(
01393         addstr, (T) (max + mid), pc++, __LINE__);  // I1 + I3 (max + 10)
01394 #endif
01395 
01396 
01397     expectedCalcOut.add(
01398         addstr, pNULL, pc++, __LINE__);      // I2 + I0 (NULL + min)
01399     expectedCalcOut.add(
01400         addstr, pNULL, pc++, __LINE__);      // I2 + I1 (NULL + max)
01401     expectedCalcOut.add(
01402         addstr, pNULL, pc++, __LINE__);      // I2 + I2 (NULL + NULL)
01403     expectedCalcOut.add(
01404         addstr, pNULL, pc++, __LINE__);      // I2 + I3 (NULL + 10)
01405 
01406     expectedCalcOut.add(
01407         addstr, (T) (mid + min), pc++, __LINE__);  // I3 + I0 (10 + min)
01408 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01409     if (std::numeric_limits<T>::is_integer) {
01410         expectedCalcOut.add(
01411             addstr, overflow, pc++, __LINE__);         // I3 + I1 (10 + max)
01412     } else {
01413         expectedCalcOut.add(
01414             addstr, (T) (mid + max), pc++, __LINE__);  // I3 + I1 (10 + max)
01415     }
01416 #else
01417     expectedCalcOut.add(
01418         addstr, (T) (mid + max), pc++, __LINE__);  // I3 + I1 (10 + max)
01419 #endif
01420     expectedCalcOut.add(
01421         addstr, pNULL, pc++, __LINE__);            // I3 + I2 (10 + NULL)
01422     expectedCalcOut.add(
01423         addstr, (T) (mid + mid), pc++, __LINE__);  // I3 + I3 (10 + 10)
01424 
01425     // Test SUB
01426     addBinaryInstructions(instostr, "SUB", outreg, inregs);
01427     string substr = string("SUB ") + typestr;
01428     expectedCalcOut.add(
01429         substr, (T) (min - min), pc++, __LINE__);  // I0 - I0 (min - min)
01430 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01431     if (std::numeric_limits<T>::is_integer) {
01432         expectedCalcOut.add(
01433             substr, overflow, pc++, __LINE__);         // I0 - I1 (min - max)
01434     } else {
01435         expectedCalcOut.add(
01436             substr, (T) (min - max), pc++, __LINE__);  // I0 - I1 (min - max)
01437     }
01438 #else
01439     expectedCalcOut.add(
01440         substr, (T) (min - max), pc++, __LINE__);  // I0 - I1 (min - max)
01441 #endif
01442     expectedCalcOut.add(
01443         substr, pNULL,   pc++, __LINE__);          // I0 - I2 (min - NULL)
01444 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01445     if (std::numeric_limits<T>::is_integer) {
01446         expectedCalcOut.add(
01447             substr, overflow,  pc++, __LINE__);        // I0 - I3 (min - 10)
01448     } else {
01449         expectedCalcOut.add(
01450             substr, (T) (min - mid),  pc++, __LINE__); // I0 - I3 (min - 10)
01451     }
01452 #else
01453     expectedCalcOut.add(
01454         substr, (T) (min - mid),  pc++, __LINE__); // I0 - I3 (min - 10)
01455 #endif
01456 
01457 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01458     if (std::numeric_limits<T>::is_signed
01459         && std::numeric_limits<T>::is_integer)
01460     {
01461         expectedCalcOut.add(
01462             substr, overflow, pc++, __LINE__);         // I1 - I0 (max - min)
01463     } else {
01464         expectedCalcOut.add(
01465             substr, (T) (max - min), pc++, __LINE__);  // I1 - I0 (max - min)
01466     }
01467 #else
01468     expectedCalcOut.add(
01469         substr, (T) (max - min), pc++, __LINE__);  // I1 - I0 (max - min)
01470 #endif
01471     expectedCalcOut.add(
01472         substr, (T) (max - max), pc++, __LINE__);  // I1 - I1 (max - max)
01473     expectedCalcOut.add(
01474         substr, pNULL,   pc++, __LINE__);          // I1 - I2 (max - NULL)
01475     expectedCalcOut.add(
01476         substr, (T) (max - mid), pc++, __LINE__);  // I1 - I3 (max - 10)
01477 
01478     expectedCalcOut.add(
01479         substr, pNULL, pc++, __LINE__);      // I2 - I0 (NULL - min)
01480     expectedCalcOut.add(
01481         substr, pNULL, pc++, __LINE__);      // I2 - I1 (NULL - max)
01482     expectedCalcOut.add(
01483         substr, pNULL, pc++, __LINE__);      // I2 - I2 (NULL - NULL)
01484     expectedCalcOut.add(
01485         substr, pNULL, pc++, __LINE__);      // I2 - I3 (NULL - 10)
01486 
01487 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01488     if (std::numeric_limits<T>::is_signed
01489         && std::numeric_limits<T>::is_integer)
01490     {
01491         expectedCalcOut.add(
01492             substr, overflow, pc++, __LINE__);    // I3 - I0 (10 - min)
01493     } else {
01494         expectedCalcOut.add(
01495             substr, (T) (mid - min), pc++, __LINE__);  // I3 - I0 (10 - min)
01496     }
01497 #else
01498     expectedCalcOut.add(
01499         substr, (T) (mid - min), pc++, __LINE__);  // I3 - I0 (10 - min)
01500 #endif
01501 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01502     if (!std::numeric_limits<T>::is_signed) {
01503         expectedCalcOut.add(
01504             substr, overflow, pc++, __LINE__);    // I3 - I1 (10 - max)
01505     } else {
01506         expectedCalcOut.add(
01507             substr, (T) (mid - max), pc++, __LINE__);  // I3 - I1 (10 - max)
01508     }
01509 #else
01510     expectedCalcOut.add(
01511         substr, (T) (mid - max), pc++, __LINE__);  // I3 - I1 (10 - max)
01512 #endif
01513     expectedCalcOut.add(
01514         substr, pNULL, pc++, __LINE__);            // I3 - I2 (10 - NULL)
01515     expectedCalcOut.add(
01516         substr, (T) (mid - mid), pc++, __LINE__);  // I3 - I3 (10 - 10)
01517 
01518     // Test MUL
01519     addBinaryInstructions(instostr, "MUL", outreg, inregs);
01520     string mulstr = string("MUL ") + typestr;
01521 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01522     if (!std::numeric_limits<T>::is_signed) {
01523         expectedCalcOut.add(
01524             mulstr, (T) (min * min), pc++, __LINE__);    // I0 * I0 (min * min)
01525     } else if (std::numeric_limits<T>::is_integer) {
01526         expectedCalcOut.add(
01527             mulstr, overflow, pc++, __LINE__);         // I0 * I0 (min * min)
01528     } else {
01529         expectedCalcOut.add(
01530             mulstr, underflow, pc++, __LINE__);         // I0 * I0 (min * min)
01531     }
01532 #else
01533     expectedCalcOut.add(
01534         mulstr, (T) (min * min), pc++, __LINE__);    // I0 * I0 (min * min)
01535 #endif
01536 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01537     if (std::numeric_limits<T>::is_signed
01538         && std::numeric_limits<T>::is_integer)
01539     {
01540         expectedCalcOut.add(
01541             mulstr, overflow, pc++, __LINE__);         // I0 * I1 (min * max)
01542     } else {
01543         expectedCalcOut.add(
01544             mulstr, (T) (min * max), pc++, __LINE__);    // I0 * I1 (min * max)
01545     }
01546 #else
01547     expectedCalcOut.add(
01548         mulstr, (T) (min*max), pc++, __LINE__);    // I0 * I1 (min * max)
01549 #endif
01550     expectedCalcOut.add(
01551         mulstr, pNULL,   pc++, __LINE__);          // I0 * I2 (min * NULL)
01552 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01553     if (std::numeric_limits<T>::is_signed
01554         && std::numeric_limits<T>::is_integer)
01555     {
01556         expectedCalcOut.add(
01557             mulstr, overflow,  pc++, __LINE__);        // I0 * I3 (min * 10)
01558     } else {
01559         expectedCalcOut.add(
01560             mulstr, (T) (min*mid),  pc++, __LINE__);   // I0 * I3 (min * 10)
01561     }
01562 #else
01563     expectedCalcOut.add(
01564         mulstr, (T) (min*mid),  pc++, __LINE__);   // I0 * I3 (min * 10)
01565 #endif
01566 
01567 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01568     if (std::numeric_limits<T>::is_signed
01569         && std::numeric_limits<T>::is_integer)
01570     {
01571         expectedCalcOut.add(
01572             mulstr, overflow, pc++, __LINE__);         // I1 * I0 (max * min)
01573     } else {
01574         expectedCalcOut.add(
01575             mulstr, (T) (max * min), pc++, __LINE__);    // I1 * I0 (max * min)
01576     }
01577 #else
01578     expectedCalcOut.add(
01579         mulstr, (T) (max * min), pc++, __LINE__);    // I1 * I0 (max * min)
01580 #endif
01581 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01582     expectedCalcOut.add(
01583         mulstr, overflow, pc++, __LINE__);         // I1 * I1 (max * max)
01584 #else
01585     expectedCalcOut.add(
01586         mulstr, (T) (max*max), pc++, __LINE__);    // I1 * I1 (max * max)
01587 #endif
01588     expectedCalcOut.add(
01589         mulstr, pNULL,   pc++, __LINE__);          // I1 * I2 (max * NULL)
01590 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01591     expectedCalcOut.add(
01592         mulstr, overflow, pc++, __LINE__);         // I1 * I3 (max * 10)
01593 #else
01594     expectedCalcOut.add(
01595         mulstr, (T) (max*mid), pc++, __LINE__);    // I1 * I3 (max * 10)
01596 #endif
01597 
01598     expectedCalcOut.add(
01599         mulstr, pNULL, pc++, __LINE__);      // I2 * I0 (NULL * min)
01600     expectedCalcOut.add(
01601         mulstr, pNULL, pc++, __LINE__);      // I2 * I1 (NULL * max)
01602     expectedCalcOut.add(
01603         mulstr, pNULL, pc++, __LINE__);      // I2 * I2 (NULL * NULL)
01604     expectedCalcOut.add(
01605         mulstr, pNULL, pc++, __LINE__);      // I2 * I3 (NULL * 10)
01606 
01607 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01608     if (std::numeric_limits<T>::is_signed
01609         && std::numeric_limits<T>::is_integer)
01610     {
01611         expectedCalcOut.add(
01612             mulstr, overflow, pc++, __LINE__);         // I3 * I0 (10 * min)
01613     } else {
01614         expectedCalcOut.add(
01615             mulstr, (T) (mid*min), pc++, __LINE__);    // I3 * I0 (10 * min)
01616     }
01617 #else
01618     expectedCalcOut.add(
01619         mulstr, (T) (mid*min), pc++, __LINE__);    // I3 * I0 (10 * min)
01620 #endif
01621 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01622     expectedCalcOut.add(
01623         mulstr, overflow, pc++, __LINE__);         // I3 * I1 (10 * max)
01624 #else
01625     expectedCalcOut.add(
01626         mulstr, (T) (mid*max), pc++, __LINE__);    // I3 * I1 (10 * max)
01627 #endif
01628     expectedCalcOut.add(
01629         mulstr, pNULL, pc++, __LINE__);            // I3 * I2 (10 * NULL)
01630     expectedCalcOut.add(
01631         mulstr, (T) (mid*mid), pc++, __LINE__);    // I3 * I3 (10 * 10)
01632 
01633     // Test DIV
01634     addBinaryInstructions(instostr, "DIV", outreg, inregs);
01635     string divstr = string("DIV ") + typestr;
01636     if (min != zero) {
01637         expectedCalcOut.add(
01638             divstr, (T) (min / min), pc++, __LINE__); // I0 / I0 (min / min)
01639     } else {
01640         expectedCalcOut.add(
01641             divstr, divbyzero, pc++, __LINE__);    // I0 / I0 (min / min)
01642     }
01643 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01644     if (std::numeric_limits<T>::is_integer) {
01645         expectedCalcOut.add(
01646             divstr, (T) (min / max), pc++, __LINE__); // I0 / I1 (min / max)
01647     } else {
01648         expectedCalcOut.add(
01649             divstr, underflow, pc++, __LINE__);    // I0 / I1 (min / min)
01650     }
01651 #else
01652     expectedCalcOut.add(
01653         divstr, (T) (min / max), pc++, __LINE__);   // I0 / I1 (min / max)
01654 #endif
01655     expectedCalcOut.add(
01656         divstr, pNULL,   pc++, __LINE__);           // I0 / I2 (min / NULL)
01657 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01658     if (std::numeric_limits<T>::is_integer) {
01659         expectedCalcOut.add(
01660             divstr, (T) (min / mid),  pc++, __LINE__);  // I0 / I3 (min / 10)
01661     } else {
01662         expectedCalcOut.add(
01663             divstr, underflow,  pc++, __LINE__);    // I0 / I3 (min / 10)
01664     }
01665 #else
01666     expectedCalcOut.add(
01667         divstr, (T) (min / mid),  pc++, __LINE__);    // I0 / I3 (min / 10)
01668 #endif
01669 
01670     if (min != zero) {
01671 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01672         if (std::numeric_limits<T>::is_integer) {
01673             expectedCalcOut.add(
01674                 divstr, (T) (max / min), pc++, __LINE__); // I1 / I0 (max / min)
01675         } else {
01676             expectedCalcOut.add(
01677                 divstr, overflow, pc++, __LINE__);    // I1 / I0 (max / min)
01678         }
01679 #else
01680         expectedCalcOut.add(
01681             divstr, (T) (max / min), pc++, __LINE__); // I1 / I0 (max / min)
01682 #endif
01683     } else {
01684         expectedCalcOut.add(
01685             divstr, divbyzero, pc++, __LINE__);    // I1 / I0 (max / min)
01686     }
01687     expectedCalcOut.add(
01688         divstr, (T) (max / max), pc++, __LINE__);  // I1 / I1 (max / max)
01689     expectedCalcOut.add(
01690         divstr, pNULL,   pc++, __LINE__);          // I1 / I2 (max / NULL)
01691     expectedCalcOut.add(
01692         divstr, (T) (max / mid), pc++, __LINE__);  // I1 / I3 (max / 10)
01693 
01694     expectedCalcOut.add(
01695         divstr, pNULL, pc++, __LINE__);      // I2 / I0 (NULL / min)
01696     expectedCalcOut.add(
01697         divstr, pNULL, pc++, __LINE__);      // I2 / I1 (NULL / max)
01698     expectedCalcOut.add(
01699         divstr, pNULL, pc++, __LINE__);      // I2 / I2 (NULL / NULL)
01700     expectedCalcOut.add(
01701         divstr, pNULL, pc++, __LINE__);      // I2 / I3 (NULL / 10)
01702 
01703     if (min != zero) {
01704 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01705         if (std::numeric_limits<T>::is_integer) {
01706             expectedCalcOut.add(
01707                 divstr, (T) (mid / min), pc++); // I3 / I0 (mid / min)
01708         } else {
01709             expectedCalcOut.add(
01710                 divstr, overflow, pc++, __LINE__);    // I3 / I0 (mid / min)
01711         }
01712 #else
01713         expectedCalcOut.add(
01714             divstr, (T) (mid / min), pc++); // I3 / I0 (mid / min)
01715 #endif
01716     } else {
01717         expectedCalcOut.add(
01718             divstr, divbyzero, pc++);    // I3 / I0 (mid / min)
01719     }
01720     expectedCalcOut.add(
01721         divstr, (T) (mid / max), pc++);   // I3 / I1 (10 / max)
01722     expectedCalcOut.add(
01723         divstr, pNULL, pc++);             // I3 / I2 (10 / NULL)
01724     expectedCalcOut.add(
01725         divstr, (T) (mid / mid), pc++);   // I3 / I3 (10 / 10)
01726 
01727     // Test NEG
01728     addUnaryInstructions(instostr, "NEG", outreg, inregs);
01729     string negstr = string("NEG ") + typestr;
01730 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01731     if (std::numeric_limits<T>::is_signed
01732         && std::numeric_limits<T>::is_integer)
01733     {
01734         expectedCalcOut.add(
01735             negstr, overflow, pc++, __LINE__);      // - I0 (- min)
01736     } else {
01737         expectedCalcOut.add(
01738             negstr, (T) (-min), pc++, __LINE__);    // - I0 (- min)
01739     }
01740 #else
01741     expectedCalcOut.add(
01742         negstr, (T) (-min), pc++, __LINE__);    // - I0 (- min)
01743 #endif
01744 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01745     if (!std::numeric_limits<T>::is_signed) {
01746         expectedCalcOut.add(
01747             negstr, overflow, pc++, __LINE__);      // - I0 (- min)
01748     } else {
01749         expectedCalcOut.add(
01750             negstr, (T) (-max), pc++, __LINE__);    // - I1 (- max)
01751     }
01752 #else
01753     expectedCalcOut.add(
01754         negstr, (T) (-max), pc++, __LINE__);    // - I1 (- max)
01755 #endif
01756     expectedCalcOut.add(
01757         negstr, pNULL,      pc++, __LINE__);    // - I2 (- NULL)
01758 #if defined(USING_NOISY_ARITHMETIC) && USING_NOISY_ARITHMETIC
01759     if (std::numeric_limits<T>::is_signed) {
01760         expectedCalcOut.add(
01761             negstr, (T) (-mid), pc++, __LINE__);// - I3 (- 10)
01762     } else {
01763         expectedCalcOut.add(
01764             negstr, overflow, pc++, __LINE__);  // - I3 (- 10)
01765     }
01766 #else
01767     expectedCalcOut.add(
01768         negstr, (T) (-mid), pc++, __LINE__);    // - I3 (- 10)
01769 #endif
01770 
01771     assert(outreg == static_cast<uint>(pc));
01772 
01773     // Form test string
01774     string testdesc = "testNativeInstructions: " + typestr;
01775     ostringstream testostr("");
01776 
01777     testostr << "I " << createRegisterString(typestr, inregs) << ";" << endl;
01778     testostr << "O " << createRegisterString(typestr, outreg) << ";" << endl;
01779     testostr << "T;" << endl;
01780 
01781     testostr << instostr.str();
01782 
01783     string teststr = testostr.str();
01784 
01785     CalcAssemblerTestCase testCase1(
01786         __LINE__, testdesc.c_str(),
01787         teststr.c_str());
01788     if (testCase1.assemble()) {
01789         testCase1.setInputMin(0);
01790         testCase1.setInputMax(1);
01791         testCase1.setInputNull(2);
01792         testCase1.template setInput<T>(3, mid);
01793         TupleData* outputTuple = testCase1.getExpectedOutputTuple();
01794         assert(outputTuple != NULL);
01795         expectedCalcOut.setTupleData(*outputTuple);
01796         testCase1.test(&expectedCalcOut);
01797     }
01798 }
01799 
01812 void CalcAssemblerTest::testBoolInstructions(StandardTypeDescriptorOrdinal type)
01813 {
01814     string typestr = getTypeString(type, CalcAssemblerTestCase::MAX_WIDTH);
01815     string boolstr = getTypeString(STANDARD_TYPE_BOOL);
01816     uint inregs = 3;
01817 
01818     // Form instruction string
01819     ostringstream instostr("");
01820     uint outreg = 0;
01821     vector<bool*> boolout;
01822     bool bFalse  = false;
01823     bool bTrue   = true;
01824     bool* pFalse = &bFalse;
01825     bool* pTrue  = &bTrue;
01826 
01827     // Make copy of input registers to local registers
01828     instostr << "MOVE L0, I0;" << endl;
01829     instostr << "MOVE L1, I1;" << endl;
01830     instostr << "MOVE L2, I2;" << endl;
01831 
01832     // Test is null
01833     addUnaryInstructions(instostr, "ISNULL", outreg, inregs);
01834     boolout.push_back(pFalse); // I0 = min
01835     boolout.push_back(pFalse); // I1 = max
01836     boolout.push_back(pTrue);  // I2 = NULL
01837 
01838     // Test is not null
01839     addUnaryInstructions(instostr, "ISNOTNULL", outreg, inregs);
01840     boolout.push_back(pTrue);  // I0 = min
01841     boolout.push_back(pTrue);  // I1 = max
01842     boolout.push_back(pFalse); // I2 = NULL
01843 
01844     // Test equal
01845     // Check equal if the registers are different (use local)
01846     instostr << "EQ O" << outreg++ <<", L0, I0;" << endl; // true
01847     boolout.push_back(pTrue);
01848     instostr << "EQ O" << outreg++ <<", L1, I1;" << endl; // true
01849     boolout.push_back(pTrue);
01850 
01851     // Check equal using input registers
01852     addBinaryInstructions(instostr, "EQ", outreg, inregs);
01853     boolout.push_back(pTrue);  // I0, I0
01854     boolout.push_back(pFalse); // I0, I1
01855     boolout.push_back(NULL);   // I0, I2
01856     boolout.push_back(pFalse); // I1, I0
01857     boolout.push_back(pTrue);  // I1, I1
01858     boolout.push_back(NULL);   // I1, I2
01859     boolout.push_back(NULL);   // I2, I0
01860     boolout.push_back(NULL);   // I2, I1
01861     boolout.push_back(NULL);   // I2, I2
01862 
01863     // Test not equal
01864     // Check not equal if the registers are different (use local)
01865     instostr << "NE O" << outreg++ <<", L0, I0;" << endl; // false
01866     boolout.push_back(pFalse);
01867     instostr << "NE O" << outreg++ <<", L1, I1;" << endl; // false
01868     boolout.push_back(pFalse);
01869 
01870     // Check not equal using input registers
01871     addBinaryInstructions(instostr, "NE", outreg, inregs);
01872     boolout.push_back(pFalse); // I0, I0
01873     boolout.push_back(pTrue);  // I0, I1
01874     boolout.push_back(NULL);   // I0, I2
01875     boolout.push_back(pTrue);  // I1, I0
01876     boolout.push_back(pFalse); // I1, I1
01877     boolout.push_back(NULL);   // I1, I2
01878     boolout.push_back(NULL);   // I2, I0
01879     boolout.push_back(NULL);   // I2, I1
01880     boolout.push_back(NULL);   // I2, I2
01881 
01882     // Test greater than
01883     addBinaryInstructions(instostr, "GT", outreg, inregs);
01884     boolout.push_back(pFalse); // I0, I0
01885     boolout.push_back(pFalse); // I0, I1
01886     boolout.push_back(NULL);   // I0, I2
01887     boolout.push_back(pTrue);  // I1, I0
01888     boolout.push_back(pFalse); // I1, I1
01889     boolout.push_back(NULL);   // I1, I2
01890     boolout.push_back(NULL);   // I2, I0
01891     boolout.push_back(NULL);   // I2, I1
01892     boolout.push_back(NULL);   // I2, I2
01893 
01894     // Test less than
01895     addBinaryInstructions(instostr, "LT", outreg, inregs);
01896     boolout.push_back(pFalse); // I0, I0
01897     boolout.push_back(pTrue);  // I0, I1
01898     boolout.push_back(NULL);   // I0, I2
01899     boolout.push_back(pFalse); // I1, I0
01900     boolout.push_back(pFalse); // I1, I1
01901     boolout.push_back(NULL);   // I1, I2
01902     boolout.push_back(NULL);   // I2, I0
01903     boolout.push_back(NULL);   // I2, I1
01904     boolout.push_back(NULL);   // I2, I2
01905 
01906     if (type == STANDARD_TYPE_BOOL) {
01907         // Test NOT
01908         addUnaryInstructions(instostr, "NOT", outreg, inregs);
01909         boolout.push_back(pTrue);  // I0 = min = false
01910         boolout.push_back(pFalse); // I1 = max = true
01911         boolout.push_back(NULL);   // I2 = NULL
01912 
01913         // Test IS
01914         addBinaryInstructions(instostr, "IS", outreg, inregs);
01915         boolout.push_back(pTrue);  // I0, I0
01916         boolout.push_back(pFalse); // I0, I1
01917         boolout.push_back(pFalse); // I0, I2
01918         boolout.push_back(pFalse); // I1, I0
01919         boolout.push_back(pTrue);  // I1, I1
01920         boolout.push_back(pFalse); // I1, I2
01921         boolout.push_back(pFalse); // I2, I0
01922         boolout.push_back(pFalse); // I2, I1
01923         boolout.push_back(pTrue);  // I2, I2
01924 
01925         // Test IS NOT
01926         addBinaryInstructions(instostr, "ISNOT", outreg, inregs);
01927         boolout.push_back(pFalse); // I0, I0
01928         boolout.push_back(pTrue);  // I0, I1
01929         boolout.push_back(pTrue);  // I0, I2
01930         boolout.push_back(pTrue);  // I1, I0
01931         boolout.push_back(pFalse); // I1, I1
01932         boolout.push_back(pTrue);  // I1, I2
01933         boolout.push_back(pTrue);  // I2, I0
01934         boolout.push_back(pTrue);  // I2, I1
01935         boolout.push_back(pFalse); // I2, I2
01936 
01937         // Test AND
01938         addBinaryInstructions(instostr, "AND", outreg, inregs);
01939         boolout.push_back(pFalse); // I0, I0
01940         boolout.push_back(pFalse); // I0, I1
01941         boolout.push_back(pFalse); // I0, I2
01942         boolout.push_back(pFalse); // I1, I0
01943         boolout.push_back(pTrue);  // I1, I1
01944         boolout.push_back(NULL);   // I1, I2
01945         boolout.push_back(pFalse); // I2, I0
01946         boolout.push_back(NULL);   // I2, I1
01947         boolout.push_back(NULL);   // I2, I2
01948 
01949         // Test OR
01950         addBinaryInstructions(instostr, "OR", outreg, inregs);
01951         boolout.push_back(pFalse); // I0, I0
01952         boolout.push_back(pTrue);  // I0, I1
01953         boolout.push_back(NULL);   // I0, I2
01954         boolout.push_back(pTrue);  // I1, I0
01955         boolout.push_back(pTrue);  // I1, I1
01956         boolout.push_back(pTrue);  // I1, I2
01957         boolout.push_back(NULL);   // I2, I0
01958         boolout.push_back(pTrue);  // I2, I1
01959         boolout.push_back(NULL);   // I2, I2
01960     } else {
01961         // Test GE
01962         addBinaryInstructions(instostr, "GE", outreg, inregs);
01963         boolout.push_back(pTrue);  // I0, I0
01964         boolout.push_back(pFalse); // I0, I1
01965         boolout.push_back(NULL);   // I0, I2
01966         boolout.push_back(pTrue);  // I1, I0
01967         boolout.push_back(pTrue);  // I1, I1
01968         boolout.push_back(NULL);   // I1, I2
01969         boolout.push_back(NULL);   // I2, I0
01970         boolout.push_back(NULL);   // I2, I1
01971         boolout.push_back(NULL);   // I2, I2
01972 
01973         // Test LE
01974         addBinaryInstructions(instostr, "LE", outreg, inregs);
01975         boolout.push_back(pTrue);  // I0, I0
01976         boolout.push_back(pTrue);  // I0, I1
01977         boolout.push_back(NULL);   // I0, I2
01978         boolout.push_back(pFalse); // I1, I0
01979         boolout.push_back(pTrue);  // I1, I1
01980         boolout.push_back(NULL);   // I1, I2
01981         boolout.push_back(NULL);   // I2, I0
01982         boolout.push_back(NULL);   // I2, I1
01983         boolout.push_back(NULL);   // I2, I2
01984     }
01985 
01986     assert(outreg == boolout.size());
01987 
01988     // Form test string
01989     string testdesc = "testBoolInstructions: " + typestr;
01990     ostringstream testostr("");
01991 
01992     testostr << "I " << createRegisterString(typestr, inregs) << ";" << endl;
01993     testostr << "L " << createRegisterString(typestr, inregs) << ";" << endl;
01994     testostr << "O " << createRegisterString(boolstr, outreg) << ";" << endl;
01995     testostr << "T;" << endl;
01996 
01997     testostr << instostr.str();
01998 
01999     string teststr = testostr.str();
02000 
02001     CalcAssemblerTestCase testCase1(
02002         __LINE__, testdesc.c_str(), teststr.c_str());
02003     if (testCase1.assemble()) {
02004         testCase1.setInputMin(0);
02005         testCase1.setInputMax(1);
02006         testCase1.setInputNull(2);
02007         for (uint i = 0; i < outreg; i++) {
02008             if (boolout[i]) {
02009                 testCase1.setExpectedOutput<bool>(i, *boolout[i]);
02010             } else {
02011                 testCase1.setExpectedOutputNull(i);
02012             }
02013         }
02014         testCase1.test();
02015     }
02016 }
02017 
02018 void CalcAssemblerTest::testStandardTypes()
02019 {
02020     string max[STANDARD_TYPE_END_NO_UNICODE];
02021     string min[STANDARD_TYPE_END_NO_UNICODE];
02022     string overflow[STANDARD_TYPE_END_NO_UNICODE];
02023     string underflow[STANDARD_TYPE_END_NO_UNICODE];
02024 
02025     min[STANDARD_TYPE_BOOL] = "0";
02026     max[STANDARD_TYPE_BOOL] = "1";
02027     underflow[STANDARD_TYPE_BOOL] = "-1";
02028     overflow[STANDARD_TYPE_BOOL] = "2";
02029 
02030     min[STANDARD_TYPE_INT_8] = "-128";
02031     max[STANDARD_TYPE_INT_8] = "127";
02032     min[STANDARD_TYPE_UINT_8] = "0";
02033     max[STANDARD_TYPE_UINT_8] = "255";
02034 
02035     underflow[STANDARD_TYPE_INT_8] = "-129";
02036     overflow[STANDARD_TYPE_INT_8] = "128";
02037     underflow[STANDARD_TYPE_UINT_8] = "-1";
02038     overflow[STANDARD_TYPE_UINT_8] = "256";
02039 
02040     min[STANDARD_TYPE_INT_16] = "-32768";
02041     max[STANDARD_TYPE_INT_16] = "32767";
02042     min[STANDARD_TYPE_UINT_16] = "0";
02043     max[STANDARD_TYPE_UINT_16] = "65535";
02044 
02045     underflow[STANDARD_TYPE_INT_16] = "-32769";
02046     overflow[STANDARD_TYPE_INT_16] = "32768";
02047     underflow[STANDARD_TYPE_UINT_16] = "-1";
02048     overflow[STANDARD_TYPE_UINT_16] = "65536";
02049 
02050     min[STANDARD_TYPE_INT_32] = "-2147483648";
02051     max[STANDARD_TYPE_INT_32] = "2147483647";
02052     min[STANDARD_TYPE_UINT_32] = "0";
02053     max[STANDARD_TYPE_UINT_32] = "4294967295";
02054 
02055     underflow[STANDARD_TYPE_INT_32] = "-2147483649";
02056     overflow[STANDARD_TYPE_INT_32] = "2147483648";
02057     underflow[STANDARD_TYPE_UINT_32] = "-1";
02058     overflow[STANDARD_TYPE_UINT_32] = "4294967296";
02059 
02060     min[STANDARD_TYPE_INT_64] = "-9223372036854775808";
02061     max[STANDARD_TYPE_INT_64] = "9223372036854775807";
02062     min[STANDARD_TYPE_UINT_64] = "0";
02063     max[STANDARD_TYPE_UINT_64] = "18446744073709551615";
02064 
02065     underflow[STANDARD_TYPE_INT_64] = "-9223372036854775809";
02066     overflow[STANDARD_TYPE_INT_64] = "9223372036854775808";
02067     underflow[STANDARD_TYPE_UINT_64] = "-1";
02068     overflow[STANDARD_TYPE_UINT_64] = "18446744073709551616";
02069 
02070     min[STANDARD_TYPE_REAL] = "1.17549e-38";
02071     max[STANDARD_TYPE_REAL] = "3.40282e+38";
02072     min[STANDARD_TYPE_DOUBLE] = "2.22507e-308";
02073     max[STANDARD_TYPE_DOUBLE] = "1.79769e+308";
02074 
02075     // TODO: What to do for underflow of floats/doubles?
02076     // Looks like they are just turned into 0s.
02077     underflow[STANDARD_TYPE_REAL] = "1.17549e-46";
02078     overflow[STANDARD_TYPE_REAL] = "3.40282e+39";
02079     underflow[STANDARD_TYPE_DOUBLE] = "2.22507e-324";
02080     overflow[STANDARD_TYPE_DOUBLE] = "1.79769e+309";
02081 
02082     for (uint i = STANDARD_TYPE_MIN; i < STANDARD_TYPE_END_NO_UNICODE; i++) {
02083         // First test setting output = input (using move)
02084         // Also test tonull
02085         // For max, min, NULL
02086         StandardTypeDescriptorOrdinal type = StandardTypeDescriptorOrdinal(i);
02087         string typestr = getTypeString(type, CalcAssemblerTestCase::MAX_WIDTH);
02088         string testdesc = "testStandardTypes: " + typestr;
02089         ostringstream testostr("");
02090         testostr << "I " << createRegisterString(typestr, 3) << ";" << endl;
02091         testostr << "O " << createRegisterString(typestr, 4) << ";" << endl;
02092         testostr << "T;" << endl;
02093         testostr << "MOVE O0, I0;" << endl;
02094         testostr << "MOVE O1, I1;" << endl;
02095         testostr << "MOVE O2, I2;" << endl;
02096         testostr << "TONULL O3;" << endl;
02097         string teststr = testostr.str();
02098 
02099         CalcAssemblerTestCase testCase1(
02100             __LINE__, testdesc.c_str(), teststr.c_str());
02101         if (testCase1.assemble()) {
02102             testCase1.setInputMin(0);
02103             testCase1.setExpectedOutputMin(0);
02104             testCase1.setInputMax(1);
02105             testCase1.setExpectedOutputMax(1);
02106             testCase1.setInputNull(2);
02107             testCase1.setExpectedOutputNull(2);
02108             testCase1.setExpectedOutputNull(3);
02109             testCase1.test();
02110         }
02111 
02112         if (!StandardTypeDescriptor::isArray(type)) {
02113             // Verify what we think is the min/max is the min/max
02114             assert (testCase1.getInput(0) == min[type]);
02115             assert (testCase1.getInput(1) == max[type]);
02116         }
02117 
02118         // Now test literal binding for the type
02119         // For min, max, NULL
02120         ostringstream testostr2("");
02121         testostr2 << "O " << createRegisterString(typestr, 3) << ";" << endl;
02122         testostr2 << "C " << createRegisterString(typestr, 3) << ";" << endl;
02123         testostr2 << "V " << testCase1.getInput(0)
02124                   << ", " << testCase1.getInput(1)
02125                   << ", " << testCase1.getInput(2)
02126                   << ";" << endl;
02127         testostr2 << "T;" << endl;
02128         testostr2 << "MOVE O0, C0;" << endl;
02129         testostr2 << "MOVE O1, C1;" << endl;
02130         testostr2 << "MOVE O2, C2;" << endl;
02131         string teststr2 = testostr2.str();
02132 
02133         CalcAssemblerTestCase testCase2(
02134             __LINE__, testdesc.c_str(), teststr2.c_str());
02135         if (testCase2.assemble()) {
02136             testCase2.setExpectedOutputMin(0);
02137             testCase2.setExpectedOutputMax(1);
02138             testCase2.setExpectedOutputNull(2);
02139             testCase2.test();
02140         }
02141 
02142         if (!StandardTypeDescriptor::isArray(type)) {
02143             // Now test literal binding for the type
02144             // For overflow and underflow
02145             ostringstream testostr3("");
02146             testostr3 << "O " << createRegisterString(typestr, 1)
02147                       << ";" << endl;
02148             testostr3 << "C " << createRegisterString(typestr, 1)
02149                       << ";" << endl;
02150             testostr3 << "V " << underflow[type] << ";" << endl;
02151             testostr3 << "T;" << endl;
02152             testostr3 << "MOVE O0, C0;" << endl;
02153 
02154             string teststr3 = testostr3.str();
02155 
02156             CalcAssemblerTestCase testCase3(
02157                 __LINE__, testdesc.c_str(), teststr3.c_str());
02158             if (type == STANDARD_TYPE_INT_64 || type == STANDARD_TYPE_DOUBLE) {
02159                 testCase3.expectAssemblerError("out of");
02160             } else if (underflow[type] == "-1") {
02161                 testCase3.expectAssemblerError("Invalid value");
02162             } else {
02163                 testCase3.expectAssemblerError(
02164                     "bad numeric");
02165             }
02166             testCase3.assemble();
02167 
02168             // For overflow and underflow
02169             ostringstream testostr4("");
02170             testostr4 << "O " << createRegisterString(typestr, 1)
02171                       << ";" << endl;
02172             testostr4 << "C " << createRegisterString(typestr, 1)
02173                       << ";" << endl;
02174             testostr4 << "V " << overflow[type] << ";" << endl;
02175             testostr4 << "T;" << endl;
02176             testostr4 << "MOVE O0, C0;" << endl;
02177 
02178             string teststr4 = testostr4.str();
02179 
02180             CalcAssemblerTestCase testCase4(
02181                 __LINE__, testdesc.c_str(),
02182                 teststr4.c_str());
02183             if (type == STANDARD_TYPE_UINT_64 || type == STANDARD_TYPE_DOUBLE) {
02184                 testCase4.expectAssemblerError("out of range");
02185             } else if (type == STANDARD_TYPE_BOOL) {
02186                 testCase4.expectAssemblerError("Invalid value");
02187             } else {
02188                 testCase4.expectAssemblerError(
02189                     "bad numeric");
02190             }
02191             testCase4.assemble();
02192         }
02193 
02194         testBoolInstructions(type);
02195 
02196         switch (type) {
02197         case STANDARD_TYPE_UINT_8:
02198             testNativeInstructions<uint8_t>(type);
02199             testIntegralNativeInstructions<uint8_t>(type);
02200             break;
02201 
02202         case STANDARD_TYPE_INT_8:
02203             testNativeInstructions<int8_t>(type);
02204             testIntegralNativeInstructions<int8_t>(type);
02205             break;
02206 
02207         case STANDARD_TYPE_UINT_16:
02208             testNativeInstructions<uint16_t>(type);
02209             testIntegralNativeInstructions<uint16_t>(type);
02210             break;
02211 
02212         case STANDARD_TYPE_INT_16:
02213             testNativeInstructions<int16_t>(type);
02214             testIntegralNativeInstructions<int16_t>(type);
02215             break;
02216 
02217         case STANDARD_TYPE_UINT_32:
02218             testNativeInstructions<uint32_t>(type);
02219             testIntegralNativeInstructions<uint32_t>(type);
02220             break;
02221 
02222         case STANDARD_TYPE_INT_32:
02223             testNativeInstructions<int32_t>(type);
02224             testIntegralNativeInstructions<int32_t>(type);
02225             break;
02226 
02227         case STANDARD_TYPE_UINT_64:
02228             testNativeInstructions<uint64_t>(type);
02229             testIntegralNativeInstructions<uint64_t>(type);
02230             break;
02231 
02232         case STANDARD_TYPE_INT_64:
02233             testNativeInstructions<int64_t>(type);
02234             testIntegralNativeInstructions<int64_t>(type);
02235             break;
02236 
02237         case STANDARD_TYPE_REAL:
02238             testNativeInstructions<float>(type);
02239             break;
02240 
02241         case STANDARD_TYPE_DOUBLE:
02242             testNativeInstructions<double>(type);
02243             break;
02244 
02245         default:
02246             break;
02247         }
02248     }
02249 }
02250 
02251 void CalcAssemblerTest::testLiteralBinding()
02252 {
02253     // Test invalid literals
02254     // Test overflow of u2
02255     CalcAssemblerTestCase testCase1(
02256         __LINE__, "OVERFLOW U2",
02257         "O u2; C u2; V 777777; T; ADD O0, C0, C0;");
02258     testCase1.expectAssemblerError(
02259         "bad numeric conversion");
02260     testCase1.assemble();
02261 
02262     // Test binding a float to a u2
02263     CalcAssemblerTestCase testCase2(
02264         __LINE__, "BADVALUE U2",
02265         "O u2; C u2; V 2451.342; T; ADD O0, C0, C0;");
02266     testCase2.expectAssemblerError("Invalid value");
02267     testCase2.assemble();
02268 
02269     // Test binding a float with exponentials
02270     CalcAssemblerTestCase testCase2b(
02271         __LINE__, "EXP",
02272         "O r, r; C r, r;\nV 24.0e-4, 54.0E6;\n"
02273         "T;\nMOVE O0, C0; MOVE O1, C1;");
02274     if (testCase2b.assemble()) {
02275         testCase2b.setExpectedOutput<float>(0, 0.0024);
02276         testCase2b.setExpectedOutput<float>(1, 54000000.0);
02277         testCase2b.test();
02278     }
02279 
02280     // Test binding a negative number to a u4
02281     CalcAssemblerTestCase testCase3(
02282         __LINE__, "NEGVALUE U4",
02283         "O u4; C u4; V -513; T; ADD O0, C0, C0;");
02284     testCase3.expectAssemblerError("Invalid value");
02285     testCase3.assemble();
02286 
02287     // Test binding a valid u2 that is out of range for a s2
02288     CalcAssemblerTestCase testCase4(
02289         __LINE__, "NEGVALUE U4",
02290         "O s2; C s2; V 40000; T; ADD O0, C0, C0;");
02291     testCase4.expectAssemblerError(
02292         "bad numeric conversion");
02293     testCase4.assemble();
02294 
02295     // Test invalid literal index
02296     CalcAssemblerTestCase testCase5(
02297         __LINE__, "BAD INDEX", "I s1; C s1; V 1, 2;");
02298     testCase5.expectAssemblerError("out of bounds");
02299     testCase5.assemble();
02300 
02301     CalcAssemblerTestCase testCase6(
02302         __LINE__, "LREG/VAL MISMATCH", "I bo; C s1, s4; V 1;");
02303     testCase6.expectAssemblerError("Error binding literal");
02304     testCase6.assemble();
02305 
02306     // Test Literal registers not specified
02307     CalcAssemblerTestCase testCase7(
02308         __LINE__, "LREG/VAL MISMATCH", "I s1, s4; V 1, 4; T; RETURN;");
02309     testCase7.expectAssemblerError("");
02310     testCase7.assemble();
02311 
02312     // Test binding a 2 to a boolean
02313     CalcAssemblerTestCase testCase8(__LINE__, "BOOL = 2", "I bo; C bo; V 2;");
02314     testCase8.expectAssemblerError("Invalid value");
02315     testCase8.assemble();
02316 
02317     // Test bind a string (char)
02318     string teststr9;
02319     teststr9 = "O c,4, u8; C c,4, u8; V 0x";
02320     teststr9 += stringToHex("test");
02321     teststr9 += ", 60000000; T; MOVE O0, C0; MOVE O1, C1;";
02322     CalcAssemblerTestCase testCase9(
02323         __LINE__, "STRING (CHAR) = \"test\"", teststr9.c_str());
02324     if (testCase9.assemble()) {
02325         testCase9.setExpectedOutput<const char>(0, "test", 4);
02326         testCase9.setExpectedOutput<uint64_t>(1, 60000000);
02327         testCase9.test();
02328     }
02329 
02330     // Test bind a string (varchar)
02331     string teststr10;
02332     teststr10 = "O vc,8; C vc,8; V 0x";
02333     teststr10 += stringToHex("short");
02334     teststr10 += "; T; MOVE O0, C0;";
02335     CalcAssemblerTestCase testCase10(
02336         __LINE__, "STRING (VARCHAR) = \"short\"", teststr10.c_str());
02337     if (testCase10.assemble()) {
02338         testCase10.setExpectedOutput<const char>(0, "short", 5);
02339         testCase10.test();
02340     }
02341 
02342     // Test bind a string (varchar) that's too long
02343     string teststr11;
02344     teststr11 = "O vc,8, u8; C vc,8, u8; V 0x";
02345     teststr11 += stringToHex("muchtoolongstring");
02346     teststr11 += "; T; MOVE O0, C0;";
02347 
02348     CalcAssemblerTestCase testCase11(
02349         __LINE__, "STRING (VARCHAR) TOO LONG", teststr11.c_str());
02350     testCase11.expectAssemblerError("too long");
02351     testCase11.assemble();
02352 
02353     // Test bind a binary string (binary) that's too short
02354     string teststr12;
02355     teststr12 = "O c,100, u8; C c,100, u8; V 0x";
02356     teststr12 += stringToHex("binarytooshort");
02357     teststr12 += ", 60000000; T; MOVE O0, C0; MOVE O1, C1;";
02358     CalcAssemblerTestCase testCase12(
02359         __LINE__, "STRING (BINARY) TOO SHORT", teststr12.c_str());
02360     testCase12.expectAssemblerError("not equal");
02361     testCase12.assemble();
02362 
02363     // Test bind a binary string (binary) of length 1
02364     string teststr13;
02365     teststr13 = "O b,1, vb,1; C b,1, vb,1; V 0xFF,0xFF;";
02366     teststr13 += "T; MOVE O0, C0; MOVE O1, C1;";
02367     CalcAssemblerTestCase testCase13(
02368         __LINE__, "STRING (BINARY) 1", teststr13.c_str());
02369     if (testCase13.assemble()) {
02370         uint8_t tmp = 0xFF;
02371         testCase13.setExpectedOutput<uint8_t>(0, &tmp, 1);
02372         testCase13.setExpectedOutput<uint8_t>(1, &tmp, 1);
02373         testCase13.test();
02374     }
02375 }
02376 
02377 void CalcAssemblerTest::testAdd()
02378 {
02379     CalcAssemblerTestCase testCase1(
02380         __LINE__, "ADD U4", "I u4, u4;\nO u4;\nT;\nADD O0, I0, I1;");
02381     if (testCase1.assemble()) {
02382         testCase1.setInput<uint32_t>(0, 100);
02383         testCase1.setInput<uint32_t>(1, 4030);
02384         testCase1.setExpectedOutput<uint32_t>(0, 4130);
02385         testCase1.test();
02386     }
02387 
02388     CalcAssemblerTestCase testCase2(
02389         __LINE__, "ADD UNKNOWN INST",
02390         "I u2, u4;\nO u4;\nT;\nADD O0, I0, I1;");
02391     testCase2.expectAssemblerError("not a registered instruction");
02392     testCase2.assemble();
02393 
02394     CalcAssemblerTestCase testCase3(
02395         __LINE__, "ADD O0 I0",
02396         "I u2, u4;\nO u4;\nT;\nADD O0, I0;");
02397     testCase3.expectAssemblerError("not a registered instruction");
02398     testCase3.assemble();
02399 
02400     CalcAssemblerTestCase testCase4(__LINE__, "ADD FLOAT", "I r, r;\nO r, r;\n"
02401                                     "C r, r;\nV 0.3, -2.3;\n"
02402                                     "T;\nADD O0, I0, C0;\nADD O1, I1, C1;");
02403     if (testCase4.assemble()) {
02404         testCase4.setInput<float>(0, 200);
02405         testCase4.setInput<float>(1, 3000);
02406         testCase4.setExpectedOutput<float>(0, 200+0.3);
02407         testCase4.setExpectedOutput<float>(1, 3000-2.3);
02408         testCase4.test();
02409     }
02410 }
02411 
02412 void CalcAssemblerTest::testBool()
02413 {
02414     CalcAssemblerTestCase testCase1(
02415         __LINE__, "AND 1 1",
02416         "O bo;\nC bo, bo;\nV 1, 1; T;\n"
02417         "AND O0, C0, C1;");
02418     if (testCase1.assemble()) {
02419         testCase1.setExpectedOutput<bool>(0, true);
02420         testCase1.test();
02421     }
02422 
02423     CalcAssemblerTestCase testCase2(
02424         __LINE__, "EQ 1 0",
02425         "O bo;\nC bo, bo;\nV 1, 0; T;\n"
02426         "EQ O0, C0, C1;");
02427     if (testCase2.assemble()) {
02428         testCase2.setExpectedOutput<bool>(0, false);
02429         testCase2.test();
02430     }
02431 }
02432 
02433 void CalcAssemblerTest::testPointer()
02434 {
02435     CalcAssemblerTestCase testCase1(
02436         __LINE__, "CHAR EQ",
02437         "I c,10, c,10;\nO bo, bo;\nT;\n"
02438         "EQ O0, I0, I1; EQ O1, I0, I0;");
02439     if (testCase1.assemble()) {
02440         testCase1.setInput<const char>(0, "test", 4);
02441         testCase1.setInput<const char>(1, "junk", 4);
02442         testCase1.setExpectedOutput<bool>(0, false);
02443         testCase1.setExpectedOutput<bool>(1, true);
02444         testCase1.test();
02445     }
02446 
02447     CalcAssemblerTestCase testCase2(
02448         __LINE__, "VARCHAR EQ/ADD",
02449         "I vc,255, vc,255;\n"
02450         "O bo, bo, vc,255, u4;\nC u4; V 10;T;\n"
02451         "EQ O0, I0, I1; EQ O1, I0, I0; ADD O2, I0, C0; GETS O3, I0;");
02452     if (testCase2.assemble()) {
02453         testCase2.setInput<const char>(
02454             0, "test varchar equal and add ....", 31);
02455         testCase2.setInput<const char>(1, "junk", 4);
02456         testCase2.setExpectedOutput<bool>(0, false);
02457         testCase2.setExpectedOutput<bool>(1, true);
02458         testCase2.setExpectedOutput<const char>(2, "ar equal and add ....", 21);
02459         testCase2.setExpectedOutput<uint32_t>(3, 31);
02460         testCase2.test();
02461     }
02462 }
02463 
02464 void CalcAssemblerTest::testJump()
02465 {
02466     // Test valid Jump True
02467     CalcAssemblerTestCase testCase1(
02468         __LINE__, "JUMP TRUE",
02469         "I u2, u2;\nO u2, u2;\nL bo;\n"
02470         "C u2, u2;\nV 0, 1;\nT;\n"
02471         "MOVE O0, C0;\nMOVE O1, C0;\n"
02472         "ADD O0, O0, I0;\nADD O1, O1, C1;\n"
02473         "LT L0, O1, I1;\nJMPT @2, L0;\n");
02474     if (testCase1.assemble()) {
02475         testCase1.setInput<uint16_t>(0, 3);
02476         testCase1.setInput<uint16_t>(1, 4);
02477         testCase1.setExpectedOutput<uint16_t>(0, 12);
02478         testCase1.setExpectedOutput<uint16_t>(1, 4);
02479         testCase1.test();
02480     }
02481 
02482     // Test Jumping to invalid PC
02483     CalcAssemblerTestCase testCase2(
02484         __LINE__, "INVALID PC", "I u2; O u2; T; JMP @10;");
02485     testCase2.expectAssemblerError("Invalid PC");
02486     testCase2.assemble();
02487 
02488     // Test Jump False a a valid PC that is later on in the program
02489     CalcAssemblerTestCase testCase3(
02490         __LINE__, "VALID PC",
02491         "I u2; O u2;\n"
02492         "C bo; V 0; T;\n"
02493         "MOVE O0, I0;\n"
02494         "JMPF @4, C0;\n"
02495         "ADD  O0, O0, I0;\n"
02496         "ADD  O0, O0, I0;\n"
02497         "ADD  O0, O0, I0;\n");
02498     if (testCase3.assemble()) {
02499         testCase3.setInput<uint16_t>(0, 15);
02500         testCase3.setExpectedOutput<uint16_t>(0, 30);
02501         testCase3.test();
02502     }
02503 }
02504 
02505 void CalcAssemblerTest::testReturn()
02506 {
02507     // Test the return instruction
02508     CalcAssemblerTestCase testCase1(
02509         __LINE__, "RETURN",
02510         "I u2;\nO u2;\n"
02511         "T;\n"
02512         "MOVE O0, I0;\n"
02513         "RETURN;\n"
02514         "ADD O0, I0, I0;\n");
02515     if (testCase1.assemble()) {
02516         testCase1.setInput<uint16_t>(0, 100);
02517         testCase1.setExpectedOutput<uint16_t>(0, 100);
02518         testCase1.test();
02519     }
02520 }
02521 
02522 void convertFloatToInt(
02523     RegisterRef<int>* regOut,
02524     RegisterRef<float>* regIn)
02525 {
02526     regOut->value((int)regIn->value());
02527 }
02528 
02529 void CalcAssemblerTest::testExtended()
02530 {
02531     // Test valid function
02532     ExtendedInstructionTable* table =
02533         InstructionFactory::getExtendedInstructionTable();
02534     assert(table != NULL);
02535 
02536     vector<StandardTypeDescriptorOrdinal> parameterTypes;
02537 
02538     // define a function
02539     parameterTypes.resize(2);
02540     parameterTypes[0] = STANDARD_TYPE_UINT_32;
02541     parameterTypes[1] = STANDARD_TYPE_REAL;
02542     table->add(
02543         "convert",
02544         parameterTypes,
02545         (ExtendedInstruction2<int32_t, float>*) NULL,
02546         &convertFloatToInt);
02547 
02548     // define test case
02549     CalcAssemblerTestCase testCase1(
02550         __LINE__, "CONVERT FLOAT TO INT",
02551         "I r; O u4;\n"
02552         "T;\n"
02553         "CALL 'convert(O0, I0);\n");
02554     if (testCase1.assemble()) {
02555         testCase1.setInput<float>(0, 53.34);
02556         testCase1.setExpectedOutput<uint32_t>(0, 53);
02557         testCase1.test();
02558     }
02559 
02560     CalcAssemblerTestCase testCase2(
02561         __LINE__, "CONVERT INT TO FLOAT (NOT REGISTERED)",
02562         "I u4; O r;\n"
02563         "T;\n"
02564         "CALL 'convert(O0, I0);\n");
02565     testCase2.expectAssemblerError("not registered");
02566     testCase2.assemble();
02567 }
02568 
02569 void CalcAssemblerTest::testInvalidPrograms()
02570 {
02571     const char* parse_error = "error";
02572 
02573     CalcAssemblerTestCase testCase1(__LINE__, "JUNK", "Junk");
02574     testCase1.expectAssemblerError(parse_error);
02575     testCase1.assemble();
02576 
02577     // Test unregistered instruction
02578     CalcAssemblerTestCase testCase2(
02579         __LINE__, "UNKNOWN INST", "I u2, u4;\nO u4;\nT;\nBAD O0, I0;");
02580     testCase2.expectAssemblerError("not a registered instruction");
02581     testCase2.assemble();
02582 
02583     // Test known instruction - but not registered for that type
02584     CalcAssemblerTestCase testCase3(
02585         __LINE__, "AND float", "I d, d;\nO d;\nT;\nAND O0, I0, I1;");
02586     testCase3.expectAssemblerError("not a registered instruction");
02587     testCase3.assemble();
02588 
02589     CalcAssemblerTestCase testCase4(
02590         __LINE__, "BAD SIGNATURE",
02591         "I u2, u4;\nO u4;\nT;\nBAD O0, I0, I0, I1;");
02592     testCase4.expectAssemblerError(parse_error);
02593     testCase4.assemble();
02594 
02595     CalcAssemblerTestCase testCase5(
02596         __LINE__, "BAD INST", "I u2, u4;\nO u4;\nT;\nklk34dfw;");
02597     testCase5.expectAssemblerError(parse_error);
02598     testCase5.assemble();
02599 
02600     // Test invalid register index
02601     CalcAssemblerTestCase testCase6(
02602         __LINE__, "BAD REG INDEX", "I u2, u4;\nO u4;\nT;\n\nADD O0, I0, I12;");
02603     testCase6.expectAssemblerError("out of bounds");
02604     testCase6.assemble();
02605 
02606     // Test invalid register index
02607     CalcAssemblerTestCase testCase7(
02608         __LINE__, "BAD REG INDEX",
02609         "I u2, u4;\nO u4;\nT;\n"
02610         "ADD O0, I0, I888888888888888888888888888888888888888888;");
02611     testCase7.expectAssemblerError("out of range");
02612     testCase7.assemble();
02613 
02614     // TODO: Test extremely long programs and stuff
02615 }
02616 
02617 void CalcAssemblerTest::testComments()
02618 {
02619     const char* parse_error = "error";
02620 
02621     CalcAssemblerTestCase testCase1(
02622         __LINE__, "COMMENTS (ONE LINE)",
02623         "I u2;\nO /* comments */ u2;\n"
02624         "T;\n"
02625         "MOVE O0, I0;\n"
02626         "RETURN;\n"
02627         "ADD O0, I0, I0;\n");
02628     if (testCase1.assemble()) {
02629         testCase1.setInput<uint16_t>(0, 100);
02630         testCase1.setExpectedOutput<uint16_t>(0, 100);
02631         testCase1.test();
02632     }
02633 
02634     CalcAssemblerTestCase testCase2(
02635         __LINE__, "COMMENTS (MULTILINE)",
02636         "I u2;\nO u2; /* *****\n*****/\n"
02637         "T;\n"
02638         "MOVE O0, I0;\n"
02639         "RETURN;\n"
02640         "ADD O0, I0, I0;\n");
02641     if (testCase2.assemble()) {
02642         testCase2.setInput<uint16_t>(0, 100);
02643         testCase2.setExpectedOutput<uint16_t>(0, 100);
02644         testCase2.test();
02645     }
02646 
02647     CalcAssemblerTestCase testCase3(
02648         __LINE__, "COMMENTS (MULTIPLE)",
02649         "I u2;\nO u2;\n"
02650         "T;\n"
02651         "MOVE O0, /* /* MOVE\n****\nO0 */ I0;\n"
02652         "RETURN;\n"
02653         "ADD /* FOR '0x' */ O0, I0, I0;\n");
02654     if (testCase3.assemble()) {
02655         testCase3.setInput<uint16_t>(0, 100);
02656         testCase3.setExpectedOutput<uint16_t>(0, 100);
02657         testCase3.test();
02658     }
02659 
02660     CalcAssemblerTestCase testCase4(
02661         __LINE__, "UNCLOSED COMMENT",
02662         "I u2;\nO u2;\n"
02663         "T;\n"
02664         "MOVE O0, /* I0;\n"
02665         "RETURN;\n"
02666         "ADD O0, I0, I0;\n");
02667     testCase4.expectAssemblerError("Unterminated comment");
02668     testCase4.assemble();
02669 
02670     CalcAssemblerTestCase testCase5(
02671         __LINE__, "CLOSE COMMENT ONLY",
02672         "I u2;\nO u2;\n"
02673         "T;\n"
02674         "MOVE O0, */ I0;\n"
02675         "RETURN;\n"
02676         "ADD O0, I0, I0;\n");
02677     // TODO: On RH9, the following works. On FC1, the result is:
02678     // "syntax error, unexpected UNKNOWN_TOKEN (at line:col 4:10 to
02679     // 4:10, characters 24 to 24)"
02680     testCase5.expectAssemblerError(parse_error);
02681     testCase5.assemble();
02682 }
02683 
02684 #if 0
02685 int main (int argc, char **argv)
02686 {
02687     ProgramName = argv[0];
02688     InstructionFactory inst();
02689     InstructionFactory::registerInstructions();
02690 
02691     try {
02692         CalcAssemblerTest test;
02693         test.testAssembler();
02694     } catch (exception& ex) {
02695         cerr << ex.what() << endl;
02696     }
02697 
02698     cout << CalcAssemblerTestCase::getPassedNumber() << "/"
02699          << CalcAssemblerTestCase::getTestNumber() << " tests passed" << endl;
02700     return CalcAssemblerTestCase::getFailedNumber();
02701 }
02702 
02703 #endif
02704 FENNEL_UNIT_TEST_SUITE(CalcAssemblerTest);
02705 
02706 // End CalcAssemblerTest.cpp

Generated on Mon Jun 22 04:00:13 2009 for Fennel by  doxygen 1.5.1