• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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