mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-16 20:41:11 +08:00
ac6a7455fd
off_t exists on Windows, but Seek is implemented in terms of SetFilePointerEx which expects a LONGLONG, so FileOffset is LONGLONG. So, use FileOffset in the test code so that it wraps at the expected value. R=mark@chromium.org BUG=crashpad:1 Review URL: https://codereview.chromium.org/854883002
381 lines
12 KiB
C++
381 lines
12 KiB
C++
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
|
//
|
|
// 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
|
|
//
|
|
// http://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 "util/file/string_file_writer.h"
|
|
|
|
#include <algorithm>
|
|
#include <limits>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace crashpad {
|
|
namespace test {
|
|
namespace {
|
|
|
|
TEST(StringFileWriter, EmptyFile) {
|
|
StringFileWriter writer;
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("", 0));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, OneByteFile) {
|
|
StringFileWriter writer;
|
|
|
|
EXPECT_TRUE(writer.Write("a", 1));
|
|
EXPECT_EQ(1u, writer.string().size());
|
|
EXPECT_EQ("a", writer.string());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("b", 1));
|
|
EXPECT_EQ(1u, writer.string().size());
|
|
EXPECT_EQ("b", writer.string());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("\0", 1));
|
|
EXPECT_EQ(1u, writer.string().size());
|
|
EXPECT_EQ('\0', writer.string()[0]);
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, Reset) {
|
|
StringFileWriter writer;
|
|
|
|
EXPECT_TRUE(writer.Write("abc", 3));
|
|
EXPECT_EQ(3u, writer.string().size());
|
|
EXPECT_EQ("abc", writer.string());
|
|
EXPECT_EQ(3, writer.Seek(0, SEEK_CUR));
|
|
|
|
writer.Reset();
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("de", 2));
|
|
EXPECT_EQ(2u, writer.string().size());
|
|
EXPECT_EQ("de", writer.string());
|
|
EXPECT_EQ(2, writer.Seek(0, SEEK_CUR));
|
|
|
|
writer.Reset();
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("fghi", 4));
|
|
EXPECT_EQ(4u, writer.string().size());
|
|
EXPECT_EQ("fghi", writer.string());
|
|
EXPECT_EQ(4, writer.Seek(0, SEEK_CUR));
|
|
|
|
writer.Reset();
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
// Test resetting after a sparse write.
|
|
EXPECT_EQ(1, writer.Seek(1, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("j", 1));
|
|
EXPECT_EQ(2u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0j", 2), writer.string());
|
|
EXPECT_EQ(2, writer.Seek(0, SEEK_CUR));
|
|
|
|
writer.Reset();
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, WriteInvalid) {
|
|
StringFileWriter writer;
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_FALSE(writer.Write(
|
|
"", implicit_cast<size_t>(std::numeric_limits<ssize_t>::max()) + 1));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("a", 1));
|
|
EXPECT_FALSE(writer.Write(
|
|
"", implicit_cast<size_t>(std::numeric_limits<ssize_t>::max())));
|
|
EXPECT_EQ(1u, writer.string().size());
|
|
EXPECT_EQ("a", writer.string());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, WriteIoVec) {
|
|
StringFileWriter writer;
|
|
|
|
std::vector<WritableIoVec> iovecs;
|
|
WritableIoVec iov;
|
|
iov.iov_base = "";
|
|
iov.iov_len = 0;
|
|
iovecs.push_back(iov);
|
|
EXPECT_TRUE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
iovecs.clear();
|
|
iov.iov_base = "a";
|
|
iov.iov_len = 1;
|
|
iovecs.push_back(iov);
|
|
EXPECT_TRUE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_EQ(1u, writer.string().size());
|
|
EXPECT_EQ("a", writer.string());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
|
|
iovecs.clear();
|
|
iovecs.push_back(iov);
|
|
EXPECT_TRUE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_EQ(2u, writer.string().size());
|
|
EXPECT_EQ("aa", writer.string());
|
|
EXPECT_EQ(2, writer.Seek(0, SEEK_CUR));
|
|
|
|
iovecs.clear();
|
|
iovecs.push_back(iov);
|
|
iov.iov_base = "bc";
|
|
iov.iov_len = 2;
|
|
iovecs.push_back(iov);
|
|
EXPECT_TRUE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("aaabc", writer.string());
|
|
EXPECT_EQ(5, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("def", 3));
|
|
EXPECT_EQ(8u, writer.string().size());
|
|
EXPECT_EQ("aaabcdef", writer.string());
|
|
EXPECT_EQ(8, writer.Seek(0, SEEK_CUR));
|
|
|
|
iovecs.clear();
|
|
iov.iov_base = "ghij";
|
|
iov.iov_len = 4;
|
|
iovecs.push_back(iov);
|
|
iov.iov_base = "klmno";
|
|
iov.iov_len = 5;
|
|
iovecs.push_back(iov);
|
|
EXPECT_TRUE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_EQ(17u, writer.string().size());
|
|
EXPECT_EQ("aaabcdefghijklmno", writer.string());
|
|
EXPECT_EQ(17, writer.Seek(0, SEEK_CUR));
|
|
|
|
writer.Reset();
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
iovecs.clear();
|
|
iov.iov_base = "abcd";
|
|
iov.iov_len = 4;
|
|
iovecs.resize(16, iov);
|
|
EXPECT_TRUE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_EQ(64u, writer.string().size());
|
|
EXPECT_EQ("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
|
writer.string());
|
|
EXPECT_EQ(64, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, WriteIoVecInvalid) {
|
|
StringFileWriter writer;
|
|
|
|
std::vector<WritableIoVec> iovecs;
|
|
EXPECT_FALSE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
|
|
WritableIoVec iov;
|
|
EXPECT_EQ(1, writer.Seek(1, SEEK_CUR));
|
|
iov.iov_base = "a";
|
|
iov.iov_len = std::numeric_limits<ssize_t>::max();
|
|
iovecs.push_back(iov);
|
|
EXPECT_FALSE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
|
|
iovecs.clear();
|
|
iov.iov_base = "a";
|
|
iov.iov_len = 1;
|
|
iovecs.push_back(iov);
|
|
iov.iov_len = std::numeric_limits<ssize_t>::max() - 1;
|
|
iovecs.push_back(iov);
|
|
EXPECT_FALSE(writer.WriteIoVec(&iovecs));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, Seek) {
|
|
StringFileWriter writer;
|
|
|
|
EXPECT_TRUE(writer.Write("abcd", 4));
|
|
EXPECT_EQ(4u, writer.string().size());
|
|
EXPECT_EQ("abcd", writer.string());
|
|
EXPECT_EQ(4, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("efgh", 4));
|
|
EXPECT_EQ(4u, writer.string().size());
|
|
EXPECT_EQ("efgh", writer.string());
|
|
EXPECT_EQ(4, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("ijk", 3));
|
|
EXPECT_EQ(4u, writer.string().size());
|
|
EXPECT_EQ("ijkh", writer.string());
|
|
EXPECT_EQ(3, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("lmnop", 5));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("lmnop", writer.string());
|
|
EXPECT_EQ(5, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(1, writer.Seek(1, SEEK_SET));
|
|
EXPECT_TRUE(writer.Write("q", 1));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("lqnop", writer.string());
|
|
EXPECT_EQ(2, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(1, writer.Seek(-1, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("r", 1));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("lrnop", writer.string());
|
|
EXPECT_EQ(2, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("s", 1));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("lrsop", writer.string());
|
|
EXPECT_EQ(3, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(2, writer.Seek(-1, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("t", 1));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("lrtop", writer.string());
|
|
EXPECT_EQ(3, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(4, writer.Seek(-1, SEEK_END));
|
|
EXPECT_TRUE(writer.Write("u", 1));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("lrtou", writer.string());
|
|
EXPECT_EQ(5, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(0, writer.Seek(-5, SEEK_END));
|
|
EXPECT_TRUE(writer.Write("v", 1));
|
|
EXPECT_EQ(5u, writer.string().size());
|
|
EXPECT_EQ("vrtou", writer.string());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(5, writer.Seek(0, SEEK_END));
|
|
EXPECT_TRUE(writer.Write("w", 1));
|
|
EXPECT_EQ(6u, writer.string().size());
|
|
EXPECT_EQ("vrtouw", writer.string());
|
|
EXPECT_EQ(6, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(8, writer.Seek(2, SEEK_END));
|
|
EXPECT_EQ(6u, writer.string().size());
|
|
EXPECT_EQ("vrtouw", writer.string());
|
|
|
|
EXPECT_EQ(6, writer.Seek(0, SEEK_END));
|
|
EXPECT_TRUE(writer.Write("x", 1));
|
|
EXPECT_EQ(7u, writer.string().size());
|
|
EXPECT_EQ("vrtouwx", writer.string());
|
|
EXPECT_EQ(7, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, SeekSparse) {
|
|
StringFileWriter writer;
|
|
|
|
EXPECT_EQ(3, writer.Seek(3, SEEK_SET));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
EXPECT_EQ(3, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("abc", 3));
|
|
EXPECT_EQ(6u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0\0\0abc", 6), writer.string());
|
|
EXPECT_EQ(6, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(9, writer.Seek(3, SEEK_END));
|
|
EXPECT_EQ(6u, writer.string().size());
|
|
EXPECT_EQ(9, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("def", 3));
|
|
EXPECT_EQ(12u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0\0\0abc\0\0\0def", 12), writer.string());
|
|
EXPECT_EQ(12, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(7, writer.Seek(-5, SEEK_END));
|
|
EXPECT_EQ(12u, writer.string().size());
|
|
EXPECT_EQ(7, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("g", 1));
|
|
EXPECT_EQ(12u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0\0\0abc\0g\0def", 12), writer.string());
|
|
EXPECT_EQ(8, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(15, writer.Seek(7, SEEK_CUR));
|
|
EXPECT_EQ(12u, writer.string().size());
|
|
EXPECT_EQ(15, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("hij", 3));
|
|
EXPECT_EQ(18u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0\0\0abc\0g\0def\0\0\0hij", 18), writer.string());
|
|
EXPECT_EQ(18, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_EQ(1, writer.Seek(-17, SEEK_CUR));
|
|
EXPECT_EQ(18u, writer.string().size());
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.Write("k", 1));
|
|
EXPECT_EQ(18u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0k\0abc\0g\0def\0\0\0hij", 18), writer.string());
|
|
EXPECT_EQ(2, writer.Seek(0, SEEK_CUR));
|
|
|
|
EXPECT_TRUE(writer.Write("l", 1));
|
|
EXPECT_TRUE(writer.Write("mnop", 4));
|
|
EXPECT_EQ(18u, writer.string().size());
|
|
EXPECT_EQ(std::string("\0klmnopg\0def\0\0\0hij", 18), writer.string());
|
|
EXPECT_EQ(7, writer.Seek(0, SEEK_CUR));
|
|
}
|
|
|
|
TEST(StringFileWriter, SeekInvalid) {
|
|
StringFileWriter writer;
|
|
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_EQ(1, writer.Seek(1, SEEK_SET));
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_LT(writer.Seek(-1, SEEK_SET), 0);
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_LT(writer.Seek(std::numeric_limits<ssize_t>::min(), SEEK_SET), 0);
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_LT(writer.Seek(std::numeric_limits<FileOffset>::min(), SEEK_SET), 0);
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
|
|
static_assert(SEEK_SET != 3 && SEEK_CUR != 3 && SEEK_END != 3,
|
|
"3 must be invalid for whence");
|
|
EXPECT_LT(writer.Seek(0, 3), 0);
|
|
|
|
writer.Reset();
|
|
EXPECT_EQ(0, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_TRUE(writer.string().empty());
|
|
|
|
const FileOffset kMaxOffset = static_cast<FileOffset>(
|
|
std::min(implicit_cast<uint64_t>(std::numeric_limits<FileOffset>::max()),
|
|
implicit_cast<uint64_t>(std::numeric_limits<size_t>::max())));
|
|
|
|
EXPECT_EQ(kMaxOffset, writer.Seek(kMaxOffset, SEEK_SET));
|
|
EXPECT_EQ(kMaxOffset, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_LT(writer.Seek(1, SEEK_CUR), 0);
|
|
|
|
EXPECT_EQ(1, writer.Seek(1, SEEK_SET));
|
|
EXPECT_EQ(1, writer.Seek(0, SEEK_CUR));
|
|
EXPECT_LT(writer.Seek(kMaxOffset, SEEK_CUR), 0);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace test
|
|
} // namespace crashpad
|