Matter SDK Coverage Report
Current view: top level - app - AttributePathExpandIterator.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 100.0 % 98 98
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2024 Project CHIP Authors
       3              :  *    All rights reserved.
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : #include <app/AttributePathExpandIterator.h>
      18              : 
      19              : #include <app/GlobalAttributes.h>
      20              : #include <lib/support/CodeUtils.h>
      21              : 
      22              : using namespace chip::app::DataModel;
      23              : 
      24              : namespace chip {
      25              : namespace app {
      26              : 
      27         3069 : AttributePathExpandIterator::AttributePathExpandIterator(DataModel::Provider * provider,
      28         3069 :                                                          SingleLinkedListNode<AttributePathParams> * attributePath) :
      29         3069 :     mDataModelProvider(provider),
      30         3069 :     mpAttributePath(attributePath), mOutputPath(kInvalidEndpointId, kInvalidClusterId, kInvalidAttributeId)
      31              : 
      32              : {
      33         3069 :     mOutputPath.mExpanded = true; // this is reset in 'next' if needed
      34              : 
      35              :     // Make the iterator ready to emit the first valid path in the list.
      36              :     // TODO: the bool return value here is completely unchecked
      37         3069 :     Next();
      38         3069 : }
      39              : 
      40           35 : bool AttributePathExpandIterator::IsValidAttributeId(AttributeId attributeId)
      41              : {
      42           35 :     switch (attributeId)
      43              :     {
      44            4 :     case Clusters::Globals::Attributes::GeneratedCommandList::Id:
      45              :     case Clusters::Globals::Attributes::AcceptedCommandList::Id:
      46              :     case Clusters::Globals::Attributes::AttributeList::Id:
      47            4 :         return true;
      48           31 :     default:
      49           31 :         break;
      50              :     }
      51              : 
      52           31 :     const ConcreteAttributePath attributePath(mOutputPath.mEndpointId, mOutputPath.mClusterId, attributeId);
      53           31 :     return mDataModelProvider->GetAttributeInfo(attributePath).has_value();
      54              : }
      55              : 
      56         4375 : std::optional<AttributeId> AttributePathExpandIterator::NextAttributeId()
      57              : {
      58         4375 :     if (mOutputPath.mAttributeId == kInvalidAttributeId)
      59              :     {
      60          771 :         if (mpAttributePath->mValue.HasWildcardAttributeId())
      61              :         {
      62          736 :             AttributeEntry entry = mDataModelProvider->FirstAttribute(mOutputPath);
      63          736 :             return entry.IsValid()                                         //
      64              :                 ? entry.path.mAttributeId                                  //
      65          736 :                 : Clusters::Globals::Attributes::GeneratedCommandList::Id; //
      66              :         }
      67              : 
      68              :         // We allow fixed attribute IDs if and only if they are valid:
      69              :         //    - they may be GLOBAL attributes OR
      70              :         //    - they are valid attributes for this cluster
      71           35 :         if (IsValidAttributeId(mpAttributePath->mValue.mAttributeId))
      72              :         {
      73           26 :             return mpAttributePath->mValue.mAttributeId;
      74              :         }
      75              : 
      76            9 :         return std::nullopt;
      77              :     }
      78              : 
      79              :     // advance the existing attribute id if it can be advanced
      80         3604 :     VerifyOrReturnValue(mpAttributePath->mValue.HasWildcardAttributeId(), std::nullopt);
      81              : 
      82              :     // Ensure (including ordering) that GlobalAttributesNotInMetadata is reported as needed
      83        11650 :     for (unsigned i = 0; i < ArraySize(GlobalAttributesNotInMetadata); i++)
      84              :     {
      85         9408 :         if (GlobalAttributesNotInMetadata[i] != mOutputPath.mAttributeId)
      86              :         {
      87         8067 :             continue;
      88              :         }
      89              : 
      90         1341 :         unsigned nextAttributeIndex = i + 1;
      91         1341 :         if (nextAttributeIndex < ArraySize(GlobalAttributesNotInMetadata))
      92              :         {
      93          894 :             return GlobalAttributesNotInMetadata[nextAttributeIndex];
      94              :         }
      95              : 
      96              :         // reached the end of global attributes
      97          447 :         return std::nullopt;
      98              :     }
      99              : 
     100         2242 :     AttributeEntry entry = mDataModelProvider->NextAttribute(mOutputPath);
     101         2242 :     if (entry.IsValid())
     102              :     {
     103         1795 :         return entry.path.mAttributeId;
     104              :     }
     105              : 
     106              :     // Finished the data model, start with global attributes
     107              :     static_assert(ArraySize(GlobalAttributesNotInMetadata) > 0);
     108          447 :     return GlobalAttributesNotInMetadata[0];
     109              : }
     110              : 
     111         1182 : std::optional<ClusterId> AttributePathExpandIterator::NextClusterId()
     112              : {
     113              : 
     114         1182 :     if (mOutputPath.mClusterId == kInvalidClusterId)
     115              :     {
     116          705 :         if (mpAttributePath->mValue.HasWildcardClusterId())
     117              :         {
     118          230 :             ClusterEntry entry = mDataModelProvider->FirstServerCluster(mOutputPath.mEndpointId);
     119          230 :             return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt;
     120              :         }
     121              : 
     122              :         // only return a cluster if it is valid
     123          475 :         const ConcreteClusterPath clusterPath(mOutputPath.mEndpointId, mpAttributePath->mValue.mClusterId);
     124          475 :         if (!mDataModelProvider->GetServerClusterInfo(clusterPath).has_value())
     125              :         {
     126           29 :             return std::nullopt;
     127              :         }
     128              : 
     129          446 :         return mpAttributePath->mValue.mClusterId;
     130              :     }
     131              : 
     132          477 :     VerifyOrReturnValue(mpAttributePath->mValue.HasWildcardClusterId(), std::nullopt);
     133              : 
     134          242 :     ClusterEntry entry = mDataModelProvider->NextServerCluster(mOutputPath);
     135          242 :     return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt;
     136              : }
     137              : 
     138         1031 : std::optional<ClusterId> AttributePathExpandIterator::NextEndpointId()
     139              : {
     140         1031 :     if (mOutputPath.mEndpointId == kInvalidEndpointId)
     141              :     {
     142          617 :         if (mpAttributePath->mValue.HasWildcardEndpointId())
     143              :         {
     144           51 :             EndpointEntry ep = mDataModelProvider->FirstEndpoint();
     145           51 :             return (ep.id != kInvalidEndpointId) ? std::make_optional(ep.id) : std::nullopt;
     146              :         }
     147              : 
     148          566 :         return mpAttributePath->mValue.mEndpointId;
     149              :     }
     150              : 
     151          414 :     VerifyOrReturnValue(mpAttributePath->mValue.HasWildcardEndpointId(), std::nullopt);
     152              : 
     153          123 :     EndpointEntry ep = mDataModelProvider->NextEndpoint(mOutputPath.mEndpointId);
     154          123 :     return (ep.id != kInvalidEndpointId) ? std::make_optional(ep.id) : std::nullopt;
     155              : }
     156              : 
     157          263 : void AttributePathExpandIterator::ResetCurrentCluster()
     158              : {
     159              :     // If this is a null iterator, or the attribute id of current cluster info is not a wildcard attribute id, then this function
     160              :     // will do nothing, since we won't be expanding the wildcard attribute ids under a cluster.
     161          263 :     VerifyOrReturn(mpAttributePath != nullptr && mpAttributePath->mValue.HasWildcardAttributeId());
     162              : 
     163              :     // Reset path expansion to ask for the first attribute of the current cluster
     164            3 :     mOutputPath.mAttributeId = kInvalidAttributeId;
     165            3 :     mOutputPath.mExpanded    = true; // we know this is a wildcard attribute
     166            3 :     Next();
     167              : }
     168              : 
     169         6821 : bool AttributePathExpandIterator::AdvanceOutputPath()
     170              : {
     171         6821 :     if (!mpAttributePath->mValue.IsWildcardPath())
     172              :     {
     173         2597 :         if (mOutputPath.mEndpointId != kInvalidEndpointId)
     174              :         {
     175          951 :             return false; // cannot expand non-wildcard path
     176              :         }
     177              : 
     178         1646 :         mOutputPath.mEndpointId  = mpAttributePath->mValue.mEndpointId;
     179         1646 :         mOutputPath.mClusterId   = mpAttributePath->mValue.mClusterId;
     180         1646 :         mOutputPath.mAttributeId = mpAttributePath->mValue.mAttributeId;
     181         1646 :         mOutputPath.mExpanded    = false;
     182         1646 :         return true;
     183              :     }
     184              : 
     185              :     while (true)
     186              :     {
     187         5697 :         if (mOutputPath.mClusterId != kInvalidClusterId)
     188              :         {
     189              : 
     190         4375 :             std::optional<AttributeId> nextAttribute = NextAttributeId();
     191         4375 :             if (nextAttribute.has_value())
     192              :             {
     193         3898 :                 mOutputPath.mAttributeId = *nextAttribute;
     194         3898 :                 return true;
     195              :             }
     196              :         }
     197              : 
     198              :         // no valid attribute, try to advance the cluster, see if a suitable one exists
     199         1799 :         if (mOutputPath.mEndpointId != kInvalidEndpointId)
     200              :         {
     201         1182 :             std::optional<ClusterId> nextCluster = NextClusterId();
     202         1182 :             if (nextCluster.has_value())
     203              :             {
     204          768 :                 mOutputPath.mClusterId   = *nextCluster;
     205          768 :                 mOutputPath.mAttributeId = kInvalidAttributeId; // restarts attributes
     206          768 :                 continue;
     207              :             }
     208              :         }
     209              : 
     210              :         // no valid cluster, try advance the endpoint, see if a suitable on exists
     211         1031 :         std::optional<EndpointId> nextEndpoint = NextEndpointId();
     212         1031 :         if (nextEndpoint.has_value())
     213              :         {
     214          705 :             mOutputPath.mEndpointId = *nextEndpoint;
     215          705 :             mOutputPath.mClusterId  = kInvalidClusterId; // restarts clusters
     216          705 :             continue;
     217              :         }
     218          326 :         return false;
     219         1473 :     }
     220              : }
     221              : 
     222         7627 : bool AttributePathExpandIterator::Next()
     223              : {
     224         8904 :     while (mpAttributePath != nullptr)
     225              :     {
     226         6821 :         if (AdvanceOutputPath())
     227              :         {
     228         5544 :             return true;
     229              :         }
     230         1277 :         mpAttributePath       = mpAttributePath->mpNext;
     231         1277 :         mOutputPath           = ConcreteReadAttributePath(kInvalidEndpointId, kInvalidClusterId, kInvalidAttributeId);
     232         1277 :         mOutputPath.mExpanded = true; // this is reset to false on advancement if needed
     233              :     }
     234              : 
     235         2083 :     mOutputPath = ConcreteReadAttributePath();
     236         2083 :     return false;
     237              : }
     238              : 
     239              : } // namespace app
     240              : } // namespace chip
        

Generated by: LCOV version 2.0-1