1/* 2******************************************************************************* 3* Copyright (C) 2014, International Business Machines Corporation and * 4* others. All Rights Reserved. * 5******************************************************************************* 6* 7* File LRUCACHETEST.CPP 8* 9******************************************************************************** 10*/ 11#include "cstring.h" 12#include "intltest.h" 13#include "lrucache.h" 14#include "sharedptr.h" 15 16class CopyOnWriteForTesting : public SharedObject { 17public: 18 CopyOnWriteForTesting() : SharedObject(), localeNamePtr(), formatStrPtr(), length(0) { 19 } 20 21 CopyOnWriteForTesting(const CopyOnWriteForTesting &other) : 22 SharedObject(other), 23 localeNamePtr(other.localeNamePtr), 24 formatStrPtr(other.formatStrPtr), 25 length(other.length) { 26 } 27 28 virtual ~CopyOnWriteForTesting() { 29 } 30 31 SharedPtr<UnicodeString> localeNamePtr; 32 SharedPtr<UnicodeString> formatStrPtr; 33 int32_t length; 34private: 35 CopyOnWriteForTesting &operator=(const CopyOnWriteForTesting &rhs); 36}; 37 38class LRUCacheForTesting : public LRUCache { 39public: 40 LRUCacheForTesting( 41 int32_t maxSize, 42 const UnicodeString &dfs, UErrorCode &status); 43 virtual ~LRUCacheForTesting() { 44 } 45protected: 46 virtual SharedObject *create(const char *localeId, UErrorCode &status); 47private: 48 SharedPtr<UnicodeString> defaultFormatStr; 49}; 50 51LRUCacheForTesting::LRUCacheForTesting( 52 int32_t maxSize, 53 const UnicodeString &dfs, UErrorCode &status) : 54 LRUCache(maxSize, status), defaultFormatStr() { 55 if (U_FAILURE(status)) { 56 return; 57 } 58 defaultFormatStr.reset(new UnicodeString(dfs)); 59} 60 61SharedObject *LRUCacheForTesting::create(const char *localeId, UErrorCode &status) { 62 if (uprv_strcmp(localeId, "error") == 0) { 63 status = U_ILLEGAL_ARGUMENT_ERROR; 64 return NULL; 65 } 66 CopyOnWriteForTesting *result = new CopyOnWriteForTesting; 67 result->localeNamePtr.reset(new UnicodeString(localeId)); 68 result->formatStrPtr = defaultFormatStr; 69 result->length = 5; 70 return result; 71} 72 73class LRUCacheTest : public IntlTest { 74public: 75 LRUCacheTest() { 76 } 77 void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0); 78private: 79 void TestSharedPointer(); 80 void TestErrorCallingConstructor(); 81 void TestLRUCache(); 82 void TestLRUCacheError(); 83 void verifySharedPointer( 84 const CopyOnWriteForTesting* ptr, 85 const UnicodeString& name, 86 const UnicodeString& format); 87 void verifyString( 88 const UnicodeString &expected, const UnicodeString &actual); 89 void verifyReferences( 90 const CopyOnWriteForTesting* ptr, 91 int32_t count, int32_t nameCount, int32_t formatCount); 92}; 93 94void LRUCacheTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) { 95 TESTCASE_AUTO_BEGIN; 96 TESTCASE_AUTO(TestSharedPointer); 97 TESTCASE_AUTO(TestErrorCallingConstructor); 98 TESTCASE_AUTO(TestLRUCache); 99 TESTCASE_AUTO(TestLRUCacheError); 100 TESTCASE_AUTO_END; 101} 102 103void LRUCacheTest::TestSharedPointer() { 104 UErrorCode status = U_ZERO_ERROR; 105 LRUCacheForTesting cache(3, "little", status); 106 const CopyOnWriteForTesting* ptr = NULL; 107 cache.get("boo", ptr, status); 108 verifySharedPointer(ptr, "boo", "little"); 109 const CopyOnWriteForTesting* ptrCopy = ptr; 110 ptrCopy->addRef(); 111 { 112 const CopyOnWriteForTesting* ptrCopy2(ptrCopy); 113 ptrCopy2->addRef(); 114 verifyReferences(ptr, 4, 1, 2); 115 ptrCopy2->removeRef(); 116 } 117 118 verifyReferences(ptr, 3, 1, 2); 119 CopyOnWriteForTesting *wPtrCopy = SharedObject::copyOnWrite(ptrCopy); 120 *wPtrCopy->localeNamePtr.readWrite() = UnicodeString("hi there"); 121 *wPtrCopy->formatStrPtr.readWrite() = UnicodeString("see you"); 122 verifyReferences(ptr, 2, 1, 2); 123 verifyReferences(ptrCopy, 1, 1, 1); 124 verifySharedPointer(ptr, "boo", "little"); 125 verifySharedPointer(ptrCopy, "hi there", "see you"); 126 ptrCopy->removeRef(); 127 ptr->removeRef(); 128} 129 130void LRUCacheTest::TestErrorCallingConstructor() { 131 UErrorCode status = U_MEMORY_ALLOCATION_ERROR; 132 LRUCacheForTesting cache(3, "little", status); 133} 134 135void LRUCacheTest::TestLRUCache() { 136 UErrorCode status = U_ZERO_ERROR; 137 LRUCacheForTesting cache(3, "little", status); 138 const CopyOnWriteForTesting* ptr1 = NULL; 139 const CopyOnWriteForTesting* ptr2 = NULL; 140 const CopyOnWriteForTesting* ptr3 = NULL; 141 const CopyOnWriteForTesting* ptr4 = NULL; 142 const CopyOnWriteForTesting* ptr5 = NULL; 143 cache.get("foo", ptr1, status); 144 cache.get("bar", ptr2, status); 145 cache.get("baz", ptr3, status); 146 verifySharedPointer(ptr1, "foo", "little"); 147 verifySharedPointer(ptr2, "bar", "little"); 148 verifySharedPointer(ptr3, "baz", "little"); 149 150 // Cache holds a reference to returned data which explains the 2s 151 // Note the '4'. each cached data has a reference to "little" and the 152 // cache itself also has a reference to "little" 153 verifyReferences(ptr1, 2, 1, 4); 154 verifyReferences(ptr2, 2, 1, 4); 155 verifyReferences(ptr3, 2, 1, 4); 156 157 // (Most recent) "baz", "bar", "foo" (Least Recent) 158 // Cache is now full but thanks to shared pointers we can still evict. 159 cache.get("full", ptr4, status); 160 verifySharedPointer(ptr4, "full", "little"); 161 162 verifyReferences(ptr4, 2, 1, 5); 163 164 // (Most Recent) "full" "baz", "bar" (Least Recent) 165 cache.get("baz", ptr5, status); 166 verifySharedPointer(ptr5, "baz", "little"); 167 // ptr5, ptr3, and cache have baz data 168 verifyReferences(ptr5, 3, 1, 5); 169 170 // This should delete foo data since it got evicted from cache. 171 ptr1->removeRef(); 172 ptr1 = NULL; 173 // Reference count for little drops to 4 because foo data was deleted. 174 verifyReferences(ptr5, 3, 1, 4); 175 176 // (Most Recent) "baz" "full" "bar" (Least Recent) 177 cache.get("baz", ptr5, status); 178 verifySharedPointer(ptr5, "baz", "little"); 179 verifyReferences(ptr5, 3, 1, 4); 180 181 // (Most Recent) "baz", "full", "bar" (Least Recent) 182 // ptr3, ptr5 -> "baz" ptr4 -> "full" ptr2 -> "bar" 183 if (!cache.contains("baz") || !cache.contains("full") || !cache.contains("bar") || cache.contains("foo")) { 184 errln("Unexpected keys in cache."); 185 } 186 cache.get("new1", ptr5, status); 187 verifySharedPointer(ptr5, "new1", "little"); 188 verifyReferences(ptr5, 2, 1, 5); 189 190 // Since bar was evicted, clearing its pointer should delete its data. 191 // Notice that the reference count to 'little' dropped from 5 to 4. 192 ptr2->removeRef(); 193 ptr2 = NULL; 194 verifyReferences(ptr5, 2, 1, 4); 195 if (cache.contains("bar") || !cache.contains("full")) { 196 errln("Unexpected 'bar' in cache."); 197 } 198 199 // (Most Recent) "new1", "baz", "full" (Least Recent) 200 // ptr3 -> "baz" ptr4 -> "full" ptr5 -> "new1" 201 cache.get("new2", ptr5, status); 202 verifySharedPointer(ptr5, "new2", "little"); 203 verifyReferences(ptr5, 2, 1, 5); 204 205 // since "full" was evicted, clearing its pointer should delete its data. 206 ptr4->removeRef(); 207 ptr4 = NULL; 208 verifyReferences(ptr5, 2, 1, 4); 209 if (cache.contains("full") || !cache.contains("baz")) { 210 errln("Unexpected 'full' in cache."); 211 } 212 213 // (Most Recent) "new2", "new1", "baz" (Least Recent) 214 // ptr3 -> "baz" ptr5 -> "new2" 215 cache.get("new3", ptr5, status); 216 verifySharedPointer(ptr5, "new3", "little"); 217 verifyReferences(ptr5, 2, 1, 5); 218 219 // since "baz" was evicted, clearing its pointer should delete its data. 220 ptr3->removeRef(); 221 ptr3 = NULL; 222 verifyReferences(ptr5, 2, 1, 4); 223 if (cache.contains("baz") || !cache.contains("new3")) { 224 errln("Unexpected 'baz' in cache."); 225 } 226 SharedObject::clearPtr(ptr1); 227 SharedObject::clearPtr(ptr2); 228 SharedObject::clearPtr(ptr3); 229 SharedObject::clearPtr(ptr4); 230 SharedObject::clearPtr(ptr5); 231} 232 233void LRUCacheTest::TestLRUCacheError() { 234 UErrorCode status = U_ZERO_ERROR; 235 LRUCacheForTesting cache(3, "little", status); 236 const CopyOnWriteForTesting *ptr1; 237 cache.get("error", ptr1, status); 238 if (status != U_ILLEGAL_ARGUMENT_ERROR) { 239 errln("Expected an error."); 240 } 241} 242 243void LRUCacheTest::verifySharedPointer( 244 const CopyOnWriteForTesting* ptr, 245 const UnicodeString& name, 246 const UnicodeString& format) { 247 const UnicodeString *strPtr = ptr->localeNamePtr.readOnly(); 248 verifyString(name, *strPtr); 249 strPtr = ptr->formatStrPtr.readOnly(); 250 verifyString(format, *strPtr); 251} 252 253void LRUCacheTest::verifyString(const UnicodeString &expected, const UnicodeString &actual) { 254 if (expected != actual) { 255 errln(UnicodeString("Expected '") + expected + "', got '"+ actual+"'"); 256 } 257} 258 259void LRUCacheTest::verifyReferences(const CopyOnWriteForTesting* ptr, int32_t count, int32_t nameCount, int32_t formatCount) { 260 int32_t actual = ptr->getRefCount(); 261 if (count != actual) { 262 errln("Main reference count wrong: Expected %d, got %d", count, actual); 263 } 264 actual = ptr->localeNamePtr.count(); 265 if (nameCount != actual) { 266 errln("name reference count wrong: Expected %d, got %d", nameCount, actual); 267 } 268 actual = ptr->formatStrPtr.count(); 269 if (formatCount != actual) { 270 errln("format reference count wrong: Expected %d, got %d", formatCount, actual); 271 } 272} 273 274extern IntlTest *createLRUCacheTest() { 275 return new LRUCacheTest(); 276} 277