1/*
2*******************************************************************************
3* Copyright (C) 2014, International Business Machines Corporation and         *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7* File UNIFIEDCACHETEST.CPP
8*
9********************************************************************************
10*/
11#include "cstring.h"
12#include "intltest.h"
13#include "unifiedcache.h"
14
15class UCTItem : public SharedObject {
16  public:
17    char *value;
18    UCTItem(const char *x) : value(NULL) {
19        value = uprv_strdup(x);
20    }
21    virtual ~UCTItem() {
22        uprv_free(value);
23    }
24};
25
26class UCTItem2 : public SharedObject {
27};
28
29U_NAMESPACE_BEGIN
30
31template<> U_EXPORT
32const UCTItem *LocaleCacheKey<UCTItem>::createObject(
33        const void * /*unused*/, UErrorCode &status) const {
34    if (uprv_strcmp(fLoc.getName(), "zh") == 0) {
35        status = U_MISSING_RESOURCE_ERROR;
36        return NULL;
37    }
38    if (uprv_strcmp(fLoc.getLanguage(), fLoc.getName()) != 0) {
39        const UCTItem *item = NULL;
40        UnifiedCache::getByLocale(fLoc.getLanguage(), item, status);
41        if (U_FAILURE(status)) {
42            return NULL;
43        }
44        return item;
45    }
46    UCTItem *result = new UCTItem(fLoc.getName());
47    result->addRef();
48    return result;
49}
50
51template<> U_EXPORT
52const UCTItem2 *LocaleCacheKey<UCTItem2>::createObject(
53        const void * /*unused*/, UErrorCode & /*status*/) const {
54    return NULL;
55}
56
57U_NAMESPACE_END
58
59
60class UnifiedCacheTest : public IntlTest {
61public:
62    UnifiedCacheTest() {
63    }
64    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
65private:
66    void TestBasic();
67    void TestError();
68    void TestHashEquals();
69};
70
71void UnifiedCacheTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
72  TESTCASE_AUTO_BEGIN;
73  TESTCASE_AUTO(TestBasic);
74  TESTCASE_AUTO(TestError);
75  TESTCASE_AUTO(TestHashEquals);
76  TESTCASE_AUTO_END;
77}
78
79void UnifiedCacheTest::TestBasic() {
80    UErrorCode status = U_ZERO_ERROR;
81    const UnifiedCache *cache = UnifiedCache::getInstance(status);
82    assertSuccess("", status);
83    cache->flush();
84    int32_t baseCount = cache->keyCount();
85    const UCTItem *en = NULL;
86    const UCTItem *enGb = NULL;
87    const UCTItem *enGb2 = NULL;
88    const UCTItem *enUs = NULL;
89    const UCTItem *fr = NULL;
90    const UCTItem *frFr = NULL;
91    cache->get(LocaleCacheKey<UCTItem>("en"), en, status);
92    cache->get(LocaleCacheKey<UCTItem>("en_US"), enUs, status);
93    cache->get(LocaleCacheKey<UCTItem>("en_GB"), enGb, status);
94    cache->get(LocaleCacheKey<UCTItem>("fr_FR"), frFr, status);
95    cache->get(LocaleCacheKey<UCTItem>("fr"), fr, status);
96    cache->get(LocaleCacheKey<UCTItem>("en_GB"), enGb2, status);
97    SharedObject::clearPtr(enGb2);
98    if (enGb != enUs) {
99        errln("Expected en_GB and en_US to resolve to same object.");
100    }
101    if (fr != frFr) {
102        errln("Expected fr and fr_FR to resolve to same object.");
103    }
104    if (enGb == fr) {
105        errln("Expected en_GB and fr to return different objects.");
106    }
107    assertSuccess("", status);
108    // en_US, en_GB, en share one object; fr_FR and fr don't share.
109    // 5 keys in all.
110    assertEquals("", baseCount + 5, cache->keyCount());
111    SharedObject::clearPtr(enGb);
112    cache->flush();
113    assertEquals("", baseCount + 5, cache->keyCount());
114    SharedObject::clearPtr(enUs);
115    SharedObject::clearPtr(en);
116    cache->flush();
117    // With en_GB and en_US and en cleared there are no more hard references to
118    // the "en" object, so it gets flushed and the keys that refer to it
119    // get removed from the cache.
120    assertEquals("", baseCount + 2, cache->keyCount());
121    SharedObject::clearPtr(fr);
122    cache->flush();
123    assertEquals("", baseCount + 2, cache->keyCount());
124    SharedObject::clearPtr(frFr);
125    cache->flush();
126    assertEquals("", baseCount + 0, cache->keyCount());
127}
128
129void UnifiedCacheTest::TestError() {
130    UErrorCode status = U_ZERO_ERROR;
131    const UnifiedCache *cache = UnifiedCache::getInstance(status);
132    assertSuccess("", status);
133    cache->flush();
134    int32_t baseCount = cache->keyCount();
135    const UCTItem *zh = NULL;
136    const UCTItem *zhTw = NULL;
137    const UCTItem *zhHk = NULL;
138
139    status = U_ZERO_ERROR;
140    cache->get(LocaleCacheKey<UCTItem>("zh"), zh, status);
141    if (status != U_MISSING_RESOURCE_ERROR) {
142        errln("Expected U_MISSING_RESOURCE_ERROR");
143    }
144    status = U_ZERO_ERROR;
145    cache->get(LocaleCacheKey<UCTItem>("zh_TW"), zhTw, status);
146    if (status != U_MISSING_RESOURCE_ERROR) {
147        errln("Expected U_MISSING_RESOURCE_ERROR");
148    }
149    status = U_ZERO_ERROR;
150    cache->get(LocaleCacheKey<UCTItem>("zh_HK"), zhHk, status);
151    if (status != U_MISSING_RESOURCE_ERROR) {
152        errln("Expected U_MISSING_RESOURCE_ERROR");
153    }
154    // 3 keys in cache zh, zhTW, zhHk all pointing to error placeholders
155    assertEquals("", baseCount + 3, cache->keyCount());
156    cache->flush();
157    // error placeholders have no hard references so they always get flushed.
158    assertEquals("", baseCount + 0, cache->keyCount());
159}
160
161void UnifiedCacheTest::TestHashEquals() {
162    LocaleCacheKey<UCTItem> key1("en_US");
163    LocaleCacheKey<UCTItem> key2("en_US");
164    LocaleCacheKey<UCTItem> diffKey1("en_UT");
165    LocaleCacheKey<UCTItem2> diffKey2("en_US");
166    assertTrue("", key1.hashCode() == key2.hashCode());
167    assertTrue("", key1.hashCode() != diffKey1.hashCode());
168    assertTrue("", key1.hashCode() != diffKey2.hashCode());
169    assertTrue("", diffKey1.hashCode() != diffKey2.hashCode());
170    assertTrue("", key1 == key2);
171    assertTrue("", key1 != diffKey1);
172    assertTrue("", key1 != diffKey2);
173    assertTrue("", diffKey1 != diffKey2);
174}
175
176extern IntlTest *createUnifiedCacheTest() {
177    return new UnifiedCacheTest();
178}
179