1 /* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 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 <gmock/gmock.h> 16 #include <gtest/gtest.h> 17 18 #include <base/containers/unordered_map.h> 19 #include <core/io/intf_file_manager.h> 20 21 #include <meta/api/make_callback.h> 22 #include <meta/api/object.h> 23 #include <meta/interface/builtin_objects.h> 24 #include <meta/interface/loaders/intf_file_content_loader.h> 25 26 #include "TestRunner.h" 27 28 using namespace testing; 29 using namespace testing::ext; 30 31 META_BEGIN_NAMESPACE() 32 33 MATCHER_P(HasProperty, name, "") 34 { 35 const META_NS::IObject::Ptr& object = arg; 36 auto meta = interface_cast<META_NS::IMetadata>(object); 37 bool found = false; 38 39 if (!meta || !object) { 40 *result_listener << "where object type is invalid"; 41 return false; 42 } 43 44 for (auto prop : meta->GetProperties()) { 45 if (prop->GetName() == name) { 46 found = true; 47 break; 48 } 49 } 50 51 if (!found) { 52 *result_listener << "where object did not have property '" << name.data() << "'"; 53 } 54 return found; 55 } 56 57 constexpr BASE_NS::string_view TRANSLATION_STRING_KEY = "strings"; 58 59 class CsvLoaderTest : public ::testing::Test { 60 protected: SetUp()61 void SetUp() override 62 { 63 loader_ = META_NS::GetObjectRegistry().Create<IFileContentLoader>(ClassId::CsvStringResourceLoader); 64 ASSERT_NE(loader_, nullptr); 65 } 66 67 using CsvContentItemType = BASE_NS::pair<BASE_NS::string, BASE_NS::vector<BASE_NS::string>>; 68 using CsvContentType = BASE_NS::vector<CsvContentItemType>; 69 CheckTranslations(const BASE_NS::string & path,const BASE_NS::vector<BASE_NS::string> & keys,const CsvContentType & content)70 void CheckTranslations( 71 const BASE_NS::string& path, const BASE_NS::vector<BASE_NS::string>& keys, const CsvContentType& content) 72 { 73 loader_->SetFile(CORE_NS::GetPluginRegister().GetFileManager().OpenFile(path)); 74 Object object(loader_->Create({})); 75 ASSERT_TRUE(object); 76 ASSERT_NE(object.GetPtr(), nullptr); 77 78 // Object should have a "strings" property 79 ASSERT_THAT(object, HasProperty(TRANSLATION_STRING_KEY)); 80 auto stringsProp = Metadata(object).GetProperty<IObject::Ptr>(TRANSLATION_STRING_KEY); 81 ASSERT_TRUE(stringsProp); 82 Object strings(stringsProp->GetValue()); 83 ASSERT_TRUE(strings); 84 EXPECT_EQ(Metadata(strings).GetProperties().size(), content.size()); 85 86 // Go through our expected content and chech that the object has all of the languages and 87 // corresponding strings 88 for (const auto& item : content) { 89 BASE_NS::string_view lang(item.first); 90 ASSERT_THAT(strings, HasProperty(lang)); 91 92 auto translationsProp = Metadata(strings).GetProperty<IObject::Ptr>(lang); 93 ASSERT_TRUE(translationsProp); 94 Object translations(translationsProp->GetValue()); 95 ASSERT_TRUE(translations); 96 97 // Must contain expected amount of translation strings 98 const auto& expectedTranslations = item.second; 99 ASSERT_EQ(Metadata(translations).GetProperties().size(), expectedTranslations.size()); 100 ASSERT_EQ(keys.size(), expectedTranslations.size()); 101 102 // Check that each translation found in the object matches our expected translation table 103 for (size_t i = 0; i < expectedTranslations.size(); i++) { 104 auto prop = Metadata(translations).GetProperty<BASE_NS::string>(keys[i]); 105 ASSERT_TRUE(prop) << "lang: " << item.first.data() << ", index: " << i; 106 ASSERT_EQ(prop->GetValue(), expectedTranslations[i]) 107 << "lang: " << item.first.data() << ", index: " << i; 108 } 109 } 110 } 111 112 IFileContentLoader::Ptr loader_; 113 }; 114 115 /** 116 * @tc.name: Basic 117 * @tc.desc: test Basic 118 * @tc.type: FUNC 119 */ 120 HWTEST_F(CsvLoaderTest, Basic, TestSize.Level1) 121 { 122 constexpr auto path = "file:///data/local/test_data/csv/basic.csv"; 123 static BASE_NS::vector<BASE_NS::string> keys = { "First string", "Second string", "Click me" }; 124 static CsvContentType content = { { "fi", { "Eka merkkijono", "Toka merkkijono", "Klikkaa mua" } }, 125 { "en", { "First string", "Second string", "Click me" } }, 126 { "zh", { "第一个字符串", "第二个字符串", "点我" } } }; 127 128 CheckTranslations(path, keys, content); 129 } 130 131 /** 132 * @tc.name: Quotes 133 * @tc.desc: test Quotes 134 * @tc.type: FUNC 135 */ 136 HWTEST_F(CsvLoaderTest, Quotes, TestSize.Level1) 137 { 138 constexpr auto path = "file:///data/local/test_data/csv/quotes.csv"; 139 // The CSV file contains quoted strings with commas, double quotes and also leading and 140 // trailing whitespace between opening/closing quote and the delimiter. Those should be 141 // handled correctly. 142 static BASE_NS::vector<BASE_NS::string> keys = { "Click,me", "Click,\"12" }; 143 static CsvContentType content = { { "fi", { "Klikkaa,mua", "Klikkaa,\"12" } }, 144 { "en", { "Click,me", "Click,\"12" } }, { "zh", { "点,我", "点,12" } } }; 145 146 CheckTranslations(path, keys, content); 147 } 148 149 /** 150 * @tc.name: Multiline 151 * @tc.desc: test Multiline 152 * @tc.type: FUNC 153 */ 154 HWTEST_F(CsvLoaderTest, Multiline, TestSize.Level1) 155 { 156 constexpr auto path = "file:///data/local/test_data/csv/multiline.csv"; 157 // These strings/keys should match the values in above csv file 158 static BASE_NS::vector<BASE_NS::string> keys = { "First string", "Click me" }; 159 static CsvContentType content = { { "fi", { "Eka \nmerkkijono", "Klikkaa mua" } }, 160 { "en", { "First \nstring", "Click me" } }, { "zh", { "第一\n个字符串", "点我" } } }; 161 162 CheckTranslations(path, keys, content); 163 } 164 165 /** 166 * @tc.name: Complex 167 * @tc.desc: test Complex 168 * @tc.type: FUNC 169 */ 170 HWTEST_F(CsvLoaderTest, Complex, TestSize.Level1) 171 { 172 constexpr auto path = "file:///data/local/test_data/csv/complex.csv"; 173 // These strings/keys should match the values in above csv file 174 static BASE_NS::vector<BASE_NS::string> keys = { "1991", "1992", "1993", "1994" }; 175 static CsvContentType content = { { "make", { "Ford", "Chevy", "Chevy", "Jeep" } }, 176 { "model", 177 { "E350", "Venture \"Extended Edition\"", "Venture \"Extended Edition, Very Large\"", "Grand Cherokee" } }, 178 { "description", { "ac, abs, moon", "", "", "MUST SELL!\nair, moon roof, loaded" } }, 179 { "price", { "3000.00", "4900.00", "5000.00", "4799.00" } } }; 180 181 CheckTranslations(path, keys, content); 182 } 183 184 /** 185 * @tc.name: CsvInvalid 186 * @tc.desc: test CsvInvalid 187 * @tc.type: FUNC 188 */ 189 HWTEST_F(CsvLoaderTest, CsvInvalid, TestSize.Level1) 190 { 191 constexpr auto path1 = "file:///data/local/test_data/csv/invalid_content.csv"; 192 constexpr auto path2 = "file:///data/local/test_data/csv/invalid_structure.csv"; 193 constexpr auto path3 = "file:///data/local/test_data/csv/invalid_header.csv"; 194 constexpr auto path4 = "file:///data/local/test_data/csv/invalid_empty.csv"; 195 constexpr auto path5 = "file:///data/local/test_data/csv/invalid_file_doesnt_exist.csv"; 196 int changed = 0; 197 __anon0442e47f0102null198 loader_->ContentChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([&changed] { changed++; })); 199 200 loader_->SetFile(CORE_NS::GetPluginRegister().GetFileManager().OpenFile(path1)); 201 EXPECT_EQ(loader_->Create({}), nullptr); 202 loader_->SetFile(CORE_NS::GetPluginRegister().GetFileManager().OpenFile(path2)); 203 EXPECT_EQ(loader_->Create({}), nullptr); 204 loader_->SetFile(CORE_NS::GetPluginRegister().GetFileManager().OpenFile(path3)); 205 EXPECT_EQ(loader_->Create({}), nullptr); 206 loader_->SetFile(CORE_NS::GetPluginRegister().GetFileManager().OpenFile(path4)); 207 EXPECT_EQ(loader_->Create({}), nullptr); 208 loader_->SetFile(CORE_NS::GetPluginRegister().GetFileManager().OpenFile(path5)); 209 EXPECT_EQ(loader_->Create({}), nullptr); 210 211 EXPECT_EQ(changed, 5); 212 } 213 214 META_END_NAMESPACE() 215