brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · 1fd940f Raw
231 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS -D_LIBCPP_ENABLE_CXX26_REMOVED_CODECVT10// MSVC warning C4242: '+=': conversion from 'const _Ty' to 'size_t', possible loss of data11// MSVC warning C4244: 'argument': conversion from 'std::streamsize' to 'size_t', possible loss of data12// ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4242 /wd424413// UNSUPPORTED: c++0314 15// <fstream>16 17// This test checks the behavior of reading payloads of different sizes in different patterns.18// In particular, it was written to exercise code paths that deal with buffering inside the fstream19// implementation.20//21// For each test, we test various behaviors w.r.t. how the buffer is handled:22// - Provide a user-managed buffer to the library. In this case, we test the following corner-cases:23//    + A 0-sized buffer.24//    + A buffer size greater than and smaller than the payload size, which causes multiple buffer effects.25//      Important values are +/- 1 byte from the payload size.26// - Let the library manage a buffer of a user-provided size 'n'. In this case, we test the following corner-cases:27//    + A 0-sized buffer.28//    + A buffer size greater than and smaller than the payload size, which causes multiple buffer effects.29//      Important values are +/- 1 or 2 bytes from the payload size.30//    + A buffer size smaller than 8 bytes. If pubsetbuf() is called with less than 8 bytes, the library will31//      use __extbuf_min_ with 8 bytes instead of allocating anything.32// - Let the library manage a buffer, without specifying any size. In this case, the library will use the default33//   buffer size of 4096 bytes.34 35#include <cassert>36#include <codecvt>37#include <fstream>38#include <locale>39#include <numeric>40#include <string>41#include <vector>42 43#include "../types.h"44#include "assert_macros.h"45#include "platform_support.h"46#include "test_macros.h"47 48template <class BufferPolicy>49void test_read(BufferPolicy policy, const std::vector<std::streamsize>& payload_sizes) {50  std::streamsize total_size = std::accumulate(payload_sizes.begin(), payload_sizes.end(), std::streamsize{0});51  std::vector<char> data(total_size);52  for (std::size_t i = 0; i < data.size(); ++i) {53    data[i] = static_cast<char>(i % (1 << 8 * sizeof(char)));54  }55  std::string p = get_temp_file_name();56  {57    std::ofstream ofs;58    ofs.open(p, std::ios::out | std::ios::binary);59    assert(ofs.is_open());60    ofs.write(data.data(), data.size());61    assert(!ofs.fail());62    // test that the user's out_buffer buffer was not modified by write()63    for (std::streamsize j = 0; j < total_size; ++j) {64      char exp = j % (1 << 8 * sizeof(char));65      TEST_REQUIRE(data[j] == exp, [&] {66        test_eprintf("failed after write() at offset %zu: got=%x, expected=%x\n", j, data[j], exp);67      });68    }69    ofs.close();70  }71  {72    std::ifstream ifs;73    policy(ifs);74    ifs.open(p, std::ios::ate | std::ios::binary);75    assert(ifs.is_open());76    const std::streamsize in_sz = ifs.tellg();77    TEST_REQUIRE(in_sz == total_size, [&] { test_eprintf("out_sz = %zu, in_sz = %ld\n", total_size, in_sz); });78    ifs.seekg(0, std::ios::beg);79    std::size_t previously_read = 0;80    std::vector<char> in_buffer(total_size);81    for (const auto& payload_sz : payload_sizes) {82      ifs.read(in_buffer.data() + previously_read, payload_sz);83      assert(ifs);84      for (std::streamsize j = 0; j < payload_sz; ++j) {85        char exp = (previously_read + j) % (1 << 8 * sizeof(char));86        TEST_REQUIRE(in_buffer[previously_read + j] == exp, [&] {87          test_eprintf(88              "failed after read() at offset %zu (offset %zu in chunk size %zu): got=%x, expected=%x\n",89              previously_read + j,90              j,91              payload_sz,92              in_buffer[previously_read + j],93              exp);94        });95      }96      previously_read += payload_sz;97    }98  }99  std::remove(p.c_str());100}101 102#ifndef TEST_HAS_NO_WIDE_CHARACTERS103template <class BufferPolicy>104void test_read_codecvt(BufferPolicy policy, const std::vector<std::streamsize>& payload_sizes) {105  std::streamsize total_size = std::accumulate(payload_sizes.begin(), payload_sizes.end(), std::streamsize{0});106  std::vector<wchar_t> data(total_size);107  for (std::size_t i = 0; i < data.size(); ++i) {108    data[i] = static_cast<wchar_t>(i);109  }110  std::string p = get_temp_file_name();111  {112    std::wofstream ofs;113    ofs.imbue(std::locale(std::locale::classic(), new std::codecvt_utf8<wchar_t>));114    ofs.open(p, std::ios::out | std::ios::binary);115    assert(ofs.is_open());116    ofs.write(data.data(), data.size());117    assert(!ofs.fail());118    // test that the user's out_buffer buffer was not modified by write()119    for (std::streamsize j = 0; j < total_size; ++j) {120      wchar_t exp = static_cast<wchar_t>(j);121      TEST_REQUIRE(data[j] == exp, [&] {122        test_eprintf("failed after write() at offset %zu: got=%x, expected=%x\n", j, data[j], exp);123      });124    }125    ofs.close();126  }127  {128    std::wifstream ifs;129    ifs.imbue(std::locale(std::locale::classic(), new std::codecvt_utf8<wchar_t>));130    policy(ifs);131    ifs.open(p, std::ios::in | std::ios::binary);132    assert(ifs.is_open());133    ifs.seekg(0, std::ios::beg);134    std::size_t previously_read = 0;135    std::vector<wchar_t> in_buffer(total_size);136    for (const auto& payload_sz : payload_sizes) {137      assert(ifs.read(in_buffer.data() + previously_read, payload_sz));138      assert(ifs);139      for (std::streamsize j = 0; j < payload_sz; ++j) {140        wchar_t exp = static_cast<wchar_t>(j + previously_read);141        TEST_REQUIRE(in_buffer[j + previously_read] == exp, [&] {142          test_eprintf(143              "failed after read() at offset %zu: got=%x, expected=%x\n", j, in_buffer[j + previously_read], exp);144        });145      }146      previously_read += payload_sz;147    }148  }149  std::remove(p.c_str());150}151#endif152 153const std::vector<std::streamsize> buffer_sizes{0L, 3L, 8L, 9L, 11L};154const std::vector<std::streamsize> io_sizes{0L, 1L, 2L, 3L, 4L, 9L, 10L, 11L, 12L, 13L, 21L, 22L, 23L};155const std::vector<std::streamsize> io_sizes_default{156    0L, 1L, 2L, 3L, 4L, 4094L, 4095L, 4096L, 4097L, 4098L, 8190L, 8191L, 8192L, 8193L, 8194L};157 158// Test single read operations159void test_1_read() {160  // with default library buffer size: 4096b161  for (std::streamsize x : io_sizes_default) {162    test_read(LibraryDefaultBuffer(), {x});163#ifndef TEST_HAS_NO_WIDE_CHARACTERS164    test_read_codecvt(LibraryDefaultBuffer(), {x});165#endif166  }167 168  // with the library-managed buffer of given size169  for (std::streamsize b : buffer_sizes) {170    for (std::streamsize x : io_sizes) {171      test_read(LibraryManagedBuffer(b), {x});172#ifndef TEST_HAS_NO_WIDE_CHARACTERS173      test_read_codecvt(LibraryManagedBuffer(b), {x});174#endif175    }176  }177 178  // with the user-managed buffer of given size179  for (std::streamsize b : buffer_sizes) {180    for (std::streamsize x : io_sizes) {181      test_read(UserManagedBuffer(b), {x});182#ifndef TEST_HAS_NO_WIDE_CHARACTERS183      test_read_codecvt(UserManagedBuffer(b), {x});184#endif185    }186  }187}188 189// Test two read operations190void test_2_reads() {191  // with default library buffer size: 4096b192  for (std::streamsize a : io_sizes_default) {193    for (std::streamsize b : io_sizes_default) {194      test_read(LibraryDefaultBuffer(), {a, b});195#ifndef TEST_HAS_NO_WIDE_CHARACTERS196      test_read_codecvt(LibraryDefaultBuffer(), {a, b});197#endif198    }199  }200 201  // with the library-managed buffer of given size202  for (std::streamsize buf : buffer_sizes) {203    for (std::streamsize a : io_sizes) {204      for (std::streamsize b : io_sizes) {205        test_read(LibraryManagedBuffer(buf), {a, b});206#ifndef TEST_HAS_NO_WIDE_CHARACTERS207        test_read_codecvt(LibraryManagedBuffer(buf), {a, b});208#endif209      }210    }211  }212 213  // with the user-managed buffer of given size214  for (std::streamsize buf : buffer_sizes) {215    for (std::streamsize a : io_sizes) {216      for (std::streamsize b : io_sizes) {217        test_read(UserManagedBuffer(buf), {a, b});218#ifndef TEST_HAS_NO_WIDE_CHARACTERS219        test_read_codecvt(UserManagedBuffer(buf), {a, b});220#endif221      }222    }223  }224}225 226int main(int, char**) {227  test_1_read();228  test_2_reads();229  return 0;230}231