You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by dr...@apache.org on 2017/08/07 22:05:03 UTC

[trafficserver] branch master updated: Test: IpMap update More tests from Larry. conversion to Catch unit test framework.

This is an automated email from the ASF dual-hosted git repository.

dragon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 79a4045  Test: IpMap update More tests from Larry. conversion to Catch unit test framework.
79a4045 is described below

commit 79a4045749dcaf4a8bcd68a77e3736229f8eb7f0
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Sat Jul 8 20:53:37 2017 -0500

    Test: IpMap update
    More tests from Larry.
    conversion to Catch unit test framework.
---
 configure.ac                    |   1 +
 lib/ts/IpMapTest.cc             | 283 -------------------
 lib/ts/Makefile.am              |   3 +-
 lib/ts/unit-tests/test_IpMap.cc | 606 ++++++++++++++++++++++++++++++++++++++++
 tests/unit_tests/Makefile.am    |  24 ++
 5 files changed, 633 insertions(+), 284 deletions(-)

diff --git a/configure.ac b/configure.ac
index 33ccce8..a564034 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1971,6 +1971,7 @@ AC_CONFIG_FILES([
   tools/Makefile
   tools/trafficserver.pc
   tools/tsxs
+  tests/unit_tests/Makefile
 ])
 
 # -----------------------------------------------------------------------------
diff --git a/lib/ts/IpMapTest.cc b/lib/ts/IpMapTest.cc
deleted file mode 100644
index 948ecd2..0000000
--- a/lib/ts/IpMapTest.cc
+++ /dev/null
@@ -1,283 +0,0 @@
-/** @file
-
-    A brief file description
-
-    @section license License
-
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you 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.
-*/
-
-#include <ts/IpMap.h>
-#include <ts/TestBox.h>
-
-void
-IpMapTestPrint(IpMap &map)
-{
-  printf("IpMap Dump\n");
-  for (IpMap::iterator spot(map.begin()), limit(map.end()); spot != limit; ++spot) {
-    ip_text_buffer ipb1, ipb2;
-
-    printf("%s - %s : %p\n", ats_ip_ntop(spot->min(), ipb1, sizeof ipb1), ats_ip_ntop(spot->max(), ipb2, sizeof(ipb2)),
-           spot->data());
-  }
-  printf("\n");
-}
-
-REGRESSION_TEST(IpMap_Basic)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
-{
-  TestBox tb(t, pstatus);
-
-  IpMap map;
-  void *const markA = reinterpret_cast<void *>(1);
-  void *const markB = reinterpret_cast<void *>(2);
-  void *const markC = reinterpret_cast<void *>(3);
-  void *mark; // for retrieval
-
-  in_addr_t ip5 = htonl(5), ip9 = htonl(9);
-  in_addr_t ip10 = htonl(10), ip15 = htonl(15), ip20 = htonl(20);
-  in_addr_t ip50 = htonl(50), ip60 = htonl(60);
-  in_addr_t ip100 = htonl(100), ip120 = htonl(120), ip140 = htonl(140);
-  in_addr_t ip150 = htonl(150), ip160 = htonl(160);
-  in_addr_t ip200 = htonl(200);
-  in_addr_t ip0   = 0;
-  in_addr_t ipmax = ~static_cast<in_addr_t>(0);
-
-  *pstatus = REGRESSION_TEST_PASSED;
-
-  map.mark(ip10, ip20, markA);
-  map.mark(ip5, ip9, markA);
-  tb.check(map.getCount() == 1, "Coalesce failed");
-  tb.check(map.contains(ip9), "Range max not found.");
-  tb.check(map.contains(ip10, &mark), "Span min not found.");
-  tb.check(mark == markA, "Mark not preserved.");
-
-  map.fill(ip15, ip100, markB);
-  tb.check(map.getCount() == 2, "Fill failed.");
-  tb.check(map.contains(ip50, &mark), "Fill interior missing.");
-  tb.check(mark == markB, "Fill mark not preserved.");
-  tb.check(!map.contains(ip200), "Span min not found.");
-  tb.check(map.contains(ip15, &mark), "Old span interior not found.");
-  tb.check(mark == markA, "Fill overwrote mark.");
-
-  map.clear();
-  tb.check(map.getCount() == 0, "Clear failed.");
-
-  map.mark(ip20, ip50, markA);
-  map.mark(ip100, ip150, markB);
-  map.fill(ip10, ip200, markC);
-  tb.check(map.getCount() == 5, "Test 3 failed [expected 5, got %d].", map.getCount());
-  tb.check(map.contains(ip15, &mark), "Test 3 - left span missing.");
-  tb.check(map.contains(ip60, &mark), "Test 3 - middle span missing.");
-  tb.check(mark == markC, "Test 3 - fill mark wrong.");
-  tb.check(map.contains(ip160), "Test 3 - right span missing.");
-  tb.check(map.contains(ip120, &mark), "Test 3 - right mark span missing.");
-  tb.check(mark == markB, "Test 3 - wrong data on right mark span.");
-  map.unmark(ip140, ip160);
-  tb.check(map.getCount() == 5, "Test 3 unmark failed [expected 5, got %d].", map.getCount());
-  tb.check(!map.contains(ip140), "Test 3 - unmark left edge still there.");
-  tb.check(!map.contains(ip150), "Test 3 - unmark middle still there.");
-  tb.check(!map.contains(ip160), "Test 3 - unmark right edge still there.");
-
-  map.clear();
-  map.mark(ip20, ip20, markA);
-  tb.check(map.contains(ip20), "Map failed on singleton insert");
-  map.mark(ip10, ip200, markB);
-  mark = 0;
-  map.contains(ip20, &mark);
-  tb.check(mark == markB, "Map held singleton against range.");
-  map.mark(ip100, ip120, markA);
-  map.mark(ip150, ip160, markB);
-  map.mark(ip0, ipmax, markC);
-  tb.check(map.getCount() == 1, "IpMap: Full range fill left extra ranges.");
-}
-
-REGRESSION_TEST(IpMap_Unmark)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
-{
-  TestBox tb(t, pstatus);
-  IpMap map;
-  //  ip_text_buffer ipb1, ipb2;
-  void *const markA = reinterpret_cast<void *>(1);
-
-  IpEndpoint a_0, a_0_0_0_16, a_0_0_0_17, a_max;
-  IpEndpoint a_10_28_56_0, a_10_28_56_4, a_10_28_56_255;
-  IpEndpoint a_10_28_55_255, a_10_28_57_0;
-  IpEndpoint a_63_128_1_12;
-  IpEndpoint a_loopback, a_loopback2;
-  IpEndpoint a6_0, a6_max, a6_fe80_9d90, a6_fe80_9d9d, a6_fe80_9d95;
-
-  ats_ip_pton("0.0.0.0", &a_0);
-  ats_ip_pton("0.0.0.16", &a_0_0_0_16);
-  ats_ip_pton("0.0.0.17", &a_0_0_0_17);
-  ats_ip_pton("255.255.255.255", &a_max);
-  ats_ip_pton("10.28.55.255", &a_10_28_55_255);
-  ats_ip_pton("10.28.56.0", &a_10_28_56_0);
-  ats_ip_pton("10.28.56.4", &a_10_28_56_4);
-  ats_ip_pton("10.28.56.255", &a_10_28_56_255);
-  ats_ip_pton("10.28.57.0", &a_10_28_57_0);
-  ats_ip_pton("63.128.1.12", &a_63_128_1_12);
-  ats_ip_pton("::", &a6_0);
-  ats_ip_pton("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &a6_max);
-  ats_ip_pton("fe80::221:9bff:fe10:9d90", &a6_fe80_9d90);
-  ats_ip_pton("fe80::221:9bff:fe10:9d9d", &a6_fe80_9d9d);
-  ats_ip_pton("fe80::221:9bff:fe10:9d95", &a6_fe80_9d95);
-  ats_ip_pton("127.0.0.1", &a_loopback);
-  ats_ip_pton("127.0.0.255", &a_loopback2);
-  *pstatus = REGRESSION_TEST_PASSED;
-
-  map.mark(&a_0, &a_max, markA);
-  tb.check(map.getCount() == 1, "IpMap Unmark: Full range not single.");
-  map.unmark(&a_10_28_56_0, &a_10_28_56_255);
-  tb.check(map.getCount() == 2, "IpMap Unmark: Range unmark failed.");
-  // Generic range check.
-  tb.check(!map.contains(&a_10_28_56_0), "IpMap Unmark: Range unmark min address not removed.");
-  tb.check(!map.contains(&a_10_28_56_255), "IpMap Unmark: Range unmark max address not removed.");
-  tb.check(map.contains(&a_10_28_55_255), "IpMap Unmark: Range unmark min-1 address removed.");
-  tb.check(map.contains(&a_10_28_57_0), "IpMap Unmark: Range unmark max+1 address removed.");
-  // Test min bounded range.
-  map.unmark(&a_0, &a_0_0_0_16);
-  tb.check(!map.contains(&a_0), "IpMap Unmark: Range unmark zero address not removed.");
-  tb.check(!map.contains(&a_0_0_0_16), "IpMap Unmark: Range unmark zero bounded range max not removed.");
-  tb.check(map.contains(&a_0_0_0_17), "IpMap Unmark: Range unmark zero bounded range max+1 removed.");
-}
-
-REGRESSION_TEST(IpMap_Fill)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
-{
-  TestBox tb(t, pstatus);
-  IpMap map;
-  ip_text_buffer ipb1, ipb2;
-  void *const allow = reinterpret_cast<void *>(0);
-  void *const deny  = reinterpret_cast<void *>(~0);
-  void *const markA = reinterpret_cast<void *>(1);
-  void *const markB = reinterpret_cast<void *>(2);
-  void *const markC = reinterpret_cast<void *>(3);
-  void *mark; // for retrieval
-
-  IpEndpoint a0, a_10_28_56_0, a_10_28_56_255, a3, a4;
-  IpEndpoint a_9_255_255_255, a_10_0_0_0, a_10_0_0_19, a_10_0_0_255, a_10_0_1_0;
-  IpEndpoint a_10_28_56_4, a_max, a_loopback, a_loopback2;
-  IpEndpoint a_10_28_55_255, a_10_28_57_0;
-  IpEndpoint a_63_128_1_12;
-  IpEndpoint a_0000_0000, a_0000_0001, a_ffff_ffff;
-  IpEndpoint a_fe80_9d8f, a_fe80_9d90, a_fe80_9d95, a_fe80_9d9d, a_fe80_9d9e;
-
-  *pstatus = REGRESSION_TEST_PASSED;
-
-  ats_ip_pton("0.0.0.0", &a0);
-  ats_ip_pton("255.255.255.255", &a_max);
-
-  ats_ip_pton("9.255.255.255", &a_9_255_255_255);
-  ats_ip_pton("10.0.0.0", &a_10_0_0_0);
-  ats_ip_pton("10.0.0.19", &a_10_0_0_19);
-  ats_ip_pton("10.0.0.255", &a_10_0_0_255);
-  ats_ip_pton("10.0.1.0", &a_10_0_1_0);
-
-  ats_ip_pton("10.28.55.255", &a_10_28_55_255);
-  ats_ip_pton("10.28.56.0", &a_10_28_56_0);
-  ats_ip_pton("10.28.56.4", &a_10_28_56_4);
-  ats_ip_pton("10.28.56.255", &a_10_28_56_255);
-  ats_ip_pton("10.28.57.0", &a_10_28_57_0);
-
-  ats_ip_pton("192.168.1.0", &a3);
-  ats_ip_pton("192.168.1.255", &a4);
-
-  ats_ip_pton("::", &a_0000_0000);
-  ats_ip_pton("::1", &a_0000_0001);
-  ats_ip_pton("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &a_ffff_ffff);
-  ats_ip_pton("fe80::221:9bff:fe10:9d8f", &a_fe80_9d8f);
-  ats_ip_pton("fe80::221:9bff:fe10:9d90", &a_fe80_9d90);
-  ats_ip_pton("fe80::221:9bff:fe10:9d95", &a_fe80_9d95);
-  ats_ip_pton("fe80::221:9bff:fe10:9d9d", &a_fe80_9d9d);
-  ats_ip_pton("fe80::221:9bff:fe10:9d9e", &a_fe80_9d9e);
-
-  ats_ip_pton("127.0.0.0", &a_loopback);
-  ats_ip_pton("127.0.0.255", &a_loopback2);
-  ats_ip_pton("63.128.1.12", &a_63_128_1_12);
-
-  map.fill(&a_10_28_56_0, &a_10_28_56_255, deny);
-  map.fill(&a0, &a_max, allow);
-
-  tb.check(map.contains(&a_10_28_56_4, &mark), "IpMap Fill: Target not found.");
-  tb.check(mark == deny, "IpMap Fill: Expected deny, got allow at %s.", ats_ip_ntop(&a_10_28_56_4, ipb1, sizeof(ipb1)));
-
-  map.clear();
-  map.fill(&a_loopback, &a_loopback, allow);
-  tb.check(map.contains(&a_loopback), "IpMap fill: singleton not marked.");
-  map.fill(&a0, &a_max, deny);
-
-  mark = 0;
-  tb.check(map.contains(&a_loopback, &mark), "IpMap fill: singleton marking lost.");
-  tb.check(mark == allow, "IpMap fill: overwrote existing singleton mark.");
-  if (tb.check(map.begin() != map.end(), "IpMap fill: map is empty.")) {
-    if (tb.check(++(map.begin()) != map.end(), "IpMap fill: only one range.")) {
-      tb.check(-1 == ats_ip_addr_cmp(map.begin()->max(), (++map.begin())->min()), "IpMap fill: ranges not disjoint [%s < %s].",
-               ats_ip_ntop(map.begin()->max(), ipb1, sizeof(ipb1)), ats_ip_ntop((++map.begin())->min(), ipb2, sizeof(ipb2)));
-    }
-  }
-
-  map.clear();
-  map.fill(&a_loopback, &a_loopback2, markA);
-  map.fill(&a_10_28_56_0, &a_10_28_56_255, markB);
-  tb.check(!map.contains(&a_63_128_1_12, &mark), "IpMap fill[2]: over extended range.");
-  map.fill(&a0, &a_max, markC);
-  tb.check(map.getCount() == 5, "IpMap[2]: Fill failed.");
-  if (tb.check(map.contains(&a_63_128_1_12, &mark), "IpMap fill[2]: Collapsed range.")) {
-    tb.check(mark == markC, "IpMap fill[2]: invalid mark for range gap.");
-  }
-
-  map.clear();
-  map.fill(&a_10_0_0_0, &a_10_0_0_255, allow);
-  map.fill(&a_loopback, &a_loopback2, allow);
-  tb.check(!map.contains(&a_63_128_1_12, &mark), "IpMap fill[3]: invalid mark between ranges.");
-  tb.check(map.contains(&a_10_0_0_19, &mark) && mark == allow, "IpMap fill[3]: invalid mark in lower range.");
-  map.fill(&a0, &a_max, deny);
-  if (!tb.check(map.getCount() == 5, "IpMap[3]: Wrong number of ranges."))
-    IpMapTestPrint(map);
-  if (tb.check(map.contains(&a_63_128_1_12, &mark), "IpMap fill[3]: Missing mark between ranges")) {
-    tb.check(mark == deny, "IpMap fill[3]: gap range invalidly marked");
-  }
-
-  map.fill(&a_fe80_9d90, &a_fe80_9d9d, markA);
-  map.fill(&a_0000_0001, &a_0000_0001, markA);
-  map.fill(&a_0000_0000, &a_ffff_ffff, markB);
-
-  tb.check(map.contains(&a_0000_0000, &mark) && mark == markB, "IpMap Fill[v6]: Zero address has bad mark.");
-  tb.check(map.contains(&a_ffff_ffff, &mark) && mark == markB, "IpMap Fill[v6]: Max address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d90, &mark) && mark == markA, "IpMap Fill[v6]: 9d90 address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d8f, &mark) && mark == markB, "IpMap Fill[v6]: 9d8f address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d9d, &mark) && mark == markA, "IpMap Fill[v6]: 9d9d address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d9e, &mark) && mark == markB, "IpMap Fill[v6]: 9d9b address has bad mark.");
-  tb.check(map.contains(&a_0000_0001, &mark) && mark == markA, "IpMap Fill[v6]: ::1 has bad mark.");
-
-  tb.check(map.getCount() == 10, "IpMap Fill[pre-refill]: Bad range count.");
-  // These should be ignored by the map as it is completely covered for IPv6.
-  map.fill(&a_fe80_9d90, &a_fe80_9d9d, markA);
-  map.fill(&a_0000_0001, &a_0000_0001, markC);
-  map.fill(&a_0000_0000, &a_ffff_ffff, markB);
-  tb.check(map.getCount() == 10, "IpMap Fill[post-refill]: Bad range count.");
-
-  map.clear();
-  map.fill(&a_fe80_9d90, &a_fe80_9d9d, markA);
-  map.fill(&a_0000_0001, &a_0000_0001, markC);
-  map.fill(&a_0000_0000, &a_ffff_ffff, markB);
-  tb.check(map.contains(&a_0000_0000, &mark) && mark == markB, "IpMap Fill[v6-2]: Zero address has bad mark.");
-  tb.check(map.contains(&a_ffff_ffff, &mark) && mark == markB, "IpMap Fill[v6-2]: Max address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d90, &mark) && mark == markA, "IpMap Fill[v6-2]: 9d90 address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d8f, &mark) && mark == markB, "IpMap Fill[v6-2]: 9d8f address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d9d, &mark) && mark == markA, "IpMap Fill[v6-2]: 9d9d address has bad mark.");
-  tb.check(map.contains(&a_fe80_9d9e, &mark) && mark == markB, "IpMap Fill[v6-2]: 9d9b address has bad mark.");
-  tb.check(map.contains(&a_0000_0001, &mark) && mark == markC, "IpMap Fill[v6-2]: ::1 has bad mark.");
-}
diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
index 737dbfe..2b9b7e2 100644
--- a/lib/ts/Makefile.am
+++ b/lib/ts/Makefile.am
@@ -252,7 +252,8 @@ test_tslib_CPPFLAGS = $(AM_CPPFLAGS)\
 test_tslib_LDADD = libtsutil.la
 test_tslib_SOURCES = \
 	unit-tests/main.cpp \
-	unit-tests/string_view.cpp
+	unit-tests/string_view.cpp \
+	unit-tests/test_IpMap.cc 
 
 CompileParseRules_SOURCES = CompileParseRules.cc
 
diff --git a/lib/ts/unit-tests/test_IpMap.cc b/lib/ts/unit-tests/test_IpMap.cc
new file mode 100644
index 0000000..3ffd66c
--- /dev/null
+++ b/lib/ts/unit-tests/test_IpMap.cc
@@ -0,0 +1,606 @@
+/** @file
+
+    IpMap unit tests.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+*/
+
+#include <ts/IpMap.h>
+#include <catch.hpp>
+
+std::ostream &
+operator<<(std::ostream &s, IpEndpoint const &addr)
+{
+  ip_text_buffer b;
+  ats_ip_ntop(addr, b, sizeof(b));
+  s << b;
+  return s;
+}
+
+void
+IpMapTestPrint(IpMap &map)
+{
+  printf("IpMap Dump\n");
+  for (IpMap::iterator spot(map.begin()), limit(map.end()); spot != limit; ++spot) {
+    ip_text_buffer ipb1, ipb2;
+
+    printf("%s - %s : %p\n", ats_ip_ntop(spot->min(), ipb1, sizeof ipb1), ats_ip_ntop(spot->max(), ipb2, sizeof(ipb2)),
+           spot->data());
+  }
+  printf("\n");
+}
+
+// --- Test helper classes ---
+class MapMarkedAt : public Catch::MatcherBase<IpMap>
+{
+  IpEndpoint const &_addr;
+
+public:
+  MapMarkedAt(IpEndpoint const &addr) : _addr(addr) {}
+
+  virtual bool
+  match(IpMap const &map) const override
+  {
+    return map.contains(&_addr);
+  }
+
+  virtual std::string
+  describe() const override
+  {
+    std::ostringstream ss;
+    ss << _addr << " is marked";
+    return ss.str();
+  }
+};
+
+// The builder function
+inline MapMarkedAt
+IsMarkedAt(IpEndpoint const &_addr)
+{
+  return {_addr};
+}
+
+class MapMarkedWith : public Catch::MatcherBase<IpMap>
+{
+  IpEndpoint const &_addr;
+  void *_mark;
+  mutable bool _found_p = false;
+
+public:
+  MapMarkedWith(IpEndpoint const &addr, void *mark) : _addr(addr), _mark(mark) {}
+
+  virtual bool
+  match(IpMap const &map) const override
+  {
+    void *mark = nullptr;
+    return (_found_p = map.contains(&_addr, &mark)) && mark == _mark;
+  }
+
+  virtual std::string
+  describe() const override
+  {
+    std::ostringstream ss;
+    if (_found_p) {
+      ss << "is marked at " << _addr << " with " << std::hex << reinterpret_cast<intptr_t>(_mark);
+    } else {
+      ss << "is not marked at " << _addr;
+    }
+    return ss.str();
+  }
+};
+
+inline MapMarkedWith
+IsMarkedWith(IpEndpoint const &addr, void *mark)
+{
+  return {addr, mark};
+}
+
+// -------------
+// --- TESTS ---
+// -------------
+TEST_CASE("IpMap Basic", "[libts][ipmap]")
+{
+  IpMap map;
+  void *const markA = reinterpret_cast<void *>(1);
+  void *const markB = reinterpret_cast<void *>(2);
+  void *const markC = reinterpret_cast<void *>(3);
+  void *mark; // for retrieval
+
+  in_addr_t ip5 = htonl(5), ip9 = htonl(9);
+  in_addr_t ip10 = htonl(10), ip15 = htonl(15), ip20 = htonl(20);
+  in_addr_t ip50 = htonl(50), ip60 = htonl(60);
+  in_addr_t ip100 = htonl(100), ip120 = htonl(120), ip140 = htonl(140);
+  in_addr_t ip150 = htonl(150), ip160 = htonl(160);
+  in_addr_t ip200 = htonl(200);
+  in_addr_t ip0   = 0;
+  in_addr_t ipmax = ~static_cast<in_addr_t>(0);
+
+  map.mark(ip10, ip20, markA);
+  map.mark(ip5, ip9, markA);
+  {
+    INFO("Coalesce failed");
+    CHECK(map.getCount() == 1);
+  }
+  {
+    INFO("Range max not found.");
+    CHECK(map.contains(ip9));
+  }
+  {
+    INFO("Span min not found");
+    CHECK(map.contains(ip10, &mark));
+  }
+  {
+    INFO("Mark not preserved.");
+    CHECK(mark == markA);
+  }
+
+  map.fill(ip15, ip100, markB);
+  {
+    INFO("Fill failed.");
+    CHECK(map.getCount() == 2);
+  }
+  {
+    INFO("fill interior missing");
+    CHECK(map.contains(ip50, &mark));
+  }
+  {
+    INFO("Fill mark not preserved.");
+    CHECK(mark == markB);
+  }
+  {
+    INFO("Span min not found.");
+    CHECK(!map.contains(ip200));
+  }
+  {
+    INFO("Old span interior not found");
+    CHECK(map.contains(ip15, &mark));
+  }
+  {
+    INFO("Fill overwrote mark.");
+    CHECK(mark == markA);
+  }
+
+  map.clear();
+  {
+    INFO("Clear failed.");
+    CHECK(map.getCount() == 0);
+  }
+
+  map.mark(ip20, ip50, markA);
+  map.mark(ip100, ip150, markB);
+  map.fill(ip10, ip200, markC);
+  CHECK(map.getCount() == 5);
+  {
+    INFO("Left span missing");
+    CHECK(map.contains(ip15, &mark));
+  }
+  {
+    INFO("Middle span missing");
+    CHECK(map.contains(ip60, &mark));
+  }
+  {
+    INFO("fill mark wrong.");
+    CHECK(mark == markC);
+  }
+  {
+    INFO("right span missing.");
+    CHECK(map.contains(ip160));
+  }
+  {
+    INFO("right span missing");
+    CHECK(map.contains(ip120, &mark));
+  }
+  {
+    INFO("wrong data on right mark span.");
+    CHECK(mark == markB);
+  }
+
+  map.unmark(ip140, ip160);
+  {
+    INFO("unmark failed");
+    CHECK(map.getCount() == 5);
+  }
+  {
+    INFO("unmark left edge still there.");
+    CHECK(!map.contains(ip140));
+  }
+  {
+    INFO("unmark middle still there.");
+    CHECK(!map.contains(ip150));
+  }
+  {
+    INFO("unmark right edge still there.");
+    CHECK(!map.contains(ip160));
+  }
+
+  map.clear();
+  map.mark(ip20, ip20, markA);
+  {
+    INFO("Map failed on singleton insert");
+    CHECK(map.contains(ip20));
+  }
+  map.mark(ip10, ip200, markB);
+  mark = 0;
+  map.contains(ip20, &mark);
+  {
+    INFO("Map held singleton against range.");
+    CHECK(mark == markB);
+  }
+  map.mark(ip100, ip120, markA);
+  map.mark(ip150, ip160, markB);
+  map.mark(ip0, ipmax, markC);
+  {
+    INFO("IpMap: Full range fill left extra ranges.");
+    CHECK(map.getCount() == 1);
+  }
+}
+
+TEST_CASE("IpMap Unmark", "[libts][ipmap]")
+{
+  IpMap map;
+  //  ip_text_buffer ipb1, ipb2;
+  void *const markA = reinterpret_cast<void *>(1);
+
+  IpEndpoint a_0, a_0_0_0_16, a_0_0_0_17, a_max;
+  IpEndpoint a_10_28_56_0, a_10_28_56_4, a_10_28_56_255;
+  IpEndpoint a_10_28_55_255, a_10_28_57_0;
+  IpEndpoint a_63_128_1_12;
+  IpEndpoint a_loopback, a_loopback2;
+  IpEndpoint a6_0, a6_max, a6_fe80_9d90, a6_fe80_9d9d, a6_fe80_9d95;
+
+  ats_ip_pton("0.0.0.0", &a_0);
+  ats_ip_pton("0.0.0.16", &a_0_0_0_16);
+  ats_ip_pton("0.0.0.17", &a_0_0_0_17);
+  ats_ip_pton("255.255.255.255", &a_max);
+  ats_ip_pton("10.28.55.255", &a_10_28_55_255);
+  ats_ip_pton("10.28.56.0", &a_10_28_56_0);
+  ats_ip_pton("10.28.56.4", &a_10_28_56_4);
+  ats_ip_pton("10.28.56.255", &a_10_28_56_255);
+  ats_ip_pton("10.28.57.0", &a_10_28_57_0);
+  ats_ip_pton("63.128.1.12", &a_63_128_1_12);
+  ats_ip_pton("::", &a6_0);
+  ats_ip_pton("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &a6_max);
+  ats_ip_pton("fe80::221:9bff:fe10:9d90", &a6_fe80_9d90);
+  ats_ip_pton("fe80::221:9bff:fe10:9d9d", &a6_fe80_9d9d);
+  ats_ip_pton("fe80::221:9bff:fe10:9d95", &a6_fe80_9d95);
+  ats_ip_pton("127.0.0.1", &a_loopback);
+  ats_ip_pton("127.0.0.255", &a_loopback2);
+
+  map.mark(&a_0, &a_max, markA);
+  {
+    INFO("IpMap Unmark: Full range not single.");
+    CHECK(map.getCount() == 1);
+  }
+  map.unmark(&a_10_28_56_0, &a_10_28_56_255);
+  {
+    INFO("IpMap Unmark: Range unmark failed.");
+    CHECK(map.getCount() == 2);
+  }
+  // Generic range check.
+  {
+    INFO("IpMap Unmark: Range unmark min address not removed.");
+    CHECK(!map.contains(&a_10_28_56_0));
+  }
+  {
+    INFO("IpMap Unmark: Range unmark max address not removed.");
+    CHECK(!map.contains(&a_10_28_56_255));
+  }
+  {
+    INFO("IpMap Unmark: Range unmark min-1 address removed.");
+    CHECK(map.contains(&a_10_28_55_255));
+  }
+  {
+    INFO("IpMap Unmark: Range unmark max+1 address removed.");
+    CHECK(map.contains(&a_10_28_57_0));
+  }
+  // Test min bounded range.
+  map.unmark(&a_0, &a_0_0_0_16);
+  {
+    INFO("IpMap Unmark: Range unmark zero address not removed.");
+    CHECK(!map.contains(&a_0));
+  }
+  {
+    INFO("IpMap Unmark: Range unmark zero bounded range max not removed.");
+    CHECK(!map.contains(&a_0_0_0_16));
+  }
+  {
+    INFO("IpMap Unmark: Range unmark zero bounded range max+1 removed.");
+    CHECK(map.contains(&a_0_0_0_17));
+  }
+}
+
+TEST_CASE("IpMap Fill", "[libts][ipmap]")
+{
+  IpMap map;
+  void *const allow = reinterpret_cast<void *>(0);
+  void *const deny  = reinterpret_cast<void *>(~0);
+  void *const markA = reinterpret_cast<void *>(1);
+  void *const markB = reinterpret_cast<void *>(2);
+  void *const markC = reinterpret_cast<void *>(3);
+  void *mark; // for retrieval
+
+  IpEndpoint a0, a_10_28_56_0, a_10_28_56_4, a_10_28_56_255, a3, a4;
+  IpEndpoint a_9_255_255_255, a_10_0_0_0, a_10_0_0_19, a_10_0_0_255, a_10_0_1_0;
+  IpEndpoint a_max, a_loopback, a_loopback2;
+  IpEndpoint a_10_28_55_255, a_10_28_57_0;
+  IpEndpoint a_63_128_1_12;
+  IpEndpoint a_0000_0000, a_0000_0001, a_ffff_ffff;
+  IpEndpoint a_fe80_9d8f, a_fe80_9d90, a_fe80_9d95, a_fe80_9d9d, a_fe80_9d9e;
+
+  ats_ip_pton("0.0.0.0", &a0);
+  ats_ip_pton("255.255.255.255", &a_max);
+
+  ats_ip_pton("9.255.255.255", &a_9_255_255_255);
+  ats_ip_pton("10.0.0.0", &a_10_0_0_0);
+  ats_ip_pton("10.0.0.19", &a_10_0_0_19);
+  ats_ip_pton("10.0.0.255", &a_10_0_0_255);
+  ats_ip_pton("10.0.1.0", &a_10_0_1_0);
+
+  ats_ip_pton("10.28.55.255", &a_10_28_55_255);
+  ats_ip_pton("10.28.56.0", &a_10_28_56_0);
+  ats_ip_pton("10.28.56.4", &a_10_28_56_4);
+  ats_ip_pton("10.28.56.255", &a_10_28_56_255);
+  ats_ip_pton("10.28.57.0", &a_10_28_57_0);
+
+  ats_ip_pton("192.168.1.0", &a3);
+  ats_ip_pton("192.168.1.255", &a4);
+
+  ats_ip_pton("::", &a_0000_0000);
+  ats_ip_pton("::1", &a_0000_0001);
+  ats_ip_pton("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", &a_ffff_ffff);
+  ats_ip_pton("fe80::221:9bff:fe10:9d8f", &a_fe80_9d8f);
+  ats_ip_pton("fe80::221:9bff:fe10:9d90", &a_fe80_9d90);
+  ats_ip_pton("fe80::221:9bff:fe10:9d95", &a_fe80_9d95);
+  ats_ip_pton("fe80::221:9bff:fe10:9d9d", &a_fe80_9d9d);
+  ats_ip_pton("fe80::221:9bff:fe10:9d9e", &a_fe80_9d9e);
+
+  ats_ip_pton("127.0.0.0", &a_loopback);
+  ats_ip_pton("127.0.0.255", &a_loopback2);
+  ats_ip_pton("63.128.1.12", &a_63_128_1_12);
+
+  SECTION("subnet overfill")
+  {
+    map.fill(&a_10_28_56_0, &a_10_28_56_255, deny);
+    map.fill(&a0, &a_max, allow);
+    CHECK_THAT(map, IsMarkedWith(a_10_28_56_4, deny));
+  }
+
+  SECTION("singleton overfill")
+  {
+    map.fill(&a_loopback, &a_loopback, allow);
+    {
+      INFO("singleton not marked.");
+      CHECK_THAT(map, IsMarkedAt(a_loopback));
+    }
+    map.fill(&a0, &a_max, deny);
+    THEN("singleton mark")
+    {
+      CHECK_THAT(map, IsMarkedWith(a_loopback, allow));
+      THEN("not empty")
+      {
+        REQUIRE(map.begin() != map.end());
+        IpMap::iterator spot = map.begin();
+        ++spot;
+        THEN("more than one range")
+        {
+          REQUIRE(spot != map.end());
+          THEN("ranges disjoint")
+          {
+            INFO(" " << map.begin()->max() << " < " << spot->min());
+            REQUIRE(-1 == ats_ip_addr_cmp(map.begin()->max(), spot->min()));
+          }
+        }
+      }
+    }
+  }
+
+  SECTION("3")
+  {
+    map.fill(&a_loopback, &a_loopback2, markA);
+    map.fill(&a_10_28_56_0, &a_10_28_56_255, markB);
+    {
+      INFO("over extended range");
+      CHECK_THAT(map, !IsMarkedWith(a_63_128_1_12, markC));
+    }
+    map.fill(&a0, &a_max, markC);
+    {
+      INFO("IpMap[2]: Fill failed.");
+      CHECK(map.getCount() == 5);
+    }
+    {
+      INFO("invalid mark in range gap");
+      CHECK_THAT(map, IsMarkedWith(a_63_128_1_12, markC));
+    }
+  }
+
+  SECTION("4")
+  {
+    map.fill(&a_10_0_0_0, &a_10_0_0_255, allow);
+    map.fill(&a_loopback, &a_loopback2, allow);
+    {
+      INFO("invalid mark between ranges");
+      CHECK_THAT(map, !IsMarkedAt(a_63_128_1_12));
+    }
+    {
+      INFO("invalid mark in lower range");
+      CHECK_THAT(map, IsMarkedWith(a_10_0_0_19, allow));
+    }
+    map.fill(&a0, &a_max, deny);
+    {
+      INFO("range count incorrect");
+      CHECK(map.getCount() == 5);
+    }
+    {
+      INFO("mark between ranges");
+      CHECK_THAT(map, IsMarkedWith(a_63_128_1_12, deny));
+    }
+
+    map.fill(&a_fe80_9d90, &a_fe80_9d9d, markA);
+    map.fill(&a_0000_0001, &a_0000_0001, markA);
+    map.fill(&a_0000_0000, &a_ffff_ffff, markB);
+
+    {
+      INFO("IpMap Fill[v6]: Zero address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_0000_0000, markB));
+    }
+    {
+      INFO("IpMap Fill[v6]: Max address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_ffff_ffff, markB));
+    }
+    {
+      INFO("IpMap Fill[v6]: 9d90 address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d90, markA));
+    }
+    {
+      INFO("IpMap Fill[v6]: 9d8f address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d8f, markB));
+    }
+    {
+      INFO("IpMap Fill[v6]: 9d9d address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d9d, markA));
+    }
+    {
+      INFO("IpMap Fill[v6]: 9d9b address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d9e, markB));
+    }
+    {
+      INFO("IpMap Fill[v6]: ::1 has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_0000_0001, markA));
+    }
+
+    {
+      INFO("IpMap Fill[pre-refill]: Bad range count.");
+      CHECK(map.getCount() == 10);
+    }
+    // These should be ignored by the map as it is completely covered for IPv6.
+    map.fill(&a_fe80_9d90, &a_fe80_9d9d, markA);
+    map.fill(&a_0000_0001, &a_0000_0001, markC);
+    map.fill(&a_0000_0000, &a_ffff_ffff, markB);
+    {
+      INFO("IpMap Fill[post-refill]: Bad range count.");
+      CHECK(map.getCount() == 10);
+    }
+  }
+
+  SECTION("5")
+  {
+    map.fill(&a_fe80_9d90, &a_fe80_9d9d, markA);
+    map.fill(&a_0000_0001, &a_0000_0001, markC);
+    map.fill(&a_0000_0000, &a_ffff_ffff, markB);
+    {
+      INFO("IpMap Fill[v6-2]: Zero address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_0000_0000, markB));
+    }
+    {
+      INFO("IpMap Fill[v6-2]: Max address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_ffff_ffff, markB));
+    }
+    {
+      INFO("IpMap Fill[v6-2]: 9d90 address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d90, markA));
+    }
+    {
+      INFO("IpMap Fill[v6-2]: 9d8f address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d8f, markB));
+    }
+    {
+      INFO("IpMap Fill[v6-2]: 9d9d address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d9d, markA));
+    }
+    {
+      INFO("IpMap Fill[v6-2]: 9d9b address has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_fe80_9d9e, markB));
+    }
+    {
+      INFO("IpMap Fill[v6-2]: ::1 has bad mark.");
+      CHECK_THAT(map, IsMarkedWith(a_0000_0001, markC));
+    }
+  }
+}
+
+TEST_CASE("IpMap CloseIntersection", "[libts][ipmap]")
+{
+  IpMap map;
+  void *const markA = reinterpret_cast<void *>(1);
+  void *const markB = reinterpret_cast<void *>(2);
+  void *const markC = reinterpret_cast<void *>(3);
+  void *const markD = reinterpret_cast<void *>(4);
+  // void *mark; // for retrieval
+
+  IpEndpoint a_1_l, a_1_u, a_2_l, a_2_u, a_3_l, a_3_u, a_4_l, a_4_u, a_5_l, a_5_u, a_6_l, a_6_u, a_7_l, a_7_u;
+  IpEndpoint b_1_l, b_1_u;
+  IpEndpoint c_1_l, c_1_u, c_2_l, c_2_u, c_3_l, c_3_u;
+  IpEndpoint d_1_l, d_1_u, d_2_l, d_2_u;
+
+  IpEndpoint a_1_m;
+
+  ats_ip_pton("123.88.172.0", &a_1_l);
+  ats_ip_pton("123.88.180.93", &a_1_m);
+  ats_ip_pton("123.88.191.255", &a_1_u);
+  ats_ip_pton("123.89.132.0", &a_2_l);
+  ats_ip_pton("123.89.135.255", &a_2_u);
+  ats_ip_pton("123.89.160.0", &a_3_l);
+  ats_ip_pton("123.89.167.255", &a_3_u);
+  ats_ip_pton("123.90.108.0", &a_4_l);
+  ats_ip_pton("123.90.111.255", &a_4_u);
+  ats_ip_pton("123.90.152.0", &a_5_l);
+  ats_ip_pton("123.90.159.255", &a_5_u);
+  ats_ip_pton("123.91.0.0", &a_6_l);
+  ats_ip_pton("123.91.35.255", &a_6_u);
+  ats_ip_pton("123.91.40.0", &a_7_l);
+  ats_ip_pton("123.91.47.255", &a_7_u);
+
+  ats_ip_pton("123.78.100.0", &b_1_l);
+  ats_ip_pton("123.78.115.255", &b_1_u);
+
+  ats_ip_pton("123.88.204.0", &c_1_l);
+  ats_ip_pton("123.88.219.255", &c_1_u);
+  ats_ip_pton("123.90.112.0", &c_2_l);
+  ats_ip_pton("123.90.119.255", &c_2_u);
+  ats_ip_pton("123.90.132.0", &c_3_l);
+  ats_ip_pton("123.90.135.255", &c_3_u);
+
+  ats_ip_pton("123.82.196.0", &d_1_l);
+  ats_ip_pton("123.82.199.255", &d_1_u);
+  ats_ip_pton("123.82.204.0", &d_2_l);
+  ats_ip_pton("123.82.219.255", &d_2_u);
+
+  map.mark(a_1_l, a_1_u, markA);
+  map.mark(a_2_l, a_2_u, markA);
+  map.mark(a_3_l, a_3_u, markA);
+  map.mark(a_4_l, a_4_u, markA);
+  map.mark(a_5_l, a_5_u, markA);
+  map.mark(a_6_l, a_6_u, markA);
+  map.mark(a_7_l, a_7_u, markA);
+  CHECK_THAT(map, IsMarkedAt(a_1_m));
+
+  map.mark(b_1_l, b_1_u, markB);
+  CHECK_THAT(map, IsMarkedAt(a_1_m));
+
+  map.mark(c_1_l, c_1_u, markC);
+  map.mark(c_2_l, c_2_u, markC);
+  map.mark(c_3_l, c_3_u, markC);
+  CHECK_THAT(map, IsMarkedAt(a_1_m));
+
+  map.mark(d_1_l, d_1_u, markD);
+  map.mark(d_2_l, d_2_u, markD);
+  CHECK_THAT(map, IsMarkedAt(a_1_m));
+
+  CHECK(map.getCount() == 13);
+}
diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am
new file mode 100644
index 0000000..e375361
--- /dev/null
+++ b/tests/unit_tests/Makefile.am
@@ -0,0 +1,24 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+
+AM_CPPFLAGS += \
+  -I$(abs_top_srcdir)
+
+bin_PROGRAMS = unit_tests
+
+unit_tests_SOURCES = main.cpp
+

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].