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