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.isEmpty() ? "<default>" : config_string)
55             << std::endl;
56   }
57 
VisitNode(const DominatorTree::Node * node,const int indent)58   void VisitNode(const DominatorTree::Node* node, const int indent) {
59     VisitConfig(node, indent);
60     for (const auto& child : node->children()) {
61       VisitNode(child.get(), indent + indent_);
62     }
63   }
64 
65   std::stringstream buffer_;
66   const int indent_ = 2;
67 };
68 
69 }  // namespace
70 
TEST(DominatorTreeTest,DefaultDominatesEverything)71 TEST(DominatorTreeTest, DefaultDominatesEverything) {
72   const ConfigDescription default_config = {};
73   const ConfigDescription land_config = test::ParseConfigOrDie("land");
74   const ConfigDescription sw600dp_land_config = test::ParseConfigOrDie("sw600dp-land-v13");
75 
76   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
77   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
78   configs.push_back(util::make_unique<ResourceConfigValue>(land_config, ""));
79   configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_land_config, ""));
80 
81   DominatorTree tree(configs);
82   PrettyPrinter printer;
83 
84   std::string expected =
85       "<default>\n"
86       "  land\n"
87       "  sw600dp-land-v13\n";
88   EXPECT_EQ(expected, printer.ToString(&tree));
89 }
90 
TEST(DominatorTreeTest,ProductsAreDominatedSeparately)91 TEST(DominatorTreeTest, ProductsAreDominatedSeparately) {
92   const ConfigDescription default_config = {};
93   const ConfigDescription land_config = test::ParseConfigOrDie("land");
94   const ConfigDescription sw600dp_land_config = test::ParseConfigOrDie("sw600dp-land-v13");
95 
96   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
97   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
98   configs.push_back(util::make_unique<ResourceConfigValue>(land_config, ""));
99   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, "phablet"));
100   configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_land_config, "phablet"));
101 
102   DominatorTree tree(configs);
103   PrettyPrinter printer;
104 
105   std::string expected =
106       "<default>\n"
107       "  land\n"
108       "<default>\n"
109       "  sw600dp-land-v13\n";
110   EXPECT_EQ(expected, printer.ToString(&tree));
111 }
112 
TEST(DominatorTreeTest,MoreSpecificConfigurationsAreDominated)113 TEST(DominatorTreeTest, MoreSpecificConfigurationsAreDominated) {
114   const ConfigDescription default_config = {};
115   const ConfigDescription en_config = test::ParseConfigOrDie("en");
116   const ConfigDescription en_v21_config = test::ParseConfigOrDie("en-v21");
117   const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl-v4");
118   const ConfigDescription ldrtl_xhdpi_config = test::ParseConfigOrDie("ldrtl-xhdpi-v4");
119   const ConfigDescription sw300dp_config = test::ParseConfigOrDie("sw300dp-v13");
120   const ConfigDescription sw540dp_config = test::ParseConfigOrDie("sw540dp-v14");
121   const ConfigDescription sw600dp_config = test::ParseConfigOrDie("sw600dp-v14");
122   const ConfigDescription sw720dp_config = test::ParseConfigOrDie("sw720dp-v13");
123   const ConfigDescription v20_config = test::ParseConfigOrDie("v20");
124 
125   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
126   configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
127   configs.push_back(util::make_unique<ResourceConfigValue>(en_config, ""));
128   configs.push_back(util::make_unique<ResourceConfigValue>(en_v21_config, ""));
129   configs.push_back(util::make_unique<ResourceConfigValue>(ldrtl_config, ""));
130   configs.push_back(util::make_unique<ResourceConfigValue>(ldrtl_xhdpi_config, ""));
131   configs.push_back(util::make_unique<ResourceConfigValue>(sw300dp_config, ""));
132   configs.push_back(util::make_unique<ResourceConfigValue>(sw540dp_config, ""));
133   configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_config, ""));
134   configs.push_back(util::make_unique<ResourceConfigValue>(sw720dp_config, ""));
135   configs.push_back(util::make_unique<ResourceConfigValue>(v20_config, ""));
136 
137   DominatorTree tree(configs);
138   PrettyPrinter printer;
139 
140   std::string expected =
141       "<default>\n"
142       "  ldrtl-v4\n"
143       "    ldrtl-xhdpi-v4\n"
144       "  sw300dp-v13\n"
145       "    sw540dp-v14\n"
146       "      sw600dp-v14\n"
147       "    sw720dp-v13\n"
148       "  v20\n"
149       "en\n"
150       "  en-v21\n";
151   EXPECT_EQ(expected, printer.ToString(&tree));
152 }
153 
TEST(DominatorTreeTest,LocalesAreNeverDominated)154 TEST(DominatorTreeTest, LocalesAreNeverDominated) {
155   const ConfigDescription fr_config = test::ParseConfigOrDie("fr");
156   const ConfigDescription fr_rCA_config = test::ParseConfigOrDie("fr-rCA");
157   const ConfigDescription fr_rFR_config = test::ParseConfigOrDie("fr-rFR");
158 
159   std::vector<std::unique_ptr<ResourceConfigValue>> configs;
160   configs.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), ""));
161   configs.push_back(util::make_unique<ResourceConfigValue>(fr_config, ""));
162   configs.push_back(util::make_unique<ResourceConfigValue>(fr_rCA_config, ""));
163   configs.push_back(util::make_unique<ResourceConfigValue>(fr_rFR_config, ""));
164 
165   DominatorTree tree(configs);
166   PrettyPrinter printer;
167 
168   std::string expected =
169       "<default>\n"
170       "fr\n"
171       "fr-rCA\n"
172       "fr-rFR\n";
173   EXPECT_EQ(expected, printer.ToString(&tree));
174 }
175 
176 }  // namespace aapt
177