blob: cf901dae11bbf6908f2c06f8c03987a874d946a7 [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 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 "ResourceParser.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include <sstream>
20#include <string>
21
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080022#include "ResourceTable.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023#include "ResourceUtils.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include "ResourceValues.h"
Adam Lesinskid0f116b2016-07-08 15:00:32 -070025#include "test/Test.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080026#include "xml/XmlPullParser.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027
Adam Lesinskid5083f62017-01-16 15:07:21 -080028using android::StringPiece;
29
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080030namespace aapt {
31
Adam Lesinskicacb28f2016-10-19 12:18:14 -070032constexpr const char* kXmlPreamble =
33 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080034
Adam Lesinski1ab598f2015-08-14 14:26:04 -070035TEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070036 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 std::stringstream input(kXmlPreamble);
38 input << "<attr name=\"foo\"/>" << std::endl;
39 ResourceTable table;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070040 ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
41 xml::XmlPullParser xml_parser(input);
42 ASSERT_FALSE(parser.Parse(&xml_parser));
Adam Lesinski769de982015-04-10 19:43:55 -070043}
44
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045class ResourceParserTest : public ::testing::Test {
46 public:
47 void SetUp() override { context_ = test::ContextBuilder().Build(); }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070048
Adam Lesinskice5e56e2016-10-21 17:56:45 -070049 ::testing::AssertionResult TestParse(const StringPiece& str) {
50 return TestParse(str, ConfigDescription{});
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 }
Adam Lesinski52364f72016-01-11 13:10:24 -080052
Adam Lesinskice5e56e2016-10-21 17:56:45 -070053 ::testing::AssertionResult TestParse(const StringPiece& str,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070054 const ConfigDescription& config) {
55 std::stringstream input(kXmlPreamble);
56 input << "<resources>\n" << str << "\n</resources>" << std::endl;
57 ResourceParserOptions parserOptions;
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"},
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059 config, parserOptions);
60 xml::XmlPullParser xmlParser(input);
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 if (parser.Parse(&xmlParser)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 return ::testing::AssertionSuccess();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080063 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 return ::testing::AssertionFailure();
65 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070066
67 protected:
68 ResourceTable table_;
69 std::unique_ptr<IAaptContext> context_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080070};
71
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080072TEST_F(ResourceParserTest, ParseQuotedString) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 std::string input = "<string name=\"foo\"> \" hey there \" </string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -070074 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080075
Adam Lesinskice5e56e2016-10-21 17:56:45 -070076 String* str = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -070077 ASSERT_NE(nullptr, str);
78 EXPECT_EQ(std::string(" hey there "), *str->value);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080079}
80
81TEST_F(ResourceParserTest, ParseEscapedString) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070082 std::string input = "<string name=\"foo\">\\?123</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080084
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 String* str = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 ASSERT_NE(nullptr, str);
87 EXPECT_EQ(std::string("?123"), *str->value);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080088}
89
Adam Lesinski9f222042015-11-04 13:51:45 -080090TEST_F(ResourceParserTest, ParseFormattedString) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 std::string input = "<string name=\"foo\">%d %s</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 ASSERT_FALSE(TestParse(input));
Adam Lesinski9f222042015-11-04 13:51:45 -080093
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094 input = "<string name=\"foo\">%1$d %2$s</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095 ASSERT_TRUE(TestParse(input));
Adam Lesinski9f222042015-11-04 13:51:45 -080096}
97
Adam Lesinski8c3f31f2016-09-07 13:45:13 -070098TEST_F(ResourceParserTest, ParseStyledString) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070099 // Use a surrogate pair unicode point so that we can verify that the span
100 // indices
101 // use UTF-16 length and not UTF-18 length.
102 std::string input =
103 "<string name=\"foo\">This is my aunt\u2019s <b>string</b></string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700104 ASSERT_TRUE(TestParse(input));
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700105
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700107 ASSERT_NE(nullptr, str);
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700108
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700109 const std::string expected_str = "This is my aunt\u2019s string";
110 EXPECT_EQ(expected_str, *str->value->str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111 EXPECT_EQ(1u, str->value->spans.size());
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700112
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700113 EXPECT_EQ(std::string("b"), *str->value->spans[0].name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114 EXPECT_EQ(17u, str->value->spans[0].first_char);
115 EXPECT_EQ(23u, str->value->spans[0].last_char);
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700116}
117
118TEST_F(ResourceParserTest, ParseStringWithWhitespace) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700119 std::string input = "<string name=\"foo\"> This is what I think </string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700120 ASSERT_TRUE(TestParse(input));
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700121
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122 String* str = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700123 ASSERT_NE(nullptr, str);
124 EXPECT_EQ(std::string("This is what I think"), *str->value);
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700125
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700126 input = "<string name=\"foo2\">\" This is what I think \"</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700127 ASSERT_TRUE(TestParse(input));
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700128
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 str = test::GetValue<String>(&table_, "string/foo2");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700130 ASSERT_NE(nullptr, str);
131 EXPECT_EQ(std::string(" This is what I think "), *str->value);
Adam Lesinski8c3f31f2016-09-07 13:45:13 -0700132}
133
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700134TEST_F(ResourceParserTest, IgnoreXliffTags) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700135 std::string input =
136 "<string name=\"foo\" \n"
137 " xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n"
138 " There are <xliff:g id=\"count\">%1$d</xliff:g> apples</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 ASSERT_TRUE(TestParse(input));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700140
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700141 String* str = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700142 ASSERT_NE(nullptr, str);
143 EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700144}
145
Adam Lesinskidfa5e072015-05-12 21:42:59 -0700146TEST_F(ResourceParserTest, ParseNull) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700147 std::string input = "<integer name=\"foo\">@null</integer>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700148 ASSERT_TRUE(TestParse(input));
Adam Lesinskidfa5e072015-05-12 21:42:59 -0700149
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 // The Android runtime treats a value of android::Res_value::TYPE_NULL as
151 // a non-existing value, and this causes problems in styles when trying to
152 // resolve
153 // an attribute. Null values must be encoded as
154 // android::Res_value::TYPE_REFERENCE
155 // with a data value of 0.
156 BinaryPrimitive* integer =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 ASSERT_NE(nullptr, integer);
159 EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE),
160 integer->value.dataType);
161 EXPECT_EQ(0u, integer->value.data);
Adam Lesinskidfa5e072015-05-12 21:42:59 -0700162}
163
164TEST_F(ResourceParserTest, ParseEmpty) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700165 std::string input = "<integer name=\"foo\">@empty</integer>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 ASSERT_TRUE(TestParse(input));
Adam Lesinskidfa5e072015-05-12 21:42:59 -0700167
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700168 BinaryPrimitive* integer =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700169 test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700170 ASSERT_NE(nullptr, integer);
171 EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType);
172 EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data);
Adam Lesinskidfa5e072015-05-12 21:42:59 -0700173}
174
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800175TEST_F(ResourceParserTest, ParseAttr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 std::string input =
177 "<attr name=\"foo\" format=\"string\"/>\n"
178 "<attr name=\"bar\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800180
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181 Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 ASSERT_NE(nullptr, attr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700183 EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800184
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700185 attr = test::GetValue<Attribute>(&table_, "attr/bar");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 ASSERT_NE(nullptr, attr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700187 EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->type_mask);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800188}
189
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700190// Old AAPT allowed attributes to be defined under different configurations, but
191// ultimately
192// stored them with the default configuration. Check that we have the same
193// behavior.
194TEST_F(ResourceParserTest,
195 ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700196 const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700197 std::string input = R"EOF(
Adam Lesinski52364f72016-01-11 13:10:24 -0800198 <attr name="foo" />
199 <declare-styleable name="bar">
200 <attr name="baz" />
201 </declare-styleable>)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700202 ASSERT_TRUE(TestParse(input, watch_config));
Adam Lesinski52364f72016-01-11 13:10:24 -0800203
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/foo",
205 watch_config));
206 EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/baz",
207 watch_config));
208 EXPECT_EQ(nullptr, test::GetValueForConfig<Styleable>(
209 &table_, "styleable/bar", watch_config));
Adam Lesinski52364f72016-01-11 13:10:24 -0800210
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211 EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/foo"));
212 EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/baz"));
213 EXPECT_NE(nullptr, test::GetValue<Styleable>(&table_, "styleable/bar"));
Adam Lesinski52364f72016-01-11 13:10:24 -0800214}
215
Adam Lesinskia5870652015-11-20 15:32:30 -0800216TEST_F(ResourceParserTest, ParseAttrWithMinMax) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 std::string input =
218 "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700219 ASSERT_TRUE(TestParse(input));
Adam Lesinskia5870652015-11-20 15:32:30 -0800220
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700221 Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222 ASSERT_NE(nullptr, attr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700223 EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->type_mask);
224 EXPECT_EQ(10, attr->min_int);
225 EXPECT_EQ(23, attr->max_int);
Adam Lesinskia5870652015-11-20 15:32:30 -0800226}
227
228TEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700229 std::string input =
230 "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 ASSERT_FALSE(TestParse(input));
Adam Lesinskia5870652015-11-20 15:32:30 -0800232}
233
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800234TEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235 std::string input =
236 "<declare-styleable name=\"Styleable\">\n"
237 " <attr name=\"foo\" />\n"
238 "</declare-styleable>\n"
239 "<attr name=\"foo\" format=\"string\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800241
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242 Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700243 ASSERT_NE(nullptr, attr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700244 EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800245}
246
247TEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700248 std::string input =
249 "<declare-styleable name=\"Theme\">"
250 " <attr name=\"foo\" />\n"
251 "</declare-styleable>\n"
252 "<declare-styleable name=\"Window\">\n"
253 " <attr name=\"foo\" format=\"boolean\"/>\n"
254 "</declare-styleable>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700255 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800256
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700257 Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700258 ASSERT_NE(nullptr, attr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700259 EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->type_mask);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800260}
261
262TEST_F(ResourceParserTest, ParseEnumAttr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700263 std::string input =
264 "<attr name=\"foo\">\n"
265 " <enum name=\"bar\" value=\"0\"/>\n"
266 " <enum name=\"bat\" value=\"1\"/>\n"
267 " <enum name=\"baz\" value=\"2\"/>\n"
268 "</attr>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700269 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800270
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
272 ASSERT_NE(enum_attr, nullptr);
273 EXPECT_EQ(enum_attr->type_mask, android::ResTable_map::TYPE_ENUM);
274 ASSERT_EQ(enum_attr->symbols.size(), 3u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800275
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700276 AAPT_ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
277 EXPECT_EQ(enum_attr->symbols[0].symbol.name.value().entry, "bar");
278 EXPECT_EQ(enum_attr->symbols[0].value, 0u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800279
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280 AAPT_ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
281 EXPECT_EQ(enum_attr->symbols[1].symbol.name.value().entry, "bat");
282 EXPECT_EQ(enum_attr->symbols[1].value, 1u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800283
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700284 AAPT_ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
285 EXPECT_EQ(enum_attr->symbols[2].symbol.name.value().entry, "baz");
286 EXPECT_EQ(enum_attr->symbols[2].value, 2u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800287}
288
289TEST_F(ResourceParserTest, ParseFlagAttr) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700290 std::string input =
291 "<attr name=\"foo\">\n"
292 " <flag name=\"bar\" value=\"0\"/>\n"
293 " <flag name=\"bat\" value=\"1\"/>\n"
294 " <flag name=\"baz\" value=\"2\"/>\n"
295 "</attr>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700296 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800297
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700298 Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
299 ASSERT_NE(nullptr, flag_attr);
300 EXPECT_EQ(flag_attr->type_mask, android::ResTable_map::TYPE_FLAGS);
301 ASSERT_EQ(flag_attr->symbols.size(), 3u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800302
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700303 AAPT_ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
304 EXPECT_EQ(flag_attr->symbols[0].symbol.name.value().entry, "bar");
305 EXPECT_EQ(flag_attr->symbols[0].value, 0u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800306
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700307 AAPT_ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
308 EXPECT_EQ(flag_attr->symbols[1].symbol.name.value().entry, "bat");
309 EXPECT_EQ(flag_attr->symbols[1].value, 1u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800310
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700311 AAPT_ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
312 EXPECT_EQ(flag_attr->symbols[2].symbol.name.value().entry, "baz");
313 EXPECT_EQ(flag_attr->symbols[2].value, 2u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800314
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700315 std::unique_ptr<BinaryPrimitive> flag_value =
316 ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
317 ASSERT_NE(nullptr, flag_value);
318 EXPECT_EQ(flag_value->value.data, 1u | 2u);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800319}
320
321TEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700322 std::string input =
323 "<attr name=\"foo\">\n"
324 " <enum name=\"bar\" value=\"0\"/>\n"
325 " <enum name=\"bat\" value=\"1\"/>\n"
326 " <enum name=\"bat\" value=\"2\"/>\n"
327 "</attr>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700328 ASSERT_FALSE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800329}
330
331TEST_F(ResourceParserTest, ParseStyle) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700332 std::string input =
333 "<style name=\"foo\" parent=\"@style/fu\">\n"
334 " <item name=\"bar\">#ffffffff</item>\n"
335 " <item name=\"bat\">@string/hey</item>\n"
336 " <item name=\"baz\"><b>hey</b></item>\n"
337 "</style>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700338 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800339
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700340 Style* style = test::GetValue<Style>(&table_, "style/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700341 ASSERT_NE(nullptr, style);
342 AAPT_ASSERT_TRUE(style->parent);
343 AAPT_ASSERT_TRUE(style->parent.value().name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700344 EXPECT_EQ(test::ParseNameOrDie("style/fu"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700345 style->parent.value().name.value());
346 ASSERT_EQ(3u, style->entries.size());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800347
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700348 AAPT_ASSERT_TRUE(style->entries[0].key.name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700349 EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700350 style->entries[0].key.name.value());
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700351
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700352 AAPT_ASSERT_TRUE(style->entries[1].key.name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700353 EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700354 style->entries[1].key.name.value());
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700355
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700356 AAPT_ASSERT_TRUE(style->entries[2].key.name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 EXPECT_EQ(test::ParseNameOrDie("attr/baz"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700358 style->entries[2].key.name.value());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800359}
360
Adam Lesinski769de982015-04-10 19:43:55 -0700361TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700362 std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363 ASSERT_TRUE(TestParse(input));
Adam Lesinski769de982015-04-10 19:43:55 -0700364
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700365 Style* style = test::GetValue<Style>(&table_, "style/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 ASSERT_NE(nullptr, style);
367 AAPT_ASSERT_TRUE(style->parent);
368 AAPT_ASSERT_TRUE(style->parent.value().name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700369 EXPECT_EQ(test::ParseNameOrDie("com.app:style/Theme"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700370 style->parent.value().name.value());
Adam Lesinski769de982015-04-10 19:43:55 -0700371}
372
Adam Lesinski24aad162015-04-24 19:19:30 -0700373TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700374 std::string input =
375 "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n"
376 " name=\"foo\" parent=\"app:Theme\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700377 ASSERT_TRUE(TestParse(input));
Adam Lesinski24aad162015-04-24 19:19:30 -0700378
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700379 Style* style = test::GetValue<Style>(&table_, "style/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700380 ASSERT_NE(nullptr, style);
381 AAPT_ASSERT_TRUE(style->parent);
382 AAPT_ASSERT_TRUE(style->parent.value().name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700383 EXPECT_EQ(test::ParseNameOrDie("android:style/Theme"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700384 style->parent.value().name.value());
Adam Lesinski24aad162015-04-24 19:19:30 -0700385}
386
387TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700388 std::string input =
389 "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" "
390 "name=\"foo\">\n"
391 " <item name=\"app:bar\">0</item>\n"
392 "</style>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700393 ASSERT_TRUE(TestParse(input));
Adam Lesinski24aad162015-04-24 19:19:30 -0700394
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700395 Style* style = test::GetValue<Style>(&table_, "style/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700396 ASSERT_NE(nullptr, style);
397 ASSERT_EQ(1u, style->entries.size());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700398 EXPECT_EQ(test::ParseNameOrDie("android:attr/bar"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700399 style->entries[0].key.name.value());
Adam Lesinski24aad162015-04-24 19:19:30 -0700400}
401
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700402TEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700403 std::string input = "<style name=\"foo.bar\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700404 ASSERT_TRUE(TestParse(input));
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700405
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700406 Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700407 ASSERT_NE(nullptr, style);
408 AAPT_ASSERT_TRUE(style->parent);
409 AAPT_ASSERT_TRUE(style->parent.value().name);
410 EXPECT_EQ(style->parent.value().name.value(),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700411 test::ParseNameOrDie("style/foo"));
412 EXPECT_TRUE(style->parent_inferred);
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700413}
414
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700415TEST_F(ResourceParserTest,
416 ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
417 std::string input = "<style name=\"foo.bar\" parent=\"\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700418 ASSERT_TRUE(TestParse(input));
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700419
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700420 Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700421 ASSERT_NE(nullptr, style);
422 AAPT_EXPECT_FALSE(style->parent);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700423 EXPECT_FALSE(style->parent_inferred);
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700424}
425
Adam Lesinski24b8ff02015-12-16 14:01:57 -0800426TEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700427 std::string input =
428 R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700429 ASSERT_TRUE(TestParse(input));
Adam Lesinski24b8ff02015-12-16 14:01:57 -0800430
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700431 Style* style = test::GetValue<Style>(&table_, "style/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700432 ASSERT_NE(nullptr, style);
433 AAPT_ASSERT_TRUE(style->parent);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700434 EXPECT_TRUE(style->parent.value().private_reference);
Adam Lesinski24b8ff02015-12-16 14:01:57 -0800435}
436
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800437TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700438 std::string input = "<string name=\"foo\">@+id/bar</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700439 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800440
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700441 Id* id = test::GetValue<Id>(&table_, "id/bar");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700442 ASSERT_NE(id, nullptr);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800443}
444
445TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700446 std::string input =
447 "<declare-styleable name=\"foo\">\n"
448 " <attr name=\"bar\" />\n"
449 " <attr name=\"bat\" format=\"string|reference\"/>\n"
450 " <attr name=\"baz\">\n"
451 " <enum name=\"foo\" value=\"1\"/>\n"
452 " </attr>\n"
453 "</declare-styleable>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700454 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800455
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700456 Maybe<ResourceTable::SearchResult> result =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700457 table_.FindResource(test::ParseNameOrDie("styleable/foo"));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700458 AAPT_ASSERT_TRUE(result);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700459 EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state);
Adam Lesinski9f222042015-11-04 13:51:45 -0800460
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700461 Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700462 ASSERT_NE(attr, nullptr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700463 EXPECT_TRUE(attr->IsWeak());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800464
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700465 attr = test::GetValue<Attribute>(&table_, "attr/bat");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700466 ASSERT_NE(attr, nullptr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700467 EXPECT_TRUE(attr->IsWeak());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800468
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700469 attr = test::GetValue<Attribute>(&table_, "attr/baz");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700470 ASSERT_NE(attr, nullptr);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700471 EXPECT_TRUE(attr->IsWeak());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700472 EXPECT_EQ(1u, attr->symbols.size());
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700473
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700474 EXPECT_NE(nullptr, test::GetValue<Id>(&table_, "id/foo"));
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700475
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700476 Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700477 ASSERT_NE(styleable, nullptr);
478 ASSERT_EQ(3u, styleable->entries.size());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800479
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700480 EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700481 styleable->entries[0].name.value());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700482 EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700483 styleable->entries[1].name.value());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800484}
485
Adam Lesinski467f1712015-11-16 17:35:44 -0800486TEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700487 std::string input =
488 "<declare-styleable name=\"foo\" "
489 "xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n"
490 " <attr name=\"*android:bar\" />\n"
491 " <attr name=\"privAndroid:bat\" />\n"
492 "</declare-styleable>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700493 ASSERT_TRUE(TestParse(input));
494 Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700495 ASSERT_NE(nullptr, styleable);
496 ASSERT_EQ(2u, styleable->entries.size());
Adam Lesinski467f1712015-11-16 17:35:44 -0800497
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700498 EXPECT_TRUE(styleable->entries[0].private_reference);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700499 AAPT_ASSERT_TRUE(styleable->entries[0].name);
500 EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package);
Adam Lesinski467f1712015-11-16 17:35:44 -0800501
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700502 EXPECT_TRUE(styleable->entries[1].private_reference);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700503 AAPT_ASSERT_TRUE(styleable->entries[1].name);
504 EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package);
Adam Lesinski467f1712015-11-16 17:35:44 -0800505}
506
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800507TEST_F(ResourceParserTest, ParseArray) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700508 std::string input =
509 "<array name=\"foo\">\n"
510 " <item>@string/ref</item>\n"
511 " <item>hey</item>\n"
512 " <item>23</item>\n"
513 "</array>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700514 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800515
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700516 Array* array = test::GetValue<Array>(&table_, "array/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700517 ASSERT_NE(array, nullptr);
518 ASSERT_EQ(3u, array->items.size());
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800519
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700520 EXPECT_NE(nullptr, ValueCast<Reference>(array->items[0].get()));
521 EXPECT_NE(nullptr, ValueCast<String>(array->items[1].get()));
522 EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(array->items[2].get()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800523}
524
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700525TEST_F(ResourceParserTest, ParseStringArray) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700526 std::string input =
527 "<string-array name=\"foo\">\n"
528 " <item>\"Werk\"</item>\n"
529 "</string-array>\n";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700530 ASSERT_TRUE(TestParse(input));
531 EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700532}
533
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800534TEST_F(ResourceParserTest, ParsePlural) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700535 std::string input =
536 "<plurals name=\"foo\">\n"
537 " <item quantity=\"other\">apples</item>\n"
538 " <item quantity=\"one\">apple</item>\n"
539 "</plurals>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700540 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800541}
542
543TEST_F(ResourceParserTest, ParseCommentsWithResource) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700544 std::string input =
545 "<!--This is a comment-->\n"
546 "<string name=\"foo\">Hi</string>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700547 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800548
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700549 String* value = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700550 ASSERT_NE(nullptr, value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700551 EXPECT_EQ(value->GetComment(), "This is a comment");
Adam Lesinskie78fd612015-10-22 12:48:43 -0700552}
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700553
Adam Lesinskie78fd612015-10-22 12:48:43 -0700554TEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700555 std::string input =
556 "<!--One-->\n"
557 "<!--Two-->\n"
558 "<string name=\"foo\">Hi</string>";
Adam Lesinskie78fd612015-10-22 12:48:43 -0700559
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700560 ASSERT_TRUE(TestParse(input));
Adam Lesinskie78fd612015-10-22 12:48:43 -0700561
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700562 String* value = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700563 ASSERT_NE(nullptr, value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700564 EXPECT_EQ(value->GetComment(), "Two");
Adam Lesinskie78fd612015-10-22 12:48:43 -0700565}
566
567TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700568 std::string input =
569 "<!--One-->\n"
570 "<string name=\"foo\">\n"
571 " Hi\n"
572 "<!--Two-->\n"
573 "</string>";
Adam Lesinskie78fd612015-10-22 12:48:43 -0700574
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700575 ASSERT_TRUE(TestParse(input));
Adam Lesinskie78fd612015-10-22 12:48:43 -0700576
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700577 String* value = test::GetValue<String>(&table_, "string/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700578 ASSERT_NE(nullptr, value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700579 EXPECT_EQ(value->GetComment(), "One");
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800580}
581
Adam Lesinskica5638f2015-10-21 14:42:43 -0700582TEST_F(ResourceParserTest, ParseNestedComments) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700583 // We only care about declare-styleable and enum/flag attributes because
584 // comments
585 // from those end up in R.java
586 std::string input = R"EOF(
Adam Lesinskica5638f2015-10-21 14:42:43 -0700587 <declare-styleable name="foo">
588 <!-- The name of the bar -->
589 <attr name="barName" format="string|reference" />
590 </declare-styleable>
591
592 <attr name="foo">
593 <!-- The very first -->
594 <enum name="one" value="1" />
595 </attr>)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700596 ASSERT_TRUE(TestParse(input));
Adam Lesinskica5638f2015-10-21 14:42:43 -0700597
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700598 Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700599 ASSERT_NE(nullptr, styleable);
600 ASSERT_EQ(1u, styleable->entries.size());
Adam Lesinskica5638f2015-10-21 14:42:43 -0700601
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700602 EXPECT_EQ(StringPiece("The name of the bar"),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700603 styleable->entries.front().GetComment());
Adam Lesinskica5638f2015-10-21 14:42:43 -0700604
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700605 Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700606 ASSERT_NE(nullptr, attr);
607 ASSERT_EQ(1u, attr->symbols.size());
Adam Lesinskica5638f2015-10-21 14:42:43 -0700608
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700609 EXPECT_EQ(StringPiece("The very first"),
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700610 attr->symbols.front().symbol.GetComment());
Adam Lesinskica5638f2015-10-21 14:42:43 -0700611}
612
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800613/*
614 * Declaring an ID as public should not require a separate definition
615 * (as an ID has no value).
616 */
617TEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700618 std::string input = "<public type=\"id\" name=\"foo\"/>";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700619 ASSERT_TRUE(TestParse(input));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800620
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700621 Id* id = test::GetValue<Id>(&table_, "id/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700622 ASSERT_NE(nullptr, id);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800623}
624
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800625TEST_F(ResourceParserTest, KeepAllProducts) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700626 std::string input = R"EOF(
Adam Lesinski7751afc2016-01-06 15:45:28 -0800627 <string name="foo" product="phone">hi</string>
628 <string name="foo" product="no-sdcard">ho</string>
629 <string name="bar" product="">wee</string>
630 <string name="baz">woo</string>
631 <string name="bit" product="phablet">hoot</string>
632 <string name="bot" product="default">yes</string>
633 )EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700634 ASSERT_TRUE(TestParse(input));
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700635
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700636 EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
637 &table_, "string/foo",
638 ConfigDescription::DefaultConfig(), "phone"));
639 EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
640 &table_, "string/foo",
641 ConfigDescription::DefaultConfig(), "no-sdcard"));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700642 EXPECT_NE(nullptr,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700643 test::GetValueForConfigAndProduct<String>(
644 &table_, "string/bar", ConfigDescription::DefaultConfig(), ""));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700645 EXPECT_NE(nullptr,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700646 test::GetValueForConfigAndProduct<String>(
647 &table_, "string/baz", ConfigDescription::DefaultConfig(), ""));
648 EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
649 &table_, "string/bit",
650 ConfigDescription::DefaultConfig(), "phablet"));
651 EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
652 &table_, "string/bot",
653 ConfigDescription::DefaultConfig(), "default"));
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700654}
655
Adam Lesinski27afb9e2015-11-06 18:25:04 -0800656TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700657 std::string input = R"EOF(
Adam Lesinski27afb9e2015-11-06 18:25:04 -0800658 <public-group type="attr" first-id="0x01010040">
659 <public name="foo" />
660 <public name="bar" />
661 </public-group>)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700662 ASSERT_TRUE(TestParse(input));
Adam Lesinski27afb9e2015-11-06 18:25:04 -0800663
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700664 Maybe<ResourceTable::SearchResult> result =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700665 table_.FindResource(test::ParseNameOrDie("attr/foo"));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700666 AAPT_ASSERT_TRUE(result);
Adam Lesinski27afb9e2015-11-06 18:25:04 -0800667
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700668 AAPT_ASSERT_TRUE(result.value().package->id);
669 AAPT_ASSERT_TRUE(result.value().type->id);
670 AAPT_ASSERT_TRUE(result.value().entry->id);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700671 ResourceId actual_id(result.value().package->id.value(),
672 result.value().type->id.value(),
673 result.value().entry->id.value());
674 EXPECT_EQ(ResourceId(0x01010040), actual_id);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700675
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700676 result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700677 AAPT_ASSERT_TRUE(result);
678
679 AAPT_ASSERT_TRUE(result.value().package->id);
680 AAPT_ASSERT_TRUE(result.value().type->id);
681 AAPT_ASSERT_TRUE(result.value().entry->id);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700682 actual_id = ResourceId(result.value().package->id.value(),
683 result.value().type->id.value(),
684 result.value().entry->id.value());
685 EXPECT_EQ(ResourceId(0x01010041), actual_id);
Adam Lesinski27afb9e2015-11-06 18:25:04 -0800686}
687
Adam Lesinskifa105052015-11-07 13:34:39 -0800688TEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700689 std::string input =
690 R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700691 ASSERT_TRUE(TestParse(input));
Adam Lesinskifa105052015-11-07 13:34:39 -0800692
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700693 input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700694 ASSERT_FALSE(TestParse(input));
Adam Lesinskifa105052015-11-07 13:34:39 -0800695}
696
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700697TEST_F(ResourceParserTest,
698 AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
699 std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700700 ASSERT_TRUE(TestParse(input));
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800701
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700702 Maybe<ResourceTable::SearchResult> result =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700703 table_.FindResource(test::ParseNameOrDie("string/bar"));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700704 AAPT_ASSERT_TRUE(result);
705 const ResourceEntry* entry = result.value().entry;
706 ASSERT_NE(nullptr, entry);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700707 EXPECT_EQ(SymbolState::kUndefined, entry->symbol_status.state);
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800708}
709
Adam Lesinski7ff3ee12015-12-14 16:08:50 -0800710TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700711 std::string input =
712 R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700713 ASSERT_TRUE(TestParse(input));
Adam Lesinski7ff3ee12015-12-14 16:08:50 -0800714
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700715 BinaryPrimitive* val =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700716 test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700717 ASSERT_NE(nullptr, val);
Adam Lesinski7ff3ee12015-12-14 16:08:50 -0800718
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700719 EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
Adam Lesinski7ff3ee12015-12-14 16:08:50 -0800720}
721
Adam Lesinski86d67df2017-01-31 13:47:27 -0800722TEST_F(ResourceParserTest, ParseConfigVaryingItem) {
723 std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF";
724 ASSERT_TRUE(TestParse(input));
725 ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo"));
726}
727
728TEST_F(ResourceParserTest, ParseBagElement) {
729 std::string input =
730 R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF";
731 ASSERT_TRUE(TestParse(input));
732
733 Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
734 ASSERT_NE(nullptr, val);
735
736 ASSERT_EQ(1u, val->entries.size());
737 EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key);
738 EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get()));
739}
740
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700741} // namespace aapt