• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
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 "lambda/shorty_field_type.h"
18 #include "mirror/object_reference.h"
19 
20 #include "utils.h"
21 #include <numeric>
22 #include <stdint.h>
23 #include "gtest/gtest.h"
24 
25 #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
26                                         reinterpret_cast<void*>(nullptr));
27 
28 namespace art {
29 namespace lambda {
30 
31 class ShortyFieldTypeTest : public ::testing::Test {
32  public:
33   ShortyFieldTypeTest() = default;
34   ~ShortyFieldTypeTest() = default;
35 
36  protected:
SetUpTestCase()37   static void SetUpTestCase() {
38   }
39 
SetUp()40   virtual void SetUp() {
41   }
42 
IsResultSuccessful(bool result)43   static ::testing::AssertionResult IsResultSuccessful(bool result) {
44     if (result) {
45       return ::testing::AssertionSuccess();
46     } else {
47       return ::testing::AssertionFailure();
48     }
49   }
50 
51   template <typename T>
ListToString(const T & list)52   static std::string ListToString(const T& list) {
53     std::stringstream stream;
54 
55     stream << "[";
56     for (auto&& val : list) {
57       stream << val << ", ";
58     }
59     stream << "]";
60 
61     return stream.str();
62   }
63 
64   // Compare two vector-like types for equality.
65   template <typename T>
AreListsEqual(const T & expected,const T & actual)66   static ::testing::AssertionResult AreListsEqual(const T& expected, const T& actual) {
67     bool success = true;
68     std::stringstream stream;
69 
70     if (expected.size() != actual.size()) {
71       success = false;
72       stream << "Expected list size: " << expected.size()
73              << ", but got list size: " << actual.size();
74       stream << std::endl;
75     }
76 
77     for (size_t j = 0; j < std::min(expected.size(), actual.size()); ++j) {
78       if (expected[j] != actual[j]) {
79         success = false;
80         stream << "Expected element '" << j << "' to be '" << expected[j] << "', but got actual: '"
81                << actual[j] << "'.";
82         stream << std::endl;
83       }
84     }
85 
86     if (success) {
87       return ::testing::AssertionSuccess();
88     }
89 
90     stream << "Expected list was: " << ListToString(expected)
91            << ", actual list was: " << ListToString(actual);
92 
93     return ::testing::AssertionFailure() << stream.str();
94   }
95 
ParseLongTypeDescriptorsToList(const char * type_descriptor)96   static std::vector<ShortyFieldType> ParseLongTypeDescriptorsToList(const char* type_descriptor) {
97     std::vector<ShortyFieldType> lst;
98 
99     ShortyFieldType shorty;
100 
101     const char* parsed = type_descriptor;
102     while ((parsed = ShortyFieldType::ParseFromFieldTypeDescriptor(parsed, &shorty)) != nullptr) {
103       lst.push_back(shorty);
104     }
105 
106     return lst;
107   }
108 
109  protected:
110   // Shorthands for the ShortyFieldType constants.
111   // The letters are the same as JNI letters, with kS_ being a lambda since \ is not available.
112   static constexpr ShortyFieldType kSZ = ShortyFieldType::kBoolean;
113   static constexpr ShortyFieldType kSB = ShortyFieldType::kByte;
114   static constexpr ShortyFieldType kSC = ShortyFieldType::kChar;
115   static constexpr ShortyFieldType kSS = ShortyFieldType::kShort;
116   static constexpr ShortyFieldType kSI = ShortyFieldType::kInt;
117   static constexpr ShortyFieldType kSF = ShortyFieldType::kFloat;
118   static constexpr ShortyFieldType kSJ = ShortyFieldType::kLong;
119   static constexpr ShortyFieldType kSD = ShortyFieldType::kDouble;
120   static constexpr ShortyFieldType kSL = ShortyFieldType::kObject;
121   static constexpr ShortyFieldType kS_ = ShortyFieldType::kLambda;
122 };
123 
TEST_F(ShortyFieldTypeTest,TestMaybeCreate)124 TEST_F(ShortyFieldTypeTest, TestMaybeCreate) {
125   ShortyFieldType shorty;
126 
127   std::vector<char> shorties = {'Z', 'B', 'C', 'S', 'I', 'F', 'J', 'D', 'L', '\\'};
128 
129   // All valid 'shorty' characters are created successfully.
130   for (const char c : shorties) {
131     EXPECT_TRUE(ShortyFieldType::MaybeCreate(c, &shorty)) << c;
132     EXPECT_EQ(c, static_cast<char>(c));
133   }
134 
135   // All other characters can never be created.
136   for (unsigned char c = 0; c < std::numeric_limits<unsigned char>::max(); ++c) {
137     // Skip the valid characters.
138     if (std::find(shorties.begin(), shorties.end(), c) != shorties.end()) { continue; }
139     // All invalid characters should fail.
140     EXPECT_FALSE(ShortyFieldType::MaybeCreate(static_cast<char>(c), &shorty)) << c;
141   }
142 }  // TEST_F
143 
TEST_F(ShortyFieldTypeTest,TestCreateFromFieldTypeDescriptor)144 TEST_F(ShortyFieldTypeTest, TestCreateFromFieldTypeDescriptor) {
145   // Sample input.
146   std::vector<const char*> lengthies = {
147       "Z", "B", "C", "S", "I", "F", "J", "D", "LObject;", "\\Closure;",
148       "[Z", "[[B", "[[LObject;"
149   };
150 
151   // Expected output.
152   std::vector<ShortyFieldType> expected = {
153       ShortyFieldType::kBoolean,
154       ShortyFieldType::kByte,
155       ShortyFieldType::kChar,
156       ShortyFieldType::kShort,
157       ShortyFieldType::kInt,
158       ShortyFieldType::kFloat,
159       ShortyFieldType::kLong,
160       ShortyFieldType::kDouble,
161       ShortyFieldType::kObject,
162       ShortyFieldType::kLambda,
163       // Arrays are always treated as objects.
164       ShortyFieldType::kObject,
165       ShortyFieldType::kObject,
166       ShortyFieldType::kObject,
167   };
168 
169   // All valid lengthy types are correctly turned into the expected shorty type.
170   for (size_t i = 0; i < lengthies.size(); ++i) {
171     EXPECT_EQ(expected[i], ShortyFieldType::CreateFromFieldTypeDescriptor(lengthies[i]));
172   }
173 }  // TEST_F
174 
TEST_F(ShortyFieldTypeTest,TestParseFromFieldTypeDescriptor)175 TEST_F(ShortyFieldTypeTest, TestParseFromFieldTypeDescriptor) {
176   // Sample input.
177   std::vector<const char*> lengthies = {
178       // Empty list
179       "",
180       // Primitives
181       "Z", "B", "C", "S", "I", "F", "J", "D",
182       // Non-primitives
183       "LObject;", "\\Closure;",
184       // Arrays. The biggest PITA.
185       "[Z", "[[B", "[[LObject;", "[[[[\\Closure;",
186       // Multiple things at once:
187       "ZBCSIFJD",
188       "LObject;LObject;SSI",
189       "[[ZDDZ",
190       "[[LObject;[[Z[F\\Closure;LObject;",
191   };
192 
193   // Expected output.
194   std::vector<std::vector<ShortyFieldType>> expected = {
195       // Empty list
196       {},
197       // Primitives
198       {kSZ}, {kSB}, {kSC}, {kSS}, {kSI}, {kSF}, {kSJ}, {kSD},
199       // Non-primitives.
200       { ShortyFieldType::kObject }, { ShortyFieldType::kLambda },
201       // Arrays are always treated as objects.
202       { kSL }, { kSL }, { kSL }, { kSL },
203       // Multiple things at once:
204       { kSZ, kSB, kSC, kSS, kSI, kSF, kSJ, kSD },
205       { kSL, kSL, kSS, kSS, kSI },
206       { kSL, kSD, kSD, kSZ },
207       { kSL, kSL, kSL, kS_, kSL },
208   };
209 
210   // Sanity check that the expected/actual lists are the same size.. when adding new entries.
211   ASSERT_EQ(expected.size(), lengthies.size());
212 
213   // All valid lengthy types are correctly turned into the expected shorty type.
214   for (size_t i = 0; i < expected.size(); ++i) {
215     const std::vector<ShortyFieldType>& expected_list = expected[i];
216     std::vector<ShortyFieldType> actual_list = ParseLongTypeDescriptorsToList(lengthies[i]);
217     EXPECT_TRUE(AreListsEqual(expected_list, actual_list));
218   }
219 }  // TEST_F
220 
221 // Helper class to probe a shorty's characteristics by minimizing copy-and-paste tests.
222 template <typename T, decltype(ShortyFieldType::kByte) kShortyEnum>
223 struct ShortyTypeCharacteristics {
224   bool is_primitive_ = false;
225   bool is_primitive_narrow_ = false;
226   bool is_primitive_wide_ = false;
227   bool is_object_ = false;
228   bool is_lambda_ = false;
229   size_t size_ = sizeof(T);
230   bool is_dynamic_sized_ = false;
231 
CheckExpectsart::lambda::ShortyTypeCharacteristics232   void CheckExpects() {
233     ShortyFieldType shorty = kShortyEnum;
234 
235     // Test the main non-parsing-related ShortyFieldType characteristics.
236     EXPECT_EQ(is_primitive_, shorty.IsPrimitive());
237     EXPECT_EQ(is_primitive_narrow_, shorty.IsPrimitiveNarrow());
238     EXPECT_EQ(is_primitive_wide_, shorty.IsPrimitiveWide());
239     EXPECT_EQ(is_object_, shorty.IsObject());
240     EXPECT_EQ(is_lambda_, shorty.IsLambda());
241     EXPECT_EQ(size_, shorty.GetStaticSize());
242     EXPECT_EQ(is_dynamic_sized_, !shorty.IsStaticSize());
243 
244     // Test compile-time ShortyFieldTypeTraits.
245     EXPECT_TRUE(ShortyFieldTypeTraits::IsType<T>());
246     EXPECT_EQ(is_primitive_, ShortyFieldTypeTraits::IsPrimitiveType<T>());
247     EXPECT_EQ(is_primitive_narrow_, ShortyFieldTypeTraits::IsPrimitiveNarrowType<T>());
248     EXPECT_EQ(is_primitive_wide_, ShortyFieldTypeTraits::IsPrimitiveWideType<T>());
249     EXPECT_EQ(is_object_, ShortyFieldTypeTraits::IsObjectType<T>());
250     EXPECT_EQ(is_lambda_, ShortyFieldTypeTraits::IsLambdaType<T>());
251 
252     // Test compile-time ShortyFieldType selectors
253     static_assert(std::is_same<T, typename ShortyFieldTypeSelectType<kShortyEnum>::type>::value,
254                   "ShortyFieldType Enum->Type incorrect mapping");
255     auto kActualEnum = ShortyFieldTypeSelectEnum<T>::value;  // Do not ODR-use, avoid linker error.
256     EXPECT_EQ(kShortyEnum, kActualEnum);
257   }
258 };
259 
TEST_F(ShortyFieldTypeTest,TestCharacteristicsAndTraits)260 TEST_F(ShortyFieldTypeTest, TestCharacteristicsAndTraits) {
261   // Boolean test
262   {
263     SCOPED_TRACE("boolean");
264     ShortyTypeCharacteristics<bool, ShortyFieldType::kBoolean> chars;
265     chars.is_primitive_ = true;
266     chars.is_primitive_narrow_ = true;
267     chars.CheckExpects();
268   }
269 
270   // Byte test
271   {
272     SCOPED_TRACE("byte");
273     ShortyTypeCharacteristics<int8_t, ShortyFieldType::kByte> chars;
274     chars.is_primitive_ = true;
275     chars.is_primitive_narrow_ = true;
276     chars.CheckExpects();
277   }
278 
279   // Char test
280   {
281     SCOPED_TRACE("char");
282     ShortyTypeCharacteristics<uint16_t, ShortyFieldType::kChar> chars;  // Char is unsigned.
283     chars.is_primitive_ = true;
284     chars.is_primitive_narrow_ = true;
285     chars.CheckExpects();
286   }
287 
288   // Short test
289   {
290     SCOPED_TRACE("short");
291     ShortyTypeCharacteristics<int16_t, ShortyFieldType::kShort> chars;
292     chars.is_primitive_ = true;
293     chars.is_primitive_narrow_ = true;
294     chars.CheckExpects();
295   }
296 
297   // Int test
298   {
299     SCOPED_TRACE("int");
300     ShortyTypeCharacteristics<int32_t, ShortyFieldType::kInt> chars;
301     chars.is_primitive_ = true;
302     chars.is_primitive_narrow_ = true;
303     chars.CheckExpects();
304   }
305 
306   // Long test
307   {
308     SCOPED_TRACE("long");
309     ShortyTypeCharacteristics<int64_t, ShortyFieldType::kLong> chars;
310     chars.is_primitive_ = true;
311     chars.is_primitive_wide_ = true;
312     chars.CheckExpects();
313   }
314 
315   // Float test
316   {
317     SCOPED_TRACE("float");
318     ShortyTypeCharacteristics<float, ShortyFieldType::kFloat> chars;
319     chars.is_primitive_ = true;
320     chars.is_primitive_narrow_ = true;
321     chars.CheckExpects();
322   }
323 
324   // Double test
325   {
326     SCOPED_TRACE("double");
327     ShortyTypeCharacteristics<double, ShortyFieldType::kDouble> chars;
328     chars.is_primitive_ = true;
329     chars.is_primitive_wide_ = true;
330     chars.CheckExpects();
331   }
332 
333   // Object test
334   {
335     SCOPED_TRACE("object");
336     ShortyTypeCharacteristics<mirror::Object*, ShortyFieldType::kObject> chars;
337     chars.is_object_ = true;
338     chars.size_ = kObjectReferenceSize;
339     chars.CheckExpects();
340     EXPECT_EQ(kObjectReferenceSize, sizeof(mirror::CompressedReference<mirror::Object>));
341   }
342 
343   // Lambda test
344   {
345     SCOPED_TRACE("lambda");
346     ShortyTypeCharacteristics<Closure*, ShortyFieldType::kLambda> chars;
347     chars.is_lambda_ = true;
348     chars.is_dynamic_sized_ = true;
349     chars.CheckExpects();
350   }
351 }
352 
353 }  // namespace lambda
354 }  // namespace art
355