Unit Testing framework based on http://cpputest.github.io/

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SimpleString.cpp Source File

SimpleString.cpp

00001 /*
00002  * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *     * Redistributions of source code must retain the above copyright
00008  *       notice, this list of conditions and the following disclaimer.
00009  *     * Redistributions in binary form must reproduce the above copyright
00010  *       notice, this list of conditions and the following disclaimer in the
00011  *       documentation and/or other materials provided with the distribution.
00012  *     * Neither the name of the <organization> nor the
00013  *       names of its contributors may be used to endorse or promote products
00014  *       derived from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
00017  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
00020  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 #include "CppUTest/TestHarness.h"
00029 #include "CppUTest/SimpleString.h"
00030 #include "CppUTest/PlatformSpecificFunctions.h"
00031 #include "CppUTest/TestMemoryAllocator.h"
00032 
00033 
00034 TestMemoryAllocator* SimpleString::stringAllocator_ = NULL;
00035 
00036 TestMemoryAllocator* SimpleString::getStringAllocator()
00037 {
00038     if (stringAllocator_ == NULL)
00039         return defaultNewArrayAllocator();
00040     return stringAllocator_;
00041 }
00042 
00043 void SimpleString::setStringAllocator(TestMemoryAllocator* allocator)
00044 {
00045     stringAllocator_ = allocator;
00046 }
00047 
00048 /* Avoid using the memory leak detector INSIDE SimpleString as its used inside the detector */
00049 char* SimpleString::allocStringBuffer(size_t _size)
00050 {
00051     return getStringAllocator()->alloc_memory(_size, __FILE__, __LINE__);
00052 }
00053 
00054 void SimpleString::deallocStringBuffer(char* str)
00055 {
00056     getStringAllocator()->free_memory(str, __FILE__, __LINE__);
00057 }
00058 
00059 char* SimpleString::getEmptyString() const
00060 {
00061     char* empty = allocStringBuffer(1);
00062     empty[0] = '\0';
00063     return empty;
00064 }
00065 
00066 char* SimpleString::StrNCpy(char* s1, const char* s2, size_t n)
00067 {
00068     char* result = s1;
00069 
00070     if((NULL == s1) || (0 == n)) return result;
00071 
00072     while ((*s1++ = *s2++) && --n != 0)
00073         ;
00074     return result;
00075 }
00076 
00077 SimpleString::SimpleString(const char *otherBuffer)
00078 {
00079     if (otherBuffer == 0) {
00080         buffer_ = getEmptyString();
00081     }
00082     else {
00083         buffer_ = copyToNewBuffer(otherBuffer);
00084     }
00085 }
00086 
00087 SimpleString::SimpleString(const char *other, size_t repeatCount)
00088 {
00089     size_t otherStringLength = PlatformSpecificStrLen(other);
00090     size_t len = otherStringLength * repeatCount + 1;
00091     buffer_ = allocStringBuffer(len);
00092     char* next = buffer_;
00093     for (size_t i = 0; i < repeatCount; i++) {
00094         StrNCpy(next, other, otherStringLength + 1);
00095         next += otherStringLength;
00096     }
00097     *next = 0;
00098 }
00099 
00100 SimpleString::SimpleString(const SimpleString& other)
00101 {
00102     buffer_ = copyToNewBuffer(other.buffer_);
00103 }
00104 
00105 SimpleString& SimpleString::operator=(const SimpleString& other)
00106 {
00107     if (this != &other) {
00108         deallocStringBuffer(buffer_);
00109         buffer_ = copyToNewBuffer(other.buffer_);
00110     }
00111     return *this;
00112 }
00113 
00114 bool SimpleString::contains(const SimpleString& other) const
00115 {
00116     //strstr on some machines does not handle ""
00117     //the right way.  "" should be found in any string
00118     if (PlatformSpecificStrLen(other.buffer_) == 0) return true;
00119     else if (PlatformSpecificStrLen(buffer_) == 0) return false;
00120     else return PlatformSpecificStrStr(buffer_, other.buffer_) != 0;
00121 }
00122 
00123 bool SimpleString::containsNoCase(const SimpleString& other) const
00124 {
00125     return toLower().contains(other.toLower());
00126 }
00127 
00128 
00129 bool SimpleString::startsWith(const SimpleString& other) const
00130 {
00131     if (PlatformSpecificStrLen(other.buffer_) == 0) return true;
00132     else if (PlatformSpecificStrLen(buffer_) == 0) return false;
00133     else return PlatformSpecificStrStr(buffer_, other.buffer_) == buffer_;
00134 }
00135 
00136 bool SimpleString::endsWith(const SimpleString& other) const
00137 {
00138     size_t buffer_length = PlatformSpecificStrLen(buffer_);
00139     size_t other_buffer_length = PlatformSpecificStrLen(other.buffer_);
00140     if (other_buffer_length == 0) return true;
00141     if (buffer_length == 0) return false;
00142     if (buffer_length < other_buffer_length) return false;
00143     return PlatformSpecificStrCmp(buffer_ + buffer_length - other_buffer_length, other.buffer_) == 0;
00144 }
00145 
00146 size_t SimpleString::count(const SimpleString& substr) const
00147 {
00148     size_t num = 0;
00149     char* str = buffer_;
00150     while ((str = PlatformSpecificStrStr(str, substr.buffer_))) {
00151         num++;
00152         str++;
00153     }
00154     return num;
00155 }
00156 
00157 void SimpleString::split(const SimpleString& delimiter, SimpleStringCollection& col) const
00158 {
00159     size_t num = count(delimiter);
00160     size_t extraEndToken = (endsWith(delimiter)) ? 0 : 1U;
00161     col.allocate(num + extraEndToken);
00162 
00163     char* str = buffer_;
00164     char* prev;
00165     for (size_t i = 0; i < num; ++i) {
00166         prev = str;
00167         str = PlatformSpecificStrStr(str, delimiter.buffer_) + 1;
00168         size_t len = (size_t) (str - prev) + 1;
00169         col[i].buffer_ = copyToNewBuffer(prev, len);
00170     }
00171     if (extraEndToken) {
00172         col[num] = str;
00173     }
00174 }
00175 
00176 void SimpleString::replace(char to, char with)
00177 {
00178     size_t s = size();
00179     for (size_t i = 0; i < s; i++) {
00180         if (buffer_[i] == to) buffer_[i] = with;
00181     }
00182 }
00183 
00184 void SimpleString::replace(const char* to, const char* with)
00185 {
00186     size_t c = count(to);
00187     size_t len = size();
00188     size_t tolen = PlatformSpecificStrLen(to);
00189     size_t withlen = PlatformSpecificStrLen(with);
00190 
00191     size_t newsize = len + (withlen * c) - (tolen * c) + 1;
00192 
00193     if (newsize) {
00194         char* newbuf = allocStringBuffer(newsize);
00195         for (size_t i = 0, j = 0; i < len;) {
00196             if (PlatformSpecificStrNCmp(&buffer_[i], to, tolen) == 0) {
00197                 StrNCpy(&newbuf[j], with, withlen + 1);
00198                 j += withlen;
00199                 i += tolen;
00200             }
00201             else {
00202                 newbuf[j] = buffer_[i];
00203                 j++;
00204                 i++;
00205             }
00206         }
00207         deallocStringBuffer(buffer_);
00208         buffer_ = newbuf;
00209         buffer_[newsize - 1] = '\0';
00210     }
00211     else {
00212         buffer_ = getEmptyString();
00213         buffer_[0] = '\0';
00214     }
00215 }
00216 
00217 SimpleString SimpleString::toLower() const
00218 {
00219     SimpleString str(*this);
00220 
00221     size_t str_size = str.size();
00222     for (size_t i = 0; i < str_size; i++)
00223         str.buffer_[i] = PlatformSpecificToLower(str.buffer_[i]);
00224 
00225     return str;
00226 }
00227 
00228 const char *SimpleString::asCharString() const
00229 {
00230     return buffer_;
00231 }
00232 
00233 size_t SimpleString::size() const
00234 {
00235     return PlatformSpecificStrLen(buffer_);
00236 }
00237 
00238 bool SimpleString::isEmpty() const
00239 {
00240     return size() == 0;
00241 }
00242 
00243 
00244 
00245 SimpleString::~SimpleString()
00246 {
00247     deallocStringBuffer(buffer_);
00248 }
00249 
00250 bool operator==(const SimpleString& left, const SimpleString& right)
00251 {
00252     return 0 == PlatformSpecificStrCmp(left.asCharString(), right.asCharString());
00253 }
00254 
00255 bool SimpleString::equalsNoCase(const SimpleString& str) const
00256 {
00257     return toLower() == str.toLower();
00258 }
00259 
00260 
00261 bool operator!=(const SimpleString& left, const SimpleString& right)
00262 {
00263     return !(left == right);
00264 }
00265 
00266 SimpleString SimpleString::operator+(const SimpleString& rhs)
00267 {
00268     SimpleString t(buffer_);
00269     t += rhs.buffer_;
00270     return t;
00271 }
00272 
00273 SimpleString& SimpleString::operator+=(const SimpleString& rhs)
00274 {
00275     return operator+=(rhs.buffer_);
00276 }
00277 
00278 SimpleString& SimpleString::operator+=(const char* rhs)
00279 {
00280     size_t originalSize = this->size();
00281     size_t additionalStringSize = PlatformSpecificStrLen(rhs) + 1;
00282     size_t sizeOfNewString = originalSize + additionalStringSize;
00283     char* tbuffer = copyToNewBuffer(this->buffer_, sizeOfNewString);
00284     StrNCpy(tbuffer + originalSize, rhs, additionalStringSize);
00285     deallocStringBuffer(this->buffer_);
00286     this->buffer_ = tbuffer;
00287     return *this;
00288 }
00289 
00290 void SimpleString::padStringsToSameLength(SimpleString& str1, SimpleString& str2, char padCharacter)
00291 {
00292     if (str1.size() > str2.size()) {
00293         padStringsToSameLength(str2, str1, padCharacter);
00294         return;
00295     }
00296 
00297     char pad[2];
00298     pad[0] = padCharacter;
00299     pad[1] = 0;
00300     str1 = SimpleString(pad, str2.size() - str1.size()) + str1;
00301 }
00302 
00303 SimpleString SimpleString::subString(size_t beginPos, size_t amount) const
00304 {
00305     if (beginPos > size()-1) return "";
00306 
00307     SimpleString newString = buffer_ + beginPos;
00308 
00309     if (newString.size() > amount)
00310         newString.buffer_[amount] = '\0';
00311 
00312     return newString;
00313 }
00314 
00315 char SimpleString::at(int pos) const
00316 {
00317     return buffer_[pos];
00318 }
00319 
00320 int SimpleString::find(char ch) const
00321 {
00322     return findFrom(0, ch);
00323 }
00324 
00325 int SimpleString::findFrom(size_t starting_position, char ch) const
00326 {
00327     size_t length = size();
00328     for (size_t i = starting_position; i < length; i++)
00329         if (buffer_[i] == ch) return (int) i;
00330     return -1;
00331 }
00332 
00333 SimpleString SimpleString::subStringFromTill(char startChar, char lastExcludedChar) const
00334 {
00335     int beginPos = find(startChar);
00336     if (beginPos < 0) return "";
00337 
00338     int endPos = findFrom((size_t)beginPos, lastExcludedChar);
00339     if (endPos == -1) return subString((size_t)beginPos, size());
00340 
00341     return subString((size_t)beginPos, (size_t) (endPos - beginPos));
00342 }
00343 
00344 char* SimpleString::copyToNewBuffer(const char* bufferToCopy, size_t bufferSize)
00345 {
00346     if(bufferSize == 0) bufferSize = PlatformSpecificStrLen(bufferToCopy) + 1;
00347 
00348     char* newBuffer = allocStringBuffer(bufferSize);
00349     StrNCpy(newBuffer, bufferToCopy, bufferSize);
00350     newBuffer[bufferSize-1] = '\0';
00351     return newBuffer;
00352 }
00353 
00354 void SimpleString::copyToBuffer(char* bufferToCopy, size_t bufferSize) const
00355 {
00356     if (bufferToCopy == NULL || bufferSize == 0) return;
00357 
00358     size_t sizeToCopy = (bufferSize-1 < size()) ? bufferSize : size();
00359 
00360     StrNCpy(bufferToCopy, buffer_, sizeToCopy);
00361     bufferToCopy[sizeToCopy] = '\0';
00362 }
00363 
00364 SimpleString StringFrom(bool value)
00365 {
00366     return SimpleString(StringFromFormat("%s", value ? "true" : "false"));
00367 }
00368 
00369 SimpleString StringFrom(const char *value)
00370 {
00371     return SimpleString(value);
00372 }
00373 
00374 SimpleString StringFromOrNull(const char * expected)
00375 {
00376     return (expected) ? StringFrom(expected) : "(null)";
00377 }
00378 
00379 SimpleString StringFrom(int value)
00380 {
00381     return StringFromFormat("%d", value);
00382 }
00383 
00384 SimpleString StringFrom(long value)
00385 {
00386     return StringFromFormat("%ld", value);
00387 }
00388 
00389 SimpleString StringFrom(const void* value)
00390 {
00391     return SimpleString("0x") + HexStringFrom(value);
00392 }
00393 
00394 SimpleString HexStringFrom(long value)
00395 {
00396     return StringFromFormat("%lx", value);
00397 }
00398 
00399 SimpleString HexStringFrom(unsigned long value)
00400 {
00401     return StringFromFormat("%lx", value);
00402 }
00403 
00404 static long convertPointerToLongValue(const void* value)
00405 {
00406     /*
00407      * This way of converting also can convert a 64bit pointer in a 32bit integer by truncating.
00408      * This isn't the right way to convert pointers values and need to change by implementing a
00409      * proper portable way to convert pointers to strings.
00410      */
00411     long* long_value = (long*) &value;
00412     return *long_value;
00413 }
00414 
00415 SimpleString HexStringFrom(const void* value)
00416 {
00417     return StringFromFormat("%lx", convertPointerToLongValue(value));
00418 }
00419 
00420 SimpleString StringFrom(double value, int precision)
00421 {
00422     return StringFromFormat("%.*g", precision, value);
00423 }
00424 
00425 SimpleString StringFrom(char value)
00426 {
00427     return StringFromFormat("%c", value);
00428 }
00429 
00430 SimpleString StringFrom(const SimpleString& value)
00431 {
00432     return SimpleString(value);
00433 }
00434 
00435 SimpleString StringFromFormat(const char* format, ...)
00436 {
00437     SimpleString resultString;
00438     va_list arguments;
00439     va_start(arguments, format);
00440 
00441     resultString = VStringFromFormat(format, arguments);
00442     va_end(arguments);
00443     return resultString;
00444 }
00445 
00446 SimpleString StringFrom(unsigned int i)
00447 {
00448     return StringFromFormat("%10u (0x%08x)", i, i);
00449 }
00450 
00451 #if CPPUTEST_USE_STD_CPP_LIB
00452 
00453 #include <string>
00454 
00455 SimpleString StringFrom(const std::string& value)
00456 {
00457     return SimpleString(value.c_str());
00458 }
00459 
00460 SimpleString StringFrom(unsigned long i)
00461 {
00462     return StringFromFormat("%lu (0x%lx)", i, i);
00463 }
00464 
00465 #else
00466 
00467 SimpleString StringFrom(unsigned long value)
00468 {
00469     return StringFromFormat("%lu", value);
00470 }
00471 
00472 #endif
00473 
00474 //Kludge to get a va_copy in VC++ V6
00475 #ifndef va_copy
00476 #define va_copy(copy, original) copy = original;
00477 #endif
00478 
00479 SimpleString VStringFromFormat(const char* format, va_list args)
00480 {
00481     va_list argsCopy;
00482     va_copy(argsCopy, args);
00483     enum
00484     {
00485         sizeOfdefaultBuffer = 100
00486     };
00487     char defaultBuffer[sizeOfdefaultBuffer];
00488     SimpleString resultString;
00489 
00490     size_t size = (size_t)PlatformSpecificVSNprintf(defaultBuffer, sizeOfdefaultBuffer, format, args);
00491     if (size < sizeOfdefaultBuffer) {
00492         resultString = SimpleString(defaultBuffer);
00493     }
00494     else {
00495         size_t newBufferSize = size + 1;
00496         char* newBuffer = SimpleString::allocStringBuffer(newBufferSize);
00497         PlatformSpecificVSNprintf(newBuffer, newBufferSize, format, argsCopy);
00498         resultString = SimpleString(newBuffer);
00499 
00500         SimpleString::deallocStringBuffer(newBuffer);
00501     }
00502     va_end(argsCopy);
00503     return resultString;
00504 }
00505 
00506 SimpleStringCollection::SimpleStringCollection()
00507 {
00508     collection_ = 0;
00509     size_ = 0;
00510 }
00511 
00512 void SimpleStringCollection::allocate(size_t _size)
00513 {
00514     delete[] collection_;
00515 
00516     size_ = _size;
00517     collection_ = new SimpleString[size_];
00518 }
00519 
00520 SimpleStringCollection::~SimpleStringCollection()
00521 {
00522     delete[] (collection_);
00523 }
00524 
00525 size_t SimpleStringCollection::size() const
00526 {
00527     return size_;
00528 }
00529 
00530 SimpleString& SimpleStringCollection::operator[](size_t index)
00531 {
00532     if (index >= size_) {
00533         empty_ = "";
00534         return empty_;
00535     }
00536 
00537     return collection_[index];
00538 }