]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add SvcParam class plus tests
authorPieter Lexis <pieter.lexis@powerdns.com>
Thu, 30 Jul 2020 13:52:17 +0000 (15:52 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Fri, 25 Sep 2020 10:26:12 +0000 (12:26 +0200)
pdns/Makefile.am
pdns/svc-records.cc [new file with mode: 0644]
pdns/svc-records.hh [new file with mode: 0644]
pdns/test-svc_records_cc.cc [new file with mode: 0644]

index 10c77ebc79d87611f6c779c7384b9e9c24538826..d0fae49483cb185f3c03e56f805373b84373d349 100644 (file)
@@ -1263,6 +1263,7 @@ testrunner_SOURCES = \
        proxy-protocol.cc proxy-protocol.hh \
        qtype.cc \
        rcpgenerator.cc \
+       svc-records.cc \
        responsestats.cc \
        responsestats-auth.cc \
        shuffle.cc shuffle.hh \
@@ -1294,9 +1295,10 @@ testrunner_SOURCES = \
        test-packetcache_hh.cc \
        test-proxy_protocol_cc.cc \
        test-rcpgenerator_cc.cc \
-       test-signers.cc \
        test-sha_hh.cc \
+       test-signers.cc \
        test-statbag_cc.cc \
+       test-svc_records_cc.cc \
        test-tsig.cc \
        test-ueberbackend_cc.cc \
        test-zoneparser_tng_cc.cc \
diff --git a/pdns/svc-records.cc b/pdns/svc-records.cc
new file mode 100644 (file)
index 0000000..1431a71
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "svc-records.hh"
+#include "misc.hh"
+#include "base64.hh"
+
+const std::map<std::string, SvcParam::SvcParamKey> SvcParam::SvcParams = {
+  {"mandatory", SvcParam::SvcParamKey::mandatory},
+  {"alpn", SvcParam::SvcParamKey::alpn},
+  {"no-default-alpn", SvcParam::SvcParamKey::no_default_alpn},
+  {"port", SvcParam::SvcParamKey::port},
+  {"ipv4hint", SvcParam::SvcParamKey::ipv4hint},
+  {"echconfig", SvcParam::SvcParamKey::echconfig},
+  {"ipv6hint", SvcParam::SvcParamKey::ipv6hint}
+};
+
+SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k) {
+  auto it = SvcParams.find(k);
+  if (it != SvcParams.end()) {
+    return it->second;
+  }
+  if (k.substr(0, 3) == "key") {
+    try {
+      return SvcParam::SvcParamKey(pdns_stou(k.substr(3)));
+    }
+    catch (...) {
+    }
+  }
+  throw std::invalid_argument("SvcParam '" + k + "'is not recognized or in keyNNNN format");
+}
+
+std::string SvcParam::keyToString(const SvcParam::SvcParamKey& k) {
+  auto ret = std::find_if(SvcParams.begin(), SvcParams.end(), [&](const std::pair<std::string, SvcParam::SvcParamKey>& e) { return e.second == k; });
+  if (ret != SvcParams.end()) {
+    return ret->first;
+  }
+  return "key" + std::to_string(k);
+}
+
+SvcParam::SvcParam() {};
+
+SvcParam::SvcParam(const SvcParamKey &key) {
+  d_key = key;
+  if (d_key != SvcParamKey::no_default_alpn) {
+    throw std::invalid_argument("can not create non-empty SvcParam for key '" + keyToString(key) + "'");
+  }
+}
+
+SvcParam::SvcParam(const SvcParamKey &key, const std::string &value) {
+  d_key = key;
+  if (d_key != SvcParamKey::echconfig && d_key < 7) {
+    throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string value");
+  }
+  if (d_key == SvcParamKey::echconfig) {
+    std::string d;
+    // TODO check Base64 decode
+    d_echconfig = value;
+    return;
+  }
+  d_value = value;
+}
+
+SvcParam::SvcParam(const SvcParamKey &key, const std::set<std::string> &value) {
+  d_key = key;
+  if (d_key != SvcParamKey::alpn && d_key != SvcParamKey::mandatory) {
+    throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value");
+  }
+  if (d_key == SvcParamKey::alpn) {
+    d_alpn = value;
+  }
+  if (d_key == SvcParamKey::mandatory) {
+    // TODO validate entries
+    d_mandatory = value;
+  }
+}
+
+SvcParam::SvcParam(const SvcParamKey &key, const std::set<ComboAddress> &value) {
+  d_key = key;
+  if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) {
+    throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an IP address value");
+  }
+  for (auto const &addr : value) {
+    if (d_key == SvcParam::ipv6hint && !addr.isIPv6()) {
+      throw std::invalid_argument("non-IPv6 address ('" + addr.toString() + "') passed for " + keyToString(key));
+    }
+    if (d_key == SvcParam::ipv4hint && !addr.isIPv4()) {
+      throw std::invalid_argument("non-IPv4 address ('" + addr.toString() + "') passed for " + keyToString(key));
+    }
+  }
+  d_ipHints = value;
+}
+
+SvcParam::SvcParam(const SvcParamKey &key, const uint16_t value) {
+  d_key = key;
+  if (d_key != SvcParamKey::port) {
+    throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an port value");
+  }
+  d_port = value;
+}
+
+std::set<ComboAddress> SvcParam::getIPHints() const {
+  if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) {
+    throw std::invalid_argument("getIPHints called for non-IP address key '" + keyToString(d_key) + "'");
+  }
+  return d_ipHints;
+}
+
+uint16_t SvcParam::getPort() const {
+  if (d_key != SvcParam::port) {
+    throw std::invalid_argument("getPort called for non-port key '" + keyToString(d_key) + "'");
+  }
+  return d_port;
+}
+
+std::set<std::string> SvcParam::getALPN() const {
+  if (d_key != SvcParam::alpn) {
+    throw std::invalid_argument("getALPN called for non-alpn key '" + keyToString(d_key) + "'");
+  }
+  return d_alpn;
+}
+
+std::set<std::string> SvcParam::getMandatory() const {
+  if (d_key != SvcParam::mandatory) {
+    throw std::invalid_argument("getMandatory called for non-mandatory key '" + keyToString(d_key) + "'");
+  }
+  return d_mandatory;
+}
+
+std::string SvcParam::getEchConfig() const {
+  if (d_key != SvcParam::echconfig) {
+    throw std::invalid_argument("getEchConfig called for non-echconfig key '" + keyToString(d_key) + "'");
+  }
+  return d_echconfig;
+}
+
+std::string SvcParam::getValue() const {
+  if (d_key < 7) {
+    throw std::invalid_argument("getValue called for non-single value key '" + keyToString(d_key) + "'");
+  }
+  return d_value;
+}
\ No newline at end of file
diff --git a/pdns/svc-records.hh b/pdns/svc-records.hh
new file mode 100644 (file)
index 0000000..5de7f0f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <string>
+#include <map>
+#include <set>
+#include "iputils.hh"
+
+class SvcParam {
+  public:
+    enum SvcParamKey: uint16_t {
+      // TODO link to IANA registry
+      /* When adding new values, you *must* update SvcParam::SvcParam(const std::string &key, const std::string &value)
+       * in svc-record.cc with the new numbers
+       */
+      mandatory = 0,
+      alpn = 1,
+      no_default_alpn = 2,
+      port = 3,
+      ipv4hint = 4,
+      echconfig = 5,
+      ipv6hint = 6
+    };
+
+  //! empty Param, unusable
+  SvcParam();
+
+  //! To create a value-less SvcParam (like no-default-alpn)
+  SvcParam(const SvcParamKey &key);
+
+  //! To create a "generic" SvcParam (for keyNNNNN and echconfig)
+  SvcParam(const SvcParamKey &key, const std::string &value);
+
+  //! To create a multi-value SvcParam (like alpn and mandatory)
+  SvcParam(const SvcParamKey &key, const std::set<std::string> &value);
+
+  //! To create and ipv{4,6}hists SvcParam
+  SvcParam(const SvcParamKey &key, const std::set<ComboAddress> &value);
+
+  //! To create a port SvcParam
+  SvcParam(const SvcParamKey &key, const uint16_t value);
+
+  //! Returns the SvcParamKey based on the input
+  static SvcParamKey keyFromString(const std::string &k);
+
+  //! Returns the string value of the SvcParamKey
+  static std::string keyToString(const SvcParamKey &k);
+
+  bool operator< (const SvcParam &other) const {
+    return this->d_key < other.d_key;
+  };
+
+  SvcParamKey getKey() const {
+    return d_key;
+  }
+
+  uint16_t getPort() const;
+  std::set<ComboAddress> getIPHints() const;
+  std::set<std::string> getALPN() const;
+  std::set<std::string> getMandatory() const;
+  std::string getEchConfig() const;
+  std::string getValue() const;
+
+  private:
+    SvcParamKey d_key;
+    std::string d_value; // For keyNNNNN vals
+
+    std::set<std::string> d_alpn; // For ALPN
+    std::set<std::string> d_mandatory; // For mandatory
+    std::set<ComboAddress> d_ipHints; // For ipv{6,4}hints
+    std::string d_echconfig; // For echconfig
+    uint16_t d_port; // For port
+
+    static const std::map<std::string, SvcParamKey> SvcParams;
+};
diff --git a/pdns/test-svc_records_cc.cc b/pdns/test-svc_records_cc.cc
new file mode 100644 (file)
index 0000000..1c08e43
--- /dev/null
@@ -0,0 +1,203 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <bitset>
+#include "svc-records.hh"
+#include "base64.hh"
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(test_svc_records_cc)
+BOOST_AUTO_TEST_CASE(test_SvcParam_keyFromString) {
+    SvcParam::SvcParamKey k;
+
+    k = SvcParam::keyFromString("mandatory");
+    BOOST_CHECK_EQUAL(k, 0);
+    BOOST_CHECK_EQUAL(k, SvcParam::mandatory);
+
+    k = SvcParam::keyFromString("alpn");
+    BOOST_CHECK_EQUAL(k, 1);
+    BOOST_CHECK_EQUAL(k, SvcParam::alpn);
+
+    k = SvcParam::keyFromString("no-default-alpn");
+    BOOST_CHECK_EQUAL(k, 2);
+    BOOST_CHECK_EQUAL(k, SvcParam::no_default_alpn);
+
+    k = SvcParam::keyFromString("port");
+    BOOST_CHECK_EQUAL(k, 3);
+    BOOST_CHECK_EQUAL(k, SvcParam::port);
+
+    k = SvcParam::keyFromString("ipv4hint");
+    BOOST_CHECK_EQUAL(k, 4);
+    BOOST_CHECK_EQUAL(k, SvcParam::ipv4hint);
+
+    k = SvcParam::keyFromString("echconfig");
+    BOOST_CHECK_EQUAL(k, 5);
+    BOOST_CHECK_EQUAL(k, SvcParam::echconfig);
+
+    k = SvcParam::keyFromString("ipv6hint");
+    BOOST_CHECK_EQUAL(k, 6);
+    BOOST_CHECK_EQUAL(k, SvcParam::ipv6hint);
+
+    k = SvcParam::keyFromString("key0");
+    BOOST_CHECK_EQUAL(k, 0);
+    BOOST_CHECK_EQUAL(k, SvcParam::mandatory);
+
+    k = SvcParam::keyFromString("key666");
+    BOOST_CHECK_EQUAL(k, 666);
+
+    BOOST_CHECK_THROW(SvcParam::keyFromString("MANDATORY"), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(test_SvcParam_keyToString) {
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::mandatory), "mandatory");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::alpn), "alpn");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::no_default_alpn), "no-default-alpn");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::port), "port");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::ipv4hint), "ipv4hint");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::echconfig), "echconfig");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::ipv6hint), "ipv6hint");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::SvcParamKey(7)), "key7");
+    BOOST_CHECK_EQUAL(SvcParam::keyToString(SvcParam::SvcParamKey(666)), "key666");
+}
+
+BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_no_value) {
+    BOOST_CHECK_NO_THROW(SvcParam(SvcParam::no_default_alpn));
+    BOOST_CHECK_THROW(SvcParam(SvcParam::alpn), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::keyFromString("key666")), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_value) {
+    string val = "foobar";
+    auto base64val = Base64Encode(val);
+    SvcParam param;
+
+    BOOST_CHECK_THROW(SvcParam(SvcParam::mandatory, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::alpn, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::no_default_alpn, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::port, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, val), std::invalid_argument);
+
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::echconfig, base64val));
+    BOOST_CHECK_EQUAL(param.getEchConfig(), base64val);
+    BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
+
+    // TODO test bad base64 value
+    // BOOST_CHECK_THROW(SvcParam(SvcParam::echconfig, val), std::invalid_argument);
+
+    // Any string is allowed.....
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("key666"), base64val));
+    BOOST_CHECK_EQUAL(param.getValue(), base64val);
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("key666"), val));
+    BOOST_CHECK_EQUAL(param.getValue(), val);
+
+    BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_set_string_value) {
+    set<string> val({"foo", "bar", "baz"});
+
+    BOOST_CHECK_THROW(SvcParam(SvcParam::no_default_alpn, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::port, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::echconfig, val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, val), std::invalid_argument);
+
+    SvcParam param;
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("mandatory"), val)); // TODO this will fail once we start checking the contents
+
+    auto retval = param.getMandatory();
+    BOOST_CHECK_EQUAL_COLLECTIONS(retval.begin(), retval.end(), val.begin(), val.end());
+    BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+
+    retval.clear();
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::keyFromString("alpn"), val));
+    retval = param.getALPN();
+    BOOST_CHECK_EQUAL_COLLECTIONS(retval.begin(), retval.end(), val.begin(), val.end());
+    BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_set_comboaddress_value) {
+    ComboAddress ca1("192.0.2.1");
+    ComboAddress ca2("192.0.2.2");
+    ComboAddress ca3("2001:db8::1");
+    ComboAddress ca4("2001:db8::2");
+
+    set<ComboAddress> mixedVal({ca1, ca3});
+    set<ComboAddress> v4Val({ca1, ca2});
+    set<ComboAddress> v6Val({ca3, ca4});
+
+    BOOST_CHECK_THROW(SvcParam(SvcParam::mandatory, v4Val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::alpn, v4Val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::no_default_alpn, v4Val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::port, v4Val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::echconfig, v4Val), std::invalid_argument);
+
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, v4Val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, v6Val), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, mixedVal), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, mixedVal), std::invalid_argument);
+
+    SvcParam param;
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::ipv4hint, v4Val));
+
+    auto retval = param.getIPHints();
+    BOOST_CHECK(retval == v4Val);
+    BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::ipv6hint, v6Val));
+    retval.clear();
+    retval = param.getIPHints();
+    BOOST_CHECK(retval == v6Val);
+    BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getPort(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_uint16_value) {
+    uint16_t port(53);
+
+    BOOST_CHECK_THROW(SvcParam(SvcParam::mandatory, port), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::alpn, port), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::no_default_alpn, port), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv4hint, port), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::echconfig, port), std::invalid_argument);
+    BOOST_CHECK_THROW(SvcParam(SvcParam::ipv6hint, port), std::invalid_argument);
+
+    SvcParam param;
+    BOOST_CHECK_NO_THROW(param = SvcParam(SvcParam::port, port));
+    BOOST_CHECK_EQUAL(param.getPort(), port);
+    BOOST_CHECK_THROW(param.getMandatory(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getALPN(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getEchConfig(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getIPHints(), std::invalid_argument);
+    BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file