blob: 9ce0654a5305392301c7e82e9920e8347e4b1fa1 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <fbl/name.h>
#include <lib/unittest/unittest.h>
namespace {
constexpr char fill = 0x7f;
bool buffer_invariants_hold(const char* buf, size_t size) {
// The buffer should start with zero or more non-NUL bytes followed
// by a NUL.
unsigned int idx = 0;
while (buf[idx] != 0) {
idx++;
if (idx == size) {
unittest_printf("No NUL byte found\n");
return false;
}
}
idx++; // Skip the NUL
// The rest of the buffer should be filled with the NUL byte
// to ensure stale data isn't leaked.
while (idx < size) {
if (buf[idx] != '\0') {
unsigned int byte = buf[idx];
unittest_printf(
"buf[%u] 0x%02x != 0x00\n", idx, byte);
return false;
}
idx++;
}
return true;
}
template <size_t Size>
bool empty_ctor() {
BEGIN_TEST;
// Note on |out| sizes: most tests use Size * 2 to ensure the out buffer is
// more than big enough to read the entire name with room to spare.
char out[Size * 2];
memset(out, fill, sizeof(out));
fbl::Name<Size> name;
name.get(sizeof(out), out);
EXPECT_EQ(out[0], 0, "");
EXPECT_TRUE(buffer_invariants_hold(out, sizeof(out)), "");
END_TEST;
}
template <size_t Size>
bool named_ctor_empty() {
BEGIN_TEST;
char out[Size * 2];
memset(out, fill, sizeof(out));
fbl::Name<Size> name("", 1);
name.get(sizeof(out), out);
EXPECT_EQ(out[0], 0, "");
EXPECT_TRUE(buffer_invariants_hold(out, sizeof(out)), "");
END_TEST;
}
template <size_t Size>
bool named_ctor_small() {
BEGIN_TEST;
char out[Size * 2];
memset(out, fill, sizeof(out));
fbl::Name<Size> name("a", 2);
name.get(sizeof(out), out);
EXPECT_EQ(out[0], 'a', "");
EXPECT_EQ(out[1], 0, "");
EXPECT_TRUE(buffer_invariants_hold(out, sizeof(out)), "");
END_TEST;
}
template <size_t Size>
bool named_ctor_exact() {
BEGIN_TEST;
char out[Size * 2];
memset(out, fill, sizeof(out));
char expected_name[Size];
memset(expected_name, 'z', Size - 1);
expected_name[Size - 1] = 0;
fbl::Name<Size> name(expected_name, Size);
name.get(sizeof(out), out);
for (size_t idx = 0; idx < Size - 1; ++idx) {
EXPECT_EQ(out[idx], 'z', "");
}
EXPECT_EQ(out[Size - 1], 0, "");
EXPECT_TRUE(buffer_invariants_hold(out, sizeof(out)), "");
END_TEST;
}
template <size_t Size>
bool named_ctor_overflow() {
BEGIN_TEST;
constexpr size_t overflow_size = 2 * Size;
char out[overflow_size * 2];
memset(out, fill, sizeof(out));
char expected_name[overflow_size];
memset(expected_name, 'z', overflow_size - 1);
expected_name[overflow_size - 1] = 0;
fbl::Name<Size> name(expected_name, overflow_size);
name.get(sizeof(out), out);
for (size_t idx = 0; idx < Size - 1; ++idx) {
EXPECT_EQ(out[idx], 'z', "");
}
EXPECT_EQ(out[Size - 1], 0, "");
EXPECT_TRUE(buffer_invariants_hold(out, sizeof(out)), "");
END_TEST;
}
template <size_t Size>
bool zero_sized_output_buffer() {
BEGIN_TEST;
// Neither of these bytes should be touched.
char out[2] = {fill, fill};
fbl::Name<Size> name("a", 2);
name.get(0, out);
EXPECT_EQ(out[0], fill, "");
EXPECT_EQ(out[1], fill, "");
END_TEST;
}
template <size_t NameSize, size_t OutSize>
bool output_buffer_size() {
static_assert(OutSize > 0, ""); // |OutSize - 1| below would fail.
BEGIN_TEST;
// Longest name possible.
char expected_name[NameSize];
memset(expected_name, 'z', NameSize - 1);
expected_name[NameSize - 1] = 0;
char out[OutSize + 2]; // Extra fill at the end.
memset(out, fill, sizeof(out));
fbl::Name<NameSize> name(expected_name, sizeof(expected_name));
name.get(OutSize, out);
// Check that the name fits in the size we passed to Name::get().
for (size_t idx = 0; idx < OutSize - 1; ++idx) {
char msg[32];
snprintf(msg, sizeof(msg), "idx=%zu", idx);
EXPECT_EQ(out[idx], 'z', msg);
}
EXPECT_EQ(out[OutSize - 1], 0, "");
// Check that the extra fill is intact.
EXPECT_TRUE(buffer_invariants_hold(out, OutSize), "");
EXPECT_EQ(out[OutSize], fill, "");
EXPECT_EQ(out[OutSize+1], fill, "");
END_TEST;
}
// Test the smallest size and a typical size.
constexpr size_t kSmallestNameSize = 2;
constexpr size_t kTypicalNameSize = 32;
} // namespace
#define NAME_UNITTEST(fname) UNITTEST(#fname, fname)
UNITTEST_START_TESTCASE(name_tests)
NAME_UNITTEST(empty_ctor<kSmallestNameSize>)
NAME_UNITTEST(empty_ctor<kTypicalNameSize>)
NAME_UNITTEST(named_ctor_empty<kSmallestNameSize>)
NAME_UNITTEST(named_ctor_empty<kTypicalNameSize>)
NAME_UNITTEST(named_ctor_small<kSmallestNameSize>)
NAME_UNITTEST(named_ctor_small<kTypicalNameSize>)
NAME_UNITTEST(named_ctor_exact<kSmallestNameSize>)
NAME_UNITTEST(named_ctor_exact<kTypicalNameSize>)
NAME_UNITTEST(named_ctor_overflow<kSmallestNameSize>)
NAME_UNITTEST(named_ctor_overflow<kTypicalNameSize>)
NAME_UNITTEST(zero_sized_output_buffer<kSmallestNameSize>)
NAME_UNITTEST(zero_sized_output_buffer<kTypicalNameSize>)
// Output buffer only contains NUL.
NAME_UNITTEST((output_buffer_size<kTypicalNameSize, 1>))
// Smallest useful output buffer.
NAME_UNITTEST((output_buffer_size<kTypicalNameSize, 2>))
// Edge cases around exactly matching the Name length.
NAME_UNITTEST((output_buffer_size<kTypicalNameSize, kTypicalNameSize - 2>))
NAME_UNITTEST((output_buffer_size<kTypicalNameSize, kTypicalNameSize - 1>))
NAME_UNITTEST((output_buffer_size<kTypicalNameSize, kTypicalNameSize>))
// Don't bother testing a larger output buffer, since most of the
// earlier tests use larger output buffers.
UNITTEST_END_TESTCASE(name_tests, "nametests", "Name test");