| // 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 "quiche/common/test_tools/quiche_test_utils.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "quiche/common/platform/api/quiche_logging.h" | 
 | #include "quiche/common/platform/api/quiche_test.h" | 
 |  | 
 | 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); | 
 | } | 
 |  | 
 | iovec MakeIOVector(absl::string_view str) { | 
 |   return iovec{const_cast<char*>(str.data()), static_cast<size_t>(str.size())}; | 
 | } | 
 |  | 
 | }  // namespace test | 
 | }  // namespace quiche |