1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18 #include <unordered_map>
19 #include <unordered_set>
20 #include <vector>
21
22 #include <fbjni/fbjni.h>
23
24 #include "expect.h"
25
26 using namespace facebook::jni;
27
nativeTestListIterator(alias_ref<jclass>,alias_ref<JList<jstring>> jlist)28 jboolean nativeTestListIterator(
29 alias_ref<jclass>,
30 alias_ref<JList<jstring>> jlist) {
31 EXPECT(jlist);
32
33 EXPECT(jlist->size() == 3);
34
35 std::vector<std::string> vs1;
36 for (const auto& elem : *jlist) {
37 vs1.push_back(elem->toStdString());
38 }
39
40 EXPECT(vs1.size() == 3);
41 EXPECT(vs1[0] == "red");
42 EXPECT(vs1[1] == "green");
43 EXPECT(vs1[2] == "blue");
44
45 std::vector<std::string> vs2;
46 std::transform(
47 jlist->begin(),
48 jlist->end(),
49 std::back_inserter(vs2),
50 [](local_ref<jstring> elem) { return elem->toStdString(); });
51
52 EXPECT(vs1 == vs2);
53
54 std::vector<std::string> vs3 = {"red", "green", "blue"};
55
56 EXPECT(vs1 == vs3);
57
58 static auto iteratorMethod =
59 JIterable<jstring>::javaClassStatic()->getMethod<JIterator<jstring>()>(
60 "iterator");
61 auto iter = iteratorMethod(jlist);
62
63 EXPECT(std::equal(iter->begin(), iter->end(), jlist->begin()));
64 EXPECT(std::equal(
65 iter->begin(),
66 iter->end(),
67 vs3.begin(),
68 [](const local_ref<jstring>& a, const std::string& b) {
69 return a->toStdString() == b;
70 }));
71
72 return JNI_TRUE;
73 }
74
nativeTestMapIterator(alias_ref<jclass>,alias_ref<JMap<jstring,JInteger>> jmap)75 jboolean nativeTestMapIterator(
76 alias_ref<jclass>,
77 alias_ref<JMap<jstring, JInteger>> jmap) {
78 EXPECT(jmap);
79
80 EXPECT(jmap->size() == 3);
81
82 std::unordered_map<std::string, int> umap;
83
84 for (const auto& entry : *jmap) {
85 umap[entry.first->toStdString()] = entry.second->intValue();
86 }
87
88 EXPECT(umap.size() == 3);
89
90 EXPECT(umap["one"] == 1);
91 EXPECT(umap["two"] == 2);
92 EXPECT(umap["four"] == 4);
93
94 // For an empty map, any types will do; the cast will only happen on null
95 // pointers, which will always succeed.
96 typedef JHashMap<jclass, jthrowable> TestMap;
97
98 static auto testmapCtor =
99 TestMap::javaClassStatic()->getConstructor<TestMap::javaobject()>();
100 auto emptyMap = TestMap::javaClassStatic()->newObject(testmapCtor);
101 EXPECT(emptyMap->size() == 0);
102
103 JHashMap<jclass, jthrowable>::Iterator i1 = emptyMap->begin();
104 JHashMap<jclass, jthrowable>::Iterator i2 = emptyMap->end();
105
106 EXPECT(i1 == i2);
107
108 return JNI_TRUE;
109 }
110
nativeTestIterateWrongType(alias_ref<jclass>,alias_ref<JMap<jstring,JInteger::javaobject>> jmap)111 jboolean nativeTestIterateWrongType(
112 alias_ref<jclass>,
113 alias_ref<JMap<jstring, JInteger::javaobject>> jmap) {
114 EXPECT(jmap);
115
116 EXPECT(jmap->size() == 3);
117
118 for (const auto& entry : *jmap) {
119 (void)entry;
120 }
121
122 // The above should throw an exception.
123 EXPECT(false);
124
125 return JNI_FALSE;
126 }
127
nativeTestIterateNullKey(alias_ref<jclass>,alias_ref<JMap<jstring,JInteger>> jmap)128 jboolean nativeTestIterateNullKey(
129 alias_ref<jclass>,
130 alias_ref<JMap<jstring, JInteger>> jmap) {
131 EXPECT(jmap);
132
133 EXPECT(jmap->size() == 3);
134
135 std::unordered_map<std::string, int> umap;
136 std::unordered_set<int> nullValues;
137
138 for (const auto& entry : *jmap) {
139 if (entry.first) {
140 umap[entry.first->toStdString()] = entry.second->intValue();
141 } else {
142 nullValues.insert(entry.second->intValue());
143 }
144 }
145
146 EXPECT(umap.size() == 2);
147
148 EXPECT(umap["one"] == 1);
149 EXPECT(umap["four"] == 4);
150
151 EXPECT(nullValues.size() == 1);
152 EXPECT(*nullValues.begin() == -99);
153
154 return JNI_TRUE;
155 }
156
nativeTestLargeMapIteration(alias_ref<jclass>,alias_ref<JMap<jstring,jstring>> jmap)157 jboolean nativeTestLargeMapIteration(
158 alias_ref<jclass>,
159 alias_ref<JMap<jstring, jstring>> jmap) {
160 EXPECT(jmap);
161 EXPECT(jmap->size() == 3000);
162
163 for (const auto& entry : *jmap) {
164 if (!entry.first) {
165 return JNI_FALSE;
166 }
167 }
168 return JNI_TRUE;
169 }
170
RegisterIteratorTests()171 void RegisterIteratorTests() {
172 registerNatives(
173 "com/facebook/jni/IteratorTests",
174 {
175 makeNativeMethod("nativeTestListIterator", nativeTestListIterator),
176 makeNativeMethod("nativeTestMapIterator", nativeTestMapIterator),
177 makeNativeMethod(
178 "nativeTestIterateWrongType", nativeTestIterateWrongType),
179 makeNativeMethod(
180 "nativeTestIterateNullKey", nativeTestIterateNullKey),
181 makeNativeMethod(
182 "nativeTestLargeMapIteration", nativeTestLargeMapIteration),
183 });
184 }
185