/** * @file tests/unit/test_display_device.cpp * @brief Test src/display_device.*. */ #include "../tests_common.h" #include #include #include #include namespace { using config_option_e = config::video_t::dd_t::config_option_e; using device_prep_t = display_device::SingleDisplayConfiguration::DevicePreparation; using hdr_option_e = config::video_t::dd_t::hdr_option_e; using hdr_state_e = display_device::HdrState; using resolution_option_e = config::video_t::dd_t::resolution_option_e; using resolution_t = display_device::Resolution; using refresh_rate_option_e = config::video_t::dd_t::refresh_rate_option_e; using rational_t = display_device::Rational; struct failed_to_parse_resolution_tag_t {}; struct failed_to_parse_refresh_rate_tag_t {}; struct no_refresh_rate_tag_t {}; struct no_resolution_tag_t {}; struct client_resolution_t { int width; int height; }; using client_fps_t = int; using sops_enabled_t = bool; using client_wants_hdr_t = bool; constexpr unsigned int max_uint {std::numeric_limits::max()}; const std::string max_uint_string {std::to_string(std::numeric_limits::max())}; template struct DisplayDeviceConfigTest: testing::TestWithParam {}; } // namespace using ParseDeviceId = DisplayDeviceConfigTest>; INSTANTIATE_TEST_SUITE_P( DisplayDeviceConfigTest, ParseDeviceId, testing::Values( std::make_pair(""s, ""s), std::make_pair("SomeId"s, "SomeId"s), std::make_pair("{daeac860-f4db-5208-b1f5-cf59444fb768}"s, "{daeac860-f4db-5208-b1f5-cf59444fb768}"s) ) ); TEST_P(ParseDeviceId, IntegrationTest) { const auto &[input_value, expected_value] = GetParam(); config::video_t video_config {}; video_config.dd.configuration_option = config_option_e::verify_only; video_config.output_name = input_value; const auto result {display_device::parse_configuration(video_config, {})}; EXPECT_EQ(std::get(result).m_device_id, expected_value); } using ParseConfigOption = DisplayDeviceConfigTest>>; INSTANTIATE_TEST_SUITE_P( DisplayDeviceConfigTest, ParseConfigOption, testing::Values( std::make_pair(config_option_e::disabled, std::nullopt), std::make_pair(config_option_e::verify_only, device_prep_t::VerifyOnly), std::make_pair(config_option_e::ensure_active, device_prep_t::EnsureActive), std::make_pair(config_option_e::ensure_primary, device_prep_t::EnsurePrimary), std::make_pair(config_option_e::ensure_only_display, device_prep_t::EnsureOnlyDisplay) ) ); TEST_P(ParseConfigOption, IntegrationTest) { const auto &[input_value, expected_value] = GetParam(); config::video_t video_config {}; video_config.dd.configuration_option = input_value; const auto result {display_device::parse_configuration(video_config, {})}; if (const auto *parsed_config {std::get_if(&result)}; parsed_config) { ASSERT_EQ(parsed_config->m_device_prep, expected_value); } else { ASSERT_EQ(std::get_if(&result) != nullptr, !expected_value); } } using ParseHdrOption = DisplayDeviceConfigTest, std::optional>>; INSTANTIATE_TEST_SUITE_P( DisplayDeviceConfigTest, ParseHdrOption, testing::Values( std::make_pair(std::make_pair(hdr_option_e::disabled, client_wants_hdr_t {true}), std::nullopt), std::make_pair(std::make_pair(hdr_option_e::disabled, client_wants_hdr_t {false}), std::nullopt), std::make_pair(std::make_pair(hdr_option_e::automatic, client_wants_hdr_t {true}), hdr_state_e::Enabled), std::make_pair(std::make_pair(hdr_option_e::automatic, client_wants_hdr_t {false}), hdr_state_e::Disabled) ) ); TEST_P(ParseHdrOption, IntegrationTest) { const auto &[input_value, expected_value] = GetParam(); const auto &[input_hdr_option, input_enable_hdr] = input_value; config::video_t video_config {}; video_config.dd.configuration_option = config_option_e::verify_only; video_config.dd.hdr_option = input_hdr_option; rtsp_stream::launch_session_t session {}; session.enable_hdr = input_enable_hdr; const auto result {display_device::parse_configuration(video_config, session)}; EXPECT_EQ(std::get(result).m_hdr_state, expected_value); } using ParseResolutionOption = DisplayDeviceConfigTest>, std::variant>>; INSTANTIATE_TEST_SUITE_P( DisplayDeviceConfigTest, ParseResolutionOption, testing::Values( //---- Disabled cases ---- std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {true}, client_resolution_t {1920, 1080}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {true}, "1920x1080"s), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {true}, client_resolution_t {-1, -1}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {true}, "invalid_res"s), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {false}, client_resolution_t {1920, 1080}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {false}, "1920x1080"s), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {false}, client_resolution_t {-1, -1}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::disabled, sops_enabled_t {false}, "invalid_res"s), no_resolution_tag_t {}), //---- Automatic cases ---- std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, client_resolution_t {1920, 1080}), resolution_t {1920, 1080}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, "1920x1080"s), resolution_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, client_resolution_t {-1, -1}), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, "invalid_res"s), resolution_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {false}, client_resolution_t {1920, 1080}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {false}, "1920x1080"s), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {false}, client_resolution_t {-1, -1}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {false}, "invalid_res"s), no_resolution_tag_t {}), //---- Manual cases ---- std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, client_resolution_t {1920, 1080}), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "1920x1080"s), resolution_t {1920, 1080}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, client_resolution_t {-1, -1}), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "invalid_res"s), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {false}, client_resolution_t {1920, 1080}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {false}, "1920x1080"s), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {false}, client_resolution_t {-1, -1}), no_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {false}, "invalid_res"s), no_resolution_tag_t {}), //---- Both negative values from client are checked ---- std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, client_resolution_t {0, 0}), resolution_t {0, 0}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, client_resolution_t {-1, 0}), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::automatic, sops_enabled_t {true}, client_resolution_t {0, -1}), failed_to_parse_resolution_tag_t {}), //---- Resolution string format validation ---- std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "0x0"s), resolution_t {0, 0}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "0x"s), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "x0"s), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "-1x1"s), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "1x-1"s), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "x0x0"s), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, "0x0x"s), failed_to_parse_resolution_tag_t {}), //---- String number is out of bounds ---- std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, max_uint_string + "x"s + max_uint_string), resolution_t {max_uint, max_uint}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, max_uint_string + "0"s + "x"s + max_uint_string), failed_to_parse_resolution_tag_t {}), std::make_pair(std::make_tuple(resolution_option_e::manual, sops_enabled_t {true}, max_uint_string + "x"s + max_uint_string + "0"s), failed_to_parse_resolution_tag_t {}) ) ); TEST_P(ParseResolutionOption, IntegrationTest) { const auto &[input_value, expected_value] = GetParam(); const auto &[input_resolution_option, input_enable_sops, input_resolution] = input_value; config::video_t video_config {}; video_config.dd.configuration_option = config_option_e::verify_only; video_config.dd.resolution_option = input_resolution_option; rtsp_stream::launch_session_t session {}; session.enable_sops = input_enable_sops; if (const auto *client_res {std::get_if(&input_resolution)}; client_res) { video_config.dd.manual_resolution = {}; session.width = client_res->width; session.height = client_res->height; } else { video_config.dd.manual_resolution = std::get(input_resolution); session.width = {}; session.height = {}; } const auto result {display_device::parse_configuration(video_config, session)}; if (const auto *failed_option {std::get_if(&expected_value)}; failed_option) { EXPECT_NO_THROW(std::get(result)); } else { std::optional expected_resolution; if (const auto *valid_resolution_option {std::get_if(&expected_value)}; valid_resolution_option) { expected_resolution = *valid_resolution_option; } EXPECT_EQ(std::get(result).m_resolution, expected_resolution); } } using ParseRefreshRateOption = DisplayDeviceConfigTest>, std::variant>>; INSTANTIATE_TEST_SUITE_P( DisplayDeviceConfigTest, ParseRefreshRateOption, testing::Values( //---- Disabled cases ---- std::make_pair(std::make_tuple(refresh_rate_option_e::disabled, client_fps_t {60}), no_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::disabled, "60"s), no_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::disabled, "59.9885"s), no_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::disabled, client_fps_t {-1}), no_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::disabled, "invalid_refresh_rate"s), no_refresh_rate_tag_t {}), //---- Automatic cases ---- std::make_pair(std::make_tuple(refresh_rate_option_e::automatic, client_fps_t {60}), rational_t {60, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::automatic, "60"s), rational_t {0, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::automatic, "59.9885"s), rational_t {0, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::automatic, client_fps_t {-1}), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::automatic, "invalid_refresh_rate"s), rational_t {0, 1}), //---- Manual cases ---- std::make_pair(std::make_tuple(refresh_rate_option_e::manual, client_fps_t {60}), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "60"s), rational_t {60, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "59.9885"s), rational_t {599885, 10000}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, client_fps_t {-1}), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "invalid_refresh_rate"s), failed_to_parse_refresh_rate_tag_t {}), //---- Refresh rate string format validation ---- std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "0000000000000"s), rational_t {0, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "0"s), rational_t {0, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "00000000.0000000"s), rational_t {0, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "0.0"s), rational_t {0, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "000000000000010"s), rational_t {10, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "00000010.0000000"s), rational_t {10, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "00000010.1000000"s), rational_t {101, 10}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "00000010.0100000"s), rational_t {1001, 100}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "00000000.1000000"s), rational_t {1, 10}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "60,0"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "-60.0"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "60.-0"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "a60.0"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "60.0b"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "a60"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "60b"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, "-60"s), failed_to_parse_refresh_rate_tag_t {}), //---- String number is out of bounds ---- std::make_pair(std::make_tuple(refresh_rate_option_e::manual, max_uint_string), rational_t {max_uint, 1}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, max_uint_string + "0"s), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, max_uint_string.substr(0, 1) + "."s + max_uint_string.substr(1)), rational_t {max_uint, static_cast(std::pow(10, max_uint_string.size() - 1))}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, max_uint_string.substr(0, 1) + "0"s + "."s + max_uint_string.substr(1)), failed_to_parse_refresh_rate_tag_t {}), std::make_pair(std::make_tuple(refresh_rate_option_e::manual, max_uint_string.substr(0, 1) + "."s + "0"s + max_uint_string.substr(1)), failed_to_parse_refresh_rate_tag_t {}) ) ); TEST_P(ParseRefreshRateOption, IntegrationTest) { const auto &[input_value, expected_value] = GetParam(); const auto &[input_refresh_rate_option, input_refresh_rate] = input_value; config::video_t video_config {}; video_config.dd.configuration_option = config_option_e::verify_only; video_config.dd.refresh_rate_option = input_refresh_rate_option; rtsp_stream::launch_session_t session {}; if (const auto *client_refresh_rate {std::get_if(&input_refresh_rate)}; client_refresh_rate) { video_config.dd.manual_refresh_rate = {}; session.fps = *client_refresh_rate; } else { video_config.dd.manual_refresh_rate = std::get(input_refresh_rate); session.fps = {}; } const auto result {display_device::parse_configuration(video_config, session)}; if (const auto *failed_option {std::get_if(&expected_value)}; failed_option) { EXPECT_NO_THROW(std::get(result)); } else { std::optional expected_refresh_rate; if (const auto *valid_refresh_rate_option {std::get_if(&expected_value)}; valid_refresh_rate_option) { expected_refresh_rate = *valid_refresh_rate_option; } EXPECT_EQ(std::get(result).m_refresh_rate, expected_refresh_rate); } } namespace { using res_t = resolution_t; using fps_t = client_fps_t; using remap_entries_t = config::video_t::dd_t::mode_remapping_t; struct no_value_t {}; template struct auto_value_t { T value; }; template struct manual_value_t { T value; }; using resolution_variant_t = std::variant, manual_value_t>; using rational_variant_t = std::variant, manual_value_t>; struct failed_to_remap_t {}; struct final_values_t { std::optional resolution; std::optional refresh_rate; }; const std::string INVALID_RES {"INVALID"}; const std::string INVALID_FPS {"1.23"}; const std::string INVALID_REFRESH_RATE {"INVALID"}; const remap_entries_t VALID_ENTRIES { .mixed = { {"1920x1080", "11", "1024x720", "1.11"}, {"1920x1080", "", "1024x720", "2"}, {"", "33", "1024x720", "3"}, {"1920x720", "44", "1024x720", ""}, {"1920x720", "55", "", "5"}, {"1920x720", "", "1024x720", ""}, {"", "11", "", "7.77"} }, .resolution_only = {{"1920x1080", "", "720x720", ""}, {"1024x720", "", "1920x1920", ""}}, .refresh_rate_only = {{"", "11", "", "1.23"}, {"", "22", "", "2.34"}} }; const remap_entries_t INVALID_REQ_RES { .mixed = {{INVALID_RES, "11", "1024x720", "1.11"}}, .resolution_only = {{INVALID_RES, "", "720x720", ""}}, .refresh_rate_only = {{INVALID_RES, "11", "", "1.23"}} }; const remap_entries_t INVALID_REQ_FPS { .mixed = {{"1920x1080", INVALID_FPS, "1024x720", "1.11"}}, .resolution_only = {{"1920x1080", INVALID_FPS, "720x720", ""}}, .refresh_rate_only = {{"", INVALID_FPS, "", "1.23"}} }; const remap_entries_t INVALID_FINAL_RES { .mixed = {{"1920x1080", "11", INVALID_RES, "1.11"}}, .resolution_only = {{"1920x1080", "", INVALID_RES, ""}}, .refresh_rate_only = {{"", "11", INVALID_RES, "1.23"}} }; const remap_entries_t INVALID_FINAL_REFRESH_RATE { .mixed = {{"1920x1080", "11", "1024x720", INVALID_REFRESH_RATE}}, .resolution_only = {{"1920x1080", "", "720x720", INVALID_REFRESH_RATE}}, .refresh_rate_only = {{"", "11", "", INVALID_REFRESH_RATE}} }; const remap_entries_t EMPTY_REQ_ENTRIES { .mixed = {{"", "", "1024x720", "1.11"}}, .resolution_only = {{"", "", "720x720", ""}}, .refresh_rate_only = {{"", "", "", "1.23"}} }; const remap_entries_t EMPTY_FINAL_ENTRIES { .mixed = {{"1920x1080", "11", "", ""}}, .resolution_only = {{"1920x1080", "", "", ""}}, .refresh_rate_only = {{"", "11", "", ""}} }; using DisplayModeRemapping = DisplayDeviceConfigTest, std::variant>>; INSTANTIATE_TEST_SUITE_P( DisplayDeviceConfigTest, DisplayModeRemapping, testing::Values( //---- Mixed (valid), SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1024, 720}}, {{111, 100}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {120}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1024, 720}}, {{2, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1, 1}, auto_value_t {33}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1024, 720}}, {{3, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 720}, auto_value_t {44}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1024, 720}}, {{44, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 720}, auto_value_t {55}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1920, 720}}, {{5, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 720}, auto_value_t {60}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1024, 720}}, {{60, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1, 1}, auto_value_t {123}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1, 1}}, {{123, 1}}}), //---- Mixed (valid), SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{777, 100}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {120}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{120, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1, 1}, auto_value_t {33}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{33, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 720}, auto_value_t {44}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{44, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 720}, auto_value_t {55}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{55, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 720}, auto_value_t {60}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{60, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1, 1}, auto_value_t {123}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{123, 1}}}), //---- Resolution only (valid), SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{720, 720}}, {{11, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1024, 720}, no_value_t {}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1920, 1920}}, std::nullopt}), std::make_pair(std::make_tuple(auto_value_t {11, 11}, manual_value_t {33}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{11, 11}}, {{33, 1}}}), //---- Resolution only (valid), SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{11, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1024, 720}, no_value_t {}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, std::nullopt}), std::make_pair(std::make_tuple(auto_value_t {11, 11}, manual_value_t {33}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{33, 1}}}), //---- Refresh rate only (valid), SOPS enabled ---- std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1920, 1080}}, {{123, 100}}}), std::make_pair(std::make_tuple(no_value_t {}, auto_value_t {22}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {std::nullopt, {{234, 100}}}), std::make_pair(std::make_tuple(manual_value_t {11, 11}, auto_value_t {33}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{11, 11}}, {{33, 1}}}), //---- Refresh rate only (valid), SOPS disabled ---- std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{123, 100}}}), std::make_pair(std::make_tuple(no_value_t {}, auto_value_t {22}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{234, 100}}}), std::make_pair(std::make_tuple(manual_value_t {11, 11}, auto_value_t {33}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{33, 1}}}), //---- No mapping (valid), SOPS enabled ---- std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {{{1920, 1080}}, {{11, 1}}}), std::make_pair(std::make_tuple(no_value_t {}, no_value_t {}, sops_enabled_t {true}, VALID_ENTRIES), final_values_t {std::nullopt, std::nullopt}), //---- No mapping (valid), SOPS disabled ---- std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, {{11, 1}}}), std::make_pair(std::make_tuple(no_value_t {}, no_value_t {}, sops_enabled_t {false}, VALID_ENTRIES), final_values_t {std::nullopt, std::nullopt}), // ---- Invalid requested resolution, SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_REQ_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, INVALID_REQ_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_REQ_RES), final_values_t {{{1920, 1080}}, {{123, 100}}}), // ---- Invalid requested resolution, SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_REQ_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, INVALID_REQ_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_REQ_RES), final_values_t {std::nullopt, {{123, 100}}}), // ---- Invalid requested FPS, SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_REQ_FPS), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, INVALID_REQ_FPS), final_values_t {{{720, 720}}, {{11, 1}}}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_REQ_FPS), failed_to_remap_t {}), // ---- Invalid requested FPS, SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_REQ_FPS), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, INVALID_REQ_FPS), final_values_t {std::nullopt, {{11, 1}}}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_REQ_FPS), failed_to_remap_t {}), // ---- Invalid final resolution, SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_FINAL_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, INVALID_FINAL_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_FINAL_RES), final_values_t {{{1920, 1080}}, {{123, 100}}}), // ---- Invalid final resolution, SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_FINAL_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, INVALID_FINAL_RES), failed_to_remap_t {}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_FINAL_RES), final_values_t {std::nullopt, {{123, 100}}}), // ---- Invalid final refresh rate, SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_FINAL_REFRESH_RATE), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, INVALID_FINAL_REFRESH_RATE), final_values_t {{{720, 720}}, {{11, 1}}}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, INVALID_FINAL_REFRESH_RATE), failed_to_remap_t {}), // ---- Invalid final refresh rate, SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_FINAL_REFRESH_RATE), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, INVALID_FINAL_REFRESH_RATE), final_values_t {std::nullopt, {{11, 1}}}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, INVALID_FINAL_REFRESH_RATE), failed_to_remap_t {}), // ---- Empty req entries, SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, EMPTY_REQ_ENTRIES), final_values_t {{{1024, 720}}, {{111, 100}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, EMPTY_REQ_ENTRIES), final_values_t {{{720, 720}}, {{11, 1}}}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, EMPTY_REQ_ENTRIES), final_values_t {{{1920, 1080}}, {{123, 100}}}), // ---- Empty req entries, SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, EMPTY_REQ_ENTRIES), final_values_t {std::nullopt, {{11, 1}}}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, EMPTY_REQ_ENTRIES), final_values_t {std::nullopt, {{11, 1}}}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, EMPTY_REQ_ENTRIES), final_values_t {std::nullopt, {{123, 100}}}), // ---- Empty final entries, SOPS enabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, EMPTY_FINAL_ENTRIES), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {true}, EMPTY_FINAL_ENTRIES), failed_to_remap_t {}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {true}, EMPTY_FINAL_ENTRIES), failed_to_remap_t {}), // ---- Empty final entries, SOPS disabled ---- std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, EMPTY_FINAL_ENTRIES), failed_to_remap_t {}), std::make_pair(std::make_tuple(auto_value_t {1920, 1080}, manual_value_t {11}, sops_enabled_t {false}, EMPTY_FINAL_ENTRIES), failed_to_remap_t {}), std::make_pair(std::make_tuple(manual_value_t {1920, 1080}, auto_value_t {11}, sops_enabled_t {false}, EMPTY_FINAL_ENTRIES), failed_to_remap_t {}) ) ); TEST_P(DisplayModeRemapping, IntegrationTest) { const auto &[input_value, expected_value] = GetParam(); const auto &[input_res, input_fps, input_enable_sops, input_entries] = input_value; config::video_t video_config {}; rtsp_stream::launch_session_t session {}; { // resolution using enum resolution_option_e; if (const auto *no_res {std::get_if(&input_res)}; no_res) { video_config.dd.resolution_option = disabled; } else if (const auto *auto_res {std::get_if>(&input_res)}; auto_res) { video_config.dd.resolution_option = automatic; session.width = static_cast(auto_res->value.m_width); session.height = static_cast(auto_res->value.m_height); } else { const auto [manual_res] = std::get>(input_res); video_config.dd.resolution_option = manual; video_config.dd.manual_resolution = std::format("{}x{}", static_cast(manual_res.m_width), static_cast(manual_res.m_height)); } } { // fps using enum refresh_rate_option_e; if (const auto *no_fps {std::get_if(&input_fps)}; no_fps) { video_config.dd.refresh_rate_option = disabled; } else if (const auto *auto_fps {std::get_if>(&input_fps)}; auto_fps) { video_config.dd.refresh_rate_option = automatic; session.fps = auto_fps->value; } else { const auto [manual_fps] = std::get>(input_fps); video_config.dd.refresh_rate_option = manual; video_config.dd.manual_refresh_rate = std::to_string(manual_fps); } } video_config.dd.configuration_option = config_option_e::verify_only; video_config.dd.mode_remapping = input_entries; session.enable_sops = input_enable_sops; const auto result {display_device::parse_configuration(video_config, session)}; if (const auto *failed_option {std::get_if(&expected_value)}; failed_option) { EXPECT_NO_THROW(std::get(result)); } else { const auto &[expected_resolution, expected_refresh_rate] = std::get(expected_value); const auto &parsed_config = std::get(result); EXPECT_EQ(parsed_config.m_resolution, expected_resolution); EXPECT_EQ(parsed_config.m_refresh_rate, expected_refresh_rate ? std::make_optional(display_device::FloatingPoint {*expected_refresh_rate}) : std::nullopt); } } } // namespace