|  | // Copyright (c) 2020 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h" | 
|  |  | 
|  | #include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" | 
|  | #include "net/third_party/quiche/src/common/platform/api/quiche_test.h" | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | std::string HexDumpWithMarks(const char* data, | 
|  | int length, | 
|  | const bool* marks, | 
|  | int mark_length) { | 
|  | static const char kHexChars[] = "0123456789abcdef"; | 
|  | static const int kColumns = 4; | 
|  |  | 
|  | const int kSizeLimit = 1024; | 
|  | if (length > kSizeLimit || mark_length > kSizeLimit) { | 
|  | QUICHE_LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; | 
|  | length = std::min(length, kSizeLimit); | 
|  | mark_length = std::min(mark_length, kSizeLimit); | 
|  | } | 
|  |  | 
|  | std::string hex; | 
|  | for (const char* row = data; length > 0; | 
|  | row += kColumns, length -= kColumns) { | 
|  | for (const char* p = row; p < row + 4; ++p) { | 
|  | if (p < row + length) { | 
|  | const bool mark = | 
|  | (marks && (p - data) < mark_length && marks[p - data]); | 
|  | hex += mark ? '*' : ' '; | 
|  | hex += kHexChars[(*p & 0xf0) >> 4]; | 
|  | hex += kHexChars[*p & 0x0f]; | 
|  | hex += mark ? '*' : ' '; | 
|  | } else { | 
|  | hex += "    "; | 
|  | } | 
|  | } | 
|  | hex = hex + "  "; | 
|  |  | 
|  | for (const char* p = row; p < row + 4 && p < row + length; ++p) { | 
|  | hex += (*p >= 0x20 && *p < 0x7f) ? (*p) : '.'; | 
|  | } | 
|  |  | 
|  | hex = hex + '\n'; | 
|  | } | 
|  | return hex; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace quiche { | 
|  | namespace test { | 
|  |  | 
|  | void CompareCharArraysWithHexError(const std::string& description, | 
|  | const char* actual, | 
|  | const int actual_len, | 
|  | const char* expected, | 
|  | const int expected_len) { | 
|  | EXPECT_EQ(actual_len, expected_len); | 
|  | const int min_len = std::min(actual_len, expected_len); | 
|  | const int max_len = std::max(actual_len, expected_len); | 
|  | std::unique_ptr<bool[]> marks(new bool[max_len]); | 
|  | bool identical = (actual_len == expected_len); | 
|  | for (int i = 0; i < min_len; ++i) { | 
|  | if (actual[i] != expected[i]) { | 
|  | marks[i] = true; | 
|  | identical = false; | 
|  | } else { | 
|  | marks[i] = false; | 
|  | } | 
|  | } | 
|  | for (int i = min_len; i < max_len; ++i) { | 
|  | marks[i] = true; | 
|  | } | 
|  | if (identical) | 
|  | return; | 
|  | ADD_FAILURE() << "Description:\n" | 
|  | << description << "\n\nExpected:\n" | 
|  | << HexDumpWithMarks(expected, expected_len, marks.get(), | 
|  | max_len) | 
|  | << "\nActual:\n" | 
|  | << HexDumpWithMarks(actual, actual_len, marks.get(), max_len); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace quiche |