| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2017 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 | #include "test/Builders.h" | 
|  | 18 |  | 
|  | 19 | #include "android-base/logging.h" | 
|  | 20 | #include "androidfw/StringPiece.h" | 
|  | 21 |  | 
| Adam Lesinski | 0045116 | 2017-10-03 07:44:08 -0700 | [diff] [blame] | 22 | #include "io/StringStream.h" | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 23 | #include "test/Common.h" | 
|  | 24 | #include "util/Util.h" | 
|  | 25 |  | 
| Shane Farmer | efe4539 | 2017-08-21 14:39:28 -0700 | [diff] [blame] | 26 | using ::aapt::configuration::Abi; | 
|  | 27 | using ::aapt::configuration::AndroidSdk; | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 28 | using ::aapt::configuration::ConfiguredArtifact; | 
| Shane Farmer | 78c43d7 | 2017-12-04 09:08:38 -0800 | [diff] [blame] | 29 | using ::aapt::configuration::GetOrCreateGroup; | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 30 | using ::aapt::io::StringInputStream; | 
| MÃ¥rten Kongstad | 24c9aa6 | 2018-06-20 08:46:41 +0200 | [diff] [blame] | 31 | using ::android::ConfigDescription; | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 32 | using ::android::StringPiece; | 
|  | 33 |  | 
|  | 34 | namespace aapt { | 
|  | 35 | namespace test { | 
|  | 36 |  | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 37 | ResourceTableBuilder& ResourceTableBuilder::AddSimple(const StringPiece& name, | 
|  | 38 | const ResourceId& id) { | 
|  | 39 | return AddValue(name, id, util::make_unique<Id>()); | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | ResourceTableBuilder& ResourceTableBuilder::AddSimple(const StringPiece& name, | 
|  | 43 | const ConfigDescription& config, | 
|  | 44 | const ResourceId& id) { | 
|  | 45 | return AddValue(name, config, id, util::make_unique<Id>()); | 
|  | 46 | } | 
|  | 47 |  | 
|  | 48 | ResourceTableBuilder& ResourceTableBuilder::AddReference(const StringPiece& name, | 
|  | 49 | const StringPiece& ref) { | 
|  | 50 | return AddReference(name, {}, ref); | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | ResourceTableBuilder& ResourceTableBuilder::AddReference(const StringPiece& name, | 
|  | 54 | const ResourceId& id, | 
|  | 55 | const StringPiece& ref) { | 
|  | 56 | return AddValue(name, id, util::make_unique<Reference>(ParseNameOrDie(ref))); | 
|  | 57 | } | 
|  | 58 |  | 
|  | 59 | ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, | 
|  | 60 | const StringPiece& str) { | 
|  | 61 | return AddString(name, {}, str); | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, const ResourceId& id, | 
|  | 65 | const StringPiece& str) { | 
|  | 66 | return AddValue(name, id, util::make_unique<String>(table_->string_pool.MakeRef(str))); | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, const ResourceId& id, | 
|  | 70 | const ConfigDescription& config, | 
|  | 71 | const StringPiece& str) { | 
|  | 72 | return AddValue(name, config, id, util::make_unique<String>(table_->string_pool.MakeRef(str))); | 
|  | 73 | } | 
|  | 74 |  | 
|  | 75 | ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name, | 
| Adam Lesinski | 8780eb6 | 2017-10-31 17:44:39 -0700 | [diff] [blame] | 76 | const StringPiece& path, | 
|  | 77 | io::IFile* file) { | 
|  | 78 | return AddFileReference(name, {}, path, file); | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 79 | } | 
|  | 80 |  | 
|  | 81 | ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name, | 
|  | 82 | const ResourceId& id, | 
| Adam Lesinski | 8780eb6 | 2017-10-31 17:44:39 -0700 | [diff] [blame] | 83 | const StringPiece& path, | 
|  | 84 | io::IFile* file) { | 
|  | 85 | auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path)); | 
|  | 86 | file_ref->file = file; | 
|  | 87 | return AddValue(name, id, std::move(file_ref)); | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 88 | } | 
|  | 89 |  | 
|  | 90 | ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name, | 
|  | 91 | const StringPiece& path, | 
| Adam Lesinski | 8780eb6 | 2017-10-31 17:44:39 -0700 | [diff] [blame] | 92 | const ConfigDescription& config, | 
|  | 93 | io::IFile* file) { | 
|  | 94 | auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path)); | 
|  | 95 | file_ref->file = file; | 
|  | 96 | return AddValue(name, config, {}, std::move(file_ref)); | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 97 | } | 
|  | 98 |  | 
|  | 99 | ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name, | 
|  | 100 | std::unique_ptr<Value> value) { | 
|  | 101 | return AddValue(name, {}, std::move(value)); | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name, const ResourceId& id, | 
|  | 105 | std::unique_ptr<Value> value) { | 
|  | 106 | return AddValue(name, {}, id, std::move(value)); | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name, | 
|  | 110 | const ConfigDescription& config, | 
|  | 111 | const ResourceId& id, | 
|  | 112 | std::unique_ptr<Value> value) { | 
|  | 113 | ResourceName res_name = ParseNameOrDie(name); | 
| Ryan Mitchell | 1d008d1 | 2021-03-19 14:54:17 -0700 | [diff] [blame] | 114 | NewResourceBuilder builder(res_name); | 
|  | 115 | builder.SetValue(std::move(value), config).SetAllowMangled(true); | 
|  | 116 | if (id.id != 0U) { | 
|  | 117 | builder.SetId(id); | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | CHECK(table_->AddResource(builder.Build(), GetDiagnostics())); | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 121 | return *this; | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& name, | 
| Adam Lesinski | 71be705 | 2017-12-12 16:48:07 -0800 | [diff] [blame] | 125 | const ResourceId& id, | 
|  | 126 | Visibility::Level level, | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 127 | bool allow_new) { | 
|  | 128 | ResourceName res_name = ParseNameOrDie(name); | 
| Ryan Mitchell | 1d008d1 | 2021-03-19 14:54:17 -0700 | [diff] [blame] | 129 | NewResourceBuilder builder(res_name); | 
|  | 130 | builder.SetVisibility({level}).SetAllowNew({}).SetAllowMangled(true); | 
|  | 131 | if (id.id != 0U) { | 
|  | 132 | builder.SetId(id); | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | CHECK(table_->AddResource(builder.Build(), GetDiagnostics())); | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 136 | return *this; | 
|  | 137 | } | 
|  | 138 |  | 
| Ryan Mitchell | 1bb1fe0 | 2018-11-16 11:21:41 -0800 | [diff] [blame] | 139 | ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(const StringPiece& name, | 
| Ryan Mitchell | 54237ff | 2018-12-13 15:44:29 -0800 | [diff] [blame] | 140 | const OverlayableItem& overlayable) { | 
| Ryan Mitchell | 1bb1fe0 | 2018-11-16 11:21:41 -0800 | [diff] [blame] | 141 |  | 
| Ryan Mitchell | e4e989c | 2018-10-29 02:21:50 -0700 | [diff] [blame] | 142 | ResourceName res_name = ParseNameOrDie(name); | 
| Ryan Mitchell | 1d008d1 | 2021-03-19 14:54:17 -0700 | [diff] [blame] | 143 | CHECK(table_->AddResource( | 
|  | 144 | NewResourceBuilder(res_name).SetOverlayable(overlayable).SetAllowMangled(true).Build(), | 
|  | 145 | GetDiagnostics())); | 
|  | 146 | return *this; | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | ResourceTableBuilder& ResourceTableBuilder::Add(NewResource&& res) { | 
|  | 150 | CHECK(table_->AddResource(std::move(res), GetDiagnostics())); | 
| Ryan Mitchell | e4e989c | 2018-10-29 02:21:50 -0700 | [diff] [blame] | 151 | return *this; | 
|  | 152 | } | 
|  | 153 |  | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 154 | StringPool* ResourceTableBuilder::string_pool() { | 
|  | 155 | return &table_->string_pool; | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | std::unique_ptr<ResourceTable> ResourceTableBuilder::Build() { | 
|  | 159 | return std::move(table_); | 
|  | 160 | } | 
|  | 161 |  | 
| Ryan Mitchell | 4382e44 | 2021-07-14 12:53:01 -0700 | [diff] [blame] | 162 | std::unique_ptr<Reference> BuildReference(const StringPiece& ref, | 
|  | 163 | const std::optional<ResourceId>& id) { | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 164 | std::unique_ptr<Reference> reference = util::make_unique<Reference>(ParseNameOrDie(ref)); | 
|  | 165 | reference->id = id; | 
|  | 166 | return reference; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | std::unique_ptr<BinaryPrimitive> BuildPrimitive(uint8_t type, uint32_t data) { | 
|  | 170 | android::Res_value value = {}; | 
|  | 171 | value.size = sizeof(value); | 
|  | 172 | value.dataType = type; | 
|  | 173 | value.data = data; | 
|  | 174 | return util::make_unique<BinaryPrimitive>(value); | 
|  | 175 | } | 
|  | 176 |  | 
| Adam Lesinski | 73bff1e | 2017-12-08 16:06:10 -0800 | [diff] [blame] | 177 | AttributeBuilder::AttributeBuilder() | 
|  | 178 | : attr_(util::make_unique<Attribute>(android::ResTable_map::TYPE_ANY)) { | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 179 | } | 
|  | 180 |  | 
|  | 181 | AttributeBuilder& AttributeBuilder::SetTypeMask(uint32_t typeMask) { | 
|  | 182 | attr_->type_mask = typeMask; | 
|  | 183 | return *this; | 
|  | 184 | } | 
|  | 185 |  | 
| Adam Lesinski | 73bff1e | 2017-12-08 16:06:10 -0800 | [diff] [blame] | 186 | AttributeBuilder& AttributeBuilder::SetWeak(bool weak) { | 
|  | 187 | attr_->SetWeak(weak); | 
|  | 188 | return *this; | 
|  | 189 | } | 
|  | 190 |  | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 191 | AttributeBuilder& AttributeBuilder::AddItem(const StringPiece& name, uint32_t value) { | 
|  | 192 | attr_->symbols.push_back( | 
|  | 193 | Attribute::Symbol{Reference(ResourceName({}, ResourceType::kId, name)), value}); | 
|  | 194 | return *this; | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | std::unique_ptr<Attribute> AttributeBuilder::Build() { | 
|  | 198 | return std::move(attr_); | 
|  | 199 | } | 
|  | 200 |  | 
|  | 201 | StyleBuilder& StyleBuilder::SetParent(const StringPiece& str) { | 
|  | 202 | style_->parent = Reference(ParseNameOrDie(str)); | 
|  | 203 | return *this; | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | StyleBuilder& StyleBuilder::AddItem(const StringPiece& str, std::unique_ptr<Item> value) { | 
|  | 207 | style_->entries.push_back(Style::Entry{Reference(ParseNameOrDie(str)), std::move(value)}); | 
|  | 208 | return *this; | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | StyleBuilder& StyleBuilder::AddItem(const StringPiece& str, const ResourceId& id, | 
|  | 212 | std::unique_ptr<Item> value) { | 
|  | 213 | AddItem(str, std::move(value)); | 
|  | 214 | style_->entries.back().key.id = id; | 
|  | 215 | return *this; | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | std::unique_ptr<Style> StyleBuilder::Build() { | 
|  | 219 | return std::move(style_); | 
|  | 220 | } | 
|  | 221 |  | 
| Ryan Mitchell | 4382e44 | 2021-07-14 12:53:01 -0700 | [diff] [blame] | 222 | StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str, | 
|  | 223 | const std::optional<ResourceId>& id) { | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 224 | styleable_->entries.push_back(Reference(ParseNameOrDie(str))); | 
|  | 225 | styleable_->entries.back().id = id; | 
|  | 226 | return *this; | 
|  | 227 | } | 
|  | 228 |  | 
|  | 229 | std::unique_ptr<Styleable> StyleableBuilder::Build() { | 
|  | 230 | return std::move(styleable_); | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | std::unique_ptr<xml::XmlResource> BuildXmlDom(const StringPiece& str) { | 
|  | 234 | std::string input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; | 
|  | 235 | input.append(str.data(), str.size()); | 
|  | 236 | StringInputStream in(input); | 
|  | 237 | StdErrDiagnostics diag; | 
|  | 238 | std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, &diag, Source("test.xml")); | 
| Adam Lesinski | 6b37299 | 2017-08-09 10:54:23 -0700 | [diff] [blame] | 239 | CHECK(doc != nullptr && doc->root != nullptr) << "failed to parse inline XML string"; | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 240 | return doc; | 
|  | 241 | } | 
|  | 242 |  | 
|  | 243 | std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(IAaptContext* context, | 
|  | 244 | const StringPiece& str) { | 
|  | 245 | std::unique_ptr<xml::XmlResource> doc = BuildXmlDom(str); | 
|  | 246 | doc->file.name.package = context->GetCompilationPackage(); | 
|  | 247 | return doc; | 
|  | 248 | } | 
|  | 249 |  | 
| Shane Farmer | 0a5b201 | 2017-06-22 12:24:12 -0700 | [diff] [blame] | 250 | ArtifactBuilder& ArtifactBuilder::SetName(const std::string& name) { | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 251 | artifact_.name = name; | 
| Shane Farmer | 0a5b201 | 2017-06-22 12:24:12 -0700 | [diff] [blame] | 252 | return *this; | 
|  | 253 | } | 
|  | 254 |  | 
| Shane Farmer | 78c43d7 | 2017-12-04 09:08:38 -0800 | [diff] [blame] | 255 | ArtifactBuilder& ArtifactBuilder::SetVersion(int version) { | 
|  | 256 | artifact_.version = version; | 
|  | 257 | return *this; | 
|  | 258 | } | 
|  | 259 |  | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 260 | ArtifactBuilder& ArtifactBuilder::AddAbi(configuration::Abi abi) { | 
|  | 261 | artifact_.abis.push_back(abi); | 
| Shane Farmer | 0a5b201 | 2017-06-22 12:24:12 -0700 | [diff] [blame] | 262 | return *this; | 
|  | 263 | } | 
|  | 264 |  | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 265 | ArtifactBuilder& ArtifactBuilder::AddDensity(const ConfigDescription& density) { | 
|  | 266 | artifact_.screen_densities.push_back(density); | 
| Shane Farmer | 0a5b201 | 2017-06-22 12:24:12 -0700 | [diff] [blame] | 267 | return *this; | 
|  | 268 | } | 
|  | 269 |  | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 270 | ArtifactBuilder& ArtifactBuilder::AddLocale(const ConfigDescription& locale) { | 
|  | 271 | artifact_.locales.push_back(locale); | 
| Shane Farmer | 0a5b201 | 2017-06-22 12:24:12 -0700 | [diff] [blame] | 272 | return *this; | 
|  | 273 | } | 
|  | 274 |  | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 275 | ArtifactBuilder& ArtifactBuilder::SetAndroidSdk(int min_sdk) { | 
|  | 276 | artifact_.android_sdk = {AndroidSdk::ForMinSdk(min_sdk)}; | 
| Shane Farmer | efe4539 | 2017-08-21 14:39:28 -0700 | [diff] [blame] | 277 | return *this; | 
|  | 278 | } | 
|  | 279 |  | 
| Shane Farmer | cb6c3f9 | 2017-11-27 13:19:36 -0800 | [diff] [blame] | 280 | configuration::OutputArtifact ArtifactBuilder::Build() { | 
| Shane Farmer | 0a5b201 | 2017-06-22 12:24:12 -0700 | [diff] [blame] | 281 | return artifact_; | 
|  | 282 | } | 
|  | 283 |  | 
| Shane Farmer | 78c43d7 | 2017-12-04 09:08:38 -0800 | [diff] [blame] | 284 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddAbiGroup( | 
|  | 285 | const std::string& label, std::vector<configuration::Abi> abis) { | 
|  | 286 | return AddGroup(label, &config_.abi_groups, std::move(abis)); | 
|  | 287 | } | 
|  | 288 |  | 
|  | 289 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddDensityGroup( | 
|  | 290 | const std::string& label, std::vector<std::string> densities) { | 
|  | 291 | std::vector<ConfigDescription> configs; | 
|  | 292 | for (const auto& density : densities) { | 
|  | 293 | configs.push_back(test::ParseConfigOrDie(density)); | 
|  | 294 | } | 
|  | 295 | return AddGroup(label, &config_.screen_density_groups, configs); | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddLocaleGroup( | 
|  | 299 | const std::string& label, std::vector<std::string> locales) { | 
|  | 300 | std::vector<ConfigDescription> configs; | 
|  | 301 | for (const auto& locale : locales) { | 
|  | 302 | configs.push_back(test::ParseConfigOrDie(locale)); | 
|  | 303 | } | 
|  | 304 | return AddGroup(label, &config_.locale_groups, configs); | 
|  | 305 | } | 
|  | 306 |  | 
|  | 307 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddDeviceFeatureGroup( | 
|  | 308 | const std::string& label) { | 
|  | 309 | return AddGroup(label, &config_.device_feature_groups); | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddGlTextureGroup( | 
|  | 313 | const std::string& label) { | 
|  | 314 | return AddGroup(label, &config_.gl_texture_groups); | 
|  | 315 | } | 
|  | 316 |  | 
|  | 317 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddAndroidSdk( | 
|  | 318 | std::string label, int min_sdk) { | 
|  | 319 | config_.android_sdks[label] = AndroidSdk::ForMinSdk(min_sdk); | 
|  | 320 | return *this; | 
|  | 321 | } | 
|  | 322 |  | 
|  | 323 | PostProcessingConfigurationBuilder& PostProcessingConfigurationBuilder::AddArtifact( | 
|  | 324 | configuration::ConfiguredArtifact artifact) { | 
|  | 325 | config_.artifacts.push_back(std::move(artifact)); | 
|  | 326 | return *this; | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | configuration::PostProcessingConfiguration PostProcessingConfigurationBuilder::Build() { | 
|  | 330 | return config_; | 
|  | 331 | } | 
|  | 332 |  | 
| Adam Lesinski | efeb7af | 2017-08-02 14:57:43 -0700 | [diff] [blame] | 333 | }  // namespace test | 
|  | 334 | }  // namespace aapt |