blob: be446fd3f42c28b6056ca111de00e027ba3abd21 [file] [log] [blame]
/*
* Copyright (c) 2022 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 <string>
#include <app-common/zap-generated/cluster-objects.h>
#include <lib/support/Span.h>
class ConstraintsChecker
{
public:
ConstraintsChecker(){};
virtual ~ConstraintsChecker(){};
protected:
virtual void Exit(std::string message, CHIP_ERROR err = CHIP_ERROR_INTERNAL) = 0;
bool CheckConstraintType(const char * itemName, const char * current, const char * expected)
{
if (strcmp(current, expected) != 0)
{
Exit(std::string(itemName) + " type (" + std::string(current) + ") is different than the expected type (" +
std::string(expected) + ").");
return false;
}
return true;
}
bool CheckConstraintFormat(const char * itemName, const char * current, const char * expected)
{
ChipLogError(chipTool, "Warning: %s format checking is not implemented yet. Expected format: '%s'",
StringOrNullMarker(itemName), StringOrNullMarker(expected));
return true;
}
bool CheckConstraintMinLength(const char * itemName, uint64_t current, uint64_t expected)
{
if (current < expected)
{
Exit(std::string(itemName) + " length < minLength: " + std::to_string(current) + " < " + std::to_string(expected));
return false;
}
return true;
}
bool CheckConstraintMaxLength(const char * itemName, uint64_t current, uint64_t expected)
{
if (current > expected)
{
Exit(std::string(itemName) + " length > maxLength: " + std::to_string(current) + " > " + std::to_string(expected));
return false;
}
return true;
}
template <typename T>
bool CheckConstraintMinLength(const char * itemName, const chip::Span<T> & current, uint64_t expected)
{
return CheckConstraintMinLength(itemName, current.size(), expected);
}
template <typename T>
bool CheckConstraintMaxLength(const char * itemName, const chip::Span<T> & current, uint64_t expected)
{
return CheckConstraintMaxLength(itemName, current.size(), expected);
}
template <typename T>
bool CheckConstraintMinLength(const char * itemName, const chip::app::DataModel::DecodableList<T> & current, uint64_t expected)
{
size_t size;
CHIP_ERROR err = current.ComputeSize(&size);
if (err != CHIP_NO_ERROR)
{
Exit(std::string(itemName) + " length cannot be extracted: " + err.AsString());
return false;
}
return CheckConstraintMinLength(itemName, size, expected);
}
template <typename T>
bool CheckConstraintMaxLength(const char * itemName, const chip::app::DataModel::DecodableList<T> & current, uint64_t expected)
{
size_t size;
CHIP_ERROR err = current.ComputeSize(&size);
if (err != CHIP_NO_ERROR)
{
Exit(std::string(itemName) + " length cannot be extracted: " + err.AsString());
return false;
}
return CheckConstraintMaxLength(itemName, size, expected);
}
bool CheckConstraintStartsWith(const char * itemName, const chip::CharSpan current, const char * expected)
{
std::string value(current.data(), current.size());
if (value.rfind(expected, 0) != 0)
{
Exit(std::string(itemName) + " (\"" + value + "\") does not starts with: \"" + std::string(expected) + "\"");
return false;
}
return true;
}
bool CheckConstraintEndsWith(const char * itemName, const chip::CharSpan current, const char * expected)
{
std::string value(current.data(), current.size());
if (value.find(expected, value.size() - strlen(expected)) == std::string::npos)
{
Exit(std::string(itemName) + " (\"" + value + "\") does not ends with: \"" + std::string(expected) + "\"");
return false;
}
return true;
}
bool CheckConstraintIsUpperCase(const char * itemName, const chip::CharSpan current, bool expectUpperCase)
{
std::string value(current.data(), current.size());
return CheckConstraintIsUpperCase(itemName, value.c_str(), expectUpperCase);
}
bool CheckConstraintIsUpperCase(const char * itemName, const char * current, bool expectUpperCase)
{
bool isUpperCase = true;
for (size_t i = 0; i < strlen(current); i++)
{
if (islower(current[i]))
{
isUpperCase = false;
break;
}
}
if (expectUpperCase && !isUpperCase)
{
Exit(std::string(itemName) + " (\"" + std::string(current) + "\") is not an upppercase string");
return false;
}
if (!expectUpperCase && isUpperCase)
{
Exit(std::string(itemName) + " (\"" + std::string(current) + "\") is an upppercase string");
return false;
}
return true;
}
bool CheckConstraintIsLowerCase(const char * itemName, const chip::CharSpan current, bool expectLowerCase)
{
std::string value(current.data(), current.size());
return CheckConstraintIsLowerCase(itemName, value.c_str(), expectLowerCase);
}
bool CheckConstraintIsLowerCase(const char * itemName, const char * current, bool expectLowerCase)
{
bool isLowerCase = true;
for (size_t i = 0; i < strlen(current); i++)
{
if (isupper(current[i]))
{
isLowerCase = false;
break;
}
}
if (expectLowerCase && !isLowerCase)
{
Exit(std::string(itemName) + " (\"" + std::string(current) + "\") is not a lowercase string");
return false;
}
if (!expectLowerCase && isLowerCase)
{
Exit(std::string(itemName) + " (\"" + std::string(current) + "\") is a lowercase string");
return false;
}
return true;
}
bool CheckConstraintIsHexString(const char * itemName, const chip::CharSpan current, bool expectHexString)
{
std::string value(current.data(), current.size());
return CheckConstraintIsHexString(itemName, value.c_str(), expectHexString);
}
bool CheckConstraintIsHexString(const char * itemName, const char * current, bool expectHexString)
{
bool isHexString = true;
for (size_t i = 0; i < strlen(current); i++)
{
if (!isxdigit(current[i]))
{
isHexString = false;
break;
}
}
if (expectHexString && !isHexString)
{
Exit(std::string(itemName) + " (\"" + std::string(current) + "\") is not a hexadecimal string");
return false;
}
if (!expectHexString && isHexString)
{
Exit(std::string(itemName) + " (\"" + std::string(current) + "\") is a hexadecimal string");
return false;
}
return true;
}
template <typename T, typename U, std::enable_if_t<!std::is_enum<T>::value && !std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, T current, U expected)
{
if (current < expected)
{
Exit(std::string(itemName) + " value < minValue: " + std::to_string(current) + " < " + std::to_string(expected));
return false;
}
return true;
}
template <typename T, typename U,
std::enable_if_t<std::is_enum<T>::value && !std::is_enum<U>::value && !std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, T current, U expected)
{
return CheckConstraintMinValue(itemName, chip::to_underlying(current), expected);
}
template <typename T, typename U, std::enable_if_t<std::is_enum<T>::value && std::is_enum<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, T current, U expected)
{
return CheckConstraintMinValue(itemName, chip::to_underlying(current), chip::to_underlying(expected));
}
template <typename T, typename U, std::enable_if_t<!std::is_enum<T>::value && std::is_enum<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, T current, U expected)
{
return CheckConstraintMinValue(itemName, current, chip::to_underlying(expected));
}
template <typename T, typename U, std::enable_if_t<!std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, chip::BitFlags<T> current, U expected)
{
if (current.Raw() < expected)
{
Exit(std::string(itemName) + " value < minValue: " + std::to_string(current.Raw()) + " < " + std::to_string(expected));
return false;
}
return true;
}
template <typename T, typename U, std::enable_if_t<!std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, chip::BitMask<T> current, U expected)
{
if (current.Raw() < expected)
{
Exit(std::string(itemName) + " value < minValue: " + std::to_string(current.Raw()) + " < " + std::to_string(expected));
return false;
}
return true;
}
template <typename T, typename U, std::enable_if_t<!std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMinValue(const char * itemName, const chip::app::DataModel::Nullable<T> & current, U expected)
{
if (current.IsNull())
{
return true;
}
return CheckConstraintMinValue(itemName, current.Value(), static_cast<T>(expected));
}
template <typename T, typename U>
bool CheckConstraintMinValue(const char * itemName, const T & current, const chip::Optional<U> & expected)
{
if (!expected.HasValue())
{
Exit(std::string(itemName) + ": expected min value does not have a value");
return false;
}
return CheckConstraintMinValue(itemName, current, expected.Value());
}
template <typename T, typename U, std::enable_if_t<!std::is_enum<T>::value && !std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, T current, U expected)
{
if (current > expected)
{
Exit(std::string(itemName) + " value > maxValue: " + std::to_string(current) + " > " + std::to_string(expected));
return false;
}
return true;
}
template <typename T, typename U,
std::enable_if_t<std::is_enum<T>::value && !std::is_enum<U>::value && !std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, T current, U expected)
{
return CheckConstraintMaxValue(itemName, chip::to_underlying(current), expected);
}
template <typename T, typename U, std::enable_if_t<std::is_enum<T>::value && std::is_enum<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, T current, U expected)
{
return CheckConstraintMaxValue(itemName, chip::to_underlying(current), chip::to_underlying(expected));
}
template <typename T, typename U, std::enable_if_t<!std::is_enum<T>::value && std::is_enum<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, T current, U expected)
{
return CheckConstraintMaxValue(itemName, current, chip::to_underlying(expected));
}
template <typename T, typename U, std::enable_if_t<!std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, chip::BitFlags<T> current, U expected)
{
if (current.Raw() > expected)
{
Exit(std::string(itemName) + " value > maxValue: " + std::to_string(current.Raw()) + " > " + std::to_string(expected));
return false;
}
return true;
}
template <typename T, typename U, std::enable_if_t<!std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, chip::BitMask<T> current, U expected)
{
if (current.Raw() > expected)
{
Exit(std::string(itemName) + " value > maxValue: " + std::to_string(current.Raw()) + " > " + std::to_string(expected));
return false;
}
return true;
}
template <typename T, typename U, std::enable_if_t<!std::is_pointer<U>::value, int> = 0>
bool CheckConstraintMaxValue(const char * itemName, const chip::app::DataModel::Nullable<T> & current, U expected)
{
if (current.IsNull())
{
return true;
}
return CheckConstraintMaxValue(itemName, current.Value(), static_cast<T>(expected));
}
template <typename T, typename U>
bool CheckConstraintMaxValue(const char * itemName, const T & current, const chip::Optional<U> & expected)
{
if (!expected.HasValue())
{
Exit(std::string(itemName) + ": expected max value does not have a value");
return false;
}
return CheckConstraintMaxValue(itemName, current, expected.Value());
}
template <typename T>
bool CheckConstraintNotValue(const char * itemName, const chip::app::DataModel::Nullable<T> & current,
const chip::app::DataModel::Nullable<T> & expected)
{
if (expected.IsNull() && current.IsNull())
{
Exit(std::string(itemName) + " got null for both values, but expected not equal");
return false;
}
if (expected.IsNull() != current.IsNull())
{
return true;
}
return CheckConstraintNotValue(itemName, current.Value(), expected.Value());
}
template <typename T, typename U, std::enable_if_t<!std::is_enum<T>::value, int> = 0>
bool CheckConstraintNotValue(const char * itemName, T current, U expected)
{
if (current == expected)
{
Exit(std::string(itemName) + " got unexpected value: " + std::to_string(current));
return false;
}
return true;
}
template <typename T, typename U, std::enable_if_t<std::is_enum<T>::value, int> = 0>
bool CheckConstraintNotValue(const char * itemName, T current, U expected)
{
return CheckConstraintNotValue(itemName, chip::to_underlying(current), expected);
}
template <typename T, std::enable_if_t<std::is_enum<T>::value, int> = 0>
bool CheckConstraintNotValue(const char * itemName, T current, T expected)
{
return CheckConstraintNotValue(itemName, chip::to_underlying(current), chip::to_underlying(expected));
}
template <typename T>
bool CheckConstraintNotValue(const char * itemName, chip::BitFlags<T> current, chip::BitFlags<T> expected)
{
if (current == expected)
{
Exit(std::string(itemName) + " got unexpected value: " + std::to_string(current.Raw()));
return false;
}
return true;
}
template <typename T>
bool CheckConstraintNotValue(const char * itemName, chip::BitMask<T> current, chip::BitMask<T> expected)
{
if (current == expected)
{
Exit(std::string(itemName) + " got unexpected value: " + std::to_string(current.Raw()));
return false;
}
return true;
}
template <typename T, typename U>
bool CheckConstraintNotValue(const char * itemName, chip::BitFlags<T> current, U expected)
{
if (current.Raw() == expected)
{
Exit(std::string(itemName) + " got unexpected value: " + std::to_string(current.Raw()));
return false;
}
return true;
}
template <typename T, typename U>
bool CheckConstraintNotValue(const char * itemName, chip::BitMask<T> current, U expected)
{
if (current.Raw() == expected)
{
Exit(std::string(itemName) + " got unexpected value: " + std::to_string(current.Raw()));
return false;
}
return true;
}
template <typename T, typename U>
bool CheckConstraintNotValue(const char * itemName, const chip::app::DataModel::Nullable<T> & current, U expected)
{
if (current.IsNull())
{
return true;
}
return CheckConstraintNotValue(itemName, current.Value(), expected);
}
bool CheckConstraintNotValue(const char * itemName, const chip::CharSpan current, const chip::CharSpan expected)
{
if (current.data_equal(expected))
{
Exit(std::string(itemName) + " got unexpected value: " + std::string(current.data(), current.size()));
return false;
}
return true;
}
bool CheckConstraintNotValue(const char * itemName, const chip::ByteSpan current, const chip::ByteSpan expected)
{
if (current.data_equal(expected))
{
Exit(std::string(itemName) + " got unexpected value of size: " + std::to_string(current.size()));
return false;
}
return true;
}
template <typename T, typename U>
bool CheckConstraintNotValue(const char * itemName, const T & current, const chip::Optional<U> & expected)
{
if (!expected.HasValue())
{
Exit(std::string(itemName) + ": expected disallowed value does not have a value");
return false;
}
return CheckConstraintNotValue(itemName, current, expected.Value());
}
template <typename T>
bool CheckConstraintHasValue(const char * itemName, const chip::Optional<T> & current, bool expected)
{
if (current.HasValue() == expected)
{
return true;
}
if (current.HasValue())
{
Exit(std::string(itemName) + " not expected to have a value but does");
}
else
{
Exit(std::string(itemName) + " expected to have a value but doesn't");
}
return false;
}
template <typename T, typename U>
bool CheckConstraintContains(const char * itemName, const chip::app::DataModel::DecodableList<T> & current, const U & expected)
{
auto iterValue = current.begin();
while (iterValue.Next())
{
auto currentValue = iterValue.GetValue();
if (currentValue == expected)
{
return true;
}
}
Exit(std::string(itemName) + " expect the value " + std::to_string(expected) + " but the list does not contains it.");
return false;
}
template <typename T, typename U>
bool CheckConstraintExcludes(const char * itemName, const chip::app::DataModel::DecodableList<T> & current, const U & expected)
{
auto iterValue = current.begin();
while (iterValue.Next())
{
auto currentValue = iterValue.GetValue();
if (currentValue == expected)
{
Exit(std::string(itemName) + " does not expect the value " + std::to_string(expected) +
" but the list contains it.");
return false;
}
}
CHIP_ERROR err = iterValue.GetStatus();
if (CHIP_NO_ERROR != err)
{
Exit(std::string(chip::ErrorStr(err)));
return false;
}
return true;
}
template <typename T, typename U>
bool CheckConstraintHasMasksSet(const char * itemName, const T & current, const U & expected)
{
if (current & expected)
{
return true;
}
Exit(std::string(itemName) + " expects the field with value " + std::to_string(expected) + " to be set but it is not.");
return false;
}
template <typename T, typename U>
bool CheckConstraintHasMasksSet(const char * itemName, const chip::BitMask<T> & current, const U & expected)
{
if (current.Has(static_cast<T>(expected)))
{
return true;
}
Exit(std::string(itemName) + " expects the field with value " + std::to_string(expected) + " to be set but it is not.");
return false;
}
template <typename T, typename U>
bool CheckConstraintHasMasksClear(const char * itemName, const T & current, const U & expected)
{
if ((current & expected) == 0)
{
return true;
}
Exit(std::string(itemName) + " expects the field with value " + std::to_string(expected) + " to not be set but it is.");
return false;
}
template <typename T, typename U>
bool CheckConstraintHasMasksClear(const char * itemName, const chip::BitMask<T> & current, const U & expected)
{
if (!current.Has(static_cast<T>(expected)))
{
return true;
}
Exit(std::string(itemName) + " expects the field with value " + std::to_string(expected) + " to not be set but it is.");
return false;
}
};