1 // Copyright (C) 2014 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <libaddressinput/supplier.h> 16 17 #include <libaddressinput/address_data.h> 18 #include <libaddressinput/callback.h> 19 #include <libaddressinput/downloader.h> 20 #include <libaddressinput/null_storage.h> 21 #include <libaddressinput/ondemand_supplier.h> 22 #include <libaddressinput/preload_supplier.h> 23 #include <libaddressinput/storage.h> 24 #include <libaddressinput/util/basictypes.h> 25 #include <libaddressinput/util/scoped_ptr.h> 26 27 #include <cstddef> 28 #include <cstring> 29 #include <string> 30 31 #include <gtest/gtest.h> 32 33 #include "fake_downloader.h" 34 #include "lookup_key.h" 35 #include "rule.h" 36 37 namespace { 38 39 // For compatibility with legacy compilers, that can't handle UTF-8 string 40 // literals in source code (please let them disappear from common use soon), 41 // Chinese strings required in the test code are here provided as string 42 // constants in hex escaped UTF-8 encoding. 43 44 /* "" */ 45 const char kKowloon[] = "\xE4\xB9\x9D\xE9\xBE\x8D"; 46 47 /* "" */ 48 const char kXinJiang[] = "\xE6\x96\xB0\xE7\x96\x86"; 49 50 /* "" */ 51 const char kKashiDiqu[] = "\xE5\x96\x80\xE4\xBB\x80\xE5\x9C\xB0\xE5\x8C\xBA"; 52 53 /* "" */ 54 const char kKashiShi[] = "\xE5\x96\x80\xE4\xBB\x80\xE5\xB8\x82"; 55 56 using i18n::addressinput::AddressData; 57 using i18n::addressinput::BuildCallback; 58 using i18n::addressinput::Downloader; 59 using i18n::addressinput::FakeDownloader; 60 using i18n::addressinput::LookupKey; 61 using i18n::addressinput::NullStorage; 62 using i18n::addressinput::OndemandSupplier; 63 using i18n::addressinput::PreloadSupplier; 64 using i18n::addressinput::Rule; 65 using i18n::addressinput::scoped_ptr; 66 using i18n::addressinput::Storage; 67 using i18n::addressinput::Supplier; 68 69 class SupplierWrapper { 70 public: 71 virtual ~SupplierWrapper() {} 72 virtual void Supply(const LookupKey& lookup_key, 73 const Supplier::Callback& supplied) = 0; 74 }; 75 76 class OndemandSupplierWrapper : public SupplierWrapper { 77 public: 78 static SupplierWrapper* Build() { return new OndemandSupplierWrapper; } 79 80 virtual ~OndemandSupplierWrapper() {} 81 82 virtual void Supply(const LookupKey& lookup_key, 83 const Supplier::Callback& supplied) { 84 ondemand_supplier_.Supply(lookup_key, supplied); 85 } 86 87 private: 88 OndemandSupplierWrapper() 89 : ondemand_supplier_(FakeDownloader::kFakeDataUrl, 90 new FakeDownloader, 91 new NullStorage) {} 92 93 OndemandSupplier ondemand_supplier_; 94 DISALLOW_COPY_AND_ASSIGN(OndemandSupplierWrapper); 95 }; 96 97 class PreloadSupplierWrapper : public SupplierWrapper { 98 public: 99 static SupplierWrapper* Build() { return new PreloadSupplierWrapper; } 100 101 virtual ~PreloadSupplierWrapper() {} 102 103 virtual void Supply(const LookupKey& lookup_key, 104 const Supplier::Callback& supplied) { 105 const std::string& region_code = lookup_key.GetRegionCode(); 106 if (!region_code.empty() && !preload_supplier_.IsLoaded(region_code)) { 107 preload_supplier_.LoadRules(region_code, *loaded_); 108 } 109 preload_supplier_.Supply(lookup_key, supplied); 110 } 111 112 private: 113 PreloadSupplierWrapper() 114 : preload_supplier_(FakeDownloader::kFakeAggregateDataUrl, 115 new FakeDownloader, 116 new NullStorage), 117 loaded_(BuildCallback(this, &PreloadSupplierWrapper::Loaded)) {} 118 119 void Loaded(bool success, const std::string&, int) { 120 ASSERT_TRUE(success); 121 } 122 123 PreloadSupplier preload_supplier_; 124 const scoped_ptr<const PreloadSupplier::Callback> loaded_; 125 DISALLOW_COPY_AND_ASSIGN(PreloadSupplierWrapper); 126 }; 127 128 class SupplierTest : public testing::TestWithParam<SupplierWrapper* (*)()> { 129 protected: 130 SupplierTest() 131 : address_(), 132 rule_(), 133 called_(false), 134 lookup_key_(), 135 supplier_wrapper_((*GetParam())()), 136 supplied_(BuildCallback(this, &SupplierTest::Supplied)) {} 137 138 virtual ~SupplierTest() {} 139 140 void Supply() { 141 lookup_key_.FromAddress(address_); 142 supplier_wrapper_->Supply(lookup_key_, *supplied_); 143 } 144 145 AddressData address_; 146 const Rule* rule_[arraysize(LookupKey::kHierarchy)]; 147 bool called_; 148 149 private: 150 void Supplied(bool success, 151 const LookupKey& lookup_key, 152 const Supplier::RuleHierarchy& hierarchy) { 153 ASSERT_TRUE(success); 154 ASSERT_EQ(&lookup_key_, &lookup_key); 155 std::memcpy(rule_, hierarchy.rule, sizeof rule_); 156 called_ = true; 157 } 158 159 LookupKey lookup_key_; 160 const scoped_ptr<SupplierWrapper> supplier_wrapper_; 161 const scoped_ptr<const Supplier::Callback> supplied_; 162 163 DISALLOW_COPY_AND_ASSIGN(SupplierTest); 164 }; 165 166 INSTANTIATE_TEST_CASE_P(OndemandSupplier, 167 SupplierTest, 168 testing::Values(&OndemandSupplierWrapper::Build)); 169 170 INSTANTIATE_TEST_CASE_P(PreloadSupplier, 171 SupplierTest, 172 testing::Values(&PreloadSupplierWrapper::Build)); 173 174 TEST_P(SupplierTest, Invalid) { 175 address_.region_code = "QZ"; 176 177 ASSERT_NO_FATAL_FAILURE(Supply()); 178 ASSERT_TRUE(called_); 179 EXPECT_TRUE(rule_[0] == NULL); 180 EXPECT_TRUE(rule_[1] == NULL); 181 EXPECT_TRUE(rule_[2] == NULL); 182 EXPECT_TRUE(rule_[3] == NULL); 183 } 184 185 TEST_P(SupplierTest, Valid) { 186 address_.region_code = "SE"; 187 188 ASSERT_NO_FATAL_FAILURE(Supply()); 189 ASSERT_TRUE(called_); 190 EXPECT_TRUE(rule_[0] != NULL); 191 EXPECT_TRUE(rule_[1] == NULL); 192 EXPECT_TRUE(rule_[2] == NULL); 193 EXPECT_TRUE(rule_[3] == NULL); 194 EXPECT_EQ("data/SE", rule_[0]->GetId()); 195 EXPECT_FALSE(rule_[0]->GetRequired().empty()); 196 EXPECT_FALSE(rule_[0]->GetFormat().empty()); 197 EXPECT_TRUE(rule_[0]->GetPostalCodeMatcher() != NULL); 198 } 199 200 TEST_P(SupplierTest, KeyDepthEqualsMaxDepth) { 201 address_.region_code = "HK"; 202 address_.administrative_area = kKowloon; 203 204 ASSERT_NO_FATAL_FAILURE(Supply()); 205 ASSERT_TRUE(called_); 206 EXPECT_TRUE(rule_[0] != NULL); 207 EXPECT_TRUE(rule_[1] != NULL); 208 EXPECT_TRUE(rule_[2] == NULL); 209 EXPECT_TRUE(rule_[3] == NULL); 210 } 211 212 TEST_P(SupplierTest, KeyDepthLargerThanMaxDepth) { 213 address_.region_code = "HK"; 214 address_.administrative_area = kKowloon; 215 address_.locality = "bbb"; // Ignored! 216 217 ASSERT_NO_FATAL_FAILURE(Supply()); 218 ASSERT_TRUE(called_); 219 EXPECT_TRUE(rule_[0] != NULL); 220 EXPECT_TRUE(rule_[1] != NULL); 221 EXPECT_TRUE(rule_[2] == NULL); 222 EXPECT_TRUE(rule_[3] == NULL); 223 } 224 225 TEST_P(SupplierTest, KeyDepthSmallerThanMaxDepth) { 226 address_.region_code = "HK"; 227 228 ASSERT_NO_FATAL_FAILURE(Supply()); 229 ASSERT_TRUE(called_); 230 EXPECT_TRUE(rule_[0] != NULL); 231 EXPECT_TRUE(rule_[1] == NULL); 232 EXPECT_TRUE(rule_[2] == NULL); 233 EXPECT_TRUE(rule_[3] == NULL); 234 } 235 236 TEST_P(SupplierTest, KeyDepth0) { 237 address_.region_code = "CN"; 238 239 ASSERT_NO_FATAL_FAILURE(Supply()); 240 ASSERT_TRUE(called_); 241 EXPECT_TRUE(rule_[0] != NULL); 242 EXPECT_TRUE(rule_[1] == NULL); 243 EXPECT_TRUE(rule_[2] == NULL); 244 EXPECT_TRUE(rule_[3] == NULL); 245 } 246 247 TEST_P(SupplierTest, KeyDepth1) { 248 address_.region_code = "CN"; 249 address_.administrative_area = kXinJiang; 250 251 ASSERT_NO_FATAL_FAILURE(Supply()); 252 ASSERT_TRUE(called_); 253 EXPECT_TRUE(rule_[0] != NULL); 254 EXPECT_TRUE(rule_[1] != NULL); 255 EXPECT_TRUE(rule_[2] == NULL); 256 EXPECT_TRUE(rule_[3] == NULL); 257 } 258 259 TEST_P(SupplierTest, KeyDepth2) { 260 address_.region_code = "CN"; 261 address_.administrative_area = kXinJiang; 262 address_.locality = kKashiDiqu; 263 264 ASSERT_NO_FATAL_FAILURE(Supply()); 265 ASSERT_TRUE(called_); 266 EXPECT_TRUE(rule_[0] != NULL); 267 EXPECT_TRUE(rule_[1] != NULL); 268 EXPECT_TRUE(rule_[2] != NULL); 269 EXPECT_TRUE(rule_[3] == NULL); 270 } 271 272 TEST_P(SupplierTest, KeyDepth3) { 273 address_.region_code = "CN"; 274 address_.administrative_area = kXinJiang; 275 address_.locality = kKashiDiqu; 276 address_.dependent_locality = kKashiShi; 277 278 ASSERT_NO_FATAL_FAILURE(Supply()); 279 ASSERT_TRUE(called_); 280 EXPECT_TRUE(rule_[0] != NULL); 281 EXPECT_TRUE(rule_[1] != NULL); 282 EXPECT_TRUE(rule_[2] != NULL); 283 EXPECT_TRUE(rule_[3] != NULL); 284 } 285 286 TEST_P(SupplierTest, RuleCache) { 287 address_.region_code = "US"; 288 address_.administrative_area = "CA"; 289 290 ASSERT_NO_FATAL_FAILURE(Supply()); 291 ASSERT_TRUE(called_); 292 EXPECT_TRUE(rule_[0] != NULL); 293 EXPECT_TRUE(rule_[1] != NULL); 294 EXPECT_TRUE(rule_[2] == NULL); 295 EXPECT_TRUE(rule_[3] == NULL); 296 297 // Make a copy of the currently returned pointers to the Rule objects (stored 298 // in the OndemandSupplier cache) and verify that calling Supply() again with 299 // the same LookupKey returns the same pointers again (and doesn't create any 300 // new Rule objects instead). 301 302 const Rule* rule[arraysize(LookupKey::kHierarchy)]; 303 std::memcpy(rule, rule_, sizeof rule); 304 305 called_ = false; 306 ASSERT_NO_FATAL_FAILURE(Supply()); 307 ASSERT_TRUE(called_); 308 EXPECT_EQ(rule[0], rule_[0]); 309 EXPECT_EQ(rule[1], rule_[1]); 310 EXPECT_EQ(rule[2], rule_[2]); 311 EXPECT_EQ(rule[3], rule_[3]); 312 } 313 314 } // namespace 315