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
26namespace aapt {
27
28namespace {
29
30class PrettyPrinter : public DominatorTree::Visitor {
31 public:
32  explicit PrettyPrinter(const int indent = 2) : indent_(indent) {}
33
34  void VisitTree(const std::string& product,
35                 DominatorTree::Node* root) override {
36    for (auto& child : root->children()) {
37      VisitNode(child.get(), 0);
38    }
39  }
40
41  std::string ToString(DominatorTree* tree) {
42    buffer_.str("");
43    buffer_.clear();
44    tree->Accept(this);
45    return buffer_.str();
46  }
47
48 private:
49  void VisitConfig(const DominatorTree::Node* node, const int indent) {
50    auto config_string = node->value()->config.toString();
51    buffer_ << std::string(indent, ' ')
52            << (config_string.isEmpty() ? "<default>" : config_string)
53            << std::endl;
54  }
55
56  void VisitNode(const DominatorTree::Node* node, const int indent) {
57    VisitConfig(node, indent);
58    for (const auto& child : node->children()) {
59      VisitNode(child.get(), indent + indent_);
60    }
61  }
62
63  std::stringstream buffer_;
64  const int indent_ = 2;
65};
66
67}  // namespace
68
69TEST(DominatorTreeTest, DefaultDominatesEverything) {
70  const ConfigDescription default_config = {};
71  const ConfigDescription land_config = test::ParseConfigOrDie("land");
72  const ConfigDescription sw600dp_land_config =
73      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(
79      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
91TEST(DominatorTreeTest, ProductsAreDominatedSeparately) {
92  const ConfigDescription default_config = {};
93  const ConfigDescription land_config = test::ParseConfigOrDie("land");
94  const ConfigDescription sw600dp_land_config =
95      test::ParseConfigOrDie("sw600dp-land-v13");
96
97  std::vector<std::unique_ptr<ResourceConfigValue>> configs;
98  configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
99  configs.push_back(util::make_unique<ResourceConfigValue>(land_config, ""));
100  configs.push_back(
101      util::make_unique<ResourceConfigValue>(default_config, "phablet"));
102  configs.push_back(
103      util::make_unique<ResourceConfigValue>(sw600dp_land_config, "phablet"));
104
105  DominatorTree tree(configs);
106  PrettyPrinter printer;
107
108  std::string expected =
109      "<default>\n"
110      "  land\n"
111      "<default>\n"
112      "  sw600dp-land-v13\n";
113  EXPECT_EQ(expected, printer.ToString(&tree));
114}
115
116TEST(DominatorTreeTest, MoreSpecificConfigurationsAreDominated) {
117  const ConfigDescription default_config = {};
118  const ConfigDescription en_config = test::ParseConfigOrDie("en");
119  const ConfigDescription en_v21_config = test::ParseConfigOrDie("en-v21");
120  const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl-v4");
121  const ConfigDescription ldrtl_xhdpi_config =
122      test::ParseConfigOrDie("ldrtl-xhdpi-v4");
123  const ConfigDescription sw300dp_config =
124      test::ParseConfigOrDie("sw300dp-v13");
125  const ConfigDescription sw540dp_config =
126      test::ParseConfigOrDie("sw540dp-v14");
127  const ConfigDescription sw600dp_config =
128      test::ParseConfigOrDie("sw600dp-v14");
129  const ConfigDescription sw720dp_config =
130      test::ParseConfigOrDie("sw720dp-v13");
131  const ConfigDescription v20_config = test::ParseConfigOrDie("v20");
132
133  std::vector<std::unique_ptr<ResourceConfigValue>> configs;
134  configs.push_back(util::make_unique<ResourceConfigValue>(default_config, ""));
135  configs.push_back(util::make_unique<ResourceConfigValue>(en_config, ""));
136  configs.push_back(util::make_unique<ResourceConfigValue>(en_v21_config, ""));
137  configs.push_back(util::make_unique<ResourceConfigValue>(ldrtl_config, ""));
138  configs.push_back(
139      util::make_unique<ResourceConfigValue>(ldrtl_xhdpi_config, ""));
140  configs.push_back(util::make_unique<ResourceConfigValue>(sw300dp_config, ""));
141  configs.push_back(util::make_unique<ResourceConfigValue>(sw540dp_config, ""));
142  configs.push_back(util::make_unique<ResourceConfigValue>(sw600dp_config, ""));
143  configs.push_back(util::make_unique<ResourceConfigValue>(sw720dp_config, ""));
144  configs.push_back(util::make_unique<ResourceConfigValue>(v20_config, ""));
145
146  DominatorTree tree(configs);
147  PrettyPrinter printer;
148
149  std::string expected =
150      "<default>\n"
151      "  en\n"
152      "    en-v21\n"
153      "  ldrtl-v4\n"
154      "    ldrtl-xhdpi-v4\n"
155      "  sw300dp-v13\n"
156      "    sw540dp-v14\n"
157      "      sw600dp-v14\n"
158      "    sw720dp-v13\n"
159      "  v20\n";
160  EXPECT_EQ(expected, printer.ToString(&tree));
161}
162
163}  // namespace aapt
164