]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
chore(SVCB): Add comparison operators
authorPieter Lexis <pieter.lexis@powerdns.com>
Wed, 7 Jan 2026 10:17:59 +0000 (11:17 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Thu, 8 Jan 2026 10:04:34 +0000 (11:04 +0100)
pdns/svc-records.cc
pdns/svc-records.hh
pdns/test-svc_records_cc.cc

index 12819860f7640c4e702817f0448584baa5a3d9ed..d2127bca3466fe00cb7119a87323192d0244750c 100644 (file)
@@ -153,6 +153,38 @@ bool SvcParam::operator<(const SvcParam& other) const {
   return this->d_key < other.getKey();
 }
 
+bool SvcParam::operator==(const SvcParam& other) const {
+  if (this->getKey() != other.getKey()) {
+    return false;
+  }
+  switch (this->d_key) {
+    case SvcParamKey::mandatory:
+      return this->getMandatory() == other.getMandatory();
+    case SvcParamKey::alpn:
+      return this->getALPN() == other.getALPN();
+    case SvcParamKey::no_default_alpn: /* fallthrough */
+    case SvcParamKey::ohttp:
+      return true;
+    case SvcParamKey::port:
+      return this->getPort() == other.getPort();
+    case SvcParamKey::ipv4hint: /* fallthrough */
+    case SvcParamKey::ipv6hint:
+      return (this->getIPHints() == other.getIPHints() && this->getAutoHint() == other.getAutoHint());
+    case SvcParamKey::ech:
+      return this->getECH() == other.getECH();
+    case SvcParamKey::dohpath:
+      return this->getValue() == other.getValue();
+    case SvcParamKey::tls_supported_groups:
+      return this->getTLSSupportedGroups() == other.getTLSSupportedGroups();
+    default:
+      return this->getValue() == other.getValue();
+  }
+}
+
+bool SvcParam::operator!=(const SvcParam& other) const {
+  return !(*this == other);
+}
+
 const std::vector<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) + "'");
index a46547ccfa17810c348ed511793b2bf2aac1fb24..15ea26e55d2aee9e9fe6d52a847b8b1c52cf4110 100644 (file)
@@ -82,6 +82,10 @@ class SvcParam {
 
   bool operator< (const SvcParam &other) const;
 
+  bool operator==(const SvcParam &other) const;
+
+  bool operator!=(const SvcParam &other) const;
+
   bool operator==(const SvcParamKey& key) const
   {
     return key == d_key;
index a7440f1a4a074d152c83de9c036cb9cbbde861b1..815b658110a89195ec2d5bb5f423d34dc16d850e 100644 (file)
@@ -8,9 +8,9 @@
 #include "config.h"
 #endif
 #include <boost/test/unit_test.hpp>
-#include <bitset>
 #include "svc-records.hh"
 #include "base64.hh"
+#include "iputils.hh"
 
 using namespace boost;
 
@@ -285,4 +285,147 @@ BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_vector_uint16_value) {
     BOOST_CHECK_THROW(param.getValue(), std::invalid_argument);
 }
 
+BOOST_AUTO_TEST_CASE(test_SvcParam_comparison) {
+    // Test the SvcParam::operator== and operator!= behaviour
+
+    {
+        std::set<SvcParam::SvcParamKey> set1{SvcParam::ech};
+        std::set<SvcParam::SvcParamKey> same_as_set1 = set1;
+        std::set<SvcParam::SvcParamKey> set2{SvcParam::alpn};
+
+        SvcParam mandatory(SvcParam::SvcParamKey::mandatory, std::move(set1));
+        SvcParam mandatory2(SvcParam::SvcParamKey::mandatory, std::move(same_as_set1));
+        SvcParam mandatory3(SvcParam::SvcParamKey::mandatory, std::move(set2));
+
+        BOOST_CHECK(mandatory == mandatory2);
+        BOOST_CHECK(mandatory != mandatory3);
+        BOOST_CHECK(mandatory2 != mandatory3);
+    }
+
+    {
+        std::vector<std::string> first{"h2", "h3"};
+        std::vector<std::string> same_as_first = first;
+        std::vector<std::string> different{"h3", "h2"};
+
+        SvcParam alpn(SvcParam::SvcParamKey::alpn, std::move(first));
+        SvcParam alpn2(SvcParam::SvcParamKey::alpn, std::move(same_as_first));
+        SvcParam alpn3(SvcParam::SvcParamKey::alpn, std::move(different));
+
+        BOOST_CHECK(alpn == alpn2);
+        BOOST_CHECK(alpn != alpn3);
+        BOOST_CHECK(alpn2 != alpn3);
+    }
+
+    {
+        // ohttps uses the same logic
+        SvcParam nda(SvcParam::SvcParamKey::no_default_alpn);
+        SvcParam nda2(SvcParam::SvcParamKey::no_default_alpn);
+
+        BOOST_CHECK(nda == nda2);
+    }
+
+    {
+        uint16_t port = 1337;
+        uint16_t other_port = 1338;
+        SvcParam param1(SvcParam::SvcParamKey::port, port);
+        SvcParam param2(SvcParam::SvcParamKey::port, port);
+        SvcParam param3(SvcParam::SvcParamKey::port, other_port);
+
+        BOOST_CHECK(param1 == param1);
+        BOOST_CHECK(param1 != param3);
+        BOOST_CHECK(param2 != param3);
+    }
+
+    {
+        // Uses the same logic as ipv6hint
+        ComboAddress ca1{"192.0.2.1"};
+        ComboAddress ca2{"192.0.2.2"};
+        ComboAddress ca3{"192.0.2.3"};
+
+        std::vector<ComboAddress> first{ca1};
+        auto same_as_first = first;
+
+        std::vector<ComboAddress> different_order{ca1, ca2};
+        std::vector<ComboAddress> different_order2{ca2, ca1};
+
+        std::vector<ComboAddress> all{ca1, ca2, ca3};
+
+        SvcParam param1(SvcParam::SvcParamKey::ipv4hint, std::move(first));
+        SvcParam param2(SvcParam::SvcParamKey::ipv4hint, std::move(same_as_first));
+
+        SvcParam param3(SvcParam::SvcParamKey::ipv4hint, std::move(different_order));
+        SvcParam param4(SvcParam::SvcParamKey::ipv4hint, std::move(different_order2));
+
+        SvcParam param5(SvcParam::SvcParamKey::ipv4hint, std::move(all));
+
+        BOOST_CHECK(param1 == param2);
+
+        BOOST_CHECK(param2 != param3);
+        BOOST_CHECK(param2 != param4);
+        BOOST_CHECK(param2 != param5);
+
+        BOOST_CHECK(param3 != param4);
+        BOOST_CHECK(param3 != param5);
+
+        BOOST_CHECK(param4 != param5);
+    }
+
+    {
+        std::string first{"somefakeechvalue"};
+        std::string same_as_first = first;
+        std::string different{"someotherfakeechvalue"};
+
+        SvcParam ech(SvcParam::SvcParamKey::ech, std::move(first));
+        SvcParam ech2(SvcParam::SvcParamKey::ech, std::move(same_as_first));
+        SvcParam ech3(SvcParam::SvcParamKey::ech, std::move(different));
+
+        BOOST_CHECK(ech == ech2);
+        BOOST_CHECK(ech != ech3);
+        BOOST_CHECK(ech2 != ech3);
+    }
+
+    {
+        std::string first{"/foo"};
+        std::string same_as_first = first;
+        std::string different{"/bar"};
+
+        SvcParam dohpath(SvcParam::SvcParamKey::dohpath, std::move(first));
+        SvcParam dohpath2(SvcParam::SvcParamKey::dohpath, std::move(same_as_first));
+        SvcParam dohpath3(SvcParam::SvcParamKey::dohpath, std::move(different));
+
+        BOOST_CHECK(dohpath == dohpath2);
+        BOOST_CHECK(dohpath != dohpath3);
+        BOOST_CHECK(dohpath2 != dohpath3);
+    }
+
+    {
+        std::vector<uint16_t> first{0, 1, 2};
+        std::vector<uint16_t> same_as_first = first;
+        std::vector<uint16_t> different{2, 3};
+
+        SvcParam tls_supported_groups(SvcParam::SvcParamKey::tls_supported_groups, std::move(first));
+        SvcParam tls_supported_groups2(SvcParam::SvcParamKey::tls_supported_groups, std::move(same_as_first));
+        SvcParam tls_supported_groups3(SvcParam::SvcParamKey::tls_supported_groups, std::move(different));
+
+        BOOST_CHECK(tls_supported_groups == tls_supported_groups2);
+        BOOST_CHECK(tls_supported_groups != tls_supported_groups3);
+        BOOST_CHECK(tls_supported_groups2 != tls_supported_groups3);
+    }
+
+    {
+        std::string first{"somegenericvalue"};
+        std::string same_as_first = first;
+        std::string different{"anothergenericvalue"};
+        auto key = "key6666";
+
+        SvcParam generic(SvcParam::keyFromString(key), std::move(first));
+        SvcParam generic2(SvcParam::keyFromString(key), std::move(same_as_first));
+        SvcParam generic3(SvcParam::keyFromString(key), std::move(different));
+
+        BOOST_CHECK(generic == generic2);
+        BOOST_CHECK(generic != generic3);
+        BOOST_CHECK(generic2 != generic3);
+    }
+}
+
 BOOST_AUTO_TEST_SUITE_END()