[omnibox] Add tests for ExtractJsonData
SearchSuggestionParser::ExtractJsonData()의 주요 분기를 검증하는 단위 테스트를 추가했습니다.
문제 설명
- issue url: https://crbug.com/41382281
- 대상 함수:
components/omnibox/browser/search_suggestion_parser.cc의SearchSuggestionParser::ExtractJsonData() - 테스트 파일:
components/omnibox/browser/search_suggestion_parser_unittest.cc
ExtractJsonData()는 suggest 서버에서 받은 응답 body를 JSON 문자열로 넘기기 전에 응답 헤더의 charset을 확인합니다.
JSON은 원칙적으로 UTF-8이지만 일부 suggest provider가 다른 인코딩을 사용할 수 있기 때문에, Content-Type에 charset이 지정되어 있으면 CodepageToUTF16()과 UTF16ToUTF8()을 이용해 UTF-8로 변환합니다.
if (response_headers) {
std::string charset;
if (response_headers->GetCharset(&charset)) {
std::u16string data_16;
// TODO(jungshik): Switch to CodePageToUTF8 after it's added.
if (base::CodepageToUTF16(
json_data, charset.c_str(),
base::OnStringConversionError::FAIL, &data_16)) {
json_data = base::UTF16ToUTF8(data_16);
}
}
}함수 안에는 여러 조건 분기가 있었지만 ExtractJsonData() 자체를 대상으로 이 동작을 직접 확인하는 단위 테스트가 없었습니다.
테스트 분기
source == nullptrresponse_body == std::nullopt- response header는 있지만 charset이 없음
- charset이 있고 인코딩 변환에 성공
- charset이 있지만 잘못된 데이터라 변환에 실패
해결 내용
search_suggestion_parser_unittest.cc에 ExtractJsonData()의 주요 동작을 검증하는 테스트를 추가했습니다.
응답 body가 없는 경우에는 빈 문자열이 반환되는지 확인합니다.
TEST(SearchSuggestionParserTest, ExtractJsonDataWithoutResponseBody) {
std::optional<std::string> response_body;
std::string result = SearchSuggestionParser::ExtractJsonData(
/*source=*/nullptr, response_body);
ASSERT_TRUE(result.empty());
}source가 없는 경우에는 별도의 charset 처리 없이 원래 body가 그대로 반환되는지 확인했습니다.
TEST(SearchSuggestionParserTest, ExtractJsonDataWithoutSource) {
std::string response_body = R"(["one"])";
std::string result = SearchSuggestionParser::ExtractJsonData(
/*source=*/nullptr, response_body);
ASSERT_EQ(response_body, result);
}charset 관련 테스트에서는 실제 SimpleURLLoader의 응답 헤더를 구성해야 했기 때문에, Content-Type을 지정한 loader를 만드는 작은 테스트 helper도 추가했습니다.
std::unique_ptr<network::SimpleURLLoader> CreateLoaderWithContentType(
network::TestURLLoaderFactory* url_loader_factory,
std::string_view content_type) {
const GURL url("https://example.com/");
auto response_head = network::CreateURLResponseHead(net::HTTP_OK);
response_head->headers->SetHeader("Content-Type", content_type);
url_loader_factory->AddResponse(url, std::move(response_head), /*content=*/"",
network::URLLoaderCompletionStatus(net::OK));
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = url;
auto loader = network::SimpleURLLoader::Create(std::move(resource_request),
TRAFFIC_ANNOTATION_FOR_TESTS);
base::test::TestFuture<std::optional<std::string>> future;
loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(url_loader_factory,
future.GetCallback());
static_cast<void>(future.Get());
return loader;
}이를 이용해 application/json처럼 charset이 없는 응답은 body가 그대로 유지되는지 확인했습니다.
또 charset=euc-kr인 응답에 EUC-KR로 인코딩된 "안녕하세요"를 넣어 UTF-8로 정상 변환되는 경우를 테스트했습니다.
// "안녕하세요" encoded as EUC-KR.
std::string response_body =
"[\""
"\xBE\xC8\xB3\xE7\xC7\xCF\xBC\xBC\xBF\xE4"
"\"]";반대로 "\xFE\x22"처럼 EUC-KR로 올바르게 해석할 수 없는 데이터를 전달해 CodepageToUTF16() 변환이 실패하면 원본 데이터가 그대로 반환되는 동작도 검증했습니다.
테스트 방법
이번 변경 자체가 기존 동작에 대한 unit test 추가이므로 다음 동작을 각각 검증했습니다.
- response body가 없으면 빈 문자열 반환
- source가 없으면 원본 body 반환
- response header에 charset이 없으면 원본 body 반환
- EUC-KR 데이터의 charset 변환 성공 시 UTF-8 문자열 반환
- 잘못된 EUC-KR 데이터의 charset 변환 실패 시 원본 body 유지
배운 점
- 테스트를 추가하기 전에 함수의 조건문을 먼저 분기로 나눠 보는 것이 도움이 됐습니다. source, response_body, header, charset, conversion 결과를 따로 정리하니 빠뜨린 경로를 확인하기 쉬었습니다.