TEST(XmlPullParserTest, NextChildNodeTraversesCorrectly) { std::stringstream str; str << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<a><b><c xmlns:a=\"http://schema.org\"><d/></c><e/></b></a>"; xml::XmlPullParser parser(str); const size_t depthOuter = parser.getDepth(); ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthOuter)); EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent()); EXPECT_EQ(StringPiece16(u"a"), StringPiece16(parser.getElementName())); const size_t depthA = parser.getDepth(); ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthA)); EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent()); EXPECT_EQ(StringPiece16(u"b"), StringPiece16(parser.getElementName())); const size_t depthB = parser.getDepth(); ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthB)); EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent()); EXPECT_EQ(StringPiece16(u"c"), StringPiece16(parser.getElementName())); ASSERT_TRUE(xml::XmlPullParser::nextChildNode(&parser, depthB)); EXPECT_EQ(xml::XmlPullParser::Event::kStartElement, parser.getEvent()); EXPECT_EQ(StringPiece16(u"e"), StringPiece16(parser.getElementName())); ASSERT_FALSE(xml::XmlPullParser::nextChildNode(&parser, depthOuter)); EXPECT_EQ(xml::XmlPullParser::Event::kEndDocument, parser.getEvent()); }
TEST(StringPieceTest, PiecesHaveCorrectSortOrder) { std::u16string testing(u"testing"); std::u16string banana(u"banana"); std::u16string car(u"car"); EXPECT_TRUE(StringPiece16(testing) > banana); EXPECT_TRUE(StringPiece16(testing) > car); EXPECT_TRUE(StringPiece16(banana) < testing); EXPECT_TRUE(StringPiece16(banana) < car); EXPECT_TRUE(StringPiece16(car) < testing); EXPECT_TRUE(StringPiece16(car) > banana); }
StringPiece16 trimWhitespace(const StringPiece16& str) { if (str.size() == 0 || str.data() == nullptr) { return str; } const char16_t* start = str.data(); const char16_t* end = str.data() + str.length(); while (start != end && util::isspace16(*start)) { start++; } while (end != start && util::isspace16(*(end - 1))) { end--; } return StringPiece16(start, end - start); }
bool ResourceTable::markPublicImpl(const ResourceNameRef& name, const ResourceId& resId, const SourceLine& source, const char16_t* validChars) { if (!name.package.empty() && name.package != mPackage) { Logger::error(source) << "resource '" << name << "' has incompatible package. Must be '" << mPackage << "'." << std::endl; return false; } auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars); if (badCharIter != name.entry.end()) { Logger::error(source) << "resource '" << name << "' has invalid entry name '" << name.entry << "'. Invalid character '" << StringPiece16(badCharIter, 1) << "'." << std::endl; return false; } std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type); if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId && type->typeId != resId.typeId()) { Logger::error(source) << "trying to make resource '" << name << "' public with ID " << resId << " but type '" << type->type << "' already has ID " << std::hex << type->typeId << std::dec << "." << std::endl; return false; } std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry); if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId && entry->entryId != resId.entryId()) { Logger::error(source) << "trying to make resource '" << name << "' public with ID " << resId << " but resource already has ID " << ResourceId(mPackageId, type->typeId, entry->entryId) << "." << std::endl; return false; } type->publicStatus.isPublic = true; entry->publicStatus.isPublic = true; entry->publicStatus.source = source; if (resId.isValid()) { type->typeId = resId.typeId(); entry->entryId = resId.entryId(); } return true; }
bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId& resId, const ConfigDescription& config, const SourceLine& source, std::unique_ptr<Value> value, const char16_t* validChars) { if (!name.package.empty() && name.package != mPackage) { Logger::error(source) << "resource '" << name << "' has incompatible package. Must be '" << mPackage << "'." << std::endl; return false; } auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars); if (badCharIter != name.entry.end()) { Logger::error(source) << "resource '" << name << "' has invalid entry name '" << name.entry << "'. Invalid character '" << StringPiece16(badCharIter, 1) << "'." << std::endl; return false; } std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type); if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId && type->typeId != resId.typeId()) { Logger::error(source) << "trying to add resource '" << name << "' with ID " << resId << " but type '" << type->type << "' already has ID " << std::hex << type->typeId << std::dec << "." << std::endl; return false; } std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry); if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId && entry->entryId != resId.entryId()) { Logger::error(source) << "trying to add resource '" << name << "' with ID " << resId << " but resource already has ID " << ResourceId(mPackageId, type->typeId, entry->entryId) << "." << std::endl; return false; } const auto endIter = std::end(entry->values); auto iter = std::lower_bound(std::begin(entry->values), endIter, config, compareConfigs); if (iter == endIter || iter->config != config) { // This resource did not exist before, add it. entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) }); } else { int collisionResult = defaultCollisionHandler(*iter->value, *value); if (collisionResult > 0) { // Take the incoming value. *iter = ResourceConfigValue{ config, source, {}, std::move(value) }; } else if (collisionResult == 0) { Logger::error(source) << "duplicate value for resource '" << name << "' " << "with config '" << iter->config << "'." << std::endl; Logger::error(iter->source) << "resource previously defined here." << std::endl; return false; } } if (resId.isValid()) { type->typeId = resId.typeId(); entry->entryId = resId.entryId(); } return true; }