blob: 1070decd31ff27462b382dfb91e642f0a09baff4 [file] [log] [blame]
// Copyright 2025 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/resize_and_overwrite.h"
#include <algorithm>
#include <cstddef>
#include <string>
#include "gtest/gtest.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/log/absl_check.h"
namespace {
struct ResizeAndOverwriteParam {
size_t initial_size;
size_t requested_capacity;
size_t final_size;
};
using StringResizeAndOverwriteTest =
::testing::TestWithParam<ResizeAndOverwriteParam>;
TEST_P(StringResizeAndOverwriteTest, StringResizeAndOverwrite) {
const auto& param = GetParam();
std::string s(param.initial_size, 'a');
absl::StringResizeAndOverwrite(
s, param.requested_capacity, [&](char* p, size_t n) {
ABSL_CHECK_EQ(n, param.requested_capacity);
if (param.final_size >= param.initial_size) {
// Append case.
std::fill(p + param.initial_size, p + param.final_size, 'b');
} else if (param.final_size > 0) {
// Truncate case.
p[param.final_size - 1] = 'b';
}
p[param.final_size] = '\0';
return param.final_size;
});
std::string expected;
if (param.final_size >= param.initial_size) {
// Append case.
expected = std::string(param.initial_size, 'a') +
std::string(param.final_size - param.initial_size, 'b');
} else if (param.final_size > 0) {
// Truncate case.
expected = std::string(param.final_size - 1, 'a') + std::string("b");
}
EXPECT_EQ(s, expected);
EXPECT_EQ(s.c_str()[param.final_size], '\0');
}
TEST_P(StringResizeAndOverwriteTest, StringResizeAndOverwriteFallback) {
const auto& param = GetParam();
std::string s(param.initial_size, 'a');
absl::strings_internal::StringResizeAndOverwriteFallback(
s, param.requested_capacity, [&](char* p, size_t n) {
ABSL_CHECK_EQ(n, param.requested_capacity);
if (param.final_size >= param.initial_size) {
// Append case.
std::fill(p + param.initial_size, p + param.final_size, 'b');
} else if (param.final_size > 0) {
// Truncate case.
p[param.final_size - 1] = 'b';
}
p[param.final_size] = '\0';
return param.final_size;
});
std::string expected;
if (param.final_size >= param.initial_size) {
// Append case.
expected = std::string(param.initial_size, 'a') +
std::string(param.final_size - param.initial_size, 'b');
} else if (param.final_size > 0) {
// Truncate case.
expected = std::string(param.final_size - 1, 'a') + std::string("b");
}
EXPECT_EQ(s, expected);
EXPECT_EQ(s.c_str()[param.final_size], '\0');
}
#ifdef ABSL_HAVE_MEMORY_SANITIZER
constexpr bool kMSan = true;
#else
constexpr bool kMSan = false;
#endif
TEST_P(StringResizeAndOverwriteTest, Initialized) {
if (!kMSan) {
GTEST_SKIP() << "Skipping test without MSan.";
}
const auto& param = GetParam();
std::string s(param.initial_size, 'a');
auto op = [&]() {
absl::StringResizeAndOverwrite(s, param.requested_capacity,
[&](char*, size_t) {
// Fail to initialize the buffer in full.
return param.final_size;
});
};
if (param.initial_size < param.final_size) {
#ifndef NDEBUG
EXPECT_DEATH_IF_SUPPORTED(op(),
"MemorySanitizer: use-of-uninitialized-value");
#endif
} else {
// The string is fully initialized from the initial constructor, or we skip
// the check in optimized builds.
op();
}
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(StringResizeAndOverwriteTestSuite,
StringResizeAndOverwriteTest,
::testing::ValuesIn<ResizeAndOverwriteParam>({
// Append cases.
{0, 10, 5},
{10, 10, 10},
{10, 15, 15},
{10, 20, 15},
{10, 40, 40},
{10, 50, 40},
{30, 35, 35},
{30, 45, 35},
{10, 30, 15},
// Truncate cases.
{15, 15, 10},
{40, 40, 35},
{40, 30, 10},
{10, 15, 0},
}));
// clang-format on
} // namespace