1 /*
2  * Copyright (C) 2016 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 "DominatorTree.h"
18 
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 #include "test/Test.h"
24 #include "util/Util.h"
25 
26 using ::android::ConfigDescription;
27 
28 namespace aapt {
29 
30 namespace {
31 
32 class PrettyPrinter : public DominatorTree::Visitor {
33  public:
PrettyPrinter(const int indent=2)34   explicit PrettyPrinter(const int indent = 2) : indent_(indent) {}
35 
VisitTree(const std::string & product,DominatorTree::Node * root)36   void VisitTree(const std::string& product,
37                  DominatorTree::Node* root) override {
38     for (auto& child : root->children()) {
39       VisitNode(child.get(), 0);
40     }
41   }
42 
ToString(DominatorTree * tree)43   std::string ToString(DominatorTree* tree) {
44     buffer_.str("");
45     buffer_.clear();
46     tree->Accept(this);
47     return buffer_.str();
48   }
49 
50  private:
VisitConfig(const DominatorTree::Node * node,const int indent)51   void VisitConfig(const DominatorTree::Node* node, const int indent) {
52     auto config_string = node->value()->config.toString();
53     buffer_ << std::string(indent, ' ')
54             << (config_string.empty() ? "<default>" : config_string.c_str()) << std::endl;
55   }
56 
VisitNode(const DominatorTree::Node * node,const int indent)57   void VisitNode(const DominatorTree::Node* node, const int indent) {
58     VisitConfig(node, indent);
59     for (const auto& child : node->children()) {
60       VisitNode(child.get(), indent + indent_);
61     }
62   }
63 
64   std::stringstream buffer_;
65   const int indent_ = 2;
66 };
67 
68 }  // namespace
69 
TEST(DominatorTreeTest,DefaultDominatesEverything)70 TEST(DominatorTreeTest, DefaultDominatesEverything) {
71   const ConfigDescription default_config = {};
72   const ConfigDescription land_config = test::ParseConfigOrDie("land");
73   const ConfigDescription sw600dp_land_config = test::ParseConfigOrDie("sw600dp-land-v13");
74 
75   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
76   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
77   configs.push_back(util::make_unique<ResourceConfigValue>(land_config, ""));
78   configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_land_config, ""));
79 
80   DominatorTree tree(configs);
81   PrettyPrinter printer;
82 
83   std::string expected =
84       "<default>\n"
85       "  land\n"
86       "  sw600dp-land-v13\n";
87   EXPECT_EQ(expected, printer.ToString(&tree));
88 }
89 
TEST(DominatorTreeTest,ProductsAreDominatedSeparately)90 TEST(DominatorTreeTest, ProductsAreDominatedSeparately) {
91   const ConfigDescription default_config = {};
92   const ConfigDescription land_config = test::ParseConfigOrDie("land");
93   const ConfigDescription sw600dp_land_config = test::ParseConfigOrDie("sw600dp-land-v13");
94 
95   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
96   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
97   configs.push_back(util::make_unique<ResourceConfigValue>(land_config, ""));
98   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, "phablet"));
99   configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_land_config, "phablet"));
100 
101   DominatorTree tree(configs);
102   PrettyPrinter printer;
103 
104   std::string expected =
105       "<default>\n"
106       "  land\n"
107       "<default>\n"
108       "  sw600dp-land-v13\n";
109   EXPECT_EQ(expected, printer.ToString(&tree));
110 }
111 
TEST(DominatorTreeTest,MoreSpecificConfigurationsAreDominated)112 TEST(DominatorTreeTest, MoreSpecificConfigurationsAreDominated) {
113   const ConfigDescription default_config = {};
114   const ConfigDescription en_config = test::ParseConfigOrDie("en");
115   const ConfigDescription en_v21_config = test::ParseConfigOrDie("en-v21");
116   const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl-v4");
117   const ConfigDescription ldrtl_xhdpi_config = test::ParseConfigOrDie("ldrtl-xhdpi-v4");
118   const ConfigDescription sw300dp_config = test::ParseConfigOrDie("sw300dp-v13");
119   const ConfigDescription sw540dp_config = test::ParseConfigOrDie("sw540dp-v14");
120   const ConfigDescription sw600dp_config = test::ParseConfigOrDie("sw600dp-v14");
121   const ConfigDescription sw720dp_config = test::ParseConfigOrDie("sw720dp-v13");
122   const ConfigDescription v20_config = test::ParseConfigOrDie("v20");
123 
124   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
125   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
126   configs.push_back(util::make_unique<ResourceConfigValue>(en_config, ""));
127   configs.push_back(util::make_unique<ResourceConfigValue>(en_v21_config, ""));
128   configs.push_back(util::make_unique<ResourceConfigValue>(ldrtl_config, ""));
129   configs.push_back(util::make_unique<ResourceConfigValue>(ldrtl_xhdpi_config, ""));
130   configs.push_back(util::make_unique<ResourceConfigValue>(sw300dp_config, ""));
131   configs.push_back(util::make_unique<ResourceConfigValue>(sw540dp_config, ""));
132   configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_config, ""));
133   configs.push_back(util::make_unique<ResourceConfigValue>(sw720dp_config, ""));
134   configs.push_back(util::make_unique<ResourceConfigValue>(v20_config, ""));
135 
136   DominatorTree tree(configs);
137   PrettyPrinter printer;
138 
139   std::string expected =
140       "<default>\n"
141       "  ldrtl-v4\n"
142       "    ldrtl-xhdpi-v4\n"
143       "  sw300dp-v13\n"
144       "    sw540dp-v14\n"
145       "      sw600dp-v14\n"
146       "    sw720dp-v13\n"
147       "  v20\n"
148       "en\n"
149       "  en-v21\n";
150   EXPECT_EQ(expected, printer.ToString(&tree));
151 }
152 
TEST(DominatorTreeTest,LocalesAreNeverDominated)153 TEST(DominatorTreeTest, LocalesAreNeverDominated) {
154   const ConfigDescription fr_config = test::ParseConfigOrDie("fr");
155   const ConfigDescription fr_rCA_config = test::ParseConfigOrDie("fr-rCA");
156   const ConfigDescription fr_rFR_config = test::ParseConfigOrDie("fr-rFR");
157 
158   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
159   configs.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), ""));
160   configs.push_back(util::make_unique<ResourceConfigValue>(fr_config, ""));
161   configs.push_back(util::make_unique<ResourceConfigValue>(fr_rCA_config, ""));
162   configs.push_back(util::make_unique<ResourceConfigValue>(fr_rFR_config, ""));
163 
164   DominatorTree tree(configs);
165   PrettyPrinter printer;
166 
167   std::string expected =
168       "<default>\n"
169       "fr\n"
170       "fr-rCA\n"
171       "fr-rFR\n";
172   EXPECT_EQ(expected, printer.ToString(&tree));
173 }
174 
TEST(DominatorTreeTest,NonZeroDensitiesMatch)175 TEST(DominatorTreeTest, NonZeroDensitiesMatch) {
176   const ConfigDescription sw600_config = test::ParseConfigOrDie("sw600dp");
177   const ConfigDescription sw600_hdpi_config = test::ParseConfigOrDie("sw600dp-hdpi");
178   const ConfigDescription sw800_hdpi_config = test::ParseConfigOrDie("sw800dp-hdpi");
179   const ConfigDescription sw800_xxhdpi_config = test::ParseConfigOrDie("sw800dp-xxhdpi");
180 
181   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
182   configs.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), ""));
183   configs.push_back(util::make_unique<ResourceConfigValue>(sw600_config, ""));
184   configs.push_back(util::make_unique<ResourceConfigValue>(sw600_hdpi_config, ""));
185   configs.push_back(util::make_unique<ResourceConfigValue>(sw800_hdpi_config, ""));
186   configs.push_back(util::make_unique<ResourceConfigValue>(sw800_xxhdpi_config, ""));
187 
188   DominatorTree tree(configs);
189   PrettyPrinter printer;
190 
191   std::string expected =
192       "<default>\n"
193       "  sw600dp-v13\n"
194       "    sw600dp-hdpi-v13\n"
195       "      sw800dp-hdpi-v13\n"
196       "      sw800dp-xxhdpi-v13\n";
197   EXPECT_EQ(expected, printer.ToString(&tree));
198 }
199 
TEST(DominatorTreeTest,MccMncIsPeertoLocale)200 TEST(DominatorTreeTest, MccMncIsPeertoLocale) {
201   const ConfigDescription default_config = {};
202   const ConfigDescription de_config = test::ParseConfigOrDie("de");
203   const ConfigDescription fr_config = test::ParseConfigOrDie("fr");
204   const ConfigDescription mcc_config = test::ParseConfigOrDie("mcc262");
205   const ConfigDescription mcc_fr_config = test::ParseConfigOrDie("mcc262-fr");
206   const ConfigDescription mnc_config = test::ParseConfigOrDie("mnc2");
207   const ConfigDescription mnc_fr_config = test::ParseConfigOrDie("mnc2-fr");
208   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
209   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
210   configs.push_back(util::make_unique<ResourceConfigValue>(de_config, ""));
211   configs.push_back(util::make_unique<ResourceConfigValue>(fr_config, ""));
212   configs.push_back(util::make_unique<ResourceConfigValue>(mcc_config, ""));
213   configs.push_back(util::make_unique<ResourceConfigValue>(mcc_fr_config, ""));
214   configs.push_back(util::make_unique<ResourceConfigValue>(mnc_config, ""));
215   configs.push_back(util::make_unique<ResourceConfigValue>(mnc_fr_config, ""));
216   DominatorTree tree(configs);
217   PrettyPrinter printer;
218   std::string expected =
219       "<default>\n"
220       "de\n"
221       "fr\n"
222       "mcc262\n"
223       "mcc262-fr\n"
224       "mnc2\n"
225       "mnc2-fr\n";
226   EXPECT_EQ(expected, printer.ToString(&tree));
227 }
228 
229 }  // namespace aapt
230