blob: bccb314e13388f905c028b466119f758a60cede9 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "binary_decoder.h"
#include <zircon/errors.h>
#include <array>
#include <cstdint>
#include <vector>
#include <zxtest/zxtest.h>
namespace audio::intel_hda {
namespace {
TEST(BinaryDecoder, Empty) {
BinaryDecoder decoder{fbl::Span<uint8_t>()};
// Empty read.
auto empty_read = decoder.Read(0);
ASSERT_TRUE(empty_read.ok());
EXPECT_EQ(empty_read.ValueOrDie().size(), 0);
// Non-empty read.
ASSERT_EQ(decoder.Read(1).status().code(), ZX_ERR_OUT_OF_RANGE);
}
TEST(BinaryDecoder, NonEmptyRead) {
std::array<uint8_t, 5> buffer;
BinaryDecoder decoder{fbl::Span<uint8_t>(buffer.begin(), buffer.size())};
// Successful read.
auto a = decoder.Read(1);
ASSERT_TRUE(a.ok());
EXPECT_EQ(a.ValueOrDie().size(), 1);
EXPECT_EQ(a.ValueOrDie().begin(), &buffer[0]);
// Another read.
auto b = decoder.Read(1);
ASSERT_TRUE(b.ok());
EXPECT_EQ(b.ValueOrDie().size(), 1);
EXPECT_EQ(b.ValueOrDie().begin(), &buffer[1]);
// Too big a read.
auto c = decoder.Read(4);
ASSERT_EQ(c.status().code(), ZX_ERR_OUT_OF_RANGE);
// But we should still be able to read the last three bytes.
auto d = decoder.Read(3);
ASSERT_TRUE(d.ok());
EXPECT_EQ(d.ValueOrDie().size(), 3);
EXPECT_EQ(d.ValueOrDie().begin(), &buffer[2]);
}
TEST(BinaryDecoder, ReadStruct) {
struct MyStruct {
char a, b;
};
// Can't read from too small a buffer.
{
std::array<uint8_t, 1> small_buffer = {1};
BinaryDecoder decoderA{fbl::Span<uint8_t>(small_buffer.begin(), small_buffer.size())};
ASSERT_EQ(decoderA.Read<MyStruct>().status().code(), ZX_ERR_OUT_OF_RANGE);
}
// We should be able to read from a precisely sized buffer.
{
std::array<uint8_t, 2> correct_buffer = {1, 2};
BinaryDecoder decoderB{fbl::Span<uint8_t>(correct_buffer.begin(), correct_buffer.size())};
auto value = decoderB.Read<MyStruct>();
ASSERT_TRUE(value.ok());
EXPECT_EQ(value.ValueOrDie().a, 1);
EXPECT_EQ(value.ValueOrDie().b, 2);
EXPECT_FALSE(decoderB.Read(1).ok());
}
// Reading from the beginning of a buffer is fine too.
{
std::array<uint8_t, 3> big_buffer = {1, 2, 3};
BinaryDecoder decoderC{fbl::Span<uint8_t>(big_buffer.begin(), big_buffer.size())};
auto value = decoderC.Read<MyStruct>();
ASSERT_TRUE(value.ok());
EXPECT_EQ(value.ValueOrDie().a, 1);
EXPECT_EQ(value.ValueOrDie().b, 2);
EXPECT_TRUE(decoderC.Read(1).ok());
}
}
TEST(BinaryDecoder, ReadIntoPointerSuccess) {
struct MyStruct {
char a, b;
};
std::array<uint8_t, 2> correct_buffer = {1, 2};
BinaryDecoder decoderB{fbl::Span<uint8_t>(correct_buffer.begin(), correct_buffer.size())};
MyStruct value;
EXPECT_TRUE(decoderB.Read<MyStruct>(&value).ok());
EXPECT_EQ(value.a, 1);
EXPECT_EQ(value.b, 2);
}
TEST(BinaryDecoder, ReadIntoPointerFailure) {
struct MyStruct {
char a, b;
};
std::array<uint8_t, 1> small_buffer = {1};
BinaryDecoder decoderC{fbl::Span<uint8_t>(small_buffer.begin(), small_buffer.size())};
MyStruct value;
EXPECT_FALSE(decoderC.Read<MyStruct>(&value).ok());
}
TEST(BinaryDecoder, VarLengthRead) {
struct VarLength {
char size;
char data;
};
// Insufficient data available.
{
BinaryDecoder d{fbl::Span<uint8_t>()};
ASSERT_FALSE((d.VariableLengthRead<VarLength>(&VarLength::size).ok()));
}
// Length is smaller than the header structure.
{
std::array<uint8_t, 3> buffer = {/*size=*/1, /*data=*/2, /*payload=*/3};
BinaryDecoder d{fbl::Span<uint8_t>(buffer.begin(), buffer.size())};
EXPECT_EQ(d.VariableLengthRead<VarLength>(&VarLength::size).status().code(),
ZX_ERR_OUT_OF_RANGE);
}
// Length is larger than the buffer.
{
std::array<uint8_t, 3> buffer = {/*size=*/4, /*data=*/2, /*payload=*/3};
BinaryDecoder d{fbl::Span<uint8_t>(buffer.begin(), buffer.size())};
EXPECT_EQ(d.VariableLengthRead<VarLength>(&VarLength::size).status().code(),
ZX_ERR_OUT_OF_RANGE);
}
// Successful read.
{
std::array<uint8_t, 3> buffer = {/*size=*/3, /*data=*/2, /*payload=*/1};
BinaryDecoder d{fbl::Span<uint8_t>(buffer.begin(), buffer.size())};
auto maybe_val = d.VariableLengthRead<VarLength>(&VarLength::size);
ASSERT_TRUE(maybe_val.ok());
auto [val, payload] = maybe_val.ValueOrDie();
EXPECT_EQ(val.size, 3);
EXPECT_EQ(val.data, 2);
EXPECT_EQ(payload.size(), 1);
EXPECT_EQ(payload.begin(), &buffer[2]);
}
}
TEST(ParseUnpaddedString, Empty) {
char buff[2] = "";
EXPECT_EQ("", ParseUnpaddedString(buff));
}
TEST(ParseUnpaddedString, SingleChar) {
char buff[2] = "A";
EXPECT_EQ("A", ParseUnpaddedString(buff));
}
TEST(ParseUnpaddedString, ConstChar) {
const char buff[2] = "A";
EXPECT_EQ("A", ParseUnpaddedString(buff));
}
TEST(ParseUnpaddedString, FillArray) {
char buff[2] = {'A', 'A'};
EXPECT_EQ("AA", ParseUnpaddedString(buff));
}
TEST(ParseUnpaddedString, InvalidDataAfterNul) {
char buff[10] = "A\0BCDEF";
EXPECT_EQ("A", ParseUnpaddedString(buff));
}
TEST(ParseUnpaddedString, Uint8Bytes) {
uint8_t buff[2] = "A";
EXPECT_EQ("A", ParseUnpaddedString(buff));
}
TEST(ParseUnpaddedString, Uint8BytesFullWidth) {
uint8_t buff[3] = {'A', 'B', 'C'};
EXPECT_EQ("ABC", ParseUnpaddedString(buff));
}
} // namespace
} // namespace audio::intel_hda