blob: 4813bc460b6be38683249fab3cef5c9440f6107d [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP 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.
*/
/**
* @file
* This file implements a unit test suite for CHIP SafeInt functions
*
*/
#include <array>
#include <pw_unit_test/framework.h>
#include <lib/core/StringBuilderAdapters.h>
#include <lib/support/Span.h>
using namespace chip;
TEST(TestSpan, TestByteSpan)
{
uint8_t arr[] = { 1, 2, 3 };
ByteSpan s0 = ByteSpan();
EXPECT_EQ(s0.size(), 0u);
EXPECT_TRUE(s0.empty());
EXPECT_TRUE(s0.data_equal(s0));
ByteSpan s1(arr, 2);
EXPECT_EQ(s1.data(), arr);
EXPECT_EQ(s1.size(), 2u);
EXPECT_FALSE(s1.empty());
EXPECT_TRUE(s1.data_equal(s1));
EXPECT_FALSE(s1.data_equal(s0));
ByteSpan s2(arr);
EXPECT_EQ(s2.data(), arr);
EXPECT_EQ(s2.size(), 3u);
EXPECT_EQ(s2.data()[2], 3u);
EXPECT_FALSE(s2.empty());
EXPECT_TRUE(s2.data_equal(s2));
EXPECT_FALSE(s2.data_equal(s1));
EXPECT_EQ(s2.front(), 1u);
EXPECT_EQ(s2.back(), 3u);
EXPECT_EQ(s2[0], 1u);
EXPECT_EQ(s2[1], 2u);
EXPECT_EQ(s2[2], 3u);
ByteSpan s3 = s2;
EXPECT_EQ(s3.data(), arr);
EXPECT_EQ(s3.size(), 3u);
EXPECT_EQ(s3.data()[2], 3u);
EXPECT_FALSE(s3.empty());
EXPECT_TRUE(s3.data_equal(s2));
uint8_t arr2[] = { 3, 2, 1 };
ByteSpan s4(arr2);
EXPECT_FALSE(s4.data_equal(s2));
ByteSpan s5(arr2, 0);
EXPECT_NE(s5.data(), nullptr);
EXPECT_FALSE(s5.data_equal(s4));
EXPECT_TRUE(s5.data_equal(s0));
EXPECT_TRUE(s0.data_equal(s5));
ByteSpan s6(arr2);
s6.reduce_size(2);
EXPECT_EQ(s6.size(), 2u);
ByteSpan s7(arr2, 2);
EXPECT_TRUE(s6.data_equal(s7));
EXPECT_TRUE(s7.data_equal(s6));
}
TEST(TestSpan, TestMutableByteSpan)
{
uint8_t arr[] = { 1, 2, 3 };
MutableByteSpan s0 = MutableByteSpan();
EXPECT_EQ(s0.size(), 0u);
EXPECT_TRUE(s0.empty());
EXPECT_TRUE(s0.data_equal(s0));
MutableByteSpan s1(arr, 2);
EXPECT_EQ(s1.data(), arr);
EXPECT_EQ(s1.size(), 2u);
EXPECT_FALSE(s1.empty());
EXPECT_TRUE(s1.data_equal(s1));
EXPECT_FALSE(s1.data_equal(s0));
MutableByteSpan s2(arr);
EXPECT_EQ(s2.data(), arr);
EXPECT_EQ(s2.size(), 3u);
EXPECT_EQ(s2.data()[2], 3u);
EXPECT_FALSE(s2.empty());
EXPECT_TRUE(s2.data_equal(s2));
EXPECT_FALSE(s2.data_equal(s1));
MutableByteSpan s3 = s2;
EXPECT_EQ(s3.data(), arr);
EXPECT_EQ(s3.size(), 3u);
EXPECT_EQ(s3.data()[2], 3u);
EXPECT_FALSE(s3.empty());
EXPECT_TRUE(s3.data_equal(s2));
uint8_t arr2[] = { 3, 2, 1 };
MutableByteSpan s4(arr2);
EXPECT_FALSE(s4.data_equal(s2));
MutableByteSpan s5(arr2, 0);
EXPECT_NE(s5.data(), nullptr);
EXPECT_FALSE(s5.data_equal(s4));
EXPECT_TRUE(s5.data_equal(s0));
EXPECT_TRUE(s0.data_equal(s5));
MutableByteSpan s6(arr2);
s6.reduce_size(2);
EXPECT_EQ(s6.size(), 2u);
MutableByteSpan s7(arr2, 2);
EXPECT_TRUE(s6.data_equal(s7));
EXPECT_TRUE(s7.data_equal(s6));
uint8_t arr3[] = { 1, 2, 3 };
MutableByteSpan s8(arr3);
EXPECT_EQ(arr3[1], 2u);
s8.data()[1] = 3;
EXPECT_EQ(arr3[1], 3u);
// Not mutable span on purpose, to test conversion.
ByteSpan s9 = s8;
EXPECT_TRUE(s9.data_equal(s8));
EXPECT_TRUE(s8.data_equal(s9));
// Not mutable span on purpose.
ByteSpan s10(s8);
EXPECT_TRUE(s10.data_equal(s8));
EXPECT_TRUE(s8.data_equal(s10));
}
TEST(TestSpan, TestFixedByteSpan)
{
uint8_t arr[] = { 1, 2, 3 };
FixedByteSpan<3> s0 = FixedByteSpan<3>();
EXPECT_NE(s0.data(), nullptr);
EXPECT_EQ(s0.size(), 3u);
EXPECT_TRUE(s0.data_equal(s0));
EXPECT_EQ(s0[0], 0u);
EXPECT_EQ(s0[1], 0u);
EXPECT_EQ(s0[2], 0u);
FixedByteSpan<2> s1(arr);
EXPECT_EQ(s1.data(), arr);
EXPECT_EQ(s1.size(), 2u);
EXPECT_TRUE(s1.data_equal(s1));
FixedByteSpan<3> s2(arr);
EXPECT_EQ(s2.data(), arr);
EXPECT_EQ(s2.size(), 3u);
EXPECT_EQ(s2.data()[2], 3u);
EXPECT_TRUE(s2.data_equal(s2));
EXPECT_EQ(s2.front(), 1u);
EXPECT_EQ(s2.back(), 3u);
EXPECT_EQ(s2[0], 1u);
EXPECT_EQ(s2[1], 2u);
EXPECT_EQ(s2[2], 3u);
FixedByteSpan<3> s3 = s2;
EXPECT_EQ(s3.data(), arr);
EXPECT_EQ(s3.size(), 3u);
EXPECT_EQ(s3.data()[2], 3u);
EXPECT_TRUE(s3.data_equal(s2));
uint8_t arr2[] = { 3, 2, 1 };
FixedSpan<uint8_t, 3> s4(arr2);
EXPECT_FALSE(s4.data_equal(s2));
size_t idx = 0;
for (auto & entry : s4)
{
EXPECT_EQ(entry, arr2[idx++]);
}
EXPECT_EQ(idx, 3u);
FixedByteSpan<3> s5(arr2);
EXPECT_TRUE(s5.data_equal(s4));
EXPECT_TRUE(s4.data_equal(s5));
FixedByteSpan<2> s6(s4);
idx = 0;
for (auto & entry : s6)
{
EXPECT_EQ(entry, arr2[idx++]);
}
EXPECT_EQ(idx, 2u);
// Not fixed, to test conversion.
ByteSpan s7(s4);
EXPECT_TRUE(s7.data_equal(s4));
EXPECT_TRUE(s4.data_equal(s7));
MutableByteSpan s8(s4);
EXPECT_TRUE(s8.data_equal(s4));
EXPECT_TRUE(s4.data_equal(s8));
}
TEST(TestSpan, TestSpanOfPointers)
{
uint8_t x = 5;
uint8_t * ptrs[] = { &x, &x };
Span<uint8_t *> s1(ptrs);
Span<uint8_t * const> s2(s1);
EXPECT_TRUE(s1.data_equal(s2));
EXPECT_TRUE(s2.data_equal(s1));
FixedSpan<uint8_t *, 2> s3(ptrs);
FixedSpan<uint8_t * const, 2> s4(s3);
EXPECT_TRUE(s1.data_equal(s3));
EXPECT_TRUE(s3.data_equal(s1));
EXPECT_TRUE(s2.data_equal(s3));
EXPECT_TRUE(s3.data_equal(s2));
EXPECT_TRUE(s1.data_equal(s4));
EXPECT_TRUE(s4.data_equal(s1));
EXPECT_TRUE(s2.data_equal(s4));
EXPECT_TRUE(s4.data_equal(s2));
EXPECT_TRUE(s3.data_equal(s4));
EXPECT_TRUE(s4.data_equal(s3));
Span<uint8_t *> s5(s3);
EXPECT_TRUE(s5.data_equal(s3));
EXPECT_TRUE(s3.data_equal(s5));
}
TEST(TestSpan, TestSubSpan)
{
uint8_t array[16];
ByteSpan span(array);
EXPECT_EQ(span.data(), &array[0]);
EXPECT_EQ(span.size(), 16u);
ByteSpan subspan = span.SubSpan(1, 14);
EXPECT_EQ(subspan.data(), &array[1]);
EXPECT_EQ(subspan.size(), 14u);
subspan = span.SubSpan(1, 0);
EXPECT_EQ(subspan.size(), 0u);
subspan = span.SubSpan(10);
EXPECT_EQ(subspan.data(), &array[10]);
EXPECT_EQ(subspan.size(), 6u);
subspan = span.SubSpan(16);
EXPECT_EQ(subspan.size(), 0u);
}
TEST(TestSpan, TestFromZclString)
{
// Purposefully larger size than data.
constexpr uint8_t array[16] = { 3, 0x41, 0x63, 0x45 };
static constexpr char str[] = "AcE";
ByteSpan s1 = ByteSpan::fromZclString(array);
EXPECT_TRUE(s1.data_equal(ByteSpan(&array[1], 3u)));
CharSpan s2 = CharSpan::fromZclString(array);
EXPECT_TRUE(s2.data_equal(CharSpan(str, 3)));
}
TEST(TestSpan, TestFromCharString)
{
static constexpr char str[] = "AcE";
CharSpan s1 = CharSpan::fromCharString(str);
EXPECT_TRUE(s1.data_equal(CharSpan(str, 3)));
}
TEST(TestSpan, TestLiteral)
{
constexpr CharSpan literal = "HI!"_span;
EXPECT_EQ(literal.size(), 3u);
EXPECT_TRUE(literal.data_equal(CharSpan::fromCharString("HI!")));
EXPECT_EQ(""_span.size(), 0u);
// These should be compile errors -- if they were allowed they would produce
// a CharSpan that includes the trailing '\0' byte in the value.
// constexpr CharSpan disallowed1("abcd");
// constexpr CharSpan disallowed2{ "abcd" };
}
TEST(TestSpan, TestConversionConstructors)
{
struct Foo
{
int member = 0;
};
struct Bar : public Foo
{
};
Bar objects[2];
// Check that various things here compile.
Span<Foo> span1(objects);
Span<Foo> span2(&objects[0], 1);
FixedSpan<Foo, 2> span3(objects);
FixedSpan<Foo, 1> span4(objects);
Span<Bar> testSpan1(objects);
FixedSpan<Bar, 2> testSpan2(objects);
Span<Foo> span5(testSpan1);
Span<Foo> span6(testSpan2);
FixedSpan<Foo, 2> span7(testSpan2);
std::array<Bar, 3> array;
const auto & constArray = array;
FixedSpan<Foo, 3> span9(array);
FixedSpan<const Foo, 3> span10(constArray);
Span<Foo> span11(array);
Span<const Foo> span12(constArray);
// Various places around the code base expect these conversions to be implicit
([](FixedSpan<Foo, 3> f) {})(array);
([](Span<Foo> f) {})(array);
([](FixedSpan<const Foo, 3> f) {})(constArray);
([](Span<const Foo> f) {})(constArray);
EXPECT_TRUE(span10.data_equal(span10));
EXPECT_TRUE(span10.data_equal(span9));
EXPECT_TRUE(span10.data_equal(array));
EXPECT_TRUE(span10.data_equal(constArray));
EXPECT_TRUE(span9.data_equal(span9));
EXPECT_TRUE(span9.data_equal(span10));
EXPECT_TRUE(span9.data_equal(array));
EXPECT_TRUE(span9.data_equal(constArray));
// The following should not compile
// Span<const Foo> error1 = std::array<Foo, 3>(); // Span would point into a temporary value
}