1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkRandom.h"
9#include "SkRefCnt.h"
10#include "SkTSearch.h"
11#include "SkTSort.h"
12#include "SkUtils.h"
13#include "Test.h"
14
15class RefClass : public SkRefCnt {
16public:
17    SK_DECLARE_INST_COUNT(RefClass)
18
19    RefClass(int n) : fN(n) {}
20    int get() const { return fN; }
21
22private:
23    int fN;
24
25    typedef SkRefCnt INHERITED;
26};
27
28static void test_autounref(skiatest::Reporter* reporter) {
29    RefClass obj(0);
30    REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
31
32    SkAutoTUnref<RefClass> tmp(&obj);
33    REPORTER_ASSERT(reporter, &obj == tmp.get());
34    REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
35
36    REPORTER_ASSERT(reporter, &obj == tmp.detach());
37    REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
38    REPORTER_ASSERT(reporter, NULL == tmp.detach());
39    REPORTER_ASSERT(reporter, NULL == tmp.get());
40
41    obj.ref();
42    REPORTER_ASSERT(reporter, 2 == obj.getRefCnt());
43    {
44        SkAutoTUnref<RefClass> tmp2(&obj);
45    }
46    REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
47}
48
49static void test_autostarray(skiatest::Reporter* reporter) {
50    RefClass obj0(0);
51    RefClass obj1(1);
52    REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
53    REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
54
55    {
56        SkAutoSTArray<2, SkAutoTUnref<RefClass> > tmp;
57        REPORTER_ASSERT(reporter, 0 == tmp.count());
58
59        tmp.reset(0);   // test out reset(0) when already at 0
60        tmp.reset(4);   // this should force a new allocation
61        REPORTER_ASSERT(reporter, 4 == tmp.count());
62        tmp[0].reset(SkRef(&obj0));
63        tmp[1].reset(SkRef(&obj1));
64        REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
65        REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
66
67        // test out reset with data in the array (and a new allocation)
68        tmp.reset(0);
69        REPORTER_ASSERT(reporter, 0 == tmp.count());
70        REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
71        REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
72
73        tmp.reset(2);   // this should use the preexisting allocation
74        REPORTER_ASSERT(reporter, 2 == tmp.count());
75        tmp[0].reset(SkRef(&obj0));
76        tmp[1].reset(SkRef(&obj1));
77    }
78
79    // test out destructor with data in the array (and using existing allocation)
80    REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
81    REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
82
83    {
84        // test out allocating ctor (this should allocate new memory)
85        SkAutoSTArray<2, SkAutoTUnref<RefClass> > tmp(4);
86        REPORTER_ASSERT(reporter, 4 == tmp.count());
87
88        tmp[0].reset(SkRef(&obj0));
89        tmp[1].reset(SkRef(&obj1));
90        REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
91        REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
92
93        // Test out resut with data in the array and malloced storage
94        tmp.reset(0);
95        REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
96        REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
97
98        tmp.reset(2);   // this should use the preexisting storage
99        tmp[0].reset(SkRef(&obj0));
100        tmp[1].reset(SkRef(&obj1));
101        REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
102        REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
103
104        tmp.reset(4);   // this should force a new malloc
105        REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
106        REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
107
108        tmp[0].reset(SkRef(&obj0));
109        tmp[1].reset(SkRef(&obj1));
110        REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
111        REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
112    }
113
114    REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
115    REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
116}
117
118/////////////////////////////////////////////////////////////////////////////
119
120#define kSEARCH_COUNT   91
121
122static void test_search(skiatest::Reporter* reporter) {
123    int         i, array[kSEARCH_COUNT];
124    SkRandom    rand;
125
126    for (i = 0; i < kSEARCH_COUNT; i++) {
127        array[i] = rand.nextS();
128    }
129
130    SkTHeapSort<int>(array, kSEARCH_COUNT);
131    // make sure we got sorted properly
132    for (i = 1; i < kSEARCH_COUNT; i++) {
133        REPORTER_ASSERT(reporter, array[i-1] <= array[i]);
134    }
135
136    // make sure we can find all of our values
137    for (i = 0; i < kSEARCH_COUNT; i++) {
138        int index = SkTSearch<int>(array, kSEARCH_COUNT, array[i], sizeof(int));
139        REPORTER_ASSERT(reporter, index == i);
140    }
141
142    // make sure that random values are either found, or the correct
143    // insertion index is returned
144    for (i = 0; i < 10000; i++) {
145        int value = rand.nextS();
146        int index = SkTSearch<int>(array, kSEARCH_COUNT, value, sizeof(int));
147
148        if (index >= 0) {
149            REPORTER_ASSERT(reporter,
150                            index < kSEARCH_COUNT && array[index] == value);
151        } else {
152            index = ~index;
153            REPORTER_ASSERT(reporter, index <= kSEARCH_COUNT);
154            if (index < kSEARCH_COUNT) {
155                REPORTER_ASSERT(reporter, value < array[index]);
156                if (index > 0) {
157                    REPORTER_ASSERT(reporter, value > array[index - 1]);
158                }
159            } else {
160                // we should append the new value
161                REPORTER_ASSERT(reporter, value > array[kSEARCH_COUNT - 1]);
162            }
163        }
164    }
165}
166
167static void test_utf16(skiatest::Reporter* reporter) {
168    static const SkUnichar gUni[] = {
169        0x10000, 0x18080, 0x20202, 0xFFFFF, 0x101234
170    };
171
172    uint16_t buf[2];
173
174    for (size_t i = 0; i < SK_ARRAY_COUNT(gUni); i++) {
175        size_t count = SkUTF16_FromUnichar(gUni[i], buf);
176        REPORTER_ASSERT(reporter, count == 2);
177        size_t count2 = SkUTF16_CountUnichars(buf, 2);
178        REPORTER_ASSERT(reporter, count2 == 1);
179        const uint16_t* ptr = buf;
180        SkUnichar c = SkUTF16_NextUnichar(&ptr);
181        REPORTER_ASSERT(reporter, c == gUni[i]);
182        REPORTER_ASSERT(reporter, ptr - buf == 2);
183    }
184}
185
186DEF_TEST(Utils, reporter) {
187    static const struct {
188        const char* fUtf8;
189        SkUnichar   fUni;
190    } gTest[] = {
191        { "a",                  'a' },
192        { "\x7f",               0x7f },
193        { "\xC2\x80",           0x80 },
194        { "\xC3\x83",           (3 << 6) | 3    },
195        { "\xDF\xBF",           0x7ff },
196        { "\xE0\xA0\x80",       0x800 },
197        { "\xE0\xB0\xB8",       0xC38 },
198        { "\xE3\x83\x83",       (3 << 12) | (3 << 6) | 3    },
199        { "\xEF\xBF\xBF",       0xFFFF },
200        { "\xF0\x90\x80\x80",   0x10000 },
201        { "\xF3\x83\x83\x83",   (3 << 18) | (3 << 12) | (3 << 6) | 3    }
202    };
203
204    for (size_t i = 0; i < SK_ARRAY_COUNT(gTest); i++) {
205        const char* p = gTest[i].fUtf8;
206        int         n = SkUTF8_CountUnichars(p);
207        SkUnichar   u0 = SkUTF8_ToUnichar(gTest[i].fUtf8);
208        SkUnichar   u1 = SkUTF8_NextUnichar(&p);
209
210        REPORTER_ASSERT(reporter, n == 1);
211        REPORTER_ASSERT(reporter, u0 == u1);
212        REPORTER_ASSERT(reporter, u0 == gTest[i].fUni);
213        REPORTER_ASSERT(reporter,
214                        p - gTest[i].fUtf8 == (int)strlen(gTest[i].fUtf8));
215    }
216
217    test_utf16(reporter);
218    test_search(reporter);
219    test_autounref(reporter);
220    test_autostarray(reporter);
221}
222