/*
 *
 *    Copyright (c) 2021 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.
 */

#include <string.h>
#include <vector>

#include "app-common/zap-generated/ids/Attributes.h"
#include "app-common/zap-generated/ids/Clusters.h"
#include "lib/core/TLVTags.h"
#include "lib/core/TLVWriter.h"
#include "protocols/interaction_model/Constants.h"
#include "system/SystemPacketBuffer.h"
#include "system/TLVPacketBufferBackingStore.h"
#include <app-common/zap-generated/cluster-objects.h>
#include <app/ClusterStateCache.h>
#include <app/MessageDef/DataVersionFilterIBs.h>
#include <app/data-model/DecodableList.h>
#include <app/data-model/Decode.h>
#include <app/tests/AppTestContext.h>
#include <lib/support/ScopedBuffer.h>

#include <lib/core/StringBuilderAdapters.h>
#include <pw_unit_test/framework.h>

using namespace chip::app;
using namespace chip;

namespace {

struct AttributeInstruction
{
    enum AttributeType
    {
        kAttributeA = 0, // int
        kAttributeB = 1, // byte string
        kAttributeC = 2, // struct
        kAttributeD = 3, // list
    };

    enum ValueType
    {
        kData   = 0,
        kStatus = 1
    };

    AttributeType mAttributeType;
    EndpointId mEndpointId;
    ValueType mValueType;
    uint8_t mInstructionId;

    AttributeInstruction() { mInstructionId = sInstructionId++; }

    bool operator<(const AttributeInstruction & instruction) const
    {
        return (mAttributeType < instruction.mAttributeType ||
                (!(mAttributeType < instruction.mAttributeType) && (mEndpointId < instruction.mEndpointId)));
    }

    AttributeInstruction(AttributeType attributeType, EndpointId endpointId, ValueType valueType) : AttributeInstruction()
    {
        mAttributeType = attributeType;
        mEndpointId    = endpointId;
        mValueType     = valueType;
    }

    AttributeId GetAttributeId() const
    {
        switch (mAttributeType)
        {
        case kAttributeA:
            return Clusters::UnitTesting::Attributes::Int16u::Id;
            break;

        case kAttributeB:
            return Clusters::UnitTesting::Attributes::OctetString::Id;
            break;

        case kAttributeC:
            return Clusters::UnitTesting::Attributes::StructAttr::Id;
            break;

        default:
            return Clusters::UnitTesting::Attributes::ListStructOctetString::Id;
            break;
        }
    }

    ConcreteAttributePath GetAttributePath() const
    {
        return ConcreteAttributePath(mEndpointId, Clusters::UnitTesting::Id, GetAttributeId());
    }

    static uint8_t sInstructionId;
};

uint8_t AttributeInstruction::sInstructionId = 0;

using AttributeInstructionListType = std::vector<AttributeInstruction>;

using TestClusterStateCache = chip::Test::AppContext;

class ForwardedDataCallbackValidator final
{
public:
    void SetExpectation(TLV::TLVReader & aData, EndpointId endpointId, AttributeInstruction::AttributeType attributeType)
    {
        auto length = aData.GetRemainingLength();
        std::vector<uint8_t> buffer(aData.GetReadPoint(), aData.GetReadPoint() + length);
        if (!mExpectedBuffers.empty() && endpointId == mLastEndpointId && attributeType == mLastAttributeType)
        {
            // For overriding test, the last buffered data is removed.
            mExpectedBuffers.pop_back();
        }
        mExpectedBuffers.push_back(buffer);
        mLastEndpointId    = endpointId;
        mLastAttributeType = attributeType;
    }

    void SetExpectation() { mExpectedBuffers.clear(); }

    void ValidateData(TLV::TLVReader & aData, bool isListOperation)
    {
        EXPECT_FALSE(mExpectedBuffers.empty());
        if (!mExpectedBuffers.empty() > 0)
        {
            auto buffer = mExpectedBuffers.front();
            mExpectedBuffers.erase(mExpectedBuffers.begin());
            uint32_t length = static_cast<uint32_t>(buffer.size());
            if (isListOperation)
            {
                // List operation will attach end of container
                EXPECT_LT(length, aData.GetRemainingLength());
            }
            else
            {
                EXPECT_EQ(length, aData.GetRemainingLength());
            }
            if (length <= aData.GetRemainingLength() && length > 0)
            {
                EXPECT_EQ(memcmp(aData.GetReadPoint(), buffer.data(), length), 0);
                if (memcmp(aData.GetReadPoint(), buffer.data(), length) != 0)
                {
                    ChipLogProgress(DataManagement, "Failed");
                }
            }
        }
    }

    void ValidateNoData() { EXPECT_TRUE(mExpectedBuffers.empty()); }

private:
    std::vector<std::vector<uint8_t>> mExpectedBuffers;
    EndpointId mLastEndpointId;
    AttributeInstruction::AttributeType mLastAttributeType;
};

class DataSeriesGenerator
{
public:
    DataSeriesGenerator(ReadClient::Callback * readCallback, AttributeInstructionListType & instructionList) :
        mReadCallback(readCallback), mInstructionList(instructionList)
    {}

    void Generate(ForwardedDataCallbackValidator & dataCallbackValidator);

private:
    ReadClient::Callback * mReadCallback;
    AttributeInstructionListType & mInstructionList;
};

void DataSeriesGenerator::Generate(ForwardedDataCallbackValidator & dataCallbackValidator)
{
    ReadClient::Callback * callback = mReadCallback;
    StatusIB status;
    callback->OnReportBegin();

    for (auto & instruction : mInstructionList)
    {
        ConcreteDataAttributePath path(instruction.mEndpointId, Clusters::UnitTesting::Id, 0);
        Platform::ScopedMemoryBufferWithSize<uint8_t> handle;
        handle.Calloc(3000);
        TLV::ScopedBufferTLVWriter writer(std::move(handle), 3000);

        status            = StatusIB();
        path.mAttributeId = instruction.GetAttributeId();
        path.mDataVersion.SetValue(1);

        ChipLogProgress(DataManagement, "\t -- Generating Instruction ID %d", instruction.mInstructionId);

        if (instruction.mValueType == AttributeInstruction::kData)
        {
            switch (instruction.mAttributeType)
            {
            case AttributeInstruction::kAttributeA: {
                ChipLogProgress(DataManagement, "\t -- Generating A");

                Clusters::UnitTesting::Attributes::Int16u::TypeInfo::Type value = instruction.mInstructionId;
                EXPECT_EQ(DataModel::Encode(writer, TLV::AnonymousTag(), value), CHIP_NO_ERROR);
                break;
            }

            case AttributeInstruction::kAttributeB: {
                ChipLogProgress(DataManagement, "\t -- Generating B");

                Clusters::UnitTesting::Attributes::OctetString::TypeInfo::Type value;
                uint8_t buf[] = { 'h', 'e', 'l', 'l', 'o' };
                value         = buf;

                EXPECT_EQ(DataModel::Encode(writer, TLV::AnonymousTag(), value), CHIP_NO_ERROR);
                break;
            }

            case AttributeInstruction::kAttributeC: {
                ChipLogProgress(DataManagement, "\t -- Generating C");

                Clusters::UnitTesting::Attributes::StructAttr::TypeInfo::Type value;
                value.a = instruction.mInstructionId;
                value.b = true;
                EXPECT_EQ(DataModel::Encode(writer, TLV::AnonymousTag(), value), CHIP_NO_ERROR);
                break;
            }

            case AttributeInstruction::kAttributeD: {
                ChipLogProgress(DataManagement, "\t -- Generating D");

                // buf[200] is 1.6k
                Clusters::UnitTesting::Structs::TestListStructOctet::Type buf[200];

                for (auto & i : buf)
                {
                    i.member1 = instruction.mInstructionId;
                }

                Clusters::UnitTesting::Attributes::ListStructOctetString::TypeInfo::Type value;
                path.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll;

                value = buf;
                EXPECT_EQ(DataModel::Encode(writer, TLV::AnonymousTag(), value), CHIP_NO_ERROR);
                break;
            }

            default:
                break;
            }

            uint32_t writtenLength = writer.GetLengthWritten();
            writer.Finalize(handle);
            TLV::ScopedBufferTLVReader reader;
            reader.Init(std::move(handle), writtenLength);
            EXPECT_EQ(reader.Next(), CHIP_NO_ERROR);
            dataCallbackValidator.SetExpectation(reader, instruction.mEndpointId, instruction.mAttributeType);
            callback->OnAttributeData(path, &reader, status);
        }
        else
        {
            ChipLogProgress(DataManagement, "\t -- Generating Status");
            status.mStatus = Protocols::InteractionModel::Status::Failure;
            dataCallbackValidator.SetExpectation();
            callback->OnAttributeData(path, nullptr, status);
        }
    }

    callback->OnReportEnd();
}

class CacheValidator : public ClusterStateCache::Callback
{
public:
    CacheValidator(AttributeInstructionListType & instructionList, ForwardedDataCallbackValidator & dataCallbackValidator);

    Clusters::UnitTesting::Attributes::TypeInfo::DecodableType clusterValue;

private:
    void OnDone(ReadClient *) override {}
    void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) override
    {
        ChipLogProgress(DataManagement, "\t\t -- Validating OnAttributeData callback");
        // Ensure that the provided path is one that we're expecting to find
        auto iter = mExpectedAttributes.find(aPath);
        ASSERT_NE(iter, mExpectedAttributes.end());

        if (aStatus.IsSuccess())
        {
            // Verify that the apData is passed as nonnull
            ASSERT_NE(apData, nullptr);
            if (apData)
            {
                mDataCallbackValidator.ValidateData(*apData, aPath.IsListOperation());
            }
        }
        else
        {
            mDataCallbackValidator.ValidateNoData();
        }
    }

    void DecodeAttribute(const AttributeInstruction & instruction, const ConcreteAttributePath & path, ClusterStateCache * cache)
    {
        CHIP_ERROR err;
        bool gotStatus = false;

        ChipLogProgress(DataManagement, "\t\t -- Validating Instruction ID: %d", instruction.mInstructionId);

        switch (instruction.mAttributeType)
        {
        case AttributeInstruction::kAttributeA: {
            ChipLogProgress(DataManagement, "\t\t -- Validating A");

            Clusters::UnitTesting::Attributes::Int16u::TypeInfo::DecodableType v = 0;
            err = cache->Get<Clusters::UnitTesting::Attributes::Int16u::TypeInfo>(path, v);
            if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
            {
                gotStatus = true;
                err       = CHIP_NO_ERROR;
            }
            else
            {
                EXPECT_EQ(err, CHIP_NO_ERROR);
                EXPECT_EQ(v, instruction.mInstructionId);
            }

            break;
        }

        case AttributeInstruction::kAttributeB: {
            ChipLogProgress(DataManagement, "\t\t -- Validating B");

            Clusters::UnitTesting::Attributes::OctetString::TypeInfo::DecodableType v;
            err = cache->Get<Clusters::UnitTesting::Attributes::OctetString::TypeInfo>(path, v);
            if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
            {
                gotStatus = true;
                err       = CHIP_NO_ERROR;
            }
            else
            {
                EXPECT_EQ(err, CHIP_NO_ERROR);
                EXPECT_EQ(strncmp((char *) v.data(), "hello", v.size()), 0);
            }

            break;
        }

        case AttributeInstruction::kAttributeC: {
            ChipLogProgress(DataManagement, "\t\t -- Validating C");

            Clusters::UnitTesting::Attributes::StructAttr::TypeInfo::DecodableType v;
            err = cache->Get<Clusters::UnitTesting::Attributes::StructAttr::TypeInfo>(path, v);
            if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
            {
                gotStatus = true;
                err       = CHIP_NO_ERROR;
            }
            else
            {
                EXPECT_EQ(v.a, instruction.mInstructionId);
                EXPECT_TRUE(v.b);
            }

            break;
        }

        case AttributeInstruction::kAttributeD: {
            ChipLogProgress(DataManagement, "\t\t -- Validating D");

            Clusters::UnitTesting::Attributes::ListStructOctetString::TypeInfo::DecodableType v;
            err = cache->Get<Clusters::UnitTesting::Attributes::ListStructOctetString::TypeInfo>(path, v);
            if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
            {
                gotStatus = true;
                err       = CHIP_NO_ERROR;
            }
            else
            {
                auto listIter = v.begin();
                while (listIter.Next())
                {
                    EXPECT_EQ(listIter.GetValue().member1, instruction.mInstructionId);
                }

                EXPECT_EQ(listIter.GetStatus(), CHIP_NO_ERROR);
            }

            break;
        }
        }

        EXPECT_EQ(err, CHIP_NO_ERROR);

        if (gotStatus)
        {
            ChipLogProgress(DataManagement, "\t\t -- Validating status");
            EXPECT_EQ(instruction.mValueType, AttributeInstruction::kStatus);
        }
    }

    void DecodeClusterObject(const AttributeInstruction & instruction, const ConcreteAttributePath & path,
                             ClusterStateCache * cache)
    {
        std::list<ClusterStateCache::AttributeStatus> statusList;
        EXPECT_EQ(cache->Get(path.mEndpointId, path.mClusterId, clusterValue, statusList), CHIP_NO_ERROR);

        if (instruction.mValueType == AttributeInstruction::kData)
        {
            EXPECT_EQ(statusList.size(), 0u);

            switch (instruction.mAttributeType)
            {
            case AttributeInstruction::kAttributeA:
                ChipLogProgress(DataManagement, "\t\t -- Validating A (Cluster Obj)");
                EXPECT_EQ(clusterValue.int16u, instruction.mInstructionId);
                break;

            case AttributeInstruction::kAttributeB:
                ChipLogProgress(DataManagement, "\t\t -- Validating B (Cluster Obj)");
                EXPECT_EQ(strncmp((char *) clusterValue.octetString.data(), "hello", clusterValue.octetString.size()), 0);
                break;

            case AttributeInstruction::kAttributeC:
                ChipLogProgress(DataManagement, "\t\t -- Validating C (Cluster Obj)");
                EXPECT_EQ(clusterValue.structAttr.a, instruction.mInstructionId);
                EXPECT_TRUE(clusterValue.structAttr.b);
                break;

            case AttributeInstruction::kAttributeD:
                ChipLogProgress(DataManagement, "\t\t -- Validating D (Cluster Obj)");

                auto listIter = clusterValue.listStructOctetString.begin();
                while (listIter.Next())
                {
                    EXPECT_EQ(listIter.GetValue().member1, instruction.mInstructionId);
                }

                EXPECT_EQ(listIter.GetStatus(), CHIP_NO_ERROR);
                break;
            }
        }
        else
        {
            EXPECT_EQ(statusList.size(), 1u);

            auto status = statusList.front();
            EXPECT_EQ(status.mPath.mEndpointId, instruction.mEndpointId);
            EXPECT_EQ(status.mPath.mClusterId, Clusters::UnitTesting::Id);
            EXPECT_EQ(status.mPath.mAttributeId, instruction.GetAttributeId());
            EXPECT_EQ(status.mStatus.mStatus, Protocols::InteractionModel::Status::Failure);
        }
    }

    void OnAttributeChanged(ClusterStateCache * cache, const ConcreteAttributePath & path) override
    {
        // Ensure that the provided path is one that we're expecting to find
        auto iter = mExpectedAttributes.find(path);
        ASSERT_NE(iter, mExpectedAttributes.end());

        // Once retrieved, let's erase it from the expected set so that we can catch duplicates coming back
        // as well as validating that we've seen all attributes at the end.
        mExpectedAttributes.erase(iter);

        for (auto & instruction : mInstructionSet)
        {
            if (instruction.mEndpointId == path.mEndpointId && instruction.GetAttributeId() == path.mAttributeId &&
                path.mClusterId == Clusters::UnitTesting::Id)
            {

                //
                // Validate both decoding into attribute objects as well as
                // cluster objects.
                //
                DecodeAttribute(instruction, path, cache);
                DecodeClusterObject(instruction, path, cache);
            }
        }
    }

    void OnClusterChanged(ClusterStateCache * cache, EndpointId endpointId, ClusterId clusterId) override
    {
        auto iter = mExpectedClusters.find(std::make_tuple(endpointId, clusterId));
        ASSERT_NE(iter, mExpectedClusters.end());
        mExpectedClusters.erase(iter);
    }

    void OnEndpointAdded(ClusterStateCache * cache, EndpointId endpointId) override
    {
        auto iter = mExpectedEndpoints.find(endpointId);
        ASSERT_NE(iter, mExpectedEndpoints.end());
        mExpectedEndpoints.erase(iter);
    }

    void OnReportEnd() override
    {
        EXPECT_EQ(mExpectedAttributes.size(), 0u);
        EXPECT_EQ(mExpectedClusters.size(), 0u);
        EXPECT_EQ(mExpectedEndpoints.size(), 0u);
    }

    //
    // We use sets for tracking most of the expected data since we're expecting
    // unique data items being provided in the callbacks.
    //
    std::set<AttributeInstruction> mInstructionSet;
    std::set<ConcreteAttributePath> mExpectedAttributes;
    std::set<std::tuple<EndpointId, ClusterId>> mExpectedClusters;
    std::set<EndpointId> mExpectedEndpoints;

    ForwardedDataCallbackValidator & mDataCallbackValidator;
};

CacheValidator::CacheValidator(AttributeInstructionListType & instructionList,
                               ForwardedDataCallbackValidator & dataCallbackValidator) :
    mDataCallbackValidator(dataCallbackValidator)
{
    for (auto & instruction : instructionList)
    {
        //
        // We need to replace a matching instruction with the latest one we see in the list to ensure we get
        // the instruction with the highest InstructionID. Hence the erase and insert (i.e replace) operation.
        //
        mInstructionSet.erase(instruction);
        mInstructionSet.insert(instruction);
        mExpectedAttributes.insert(
            ConcreteAttributePath(instruction.mEndpointId, Clusters::UnitTesting::Id, instruction.GetAttributeId()));
        mExpectedClusters.insert(std::make_tuple(instruction.mEndpointId, Clusters::UnitTesting::Id));
        mExpectedEndpoints.insert(instruction.mEndpointId);
    }
}

void RunAndValidateSequence(AttributeInstructionListType list)
{
    ForwardedDataCallbackValidator dataCallbackValidator;
    CacheValidator client(list, dataCallbackValidator);
    ClusterStateCache cache(client);

    // In order for the cache to track our data versions, we need to claim to it
    // that we are dealing with a wildcard path.  And we need to do that before
    // it has seen any reports.
    AttributePathParams wildcardPath;
    const Span<AttributePathParams> pathSpan(&wildcardPath, 1);
    {
        // Just need a buffer big enough that we can start the list.  We don't
        // care about the actual data versions here.
        uint8_t buf[20];
        TLV::TLVWriter writer;
        writer.Init(buf);
        DataVersionFilterIBs::Builder builder;
        EXPECT_EQ(builder.Init(&writer), CHIP_NO_ERROR);
        bool encodedDataVersionList = false;

        // We had nothing to encode so far.
        EXPECT_EQ(cache.GetBufferedCallback().OnUpdateDataVersionFilterList(builder, pathSpan, encodedDataVersionList),
                  CHIP_NO_ERROR);
        EXPECT_FALSE(encodedDataVersionList);
    }

    DataSeriesGenerator generator(&cache.GetBufferedCallback(), list);
    generator.Generate(dataCallbackValidator);

    // Check that iteration of the ClusterStateCache does the right thing.
    //
    // The basic idea is that we make a copy of our instruction list, iterate
    // the cache in some way and remove instructions matching the observed paths
    // from the copy.  Then we test whether all the things we expected to be
    // removed got removed.
    auto newInstructionRemovalFunction = [](AttributeInstructionListType & listToRemoveFrom) {
        return [&listToRemoveFrom](const ConcreteAttributePath & path) {
            size_t sizeBeforeErase = listToRemoveFrom.size();
            // Remove all instructions matching the path; there might have been
            // multiple such instructions, but the path can be present in the
            // cache only once.
            listToRemoveFrom.erase(std::remove_if(listToRemoveFrom.begin(), listToRemoveFrom.end(),
                                                  [&path](const AttributeInstruction & instruction) {
                                                      return instruction.GetAttributePath() == path;
                                                  }),
                                   listToRemoveFrom.end());

            // We should have had an instruction for this path.
            EXPECT_NE(listToRemoveFrom.size(), sizeBeforeErase);

            return CHIP_NO_ERROR;
        };
    };

    if (!list.empty())
    {
        AttributeInstructionListType listCopy(list);
        ConcreteClusterPath clusterPath = listCopy[0].GetAttributePath();
        cache.ForEachAttribute(clusterPath.mEndpointId, clusterPath.mClusterId, newInstructionRemovalFunction(listCopy));

        // Should have removed all instructions matching this cluster instance.
        for (auto & instruction : listCopy)
        {
            EXPECT_FALSE(clusterPath == instruction.GetAttributePath());
        }
    }

    if (!list.empty())
    {
        AttributeInstructionListType listCopy(list);
        ClusterId cluster = listCopy[0].GetAttributePath().mClusterId;
        cache.ForEachAttribute(cluster, newInstructionRemovalFunction(listCopy));

        // Should have removed all instructions matching this cluster id.
        for (auto & instruction : listCopy)
        {
            EXPECT_NE(instruction.GetAttributePath().mClusterId, cluster);
        }
    }

    {
        AttributeInstructionListType listCopy(list);
        cache.ForEachAttribute(newInstructionRemovalFunction(listCopy));

        // We should have had things in the cache for all our instructions.
        EXPECT_EQ(listCopy.size(), 0u);
    }

    // Now verify that we would do the right thing when encoding our data
    // versions.

    size_t bufferSize = 1;
    do
    {
        Platform::ScopedMemoryBuffer<uint8_t> buf;
        ASSERT_TRUE(buf.Calloc(bufferSize));

        TLV::TLVWriter writer;
        writer.Init(buf.Get(), bufferSize);

        DataVersionFilterIBs::Builder builder;
        CHIP_ERROR err = builder.Init(&writer);
        EXPECT_TRUE(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL);
        if (err == CHIP_NO_ERROR)
        {
            // We had enough space to start the list.  Now try encoding the data
            // version filters.
            bool encodedDataVersionList = false;

            // We should be rolling back properly if we run out of space.
            EXPECT_EQ(cache.GetBufferedCallback().OnUpdateDataVersionFilterList(builder, pathSpan, encodedDataVersionList),
                      CHIP_NO_ERROR);
            EXPECT_EQ(builder.GetError(), CHIP_NO_ERROR);

            if (writer.GetRemainingFreeLength() > 40)
            {
                // We have lots of empty space left, so we did not end up
                // needing to roll back; no point testing larger buffer sizes.
                //
                // Note: we may still have encodedDataVersionList false here, if
                // there were no non-status attribute values cached.
                break;
            }
        }

        ++bufferSize;
    } while (true);

    // Now check clearing behavior.  First for attributes.
    ConcreteAttributePath firstAttr = list[0].GetAttributePath();

    TLV::TLVReader reader;
    CHIP_ERROR err = cache.Get(firstAttr, reader);
    // Should have gotten a value or status for now.
    EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND);

    cache.ClearAttribute(firstAttr);

    err = cache.Get(firstAttr, reader);
    // Should have gotten no value.
    EXPECT_EQ(err, CHIP_ERROR_KEY_NOT_FOUND);

    // Now clearing for clusters.  First check that things that should be there are.
    for (auto & listItem : list)
    {
        ConcreteAttributePath path = listItem.GetAttributePath();
        if (path == firstAttr)
        {
            // We removed this one already.
            continue;
        }

        err = cache.Get(path, reader);

        // Should have gotten a value or status for now.
        EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND);
    }

    auto firstCluster = ConcreteClusterPath(firstAttr);
    cache.ClearAttributes(firstCluster);

    for (auto & listItem : list)
    {
        ConcreteAttributePath path = listItem.GetAttributePath();

        err = cache.Get(path, reader);

        if (ConcreteClusterPath(path) == firstCluster)
        {
            EXPECT_EQ(err, CHIP_ERROR_KEY_NOT_FOUND);
        }
        else
        {
            // Should still have a value or status
            EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND);
        }
    }

    // Now clearing for endpoints.  First check that things that should be there are.
    // TODO: Since all our attributes have the same cluster, this is not
    // actually testing anything useful right now.
    for (auto & listItem : list)
    {
        ConcreteAttributePath path = listItem.GetAttributePath();
        if (ConcreteClusterPath(path) == firstCluster)
        {
            // We removed this one already.
            continue;
        }

        err = cache.Get(path, reader);

        // Should have gotten a value or status for now.
        EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND);
    }

    auto firstEndpoint = firstAttr.mEndpointId;
    cache.ClearAttributes(firstEndpoint);

    for (auto & listItem : list)
    {
        ConcreteAttributePath path = listItem.GetAttributePath();

        err = cache.Get(path, reader);

        if (path.mEndpointId == firstEndpoint)
        {
            EXPECT_EQ(err, CHIP_ERROR_KEY_NOT_FOUND);
        }
        else
        {
            // Should still have a value or status
            EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND);
        }
    }
}

/*
 * This validates the cache by issuing different sequences of attribute combinations
 * and ensuring that the latest view in the cache matches up with expectations.
 *
 * The print statements indicate the expected output.
 *
 * The legend is as follows:
 *
 * E1:A1 --- Endpoint 1, Attribute A, Version 1
 *
 */
TEST_F(TestClusterStateCache, TestCache)
{
    ChipLogProgress(DataManagement, "Validating various sequences of attribute data IBs...");

    //
    // Validate a range of types and ensure that they can be successfully decoded.
    //
    ChipLogProgress(DataManagement, "E1:A1 --> E1:A1");
    RunAndValidateSequence({ AttributeInstruction(

        AttributeInstruction::kAttributeA, 1, AttributeInstruction::kData) });

    ChipLogProgress(DataManagement, "E1:B1 --> E1:B1");
    RunAndValidateSequence({ AttributeInstruction(

        AttributeInstruction::kAttributeB, 1, AttributeInstruction::kData) });

    ChipLogProgress(DataManagement, "E1:C1 --> E1:C1");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeC, 1, AttributeInstruction::kData) });

    ChipLogProgress(DataManagement, "E1:D1 --> E1:D1");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kData) });

    //
    // Validate that a newer version of a data item over-rides the
    // previous copy.
    //
    ChipLogProgress(DataManagement, "E1:D1 E1:D2 --> E1:D2");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kData),
                             AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kData) });

    //
    // Validate that a newer StatusIB over-rides a previous data value.
    //
    ChipLogProgress(DataManagement, "E1:D1 E1:D2s --> E1:D2s");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kData),
                             AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kStatus) });

    //
    // Validate that a newer data value over-rides a previous status value.
    //
    ChipLogProgress(DataManagement, "E1:D1s E1:D2 --> E1:D2");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kStatus),
                             AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kData) });

    //
    // Validate data across different endpoints.
    //
    ChipLogProgress(DataManagement, "E0:D1 E1:D2 --> E0:D1 E1:D2");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeD, 0, AttributeInstruction::kData),
                             AttributeInstruction(AttributeInstruction::kAttributeD, 1, AttributeInstruction::kData) });

    ChipLogProgress(DataManagement, "E0:A1 E0:B2 E0:A3 E0:B4 --> E0:A3 E0:B4");
    RunAndValidateSequence({ AttributeInstruction(AttributeInstruction::kAttributeA, 0, AttributeInstruction::kData),
                             AttributeInstruction(AttributeInstruction::kAttributeB, 0, AttributeInstruction::kData),
                             AttributeInstruction(AttributeInstruction::kAttributeA, 0, AttributeInstruction::kData),
                             AttributeInstruction(AttributeInstruction::kAttributeB, 0, AttributeInstruction::kData) });
}

} // namespace
