1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/common/cpp/client_wrapper/testing/encodable_value_utils.h"
6
7 #include <cmath>
8
9 namespace flutter {
10 namespace testing {
11
EncodableValuesAreEqual(const EncodableValue & a,const EncodableValue & b)12 bool EncodableValuesAreEqual(const EncodableValue& a, const EncodableValue& b) {
13 if (a.type() != b.type()) {
14 return false;
15 }
16
17 switch (a.type()) {
18 case EncodableValue::Type::kNull:
19 return true;
20 case EncodableValue::Type::kBool:
21 return a.BoolValue() == b.BoolValue();
22 case EncodableValue::Type::kInt:
23 return a.IntValue() == b.IntValue();
24 case EncodableValue::Type::kLong:
25 return a.LongValue() == b.LongValue();
26 case EncodableValue::Type::kDouble:
27 // This is a crude epsilon, but fine for the values in the unit tests.
28 return std::abs(a.DoubleValue() - b.DoubleValue()) < 0.0001l;
29 case EncodableValue::Type::kString:
30 return a.StringValue() == b.StringValue();
31 case EncodableValue::Type::kByteList:
32 return a.ByteListValue() == b.ByteListValue();
33 case EncodableValue::Type::kIntList:
34 return a.IntListValue() == b.IntListValue();
35 case EncodableValue::Type::kLongList:
36 return a.LongListValue() == b.LongListValue();
37 case EncodableValue::Type::kDoubleList:
38 return a.DoubleListValue() == b.DoubleListValue();
39 case EncodableValue::Type::kList: {
40 const auto& a_list = a.ListValue();
41 const auto& b_list = b.ListValue();
42 if (a_list.size() != b_list.size()) {
43 return false;
44 }
45 for (size_t i = 0; i < a_list.size(); ++i) {
46 if (!EncodableValuesAreEqual(a_list[0], b_list[0])) {
47 return false;
48 }
49 }
50 return true;
51 }
52 case EncodableValue::Type::kMap: {
53 const auto& a_map = a.MapValue();
54 const auto& b_map = b.MapValue();
55 if (a_map.size() != b_map.size()) {
56 return false;
57 }
58 // Store references to all the keys in |b|.
59 std::vector<const EncodableValue*> unmatched_b_keys;
60 for (auto& pair : b_map) {
61 unmatched_b_keys.push_back(&pair.first);
62 }
63 // For each key,value in |a|, see if any of the not-yet-matched key,value
64 // pairs in |b| match by value; if so, remove that match and continue.
65 for (const auto& pair : a_map) {
66 bool found_match = false;
67 for (size_t i = 0; i < unmatched_b_keys.size(); ++i) {
68 const EncodableValue& b_key = *unmatched_b_keys[i];
69 if (EncodableValuesAreEqual(pair.first, b_key) &&
70 EncodableValuesAreEqual(pair.second, b_map.at(b_key))) {
71 found_match = true;
72 unmatched_b_keys.erase(unmatched_b_keys.begin() + i);
73 break;
74 }
75 }
76 if (!found_match) {
77 return false;
78 }
79 }
80 // If all entries had matches, consider the maps equal.
81 return true;
82 }
83 }
84 assert(false);
85 return false;
86 }
87
88 } // namespace testing
89 } // namespace flutter
90