| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <inttypes.h> |
| #include <uapi/err.h> |
| #include <optional> |
| #include "device_parameters.h" |
| |
| #define TLOG_TAG "confui-test" |
| #include <trusty_unittest.h> |
| |
| #define MIN_EXPECTED_DRAW_COUNT 1000u |
| #define MIN_EXPECTED_DRAW_PERCENTAGE 1u |
| |
| static const char* language_ids[] = {"en"}; |
| |
| static const char* messages[] = { |
| /* Simple message */ |
| "Android Test Message", |
| /* Two line message as required by Android design guidelines */ |
| "WM Line 1\nWM Line 2", |
| /* 100 'W' characters as required by Android design guidelines */ |
| "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", |
| /* 8 groups of 12 'W' characters as required by Android design |
| guidelines */ |
| "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW"}; |
| |
| TEST(confui, display_count) { |
| int display_count = devices::getDisplayCount(); |
| |
| EXPECT_GT(display_count, 0); |
| } |
| |
| typedef struct { |
| uint32_t count; |
| } draw_stats_t; |
| |
| typedef struct { |
| const char* lang_id; |
| const char* message; |
| bool magnified; |
| bool inverse; |
| } confuip_t; |
| |
| TEST_F_SETUP(confuip) { |
| const void* const* param_arr = (const void* const*)GetParam(); |
| const bool* magnified = (const bool*)param_arr[0]; |
| const bool* inverse = (const bool*)param_arr[1]; |
| const char** lang_id = (const char**)param_arr[2]; |
| const char** message = (const char**)param_arr[3]; |
| |
| _state->magnified = *magnified; |
| _state->inverse = *inverse; |
| _state->lang_id = *lang_id; |
| _state->message = *message; |
| } |
| |
| TEST_F_TEARDOWN(confuip) {} |
| |
| TEST_P(confuip, display_params) { |
| int display_count = devices::getDisplayCount(); |
| |
| for (int i = 0; i < display_count; i++) { |
| std::optional<teeui::context<teeui::ConUIParameters>> params; |
| |
| params = devices::getDisplayContext(i, _state->magnified); |
| EXPECT_EQ(params.has_value(), true, "getDisplayContext %d", i); |
| |
| if (params) { |
| const uint32_t screen_width = |
| params->getParam<teeui::RightEdgeOfScreen>()->count() + 1; |
| const uint32_t screen_height = |
| params->getParam<teeui::BottomOfScreen>()->count() + 1; |
| std::optional<std::unique_ptr<teeui::layouts::ILayout>> optlayout; |
| |
| optlayout = devices::getDisplayLayout(i, _state->inverse, *params); |
| EXPECT_EQ(optlayout.has_value(), true, "getDisplayLayout %d", i); |
| |
| /* Configure the layout */ |
| if (optlayout) { |
| std::unique_ptr<teeui::layouts::ILayout> layout = |
| std::move(*optlayout); |
| draw_stats_t stats = {}; |
| |
| /* Configure the layout */ |
| layout->setLanguage(_state->lang_id); |
| layout->setConfirmationMessage(_state->message); |
| layout->showInstructions(true /* enable */); |
| |
| auto drawPixel = teeui::makePixelDrawer( |
| [&](uint32_t x, uint32_t y, |
| teeui::Color color) -> teeui::Error { |
| TLOGD("px %u %u: %08x", x, y, color); |
| |
| /* Check bounds */ |
| if (x >= screen_width || y >= screen_height) { |
| return teeui::Error::OutOfBoundsDrawing; |
| } |
| |
| /* Count calls, noting there is no check if some |
| * pixels are written multiple times. |
| */ |
| stats.count++; |
| |
| return teeui::Error::OK; |
| }); |
| |
| /* Render the layout */ |
| teeui::Error rc = layout->drawElements(drawPixel); |
| EXPECT_EQ(rc.code(), teeui::Error::OK, "drawElements %d", i); |
| |
| EXPECT_GT(stats.count, MIN_EXPECTED_DRAW_COUNT, |
| "pixel count %d", i); |
| |
| const uint32_t area = screen_width * screen_height; |
| const uint32_t coverage = |
| (float)stats.count / (float)area * 1000.0f; |
| |
| EXPECT_GT(coverage, MIN_EXPECTED_DRAW_PERCENTAGE * 10u, |
| "pixel coverage %" PRIu32 ".%" PRIu32 "%%", |
| coverage / 10, coverage % 10); |
| |
| trusty_unittest_printf("[ DATA ] %" PRIu32 "x%" PRIu32 |
| ", %" PRIu32 |
| " plot calls = approx %" PRIu32 |
| ".%" PRIu32 "%% coverage\n", |
| screen_width, screen_height, stats.count, |
| coverage / 10, coverage % 10); |
| } |
| } |
| } |
| } |
| |
| void confuip_to_string(const void* param, char* buf, size_t buf_size) { |
| const void* const* param_arr = (const void* const*)GetParam(); |
| const bool* magnified = (const bool*)param_arr[0]; |
| const bool* inverse = (const bool*)param_arr[1]; |
| const char** lang_id = (const char**)param_arr[2]; |
| const char** message = (const char**)param_arr[3]; |
| uint8_t msg_index = message - messages; |
| |
| snprintf(buf, buf_size, "%s/msg%" PRIu8 "%s%s", *lang_id, msg_index, |
| *magnified ? "/mag" : "", *inverse ? "/inv" : ""); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(confui, |
| confuip, |
| testing_Combine(testing_Bool(), /* magnified */ |
| testing_Bool(), /* inverse */ |
| testing_ValuesIn(language_ids), |
| testing_ValuesIn(messages)), |
| confuip_to_string); |
| |
| PORT_TEST(confui, "com.android.trusty.confirmationui.test"); |