//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// span_unittests.cpp: Unit tests for the angle::Span class.
//

#include "common/span.h"
#include "common/unsafe_buffers.h"

#include <gtest/gtest.h>

#include <array>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>

namespace angle
{
namespace
{

constexpr size_t kSpanDataSize                  = 16;
constexpr unsigned int kSpanData[kSpanDataSize]                  = {0, 1, 2,  3,  4,  5,  6,  7,
                                                                    8, 9, 10, 11, 12, 13, 14, 15};
constexpr std::array<const unsigned int, kSpanDataSize> kSpanArr = {
    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};

class FakeRange
{
  public:
    size_t size() const { return kSpanDataSize; }
    const unsigned int *data() { return kSpanData; }
};

// Test that comparing spans work
TEST(SpanTest, Comparison)
{
    // Duplicate data to make sure comparison is being done on values (and not addresses).
    static constexpr unsigned int kSpanDataDup[kSpanDataSize] = {0, 1, 2,  3,  4,  5,  6,  7,
                                                                 8, 9, 10, 11, 12, 13, 14, 15};

    // Don't use ASSERT_EQ at first because the == is more hidden
    ANGLE_UNSAFE_TODO({
        ASSERT_TRUE(Span<const unsigned int>() == Span(kSpanData, 0));
        ASSERT_TRUE(Span(kSpanData + 3, 4) != Span(kSpanDataDup + 5, 4));
    })

    // Check ASSERT_EQ and ASSERT_NE work correctly
    ANGLE_UNSAFE_TODO({
        ASSERT_EQ(Span(kSpanData, kSpanDataSize), Span(kSpanDataDup, kSpanDataSize));
        ASSERT_NE(Span(kSpanData, kSpanDataSize - 1), Span(kSpanDataDup + 1, kSpanDataSize - 1));
        ASSERT_NE(Span(kSpanData, kSpanDataSize), Span(kSpanDataDup, kSpanDataSize - 1));
        ASSERT_NE(Span(kSpanData, kSpanDataSize - 1), Span(kSpanDataDup, kSpanDataSize));
        ASSERT_NE(Span(kSpanData, 0), Span(kSpanDataDup, 1));
        ASSERT_NE(Span(kSpanData, 1), Span(kSpanDataDup, 0));
    })
}

// Test indexing
TEST(SpanTest, Indexing)
{
    constexpr auto sp = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));

    for (size_t i = 0; i < kSpanDataSize; ++i)
    {
        ASSERT_EQ(sp[i], i);
    }

    unsigned int storage[kSpanDataSize] = {};
    auto writableSpan = ANGLE_UNSAFE_TODO(angle::Span<unsigned int>(storage, kSpanDataSize));

    for (size_t i = 0; i < kSpanDataSize; ++i)
    {
        writableSpan[i] = i;
    }
    for (size_t i = 0; i < kSpanDataSize; ++i)
    {
        ASSERT_EQ(writableSpan[i], i);
    }
    for (size_t i = 0; i < kSpanDataSize; ++i)
    {
        ANGLE_UNSAFE_TODO(ASSERT_EQ(storage[i], i));
    }
}

// Test for the various constructors
TEST(SpanTest, Constructors)
{
    // Default constructor
    {
        Span<const unsigned int> sp;
        static_assert(std::is_same_v<decltype(sp), Span<const unsigned int, dynamic_extent>>);
        ASSERT_TRUE(sp.size() == 0);
        ASSERT_TRUE(sp.empty());
    }

    // Constexpr construct from pointer and size
    {
        constexpr auto sp = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));
        static_assert(std::is_same_v<decltype(sp), const Span<const unsigned int, dynamic_extent>>);
        ASSERT_EQ(sp.data(), kSpanData);
        ASSERT_EQ(sp.size(), kSpanDataSize);
        ASSERT_FALSE(sp.empty());
    }

    // Constexpr construct from fixed C-style array
    {
        constexpr Span sp(kSpanData);
        static_assert(std::is_same_v<decltype(sp), const Span<const unsigned int, kSpanDataSize>>);
        ASSERT_EQ(sp.data(), kSpanData);
        ASSERT_EQ(sp.size(), kSpanDataSize);
        ASSERT_FALSE(sp.empty());
    }

    // Constexpr construct from constexpr std::array<const>
    {
        constexpr Span sp(kSpanArr);
        static_assert(std::is_same_v<decltype(sp), const Span<const unsigned int, kSpanDataSize>>);
        ASSERT_EQ(sp.data(), kSpanArr.data());
        ASSERT_EQ(sp.size(), kSpanArr.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from const std::array<non-const>.
    {
        const std::array<int, 2> kArr = {1, 2};
        Span sp(kArr);
        static_assert(std::is_same_v<decltype(sp), Span<const int, 2u>>);
        ASSERT_EQ(sp.data(), kArr.data());
        ASSERT_EQ(sp.size(), kArr.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from std::array<const>.
    {
        std::array<const int, 2> arr = {1, 2};
        Span sp(arr);
        static_assert(std::is_same_v<decltype(sp), Span<const int, 2u>>);
        ASSERT_EQ(sp.data(), arr.data());
        ASSERT_EQ(sp.size(), arr.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from std::array<non-const>.
    {
        std::array<int, 2> arr = {1, 2};
        Span sp(arr);
        static_assert(std::is_same_v<decltype(sp), Span<int, 2u>>);
        ASSERT_EQ(sp.data(), arr.data());
        ASSERT_EQ(sp.size(), arr.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from std::vector
    {
        std::vector<unsigned int> vec({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
        Span sp(vec);
        static_assert(std::is_same_v<decltype(sp), Span<unsigned int, dynamic_extent>>);
        ASSERT_EQ(sp.data(), vec.data());
        ASSERT_EQ(sp.size(), vec.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from const std::vector
    {
        const std::vector<unsigned int> vec({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
        Span sp(vec);
        static_assert(std::is_same_v<decltype(sp), Span<const unsigned int, dynamic_extent>>);
        ASSERT_EQ(sp.data(), vec.data());
        ASSERT_EQ(sp.size(), vec.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from std::string
    {
        std::string str = "hooray";
        Span sp(str);
        static_assert(std::is_same_v<decltype(sp), Span<char, dynamic_extent>>);
        ASSERT_EQ(sp.data(), str.data());
        ASSERT_EQ(sp.size(), str.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from const std::string
    {
        const std::string str = "hooray";
        Span sp(str);
        static_assert(std::is_same_v<decltype(sp), Span<const char, dynamic_extent>>);
        ASSERT_EQ(sp.data(), str.data());
        ASSERT_EQ(sp.size(), str.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construct from std::string_view
    {
        std::string_view view = "hooray";
        Span sp(view);
        static_assert(std::is_same_v<decltype(sp), Span<const char, dynamic_extent>>);
        ASSERT_EQ(sp.data(), view.data());
        ASSERT_EQ(sp.size(), view.size());
        ASSERT_FALSE(sp.empty());
    }

    // Construction from any class that provides data() and size().
    {
        FakeRange range;
        Span sp(range);
        ASSERT_EQ(sp.data(), kSpanData);
        ASSERT_EQ(sp.size(), kSpanDataSize);
    }

    // Copy constructor and copy assignment
    {
        Span sp(kSpanData);
        Span sp2(sp);
        Span<const unsigned int> sp3;

        ASSERT_EQ(sp, sp2);
        ASSERT_EQ(sp2.data(), kSpanData);
        ASSERT_EQ(sp2.size(), kSpanDataSize);
        ASSERT_FALSE(sp2.empty());

        sp3 = sp;

        ASSERT_EQ(sp3, sp);
        ASSERT_EQ(sp3.data(), kSpanData);
        ASSERT_EQ(sp3.size(), kSpanDataSize);
        ASSERT_FALSE(sp3.empty());
    }
}

// Test accessing the data directly
TEST(SpanTest, DataAccess)
{
    constexpr auto sp        = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));
    const unsigned int *data = sp.data();

    for (size_t i = 0; i < kSpanDataSize; ++i)
    {
        ANGLE_UNSAFE_TODO(ASSERT_EQ(data[i], i));
    }
}

// Test front and back
TEST(SpanTest, FrontAndBack)
{
    constexpr auto sp = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));
    ASSERT_TRUE(sp.front() == 0);
    ASSERT_EQ(sp.back(), kSpanDataSize - 1);
}

// Test begin and end
TEST(SpanTest, BeginAndEnd)
{
    constexpr auto sp = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));

    size_t currentIndex = 0;
    for (unsigned int value : sp)
    {
        ASSERT_EQ(value, currentIndex);
        ++currentIndex;
    }
}

// Test reverse begin and end
TEST(SpanTest, RbeginAndRend)
{
    constexpr auto sp = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));

    size_t currentIndex = 0;
    for (auto iter = sp.rbegin(); iter != sp.rend(); ++iter)
    {
        ASSERT_EQ(*iter, kSpanDataSize - 1 - currentIndex);
        ++currentIndex;
    }
}

// Test first and last
TEST(SpanTest, FirstAndLast)
{
    constexpr auto sp           = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));
    constexpr size_t kSplitSize = kSpanDataSize / 4;
    {
        constexpr Span first = sp.first(kSplitSize);
        constexpr Span last  = sp.last(kSplitSize);

        static_assert(
            std::is_same_v<decltype(first), const Span<const unsigned int, dynamic_extent>>);
        ANGLE_UNSAFE_TODO(ASSERT_EQ(first, Span(kSpanData, kSplitSize)));
        ASSERT_EQ(first.data(), kSpanData);
        ASSERT_EQ(first.size(), kSplitSize);

        static_assert(
            std::is_same_v<decltype(last), const Span<const unsigned int, dynamic_extent>>);
        ANGLE_UNSAFE_TODO({
            ASSERT_EQ(last, Span(kSpanData + kSpanDataSize - kSplitSize, kSplitSize));
            ASSERT_EQ(last.data(), kSpanData + kSpanDataSize - kSplitSize);
        })
        ASSERT_EQ(last.size(), kSplitSize);
    }

    {
        constexpr Span first = sp.first<kSplitSize>();
        constexpr Span last  = sp.last<kSplitSize>();

        static_assert(std::is_same_v<decltype(first), const Span<const unsigned int, kSplitSize>>);
        ANGLE_UNSAFE_TODO(ASSERT_EQ(first, Span(kSpanData, kSplitSize)));
        ASSERT_EQ(first.data(), kSpanData);
        ASSERT_EQ(first.size(), kSplitSize);

        static_assert(std::is_same_v<decltype(last), const Span<const unsigned int, kSplitSize>>);
        ANGLE_UNSAFE_TODO({
            ASSERT_EQ(last, Span(kSpanData + kSpanDataSize - kSplitSize, kSplitSize));
            ASSERT_EQ(last.data(), kSpanData + kSpanDataSize - kSplitSize);
        })
        ASSERT_EQ(last.size(), kSplitSize);
    }
}

// Test subspan
TEST(SpanTest, Subspan)
{
    constexpr auto sp             = ANGLE_UNSAFE_TODO(Span(kSpanData, kSpanDataSize));
    constexpr size_t kSplitOffset = kSpanDataSize / 4;
    constexpr size_t kSplitSize   = kSpanDataSize / 2;

    // Test one-arg subspan
    {
        constexpr Span subspan = sp.subspan(kSplitOffset);
        static_assert(
            std::is_same_v<decltype(subspan), const Span<const unsigned int, dynamic_extent>>);
        ANGLE_UNSAFE_TODO({
            ASSERT_EQ(subspan, Span(kSpanData + kSplitOffset, kSpanDataSize - kSplitOffset));
            ASSERT_EQ(subspan.data(), kSpanData + kSplitOffset);
        })
        ASSERT_EQ(subspan.size(), kSpanDataSize - kSplitOffset);
    }

    // Test two-arg subspan
    {
        constexpr Span subspan = sp.subspan(kSplitOffset, kSplitSize);
        static_assert(
            std::is_same_v<decltype(subspan), const Span<const unsigned int, dynamic_extent>>);
        ANGLE_UNSAFE_TODO({
            ASSERT_EQ(subspan, Span(kSpanData + kSplitOffset, kSplitSize));
            ASSERT_EQ(subspan.data(), kSpanData + kSplitOffset);
        })
        ASSERT_EQ(subspan.size(), kSplitSize);
    }

    // Templated one-arg subspan just sugar until C++20 fixed spans.
    {
        constexpr Span subspan = sp.subspan<kSplitOffset>();
        static_assert(
            std::is_same_v<decltype(subspan), const Span<const unsigned int, dynamic_extent>>);
        ANGLE_UNSAFE_TODO({
            ASSERT_EQ(subspan, Span(kSpanData + kSplitOffset, kSpanDataSize - kSplitOffset));
            ASSERT_EQ(subspan.data(), kSpanData + kSplitOffset);
        })
        ASSERT_EQ(subspan.size(), kSpanDataSize - kSplitOffset);
    }

    // Templated two-arg subspan just sugar until C++20 fixed spans.
    {
        constexpr Span subspan = sp.subspan<kSplitOffset, kSplitSize>();
        static_assert(
            std::is_same_v<decltype(subspan), const Span<const unsigned int, dynamic_extent>>);
        ANGLE_UNSAFE_TODO({
            ASSERT_EQ(subspan, Span(kSpanData + kSplitOffset, kSplitSize));
            ASSERT_EQ(subspan.data(), kSpanData + kSplitOffset);
        })
        ASSERT_EQ(subspan.size(), kSplitSize);
    }
}

// Test conversions from non-const to const spans.
TEST(SpanTest, ConstConversions)
{
    const unsigned int kStorage[kSpanDataSize] = {0, 1, 2,  3,  4,  5,  6,  7,
                                                  8, 9, 10, 11, 12, 13, 14, 15};
    unsigned int storage[kSpanDataSize] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
    auto readable_span = ANGLE_UNSAFE_TODO(angle::Span(kStorage, kSpanDataSize));
    auto writable_span = ANGLE_UNSAFE_TODO(angle::Span(storage, kSpanDataSize));

    static_assert(
        std::is_same_v<decltype(readable_span), Span<const unsigned int, dynamic_extent>>);

    static_assert(std::is_same_v<decltype(writable_span), Span<unsigned int, dynamic_extent>>);

    // Direct comparisons allowed.
    EXPECT_TRUE(readable_span == writable_span);
    EXPECT_FALSE(readable_span != writable_span);

    writable_span[0] = 1234;
    EXPECT_FALSE(readable_span == writable_span);

    // Assignment allowed from non-const to const.
    readable_span = writable_span;
    EXPECT_TRUE(readable_span == writable_span);
}

// Test conversions from fixed to dynamic spans.
TEST(SpanTest, FixedConversions)
{
    unsigned int storage[kSpanDataSize] = {};
    std::vector<unsigned int> vec(kSpanDataSize, 42);
    Span<unsigned int> dynamic_span(vec);
    Span<unsigned int, kSpanDataSize> static_span(storage);

    // Direct comparisons allowed.
    EXPECT_NE(static_span, dynamic_span);

    // Assignment allowed from fixed to dynamic.
    dynamic_span = static_span;
    EXPECT_EQ(static_span, dynamic_span);

    // Other way around prohibited without fixed conversion.
    dynamic_span[0] = 1234;
    static_span     = dynamic_span.first<kSpanDataSize>();
    EXPECT_EQ(static_span, dynamic_span);
}

// Test non-member functions.
TEST(SpanTest, Helpers)
{
    // Test as_bytes.
    {
        constexpr int kArray[] = {2, 3, 5, 7, 11, 13};
        auto bytes_span        = as_bytes(Span(kArray));
        EXPECT_EQ(reinterpret_cast<const uint8_t *>(kArray), bytes_span.data());
        EXPECT_EQ(sizeof(kArray), bytes_span.size());
        EXPECT_EQ(bytes_span.size(), bytes_span.size_bytes());
    }

    // Test as_writble_bytes.
    {
        std::vector<int> vec = {1, 1, 2, 3, 5, 8};
        Span<int> mutable_span(vec);
        auto writable_bytes_span = as_writable_bytes(mutable_span);
        static_assert(std::is_same_v<decltype(writable_bytes_span), Span<uint8_t>>);
        EXPECT_EQ(reinterpret_cast<uint8_t *>(vec.data()), writable_bytes_span.data());
        EXPECT_EQ(sizeof(int) * vec.size(), writable_bytes_span.size());
        EXPECT_EQ(writable_bytes_span.size(), writable_bytes_span.size_bytes());
    }

    // Test as_chars.
    {
        constexpr int kArray[] = {2, 3, 5, 7, 11, 13};
        auto chars_span        = as_chars(Span(kArray));
        EXPECT_EQ(reinterpret_cast<const char *>(kArray), chars_span.data());
        EXPECT_EQ(sizeof(kArray), chars_span.size());
        EXPECT_EQ(chars_span.size(), chars_span.size_bytes());
    }

    // Test as writable chars.
    {
        std::vector<int> vec = {1, 1, 2, 3, 5, 8};
        Span<int> mutable_span(vec);
        auto writable_chars_span = as_writable_chars(mutable_span);
        static_assert(std::is_same_v<decltype(writable_chars_span), Span<char>>);
        EXPECT_EQ(reinterpret_cast<char *>(vec.data()), writable_chars_span.data());
        EXPECT_EQ(sizeof(int) * vec.size(), writable_chars_span.size());
        EXPECT_EQ(writable_chars_span.size(), writable_chars_span.size_bytes());
    }

    // Test span_from_ref.
    {
        int x  = 123;
        auto s = span_from_ref(x);
        EXPECT_EQ(&x, s.data());
        EXPECT_EQ(1u, s.size());
        EXPECT_EQ(sizeof(int), s.size_bytes());
        EXPECT_EQ(123, s[0]);
    }

    // Test byte_span_from_ref.
    {
        int x  = 123;
        auto b = byte_span_from_ref(x);
        EXPECT_EQ(reinterpret_cast<uint8_t *>(&x), b.data());
        EXPECT_EQ(sizeof(int), b.size());
    }

    //  Test as_byte_span.
    {
        const std::vector<int> kVec({2, 3, 5, 7, 11, 13});
        auto byte_span = as_byte_span(kVec);
        static_assert(std::is_same_v<decltype(byte_span), Span<const uint8_t>>);
        EXPECT_EQ(byte_span.data(), reinterpret_cast<const uint8_t *>(kVec.data()));
        EXPECT_EQ(byte_span.size(), kVec.size() * sizeof(int));
    }

    // Test as_writable_byte_span
    {
        int kMutArray[] = {2, 3, 5, 7};
        auto byte_span  = as_writable_byte_span(kMutArray);
        EXPECT_EQ(byte_span.data(), reinterpret_cast<uint8_t *>(kMutArray));
        EXPECT_EQ(byte_span.size(), sizeof(kMutArray));
    }

    // Test copy_from.
    {
        unsigned int data1[4] = {1, 2, 3, 4};
        unsigned int data2[4] = {0, 0, 0, 0};

        Span<unsigned int> sp1(data1);
        Span<unsigned int> sp2(data2);

        sp2.copy_from(sp1);
        for (size_t i = 0; i < 4; ++i)
        {
            ANGLE_UNSAFE_TODO(EXPECT_EQ(data2[i], data1[i]));
        }
    }

    // Test copy_from with container.
    {
        std::vector<unsigned int> vec = {10, 20, 30, 40};
        unsigned int data[4]          = {0, 0, 0, 0};
        Span<unsigned int, 4> sp(data);

        sp.copy_from(vec);
        EXPECT_EQ(data[0], 10u);
        EXPECT_EQ(data[1], 20u);
        EXPECT_EQ(data[2], 30u);
        EXPECT_EQ(data[3], 40u);
    }

    // Test copy_from with overlapping memory (forward move).
    {
        unsigned int data[4] = {1, 2, 3, 4};
        Span<unsigned int> sp(data);

        // Copy [1, 2, 3] to [2, 3, 4] -> Result should be [1, 1, 2, 3]
        // This exercises the std::copy_backward path in the overlap logic.
        sp.subspan(1).copy_from(sp.first(3));
        EXPECT_EQ(data[0], 1u);
        EXPECT_EQ(data[1], 1u);
        EXPECT_EQ(data[2], 2u);
        EXPECT_EQ(data[3], 3u);
    }

    // Test copy_from with overlapping memory (backward move).
    {
        unsigned int data[4] = {1, 2, 3, 4};
        Span<unsigned int> sp(data);

        // Copy [2, 3, 4] to [1, 2, 3] -> Result should be [2, 3, 4, 4]
        // This exercises the std::copy path in the overlap logic.
        sp.first(3).copy_from(sp.subspan(1));
        EXPECT_EQ(data[0], 2u);
        EXPECT_EQ(data[1], 3u);
        EXPECT_EQ(data[2], 4u);
        EXPECT_EQ(data[3], 4u);
    }

    // Verify Extent Safety (Compile-time)
    {
        using FixedSpan   = Span<int, 4>;
        using DynamicSpan = Span<int, dynamic_extent>;

        // Identical fixed extents are allowed.
        static_assert(std::is_invocable_v<decltype(&FixedSpan::copy_from<int, 4, int *>), FixedSpan,
                                          const FixedSpan &>);
        // Const sources are allowed.
        static_assert(
            std::is_invocable_v<decltype(&FixedSpan::copy_from<const int, 4, const int *>),
                                FixedSpan, const Span<const int, 4> &>);
        // Fixed from Dynamic is allowed (runtime CHECK handles mismatch).
        static_assert(
            std::is_invocable_v<decltype(&FixedSpan::copy_from<int, dynamic_extent, int *>),
                                FixedSpan, const DynamicSpan &>);
        // Dynamic from Fixed is allowed.
        static_assert(std::is_invocable_v<decltype(&DynamicSpan::copy_from<int, 4, int *>),
                                          DynamicSpan, const FixedSpan &>);
        // Containers are allowed.
        static_assert(std::is_invocable_v<decltype(&FixedSpan::copy_from<std::vector<int>>),
                                          FixedSpan, const std::vector<int> &>);
    }

    // Test to_fixed_extent.
    {
        unsigned int data[4] = {1, 2, 3, 4};
        Span<unsigned int> sp(data);

        auto fixed_sp = sp.to_fixed_extent<4>();
        ASSERT_TRUE(fixed_sp.has_value());
        EXPECT_EQ(fixed_sp->size(), 4u);
        EXPECT_EQ((*fixed_sp)[0], 1u);

        auto fixed_sp_wrong = sp.to_fixed_extent<5>();
        ASSERT_FALSE(fixed_sp_wrong.has_value());
    }

    // Test split_at.
    {
        unsigned int data[4] = {1, 2, 3, 4};
        Span<unsigned int> sp(data);

        {
            auto [front, back] = sp.split_at<2>();
            static_assert(std::is_same_v<decltype(front), Span<unsigned int, 2>>);
            EXPECT_EQ(front.size(), 2u);
            EXPECT_EQ(back.size(), 2u);
            EXPECT_EQ(front[0], 1u);
            EXPECT_EQ(back[0], 3u);
        }

        {
            auto [front, back] = sp.split_at(1);
            EXPECT_EQ(front.size(), 1u);
            EXPECT_EQ(back.size(), 3u);
            EXPECT_EQ(front[0], 1u);
            EXPECT_EQ(back[0], 2u);
        }
    }

    // Test copy_from on a const Span handle.
    {
        unsigned int data1[4] = {1, 2, 3, 4};
        unsigned int data2[4] = {0, 0, 0, 0};

        const Span<unsigned int> sp1(data1);
        const Span<unsigned int> sp2(data2);

        sp2.copy_from(sp1);

        for (size_t i = 0; i < 4; ++i)
        {
            ANGLE_UNSAFE_TODO(EXPECT_EQ(data2[i], data1[i]));
        }
    }
}

}  // anonymous namespace
}  // namespace angle
