From d17a6885253da909e376ba5ca5084f5281f3557c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 9 Jan 2017 11:18:29 -0800 Subject: [PATCH] Add checkers and tests for empty locale in PNG file match_locale() will return false for empty locale string in the PNG file. Also add a manual test to validate if a PNG file is qualified to use under recovery. Bug: 34054052 Test: recovery_manual_test catches invalid PNG files successfully & Locale_test passed Change-Id: Id7e2136e1d8abf20da15825aa7901effbced8b03 --- README.md | 7 ++ minui/resources.cpp | 4 +- tests/Android.mk | 28 ++++++- tests/manual/recovery_test.cpp | 138 +++++++++++++++++++++++++++++++++ tests/unit/locale_test.cpp | 3 + 5 files changed, 177 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dc3d44e6..8e20b5a6 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,10 @@ Running the manual tests - Reboot the device immediately and run the test again. The test should save the contents of pmsg buffer into /data/misc/recovery/inject.txt. Test will pass if this file has expected contents. + +`ResourceTest` validates whether the png files are qualified as background text +image under recovery. + + 1. `adb sync data` to make sure the test-dir has the images to test. + 2. The test will automatically pickup and verify all `_text.png` files in + the test dir. diff --git a/minui/resources.cpp b/minui/resources.cpp index e6909f26..726c627e 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -374,7 +374,9 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) { // This function tests if a locale string stored in PNG (prefix) matches // the locale string provided by the system (locale). bool matches_locale(const char* prefix, const char* locale) { - if (locale == NULL) return false; + if (locale == nullptr) { + return false; + } // Return true if the whole string of prefix matches the top part of // locale. For instance, prefix == "en" matches locale == "en_US"; diff --git a/tests/Android.mk b/tests/Android.mk index 1203817a..1dbd2b61 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -49,10 +49,34 @@ LOCAL_CLANG := true LOCAL_CFLAGS := -Werror LOCAL_MODULE := recovery_manual_test LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_STATIC_LIBRARIES := libbase +LOCAL_STATIC_LIBRARIES := \ + libminui \ + libbase LOCAL_SRC_FILES := manual/recovery_test.cpp -LOCAL_SHARED_LIBRARIES := liblog +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libpng + +resource_files := $(call find-files-in-subdirs, bootable/recovery, \ + "*_text.png", \ + res-mdpi/images \ + res-hdpi/images \ + res-xhdpi/images \ + res-xxhdpi/images \ + res-xxxhdpi/images \ + ) + +# The resource image files that will go to $OUT/data/nativetest/recovery. +testimage_out_path := $(TARGET_OUT_DATA)/nativetest/recovery +GEN := $(addprefix $(testimage_out_path)/, $(resource_files)) + +$(GEN): PRIVATE_PATH := $(LOCAL_PATH) +$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@ +$(GEN): $(testimage_out_path)/% : bootable/recovery/% + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + include $(BUILD_NATIVE_TEST) # Component tests diff --git a/tests/manual/recovery_test.cpp b/tests/manual/recovery_test.cpp index e73cb150..d36dd331 100644 --- a/tests/manual/recovery_test.cpp +++ b/tests/manual/recovery_test.cpp @@ -14,19 +14,27 @@ * limitations under the License. */ +#include #include #include #include #include +#include #include +#include #include #include +#include #include +#include "minui/minui.h" + static const std::string myFilename = "/data/misc/recovery/inject.txt"; static const std::string myContent = "Hello World\nWelcome to my recovery\n"; +static const std::string kLocale = "zu"; +static const std::string kResourceTestDir = "/data/nativetest/recovery/"; // Failure is expected on systems that do not deliver either the // recovery-persist or recovery-refresh executables. Tests also require @@ -84,3 +92,133 @@ TEST(recovery, persist) { } EXPECT_EQ(0, unlink(myFilename.c_str())); } + +std::vector image_dir { + "res-mdpi/images/", + "res-hdpi/images/", + "res-xhdpi/images/", + "res-xxhdpi/images/", + "res-xxxhdpi/images/" +}; + +static int png_filter(const dirent* de) { + if (de->d_type != DT_REG || !android::base::EndsWith(de->d_name, "_text.png")) { + return 0; + } + return 1; +} + +// Find out all png files to test under /data/nativetest/recovery/. +static std::vector add_files() { + std::vector files; + for (const std::string& str : image_dir) { + std::string dir_path = kResourceTestDir + str; + dirent** namelist; + int n = scandir(dir_path.c_str(), &namelist, png_filter, alphasort); + if (n == -1) { + printf("Failed to scan dir %s: %s\n", kResourceTestDir.c_str(), strerror(errno)); + return files; + } + if (n == 0) { + printf("No file is added for test in %s\n", kResourceTestDir.c_str()); + } + + while (n--) { + std::string file_path = dir_path + namelist[n]->d_name; + files.push_back(file_path); + free(namelist[n]); + } + free(namelist); + } + return files; +} + +class ResourceTest : public testing::TestWithParam { + public: + static std::vector png_list; + + // Parse a png file and test if it's qualified for the background text image + // under recovery. + void SetUp() override { + std::string file_path = GetParam(); + fp = fopen(file_path.c_str(), "rb"); + ASSERT_NE(nullptr, fp); + + unsigned char header[8]; + size_t bytesRead = fread(header, 1, sizeof(header), fp); + ASSERT_EQ(sizeof(header), bytesRead); + ASSERT_EQ(0, png_sig_cmp(header, 0, sizeof(header))); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + ASSERT_NE(nullptr, png_ptr); + + info_ptr = png_create_info_struct(png_ptr); + ASSERT_NE(nullptr, info_ptr); + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, sizeof(header)); + png_read_info(png_ptr, info_ptr); + + int color_type, bit_depth; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, + nullptr); + ASSERT_EQ(PNG_COLOR_TYPE_GRAY, color_type) << "Recovery expects grayscale PNG file."; + ASSERT_LT(static_cast(5), width); + ASSERT_LT(static_cast(0), height); + if (bit_depth <= 8) { + // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. + png_set_expand_gray_1_2_4_to_8(png_ptr); + } + + png_byte channels = png_get_channels(png_ptr, info_ptr); + ASSERT_EQ(1, channels) << "Recovery background text images expects 1-channel PNG file."; + } + + void TearDown() override { + if (png_ptr != nullptr && info_ptr != nullptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + } + + if (fp != nullptr) { + fclose(fp); + } + } + + protected: + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + + FILE* fp; +}; + +std::vector ResourceTest::png_list = add_files(); + +TEST_P(ResourceTest, ValidateLocale) { + std::vector row(width); + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_ptr, row.data(), nullptr); + int w = (row[1] << 8) | row[0]; + int h = (row[3] << 8) | row[2]; + int len = row[4]; + EXPECT_LT(0, w); + EXPECT_LT(0, h); + EXPECT_LT(0, len) << "Locale string should be non-empty."; + EXPECT_NE(0, row[5]) << "Locale string is missing."; + + ASSERT_GT(height, y + 1 + h) << "Locale: " << kLocale << " is not found in the file."; + char* loc = reinterpret_cast(&row[5]); + if (matches_locale(loc, kLocale.c_str())) { + EXPECT_TRUE(android::base::StartsWith(loc, kLocale.c_str())); + break; + } else { + for (int i = 0; i < h; ++i, ++y) { + png_read_row(png_ptr, row.data(), nullptr); + } + } + } +} + +INSTANTIATE_TEST_CASE_P(BackgroundTextValidation, ResourceTest, + ::testing::ValuesIn(ResourceTest::png_list.cbegin(), + ResourceTest::png_list.cend())); diff --git a/tests/unit/locale_test.cpp b/tests/unit/locale_test.cpp index 0e515f8c..f7323500 100644 --- a/tests/unit/locale_test.cpp +++ b/tests/unit/locale_test.cpp @@ -26,4 +26,7 @@ TEST(LocaleTest, Misc) { EXPECT_TRUE(matches_locale("en", "en_GB")); EXPECT_FALSE(matches_locale("en_GB", "en")); EXPECT_FALSE(matches_locale("en_GB", "en_US")); + EXPECT_FALSE(matches_locale("en_US", "")); + // Empty locale prefix in the PNG file will match the input locale. + EXPECT_TRUE(matches_locale("", "en_US")); }