blob: e34a83377313abe721778bf596bd18cc9025cc87 [file] [log] [blame]
/*
* Copyright (c) 2024 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.
*/
#pragma once
#include <access/SubjectDescriptor.h>
#include <app/AttributeEncodeState.h>
#include <app/AttributeValueEncoder.h>
#include <app/ConcreteAttributePath.h>
#include <app/data-model-provider/OperationTypes.h>
#include <app/data-model-provider/tests/TestConstants.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/BitFlags.h>
#include <vector>
namespace chip {
namespace app {
namespace Testing {
/// Contains information about a single parsed item inside an attribute data IB
struct DecodedAttributeData
{
chip::DataVersion dataVersion;
chip::app::ConcreteDataAttributePath attributePath;
chip::TLV::TLVReader dataReader;
CHIP_ERROR DecodeFrom(const chip::app::AttributeDataIB::Parser & parser);
};
/// Maintains an internal TLV buffer for data encoding and
/// decoding for ReportIBs.
///
/// Main use case is that explicit TLV layouts (structure and container starting) need to be
/// prepared to have a proper AttributeReportIBs::Builder/parser to exist.
class EncodedReportIBs
{
public:
/// Initialize the report structures required to encode a
CHIP_ERROR StartEncoding(app::AttributeReportIBs::Builder & builder);
CHIP_ERROR FinishEncoding(app::AttributeReportIBs::Builder & builder);
/// Decode the embedded attribute report IBs.
/// The TLVReaders inside data have a lifetime tied to the current object (its readers point
/// inside the current object)
CHIP_ERROR Decode(std::vector<DecodedAttributeData> & decoded_items) const;
private:
constexpr static size_t kMaxTLVBufferSize = 1024;
uint8_t mTlvDataBuffer[kMaxTLVBufferSize];
TLV::TLVType mOuterStructureType;
TLV::TLVWriter mEncodeWriter;
ByteSpan mDecodeSpan;
};
/// Contains a `ReadAttributeRequest` as well as classes to convert this into a AttributeReportIBs
/// and later decode it
///
/// It wraps boilerplate code to obtain a `AttributeValueEncoder` as well as later decoding
/// the underlying encoded data for verification.
///
/// Usage:
///
/// ReadOperation operation(1 /* endpoint */, 2 /* cluster */, 3 /* attribute */);
///
/// auto encoder = operation.StartEncoding(/* ... */);
/// ASSERT_NE(encoder.get(), nullptr);
///
/// // use encoder, like pass in to a WriteAttribute() call
///
/// ASSERT_EQ(operation.FinishEncoding(), CHIP_NO_ERROR);
///
/// // extract the written data
/// std::vector<DecodedAttributeData> items;
/// ASSERT_EQ(read_request.GetEncodedIBs().Decode(items), CHIP_NO_ERROR);
///
/// // can use items::dataReader for a chip::TLV::TLVReader access to the underlying data
/// // for example
/// uint32_t value = 0;
/// chip::TLV::TLVReader reader(items[0].dataReader);
/// ASSERT_EQ(reader.Get(value), CHIP_NO_ERROR);
/// ASSERT_EQ(value, 123u);
///
///
class ReadOperation
{
public:
/// Represents parameters for StartEncoding
class EncodingParams
{
public:
EncodingParams() {}
EncodingParams & SetDataVersion(chip::DataVersion v)
{
mDataVersion = v;
return *this;
}
EncodingParams & SetIsFabricFiltered(bool filtered)
{
mIsFabricFiltered = filtered;
return *this;
}
EncodingParams & SetEncodingState(const AttributeEncodeState & state)
{
mAttributeEncodeState = state;
return *this;
}
chip::DataVersion GetDataVersion() const { return mDataVersion; }
bool GetIsFabricFiltered() const { return mIsFabricFiltered; }
const AttributeEncodeState & GetAttributeEncodeState() const { return mAttributeEncodeState; }
private:
chip::DataVersion mDataVersion = 0x1234;
bool mIsFabricFiltered = false;
AttributeEncodeState mAttributeEncodeState;
};
ReadOperation(const ConcreteAttributePath & path)
{
mRequest.path = path;
mRequest.subjectDescriptor = &kDenySubjectDescriptor;
}
ReadOperation(EndpointId endpoint, ClusterId cluster, AttributeId attribute) :
ReadOperation(ConcreteAttributePath(endpoint, cluster, attribute))
{}
ReadOperation & SetSubjectDescriptor(const chip::Access::SubjectDescriptor & descriptor)
{
VerifyOrDie(mState == State::kInitializing);
mRequest.subjectDescriptor = &descriptor;
return *this;
}
ReadOperation & SetReadFlags(const BitFlags<DataModel::ReadFlags> & flags)
{
VerifyOrDie(mState == State::kInitializing);
mRequest.readFlags = flags;
return *this;
}
ReadOperation & SetOperationFlags(const BitFlags<DataModel::OperationFlags> & flags)
{
VerifyOrDie(mState == State::kInitializing);
mRequest.operationFlags = flags;
return *this;
}
ReadOperation & SetPathExpanded(bool value)
{
VerifyOrDie(mState == State::kInitializing);
mRequest.path.mExpanded = value;
return *this;
}
/// Start the encoding of a new element with the given data version associated to it.
///
/// The input attribute encoding state will be attached to the returned value encoded (so that
/// encoding for list elements is possible)
///
std::unique_ptr<AttributeValueEncoder> StartEncoding(const EncodingParams & params = EncodingParams());
/// Completes the encoding and finalizes the undelying AttributeReport.
///
/// Call this to finish a set of `StartEncoding` values and have access to
/// the underlying `GetEncodedIBs`
CHIP_ERROR FinishEncoding();
/// Get the underlying read request (i.e. path and flags) for this request
const DataModel::ReadAttributeRequest & GetRequest() const { return mRequest; }
/// Once encoding has finished, you can get access to the underlying
/// written data via GetEncodedIBs.
const EncodedReportIBs & GetEncodedIBs() const
{
VerifyOrDie(mState == State::kFinished);
return mEncodedIBs;
}
private:
enum class State
{
kInitializing, // Setting up initial values (i.e. setting up mRequest)
kEncoding, // Encoding values via StartEncoding
kFinished, // FinishEncoding has been called
};
State mState = State::kInitializing;
DataModel::ReadAttributeRequest mRequest;
// encoded-used classes
EncodedReportIBs mEncodedIBs;
AttributeReportIBs::Builder mAttributeReportIBsBuilder;
};
} // namespace Testing
} // namespace app
} // namespace chip