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
16 class CopyOnWriteForTesting : public SharedObject {
17 public:
CopyOnWriteForTesting()18 CopyOnWriteForTesting() : SharedObject(), localeNamePtr(), formatStrPtr(), length(0) {
19 }
20
CopyOnWriteForTesting(const CopyOnWriteForTesting & other)21 CopyOnWriteForTesting(const CopyOnWriteForTesting &other) :
22 SharedObject(other),
23 localeNamePtr(other.localeNamePtr),
24 formatStrPtr(other.formatStrPtr),
25 length(other.length) {
26 }
27
~CopyOnWriteForTesting()28 virtual ~CopyOnWriteForTesting() {
29 }
30
31 SharedPtr<UnicodeString> localeNamePtr;
32 SharedPtr<UnicodeString> formatStrPtr;
33 int32_t length;
34 private:
35 CopyOnWriteForTesting &operator=(const CopyOnWriteForTesting &rhs);
36 };
37
38 class LRUCacheForTesting : public LRUCache {
39 public:
40 LRUCacheForTesting(
41 int32_t maxSize,
42 const UnicodeString &dfs, UErrorCode &status);
~LRUCacheForTesting()43 virtual ~LRUCacheForTesting() {
44 }
45 protected:
46 virtual SharedObject *create(const char *localeId, UErrorCode &status);
47 private:
48 SharedPtr<UnicodeString> defaultFormatStr;
49 };
50
LRUCacheForTesting(int32_t maxSize,const UnicodeString & dfs,UErrorCode & status)51 LRUCacheForTesting::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
create(const char * localeId,UErrorCode & status)61 SharedObject *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
73 class LRUCacheTest : public IntlTest {
74 public:
LRUCacheTest()75 LRUCacheTest() {
76 }
77 void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
78 private:
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
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)94 void 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
TestSharedPointer()103 void 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
TestErrorCallingConstructor()130 void LRUCacheTest::TestErrorCallingConstructor() {
131 UErrorCode status = U_MEMORY_ALLOCATION_ERROR;
132 LRUCacheForTesting cache(3, "little", status);
133 }
134
TestLRUCache()135 void 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
TestLRUCacheError()233 void 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
verifySharedPointer(const CopyOnWriteForTesting * ptr,const UnicodeString & name,const UnicodeString & format)243 void 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
verifyString(const UnicodeString & expected,const UnicodeString & actual)253 void LRUCacheTest::verifyString(const UnicodeString &expected, const UnicodeString &actual) {
254 if (expected != actual) {
255 errln(UnicodeString("Expected '") + expected + "', got '"+ actual+"'");
256 }
257 }
258
verifyReferences(const CopyOnWriteForTesting * ptr,int32_t count,int32_t nameCount,int32_t formatCount)259 void 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
createLRUCacheTest()274 extern IntlTest *createLRUCacheTest() {
275 return new LRUCacheTest();
276 }
277