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 #ifndef AAPT_TEST_COMMON_H 18 #define AAPT_TEST_COMMON_H 19 20 #include <iostream> 21 22 #include "android-base/logging.h" 23 #include "android-base/macros.h" 24 #include "androidfw/StringPiece.h" 25 #include "gmock/gmock.h" 26 #include "gtest/gtest.h" 27 28 #include "ConfigDescription.h" 29 #include "Debug.h" 30 #include "ResourceTable.h" 31 #include "ResourceUtils.h" 32 #include "ResourceValues.h" 33 #include "ValueVisitor.h" 34 #include "io/File.h" 35 #include "process/IResourceTableConsumer.h" 36 37 namespace aapt { 38 namespace test { 39 40 IDiagnostics* GetDiagnostics(); 41 42 inline ResourceName ParseNameOrDie(const android::StringPiece& str) { 43 ResourceNameRef ref; 44 CHECK(ResourceUtils::ParseResourceName(str, &ref)) << "invalid resource name: " << str; 45 return ref.ToResourceName(); 46 } 47 48 inline ConfigDescription ParseConfigOrDie(const android::StringPiece& str) { 49 ConfigDescription config; 50 CHECK(ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str; 51 return config; 52 } 53 54 template <typename T = Value> 55 T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name, 56 const ConfigDescription& config, 57 const android::StringPiece& product) { 58 Maybe<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name)); 59 if (result) { 60 ResourceConfigValue* config_value = result.value().entry->FindValue(config, product); 61 if (config_value) { 62 return ValueCast<T>(config_value->value.get()); 63 } 64 } 65 return nullptr; 66 } 67 68 template <> 69 Value* GetValueForConfigAndProduct<Value>(ResourceTable* table, 70 const android::StringPiece& res_name, 71 const ConfigDescription& config, 72 const android::StringPiece& product); 73 74 template <typename T = Value> 75 T* GetValueForConfig(ResourceTable* table, const android::StringPiece& res_name, 76 const ConfigDescription& config) { 77 return GetValueForConfigAndProduct<T>(table, res_name, config, {}); 78 } 79 80 template <typename T = Value> 81 T* GetValue(ResourceTable* table, const android::StringPiece& res_name) { 82 return GetValueForConfig<T>(table, res_name, {}); 83 } 84 85 class TestFile : public io::IFile { 86 public: 87 explicit TestFile(const android::StringPiece& path) : source_(path) {} 88 89 std::unique_ptr<io::IData> OpenAsData() override { 90 return {}; 91 } 92 93 std::unique_ptr<io::InputStream> OpenInputStream() override { 94 return OpenAsData(); 95 } 96 97 const Source& GetSource() const override { 98 return source_; 99 } 100 101 private: 102 DISALLOW_COPY_AND_ASSIGN(TestFile); 103 104 Source source_; 105 }; 106 107 } // namespace test 108 109 // Workaround gtest bug (https://github.com/google/googletest/issues/443) 110 // that does not select base class operator<< for derived class T. 111 template <typename T> 112 typename std::enable_if<std::is_base_of<Value, T>::value, std::ostream&>::type operator<<( 113 std::ostream& out, const T& value) { 114 value.Print(&out); 115 return out; 116 } 117 118 template std::ostream& operator<<<Item>(std::ostream&, const Item&); 119 template std::ostream& operator<<<Reference>(std::ostream&, const Reference&); 120 template std::ostream& operator<<<Id>(std::ostream&, const Id&); 121 template std::ostream& operator<<<RawString>(std::ostream&, const RawString&); 122 template std::ostream& operator<<<String>(std::ostream&, const String&); 123 template std::ostream& operator<<<StyledString>(std::ostream&, const StyledString&); 124 template std::ostream& operator<<<FileReference>(std::ostream&, const FileReference&); 125 template std::ostream& operator<<<BinaryPrimitive>(std::ostream&, const BinaryPrimitive&); 126 template std::ostream& operator<<<Attribute>(std::ostream&, const Attribute&); 127 template std::ostream& operator<<<Style>(std::ostream&, const Style&); 128 template std::ostream& operator<<<Array>(std::ostream&, const Array&); 129 template std::ostream& operator<<<Plural>(std::ostream&, const Plural&); 130 131 // Add a print method to Maybe. 132 template <typename T> 133 void PrintTo(const Maybe<T>& value, std::ostream* out) { 134 if (value) { 135 *out << ::testing::PrintToString(value.value()); 136 } else { 137 *out << "Nothing"; 138 } 139 } 140 141 namespace test { 142 143 MATCHER_P(StrEq, a, 144 std::string(negation ? "isn't" : "is") + " equal to " + 145 ::testing::PrintToString(android::StringPiece16(a))) { 146 return android::StringPiece16(arg) == a; 147 } 148 149 template <typename T> 150 class ValueEqImpl : public ::testing::MatcherInterface<T> { 151 public: 152 explicit ValueEqImpl(const Value* expected) : expected_(expected) { 153 } 154 155 bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override { 156 return expected_->Equals(&x); 157 } 158 159 void DescribeTo(::std::ostream* os) const override { 160 *os << "is equal to " << *expected_; 161 } 162 163 void DescribeNegationTo(::std::ostream* os) const override { 164 *os << "is not equal to " << *expected_; 165 } 166 167 private: 168 DISALLOW_COPY_AND_ASSIGN(ValueEqImpl); 169 170 const Value* expected_; 171 }; 172 173 template <typename TValue> 174 class ValueEqMatcher { 175 public: 176 ValueEqMatcher(TValue expected) : expected_(std::move(expected)) { 177 } 178 179 template <typename T> 180 operator ::testing::Matcher<T>() const { 181 return ::testing::Matcher<T>(new ValueEqImpl<T>(&expected_)); 182 } 183 184 private: 185 TValue expected_; 186 }; 187 188 template <typename TValue> 189 class ValueEqPointerMatcher { 190 public: 191 ValueEqPointerMatcher(const TValue* expected) : expected_(expected) { 192 } 193 194 template <typename T> 195 operator ::testing::Matcher<T>() const { 196 return ::testing::Matcher<T>(new ValueEqImpl<T>(expected_)); 197 } 198 199 private: 200 const TValue* expected_; 201 }; 202 203 template <typename TValue, 204 typename = typename std::enable_if<!std::is_pointer<TValue>::value, void>::type> 205 inline ValueEqMatcher<TValue> ValueEq(TValue value) { 206 return ValueEqMatcher<TValue>(std::move(value)); 207 } 208 209 template <typename TValue> 210 inline ValueEqPointerMatcher<TValue> ValueEq(const TValue* value) { 211 return ValueEqPointerMatcher<TValue>(value); 212 } 213 214 MATCHER_P(StrValueEq, a, 215 std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) { 216 return *(arg.value) == a; 217 } 218 219 MATCHER_P(HasValue, name, 220 std::string(negation ? "does not have" : "has") + " value " + 221 ::testing::PrintToString(name)) { 222 return GetValueForConfig<Value>(&(*arg), name, {}) != nullptr; 223 } 224 225 MATCHER_P2(HasValue, name, config, 226 std::string(negation ? "does not have" : "has") + " value " + 227 ::testing::PrintToString(name) + " for config " + ::testing::PrintToString(config)) { 228 return GetValueForConfig<Value>(&(*arg), name, config) != nullptr; 229 } 230 231 } // namespace test 232 } // namespace aapt 233 234 #endif /* AAPT_TEST_COMMON_H */ 235