LCOV - code coverage report
Current view: top level - src - mqtt_client_subscription_topic.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 24 24 100.0 %
Date: 2017-10-09 Functions: 0 0 -

          Line data    Source code
       1             : /*
       2             :  * Package : mqtt_client
       3             :  * Author : S. Hamblett <steve.hamblett@linux.com>
       4             :  * Date   : 31/05/2017
       5             :  * Copyright :  S.Hamblett
       6             :  */
       7             : 
       8             : part of mqtt_client;
       9             : 
      10             : /// Implementation of a Subscription topic that performs additional validations
      11             : /// of topics that are subscribed to.
      12             : class SubscriptionTopic extends Topic {
      13             :   /// Creates a new instance of a rawTopic from a topic string.
      14             :   SubscriptionTopic(String rawTopic)
      15           4 :       : super(rawTopic, [
      16             :     Topic.validateMinLength,
      17             :     Topic.validateMaxLength,
      18             :     _validateMultiWildcard,
      19             :     _validateFragments
      20             :   ]);
      21             : 
      22             :   /// Validates all unique fragments in the topic match the MQTT spec requirements.
      23             :   static void _validateFragments(Topic topicInstance) {
      24             :     // If any fragment contains a wildcard or a multi wildcard but is greater than
      25             :     // 1 character long, then it's an error - wildcards must appear by themselves.
      26           4 :     final bool invalidFragment = topicInstance.topicFragments.any(
      27             :             (String fragment) =>
      28           2 :         (fragment.contains(Topic.multiWildcard) ||
      29           2 :             fragment.contains(Topic.wildcard)) &&
      30           2 :             fragment.length > 1);
      31             :     if (invalidFragment) {
      32           1 :       throw new Exception(
      33             :           "mqtt_client::SubscriptionTopic: rawTopic Fragment contains a wildcard but is more than one character long");
      34             :     }
      35             :   }
      36             : 
      37             :   /// Validates the placement of the multi-wildcard character in subscription topics.
      38             :   static void _validateMultiWildcard(Topic topicInstance) {
      39           4 :     if (topicInstance.rawTopic.contains(Topic.multiWildcard) &&
      40           2 :         !topicInstance.rawTopic.endsWith(Topic.multiWildcard)) {
      41           1 :       throw new Exception(
      42             :           "mqtt_client::SubscriptionTopic: The rawTopic wildcard # can only be present at the end of a topic");
      43             :     }
      44           6 :     if (topicInstance.rawTopic.length > 1 &&
      45           4 :         topicInstance.rawTopic.endsWith(Topic.multiWildcard) &&
      46           2 :         !topicInstance.rawTopic.endsWith(Topic.multiWildcardValidEnd)) {
      47           1 :       throw new Exception(
      48             :           "mqtt_client::SubscriptionTopic: Topics using the # wildcard longer than 1 character must "
      49             :               "be immediately preceeded by a the rawTopic separator /");
      50             :     }
      51             :   }
      52             : 
      53             :   /// Checks if the rawTopic matches the supplied rawTopic using the MQTT rawTopic matching rules.
      54             :   /// Returns true if the rawTopic matches based on the MQTT rawTopic matching rules, otherwise false.
      55             :   bool matches(PublicationTopic matcheeTopic) {
      56             :     // If the left rawTopic is just a multi wildcard then we have a match without
      57             :     // needing to check any further.
      58           2 :     if (this.rawTopic == Topic.multiWildcard) {
      59             :       return true;
      60             :     }
      61             :     // If the topics are an exact match, bail early with a cheap comparison
      62           3 :     if (this.rawTopic == matcheeTopic.rawTopic) {
      63             :       return true;
      64             :     }
      65             :     // no match yet so we need to check each fragment
      66           4 :     for (int i = 0; i < this.topicFragments.length; i++) {
      67           2 :       final String lhsFragment = topicFragments[i];
      68             :       // If we've reached a multi wildcard in the lhs rawTopic,
      69             :       // we have a match.
      70             :       // (this is the mqtt spec rule finance matches finance or finance/#)
      71           1 :       if (lhsFragment == Topic.multiWildcard) {
      72             :         return true;
      73             :       }
      74           1 :       final bool isLhsWildcard = lhsFragment == Topic.wildcard;
      75             :       // If we've reached a wildcard match but the matchee does not have anything at
      76             :       // this fragment level then it's not a match.
      77             :       // (this is the mqtt spec rule finance does not match finance/+
      78           3 :       if (isLhsWildcard && matcheeTopic.topicFragments.length <= i) {
      79             :         return false;
      80             :       }
      81             :       // if lhs is not a wildcard we need to check whether the
      82             :       // two fragments match each other.
      83             :       if (!isLhsWildcard) {
      84           2 :         final String rhsFragment = matcheeTopic.topicFragments[i];
      85             :         // If the hs fragment is not wildcard then we need an exact match
      86           1 :         if (lhsFragment != rhsFragment) {
      87             :           return false;
      88             :         }
      89             :       }
      90             :       // If we're at the last fragment of the lhs rawTopic but there are
      91             :       // more fragments in the in the matchee then the matchee rawTopic
      92             :       // is too specific to be a match.
      93           4 :       if (i + 1 == this.topicFragments.length &&
      94           5 :           matcheeTopic.topicFragments.length > this.topicFragments.length) {
      95             :         return false;
      96             :       }
      97             :       // If we're here the current fragment matches so check the next
      98             :     }
      99             :     // If we exit out of the loop without a return then we have a full match rawTopic/rawTopic which would
     100             :     // have been caught by the original exact match check at the top anyway.
     101             :     return true;
     102             :   }
     103             : }

Generated by: LCOV version 1.10