2011-09-13 21:42:16 +02:00
|
|
|
//===- llvm/unittest/Support/DataExtractorTest.cpp - DataExtractor tests --===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-09-13 21:42:16 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Support/DataExtractor.h"
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 13:24:08 +02:00
|
|
|
#include "llvm/Testing/Support/Error.h"
|
2017-06-06 13:06:56 +02:00
|
|
|
#include "gtest/gtest.h"
|
2011-09-13 21:42:16 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const char numberData[] = "\x80\x90\xFF\xFF\x80\x00\x00\x00";
|
|
|
|
const char leb128data[] = "\xA6\x49";
|
2012-08-20 12:52:11 +02:00
|
|
|
const char bigleb128data[] = "\xAA\xA9\xFF\xAA\xFF\xAA\xFF\x4A";
|
2011-09-13 21:42:16 +02:00
|
|
|
|
2019-08-07 13:44:47 +02:00
|
|
|
TEST(DataExtractorTest, OffsetOverflow) {
|
2011-09-13 21:42:16 +02:00
|
|
|
DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8);
|
|
|
|
EXPECT_FALSE(DE.isValidOffsetForDataOfSize(-2U, 5));
|
|
|
|
}
|
|
|
|
|
2019-08-07 13:44:47 +02:00
|
|
|
TEST(DataExtractorTest, UnsignedNumbers) {
|
2011-09-13 21:42:16 +02:00
|
|
|
DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8);
|
2019-08-07 13:44:47 +02:00
|
|
|
uint64_t offset = 0;
|
2011-09-13 21:42:16 +02:00
|
|
|
|
|
|
|
EXPECT_EQ(0x80U, DE.getU8(&offset));
|
|
|
|
EXPECT_EQ(1U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(0x8090U, DE.getU16(&offset));
|
|
|
|
EXPECT_EQ(2U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(0x8090FFFFU, DE.getU32(&offset));
|
|
|
|
EXPECT_EQ(4U, offset);
|
|
|
|
offset = 0;
|
2011-09-14 01:23:49 +02:00
|
|
|
EXPECT_EQ(0x8090FFFF80000000ULL, DE.getU64(&offset));
|
2011-09-13 21:42:16 +02:00
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
offset = 0;
|
2011-09-14 01:23:49 +02:00
|
|
|
EXPECT_EQ(0x8090FFFF80000000ULL, DE.getAddress(&offset));
|
2011-09-13 21:42:16 +02:00
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
uint32_t data[2];
|
|
|
|
EXPECT_EQ(data, DE.getU32(&offset, data, 2));
|
|
|
|
EXPECT_EQ(0x8090FFFFU, data[0]);
|
|
|
|
EXPECT_EQ(0x80000000U, data[1]);
|
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
// Now for little endian.
|
|
|
|
DE = DataExtractor(StringRef(numberData, sizeof(numberData)-1), true, 4);
|
|
|
|
EXPECT_EQ(0x9080U, DE.getU16(&offset));
|
|
|
|
EXPECT_EQ(2U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(0xFFFF9080U, DE.getU32(&offset));
|
|
|
|
EXPECT_EQ(4U, offset);
|
|
|
|
offset = 0;
|
2011-09-14 01:23:49 +02:00
|
|
|
EXPECT_EQ(0x80FFFF9080ULL, DE.getU64(&offset));
|
2011-09-13 21:42:16 +02:00
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(0xFFFF9080U, DE.getAddress(&offset));
|
|
|
|
EXPECT_EQ(4U, offset);
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
EXPECT_EQ(data, DE.getU32(&offset, data, 2));
|
|
|
|
EXPECT_EQ(0xFFFF9080U, data[0]);
|
|
|
|
EXPECT_EQ(0x80U, data[1]);
|
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
}
|
|
|
|
|
2019-08-07 13:44:47 +02:00
|
|
|
TEST(DataExtractorTest, SignedNumbers) {
|
2011-09-13 21:42:16 +02:00
|
|
|
DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8);
|
2019-08-07 13:44:47 +02:00
|
|
|
uint64_t offset = 0;
|
2011-09-13 21:42:16 +02:00
|
|
|
|
|
|
|
EXPECT_EQ(-128, DE.getSigned(&offset, 1));
|
|
|
|
EXPECT_EQ(1U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(-32624, DE.getSigned(&offset, 2));
|
|
|
|
EXPECT_EQ(2U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(-2137980929, DE.getSigned(&offset, 4));
|
|
|
|
EXPECT_EQ(4U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(-9182558167379214336LL, DE.getSigned(&offset, 8));
|
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
}
|
|
|
|
|
2019-08-07 13:44:47 +02:00
|
|
|
TEST(DataExtractorTest, Strings) {
|
2020-03-23 16:15:49 +01:00
|
|
|
const char stringData[] = "hellohello\0hello";
|
2011-09-13 21:42:16 +02:00
|
|
|
DataExtractor DE(StringRef(stringData, sizeof(stringData)-1), false, 8);
|
2019-08-07 13:44:47 +02:00
|
|
|
uint64_t offset = 0;
|
2011-09-13 21:42:16 +02:00
|
|
|
|
|
|
|
EXPECT_EQ(stringData, DE.getCStr(&offset));
|
|
|
|
EXPECT_EQ(11U, offset);
|
2014-06-09 00:29:17 +02:00
|
|
|
EXPECT_EQ(nullptr, DE.getCStr(&offset));
|
2011-09-13 21:42:16 +02:00
|
|
|
EXPECT_EQ(11U, offset);
|
2020-03-23 16:15:49 +01:00
|
|
|
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
EXPECT_EQ(stringData, DE.getCStr(C));
|
|
|
|
EXPECT_EQ(11U, C.tell());
|
|
|
|
EXPECT_EQ(nullptr, DE.getCStr(C));
|
|
|
|
EXPECT_EQ(11U, C.tell());
|
2020-04-20 17:28:15 +02:00
|
|
|
EXPECT_THAT_ERROR(
|
|
|
|
C.takeError(),
|
|
|
|
FailedWithMessage("no null terminated string at offset 0xb"));
|
2011-09-13 21:42:16 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 13:44:47 +02:00
|
|
|
TEST(DataExtractorTest, LEB128) {
|
2011-09-13 21:42:16 +02:00
|
|
|
DataExtractor DE(StringRef(leb128data, sizeof(leb128data)-1), false, 8);
|
2019-08-07 13:44:47 +02:00
|
|
|
uint64_t offset = 0;
|
2011-09-13 21:42:16 +02:00
|
|
|
|
|
|
|
EXPECT_EQ(9382ULL, DE.getULEB128(&offset));
|
|
|
|
EXPECT_EQ(2U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(-7002LL, DE.getSLEB128(&offset));
|
|
|
|
EXPECT_EQ(2U, offset);
|
2012-08-20 12:52:11 +02:00
|
|
|
|
|
|
|
DataExtractor BDE(StringRef(bigleb128data, sizeof(bigleb128data)-1), false,8);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(42218325750568106ULL, BDE.getULEB128(&offset));
|
|
|
|
EXPECT_EQ(8U, offset);
|
|
|
|
offset = 0;
|
|
|
|
EXPECT_EQ(-29839268287359830LL, BDE.getSLEB128(&offset));
|
|
|
|
EXPECT_EQ(8U, offset);
|
2011-09-13 21:42:16 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 13:44:47 +02:00
|
|
|
TEST(DataExtractorTest, LEB128_error) {
|
2019-06-24 11:11:24 +02:00
|
|
|
DataExtractor DE(StringRef("\x81"), false, 8);
|
2019-08-07 13:44:47 +02:00
|
|
|
uint64_t Offset = 0;
|
2019-06-24 11:11:24 +02:00
|
|
|
EXPECT_EQ(0U, DE.getULEB128(&Offset));
|
|
|
|
EXPECT_EQ(0U, Offset);
|
|
|
|
|
|
|
|
Offset = 0;
|
|
|
|
EXPECT_EQ(0U, DE.getSLEB128(&Offset));
|
|
|
|
EXPECT_EQ(0U, Offset);
|
2020-03-24 17:49:55 +01:00
|
|
|
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
EXPECT_EQ(0U, DE.getULEB128(C));
|
2020-05-22 14:53:47 +02:00
|
|
|
EXPECT_THAT_ERROR(
|
|
|
|
C.takeError(),
|
|
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000000: "
|
|
|
|
"malformed uleb128, extends past end"));
|
2020-03-24 17:49:55 +01:00
|
|
|
|
|
|
|
C = DataExtractor::Cursor(0);
|
|
|
|
EXPECT_EQ(0U, DE.getSLEB128(C));
|
2020-05-22 14:53:47 +02:00
|
|
|
EXPECT_THAT_ERROR(
|
|
|
|
C.takeError(),
|
|
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000000: "
|
|
|
|
"malformed sleb128, extends past end"));
|
|
|
|
|
|
|
|
// Show non-zero offsets are reported appropriately.
|
|
|
|
C = DataExtractor::Cursor(1);
|
|
|
|
EXPECT_EQ(0U, DE.getULEB128(C));
|
|
|
|
EXPECT_THAT_ERROR(
|
|
|
|
C.takeError(),
|
|
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
|
|
|
|
"malformed uleb128, extends past end"));
|
2019-06-24 11:11:24 +02:00
|
|
|
}
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 13:24:08 +02:00
|
|
|
|
|
|
|
TEST(DataExtractorTest, Cursor_tell) {
|
|
|
|
DataExtractor DE(StringRef("AB"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
// A successful read operation advances the cursor
|
|
|
|
EXPECT_EQ('A', DE.getU8(C));
|
|
|
|
EXPECT_EQ(1u, C.tell());
|
|
|
|
|
|
|
|
// An unsuccessful one doesn't.
|
|
|
|
EXPECT_EQ(0u, DE.getU16(C));
|
|
|
|
EXPECT_EQ(1u, C.tell());
|
|
|
|
|
|
|
|
// And neither do any subsequent operations.
|
|
|
|
EXPECT_EQ(0, DE.getU8(C));
|
|
|
|
EXPECT_EQ(1u, C.tell());
|
|
|
|
|
|
|
|
consumeError(C.takeError());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DataExtractorTest, Cursor_takeError) {
|
|
|
|
DataExtractor DE(StringRef("AB"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
// Initially, the cursor is in the "success" state.
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
|
|
|
|
// It remains "success" after a successful read.
|
|
|
|
EXPECT_EQ('A', DE.getU8(C));
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
|
|
|
|
// An unsuccessful read sets the error state.
|
|
|
|
EXPECT_EQ(0u, DE.getU32(C));
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
|
|
|
|
|
|
|
// Once set the error sticks until explicitly cleared.
|
|
|
|
EXPECT_EQ(0u, DE.getU32(C));
|
|
|
|
EXPECT_EQ(0, DE.getU8(C));
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
|
|
|
|
|
|
|
// At which point reads can be succeed again.
|
|
|
|
EXPECT_EQ('B', DE.getU8(C));
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DataExtractorTest, Cursor_chaining) {
|
|
|
|
DataExtractor DE(StringRef("ABCD"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
|
|
|
|
// Multiple reads can be chained without trigerring any assertions.
|
|
|
|
EXPECT_EQ('A', DE.getU8(C));
|
|
|
|
EXPECT_EQ('B', DE.getU8(C));
|
|
|
|
EXPECT_EQ('C', DE.getU8(C));
|
|
|
|
EXPECT_EQ('D', DE.getU8(C));
|
|
|
|
// And the error checked at the end.
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
}
|
|
|
|
|
2021-01-07 23:17:24 +01:00
|
|
|
#if defined(GTEST_HAS_DEATH_TEST) && defined(_DEBUG) && \
|
|
|
|
LLVM_ENABLE_ABI_BREAKING_CHECKS
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 13:24:08 +02:00
|
|
|
TEST(DataExtractorDeathTest, Cursor) {
|
|
|
|
DataExtractor DE(StringRef("AB"), false, 8);
|
|
|
|
|
|
|
|
// Even an unused cursor must be checked for errors:
|
|
|
|
EXPECT_DEATH(DataExtractor::Cursor(0),
|
|
|
|
"Success values must still be checked prior to being destroyed");
|
|
|
|
|
|
|
|
{
|
|
|
|
auto C = std::make_unique<DataExtractor::Cursor>(0);
|
|
|
|
EXPECT_EQ(0u, DE.getU32(*C));
|
|
|
|
// It must also be checked after an unsuccessful operation.
|
|
|
|
// destruction.
|
|
|
|
EXPECT_DEATH(C.reset(), "unexpected end of data");
|
|
|
|
EXPECT_THAT_ERROR(C->takeError(), Failed());
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto C = std::make_unique<DataExtractor::Cursor>(0);
|
|
|
|
EXPECT_EQ('A', DE.getU8(*C));
|
|
|
|
// Same goes for a successful one.
|
|
|
|
EXPECT_DEATH(
|
|
|
|
C.reset(),
|
|
|
|
"Success values must still be checked prior to being destroyed");
|
|
|
|
EXPECT_THAT_ERROR(C->takeError(), Succeeded());
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto C = std::make_unique<DataExtractor::Cursor>(0);
|
|
|
|
EXPECT_EQ('A', DE.getU8(*C));
|
|
|
|
EXPECT_EQ(0u, DE.getU32(*C));
|
|
|
|
// Even if a successful operation is followed by an unsuccessful one.
|
|
|
|
EXPECT_DEATH(C.reset(), "unexpected end of data");
|
|
|
|
EXPECT_THAT_ERROR(C->takeError(), Failed());
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto C = std::make_unique<DataExtractor::Cursor>(0);
|
|
|
|
EXPECT_EQ(0u, DE.getU32(*C));
|
|
|
|
EXPECT_EQ(0, DE.getU8(*C));
|
|
|
|
// Even if an unsuccessful operation is followed by one that would normally
|
|
|
|
// succeed.
|
|
|
|
EXPECT_DEATH(C.reset(), "unexpected end of data");
|
|
|
|
EXPECT_THAT_ERROR(C->takeError(), Failed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TEST(DataExtractorTest, getU8_vector) {
|
|
|
|
DataExtractor DE(StringRef("AB"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
SmallVector<uint8_t, 2> S;
|
|
|
|
|
|
|
|
DE.getU8(C, S, 4);
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
|
|
|
EXPECT_EQ("", toStringRef(S));
|
|
|
|
|
|
|
|
DE.getU8(C, S, 2);
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
EXPECT_EQ("AB", toStringRef(S));
|
2020-04-20 17:28:15 +02:00
|
|
|
|
|
|
|
C = DataExtractor::Cursor(0x47);
|
|
|
|
DE.getU8(C, S, 2);
|
|
|
|
EXPECT_THAT_ERROR(
|
|
|
|
C.takeError(),
|
|
|
|
FailedWithMessage("offset 0x47 is beyond the end of data at 0x2"));
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 13:24:08 +02:00
|
|
|
}
|
|
|
|
|
2020-03-24 17:49:55 +01:00
|
|
|
TEST(DataExtractorTest, getU24) {
|
|
|
|
DataExtractor DE(StringRef("ABCD"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
|
|
|
|
EXPECT_EQ(0x414243u, DE.getU24(C));
|
|
|
|
EXPECT_EQ(0u, DE.getU24(C));
|
|
|
|
EXPECT_EQ(3u, C.tell());
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
|
|
|
}
|
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 13:24:08 +02:00
|
|
|
TEST(DataExtractorTest, skip) {
|
|
|
|
DataExtractor DE(StringRef("AB"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
|
|
|
|
DE.skip(C, 4);
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
|
|
|
EXPECT_EQ(0u, C.tell());
|
|
|
|
|
|
|
|
DE.skip(C, 2);
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
EXPECT_EQ(2u, C.tell());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DataExtractorTest, eof) {
|
|
|
|
DataExtractor DE(StringRef("A"), false, 8);
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
|
|
|
|
EXPECT_FALSE(DE.eof(C));
|
|
|
|
|
|
|
|
EXPECT_EQ(0, DE.getU16(C));
|
|
|
|
EXPECT_FALSE(DE.eof(C));
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
|
|
|
|
|
|
|
EXPECT_EQ('A', DE.getU8(C));
|
|
|
|
EXPECT_TRUE(DE.eof(C));
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Succeeded());
|
|
|
|
}
|
2020-01-13 10:30:52 +01:00
|
|
|
|
|
|
|
TEST(DataExtractorTest, size) {
|
|
|
|
uint8_t Data[] = {'A', 'B', 'C', 'D'};
|
|
|
|
DataExtractor DE1(StringRef(reinterpret_cast<char *>(Data), sizeof(Data)),
|
|
|
|
false, 8);
|
|
|
|
EXPECT_EQ(DE1.size(), sizeof(Data));
|
|
|
|
DataExtractor DE2(ArrayRef<uint8_t>(Data), false, 8);
|
|
|
|
EXPECT_EQ(DE2.size(), sizeof(Data));
|
|
|
|
}
|
2020-02-22 00:21:07 +01:00
|
|
|
|
|
|
|
TEST(DataExtractorTest, FixedLengthString) {
|
|
|
|
const char Data[] = "hello\x00\x00\x00world \thola\x00";
|
|
|
|
DataExtractor DE(StringRef(Data, sizeof(Data)-1), false, 8);
|
|
|
|
uint64_t Offset = 0;
|
|
|
|
StringRef Str;
|
|
|
|
// Test extracting too many bytes doesn't modify Offset and returns None.
|
|
|
|
Str = DE.getFixedLengthString(&Offset, sizeof(Data));
|
|
|
|
EXPECT_TRUE(Str.empty());
|
|
|
|
EXPECT_EQ(Offset, 0u);
|
|
|
|
|
|
|
|
// Test extracting a fixed width C string with trailing NULL characters.
|
|
|
|
Str = DE.getFixedLengthString(&Offset, 8);
|
|
|
|
EXPECT_EQ(Offset, 8u);
|
|
|
|
EXPECT_EQ(Str.size(), 5u);
|
|
|
|
EXPECT_EQ(Str, "hello");
|
|
|
|
// Test extracting a fixed width C string with trailing space and tab
|
|
|
|
// characters.
|
|
|
|
Str = DE.getFixedLengthString(&Offset, 8, " \t");
|
|
|
|
EXPECT_EQ(Offset, 16u);
|
|
|
|
EXPECT_EQ(Str.size(), 5u);
|
|
|
|
EXPECT_EQ(Str, "world");
|
|
|
|
// Now extract a normal C string.
|
|
|
|
Str = DE.getCStrRef(&Offset);
|
|
|
|
EXPECT_EQ(Str.size(), 4u);
|
|
|
|
EXPECT_EQ(Str, "hola");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST(DataExtractorTest, GetBytes) {
|
|
|
|
// Use data with an embedded NULL character for good measure.
|
|
|
|
const char Data[] = "\x01\x02\x00\x04";
|
|
|
|
StringRef Bytes(Data, sizeof(Data)-1);
|
|
|
|
DataExtractor DE(Bytes, false, 8);
|
|
|
|
uint64_t Offset = 0;
|
|
|
|
StringRef Str;
|
|
|
|
// Test extracting too many bytes doesn't modify Offset and returns None.
|
|
|
|
Str = DE.getBytes(&Offset, sizeof(Data));
|
|
|
|
EXPECT_TRUE(Str.empty());
|
|
|
|
EXPECT_EQ(Offset, 0u);
|
|
|
|
// Test extracting 4 bytes from the stream.
|
|
|
|
Str = DE.getBytes(&Offset, 4);
|
|
|
|
EXPECT_EQ(Offset, 4u);
|
|
|
|
EXPECT_EQ(Str.size(), 4u);
|
|
|
|
EXPECT_EQ(Str, Bytes);
|
2020-03-24 17:49:55 +01:00
|
|
|
|
|
|
|
DataExtractor::Cursor C(0);
|
|
|
|
EXPECT_EQ(StringRef("\x01\x02"), DE.getBytes(C, 2));
|
|
|
|
EXPECT_EQ(StringRef("\x00\x04", 2), DE.getBytes(C, 2));
|
|
|
|
EXPECT_EQ(StringRef(), DE.getBytes(C, 2));
|
|
|
|
EXPECT_EQ(StringRef(), DE.getBytes(C, 2));
|
|
|
|
EXPECT_EQ(4u, C.tell());
|
|
|
|
EXPECT_THAT_ERROR(C.takeError(), Failed());
|
2020-02-22 00:21:07 +01:00
|
|
|
}
|
|
|
|
|
2011-09-13 21:42:16 +02:00
|
|
|
}
|