Loading libs/androidfw/ResourceTypes.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -2880,14 +2880,13 @@ bool ResTable_config::isBetterThan(const ResTable_config& o, } } if (version || o.version) { if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { if ((version || o.version) && requested->version) { if (sdkVersion != o.sdkVersion) { return (sdkVersion > o.sdkVersion); } if ((minorVersion != o.minorVersion) && requested->minorVersion) { return (minorVersion); if (minorVersion != o.minorVersion) { return (minorVersion > o.minorVersion); } } Loading Loading @@ -3077,11 +3076,16 @@ bool ResTable_config::match(const ResTable_config& settings) const { return false; } } if (version != 0) { if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) { return false; } if (minorVersion != 0 && minorVersion != settings.minorVersion) { if (minorVersion != 0) { if (sdkVersion == 0) { // The version is 0.x. sdkVersion of 0 is not really valid. Therefore if it's 0, // we shouldn't allow a minorVersion (unless it's also 0). return false; } if (sdkVersion == settings.sdkVersion && minorVersion > settings.minorVersion) { return false; } } Loading libs/androidfw/include/androidfw/ResourceTypes.h +3 −2 Original line number Diff line number Diff line Loading @@ -1143,8 +1143,9 @@ struct ResTable_config union { struct { uint16_t sdkVersion; // For now minorVersion must always be 0!!! Its meaning // is currently undefined. // Until Baklava, this was always set to and assumed to be 0. // After Baklava, this started to be used with minor SDK releases. uint16_t minorVersion; }; uint32_t version; Loading libs/androidfw/tests/Config_test.cpp +123 −16 Original line number Diff line number Diff line Loading @@ -14,6 +14,9 @@ * limitations under the License. */ #include <vector> #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" #include "utils/Log.h" Loading @@ -23,15 +26,15 @@ #include "TestHelpers.h" #include "gtest/gtest.h" using ::android::ConfigDescription; namespace android { static ResTable_config selectBest(const ResTable_config& target, const Vector<ResTable_config>& configs) { const std::vector<ResTable_config>& configs) { ResTable_config bestConfig; memset(&bestConfig, 0, sizeof(bestConfig)); const size_t configCount = configs.size(); for (size_t i = 0; i < configCount; i++) { const ResTable_config& thisConfig = configs[i]; for (const auto& thisConfig : configs) { if (!thisConfig.match(target)) { continue; } Loading @@ -57,34 +60,34 @@ TEST(ConfigTest, shouldSelectBestDensity) { deviceConfig.density = ResTable_config::DENSITY_XHIGH; deviceConfig.sdkVersion = 21; Vector<ResTable_config> configs; std::vector<ResTable_config> configs; ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_HIGH); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_XXHIGH); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(int(ResTable_config::DENSITY_XXHIGH) - 20); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20)); configs.push_back(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20)); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); configs.add(buildDensityConfig(int(ResTable_config::DENSITY_XHIGH) - 1)); configs.push_back(buildDensityConfig(int(ResTable_config::DENSITY_XHIGH) - 1)); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY); expectedBest.sdkVersion = 21; configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); } Loading @@ -93,16 +96,16 @@ TEST(ConfigTest, shouldSelectBestDensityWhenNoneSpecified) { memset(&deviceConfig, 0, sizeof(deviceConfig)); deviceConfig.sdkVersion = 21; Vector<ResTable_config> configs; configs.add(buildDensityConfig(ResTable_config::DENSITY_HIGH)); std::vector<ResTable_config> configs; configs.push_back(buildDensityConfig(ResTable_config::DENSITY_HIGH)); ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_MEDIUM); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); } Loading Loading @@ -219,4 +222,108 @@ TEST(ConfigTest, GrammaticalGender) { EXPECT_EQ(masculine.diff(feminine), ResTable_config::CONFIG_GRAMMATICAL_GENDER); } static ResTable_config Cfg(StringPiece str) { ConfigDescription config = {}; // We're assuming str will successfully parse, to simplify writing tests ConfigDescription::Parse(str, &config); return config; } TEST(ConfigTest, SdkAndMinorVersion_Match) { // Left is resource version, right is platform version EXPECT_TRUE(Cfg("").match(Cfg("v41"))); EXPECT_TRUE(Cfg("").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v41"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v41.1").match(Cfg("v41"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v41.2").match(Cfg("v41"))); EXPECT_FALSE(Cfg("v41.2").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41.2").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v41.2").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v41.2").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v42").match(Cfg("v41"))); EXPECT_FALSE(Cfg("v42").match(Cfg("v41.1"))); EXPECT_FALSE(Cfg("v42").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v42").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v42").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v41"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v41.1"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v41.2"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v42.1").match(Cfg("v42.1"))); // ConfigDescription::Parse doesn't allow "v0.3" so we have to create it manually to test ResTable_config config = {}; config.sdkVersion = 0; config.minorVersion = 3; EXPECT_FALSE(config.match(Cfg("v41"))); } TEST(ConfigTest, SdkAndMinorVersion_IsBetterThan) { ResTable_config requested = Cfg("v45"); EXPECT_FALSE(Cfg("v40").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41.1").isBetterThan(Cfg("v41"), &requested)); EXPECT_TRUE(Cfg("v41.2").isBetterThan(Cfg("v41.1"), &requested)); EXPECT_TRUE(Cfg("v42").isBetterThan(Cfg("v41.2"), &requested)); EXPECT_TRUE(Cfg("v43.1").isBetterThan(Cfg("v42"), &requested)); requested = Cfg("v45.9"); EXPECT_FALSE(Cfg("v40").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41.1").isBetterThan(Cfg("v41"), &requested)); EXPECT_TRUE(Cfg("v41.2").isBetterThan(Cfg("v41.1"), &requested)); EXPECT_TRUE(Cfg("v42").isBetterThan(Cfg("v41.2"), &requested)); EXPECT_TRUE(Cfg("v43.1").isBetterThan(Cfg("v42"), &requested)); // isBetterThan defaults to isMoreSpecificThan if requested is null EXPECT_FALSE(Cfg("v40").isBetterThan(Cfg("v40"), nullptr)); EXPECT_FALSE(Cfg("v41").isBetterThan(Cfg("v40"), nullptr)); EXPECT_TRUE(Cfg("v41.1").isBetterThan(Cfg("v41"), nullptr)); EXPECT_FALSE(Cfg("v41.2").isBetterThan(Cfg("v41.1"), nullptr)); EXPECT_FALSE(Cfg("v42").isBetterThan(Cfg("v41.2"), nullptr)); EXPECT_TRUE(Cfg("v43.1").isBetterThan(Cfg("v42"), nullptr)); } TEST(ConfigTest, SdkAndMinorVersion_SelectBest) { ResTable_config requested = Cfg("v45"); EXPECT_STREQ("v42", selectBest(requested, {Cfg("v40"), Cfg("v42"), Cfg("v41")}).toString()); EXPECT_STREQ("v42.3", selectBest(requested, {Cfg("v40.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.3"), Cfg("v41.2"), Cfg("v42.5")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42"), Cfg("v42.5"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v44", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v44")}).toString()); requested = Cfg("v45.9"); EXPECT_STREQ("v42", selectBest(requested, {Cfg("v40"), Cfg("v42"), Cfg("v41")}).toString()); EXPECT_STREQ("v42.3", selectBest(requested, {Cfg("v40.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.3"), Cfg("v41.2"), Cfg("v42.5")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42"), Cfg("v42.5"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v44", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v44")}).toString()); EXPECT_STREQ("v45.6", selectBest(requested, {Cfg("v45.3"), Cfg("45"), Cfg("v45.6")}).toString()); } } // namespace android. Loading
libs/androidfw/ResourceTypes.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -2880,14 +2880,13 @@ bool ResTable_config::isBetterThan(const ResTable_config& o, } } if (version || o.version) { if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { if ((version || o.version) && requested->version) { if (sdkVersion != o.sdkVersion) { return (sdkVersion > o.sdkVersion); } if ((minorVersion != o.minorVersion) && requested->minorVersion) { return (minorVersion); if (minorVersion != o.minorVersion) { return (minorVersion > o.minorVersion); } } Loading Loading @@ -3077,11 +3076,16 @@ bool ResTable_config::match(const ResTable_config& settings) const { return false; } } if (version != 0) { if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) { return false; } if (minorVersion != 0 && minorVersion != settings.minorVersion) { if (minorVersion != 0) { if (sdkVersion == 0) { // The version is 0.x. sdkVersion of 0 is not really valid. Therefore if it's 0, // we shouldn't allow a minorVersion (unless it's also 0). return false; } if (sdkVersion == settings.sdkVersion && minorVersion > settings.minorVersion) { return false; } } Loading
libs/androidfw/include/androidfw/ResourceTypes.h +3 −2 Original line number Diff line number Diff line Loading @@ -1143,8 +1143,9 @@ struct ResTable_config union { struct { uint16_t sdkVersion; // For now minorVersion must always be 0!!! Its meaning // is currently undefined. // Until Baklava, this was always set to and assumed to be 0. // After Baklava, this started to be used with minor SDK releases. uint16_t minorVersion; }; uint32_t version; Loading
libs/androidfw/tests/Config_test.cpp +123 −16 Original line number Diff line number Diff line Loading @@ -14,6 +14,9 @@ * limitations under the License. */ #include <vector> #include "androidfw/ConfigDescription.h" #include "androidfw/ResourceTypes.h" #include "utils/Log.h" Loading @@ -23,15 +26,15 @@ #include "TestHelpers.h" #include "gtest/gtest.h" using ::android::ConfigDescription; namespace android { static ResTable_config selectBest(const ResTable_config& target, const Vector<ResTable_config>& configs) { const std::vector<ResTable_config>& configs) { ResTable_config bestConfig; memset(&bestConfig, 0, sizeof(bestConfig)); const size_t configCount = configs.size(); for (size_t i = 0; i < configCount; i++) { const ResTable_config& thisConfig = configs[i]; for (const auto& thisConfig : configs) { if (!thisConfig.match(target)) { continue; } Loading @@ -57,34 +60,34 @@ TEST(ConfigTest, shouldSelectBestDensity) { deviceConfig.density = ResTable_config::DENSITY_XHIGH; deviceConfig.sdkVersion = 21; Vector<ResTable_config> configs; std::vector<ResTable_config> configs; ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_HIGH); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_XXHIGH); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(int(ResTable_config::DENSITY_XXHIGH) - 20); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20)); configs.push_back(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20)); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); configs.add(buildDensityConfig(int(ResTable_config::DENSITY_XHIGH) - 1)); configs.push_back(buildDensityConfig(int(ResTable_config::DENSITY_XHIGH) - 1)); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY); expectedBest.sdkVersion = 21; configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); } Loading @@ -93,16 +96,16 @@ TEST(ConfigTest, shouldSelectBestDensityWhenNoneSpecified) { memset(&deviceConfig, 0, sizeof(deviceConfig)); deviceConfig.sdkVersion = 21; Vector<ResTable_config> configs; configs.add(buildDensityConfig(ResTable_config::DENSITY_HIGH)); std::vector<ResTable_config> configs; configs.push_back(buildDensityConfig(ResTable_config::DENSITY_HIGH)); ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_MEDIUM); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY); configs.add(expectedBest); configs.push_back(expectedBest); ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); } Loading Loading @@ -219,4 +222,108 @@ TEST(ConfigTest, GrammaticalGender) { EXPECT_EQ(masculine.diff(feminine), ResTable_config::CONFIG_GRAMMATICAL_GENDER); } static ResTable_config Cfg(StringPiece str) { ConfigDescription config = {}; // We're assuming str will successfully parse, to simplify writing tests ConfigDescription::Parse(str, &config); return config; } TEST(ConfigTest, SdkAndMinorVersion_Match) { // Left is resource version, right is platform version EXPECT_TRUE(Cfg("").match(Cfg("v41"))); EXPECT_TRUE(Cfg("").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v41"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v41").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v41.1").match(Cfg("v41"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v41.1").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v41.2").match(Cfg("v41"))); EXPECT_FALSE(Cfg("v41.2").match(Cfg("v41.1"))); EXPECT_TRUE(Cfg("v41.2").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v41.2").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v41.2").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v42").match(Cfg("v41"))); EXPECT_FALSE(Cfg("v42").match(Cfg("v41.1"))); EXPECT_FALSE(Cfg("v42").match(Cfg("v41.2"))); EXPECT_TRUE(Cfg("v42").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v42").match(Cfg("v42.1"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v41"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v41.1"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v41.2"))); EXPECT_FALSE(Cfg("v42.1").match(Cfg("v42"))); EXPECT_TRUE(Cfg("v42.1").match(Cfg("v42.1"))); // ConfigDescription::Parse doesn't allow "v0.3" so we have to create it manually to test ResTable_config config = {}; config.sdkVersion = 0; config.minorVersion = 3; EXPECT_FALSE(config.match(Cfg("v41"))); } TEST(ConfigTest, SdkAndMinorVersion_IsBetterThan) { ResTable_config requested = Cfg("v45"); EXPECT_FALSE(Cfg("v40").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41.1").isBetterThan(Cfg("v41"), &requested)); EXPECT_TRUE(Cfg("v41.2").isBetterThan(Cfg("v41.1"), &requested)); EXPECT_TRUE(Cfg("v42").isBetterThan(Cfg("v41.2"), &requested)); EXPECT_TRUE(Cfg("v43.1").isBetterThan(Cfg("v42"), &requested)); requested = Cfg("v45.9"); EXPECT_FALSE(Cfg("v40").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41").isBetterThan(Cfg("v40"), &requested)); EXPECT_TRUE(Cfg("v41.1").isBetterThan(Cfg("v41"), &requested)); EXPECT_TRUE(Cfg("v41.2").isBetterThan(Cfg("v41.1"), &requested)); EXPECT_TRUE(Cfg("v42").isBetterThan(Cfg("v41.2"), &requested)); EXPECT_TRUE(Cfg("v43.1").isBetterThan(Cfg("v42"), &requested)); // isBetterThan defaults to isMoreSpecificThan if requested is null EXPECT_FALSE(Cfg("v40").isBetterThan(Cfg("v40"), nullptr)); EXPECT_FALSE(Cfg("v41").isBetterThan(Cfg("v40"), nullptr)); EXPECT_TRUE(Cfg("v41.1").isBetterThan(Cfg("v41"), nullptr)); EXPECT_FALSE(Cfg("v41.2").isBetterThan(Cfg("v41.1"), nullptr)); EXPECT_FALSE(Cfg("v42").isBetterThan(Cfg("v41.2"), nullptr)); EXPECT_TRUE(Cfg("v43.1").isBetterThan(Cfg("v42"), nullptr)); } TEST(ConfigTest, SdkAndMinorVersion_SelectBest) { ResTable_config requested = Cfg("v45"); EXPECT_STREQ("v42", selectBest(requested, {Cfg("v40"), Cfg("v42"), Cfg("v41")}).toString()); EXPECT_STREQ("v42.3", selectBest(requested, {Cfg("v40.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.3"), Cfg("v41.2"), Cfg("v42.5")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42"), Cfg("v42.5"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v44", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v44")}).toString()); requested = Cfg("v45.9"); EXPECT_STREQ("v42", selectBest(requested, {Cfg("v40"), Cfg("v42"), Cfg("v41")}).toString()); EXPECT_STREQ("v42.3", selectBest(requested, {Cfg("v40.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42.3"), Cfg("v41.2"), Cfg("v42.5")}).toString()); EXPECT_STREQ("v42.5", selectBest(requested, {Cfg("v42"), Cfg("v42.5"), Cfg("v41.2")}).toString()); EXPECT_STREQ("v44", selectBest(requested, {Cfg("v42.5"), Cfg("v42.3"), Cfg("v44")}).toString()); EXPECT_STREQ("v45.6", selectBest(requested, {Cfg("v45.3"), Cfg("45"), Cfg("v45.6")}).toString()); } } // namespace android.