You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datasketches.apache.org by jm...@apache.org on 2020/04/13 08:09:42 UTC
[incubator-datasketches-cpp] branch catch2_tests updated: migrate
hll, theta to catch2 for testing
This is an automated email from the ASF dual-hosted git repository.
jmalkin pushed a commit to branch catch2_tests
in repository https://gitbox.apache.org/repos/asf/incubator-datasketches-cpp.git
The following commit(s) were added to refs/heads/catch2_tests by this push:
new 2581b1c migrate hll, theta to catch2 for testing
2581b1c is described below
commit 2581b1c92f14613ea8cdcf937ff63ea68e3a7f5d
Author: Jon Malkin <jm...@users.noreply.github.com>
AuthorDate: Mon Apr 13 01:09:23 2020 -0700
migrate hll, theta to catch2 for testing
---
common/test/CMakeLists.txt | 36 +-
cpc/test/CMakeLists.txt | 7 +-
fi/test/CMakeLists.txt | 7 +-
hll/test/AuxHashMapTest.cpp | 124 +++---
hll/test/CouponHashSetTest.cpp | 226 +++++-----
hll/test/CouponListTest.cpp | 334 +++++++--------
hll/test/CrossCountingTest.cpp | 141 +++---
hll/test/HllArrayTest.cpp | 357 +++++++---------
hll/test/HllSketchTest.cpp | 501 ++++++++++------------
hll/test/HllUnionTest.cpp | 707 +++++++++++++++---------------
hll/test/IsomorphicTest.cpp | 193 ++++-----
hll/test/TablesTest.cpp | 51 +--
hll/test/ToFromByteArrayTest.cpp | 271 ++++++------
kll/test/CMakeLists.txt | 7 +-
sampling/test/CMakeLists.txt | 7 +-
theta/test/theta_a_not_b_test.cpp | 403 +++++++++---------
theta/test/theta_intersection_test.cpp | 406 +++++++++---------
theta/test/theta_sketch_test.cpp | 755 ++++++++++++++++-----------------
theta/test/theta_union_test.cpp | 157 ++++---
19 files changed, 2142 insertions(+), 2548 deletions(-)
diff --git a/common/test/CMakeLists.txt b/common/test/CMakeLists.txt
index c75fed6..6ac5066 100644
--- a/common/test/CMakeLists.txt
+++ b/common/test/CMakeLists.txt
@@ -17,38 +17,22 @@
add_library(common_test OBJECT "")
-target_link_libraries(common_test ${CPPUNIT_LIBRARY})
-
set_target_properties(common_test PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
)
-target_include_directories(common_test
- PUBLIC
- ${CPPUNIT_INCLUDE_DIR}
-)
-target_sources(common_test
- PRIVATE
- test_runner.cpp
- test_type.hpp
- test_allocator.hpp
- test_allocator.cpp
+target_include_directories(common
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}
)
-
-add_library(catch_test OBJECT "")
-
-set_target_properties(catch_test PROPERTIES
- CXX_STANDARD 11
- CXX_STANDARD_REQUIRED YES
-)
-
-target_sources(catch_test
+target_sources(common_test
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/catch.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test_allocator.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test_type.hpp
PRIVATE
- catch.hpp
- catch_runner.cpp
- test_type.hpp
- test_allocator.hpp
- test_allocator.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/catch_runner.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test_allocator.cpp
)
diff --git a/cpc/test/CMakeLists.txt b/cpc/test/CMakeLists.txt
index cc96580..0d31219 100644
--- a/cpc/test/CMakeLists.txt
+++ b/cpc/test/CMakeLists.txt
@@ -17,7 +17,7 @@
add_executable(cpc_test)
-target_link_libraries(cpc_test cpc catch_test)
+target_link_libraries(cpc_test cpc common_test)
set_target_properties(cpc_test PROPERTIES
CXX_STANDARD 11
@@ -41,8 +41,3 @@ target_sources(cpc_test
cpc_union_test.cpp
compression_test.cpp
)
-
-target_include_directories(cpc_test
- PRIVATE
- ../../common/test
-)
diff --git a/fi/test/CMakeLists.txt b/fi/test/CMakeLists.txt
index 37d01f0..51c020c 100644
--- a/fi/test/CMakeLists.txt
+++ b/fi/test/CMakeLists.txt
@@ -17,7 +17,7 @@
add_executable(fi_test)
-target_link_libraries(fi_test fi catch_test)
+target_link_libraries(fi_test fi common_test)
set_target_properties(fi_test PROPERTIES
CXX_STANDARD 11
@@ -41,8 +41,3 @@ target_sources(fi_test
frequent_items_sketch_test.cpp
frequent_items_sketch_custom_type_test.cpp
)
-
-target_include_directories(fi_test
- PRIVATE
- ../../common/test
-)
diff --git a/hll/test/AuxHashMapTest.cpp b/hll/test/AuxHashMapTest.cpp
index 2ab3fff..827f4ad 100644
--- a/hll/test/AuxHashMapTest.cpp
+++ b/hll/test/AuxHashMapTest.cpp
@@ -17,83 +17,63 @@
* under the License.
*/
-#include "AuxHashMap.hpp"
-
+#include <catch.hpp>
#include <memory>
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
-
-namespace datasketches {
-
-class AuxHashMapTest : public CppUnit::TestFixture {
-
- // list of values defined at bottom of file
- static const int nArr[]; // = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
-
- CPPUNIT_TEST_SUITE(AuxHashMapTest);
- CPPUNIT_TEST(checkMustReplace);
- CPPUNIT_TEST(checkGrowSpace);
- CPPUNIT_TEST(checkExceptionMustFindValueFor);
- CPPUNIT_TEST(checkExceptionMustAdd);
- CPPUNIT_TEST_SUITE_END();
-
- void checkMustReplace() {
- AuxHashMap<>* map = new AuxHashMap<>(3, 7);
- map->mustAdd(100, 5);
- int val = map->mustFindValueFor(100);
- CPPUNIT_ASSERT_EQUAL(val, 5);
-
- map->mustReplace(100, 10);
- val = map->mustFindValueFor(100);
- CPPUNIT_ASSERT_EQUAL(val, 10);
- CPPUNIT_ASSERT_THROW_MESSAGE("map->mustReplace() should fail",
- map->mustReplace(101, 5), std::invalid_argument);
-
- delete map;
- }
+#include "AuxHashMap.hpp"
- void checkGrowSpace() {
- auto map = std::unique_ptr<AuxHashMap<>, std::function<void(AuxHashMap<>*)>>(
- AuxHashMap<>::newAuxHashMap(3, 7),
- AuxHashMap<>::make_deleter()
- );
- CPPUNIT_ASSERT_EQUAL(map->getLgAuxArrInts(), 3);
- for (int i = 1; i <= 7; ++i) {
- map->mustAdd(i, i);
- }
- CPPUNIT_ASSERT_EQUAL(map->getLgAuxArrInts(), 4);
- auto itr = map->begin(true);
- int count1 = 0;
- int count2 = 0;
- while (itr != map->end()) {
- ++count2;
- int pair = *itr;
- if (pair != 0) { ++count1; }
- ++itr;
- }
- CPPUNIT_ASSERT_EQUAL(count1, 7);
- CPPUNIT_ASSERT_EQUAL(count2, 16);
- }
+namespace datasketches {
- void checkExceptionMustFindValueFor() {
- AuxHashMap<> map(3, 7);
- map.mustAdd(100, 5);
- CPPUNIT_ASSERT_THROW_MESSAGE("map.mustFindValueFor() should fail",
- map.mustFindValueFor(101), std::invalid_argument);
+TEST_CASE("aux hash map: check must replace", "[aux_hash_map]") {
+ AuxHashMap<>* map = new AuxHashMap<>(3, 7);
+ map->mustAdd(100, 5);
+ int val = map->mustFindValueFor(100);
+ REQUIRE(val == 5);
+
+ map->mustReplace(100, 10);
+ val = map->mustFindValueFor(100);
+ REQUIRE(val == 10);
+
+ REQUIRE_THROWS_AS(map->mustReplace(101, 5), std::invalid_argument);
+
+ delete map;
+}
+
+TEST_CASE("aux hash map: check grow space", "[aux_hash_map]") {
+ auto map = std::unique_ptr<AuxHashMap<>, std::function<void(AuxHashMap<>*)>>(
+ AuxHashMap<>::newAuxHashMap(3, 7),
+ AuxHashMap<>::make_deleter()
+ );
+ REQUIRE(map->getLgAuxArrInts() == 3);
+ for (int i = 1; i <= 7; ++i) {
+ map->mustAdd(i, i);
}
-
- void checkExceptionMustAdd() {
- AuxHashMap<>* map = AuxHashMap<>::newAuxHashMap(3, 7);
- map->mustAdd(100, 5);
- CPPUNIT_ASSERT_THROW_MESSAGE("map->mustAdd() should fail",
- map->mustAdd(100, 6), std::invalid_argument);
-
- AuxHashMap<>::make_deleter()(map);
+ REQUIRE(map->getLgAuxArrInts() == 4);
+ auto itr = map->begin(true);
+ int count1 = 0;
+ int count2 = 0;
+ while (itr != map->end()) {
+ ++count2;
+ int pair = *itr;
+ if (pair != 0) { ++count1; }
+ ++itr;
}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(AuxHashMapTest);
+ REQUIRE(count1 == 7);
+ REQUIRE(count2 == 16);
+}
+
+TEST_CASE("aux hash map: check exception must find value for", "[aux_hash_map]") {
+ AuxHashMap<> map(3, 7);
+ map.mustAdd(100, 5);
+ REQUIRE_THROWS_AS(map.mustFindValueFor(101), std::invalid_argument);
+}
+
+TEST_CASE("aux hash map: check exception must add", "[aux_hash_map]") {
+ AuxHashMap<>* map = AuxHashMap<>::newAuxHashMap(3, 7);
+ map->mustAdd(100, 5);
+ REQUIRE_THROWS_AS(map->mustAdd(100, 6), std::invalid_argument);
+
+ AuxHashMap<>::make_deleter()(map);
+}
} /* namespace datasketches */
diff --git a/hll/test/CouponHashSetTest.cpp b/hll/test/CouponHashSetTest.cpp
index 5ed9e03..76d1b68 100644
--- a/hll/test/CouponHashSetTest.cpp
+++ b/hll/test/CouponHashSetTest.cpp
@@ -21,8 +21,7 @@
#include "CouponHashSet.hpp"
#include "HllUtil.hpp"
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
#include <ostream>
#include <cmath>
#include <string>
@@ -30,137 +29,102 @@
namespace datasketches {
-class CouponHashSetTest : public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(CouponHashSetTest);
- CPPUNIT_TEST(checkCorruptBytearray);
- CPPUNIT_TEST(checkCorruptStream);
- CPPUNIT_TEST_SUITE_END();
-
- void checkCorruptBytearray() {
- int lgK = 8;
- hll_sketch sk1(lgK);
- for (int i = 0; i < 24; ++i) {
- sk1.update(i);
- }
- auto sketchBytes = sk1.serialize_updatable();
- uint8_t* bytes = sketchBytes.data();
- const size_t size = sketchBytes.size();
-
- bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = 0;
- // fail in HllSketchImpl
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- // fail in CouponHashSet
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- CouponHashSet<>::newSet(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = HllUtil<>::HASH_SET_PREINTS;
-
- bytes[HllUtil<>::SER_VER_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialization version byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::SER_VER_BYTE] = HllUtil<>::SER_VER;
-
- bytes[HllUtil<>::FAMILY_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in family id byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::FAMILY_BYTE] = HllUtil<>::FAMILY_ID;
-
- bytes[HllUtil<>::LG_K_BYTE] = 6;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect too small a lgK for Set mode",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::LG_K_BYTE] = lgK;
-
- uint8_t tmp = bytes[HllUtil<>::MODE_BYTE];
- bytes[HllUtil<>::MODE_BYTE] = 0x10; // HLL_6, LIST
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in mode byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::MODE_BYTE] = tmp;
-
- tmp = bytes[HllUtil<>::LG_ARR_BYTE];
- bytes[HllUtil<>::LG_ARR_BYTE] = 0;
- hll_sketch::deserialize(bytes, size);
- // should work fine despite the corruption
- bytes[HllUtil<>::LG_ARR_BYTE] = tmp;
-
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialized length",
- hll_sketch::deserialize(bytes, size - 1),
- std::invalid_argument);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialized length",
- hll_sketch::deserialize(bytes, 3),
- std::invalid_argument);
+TEST_CASE("coupon hash set: check corrupt bytearray", "[coupon_hash_set]") {
+ int lgK = 8;
+ hll_sketch sk1(lgK);
+ for (int i = 0; i < 24; ++i) {
+ sk1.update(i);
}
-
- void checkCorruptStream() {
- int lgK = 9;
- hll_sketch sk1(lgK);
- for (int i = 0; i < 24; ++i) {
- sk1.update(i);
- }
- std::stringstream ss;
- sk1.serialize_compact(ss);
-
- ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
- ss.put(0);
- ss.seekg(0);
- // fail in HllSketchImpl
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- // fail in CouponHashSet
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- CouponHashSet<>::newSet(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
- ss.put(HllUtil<>::HASH_SET_PREINTS);
-
- ss.seekp(HllUtil<>::SER_VER_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialization version byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::SER_VER_BYTE);
- ss.put(HllUtil<>::SER_VER);
-
- ss.seekp(HllUtil<>::FAMILY_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in family id byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::FAMILY_BYTE);
- ss.put(HllUtil<>::FAMILY_ID);
-
- ss.seekg(HllUtil<>::MODE_BYTE);
- uint8_t tmp = ss.get();
- ss.seekp(HllUtil<>::MODE_BYTE);
- ss.put(0x22); // HLL_8, HLL
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in mode byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::MODE_BYTE);
- ss.put(tmp);
-
- ss.seekg(HllUtil<>::LG_ARR_BYTE);
- tmp = ss.get();
- ss.seekp(HllUtil<>::LG_ARR_BYTE);
- ss.put(0);
- ss.seekg(0);
- hll_sketch::deserialize(ss);
- // should work fine despite the corruption
- ss.seekp(HllUtil<>::LG_ARR_BYTE);
- ss.put(tmp);
+ auto sketchBytes = sk1.serialize_updatable();
+ uint8_t* bytes = sketchBytes.data();
+ const size_t size = sketchBytes.size();
+
+ bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = 0;
+ // fail in HllSketchImpl
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ // fail in CouponHashSet
+ REQUIRE_THROWS_AS(CouponHashSet<>::newSet(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = HllUtil<>::HASH_SET_PREINTS;
+
+ bytes[HllUtil<>::SER_VER_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::SER_VER_BYTE] = HllUtil<>::SER_VER;
+
+ bytes[HllUtil<>::FAMILY_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::FAMILY_BYTE] = HllUtil<>::FAMILY_ID;
+
+ bytes[HllUtil<>::LG_K_BYTE] = 6;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::LG_K_BYTE] = lgK;
+
+ uint8_t tmp = bytes[HllUtil<>::MODE_BYTE];
+ bytes[HllUtil<>::MODE_BYTE] = 0x10; // HLL_6, LIST
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::MODE_BYTE] = tmp;
+
+ tmp = bytes[HllUtil<>::LG_ARR_BYTE];
+ bytes[HllUtil<>::LG_ARR_BYTE] = 0;
+ hll_sketch::deserialize(bytes, size);
+ // should work fine despite the corruption
+ bytes[HllUtil<>::LG_ARR_BYTE] = tmp;
+
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size - 1), std::invalid_argument);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, 3), std::invalid_argument);
+}
+
+TEST_CASE("coupon hash set: check corrupt stream", "[coupon_hash_set]") {
+ int lgK = 9;
+ hll_sketch sk1(lgK);
+ for (int i = 0; i < 24; ++i) {
+ sk1.update(i);
}
-};
+ std::stringstream ss;
+ sk1.serialize_compact(ss);
+
+ ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ // fail in HllSketchImpl
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ // fail in CouponHashSet
+ REQUIRE_THROWS_AS(CouponHashSet<>::newSet(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
+ ss.put(HllUtil<>::HASH_SET_PREINTS);
+
+ ss.seekp(HllUtil<>::SER_VER_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::SER_VER_BYTE);
+ ss.put(HllUtil<>::SER_VER);
+
+ ss.seekp(HllUtil<>::FAMILY_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::FAMILY_BYTE);
+ ss.put(HllUtil<>::FAMILY_ID);
+
+ ss.seekg(HllUtil<>::MODE_BYTE);
+ uint8_t tmp = ss.get();
+ ss.seekp(HllUtil<>::MODE_BYTE);
+ ss.put(0x22); // HLL_8, HLL
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::MODE_BYTE);
+ ss.put(tmp);
+
+ ss.seekg(HllUtil<>::LG_ARR_BYTE);
+ tmp = ss.get();
+ ss.seekp(HllUtil<>::LG_ARR_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ hll_sketch::deserialize(ss);
+ // should work fine despite the corruption
+ ss.seekp(HllUtil<>::LG_ARR_BYTE);
+ ss.put(tmp);
+}
-CPPUNIT_TEST_SUITE_REGISTRATION(CouponHashSetTest);
} // namespace datasketches
diff --git a/hll/test/CouponListTest.cpp b/hll/test/CouponListTest.cpp
index 5284032..d7d18fc 100644
--- a/hll/test/CouponListTest.cpp
+++ b/hll/test/CouponListTest.cpp
@@ -17,215 +17,165 @@
* under the License.
*/
-#include "hll.hpp"
-#include "CouponList.hpp"
-#include "HllUtil.hpp"
-
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
#include <ostream>
+#include <sstream>
#include <cmath>
#include <string>
#include <exception>
-namespace datasketches {
-
-class CouponListTest : public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(CouponListTest);
- CPPUNIT_TEST(checkIterator);
- CPPUNIT_TEST(checkDuplicatesAndMisc);
- CPPUNIT_TEST(checkSerializeDeserialize);
- CPPUNIT_TEST(checkCorruptBytearrayData);
- CPPUNIT_TEST(checkCorruptStreamData);
- CPPUNIT_TEST_SUITE_END();
+#include "hll.hpp"
+#include "CouponList.hpp"
+#include "HllUtil.hpp"
- void println_string(std::string str) {
- //std::cout << str << std::endl;
- }
+namespace datasketches {
- void checkIterator() {
- int lgConfigK = 8;
- CouponList<> cl(lgConfigK, HLL_4, LIST);
- for (int i = 1; i <= 8; ++i) { cl.couponUpdate(HllUtil<>::pair(i, i)); } // not hashes but distinct values
- const int mask = (1 << lgConfigK) - 1;
- int idx = 0;
- auto itr = cl.begin(true);
- while (itr != cl.end()) {
- int key = HllUtil<>::getLow26(*itr);
- int val = HllUtil<>::getValue(*itr);
- int slot = HllUtil<>::getLow26(*itr) & mask;
- std::ostringstream oss;
- oss << "Idx: " << idx << ", Key: " << key << ", Val: " << val
- << ", Slot: " << slot;
- println_string(oss.str());
- CPPUNIT_ASSERT_EQUAL(val, idx + 1);
- ++itr;
- ++idx;
- }
+void println_string(std::string str) {
+ //std::cout << str << std::endl;
+}
+
+TEST_CASE("coupon list: check iterator", "[coupon_list]") {
+ int lgConfigK = 8;
+ CouponList<> cl(lgConfigK, HLL_4, LIST);
+ for (int i = 1; i <= 8; ++i) { cl.couponUpdate(HllUtil<>::pair(i, i)); } // not hashes but distinct values
+ const int mask = (1 << lgConfigK) - 1;
+ int idx = 0;
+ auto itr = cl.begin(true);
+ while (itr != cl.end()) {
+ int key = HllUtil<>::getLow26(*itr);
+ int val = HllUtil<>::getValue(*itr);
+ int slot = HllUtil<>::getLow26(*itr) & mask;
+ std::ostringstream oss;
+ oss << "Idx: " << idx << ", Key: " << key << ", Val: " << val
+ << ", Slot: " << slot;
+ println_string(oss.str());
+ REQUIRE(val == idx + 1);
+ ++itr;
+ ++idx;
}
+}
- void checkDuplicatesAndMisc() {
- int lgConfigK = 8;
- hll_sketch sk(lgConfigK);
-
- for (int i = 1; i <= 7; ++i) {
- sk.update(i);
- sk.update(i);
- }
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_composite_estimate(), 7.0, 7 * 0.1);
-
- sk.update(8);
- sk.update(8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_composite_estimate(), 8.0, 8 * 0.1);
-
- for (int i = 9; i <= 25; ++i) {
- sk.update(i);
- sk.update(i);
- }
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_composite_estimate(), 25.0, 25 * 0.1);
+TEST_CASE("coupon list: check duplicates and misc", "[coupon_list]") {
+ int lgConfigK = 8;
+ hll_sketch sk(lgConfigK);
- double relErr = sk.get_rel_err(true, true, 4, 1);
- CPPUNIT_ASSERT(relErr < 0.0);
+ for (int i = 1; i <= 7; ++i) {
+ sk.update(i);
+ sk.update(i);
}
+ REQUIRE(sk.get_composite_estimate() == Approx(7.0).epsilon(0.1));
- std::string dumpAsHex(const char* data, int len) {
- constexpr uint8_t hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ sk.update(8);
+ sk.update(8);
+ REQUIRE(sk.get_composite_estimate() == Approx(8.0).epsilon(0.1));
- std::string s(len * 2, ' ');
- for (int i = 0; i < len; ++i) {
- s[2 * i] = hexmap[(data[i] & 0xF0) >> 4];
- s[2 * i + 1] = hexmap[(data[i] & 0x0F)];
- }
- return s;
+ for (int i = 9; i <= 25; ++i) {
+ sk.update(i);
+ sk.update(i);
}
+ REQUIRE(sk.get_composite_estimate() == Approx(25.0).epsilon(0.1));
- void serializeDeserialize(const int lgK) {
- hll_sketch sk1(lgK);
-
- int u = (lgK < 8) ? 7 : (((1 << (lgK - 3))/ 4) * 3);
- for (int i = 0; i < u; ++i) {
- sk1.update(i);
- }
- double est1 = sk1.get_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(est1, u, u * 1e-4);
-
- std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
- sk1.serialize_compact(ss);
- hll_sketch sk2 = hll_sketch::deserialize(ss);
- double est2 = sk2.get_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(est2, est1, 0.0);
-
- ss.str(std::string());
- ss.clear();
-
- sk1.serialize_updatable(ss);
- sk2 = hll_sketch::deserialize(ss);
- est2 = sk2.get_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(est2, est1, 0.0);
- }
-
- void checkSerializeDeserialize() {
- serializeDeserialize(7);
- serializeDeserialize(21);
- }
+ double relErr = sk.get_rel_err(true, true, 4, 1);
+ REQUIRE(relErr < 0.0);
+}
- void checkCorruptBytearrayData() {
- int lgK = 6;
- hll_sketch sk1(lgK);
- sk1.update(1);
- sk1.update(2);
- auto sketchBytes = sk1.serialize_compact();
- uint8_t* bytes = sketchBytes.data();
- const size_t size = sketchBytes.size();
-
- bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- CouponList<>::newList(bytes, size),
- std::invalid_argument);
-
- bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = HllUtil<>::LIST_PREINTS;
-
- bytes[HllUtil<>::SER_VER_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialization version byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::SER_VER_BYTE] = HllUtil<>::SER_VER;
-
- bytes[HllUtil<>::FAMILY_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in family id byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::FAMILY_BYTE] = HllUtil<>::FAMILY_ID;
-
- uint8_t tmp = bytes[HllUtil<>::MODE_BYTE];
- bytes[HllUtil<>::MODE_BYTE] = 0x01; // HLL_4, SET
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in mode byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::MODE_BYTE] = tmp;
-
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialized length",
- hll_sketch::deserialize(bytes, size - 1),
- std::invalid_argument);
-
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialized length",
- hll_sketch::deserialize(bytes, 3),
- std::invalid_argument);
- }
+static void serializeDeserialize(const int lgK) {
+ hll_sketch sk1(lgK);
- void checkCorruptStreamData() {
- int lgK = 6;
- hll_sketch sk1(lgK);
- sk1.update(1);
- sk1.update(2);
- std::stringstream ss;
- sk1.serialize_compact(ss);
-
- ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- CouponList<>::newList(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
- ss.put(HllUtil<>::LIST_PREINTS);
-
- ss.seekp(HllUtil<>::SER_VER_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialization version byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::SER_VER_BYTE);
- ss.put(HllUtil<>::SER_VER);
-
- ss.seekp(HllUtil<>::FAMILY_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in family id byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::FAMILY_BYTE);
- ss.put(HllUtil<>::FAMILY_ID);
-
- ss.seekp(HllUtil<>::MODE_BYTE);
- ss.put(0x22); // HLL_8, HLL
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in mode bytes",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
+ int u = (lgK < 8) ? 7 : (((1 << (lgK - 3))/ 4) * 3);
+ for (int i = 0; i < u; ++i) {
+ sk1.update(i);
}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(CouponListTest);
+ double est1 = sk1.get_estimate();
+ REQUIRE(est1 == Approx(u).margin(u * 1e-4));
+
+ std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
+ sk1.serialize_compact(ss);
+ hll_sketch sk2 = hll_sketch::deserialize(ss);
+ double est2 = sk2.get_estimate();
+ REQUIRE(est1 == est2);
+
+ ss.str(std::string());
+ ss.clear();
+
+ sk1.serialize_updatable(ss);
+ sk2 = hll_sketch::deserialize(ss);
+ est2 = sk2.get_estimate();
+ REQUIRE(est1 == est2);
+}
+
+TEST_CASE("coupon list: check serialize deserialize", "[coupon_list]") {
+ serializeDeserialize(7);
+ serializeDeserialize(21);
+}
+
+TEST_CASE("coupon list: check corrupt bytearray data", "[coupon_list]") {
+ int lgK = 6;
+ hll_sketch sk1(lgK);
+ sk1.update(1);
+ sk1.update(2);
+ auto sketchBytes = sk1.serialize_compact();
+ uint8_t* bytes = sketchBytes.data();
+ const size_t size = sketchBytes.size();
+
+ bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ REQUIRE_THROWS_AS(CouponList<>::newList(bytes, size), std::invalid_argument);
+
+ bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = HllUtil<>::LIST_PREINTS;
+
+ bytes[HllUtil<>::SER_VER_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::SER_VER_BYTE] = HllUtil<>::SER_VER;
+
+ bytes[HllUtil<>::FAMILY_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::FAMILY_BYTE] = HllUtil<>::FAMILY_ID;
+
+ uint8_t tmp = bytes[HllUtil<>::MODE_BYTE];
+ bytes[HllUtil<>::MODE_BYTE] = 0x01; // HLL_4, SET
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::MODE_BYTE] = tmp;
+
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size - 1), std::invalid_argument);
+
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, 3), std::invalid_argument);
+}
+
+TEST_CASE("coupon list: check corrupt stream data", "[coupon_list]") {
+ int lgK = 6;
+ hll_sketch sk1(lgK);
+ sk1.update(1);
+ sk1.update(2);
+ std::stringstream ss;
+ sk1.serialize_compact(ss);
+
+ ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ REQUIRE_THROWS_AS(CouponList<>::newList(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
+ ss.put(HllUtil<>::LIST_PREINTS);
+
+ ss.seekp(HllUtil<>::SER_VER_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::SER_VER_BYTE);
+ ss.put(HllUtil<>::SER_VER);
+
+ ss.seekp(HllUtil<>::FAMILY_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::FAMILY_BYTE);
+ ss.put(HllUtil<>::FAMILY_ID);
+
+ ss.seekp(HllUtil<>::MODE_BYTE);
+ ss.put(0x22); // HLL_8, HLL
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+}
} /* namespace datasketches */
diff --git a/hll/test/CrossCountingTest.cpp b/hll/test/CrossCountingTest.cpp
index c46beba..21eb919 100644
--- a/hll/test/CrossCountingTest.cpp
+++ b/hll/test/CrossCountingTest.cpp
@@ -17,88 +17,77 @@
* under the License.
*/
-#include "hll.hpp"
-
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
#include <ostream>
#include <cmath>
#include <string>
-namespace datasketches {
-
-class CrossCountingTest : public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(CrossCountingTest);
- CPPUNIT_TEST(crossCountingChecks);
- CPPUNIT_TEST_SUITE_END();
-
- hll_sketch buildSketch(const int n, const int lgK, const target_hll_type tgtHllType) {
- hll_sketch sketch(lgK, tgtHllType);
- for (int i = 0; i < n; ++i) {
- sketch.update(i);
- }
- return sketch;
- }
-
- void crossCountingCheck(const int lgK, const int n) {
- hll_sketch sk4 = buildSketch(n, lgK, HLL_4);
- const double est = sk4.get_estimate();
- const double lb = sk4.get_lower_bound(1);
- const double ub = sk4.get_upper_bound(1);
-
- hll_sketch sk6 = buildSketch(n, lgK, HLL_6);
- CPPUNIT_ASSERT_EQUAL(sk6.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk6.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk6.get_upper_bound(1), ub);
-
- hll_sketch sk8 = buildSketch(n, lgK, HLL_8);
- CPPUNIT_ASSERT_EQUAL(sk8.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk8.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk8.get_upper_bound(1), ub);
-
- // Conversions
- hll_sketch sk4to6(sk4, HLL_6);
- CPPUNIT_ASSERT_EQUAL(sk4to6.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk4to6.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk4to6.get_upper_bound(1), ub);
-
- hll_sketch sk4to8(sk4, HLL_8);
- CPPUNIT_ASSERT_EQUAL(sk4to8.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk4to8.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk4to8.get_upper_bound(1), ub);
-
- hll_sketch sk6to4(sk6, HLL_4);
- CPPUNIT_ASSERT_EQUAL(sk6to4.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk6to4.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk6to4.get_upper_bound(1), ub);
-
- hll_sketch sk6to8(sk6, HLL_8);
- CPPUNIT_ASSERT_EQUAL(sk6to8.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk6to8.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk6to8.get_upper_bound(1), ub);
-
- hll_sketch sk8to4(sk8, HLL_4);
- CPPUNIT_ASSERT_EQUAL(sk8to4.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk8to4.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk8to4.get_upper_bound(1), ub);
+#include "hll.hpp"
- hll_sketch sk8to6(sk8, HLL_6);
- CPPUNIT_ASSERT_EQUAL(sk8to6.get_estimate(), est);
- CPPUNIT_ASSERT_EQUAL(sk8to6.get_lower_bound(1), lb);
- CPPUNIT_ASSERT_EQUAL(sk8to6.get_upper_bound(1), ub);
- }
+namespace datasketches {
- void crossCountingChecks() {
- crossCountingCheck(4, 100);
- crossCountingCheck(4, 10000);
- crossCountingCheck(12, 7);
- crossCountingCheck(12, 384);
- crossCountingCheck(12, 10000);
+static hll_sketch buildSketch(const int n, const int lgK, const target_hll_type tgtHllType) {
+ hll_sketch sketch(lgK, tgtHllType);
+ for (int i = 0; i < n; ++i) {
+ sketch.update(i);
}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(CrossCountingTest);
+ return sketch;
+}
+
+static void crossCountingCheck(const int lgK, const int n) {
+ hll_sketch sk4 = buildSketch(n, lgK, HLL_4);
+ const double est = sk4.get_estimate();
+ const double lb = sk4.get_lower_bound(1);
+ const double ub = sk4.get_upper_bound(1);
+
+ hll_sketch sk6 = buildSketch(n, lgK, HLL_6);
+ REQUIRE(sk6.get_estimate() == est);
+ REQUIRE(sk6.get_lower_bound(1) == lb);
+ REQUIRE(sk6.get_upper_bound(1) == ub);
+
+ hll_sketch sk8 = buildSketch(n, lgK, HLL_8);
+ REQUIRE(sk8.get_estimate() == est);
+ REQUIRE(sk8.get_lower_bound(1) == lb);
+ REQUIRE(sk8.get_upper_bound(1) == ub);
+
+ // Conversions
+ hll_sketch sk4to6(sk4, HLL_6);
+ REQUIRE(sk4to6.get_estimate() == est);
+ REQUIRE(sk4to6.get_lower_bound(1) == lb);
+ REQUIRE(sk4to6.get_upper_bound(1) == ub);
+
+ hll_sketch sk4to8(sk4, HLL_8);
+ REQUIRE(sk4to8.get_estimate() == est);
+ REQUIRE(sk4to8.get_lower_bound(1) == lb);
+ REQUIRE(sk4to8.get_upper_bound(1) == ub);
+
+ hll_sketch sk6to4(sk6, HLL_4);
+ REQUIRE(sk6to4.get_estimate() == est);
+ REQUIRE(sk6to4.get_lower_bound(1) == lb);
+ REQUIRE(sk6to4.get_upper_bound(1) == ub);
+
+ hll_sketch sk6to8(sk6, HLL_8);
+ REQUIRE(sk6to8.get_estimate() == est);
+ REQUIRE(sk6to8.get_lower_bound(1) == lb);
+ REQUIRE(sk6to8.get_upper_bound(1) == ub);
+
+ hll_sketch sk8to4(sk8, HLL_4);
+ REQUIRE(sk8to4.get_estimate() == est);
+ REQUIRE(sk8to4.get_lower_bound(1) == lb);
+ REQUIRE(sk8to4.get_upper_bound(1) == ub);
+
+ hll_sketch sk8to6(sk8, HLL_6);
+ REQUIRE(sk8to6.get_estimate() == est);
+ REQUIRE(sk8to6.get_lower_bound(1) == lb);
+ REQUIRE(sk8to6.get_upper_bound(1) == ub);
+}
+
+TEST_CASE("cross counting: cross counting checks", "[cross_counting]") {
+ crossCountingCheck(4, 100);
+ crossCountingCheck(4, 10000);
+ crossCountingCheck(12, 7);
+ crossCountingCheck(12, 384);
+ crossCountingCheck(12, 10000);
+}
} /* namespace datasketches */
diff --git a/hll/test/HllArrayTest.cpp b/hll/test/HllArrayTest.cpp
index 2f75625..72d0851 100644
--- a/hll/test/HllArrayTest.cpp
+++ b/hll/test/HllArrayTest.cpp
@@ -18,215 +18,174 @@
*/
#include "hll.hpp"
-//#include "HllArray.hpp"
-//#include "HllSketch.hpp"
#include <exception>
#include <sstream>
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
namespace datasketches {
-class HllArrayTest : public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(HllArrayTest);
- CPPUNIT_TEST(checkCompositeEstimate);
- CPPUNIT_TEST(checkSerializeDeserialize);
- CPPUNIT_TEST(checkIsCompact);
- CPPUNIT_TEST(checkCorruptBytearray);
- CPPUNIT_TEST(checkCorruptStream);
- CPPUNIT_TEST_SUITE_END();
-
- void testComposite(const int lgK, const target_hll_type tgtHllType, const int n) {
- hll_union u(lgK);
- hll_sketch sk(lgK, tgtHllType);
- for (int i = 0; i < n; ++i) {
- u.update(i);
- sk.update(i);
- }
- u.update(sk); // merge
- hll_sketch res = u.get_result(target_hll_type::HLL_8);
- double est = res.get_composite_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(est, sk.get_composite_estimate(), 0.0);
+static void testComposite(const int lgK, const target_hll_type tgtHllType, const int n) {
+ hll_union u(lgK);
+ hll_sketch sk(lgK, tgtHllType);
+ for (int i = 0; i < n; ++i) {
+ u.update(i);
+ sk.update(i);
}
-
- void checkCompositeEstimate() {
- testComposite(4, target_hll_type::HLL_8, 10000);
- testComposite(5, target_hll_type::HLL_8, 10000);
- testComposite(6, target_hll_type::HLL_8, 10000);
- testComposite(13, target_hll_type::HLL_8, 10000);
+ u.update(sk); // merge
+ hll_sketch res = u.get_result(target_hll_type::HLL_8);
+ double est = res.get_composite_estimate();
+ REQUIRE(sk.get_composite_estimate() == est);
+}
+
+TEST_CASE("hll array: check composite estimate", "[hll_array]") {
+ testComposite(4, target_hll_type::HLL_8, 10000);
+ testComposite(5, target_hll_type::HLL_8, 10000);
+ testComposite(6, target_hll_type::HLL_8, 10000);
+ testComposite(13, target_hll_type::HLL_8, 10000);
+}
+
+static void serializeDeserialize(const int lgK, target_hll_type tgtHllType, const int n) {
+ hll_sketch sk1(lgK, tgtHllType);
+
+ for (int i = 0; i < n; ++i) {
+ sk1.update(i);
}
-
- void checkSerializeDeserialize() {
- int lgK = 4;
- int n = 8;
- serializeDeserialize(lgK, HLL_4, n);
- serializeDeserialize(lgK, HLL_6, n);
- serializeDeserialize(lgK, HLL_8, n);
-
- lgK = 15;
- n = (((1 << (lgK - 3))*3)/4) + 100;
- serializeDeserialize(lgK, HLL_4, n);
- serializeDeserialize(lgK, HLL_6, n);
- serializeDeserialize(lgK, HLL_8, n);
-
- lgK = 21;
- n = (((1 << (lgK - 3))*3)/4) + 1000;
- serializeDeserialize(lgK, HLL_4, n);
- serializeDeserialize(lgK, HLL_6, n);
- serializeDeserialize(lgK, HLL_8, n);
+ //REQUIRE(sk1.getCurrentMode() == CurMode::HLL);
+
+ double est1 = sk1.get_estimate();
+ REQUIRE(est1 == Approx(n).margin(n * 0.03));
+
+ // serialize as compact and updatable, deserialize, compare estimates are exact
+ std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
+ sk1.serialize_compact(ss);
+ hll_sketch sk2 = hll_sketch::deserialize(ss);
+ REQUIRE(sk1.get_estimate() == sk2.get_estimate());
+
+ ss.clear();
+ sk1.serialize_updatable(ss);
+ sk2 = hll_sketch::deserialize(ss);
+ REQUIRE(sk1.get_estimate() == sk2.get_estimate());
+
+ sk1.reset();
+ REQUIRE(sk1.get_estimate() == 0.0);
+}
+
+TEST_CASE("hll array: check serialize deserialize", "[hll_array]") {
+ int lgK = 4;
+ int n = 8;
+ serializeDeserialize(lgK, HLL_4, n);
+ serializeDeserialize(lgK, HLL_6, n);
+ serializeDeserialize(lgK, HLL_8, n);
+
+ lgK = 15;
+ n = (((1 << (lgK - 3))*3)/4) + 100;
+ serializeDeserialize(lgK, HLL_4, n);
+ serializeDeserialize(lgK, HLL_6, n);
+ serializeDeserialize(lgK, HLL_8, n);
+
+ lgK = 21;
+ n = (((1 << (lgK - 3))*3)/4) + 1000;
+ serializeDeserialize(lgK, HLL_4, n);
+ serializeDeserialize(lgK, HLL_6, n);
+ serializeDeserialize(lgK, HLL_8, n);
+}
+
+TEST_CASE("hll array: check is compact", "[hll_array]") {
+ hll_sketch sk(4);
+ for (int i = 0; i < 8; ++i) {
+ sk.update(i);
}
-
- void serializeDeserialize(const int lgK, target_hll_type tgtHllType, const int n) {
- hll_sketch sk1(lgK, tgtHllType);
-
- for (int i = 0; i < n; ++i) {
- sk1.update(i);
- }
- //CPPUNIT_ASSERT(sk1.getCurrentMode() == CurMode::HLL);
-
- double est1 = sk1.get_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(n, est1, n * 0.03);
-
- // serialize as compact and updatable, deserialize, compare estimates are exact
- std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
- sk1.serialize_compact(ss);
- hll_sketch sk2 = hll_sketch::deserialize(ss);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk2.get_estimate(), sk1.get_estimate(), 0.0);
-
- ss.clear();
- sk1.serialize_updatable(ss);
- sk2 = hll_sketch::deserialize(ss);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk2.get_estimate(), sk1.get_estimate(), 0.0);
-
- sk1.reset();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, sk1.get_estimate(), 0.0);
- }
-
- void checkIsCompact() {
- hll_sketch sk(4);
- for (int i = 0; i < 8; ++i) {
- sk.update(i);
- }
- CPPUNIT_ASSERT(!sk.is_compact());
+ REQUIRE_FALSE(sk.is_compact());
+}
+
+TEST_CASE("hll array: check corrupt bytearray", "[hll_array]") {
+ int lgK = 8;
+ hll_sketch sk1(lgK, HLL_8);
+ for (int i = 0; i < 50; ++i) {
+ sk1.update(i);
}
-
- void checkCorruptBytearray() {
- int lgK = 8;
- hll_sketch sk1(lgK, HLL_8);
- for (int i = 0; i < 50; ++i) {
- sk1.update(i);
- }
- auto sketchBytes = sk1.serialize_compact();
- uint8_t* bytes = sketchBytes.data();
- const size_t size = sketchBytes.size();
-
- bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- HllArray<>::newHll(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = HllUtil<>::HLL_PREINTS;
-
- bytes[HllUtil<>::SER_VER_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialization version byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::SER_VER_BYTE] = HllUtil<>::SER_VER;
-
- bytes[HllUtil<>::FAMILY_BYTE] = 0;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in family id byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::FAMILY_BYTE] = HllUtil<>::FAMILY_ID;
-
- uint8_t tmp = bytes[HllUtil<>::MODE_BYTE];
- bytes[HllUtil<>::MODE_BYTE] = 0x10; // HLL_6, LIST
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in mode byte",
- hll_sketch::deserialize(bytes, size),
- std::invalid_argument);
- bytes[HllUtil<>::MODE_BYTE] = tmp;
-
- tmp = bytes[HllUtil<>::LG_ARR_BYTE];
- bytes[HllUtil<>::LG_ARR_BYTE] = 0;
- hll_sketch::deserialize(bytes, size);
- // should work fine despite the corruption
- bytes[HllUtil<>::LG_ARR_BYTE] = tmp;
-
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialized length",
- hll_sketch::deserialize(bytes, size - 1),
- std::invalid_argument);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialized length",
- hll_sketch::deserialize(bytes, 3),
- std::invalid_argument);
- }
-
- void checkCorruptStream() {
- int lgK = 6;
- hll_sketch sk1(lgK);
- for (int i = 0; i < 50; ++i) {
- sk1.update(i);
- }
- std::stringstream ss;
- sk1.serialize_compact(ss);
-
- ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in preInts byte",
- HllArray<>::newHll(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
- ss.put(HllUtil<>::HLL_PREINTS);
-
- ss.seekp(HllUtil<>::SER_VER_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in serialization version byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::SER_VER_BYTE);
- ss.put(HllUtil<>::SER_VER);
-
- ss.seekp(HllUtil<>::FAMILY_BYTE);
- ss.put(0);
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in family id byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::FAMILY_BYTE);
- ss.put(HllUtil<>::FAMILY_ID);
-
- ss.seekg(HllUtil<>::MODE_BYTE);
- uint8_t tmp = ss.get();
- ss.seekp(HllUtil<>::MODE_BYTE);
- ss.put(0x11); // HLL_6, SET
- ss.seekg(0);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect error in mode byte",
- hll_sketch::deserialize(ss),
- std::invalid_argument);
- ss.seekp(HllUtil<>::MODE_BYTE);
- ss.put(tmp);
-
- ss.seekg(HllUtil<>::LG_ARR_BYTE);
- tmp = ss.get();
- ss.seekp(HllUtil<>::LG_ARR_BYTE);
- ss.put(0);
- ss.seekg(0);
- hll_sketch::deserialize(ss);
- // should work fine despite the corruption
- ss.seekp(HllUtil<>::LG_ARR_BYTE);
- ss.put(tmp);
+ auto sketchBytes = sk1.serialize_compact();
+ uint8_t* bytes = sketchBytes.data();
+ const size_t size = sketchBytes.size();
+
+ bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ REQUIRE_THROWS_AS(HllArray<>::newHll(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::PREAMBLE_INTS_BYTE] = HllUtil<>::HLL_PREINTS;
+
+ bytes[HllUtil<>::SER_VER_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::SER_VER_BYTE] = HllUtil<>::SER_VER;
+
+ bytes[HllUtil<>::FAMILY_BYTE] = 0;
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::FAMILY_BYTE] = HllUtil<>::FAMILY_ID;
+
+ uint8_t tmp = bytes[HllUtil<>::MODE_BYTE];
+ bytes[HllUtil<>::MODE_BYTE] = 0x10; // HLL_6, LIST
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size), std::invalid_argument);
+ bytes[HllUtil<>::MODE_BYTE] = tmp;
+
+ tmp = bytes[HllUtil<>::LG_ARR_BYTE];
+ bytes[HllUtil<>::LG_ARR_BYTE] = 0;
+ hll_sketch::deserialize(bytes, size);
+ // should work fine despite the corruption
+ bytes[HllUtil<>::LG_ARR_BYTE] = tmp;
+
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, size - 1), std::invalid_argument);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(bytes, 3), std::invalid_argument);
+}
+
+TEST_CASE("hll array: check corrupt stream", "[hll_array]") {
+ int lgK = 6;
+ hll_sketch sk1(lgK);
+ for (int i = 0; i < 50; ++i) {
+ sk1.update(i);
}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(HllArrayTest);
+ std::stringstream ss;
+ sk1.serialize_compact(ss);
+
+ ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ REQUIRE_THROWS_AS(HllArray<>::newHll(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::PREAMBLE_INTS_BYTE);
+ ss.put(HllUtil<>::HLL_PREINTS);
+
+ ss.seekp(HllUtil<>::SER_VER_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::SER_VER_BYTE);
+ ss.put(HllUtil<>::SER_VER);
+
+ ss.seekp(HllUtil<>::FAMILY_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::FAMILY_BYTE);
+ ss.put(HllUtil<>::FAMILY_ID);
+
+ ss.seekg(HllUtil<>::MODE_BYTE);
+ uint8_t tmp = ss.get();
+ ss.seekp(HllUtil<>::MODE_BYTE);
+ ss.put(0x11); // HLL_6, SET
+ ss.seekg(0);
+ REQUIRE_THROWS_AS(hll_sketch::deserialize(ss), std::invalid_argument);
+ ss.seekp(HllUtil<>::MODE_BYTE);
+ ss.put(tmp);
+
+ ss.seekg(HllUtil<>::LG_ARR_BYTE);
+ tmp = ss.get();
+ ss.seekp(HllUtil<>::LG_ARR_BYTE);
+ ss.put(0);
+ ss.seekg(0);
+ hll_sketch::deserialize(ss);
+ // should work fine despite the corruption
+ ss.seekp(HllUtil<>::LG_ARR_BYTE);
+ ss.put(tmp);
+}
} /* namespace datasketches */
diff --git a/hll/test/HllSketchTest.cpp b/hll/test/HllSketchTest.cpp
index 1e33c1a..1cd62c3 100644
--- a/hll/test/HllSketchTest.cpp
+++ b/hll/test/HllSketchTest.cpp
@@ -19,302 +19,249 @@
#include "hll.hpp"
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
namespace datasketches {
-class hllSketchTest : public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(hllSketchTest);
- CPPUNIT_TEST(checkCopies);
- CPPUNIT_TEST(checkCopyAs);
- CPPUNIT_TEST(checkMisc1);
- CPPUNIT_TEST(checkNumStdDev);
- CPPUNIT_TEST(checkSerSizes);
- CPPUNIT_TEST(exerciseToString);
- CPPUNIT_TEST(checkCompactFlag);
- CPPUNIT_TEST(checkKLimits);
- CPPUNIT_TEST(checkInputTypes);
- CPPUNIT_TEST_SUITE_END();
-
- void checkCopies() {
- runCheckCopy(14, HLL_4);
- runCheckCopy(8, HLL_6);
- runCheckCopy(8, HLL_8);
- }
-
- void runCheckCopy(int lgConfigK, target_hll_type tgtHllType) {
- hll_sketch sk(lgConfigK, tgtHllType);
-
- for (int i = 0; i < 7; ++i) {
- sk.update(i);
- }
-
- hll_sketch skCopy = sk;
- CPPUNIT_ASSERT_DOUBLES_EQUAL(skCopy.get_estimate(), sk.get_estimate(), 0.0);
-
- // no access to hllSketchImpl, so we'll ensure those differ by adding more
- // data to sk and ensuring the mode and estimates differ
- for (int i = 7; i < 24; ++i) {
- sk.update(i);
- }
- CPPUNIT_ASSERT(16.0 < (sk.get_estimate() - skCopy.get_estimate()));
-
- skCopy = sk;
- CPPUNIT_ASSERT_DOUBLES_EQUAL(skCopy.get_estimate(), sk.get_estimate(), 0.0);
-
- int u = (sk.get_target_type() == HLL_4) ? 100000 : 25;
- for (int i = 24; i < u; ++i) {
- sk.update(i);
- }
- CPPUNIT_ASSERT(sk.get_estimate() != skCopy.get_estimate()); // either 1 or 100k difference
+static void runCheckCopy(int lgConfigK, target_hll_type tgtHllType) {
+ hll_sketch sk(lgConfigK, tgtHllType);
- skCopy = sk;
- CPPUNIT_ASSERT_DOUBLES_EQUAL(skCopy.get_estimate(), sk.get_estimate(), 0.0);
-
- }
-
- void checkCopyAs() {
- copyAs(HLL_4, HLL_4);
- copyAs(HLL_4, HLL_6);
- copyAs(HLL_4, HLL_8);
- copyAs(HLL_6, HLL_4);
- copyAs(HLL_6, HLL_6);
- copyAs(HLL_6, HLL_8);
- copyAs(HLL_8, HLL_4);
- copyAs(HLL_8, HLL_6);
- copyAs(HLL_8, HLL_8);
- }
-
- void copyAs(target_hll_type srcType, target_hll_type dstType) {
- int lgK = 8;
- int n1 = 7;
- int n2 = 24;
- int n3 = 1000;
- int base = 0;
-
- hll_sketch src(lgK, srcType);
- for (int i = 0; i < n1; ++i) {
- src.update(i + base);
- }
- hll_sketch dst(src, dstType);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(dst.get_estimate(), src.get_estimate(), 0.0);
-
- for (int i = n1; i < n2; ++i) {
- src.update(i + base);
- }
- dst = hll_sketch(src, dstType);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(dst.get_estimate(), src.get_estimate(), 0.0);
-
- for (int i = n2; i < n3; ++i) {
- src.update(i + base);
- }
- dst = hll_sketch(src, dstType);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(dst.get_estimate(), src.get_estimate(), 0.0);
+ for (int i = 0; i < 7; ++i) {
+ sk.update(i);
}
- void checkMisc1() {
- int lgConfigK = 8;
- target_hll_type srcType = target_hll_type::HLL_8;
- hll_sketch sk(lgConfigK, srcType);
-
- for (int i = 0; i < 7; ++i) { sk.update(i); } // LIST
- CPPUNIT_ASSERT_EQUAL(36, sk.get_compact_serialization_bytes());
- CPPUNIT_ASSERT_EQUAL(40, sk.get_updatable_serialization_bytes());
+ hll_sketch skCopy = sk;
+ REQUIRE(sk.get_estimate() == skCopy.get_estimate());
- for (int i = 7; i < 24; ++i) { sk.update(i); } // SET
- CPPUNIT_ASSERT_EQUAL(108, sk.get_compact_serialization_bytes());
- CPPUNIT_ASSERT_EQUAL(140, sk.get_updatable_serialization_bytes());
-
- sk.update(24); // HLL
- CPPUNIT_ASSERT_EQUAL(40 + 256, sk.get_updatable_serialization_bytes());
-
- const int hllBytes = HllUtil<>::HLL_BYTE_ARR_START + (1 << lgConfigK);
- CPPUNIT_ASSERT_EQUAL(hllBytes, sk.get_compact_serialization_bytes());
- CPPUNIT_ASSERT_EQUAL(hllBytes, hll_sketch::get_max_updatable_serialization_bytes(lgConfigK, HLL_8));
- }
-
- void checkNumStdDev() {
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to throw on invalid number of std deviations",
- HllUtil<>::checkNumStdDev(0), std::invalid_argument);
+ // no access to hllSketchImpl, so we'll ensure those differ by adding more
+ // data to sk and ensuring the mode and estimates differ
+ for (int i = 7; i < 24; ++i) {
+ sk.update(i);
}
+ REQUIRE(16.0 < (sk.get_estimate() - skCopy.get_estimate()));
- void checkSerSizes() {
- checkSerializationSizes(8, HLL_8);
- checkSerializationSizes(8, HLL_6);
- checkSerializationSizes(8, HLL_4);
- }
+ skCopy = sk;
+ REQUIRE(sk.get_estimate() == skCopy.get_estimate());
- void checkSerializationSizes(const int lgConfigK, target_hll_type tgtHllType) {
- hll_sketch sk(lgConfigK, tgtHllType);
- int i;
-
- // LIST
- for (i = 0; i < 7; ++i) { sk.update(i); }
- int expected = HllUtil<>::LIST_INT_ARR_START + (i << 2);
- CPPUNIT_ASSERT_EQUAL(expected, sk.get_compact_serialization_bytes());
- expected = HllUtil<>::LIST_INT_ARR_START + (4 << HllUtil<>::LG_INIT_LIST_SIZE);
- CPPUNIT_ASSERT_EQUAL(expected, sk.get_updatable_serialization_bytes());
-
- // SET
- for (i = 7; i < 24; ++i) { sk.update(i); }
- expected = HllUtil<>::HASH_SET_INT_ARR_START + (i << 2);
- CPPUNIT_ASSERT_EQUAL(expected, sk.get_compact_serialization_bytes());
- expected = HllUtil<>::HASH_SET_INT_ARR_START + (4 << HllUtil<>::LG_INIT_SET_SIZE);
- CPPUNIT_ASSERT_EQUAL(expected, sk.get_updatable_serialization_bytes());
-
- // HLL
+ int u = (sk.get_target_type() == HLL_4) ? 100000 : 25;
+ for (int i = 24; i < u; ++i) {
sk.update(i);
- //CPPUNIT_ASSERT_EQUAL(CurMode::HLL, s.getCurrentMode());
- //HllArray* hllArr = (HllArray*) s.hllSketchImpl;
-
- /*
- int auxCountBytes = 0;
- int auxArrBytes = 0;
- if (hllArr.getTgtHllType() == target_hll_type::HLL_4) {
- AuxHashMap* auxMap = hllArr.getAuxHashMap();
- if (auxMap != nullptr) {
- auxCountBytes = auxMap.getAuxCount() << 2;
- auxArrBytes = 4 << auxMap.getLgAuxArrInts();
- } else {
- auxArrBytes = 4 << HllUtil<>::LG_AUX_ARR_INTS[lgConfigK];
- }
- }
- int hllArrBytes = hllArr.getHllByteArrBytes();
- expected = HllUtil<>::HLL_BYTE_ARR_START + hllArrBytes + auxCountBytes;
- CPPUNIT_ASSERT_EQUAL(expected, sk.get_compact_serialization_bytes());
- expected = HllUtil<>::HLL_BYTE_ARR_START + hllArrBytes + auxArrBytes;
- CPPUNIT_ASSERT_EQUAL(expected, sk.get_updatable_serialization_bytes());
-
- int fullAuxArrBytes = (tgtHllType == HLL_4) ? (4 << HllUtil<>::LG_AUX_ARR_INTS[lgConfigK]) : 0;
- expected = HllUtil<>::HLL_BYTE_ARR_START + hllArrBytes + fullAuxArrBytes;
- CPPUNIT_ASSERT_EQUAL(expected,
- HllSketch::get_max_updatable_serialization_bytes(lgConfigK, tgtHllType));
- */
}
-
- void exerciseToString() {
- hll_sketch sk(15, HLL_4);
- for (int i = 0; i < 25; ++i) { sk.update(i); }
- std::ostringstream oss(std::ios::binary);
- sk.to_string(oss, false, true, true, true);
- for (int i = 25; i < (1 << 20); ++i) { sk.update(i); }
- sk.to_string(oss, false, true, true, true);
- sk.to_string(oss, false, true, true, false);
-
- // need to delete old sketch?
- sk = hll_sketch(8, HLL_8);
- for (int i = 0; i < 25; ++i) { sk.update(i); }
- sk.to_string(oss, false, true, true, true);
- }
-
- void checkCompactFlag() {
- int lgK = 8;
- // unless/until we create non-updatable "direct" versions,
- // deserialized image should never be compact
- // LIST: follows serialization request
- CPPUNIT_ASSERT(checkCompact(lgK, 7, HLL_8, false) == false);
- CPPUNIT_ASSERT(checkCompact(lgK, 7, HLL_8, true) == false);
-
- // SET: follows serialization request
- CPPUNIT_ASSERT(checkCompact(lgK, 24, HLL_8, false) == false);
- CPPUNIT_ASSERT(checkCompact(lgK, 24, HLL_8, true) == false);
-
- // HLL8: always updatable
- CPPUNIT_ASSERT(checkCompact(lgK, 25, HLL_8, false) == false);
- CPPUNIT_ASSERT(checkCompact(lgK, 25, HLL_8, true) == false);
-
- // HLL6: always updatable
- CPPUNIT_ASSERT(checkCompact(lgK, 25, HLL_6, false) == false);
- CPPUNIT_ASSERT(checkCompact(lgK, 25, HLL_6, true) == false);
-
- // HLL4: follows serialization request
- CPPUNIT_ASSERT(checkCompact(lgK, 25, HLL_4, false) == false);
- CPPUNIT_ASSERT(checkCompact(lgK, 25, HLL_4, true) == false);
+ REQUIRE(sk.get_estimate() != skCopy.get_estimate()); // either 1 or 100k difference
+
+ skCopy = sk;
+ REQUIRE(sk.get_estimate() == skCopy.get_estimate());
+}
+
+TEST_CASE("hll sketch: check copies", "[hll_sketch]") {
+ runCheckCopy(14, HLL_4);
+ runCheckCopy(8, HLL_6);
+ runCheckCopy(8, HLL_8);
+}
+
+static void copyAs(target_hll_type srcType, target_hll_type dstType) {
+ int lgK = 8;
+ int n1 = 7;
+ int n2 = 24;
+ int n3 = 1000;
+ int base = 0;
+
+ hll_sketch src(lgK, srcType);
+ for (int i = 0; i < n1; ++i) {
+ src.update(i + base);
}
+ hll_sketch dst(src, dstType);
+ REQUIRE(src.get_estimate() == dst.get_estimate());
- // Creates and serializes then deserializes sketch.
- // Returns true if deserialized sketch is compact.
- bool checkCompact(const int lgK, const int n, const target_hll_type type, bool compact) {
- hll_sketch sk(lgK, type);
- for (int i = 0; i < n; ++i) { sk.update(i); }
-
- std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
- if (compact) {
- sk.serialize_compact(ss);
- CPPUNIT_ASSERT_EQUAL(sk.get_compact_serialization_bytes(), (int) ss.tellp());
- } else {
- sk.serialize_updatable(ss);
- CPPUNIT_ASSERT_EQUAL(sk.get_updatable_serialization_bytes(), (int) ss.tellp());
- }
-
- hll_sketch sk2 = hll_sketch::deserialize(ss);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(n, sk2.get_estimate(), 0.01);
- bool isCompact = sk2.is_compact();
-
- return isCompact;
+ for (int i = n1; i < n2; ++i) {
+ src.update(i + base);
}
+ dst = hll_sketch(src, dstType);
+ REQUIRE(src.get_estimate() == dst.get_estimate());
- void checkKLimits() {
- hll_sketch sketch1(HllUtil<>::MIN_LOG_K, target_hll_type::HLL_8);
- hll_sketch sketch2(HllUtil<>::MAX_LOG_K, target_hll_type::HLL_4);
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to throw with lgK too small",
- hll_sketch(HllUtil<>::MIN_LOG_K - 1),
- std::invalid_argument);
-
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to throw with lgK too large",
- hll_sketch(HllUtil<>::MAX_LOG_K + 1),
- std::invalid_argument);
+ for (int i = n2; i < n3; ++i) {
+ src.update(i + base);
}
-
- void checkInputTypes() {
- hll_sketch sk(8, target_hll_type::HLL_8);
-
- // inserting the same value as a variety of input types
- sk.update((uint8_t) 102);
- sk.update((uint16_t) 102);
- sk.update((uint32_t) 102);
- sk.update((uint64_t) 102);
- sk.update((int8_t) 102);
- sk.update((int16_t) 102);
- sk.update((int32_t) 102);
- sk.update((int64_t) 102);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, sk.get_estimate(), 0.01);
-
- // identical binary representations
- // no unsigned in Java, but need to sign-extend both as Java would do
- sk.update((uint8_t) 255);
- sk.update((int8_t) -1);
-
- sk.update((float) -2.0);
- sk.update((double) -2.0);
-
- std::string str = "input string";
- sk.update(str);
- sk.update(str.c_str(), str.length());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, sk.get_estimate(), 0.01);
-
- sk = hll_sketch(8, target_hll_type::HLL_6);
- sk.update((float) 0.0);
- sk.update((float) -0.0);
- sk.update((double) 0.0);
- sk.update((double) -0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, sk.get_estimate(), 0.01);
-
- sk = hll_sketch(8, target_hll_type::HLL_4);
- sk.update(std::nanf("3"));
- sk.update(std::nan("9"));
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, sk.get_estimate(), 0.01);
-
- sk = hll_sketch(8, target_hll_type::HLL_4);
- sk.update(nullptr, 0);
- sk.update("");
- CPPUNIT_ASSERT(sk.is_empty());
+ dst = hll_sketch(src, dstType);
+ REQUIRE(src.get_estimate() == dst.get_estimate());
+}
+
+TEST_CASE("hll sketch: check copy as", "[hll_sketch]") {
+ copyAs(HLL_4, HLL_4);
+ copyAs(HLL_4, HLL_6);
+ copyAs(HLL_4, HLL_8);
+ copyAs(HLL_6, HLL_4);
+ copyAs(HLL_6, HLL_6);
+ copyAs(HLL_6, HLL_8);
+ copyAs(HLL_8, HLL_4);
+ copyAs(HLL_8, HLL_6);
+ copyAs(HLL_8, HLL_8);
+}
+
+TEST_CASE("hll sketch: check misc1", "[hll_sketch]") {
+ int lgConfigK = 8;
+ target_hll_type srcType = target_hll_type::HLL_8;
+ hll_sketch sk(lgConfigK, srcType);
+
+ for (int i = 0; i < 7; ++i) { sk.update(i); } // LIST
+ REQUIRE(sk.get_compact_serialization_bytes() == 36);
+ REQUIRE(sk.get_updatable_serialization_bytes() == 40);
+
+ for (int i = 7; i < 24; ++i) { sk.update(i); } // SET
+ REQUIRE(sk.get_compact_serialization_bytes() == 108);
+ REQUIRE(sk.get_updatable_serialization_bytes() == 140);
+
+ sk.update(24); // HLL
+ REQUIRE(sk.get_updatable_serialization_bytes() == 40 + 256);
+
+ const int hllBytes = HllUtil<>::HLL_BYTE_ARR_START + (1 << lgConfigK);
+ REQUIRE(sk.get_compact_serialization_bytes() == hllBytes);
+ REQUIRE(hll_sketch::get_max_updatable_serialization_bytes(lgConfigK, HLL_8) == hllBytes);
+}
+
+TEST_CASE("hll sketch: check num std dev", "[hll_sketch]") {
+ REQUIRE_THROWS_AS(HllUtil<>::checkNumStdDev(0), std::invalid_argument);
+}
+
+void checkSerializationSizes(const int lgConfigK, target_hll_type tgtHllType) {
+ hll_sketch sk(lgConfigK, tgtHllType);
+ int i;
+
+ // LIST
+ for (i = 0; i < 7; ++i) { sk.update(i); }
+ int expected = HllUtil<>::LIST_INT_ARR_START + (i << 2);
+ REQUIRE(sk.get_compact_serialization_bytes() == expected);
+ expected = HllUtil<>::LIST_INT_ARR_START + (4 << HllUtil<>::LG_INIT_LIST_SIZE);
+ REQUIRE(sk.get_updatable_serialization_bytes() == expected);
+
+ // SET
+ for (i = 7; i < 24; ++i) { sk.update(i); }
+ expected = HllUtil<>::HASH_SET_INT_ARR_START + (i << 2);
+ REQUIRE(sk.get_compact_serialization_bytes() == expected);
+ expected = HllUtil<>::HASH_SET_INT_ARR_START + (4 << HllUtil<>::LG_INIT_SET_SIZE);
+ REQUIRE(sk.get_updatable_serialization_bytes() == expected);
+}
+
+TEST_CASE("hll sketch: check ser sizes", "[hll_sketch]") {
+ checkSerializationSizes(8, HLL_8);
+ checkSerializationSizes(8, HLL_6);
+ checkSerializationSizes(8, HLL_4);
+}
+
+TEST_CASE("hll sketch: exercise to string", "[hll_sketch]") {
+ hll_sketch sk(15, HLL_4);
+ for (int i = 0; i < 25; ++i) { sk.update(i); }
+ std::ostringstream oss(std::ios::binary);
+ sk.to_string(oss, false, true, true, true);
+ for (int i = 25; i < (1 << 20); ++i) { sk.update(i); }
+ sk.to_string(oss, false, true, true, true);
+ sk.to_string(oss, false, true, true, false);
+
+ sk = hll_sketch(8, HLL_8);
+ for (int i = 0; i < 25; ++i) { sk.update(i); }
+ sk.to_string(oss, false, true, true, true);
+}
+
+// Creates and serializes then deserializes sketch.
+// Returns true if deserialized sketch is compact.
+static bool checkCompact(const int lgK, const int n, const target_hll_type type, bool compact) {
+ hll_sketch sk(lgK, type);
+ for (int i = 0; i < n; ++i) { sk.update(i); }
+
+ std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
+ if (compact) {
+ sk.serialize_compact(ss);
+ REQUIRE(ss.tellp() == sk.get_compact_serialization_bytes());
+ } else {
+ sk.serialize_updatable(ss);
+ REQUIRE(ss.tellp() == sk.get_updatable_serialization_bytes());
}
+
+ hll_sketch sk2 = hll_sketch::deserialize(ss);
+ REQUIRE(sk2.get_estimate() == Approx(n).margin(0.01));
+ bool isCompact = sk2.is_compact();
+
+ return isCompact;
+}
+
+TEST_CASE("hll sketch: check compact flag", "[hll_sketch]") {
+ int lgK = 8;
+ // unless/until we create non-updatable "direct" versions,
+ // deserialized image should never be compact
+ // LIST: follows serialization request
+ REQUIRE(checkCompact(lgK, 7, HLL_8, false) == false);
+ REQUIRE(checkCompact(lgK, 7, HLL_8, true) == false);
+
+ // SET: follows serialization request
+ REQUIRE(checkCompact(lgK, 24, HLL_8, false) == false);
+ REQUIRE(checkCompact(lgK, 24, HLL_8, true) == false);
+
+ // HLL8: always updatable
+ REQUIRE(checkCompact(lgK, 25, HLL_8, false) == false);
+ REQUIRE(checkCompact(lgK, 25, HLL_8, true) == false);
+
+ // HLL6: always updatable
+ REQUIRE(checkCompact(lgK, 25, HLL_6, false) == false);
+ REQUIRE(checkCompact(lgK, 25, HLL_6, true) == false);
+
+ // HLL4: follows serialization request
+ REQUIRE(checkCompact(lgK, 25, HLL_4, false) == false);
+ REQUIRE(checkCompact(lgK, 25, HLL_4, true) == false);
+}
+
+TEST_CASE("hll sketch: check k limits", "[hll_sketch]") {
+ hll_sketch sketch1(HllUtil<>::MIN_LOG_K, target_hll_type::HLL_8);
+ hll_sketch sketch2(HllUtil<>::MAX_LOG_K, target_hll_type::HLL_4);
+ REQUIRE_THROWS_AS(hll_sketch(HllUtil<>::MIN_LOG_K - 1), std::invalid_argument);
+
+ REQUIRE_THROWS_AS(hll_sketch(HllUtil<>::MAX_LOG_K + 1), std::invalid_argument);
+}
+
+TEST_CASE("hll sketch: check input types", "[hll_sketch]") {
+ hll_sketch sk(8, target_hll_type::HLL_8);
+
+ // inserting the same value as a variety of input types
+ sk.update((uint8_t) 102);
+ sk.update((uint16_t) 102);
+ sk.update((uint32_t) 102);
+ sk.update((uint64_t) 102);
+ sk.update((int8_t) 102);
+ sk.update((int16_t) 102);
+ sk.update((int32_t) 102);
+ sk.update((int64_t) 102);
+ REQUIRE(sk.get_estimate() == Approx(1.0).margin(0.01));
+
+ // identical binary representations
+ // no unsigned in Java, but need to sign-extend both as Java would do
+ sk.update((uint8_t) 255);
+ sk.update((int8_t) -1);
+
+ sk.update((float) -2.0);
+ sk.update((double) -2.0);
+
+ std::string str = "input string";
+ sk.update(str);
+ sk.update(str.c_str(), str.length());
+ REQUIRE(sk.get_estimate() == Approx(4.0).margin(0.01));
+
+ sk = hll_sketch(8, target_hll_type::HLL_6);
+ sk.update((float) 0.0);
+ sk.update((float) -0.0);
+ sk.update((double) 0.0);
+ sk.update((double) -0.0);
+ REQUIRE(sk.get_estimate() == Approx(1.0).margin(0.01));
+
+ sk = hll_sketch(8, target_hll_type::HLL_4);
+ sk.update(std::nanf("3"));
+ sk.update(std::nan("9"));
+ REQUIRE(sk.get_estimate() == Approx(1.0).margin(0.01));
+
+ sk = hll_sketch(8, target_hll_type::HLL_4);
+ sk.update(nullptr, 0);
+ sk.update("");
+ REQUIRE(sk.is_empty());
+}
-};
-CPPUNIT_TEST_SUITE_REGISTRATION(hllSketchTest);
} /* namespace datasketches */
diff --git a/hll/test/HllUnionTest.cpp b/hll/test/HllUnionTest.cpp
index a6481a6..23bdd1c 100644
--- a/hll/test/HllUnionTest.cpp
+++ b/hll/test/HllUnionTest.cpp
@@ -17,394 +17,369 @@
* under the License.
*/
-#include "hll.hpp"
+#include <catch.hpp>
+#include <sstream>
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include "hll.hpp"
namespace datasketches {
-class HllUnionTest : public CppUnit::TestFixture {
-
- // list of values defined at bottom of file
- static const int nArr[]; // = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
-
- CPPUNIT_TEST_SUITE(HllUnionTest);
- CPPUNIT_TEST(checkUnions);
- CPPUNIT_TEST(checkToFrom);
- CPPUNIT_TEST(checkCompositeEstimate);
- CPPUNIT_TEST(checkConfigKLimits);
- CPPUNIT_TEST(checkUbLb);
- CPPUNIT_TEST(checkConversions);
- CPPUNIT_TEST(checkMisc);
- CPPUNIT_TEST(checkInputTypes);
- CPPUNIT_TEST(check_hll_to_hll);
- CPPUNIT_TEST_SUITE_END();
-
- int min(int a, int b) {
- return (a < b) ? a : b;
- }
-
- void println(std::string& str) {
- //std::cout << str << "\n";
- }
-
- /**
- * The task here is to check the transition boundaries as the sketch morphs between LIST to
- * SET to HLL modes. The transition points vary as a function of lgConfigK. In addition,
- * this checks that the union operation is operating properly based on the order the
- * sketches are presented to the union.
- */
- void checkUnions() {
- target_hll_type type1 = HLL_8;
- target_hll_type type2 = HLL_8;
- target_hll_type resultType = HLL_8;
-
- uint64_t lgK1 = 7;
- uint64_t lgK2 = 7;
- uint64_t lgMaxK = 7;
- uint64_t n1 = 7;
- uint64_t n2 = 7;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 = 8;
- n2 = 7;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 = 7;
- n2 = 8;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 = 8;
- n2 = 8;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 = 7;
- n2 = 14;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
-
- int i = 0;
- for (i = 7; i <= 13; ++i) {
- lgK1 = i;
- lgK2 = i;
- lgMaxK = i;
- {
- n1 = ((1 << (i - 3)) * 3)/4; // compute the transition point
- n2 = n1;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 -= 2;
- n2 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- }
- lgK1 = i;
- lgK2 = i + 1;
- lgMaxK = i;
- {
- n1 = ((1 << (i - 3)) * 3)/4;
- n2 = n1;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 -= 2;
- n2 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- }
- lgK1 = i + 1;
- lgK2 = i;
- lgMaxK = i;
- {
- n1 = ((1 << (i - 3)) * 3)/4;
- n2 = n1;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 -= 2;
- n2 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- }
- lgK1 = i + 1;
- lgK2 = i + 1;
- lgMaxK = i;
- {
- n1 = ((1 << (i - 3)) * 3)/4;
- n2 = n1;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 -= 2;
- n2 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- n1 += 2;
- basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
- }
- }
- }
+static const int nArr[] = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
- void basicUnion(uint64_t n1, uint64_t n2,
- uint64_t lgk1, uint64_t lgk2, uint64_t lgMaxK,
- target_hll_type type1, target_hll_type type2, target_hll_type resultType) {
- uint64_t v = 0;
- //int tot = n1 + n2;
+static int min(int a, int b) {
+ return (a < b) ? a : b;
+}
- hll_sketch h1(lgk1, type1);
- hll_sketch h2(lgk2, type2);
- int lgControlK = min(min(lgk1, lgk2), lgMaxK);
- hll_sketch control(lgControlK, resultType);
+static void println(std::string& str) {
+ //std::cout << str << "\n";
+}
- for (uint64_t i = 0; i < n1; ++i) {
- h1.update(v + i);
- control.update(v + i);
- }
- v += n1;
- for (uint64_t i = 0; i < n2; ++i) {
- h2.update(v + i);
- control.update(v + i);
- }
- v += n2;
+static void basicUnion(uint64_t n1, uint64_t n2,
+ uint64_t lgk1, uint64_t lgk2, uint64_t lgMaxK,
+ target_hll_type type1, target_hll_type type2, target_hll_type resultType) {
+ uint64_t v = 0;
+ //int tot = n1 + n2;
- hll_union u(lgMaxK);
- u.update(std::move(h1));
- u.update(h2);
+ hll_sketch h1(lgk1, type1);
+ hll_sketch h2(lgk2, type2);
+ int lgControlK = min(min(lgk1, lgk2), lgMaxK);
+ hll_sketch control(lgControlK, resultType);
- hll_sketch result = u.get_result(resultType);
-
- // force non-HIP estimates to avoid issues with in- vs out-of-order
- double uEst = result.get_composite_estimate();
- double uUb = result.get_upper_bound(2);
- double uLb = result.get_lower_bound(2);
- //double rerr = ((uEst/tot) - 1.0) * 100;
-
- double controlEst = control.get_composite_estimate();
- double controlUb = control.get_upper_bound(2);
- double controlLb = control.get_lower_bound(2);
-
- CPPUNIT_ASSERT((controlUb - controlEst) >= 0.0);
- CPPUNIT_ASSERT((uUb - uEst) >= 0.0);
- CPPUNIT_ASSERT((controlEst - controlLb) >= 0.0);
- CPPUNIT_ASSERT((uEst - uLb) >= 0.0);
-
- CPPUNIT_ASSERT_DOUBLES_EQUAL(controlEst, uEst, 0.0);
+ for (uint64_t i = 0; i < n1; ++i) {
+ h1.update(v + i);
+ control.update(v + i);
}
-
- void checkToFrom() {
- for (int i = 0; i < 10; ++i) {
- int n = nArr[i];
- for (int lgK = 4; lgK <= 13; ++lgK) {
- toFrom(lgK, HLL_4, n);
- toFrom(lgK, HLL_6, n);
- toFrom(lgK, HLL_8, n);
- }
- }
+ v += n1;
+ for (uint64_t i = 0; i < n2; ++i) {
+ h2.update(v + i);
+ control.update(v + i);
}
+ v += n2;
- void checkUnionEquality(hll_union& u1, hll_union& u2) {
- hll_sketch sk1 = u1.get_result();
- hll_sketch sk2 = u2.get_result();
-
- CPPUNIT_ASSERT_EQUAL(sk1.get_lg_config_k(), sk2.get_lg_config_k());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk1.get_lower_bound(1), sk2.get_lower_bound(1), 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk1.get_estimate(), sk2.get_estimate(), 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk1.get_upper_bound(1), sk2.get_upper_bound(1), 0.0);
- CPPUNIT_ASSERT_EQUAL(sk1.get_target_type(), sk2.get_target_type());
- }
+ hll_union u(lgMaxK);
+ u.update(std::move(h1));
+ u.update(h2);
- void toFrom(const int lgConfigK, const target_hll_type tgtHllType, const int n) {
- hll_union srcU(lgConfigK);
- hll_sketch srcSk(lgConfigK, tgtHllType);
- for (int i = 0; i < n; ++i) {
- srcSk.update(i);
- }
- srcU.update(srcSk);
-
- std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
- srcU.serialize_compact(ss);
- hll_union dstU = hll_union::deserialize(ss);
- checkUnionEquality(srcU, dstU);
-
- auto bytes1 = srcU.serialize_compact();
- dstU = hll_union::deserialize(bytes1.data(), bytes1.size());
- checkUnionEquality(srcU, dstU);
-
- ss.clear();
- srcU.serialize_updatable(ss);
- dstU = hll_union::deserialize(ss);
- checkUnionEquality(srcU, dstU);
-
- auto bytes2 = srcU.serialize_updatable();
- dstU = hll_union::deserialize(bytes2.data(), bytes2.size());
- checkUnionEquality(srcU, dstU);
- }
-
- void checkCompositeEstimate() {
- hll_union u(12);
- CPPUNIT_ASSERT(u.is_empty());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, u.get_composite_estimate(), 0.03);
- for (int i = 1; i <= 15; ++i) { u.update(i); }
- CPPUNIT_ASSERT_DOUBLES_EQUAL(15.0, u.get_composite_estimate(), 15 * 0.03);
- for (int i = 16; i <= 1000; ++i) { u.update(i); }
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1000.0, u.get_composite_estimate(), 1000 * 0.03);
- }
+ hll_sketch result = u.get_result(resultType);
- void checkConfigKLimits() {
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect lgK too small",
- hll_union(HllUtil<>::MIN_LOG_K - 1),
- std::invalid_argument);
+ // force non-HIP estimates to avoid issues with in- vs out-of-order
+ double uEst = result.get_composite_estimate();
+ double uUb = result.get_upper_bound(2);
+ double uLb = result.get_lower_bound(2);
+ //double rerr = ((uEst/tot) - 1.0) * 100;
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to detect lgK too large",
- hll_union(HllUtil<>::MAX_LOG_K + 1),
- std::invalid_argument);
- }
+ double controlEst = control.get_composite_estimate();
+ double controlUb = control.get_upper_bound(2);
+ double controlLb = control.get_lower_bound(2);
- double getBound(int lgK, bool ub, bool oooFlag, int numStdDev, double est) {
- double re = RelativeErrorTables<>::getRelErr(ub, oooFlag, lgK, numStdDev);
- return est / (1.0 + re);
- }
+ REQUIRE((controlUb - controlEst) >= 0.0);
+ REQUIRE((uUb - uEst) >= 0.0);
+ REQUIRE((controlEst - controlLb) >= 0.0);
+ REQUIRE((uEst - uLb) >= 0.0);
- void checkUbLb() { // for lgK <= 12
- int lgK = 4;
- int n = 1 << 20;
- bool oooFlag = false;
-
- double bound;
- std::string str;
-
- bound = (getBound(lgK, true, oooFlag, 3, n) / n) - 1;
- str = "LgK=" + std::to_string(lgK) + ", UB3: " + std::to_string(bound);
- println(str);
- bound = (getBound(lgK, true, oooFlag, 2, n) / n) - 1;
- str = "LgK=" + std::to_string(lgK) + ", UB2: " + std::to_string(bound);
- println(str);
- bound = (getBound(lgK, true, oooFlag, 1, n) / n) - 1;
- str = "LgK=" + std::to_string(lgK) + ", UB1: " + std::to_string(bound);
- println(str);
- bound = (getBound(lgK, false, oooFlag, 1, n) / n) - 1;
- str = "LgK=" + std::to_string(lgK) + ", LB1: " + std::to_string(bound);
- println(str);
- bound = (getBound(lgK, false, oooFlag, 2, n) / n) - 1;
- str = "LgK=" + std::to_string(lgK) + ", LB2: " + std::to_string(bound);
- println(str);
- bound = (getBound(lgK, false, oooFlag, 3, n) / n) - 1;
- str = "LgK=" + std::to_string(lgK) + ", LB3: " + std::to_string(bound);
- println(str);
- }
+ REQUIRE(controlEst == uEst);
+}
- void checkConversions() {
- int lgK = 4;
- hll_sketch sk1(lgK, HLL_8);
- hll_sketch sk2(lgK, HLL_8);
- int n = 1 << 20;
- for (int i = 0; i < n; ++i) {
- sk1.update(i);
- sk2.update(i + n);
+/**
+ * The task here is to check the transition boundaries as the sketch morphs between LIST to
+ * SET to HLL modes. The transition points vary as a function of lgConfigK. In addition,
+ * this checks that the union operation is operating properly based on the order the
+ * sketches are presented to the union.
+ */
+TEST_CASE("hll union: check unions", "[hll_union]") {
+ target_hll_type type1 = HLL_8;
+ target_hll_type type2 = HLL_8;
+ target_hll_type resultType = HLL_8;
+
+ uint64_t lgK1 = 7;
+ uint64_t lgK2 = 7;
+ uint64_t lgMaxK = 7;
+ uint64_t n1 = 7;
+ uint64_t n2 = 7;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 = 8;
+ n2 = 7;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 = 7;
+ n2 = 8;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 = 8;
+ n2 = 8;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 = 7;
+ n2 = 14;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+
+ int i = 0;
+ for (i = 7; i <= 13; ++i) {
+ lgK1 = i;
+ lgK2 = i;
+ lgMaxK = i;
+ {
+ n1 = ((1 << (i - 3)) * 3)/4; // compute the transition point
+ n2 = n1;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 -= 2;
+ n2 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ }
+ lgK1 = i;
+ lgK2 = i + 1;
+ lgMaxK = i;
+ {
+ n1 = ((1 << (i - 3)) * 3)/4;
+ n2 = n1;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 -= 2;
+ n2 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ }
+ lgK1 = i + 1;
+ lgK2 = i;
+ lgMaxK = i;
+ {
+ n1 = ((1 << (i - 3)) * 3)/4;
+ n2 = n1;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 -= 2;
+ n2 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ }
+ lgK1 = i + 1;
+ lgK2 = i + 1;
+ lgMaxK = i;
+ {
+ n1 = ((1 << (i - 3)) * 3)/4;
+ n2 = n1;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 -= 2;
+ n2 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
+ n1 += 2;
+ basicUnion(n1, n2, lgK1, lgK2, lgMaxK, type1, type2, resultType);
}
- hll_union hllUnion(lgK);
- hllUnion.update(sk1);
- hllUnion.update(sk2);
-
- hll_sketch rsk1 = hllUnion.get_result(HLL_4);
- hll_sketch rsk2 = hllUnion.get_result(HLL_6);
- hll_sketch rsk3 = hllUnion.get_result(HLL_8);
- double est1 = rsk1.get_estimate();
- double est2 = rsk2.get_estimate();
- double est3 = rsk3.get_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(est1, est2, 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(est1, est3, 0.0);
}
-
- // moved from UnionCaseTest in java
- void checkMisc() {
- hll_union u(12);
- int bytes = u.get_compact_serialization_bytes();
- CPPUNIT_ASSERT_EQUAL(8, bytes);
- bytes = hll_union::get_max_serialization_bytes(7);
- CPPUNIT_ASSERT_EQUAL(40 + 128, bytes);
- double v = u.get_estimate();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, v, 0.0);
- v = u.get_lower_bound(1);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, v, 0.0);
- v = u.get_upper_bound(1);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, v, 0.0);
- CPPUNIT_ASSERT(u.is_empty());
- u.reset();
- CPPUNIT_ASSERT(u.is_empty());
- std::ostringstream oss(std::ios::binary);
- u.serialize_compact(oss);
- CPPUNIT_ASSERT_EQUAL(8, static_cast<int>(oss.tellp()));
+}
+
+static void checkUnionEquality(hll_union& u1, hll_union& u2) {
+ hll_sketch sk1 = u1.get_result();
+ hll_sketch sk2 = u2.get_result();
+
+ REQUIRE(sk2.get_lg_config_k() == sk1.get_lg_config_k());
+ REQUIRE(sk1.get_lower_bound(1) == sk2.get_lower_bound(1));
+ REQUIRE(sk1.get_estimate() == sk2.get_estimate());
+ REQUIRE(sk1.get_upper_bound(1) == sk2.get_upper_bound(1));
+ REQUIRE(sk2.get_target_type() == sk1.get_target_type());
+}
+
+static void toFrom(const int lgConfigK, const target_hll_type tgtHllType, const int n) {
+ hll_union srcU(lgConfigK);
+ hll_sketch srcSk(lgConfigK, tgtHllType);
+ for (int i = 0; i < n; ++i) {
+ srcSk.update(i);
}
-
- void checkInputTypes() {
- hll_union u(8);
-
- // inserting the same value as a variety of input types
- u.update((uint8_t) 102);
- u.update((uint16_t) 102);
- u.update((uint32_t) 102);
- u.update((uint64_t) 102);
- u.update((int8_t) 102);
- u.update((int16_t) 102);
- u.update((int32_t) 102);
- u.update((int64_t) 102);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, u.get_estimate(), 0.01);
-
- // identical binary representations
- // no unsigned in Java, but need to sign-extend both as Java would do
- u.update((uint8_t) 255);
- u.update((int8_t) -1);
-
- u.update((float) -2.0);
- u.update((double) -2.0);
-
- std::string str = "input string";
- u.update(str);
- u.update(str.c_str(), str.length());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, u.get_estimate(), 0.01);
-
- u = hll_union(8);
- u.update((float) 0.0);
- u.update((float) -0.0);
- u.update((double) 0.0);
- u.update((double) -0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, u.get_estimate(), 0.01);
-
- u = hll_union(8);
- u.update(std::nanf("3"));
- u.update(std::nan("12"));
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, u.get_estimate(), 0.01);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(u.get_result().get_estimate(), u.get_estimate(), 0.01);
-
- u = hll_union(8);
- u.update(nullptr, 0);
- u.update("");
- CPPUNIT_ASSERT(u.is_empty());
+ srcU.update(srcSk);
+
+ std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
+ srcU.serialize_compact(ss);
+ hll_union dstU = hll_union::deserialize(ss);
+ checkUnionEquality(srcU, dstU);
+
+ auto bytes1 = srcU.serialize_compact();
+ dstU = hll_union::deserialize(bytes1.data(), bytes1.size());
+ checkUnionEquality(srcU, dstU);
+
+ ss.clear();
+ srcU.serialize_updatable(ss);
+ dstU = hll_union::deserialize(ss);
+ checkUnionEquality(srcU, dstU);
+
+ auto bytes2 = srcU.serialize_updatable();
+ dstU = hll_union::deserialize(bytes2.data(), bytes2.size());
+ checkUnionEquality(srcU, dstU);
+}
+
+TEST_CASE("hll union: check to from", "[hll_union]") {
+ for (int i = 0; i < 10; ++i) {
+ int n = nArr[i];
+ for (int lgK = 4; lgK <= 13; ++lgK) {
+ toFrom(lgK, HLL_4, n);
+ toFrom(lgK, HLL_6, n);
+ toFrom(lgK, HLL_8, n);
+ }
}
-
- void union_two_sketches_with_overlap(int num, uint8_t lg_k, target_hll_type type) {
- hll_sketch sketch1(lg_k, type);
- for (int key = 0; key < num; key++) sketch1.update(key);
-
- const int overlap = num / 2;
- hll_sketch sketch2(lg_k, type);
- for (int key = overlap; key < num + overlap; key++) sketch2.update(key);
-
- hll_union u(lg_k);
- u.update(sketch1);
- u.update(sketch2);
- hll_sketch sketch = u.get_result(type);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(num * 1.5, sketch.get_estimate(), num * 1.5 * 0.02);
+}
+
+TEST_CASE("hll union: check composite estimate", "[hll_union]") {
+ hll_union u(12);
+ REQUIRE(u.is_empty());
+ REQUIRE(u.get_composite_estimate() == Approx(0.0).margin(0.03));
+ for (int i = 1; i <= 15; ++i) { u.update(i); }
+ REQUIRE(u.get_composite_estimate() == Approx(15.0).margin(15 * 0.03));
+ for (int i = 16; i <= 1000; ++i) { u.update(i); }
+ REQUIRE(u.get_composite_estimate() == Approx(1000.0).margin(1000 * 0.03));
+}
+
+TEST_CASE("hll union: check config k limits", "[hll_union]") {
+ REQUIRE_THROWS_AS(hll_union(HllUtil<>::MIN_LOG_K - 1), std::invalid_argument);
+
+ REQUIRE_THROWS_AS(hll_union(HllUtil<>::MAX_LOG_K + 1), std::invalid_argument);
+}
+
+static double getBound(int lgK, bool ub, bool oooFlag, int numStdDev, double est) {
+ double re = RelativeErrorTables<>::getRelErr(ub, oooFlag, lgK, numStdDev);
+ return est / (1.0 + re);
+}
+
+TEST_CASE("hll union: check ub lb", "[hll_union]") {
+ int lgK = 4;
+ int n = 1 << 20;
+ bool oooFlag = false;
+
+ double bound;
+ std::string str;
+
+ bound = (getBound(lgK, true, oooFlag, 3, n) / n) - 1;
+ str = "LgK=" + std::to_string(lgK) + ", UB3: " + std::to_string(bound);
+ println(str);
+ bound = (getBound(lgK, true, oooFlag, 2, n) / n) - 1;
+ str = "LgK=" + std::to_string(lgK) + ", UB2: " + std::to_string(bound);
+ println(str);
+ bound = (getBound(lgK, true, oooFlag, 1, n) / n) - 1;
+ str = "LgK=" + std::to_string(lgK) + ", UB1: " + std::to_string(bound);
+ println(str);
+ bound = (getBound(lgK, false, oooFlag, 1, n) / n) - 1;
+ str = "LgK=" + std::to_string(lgK) + ", LB1: " + std::to_string(bound);
+ println(str);
+ bound = (getBound(lgK, false, oooFlag, 2, n) / n) - 1;
+ str = "LgK=" + std::to_string(lgK) + ", LB2: " + std::to_string(bound);
+ println(str);
+ bound = (getBound(lgK, false, oooFlag, 3, n) / n) - 1;
+ str = "LgK=" + std::to_string(lgK) + ", LB3: " + std::to_string(bound);
+ println(str);
+}
+
+TEST_CASE("hll union: check conversions", "[hll_union]") {
+ int lgK = 4;
+ hll_sketch sk1(lgK, HLL_8);
+ hll_sketch sk2(lgK, HLL_8);
+ int n = 1 << 20;
+ for (int i = 0; i < n; ++i) {
+ sk1.update(i);
+ sk2.update(i + n);
}
-
- void check_hll_to_hll() {
- union_two_sketches_with_overlap(1000000, 11, HLL_4);
- }
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(HllUnionTest);
-
-const int HllUnionTest::nArr[] = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
+ hll_union hllUnion(lgK);
+ hllUnion.update(sk1);
+ hllUnion.update(sk2);
+
+ hll_sketch rsk1 = hllUnion.get_result(HLL_4);
+ hll_sketch rsk2 = hllUnion.get_result(HLL_6);
+ hll_sketch rsk3 = hllUnion.get_result(HLL_8);
+ double est1 = rsk1.get_estimate();
+ double est2 = rsk2.get_estimate();
+ double est3 = rsk3.get_estimate();
+ REQUIRE(est1 == est2);
+ REQUIRE(est1 == est3);
+}
+
+// moved from UnionCaseTest in java
+TEST_CASE("hll union: check misc", "[hll_union]") {
+ hll_union u(12);
+ int bytes = u.get_compact_serialization_bytes();
+ REQUIRE(bytes == 8);
+ bytes = hll_union::get_max_serialization_bytes(7);
+ REQUIRE(bytes == 40 + 128);
+ double v = u.get_estimate();
+ REQUIRE(0.0 == v);
+ v = u.get_lower_bound(1);
+ REQUIRE(0.0 == v);
+ v = u.get_upper_bound(1);
+ REQUIRE(0.0 == v);
+ REQUIRE(u.is_empty());
+ u.reset();
+ REQUIRE(u.is_empty());
+ std::ostringstream oss(std::ios::binary);
+ u.serialize_compact(oss);
+ REQUIRE(static_cast<int>(oss.tellp()) == 8);
+}
+
+TEST_CASE("hll union: check input types", "[hll_union]") {
+ hll_union u(8);
+
+ // inserting the same value as a variety of input types
+ u.update((uint8_t) 102);
+ u.update((uint16_t) 102);
+ u.update((uint32_t) 102);
+ u.update((uint64_t) 102);
+ u.update((int8_t) 102);
+ u.update((int16_t) 102);
+ u.update((int32_t) 102);
+ u.update((int64_t) 102);
+ REQUIRE(u.get_estimate() == Approx(1.0).margin(0.01));
+
+ // identical binary representations
+ // no unsigned in Java, but need to sign-extend both as Java would do
+ u.update((uint8_t) 255);
+ u.update((int8_t) -1);
+
+ u.update((float) -2.0);
+ u.update((double) -2.0);
+
+ std::string str = "input string";
+ u.update(str);
+ u.update(str.c_str(), str.length());
+ REQUIRE(u.get_estimate() == Approx(4.0).margin(0.01));
+
+ u = hll_union(8);
+ u.update((float) 0.0);
+ u.update((float) -0.0);
+ u.update((double) 0.0);
+ u.update((double) -0.0);
+ REQUIRE(u.get_estimate() == Approx(1.0).margin(0.01));
+
+ u = hll_union(8);
+ u.update(std::nanf("3"));
+ u.update(std::nan("12"));
+ REQUIRE(1.0 == Approx(u.get_estimate()).margin(0.01));
+ REQUIRE(u.get_result().get_estimate() == Approx(u.get_estimate()).margin(0.01));
+
+ u = hll_union(8);
+ u.update(nullptr, 0);
+ u.update("");
+ REQUIRE(u.is_empty());
+}
+
+static void union_two_sketches_with_overlap(int num, uint8_t lg_k, target_hll_type type) {
+ hll_sketch sketch1(lg_k, type);
+ for (int key = 0; key < num; key++) sketch1.update(key);
+
+ const int overlap = num / 2;
+ hll_sketch sketch2(lg_k, type);
+ for (int key = overlap; key < num + overlap; key++) sketch2.update(key);
+
+ hll_union u(lg_k);
+ u.update(sketch1);
+ u.update(sketch2);
+ hll_sketch sketch = u.get_result(type);
+ REQUIRE(sketch.get_estimate() == Approx(num * 1.5).margin(num * 1.5 * 0.02));
+}
+
+TEST_CASE("hll union: check hll to hll", "[hll_union]") {
+ union_two_sketches_with_overlap(1000000, 11, HLL_4);
+}
} /* namespace datasketches */
diff --git a/hll/test/IsomorphicTest.cpp b/hll/test/IsomorphicTest.cpp
index e030900..1370fb1 100644
--- a/hll/test/IsomorphicTest.cpp
+++ b/hll/test/IsomorphicTest.cpp
@@ -17,139 +17,120 @@
* under the License.
*/
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/TestAssert.h>
+#include <catch.hpp>
#include <cstdio>
#include "hll.hpp"
#include "HllUtil.hpp"
-// hex format for comparing serialized bytes
-namespace CppUnit {
-
-template<>
-struct assertion_traits<datasketches::hll_sketch::vector_bytes> {
- static bool equal(const datasketches::hll_sketch::vector_bytes& a, const datasketches::hll_sketch::vector_bytes& b) {
- return a == b;
- }
+namespace datasketches {
- static std::string toString(const datasketches::hll_sketch::vector_bytes& v) {
- std::ostringstream s;
- s << std::hex << std::setfill('0');
- int cnt = 0;
- for (uint8_t byte: v) {
- if (cnt == 8) { // insert space after each 8 bytes for readability
- s << ' ';
- cnt = 0;
- } else {
- ++cnt;
- }
- s << std::setw(2) << static_cast<int>(byte);
+// hex format for comparing serialized bytes
+static std::string toString(const datasketches::hll_sketch::vector_bytes& v) {
+ std::ostringstream s;
+ s << std::hex << std::setfill('0');
+ int cnt = 0;
+ for (uint8_t byte: v) {
+ if (cnt == 8) { // insert space after each 8 bytes for readability
+ s << ' ';
+ cnt = 0;
+ } else {
+ ++cnt;
}
- return s.str();
- }
-};
-
+ s << std::setw(2) << static_cast<int>(byte);
+ }
+ return s.str();
}
-namespace datasketches {
+// if lg_k >= 8, mode != SET!
+static int get_n(int lg_k, hll_mode mode) {
+ if (mode == LIST) return 4;
+ if (mode == SET) return 1 << (lg_k - 4);
+ return ((lg_k < 8) && (mode == HLL)) ? (1 << lg_k) : 1 << (lg_k - 3);
+}
-class IsomorphicTest : public CppUnit::TestFixture {
- long v = 0;
+static long v = 0;
- CPPUNIT_TEST_SUITE(IsomorphicTest);
- CPPUNIT_TEST(union_one_update_serialize_updatable);
- CPPUNIT_TEST(union_one_update_serialize_compact);
- CPPUNIT_TEST(convert_back_and_forth_serialize_updatable);
- CPPUNIT_TEST(convert_back_and_forth_serialize_compact);
- CPPUNIT_TEST_SUITE_END();
+static hll_sketch build_sketch(int lg_k, target_hll_type hll_type, hll_mode mode) {
+ hll_sketch sk(lg_k, hll_type);
+ int n = get_n(lg_k, mode);
+ for (int i = 0; i < n; i++) sk.update(static_cast<uint64_t>(i + v));
+ v += n;
+ return sk;
+}
- // if lg_k >= 8, mode != SET!
- static int get_n(int lg_k, hll_mode mode) {
- if (mode == LIST) return 4;
- if (mode == SET) return 1 << (lg_k - 4);
- return ((lg_k < 8) && (mode == HLL)) ? (1 << lg_k) : 1 << (lg_k - 3);
+// merges a sketch to an empty union and gets result of the same type, checks binary equivalence
+static void union_one_update(bool compact) {
+ for (int lg_k = 4; lg_k <= 21; lg_k++) { // all lg_k
+ for (int mode = 0; mode <= 2; mode++) { // List, Set, Hll
+ if ((lg_k < 8) && (mode == 1)) continue; // lg_k < 8 list transitions directly to HLL
+ for (int t = 0; t <= 2; t++) { // HLL_4, HLL_6, HLL_8
+ target_hll_type hll_type = (target_hll_type) t;
+ hll_sketch sk1 = build_sketch(lg_k, hll_type, (hll_mode) mode);
+ hll_union u(lg_k);
+ u.update(sk1);
+ hll_sketch sk2 = u.get_result(hll_type);
+ auto bytes1 = compact ? sk1.serialize_compact() : sk1.serialize_updatable();
+ auto bytes2 = compact ? sk2.serialize_compact() : sk2.serialize_updatable();
+ auto msg = "LgK=" + std::to_string(lg_k)
+ + ", Mode=" + std::to_string(mode)
+ + ", Type=" + std::to_string(hll_type)
+ + "\n" + sk1.to_string(true, true, true, true)
+ + "\n" + sk2.to_string(true, true, true, true);
+ if (bytes1 != bytes2) {
+ std::cerr << msg << std::endl;
+ REQUIRE(bytes1 == bytes2);
+ }
+ }
+ }
}
+}
- hll_sketch build_sketch(int lg_k, target_hll_type hll_type, hll_mode mode) {
- hll_sketch sk(lg_k, hll_type);
- int n = get_n(lg_k, mode);
- for (int i = 0; i < n; i++) sk.update(static_cast<uint64_t>(i + v));
- v += n;
- return sk;
- }
+TEST_CASE("hll isomorphic: union one update serialize updatable", "[hll_isomorphic]") {
+ union_one_update(false);
+}
+
+TEST_CASE("hll isomorphic: union one update serialize compact", "[hll_isomorphic]") {
+ union_one_update(true);
+}
- // merges a sketch to an empty union and gets result of the same type, checks binary equivalence
- void union_one_update(bool compact) {
- for (int lg_k = 4; lg_k <= 21; lg_k++) { // all lg_k
- for (int mode = 0; mode <= 2; mode++) { // List, Set, Hll
- if ((lg_k < 8) && (mode == 1)) continue; // lg_k < 8 list transitions directly to HLL
- for (int t = 0; t <= 2; t++) { // HLL_4, HLL_6, HLL_8
- target_hll_type hll_type = (target_hll_type) t;
- hll_sketch sk1 = build_sketch(lg_k, hll_type, (hll_mode) mode);
- hll_union u(lg_k);
- u.update(sk1);
- hll_sketch sk2 = u.get_result(hll_type);
- auto bytes1 = compact ? sk1.serialize_compact() : sk1.serialize_updatable();
+// converts a sketch to a different type and converts back to the original type to check binary equivalence
+static void convert_back_and_forth(bool compact) {
+ for (int lg_k = 4; lg_k <= 21; lg_k++) { // all lg_k
+ for (int mode = 0; mode <= 2; mode++) { // List, Set, Hll
+ if ((lg_k < 8) && (mode == 1)) continue; // lg_k < 8 list transitions directly to HLL
+ for (int t1 = 0; t1 <= 2; t1++) { // HLL_4, HLL_6, HLL_8
+ target_hll_type hll_type1 = (target_hll_type) t1;
+ hll_sketch sk1 = build_sketch(lg_k, hll_type1, (hll_mode) mode);
+ auto bytes1 = compact ? sk1.serialize_compact() : sk1.serialize_updatable();
+ for (int t2 = 0; t2 <= 2; t2++) { // HLL_4, HLL_6, HLL_8
+ if (t2 == t1) continue;
+ target_hll_type hll_type2 = (target_hll_type) t2;
+ hll_sketch sk2(hll_sketch(sk1, hll_type2), hll_type1);
auto bytes2 = compact ? sk2.serialize_compact() : sk2.serialize_updatable();
auto msg = "LgK=" + std::to_string(lg_k)
+ ", Mode=" + std::to_string(mode)
- + ", Type=" + std::to_string(hll_type)
+ + ", Type1=" + std::to_string(hll_type1)
+ + ", Type2=" + std::to_string(hll_type2)
+ "\n" + sk1.to_string(true, true, true, true)
+ "\n" + sk2.to_string(true, true, true, true);
- CPPUNIT_ASSERT_EQUAL_MESSAGE(msg, bytes1, bytes2);
- }
- }
- }
- }
-
- void union_one_update_serialize_updatable() {
- union_one_update(false);
- }
-
- void union_one_update_serialize_compact() {
- union_one_update(true);
- }
-
- // converts a sketch to a different type and converts back to the original type to check binary equivalence
- void convert_back_and_forth(bool compact) {
- for (int lg_k = 4; lg_k <= 21; lg_k++) { // all lg_k
- for (int mode = 0; mode <= 2; mode++) { // List, Set, Hll
- if ((lg_k < 8) && (mode == 1)) continue; // lg_k < 8 list transitions directly to HLL
- for (int t1 = 0; t1 <= 2; t1++) { // HLL_4, HLL_6, HLL_8
- target_hll_type hll_type1 = (target_hll_type) t1;
- hll_sketch sk1 = build_sketch(lg_k, hll_type1, (hll_mode) mode);
- auto bytes1 = compact ? sk1.serialize_compact() : sk1.serialize_updatable();
- for (int t2 = 0; t2 <= 2; t2++) { // HLL_4, HLL_6, HLL_8
- if (t2 == t1) continue;
- target_hll_type hll_type2 = (target_hll_type) t2;
- hll_sketch sk2(hll_sketch(sk1, hll_type2), hll_type1);
- auto bytes2 = compact ? sk2.serialize_compact() : sk2.serialize_updatable();
- auto msg = "LgK=" + std::to_string(lg_k)
- + ", Mode=" + std::to_string(mode)
- + ", Type1=" + std::to_string(hll_type1)
- + ", Type2=" + std::to_string(hll_type2)
- + "\n" + sk1.to_string(true, true, true, true)
- + "\n" + sk2.to_string(true, true, true, true);
- CPPUNIT_ASSERT_EQUAL_MESSAGE(msg, bytes1, bytes2);
+ if (bytes1 != bytes2) {
+ std::cerr << msg << std::endl;
+ REQUIRE(bytes1 == bytes2);
}
}
}
}
}
+}
- void convert_back_and_forth_serialize_updatable() {
- convert_back_and_forth(false);
- }
-
- void convert_back_and_forth_serialize_compact() {
- convert_back_and_forth(true);
- }
-
-};
+TEST_CASE("hll isomorphic: convert back and forth serialize updatable", "[hll_isomorphic]") {
+ convert_back_and_forth(false);
+}
-CPPUNIT_TEST_SUITE_REGISTRATION(IsomorphicTest);
+TEST_CASE("hll isomorphic: convert back and forth serialize compact", "[hll_isomorphic]") {
+ convert_back_and_forth(true);
+}
} /* namespace datasketches */
diff --git a/hll/test/TablesTest.cpp b/hll/test/TablesTest.cpp
index 15b13cc..aee0e9d 100644
--- a/hll/test/TablesTest.cpp
+++ b/hll/test/TablesTest.cpp
@@ -17,43 +17,28 @@
* under the License.
*/
-#include "CubicInterpolation.hpp"
-
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
-
-namespace datasketches {
-
-class TablesTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(TablesTest);
- CPPUNIT_TEST(interpolationException);
- CPPUNIT_TEST(checkCornerCase);
- CPPUNIT_TEST_SUITE_END();
+#include <catch.hpp>
- void interpolationException() {
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to throw with x = -1.0",
- CubicInterpolation<>::usingXAndYTables(-1.0),
- std::invalid_argument);
-
- CPPUNIT_ASSERT_THROW_MESSAGE("Failed to throw with x = 1e12",
- CubicInterpolation<>::usingXAndYTables(1e12),
- std::invalid_argument);
- }
-
- void checkCornerCase() {
- int len = 10;
- double xArr[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
- double yArr[] = {2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0};
- double x = xArr[len - 1];
- double y = CubicInterpolation<>::usingXAndYTables(xArr, yArr, len, x);
- double yExp = yArr[len - 1];
- CPPUNIT_ASSERT_DOUBLES_EQUAL(yExp, y, 0.0);
- }
+#include "CubicInterpolation.hpp"
-};
+namespace datasketches {
-CPPUNIT_TEST_SUITE_REGISTRATION(TablesTest);
+TEST_CASE("hll tables: interpolation exception", "[hll_tables]") {
+ REQUIRE_THROWS_AS(CubicInterpolation<>::usingXAndYTables(-1.0), std::invalid_argument);
+
+ REQUIRE_THROWS_AS(CubicInterpolation<>::usingXAndYTables(1e12), std::invalid_argument);
+}
+
+TEST_CASE("hll tables: check corner case", "[hll_tables]") {
+ int len = 10;
+ double xArr[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
+ double yArr[] = {2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0};
+ double x = xArr[len - 1];
+ double y = CubicInterpolation<>::usingXAndYTables(xArr, yArr, len, x);
+ double yExp = yArr[len - 1];
+ REQUIRE(y == yExp);
+}
} /* namespace datasketches */
diff --git a/hll/test/ToFromByteArrayTest.cpp b/hll/test/ToFromByteArrayTest.cpp
index 5837ffa..db00731 100644
--- a/hll/test/ToFromByteArrayTest.cpp
+++ b/hll/test/ToFromByteArrayTest.cpp
@@ -17,167 +17,152 @@
* under the License.
*/
-#include "hll.hpp"
+#include <catch.hpp>
+#include <fstream>
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include "hll.hpp"
namespace datasketches {
-class ToFromByteArrayTest : public CppUnit::TestFixture {
-
- // list of values defined at bottom of file
- static const int nArr[]; // = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
-
- CPPUNIT_TEST_SUITE(ToFromByteArrayTest);
- CPPUNIT_TEST(deserializeFromJava);
- CPPUNIT_TEST(toFromSketch);
- CPPUNIT_TEST(doubleSerialize);
- CPPUNIT_TEST_SUITE_END();
-
- void doubleSerialize() {
- hll_sketch sk(9, HLL_8);
- for (int i = 0; i < 1024; ++i) {
- sk.update(i);
- }
-
- std::stringstream ss1;
- sk.serialize_updatable(ss1);
- auto ser1 = sk.serialize_updatable();
+static const int nArr[] = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
- std::stringstream ss;
- sk.serialize_updatable(ss);
- std::string str = ss.str();
+TEST_CASE("hll to/from byte array: double serialize", "[hll_byte_array]") {
+ hll_sketch sk(9, HLL_8);
+ for (int i = 0; i < 1024; ++i) {
+ sk.update(i);
+ }
+
+ std::stringstream ss1;
+ sk.serialize_updatable(ss1);
+ auto ser1 = sk.serialize_updatable();
+ std::stringstream ss;
+ sk.serialize_updatable(ss);
+ std::string str = ss.str();
- hll_sketch sk2 = hll_sketch::deserialize(ser1.data(), ser1.size());
- auto ser2 = sk.serialize_updatable();
+ hll_sketch sk2 = hll_sketch::deserialize(ser1.data(), ser1.size());
+ auto ser2 = sk.serialize_updatable();
- CPPUNIT_ASSERT_EQUAL(ser1.size(), ser2.size());
- int len = ser1.size();
- uint8_t* b1 = ser1.data();
- uint8_t* b2 = ser2.data();
+ REQUIRE(ser1.size() == ser2.size());
+ int len = ser1.size();
+ uint8_t* b1 = ser1.data();
+ uint8_t* b2 = ser2.data();
- for (int i = 0; i < len; ++i) {
- CPPUNIT_ASSERT_EQUAL(b1[i], b2[i]);
- }
+ for (int i = 0; i < len; ++i) {
+ REQUIRE(b2[i] == b1[i]);
}
+}
- void deserializeFromJava() {
- std::string inputPath;
+TEST_CASE("hll to/from byte array: deserialize from java", "[hll_byte_array]") {
+ std::string inputPath;
#ifdef TEST_BINARY_INPUT_PATH
- inputPath = TEST_BINARY_INPUT_PATH;
+ inputPath = TEST_BINARY_INPUT_PATH;
#else
- inputPath = "test/";
+ inputPath = "test/";
#endif
- std::ifstream ifs;
- ifs.open(inputPath + "list_from_java.bin", std::ios::binary);
- hll_sketch sk = hll_sketch::deserialize(ifs);
- CPPUNIT_ASSERT(sk.is_empty() == false);
- CPPUNIT_ASSERT_EQUAL(sk.get_lg_config_k(), 8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_lower_bound(1), 7.0, 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_estimate(), 7.0, 1e-6); // java: 7.000000104308129
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_upper_bound(1), 7.000350, 1e-5); // java: 7.000349609067664
- ifs.close();
-
- ifs.open(inputPath + "compact_set_from_java.bin", std::ios::binary);
- sk = hll_sketch::deserialize(ifs);
- CPPUNIT_ASSERT(sk.is_empty() == false);
- CPPUNIT_ASSERT_EQUAL(sk.get_lg_config_k(), 8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_lower_bound(1), 24.0, 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_estimate(), 24.0, 1e-5); // java: 24.00000137090692
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_upper_bound(1), 24.001200, 1e-5); // java: 24.0011996729902
- ifs.close();
-
- ifs.open(inputPath + "updatable_set_from_java.bin", std::ios::binary);
- sk = hll_sketch::deserialize(ifs);
- CPPUNIT_ASSERT(sk.is_empty() == false);
- CPPUNIT_ASSERT_EQUAL(sk.get_lg_config_k(), 8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_lower_bound(1), 24.0, 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_estimate(), 24.0, 1e-5); // java: 24.00000137090692
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_upper_bound(1), 24.001200, 1e-5); // java: 24.0011996729902
- ifs.close();
-
-
- ifs.open(inputPath + "array6_from_java.bin", std::ios::binary);
- sk = hll_sketch::deserialize(ifs);
- CPPUNIT_ASSERT(sk.is_empty() == false);
- CPPUNIT_ASSERT_EQUAL(sk.get_lg_config_k(), 8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_lower_bound(1), 9589.968564, 1e-5); // java: 9589.968564432073
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_estimate(), 10089.150211, 1e-5); // java: 10089.1502113328
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_upper_bound(1), 10642.370492, 1e-5); // java: 10642.370491998483
- ifs.close();
-
-
- ifs.open(inputPath + "compact_array4_from_java.bin", std::ios::binary);
- sk = hll_sketch::deserialize(ifs);
- CPPUNIT_ASSERT(sk.is_empty() == false);
- CPPUNIT_ASSERT_EQUAL(sk.get_lg_config_k(), 8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_lower_bound(1), 9589.968564, 1e-5); // java: 9589.968564432073
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_estimate(), 10089.150211, 1e-5); // java: 10089.1502113328
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_upper_bound(1), 10642.370492, 1e-5); // java: 10642.370491998483
-
- ifs.close();
-
-
- ifs.open(inputPath + "updatable_array4_from_java.bin", std::ios::binary);
- sk = hll_sketch::deserialize(ifs);
- CPPUNIT_ASSERT(sk.is_empty() == false);
- CPPUNIT_ASSERT_EQUAL(sk.get_lg_config_k(), 8);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_lower_bound(1), 9589.968564, 1e-5); // java: 9589.968564432073
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_estimate(), 10089.150211, 1e-5); // java: 10089.1502113328
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk.get_upper_bound(1), 10642.370492, 1e-5); // java: 10642.370491998483
- ifs.close();
- }
-
- void toFrom(const int lgConfigK, const target_hll_type tgtHllType, const int n) {
- hll_sketch src(lgConfigK, tgtHllType);
- for (int i = 0; i < n; ++i) {
- src.update(i);
- }
-
- std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
- src.serialize_compact(ss);
- hll_sketch dst = hll_sketch::deserialize(ss);
- checkSketchEquality(src, dst);
-
- auto bytes1 = src.serialize_compact();
- dst = hll_sketch::deserialize(bytes1.data(), bytes1.size());
- checkSketchEquality(src, dst);
-
- ss.clear();
- src.serialize_updatable(ss);
- dst = hll_sketch::deserialize(ss);
- checkSketchEquality(src, dst);
-
- auto bytes2 = src.serialize_updatable();
- dst = hll_sketch::deserialize(bytes2.data(), bytes2.size());
- checkSketchEquality(src, dst);
- }
-
- void checkSketchEquality(hll_sketch& sk1, hll_sketch& sk2) {
- CPPUNIT_ASSERT_EQUAL(sk1.get_lg_config_k(), sk2.get_lg_config_k());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk1.get_lower_bound(1), sk2.get_lower_bound(1), 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk1.get_estimate(), sk2.get_estimate(), 0.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(sk1.get_upper_bound(1), sk2.get_upper_bound(1), 0.0);
- CPPUNIT_ASSERT_EQUAL(sk1.get_target_type(), sk2.get_target_type());
+ std::ifstream ifs;
+ ifs.open(inputPath + "list_from_java.bin", std::ios::binary);
+ hll_sketch sk = hll_sketch::deserialize(ifs);
+ REQUIRE(sk.is_empty() == false);
+ REQUIRE(sk.get_lg_config_k() == 8);
+ REQUIRE(sk.get_lower_bound(1) == 7.0);
+ REQUIRE(sk.get_estimate() == Approx(7.0).margin(1e-6));
+ REQUIRE(sk.get_upper_bound(1) == Approx(7.000350).margin(1e-5));
+ ifs.close();
+
+ ifs.open(inputPath + "compact_set_from_java.bin", std::ios::binary);
+ sk = hll_sketch::deserialize(ifs);
+ REQUIRE(sk.is_empty() == false);
+ REQUIRE(sk.get_lg_config_k() == 8);
+ REQUIRE(sk.get_lower_bound(1) == 24.0);
+ REQUIRE(sk.get_estimate() == Approx(24.0).margin(1e-5));
+ REQUIRE(sk.get_upper_bound(1) == Approx(24.001200).margin(1e-5));
+ ifs.close();
+
+ ifs.open(inputPath + "updatable_set_from_java.bin", std::ios::binary);
+ sk = hll_sketch::deserialize(ifs);
+ REQUIRE(sk.is_empty() == false);
+ REQUIRE(sk.get_lg_config_k() == 8);
+ REQUIRE(sk.get_lower_bound(1) == 24.0);
+ REQUIRE(sk.get_estimate() == Approx(24.0).margin(1e-5));
+ REQUIRE(sk.get_upper_bound(1) == Approx(24.001200).margin(1e-5));
+ ifs.close();
+
+
+ ifs.open(inputPath + "array6_from_java.bin", std::ios::binary);
+ sk = hll_sketch::deserialize(ifs);
+ REQUIRE(sk.is_empty() == false);
+ REQUIRE(sk.get_lg_config_k() == 8);
+ REQUIRE(sk.get_lower_bound(1) == Approx(9589.968564).margin(1e-5));
+ REQUIRE(sk.get_estimate() == Approx(10089.150211).margin(1e-5));
+ REQUIRE(sk.get_upper_bound(1) == Approx(10642.370492).margin(1e-5));
+ ifs.close();
+
+
+ ifs.open(inputPath + "compact_array4_from_java.bin", std::ios::binary);
+ sk = hll_sketch::deserialize(ifs);
+ REQUIRE(sk.is_empty() == false);
+ REQUIRE(sk.get_lg_config_k() == 8);
+ REQUIRE(sk.get_lower_bound(1) == Approx(9589.968564).margin(1e-5));
+ REQUIRE(sk.get_estimate() == Approx(10089.150211).margin(1e-5));
+ REQUIRE(sk.get_upper_bound(1) == Approx(10642.370492).margin(1e-5));
+
+ ifs.close();
+
+
+ ifs.open(inputPath + "updatable_array4_from_java.bin", std::ios::binary);
+ sk = hll_sketch::deserialize(ifs);
+ REQUIRE(sk.is_empty() == false);
+ REQUIRE(sk.get_lg_config_k() == 8);
+ REQUIRE(sk.get_lower_bound(1) == Approx(9589.968564).margin(1e-5));
+ REQUIRE(sk.get_estimate() == Approx(10089.150211).margin(1e-5));
+ REQUIRE(sk.get_upper_bound(1) == Approx(10642.370492).margin(1e-5));
+ ifs.close();
+}
+
+static void checkSketchEquality(hll_sketch& sk1, hll_sketch& sk2) {
+ REQUIRE(sk1.get_lg_config_k() == sk2.get_lg_config_k());
+ REQUIRE(sk1.get_lower_bound(1) == sk2.get_lower_bound(1));
+ REQUIRE(sk1.get_estimate() == sk2.get_estimate());
+ REQUIRE(sk1.get_upper_bound(1) == sk2.get_upper_bound(1));
+ REQUIRE(sk1.get_target_type() == sk2.get_target_type());
+}
+
+static void toFrom(const int lgConfigK, const target_hll_type tgtHllType, const int n) {
+ hll_sketch src(lgConfigK, tgtHllType);
+ for (int i = 0; i < n; ++i) {
+ src.update(i);
}
- void toFromSketch() {
- for (int i = 0; i < 10; ++i) {
- int n = nArr[i];
- for (int lgK = 4; lgK <= 13; ++lgK) {
- toFrom(lgK, HLL_4, n);
- toFrom(lgK, HLL_6, n);
- toFrom(lgK, HLL_8, n);
- }
+ std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
+ src.serialize_compact(ss);
+ hll_sketch dst = hll_sketch::deserialize(ss);
+ checkSketchEquality(src, dst);
+
+ auto bytes1 = src.serialize_compact();
+ dst = hll_sketch::deserialize(bytes1.data(), bytes1.size());
+ checkSketchEquality(src, dst);
+
+ ss.clear();
+ src.serialize_updatable(ss);
+ dst = hll_sketch::deserialize(ss);
+ checkSketchEquality(src, dst);
+
+ auto bytes2 = src.serialize_updatable();
+ dst = hll_sketch::deserialize(bytes2.data(), bytes2.size());
+ checkSketchEquality(src, dst);
+}
+
+TEST_CASE("hll to/from byte array: to from sketch", "[hll_byte_array]") {
+ for (int i = 0; i < 10; ++i) {
+ int n = nArr[i];
+ for (int lgK = 4; lgK <= 13; ++lgK) {
+ toFrom(lgK, HLL_4, n);
+ toFrom(lgK, HLL_6, n);
+ toFrom(lgK, HLL_8, n);
}
}
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(ToFromByteArrayTest);
-
-const int ToFromByteArrayTest::nArr[] = {1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000};
+}
} /* namespace datasketches */
diff --git a/kll/test/CMakeLists.txt b/kll/test/CMakeLists.txt
index fc18587..61747c2 100644
--- a/kll/test/CMakeLists.txt
+++ b/kll/test/CMakeLists.txt
@@ -17,7 +17,7 @@
add_executable(kll_test)
-target_link_libraries(kll_test kll catch_test)
+target_link_libraries(kll_test kll common_test)
set_target_properties(kll_test PROPERTIES
CXX_STANDARD 11
@@ -41,8 +41,3 @@ target_sources(kll_test
kll_sketch_custom_type_test.cpp
kll_sketch_validation.cpp
)
-
-target_include_directories(kll_test
- PRIVATE
- ../../common/test
-)
diff --git a/sampling/test/CMakeLists.txt b/sampling/test/CMakeLists.txt
index a921d1f..886abb3 100644
--- a/sampling/test/CMakeLists.txt
+++ b/sampling/test/CMakeLists.txt
@@ -17,7 +17,7 @@
add_executable(sampling_test)
-target_link_libraries(sampling_test sampling catch_test)
+target_link_libraries(sampling_test sampling common_test)
set_target_properties(sampling_test PROPERTIES
CXX_STANDARD 11
@@ -40,8 +40,3 @@ target_sources(sampling_test
var_opt_sketch_test.cpp
var_opt_union_test.cpp
)
-
-target_include_directories(sampling_test
- PRIVATE
- ../../common/test
-)
diff --git a/theta/test/theta_a_not_b_test.cpp b/theta/test/theta_a_not_b_test.cpp
index cb7efdd..54bd3fa 100644
--- a/theta/test/theta_a_not_b_test.cpp
+++ b/theta/test/theta_a_not_b_test.cpp
@@ -17,223 +17,204 @@
* under the License.
*/
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
#include <theta_a_not_b.hpp>
namespace datasketches {
-class theta_a_not_b_test: public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(theta_a_not_b_test);
- CPPUNIT_TEST(empty);
- CPPUNIT_TEST(non_empty_no_retained_keys);
- CPPUNIT_TEST(exact_mode_half_overlap);
- CPPUNIT_TEST(exact_mode_disjoint);
- CPPUNIT_TEST(exact_mode_full_overlap);
- CPPUNIT_TEST(estimation_mode_half_overlap);
- CPPUNIT_TEST(estimation_mode_disjoint);
- CPPUNIT_TEST(estimation_mode_full_overlap);
- CPPUNIT_TEST(seed_mismatch);
- CPPUNIT_TEST_SUITE_END();
-
- void empty() {
- theta_a_not_b a_not_b;
- update_theta_sketch a = update_theta_sketch::builder().build();
- update_theta_sketch b = update_theta_sketch::builder().build();
- compact_theta_sketch result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT_EQUAL(0U, result.get_num_retained());
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void non_empty_no_retained_keys() {
- update_theta_sketch a = update_theta_sketch::builder().build();
- a.update(1);
- update_theta_sketch b = update_theta_sketch::builder().set_p(0.001).build();
- theta_a_not_b a_not_b;
-
- // B is still empty
- compact_theta_sketch result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1U, result.get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result.get_theta(), 1e-10);
- CPPUNIT_ASSERT_EQUAL(1.0, result.get_estimate());
-
- // B is not empty in estimation mode and no entries
- b.update(1);
- CPPUNIT_ASSERT_EQUAL(0U, b.get_num_retained());
-
- result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0U, result.get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.001, result.get_theta(), 1e-10);
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void exact_mode_half_overlap() {
- update_theta_sketch a = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) a.update(value++);
-
- update_theta_sketch b = update_theta_sketch::builder().build();
- value = 500;
- for (int i = 0; i < 1000; i++) b.update(value++);
-
- theta_a_not_b a_not_b;
-
- // unordered inputs, ordered result
- compact_theta_sketch result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT(result.is_ordered());
- CPPUNIT_ASSERT_EQUAL(500.0, result.get_estimate());
-
- // unordered inputs, unordered result
- result = a_not_b.compute(a, b, false);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT(!result.is_ordered());
- CPPUNIT_ASSERT_EQUAL(500.0, result.get_estimate());
-
- // ordered inputs
- result = a_not_b.compute(a.compact(), b.compact());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT(result.is_ordered());
- CPPUNIT_ASSERT_EQUAL(500.0, result.get_estimate());
-
- // A is ordered, so the result is ordered regardless
- result = a_not_b.compute(a.compact(), b, false);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT(result.is_ordered());
- CPPUNIT_ASSERT_EQUAL(500.0, result.get_estimate());
+TEST_CASE("theta a-not-b: empty", "[theta_a_not_b]") {
+ theta_a_not_b a_not_b;
+ update_theta_sketch a = update_theta_sketch::builder().build();
+ update_theta_sketch b = update_theta_sketch::builder().build();
+ compact_theta_sketch result = a_not_b.compute(a, b);
+ REQUIRE(result.get_num_retained() == 0);
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
}
- void exact_mode_disjoint() {
- update_theta_sketch a = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) a.update(value++);
-
- update_theta_sketch b = update_theta_sketch::builder().build();
- for (int i = 0; i < 1000; i++) b.update(value++);
-
- theta_a_not_b a_not_b;
-
- // unordered inputs
- compact_theta_sketch result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1000.0, result.get_estimate());
-
- // ordered inputs
- result = a_not_b.compute(a.compact(), b.compact());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1000.0, result.get_estimate());
- }
-
- void exact_mode_full_overlap() {
- update_theta_sketch sketch = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) sketch.update(value++);
-
- theta_a_not_b a_not_b;
-
- // unordered inputs
- compact_theta_sketch result = a_not_b.compute(sketch, sketch);
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
-
- // ordered inputs
- result = a_not_b.compute(sketch.compact(), sketch.compact());
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void estimation_mode_half_overlap() {
- update_theta_sketch a = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) a.update(value++);
-
- update_theta_sketch b = update_theta_sketch::builder().build();
- value = 5000;
- for (int i = 0; i < 10000; i++) b.update(value++);
-
- theta_a_not_b a_not_b;
-
- // unordered inputs
- compact_theta_sketch result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(5000, result.get_estimate(), 5000 * 0.02);
-
- // ordered inputs
- result = a_not_b.compute(a.compact(), b.compact());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(5000, result.get_estimate(), 5000 * 0.02);
- }
-
- void estimation_mode_disjoint() {
- update_theta_sketch a = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) a.update(value++);
-
- update_theta_sketch b = update_theta_sketch::builder().build();
- for (int i = 0; i < 10000; i++) b.update(value++);
-
- theta_a_not_b a_not_b;
-
- // unordered inputs
- compact_theta_sketch result = a_not_b.compute(a, b);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(10000, result.get_estimate(), 10000 * 0.02);
-
- // ordered inputs
- result = a_not_b.compute(a.compact(), b.compact());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(10000, result.get_estimate(), 10000 * 0.02);
- }
-
- void estimation_mode_full_overlap() {
- update_theta_sketch sketch = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) sketch.update(value++);
-
- theta_a_not_b a_not_b;
-
- // unordered inputs
- compact_theta_sketch result = a_not_b.compute(sketch, sketch);
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
-
- // ordered inputs
- result = a_not_b.compute(sketch.compact(), sketch.compact());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void seed_mismatch() {
- update_theta_sketch sketch = update_theta_sketch::builder().build();
- sketch.update(1); // non-empty should not be ignored
- theta_a_not_b a_not_b(123);
- CPPUNIT_ASSERT_THROW(a_not_b.compute(sketch, sketch), std::invalid_argument);
- }
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(theta_a_not_b_test);
+TEST_CASE("theta a-not-b: non empty no retained keys", "[theta_a_not_b]") {
+ update_theta_sketch a = update_theta_sketch::builder().build();
+ a.update(1);
+ update_theta_sketch b = update_theta_sketch::builder().set_p(0.001).build();
+ theta_a_not_b a_not_b;
+
+ // B is still empty
+ compact_theta_sketch result = a_not_b.compute(a, b);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_num_retained() == 1);
+ REQUIRE(result.get_theta() == Approx(1).margin(1e-10));
+ REQUIRE(result.get_estimate() == 1.0);
+
+ // B is not empty in estimation mode and no entries
+ b.update(1);
+ REQUIRE(b.get_num_retained() == 0U);
+
+ result = a_not_b.compute(a, b);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_num_retained() == 0);
+ REQUIRE(result.get_theta() == Approx(0.001).margin(1e-10));
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta a-not-b: exact mode half overlap", "[theta_a_not_b]") {
+ update_theta_sketch a = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) a.update(value++);
+
+ update_theta_sketch b = update_theta_sketch::builder().build();
+ value = 500;
+ for (int i = 0; i < 1000; i++) b.update(value++);
+
+ theta_a_not_b a_not_b;
+
+ // unordered inputs, ordered result
+ compact_theta_sketch result = a_not_b.compute(a, b);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.is_ordered());
+ REQUIRE(result.get_estimate() == 500.0);
+
+ // unordered inputs, unordered result
+ result = a_not_b.compute(a, b, false);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE_FALSE(result.is_ordered());
+ REQUIRE(result.get_estimate() == 500.0);
+
+ // ordered inputs
+ result = a_not_b.compute(a.compact(), b.compact());
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.is_ordered());
+ REQUIRE(result.get_estimate() == 500.0);
+
+ // A is ordered, so the result is ordered regardless
+ result = a_not_b.compute(a.compact(), b, false);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.is_ordered());
+ REQUIRE(result.get_estimate() == 500.0);
+}
+
+TEST_CASE("theta a-not-b: exact mode disjoint", "[theta_a_not_b]") {
+ update_theta_sketch a = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) a.update(value++);
+
+ update_theta_sketch b = update_theta_sketch::builder().build();
+ for (int i = 0; i < 1000; i++) b.update(value++);
+
+ theta_a_not_b a_not_b;
+
+ // unordered inputs
+ compact_theta_sketch result = a_not_b.compute(a, b);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 1000.0);
+
+ // ordered inputs
+ result = a_not_b.compute(a.compact(), b.compact());
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 1000.0);
+}
+
+TEST_CASE("theta a-not-b: exact mode full overlap", "[theta_a_not_b]") {
+ update_theta_sketch sketch = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) sketch.update(value++);
+
+ theta_a_not_b a_not_b;
+
+ // unordered inputs
+ compact_theta_sketch result = a_not_b.compute(sketch, sketch);
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+
+ // ordered inputs
+ result = a_not_b.compute(sketch.compact(), sketch.compact());
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta a-not-b: estimation mode half overlap", "[theta_a_not_b]") {
+ update_theta_sketch a = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) a.update(value++);
+
+ update_theta_sketch b = update_theta_sketch::builder().build();
+ value = 5000;
+ for (int i = 0; i < 10000; i++) b.update(value++);
+
+ theta_a_not_b a_not_b;
+
+ // unordered inputs
+ compact_theta_sketch result = a_not_b.compute(a, b);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == Approx(5000).margin(5000 * 0.02));
+
+ // ordered inputs
+ result = a_not_b.compute(a.compact(), b.compact());
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == Approx(5000).margin(5000 * 0.02));
+}
+
+TEST_CASE("theta a-not-b: estimation mode disjoint", "[theta_a_not_b]") {
+ update_theta_sketch a = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) a.update(value++);
+
+ update_theta_sketch b = update_theta_sketch::builder().build();
+ for (int i = 0; i < 10000; i++) b.update(value++);
+
+ theta_a_not_b a_not_b;
+
+ // unordered inputs
+ compact_theta_sketch result = a_not_b.compute(a, b);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == Approx(10000).margin(10000 * 0.02));
+
+ // ordered inputs
+ result = a_not_b.compute(a.compact(), b.compact());
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == Approx(10000).margin(10000 * 0.02));
+}
+
+TEST_CASE("theta a-not-b: estimation mode full overlap", "[theta_a_not_b]") {
+ update_theta_sketch sketch = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) sketch.update(value++);
+
+ theta_a_not_b a_not_b;
+
+ // unordered inputs
+ compact_theta_sketch result = a_not_b.compute(sketch, sketch);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+
+ // ordered inputs
+ result = a_not_b.compute(sketch.compact(), sketch.compact());
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta a-not-b: seed mismatch", "[theta_a_not_b]") {
+ update_theta_sketch sketch = update_theta_sketch::builder().build();
+ sketch.update(1); // non-empty should not be ignored
+ theta_a_not_b a_not_b(123);
+ REQUIRE_THROWS_AS(a_not_b.compute(sketch, sketch), std::invalid_argument);
+}
} /* namespace datasketches */
diff --git a/theta/test/theta_intersection_test.cpp b/theta/test/theta_intersection_test.cpp
index 3cd010f..2c8d6c0 100644
--- a/theta/test/theta_intersection_test.cpp
+++ b/theta/test/theta_intersection_test.cpp
@@ -17,224 +17,202 @@
* under the License.
*/
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
#include <theta_intersection.hpp>
namespace datasketches {
-class theta_intersection_test: public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(theta_intersection_test);
- CPPUNIT_TEST(invalid);
- CPPUNIT_TEST(empty);
- CPPUNIT_TEST(non_empty_no_retained_keys);
- CPPUNIT_TEST(exact_mode_half_overlap_unordered);
- CPPUNIT_TEST(exact_mode_half_overlap_ordered);
- CPPUNIT_TEST(exact_mode_disjoint_unordered);
- CPPUNIT_TEST(exact_mode_disjoint_ordered);
- CPPUNIT_TEST(estimation_mode_half_overlap_unordered);
- CPPUNIT_TEST(estimation_mode_half_overlap_ordered);
- CPPUNIT_TEST(estimation_mode_disjoint_unordered);
- CPPUNIT_TEST(estimation_mode_disjoint_ordered);
- CPPUNIT_TEST(seed_mismatch);
- CPPUNIT_TEST_SUITE_END();
-
- void invalid() {
- theta_intersection intersection;
- CPPUNIT_ASSERT(!intersection.has_result());
- CPPUNIT_ASSERT_THROW(intersection.get_result(), std::invalid_argument);
- }
-
- void empty() {
- theta_intersection intersection;
- update_theta_sketch sketch = update_theta_sketch::builder().build();
- intersection.update(sketch);
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, result.get_num_retained());
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
-
- intersection.update(sketch);
- result = intersection.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, result.get_num_retained());
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void non_empty_no_retained_keys() {
- update_theta_sketch sketch = update_theta_sketch::builder().set_p(0.001).build();
- sketch.update(1);
- theta_intersection intersection;
- intersection.update(sketch);
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, result.get_num_retained());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.001, result.get_theta(), 1e-10);
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
-
- intersection.update(sketch);
- result = intersection.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, result.get_num_retained());
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.001, result.get_theta(), 1e-10);
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void exact_mode_half_overlap_unordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- value = 500;
- for (int i = 0; i < 1000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1);
- intersection.update(sketch2);
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(500.0, result.get_estimate());
- }
-
- void exact_mode_half_overlap_ordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- value = 500;
- for (int i = 0; i < 1000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1.compact());
- intersection.update(sketch2.compact());
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(500.0, result.get_estimate());
- }
-
- void exact_mode_disjoint_unordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- for (int i = 0; i < 1000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1);
- intersection.update(sketch2);
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void exact_mode_disjoint_ordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- for (int i = 0; i < 1000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1.compact());
- intersection.update(sketch2.compact());
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(result.is_empty());
- CPPUNIT_ASSERT(!result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void estimation_mode_half_overlap_unordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- value = 5000;
- for (int i = 0; i < 10000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1);
- intersection.update(sketch2);
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(5000, result.get_estimate(), 5000 * 0.02);
- }
-
- void estimation_mode_half_overlap_ordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- value = 5000;
- for (int i = 0; i < 10000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1.compact());
- intersection.update(sketch2.compact());
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(5000, result.get_estimate(), 5000 * 0.02);
- }
-
- void estimation_mode_disjoint_unordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- for (int i = 0; i < 10000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1);
- intersection.update(sketch2);
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void estimation_mode_disjoint_ordered() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- for (int i = 0; i < 10000; i++) sketch2.update(value++);
-
- theta_intersection intersection;
- intersection.update(sketch1.compact());
- intersection.update(sketch2.compact());
- compact_theta_sketch result = intersection.get_result();
- CPPUNIT_ASSERT(!result.is_empty());
- CPPUNIT_ASSERT(result.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, result.get_estimate());
- }
-
- void seed_mismatch() {
- update_theta_sketch sketch = update_theta_sketch::builder().build();
- sketch.update(1); // non-empty should not be ignored
- theta_intersection intersection(123);
- CPPUNIT_ASSERT_THROW(intersection.update(sketch), std::invalid_argument);
- }
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(theta_intersection_test);
+TEST_CASE("theta intersection: invalid", "[theta_intersection]") {
+ theta_intersection intersection;
+ REQUIRE_FALSE(intersection.has_result());
+ REQUIRE_THROWS_AS(intersection.get_result(), std::invalid_argument);
+}
+
+TEST_CASE("theta intersection: empty", "[theta_intersection]") {
+ theta_intersection intersection;
+ update_theta_sketch sketch = update_theta_sketch::builder().build();
+ intersection.update(sketch);
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE(result.get_num_retained() == 0);
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+
+ intersection.update(sketch);
+ result = intersection.get_result();
+ REQUIRE(result.get_num_retained() == 0);
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta intersection: non empty no retained keys", "[theta_intersection]") {
+ update_theta_sketch sketch = update_theta_sketch::builder().set_p(0.001).build();
+ sketch.update(1);
+ theta_intersection intersection;
+ intersection.update(sketch);
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE(result.get_num_retained() == 0);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_theta() == Approx(0.001).margin(1e-10));
+ REQUIRE(result.get_estimate() == 0.0);
+
+ intersection.update(sketch);
+ result = intersection.get_result();
+ REQUIRE(result.get_num_retained() == 0);
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_theta() == Approx(0.001).margin(1e-10));
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta intersection: exact mode half overlap unordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ value = 500;
+ for (int i = 0; i < 1000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1);
+ intersection.update(sketch2);
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 500.0);
+}
+
+TEST_CASE("theta intersection: exact mode half overlap ordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ value = 500;
+ for (int i = 0; i < 1000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1.compact());
+ intersection.update(sketch2.compact());
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 500.0);
+}
+
+TEST_CASE("theta intersection: exact mode disjoint unordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ for (int i = 0; i < 1000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1);
+ intersection.update(sketch2);
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta intersection: exact mode disjoint ordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ for (int i = 0; i < 1000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1.compact());
+ intersection.update(sketch2.compact());
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE(result.is_empty());
+ REQUIRE_FALSE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta intersection: estimation mode half overlap unordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ value = 5000;
+ for (int i = 0; i < 10000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1);
+ intersection.update(sketch2);
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == Approx(5000).margin(5000 * 0.02));
+}
+
+TEST_CASE("theta intersection: estimation mode half overlap ordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ value = 5000;
+ for (int i = 0; i < 10000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1.compact());
+ intersection.update(sketch2.compact());
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == Approx(5000).margin(5000 * 0.02));
+}
+
+TEST_CASE("theta intersection: estimation mode disjoint unordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ for (int i = 0; i < 10000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1);
+ intersection.update(sketch2);
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta intersection: estimation mode disjoint ordered", "[theta_intersection]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ for (int i = 0; i < 10000; i++) sketch2.update(value++);
+
+ theta_intersection intersection;
+ intersection.update(sketch1.compact());
+ intersection.update(sketch2.compact());
+ compact_theta_sketch result = intersection.get_result();
+ REQUIRE_FALSE(result.is_empty());
+ REQUIRE(result.is_estimation_mode());
+ REQUIRE(result.get_estimate() == 0.0);
+}
+
+TEST_CASE("theta intersection: seed mismatch", "[theta_intersection]") {
+ update_theta_sketch sketch = update_theta_sketch::builder().build();
+ sketch.update(1); // non-empty should not be ignored
+ theta_intersection intersection(123);
+ REQUIRE_THROWS_AS(intersection.update(sketch), std::invalid_argument);
+}
} /* namespace datasketches */
diff --git a/theta/test/theta_sketch_test.cpp b/theta/test/theta_sketch_test.cpp
index 47e6231..007c267 100644
--- a/theta/test/theta_sketch_test.cpp
+++ b/theta/test/theta_sketch_test.cpp
@@ -17,435 +17,406 @@
* under the License.
*/
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
+#include <fstream>
+#include <sstream>
#include <theta_sketch.hpp>
namespace datasketches {
-class theta_sketch_test: public CppUnit::TestFixture {
-
- // optional prefix for input binary files
- // default value defined at end of file
- static const std::string inputPath;
-
- CPPUNIT_TEST_SUITE(theta_sketch_test);
- CPPUNIT_TEST(empty);
- CPPUNIT_TEST(non_empty_no_retained_keys);
- CPPUNIT_TEST(single_item);
- CPPUNIT_TEST(resize_exact);
- CPPUNIT_TEST(estimation);
- CPPUNIT_TEST(deserialize_update_empty_from_java_as_base);
- CPPUNIT_TEST(deserialize_update_empty_from_java_as_subclass);
- CPPUNIT_TEST(deserialize_update_estimation_from_java_as_base);
- CPPUNIT_TEST(deserialize_update_estimation_from_java_as_subclass);
- CPPUNIT_TEST(deserialize_compact_empty_from_java_as_base);
- CPPUNIT_TEST(deserialize_compact_empty_from_java_as_subclass);
- CPPUNIT_TEST(deserialize_single_item_from_java_as_base);
- CPPUNIT_TEST(deserialize_single_item_from_java_as_subclass);
- CPPUNIT_TEST(deserialize_compact_estimation_from_java_as_base);
- CPPUNIT_TEST(deserialize_compact_estimation_from_java_as_subclass);
- CPPUNIT_TEST(serialize_deserialize_stream_and_bytes_equivalency);
- CPPUNIT_TEST_SUITE_END();
-
- void empty() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().build();
- CPPUNIT_ASSERT(update_sketch.is_empty());
- CPPUNIT_ASSERT(!update_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1.0, update_sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(0.0, update_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, update_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(0.0, update_sketch.get_upper_bound(1));
-
- compact_theta_sketch compact_sketch = update_sketch.compact();
- CPPUNIT_ASSERT(compact_sketch.is_empty());
- CPPUNIT_ASSERT(!compact_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1.0, compact_sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(0.0, compact_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, compact_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(0.0, compact_sketch.get_upper_bound(1));
- }
+#ifdef TEST_BINARY_INPUT_PATH
+const std::string inputPath = TEST_BINARY_INPUT_PATH;
+#else
+const std::string inputPath = "test/";
+#endif
- void non_empty_no_retained_keys() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().set_p(0.001).build();
- update_sketch.update(1);
- //update_sketch.to_stream(std::cerr);
- CPPUNIT_ASSERT_EQUAL(0U, update_sketch.get_num_retained());
- CPPUNIT_ASSERT(!update_sketch.is_empty());
- CPPUNIT_ASSERT(update_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, update_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, update_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT(update_sketch.get_upper_bound(1) > 0);
-
- compact_theta_sketch compact_sketch = update_sketch.compact();
- CPPUNIT_ASSERT_EQUAL(0U, compact_sketch.get_num_retained());
- CPPUNIT_ASSERT(!compact_sketch.is_empty());
- CPPUNIT_ASSERT(compact_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0.0, compact_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, compact_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT(compact_sketch.get_upper_bound(1) > 0);
+TEST_CASE("theta sketch: empty", "[theta_sketch]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().build();
+ REQUIRE(update_sketch.is_empty());
+ REQUIRE_FALSE(update_sketch.is_estimation_mode());
+ REQUIRE(update_sketch.get_theta() == 1.0);
+ REQUIRE(update_sketch.get_estimate() == 0.0);
+ REQUIRE(update_sketch.get_lower_bound(1) == 0.0);
+ REQUIRE(update_sketch.get_upper_bound(1) == 0.0);
+
+ compact_theta_sketch compact_sketch = update_sketch.compact();
+ REQUIRE(compact_sketch.is_empty());
+ REQUIRE_FALSE(compact_sketch.is_estimation_mode());
+ REQUIRE(compact_sketch.get_theta() == 1.0);
+ REQUIRE(compact_sketch.get_estimate() == 0.0);
+ REQUIRE(compact_sketch.get_lower_bound(1) == 0.0);
+ REQUIRE(compact_sketch.get_upper_bound(1) == 0.0);
}
- void single_item() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().build();
- update_sketch.update(1);
- CPPUNIT_ASSERT(!update_sketch.is_empty());
- CPPUNIT_ASSERT(!update_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1.0, update_sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(1.0, update_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(1.0, update_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(1.0, update_sketch.get_upper_bound(1));
-
- compact_theta_sketch compact_sketch = update_sketch.compact();
- CPPUNIT_ASSERT(!compact_sketch.is_empty());
- CPPUNIT_ASSERT(!compact_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1.0, compact_sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(1.0, compact_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(1.0, compact_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(1.0, compact_sketch.get_upper_bound(1));
- }
+TEST_CASE("theta sketch: non empty no retained keys", "[theta_sketch]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().set_p(0.001).build();
+ update_sketch.update(1);
+ //update_sketch.to_stream(std::cerr);
+ REQUIRE(update_sketch.get_num_retained() == 0);
+ REQUIRE_FALSE(update_sketch.is_empty());
+ REQUIRE(update_sketch.is_estimation_mode());
+ REQUIRE(update_sketch.get_estimate() == 0.0);
+ REQUIRE(update_sketch.get_lower_bound(1) == 0.0);
+ REQUIRE(update_sketch.get_upper_bound(1) > 0);
+
+ compact_theta_sketch compact_sketch = update_sketch.compact();
+ REQUIRE(compact_sketch.get_num_retained() == 0);
+ REQUIRE_FALSE(compact_sketch.is_empty());
+ REQUIRE(compact_sketch.is_estimation_mode());
+ REQUIRE(compact_sketch.get_estimate() == 0.0);
+ REQUIRE(compact_sketch.get_lower_bound(1) == 0.0);
+ REQUIRE(compact_sketch.get_upper_bound(1) > 0);
+}
- void resize_exact() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().build();
- for (int i = 0; i < 2000; i++) update_sketch.update(i);
- CPPUNIT_ASSERT(!update_sketch.is_empty());
- CPPUNIT_ASSERT(!update_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1.0, update_sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(2000.0, update_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(2000.0, update_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(2000.0, update_sketch.get_upper_bound(1));
-
- compact_theta_sketch compact_sketch = update_sketch.compact();
- CPPUNIT_ASSERT(!compact_sketch.is_empty());
- CPPUNIT_ASSERT(!compact_sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1.0, compact_sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(2000.0, compact_sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(2000.0, compact_sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(2000.0, compact_sketch.get_upper_bound(1));
+TEST_CASE("theta sketch: single item", "[theta_sketch]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().build();
+ update_sketch.update(1);
+ REQUIRE_FALSE(update_sketch.is_empty());
+ REQUIRE_FALSE(update_sketch.is_estimation_mode());
+ REQUIRE(update_sketch.get_theta() == 1.0);
+ REQUIRE(update_sketch.get_estimate() == 1.0);
+ REQUIRE(update_sketch.get_lower_bound(1) == 1.0);
+ REQUIRE(update_sketch.get_upper_bound(1) == 1.0);
+
+ compact_theta_sketch compact_sketch = update_sketch.compact();
+ REQUIRE_FALSE(compact_sketch.is_empty());
+ REQUIRE_FALSE(compact_sketch.is_estimation_mode());
+ REQUIRE(compact_sketch.get_theta() == 1.0);
+ REQUIRE(compact_sketch.get_estimate() == 1.0);
+ REQUIRE(compact_sketch.get_lower_bound(1) == 1.0);
+ REQUIRE(compact_sketch.get_upper_bound(1) == 1.0);
}
- void estimation() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().set_resize_factor(update_theta_sketch::resize_factor::X1).build();
- const int n = 8000;
- for (int i = 0; i < n; i++) update_sketch.update(i);
- //update_sketch.to_stream(std::cerr);
- CPPUNIT_ASSERT(!update_sketch.is_empty());
- CPPUNIT_ASSERT(update_sketch.is_estimation_mode());
- CPPUNIT_ASSERT(update_sketch.get_theta() < 1.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL((double) n, update_sketch.get_estimate(), n * 0.01);
- CPPUNIT_ASSERT(update_sketch.get_lower_bound(1) < n);
- CPPUNIT_ASSERT(update_sketch.get_upper_bound(1) > n);
-
- const uint32_t k = 1 << update_theta_sketch::builder::DEFAULT_LG_K;
- CPPUNIT_ASSERT(update_sketch.get_num_retained() >= k);
- update_sketch.trim();
- CPPUNIT_ASSERT_EQUAL(k, update_sketch.get_num_retained());
-
- compact_theta_sketch compact_sketch = update_sketch.compact();
- CPPUNIT_ASSERT(!compact_sketch.is_empty());
- CPPUNIT_ASSERT(compact_sketch.is_ordered());
- CPPUNIT_ASSERT(compact_sketch.is_estimation_mode());
- CPPUNIT_ASSERT(compact_sketch.get_theta() < 1.0);
- CPPUNIT_ASSERT_DOUBLES_EQUAL((double) n, compact_sketch.get_estimate(), n * 0.01);
- CPPUNIT_ASSERT(compact_sketch.get_lower_bound(1) < n);
- CPPUNIT_ASSERT(compact_sketch.get_upper_bound(1) > n);
+TEST_CASE("theta sketch: resize exact", "[theta_sketch]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().build();
+ for (int i = 0; i < 2000; i++) update_sketch.update(i);
+ REQUIRE_FALSE(update_sketch.is_empty());
+ REQUIRE_FALSE(update_sketch.is_estimation_mode());
+ REQUIRE(update_sketch.get_theta() == 1.0);
+ REQUIRE(update_sketch.get_estimate() == 2000.0);
+ REQUIRE(update_sketch.get_lower_bound(1) == 2000.0);
+ REQUIRE(update_sketch.get_upper_bound(1) == 2000.0);
+
+ compact_theta_sketch compact_sketch = update_sketch.compact();
+ REQUIRE_FALSE(compact_sketch.is_empty());
+ REQUIRE_FALSE(compact_sketch.is_estimation_mode());
+ REQUIRE(compact_sketch.get_theta() == 1.0);
+ REQUIRE(compact_sketch.get_estimate() == 2000.0);
+ REQUIRE(compact_sketch.get_lower_bound(1) == 2000.0);
+ REQUIRE(compact_sketch.get_upper_bound(1) == 2000.0);
}
- void deserialize_update_empty_from_java_as_base() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_update_empty_from_java.bin", std::ios::binary);
- auto sketchptr = theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(sketchptr->is_empty());
- CPPUNIT_ASSERT(!sketchptr->is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0U, sketchptr->get_num_retained());
- CPPUNIT_ASSERT_EQUAL(1.0, sketchptr->get_theta());
- CPPUNIT_ASSERT_EQUAL(0.0, sketchptr->get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, sketchptr->get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(0.0, sketchptr->get_upper_bound(1));
- }
+TEST_CASE("theta sketch: estimation", "[theta_sketch]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().set_resize_factor(update_theta_sketch::resize_factor::X1).build();
+ const int n = 8000;
+ for (int i = 0; i < n; i++) update_sketch.update(i);
+ //update_sketch.to_stream(std::cerr);
+ REQUIRE_FALSE(update_sketch.is_empty());
+ REQUIRE(update_sketch.is_estimation_mode());
+ REQUIRE(update_sketch.get_theta() < 1.0);
+ REQUIRE(update_sketch.get_estimate() == Approx((double) n).margin(n * 0.01));
+ REQUIRE(update_sketch.get_lower_bound(1) < n);
+ REQUIRE(update_sketch.get_upper_bound(1) > n);
+
+ const uint32_t k = 1 << update_theta_sketch::builder::DEFAULT_LG_K;
+ REQUIRE(update_sketch.get_num_retained() >= k);
+ update_sketch.trim();
+ REQUIRE(update_sketch.get_num_retained() == k);
+
+ compact_theta_sketch compact_sketch = update_sketch.compact();
+ REQUIRE_FALSE(compact_sketch.is_empty());
+ REQUIRE(compact_sketch.is_ordered());
+ REQUIRE(compact_sketch.is_estimation_mode());
+ REQUIRE(compact_sketch.get_theta() < 1.0);
+ REQUIRE(compact_sketch.get_estimate() == Approx((double) n).margin(n * 0.01));
+ REQUIRE(compact_sketch.get_lower_bound(1) < n);
+ REQUIRE(compact_sketch.get_upper_bound(1) > n);
+}
- void deserialize_update_empty_from_java_as_subclass() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_update_empty_from_java.bin", std::ios::binary);
- auto sketch = update_theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(sketch.is_empty());
- CPPUNIT_ASSERT(!sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0U, sketch.get_num_retained());
- CPPUNIT_ASSERT_EQUAL(1.0, sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(0.0, sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(0.0, sketch.get_upper_bound(1));
- }
+TEST_CASE("theta sketch: deserialize update empty from java as base", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_update_empty_from_java.bin", std::ios::binary);
+ auto sketchptr = theta_sketch::deserialize(is);
+ REQUIRE(sketchptr->is_empty());
+ REQUIRE_FALSE(sketchptr->is_estimation_mode());
+ REQUIRE(sketchptr->get_num_retained() == 0);
+ REQUIRE(sketchptr->get_theta() == 1.0);
+ REQUIRE(sketchptr->get_estimate() == 0.0);
+ REQUIRE(sketchptr->get_lower_bound(1) == 0.0);
+ REQUIRE(sketchptr->get_upper_bound(1) == 0.0);
+}
- void deserialize_update_estimation_from_java_as_base() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_update_estimation_from_java.bin", std::ios::binary);
- auto sketchptr = theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(!sketchptr->is_empty());
- CPPUNIT_ASSERT(sketchptr->is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(5324U, sketchptr->get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(10000.0, sketchptr->get_estimate(), 10000 * 0.01);
- CPPUNIT_ASSERT(sketchptr->get_lower_bound(1) < 10000);
- CPPUNIT_ASSERT(sketchptr->get_upper_bound(1) > 10000);
- }
+TEST_CASE("theta sketch: deserialize update empty from java as subclass", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_update_empty_from_java.bin", std::ios::binary);
+ auto sketch = update_theta_sketch::deserialize(is);
+ REQUIRE(sketch.is_empty());
+ REQUIRE_FALSE(sketch.is_estimation_mode());
+ REQUIRE(sketch.get_num_retained() == 0);
+ REQUIRE(sketch.get_theta() == 1.0);
+ REQUIRE(sketch.get_estimate() == 0.0);
+ REQUIRE(sketch.get_lower_bound(1) == 0.0);
+ REQUIRE(sketch.get_upper_bound(1) == 0.0);
+}
- void deserialize_update_estimation_from_java_as_subclass() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_update_estimation_from_java.bin", std::ios::binary);
- auto sketch = update_theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(!sketch.is_empty());
- CPPUNIT_ASSERT(sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(5324U, sketch.get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(10000.0, sketch.get_estimate(), 10000 * 0.01);
- CPPUNIT_ASSERT(sketch.get_lower_bound(1) < 10000);
- CPPUNIT_ASSERT(sketch.get_upper_bound(1) > 10000);
- }
+TEST_CASE("theta sketch: deserialize update estimation from java as base", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_update_estimation_from_java.bin", std::ios::binary);
+ auto sketchptr = theta_sketch::deserialize(is);
+ REQUIRE_FALSE(sketchptr->is_empty());
+ REQUIRE(sketchptr->is_estimation_mode());
+ REQUIRE(sketchptr->get_num_retained() == 5324);
+ REQUIRE(sketchptr->get_estimate() == Approx(10000.0).margin(10000 * 0.01));
+ REQUIRE(sketchptr->get_lower_bound(1) < 10000);
+ REQUIRE(sketchptr->get_upper_bound(1) > 10000);
+}
- void deserialize_compact_empty_from_java_as_base() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_compact_empty_from_java.bin", std::ios::binary);
- auto sketchptr = theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(sketchptr->is_empty());
- CPPUNIT_ASSERT(!sketchptr->is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0U, sketchptr->get_num_retained());
- CPPUNIT_ASSERT_EQUAL(1.0, sketchptr->get_theta());
- CPPUNIT_ASSERT_EQUAL(0.0, sketchptr->get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, sketchptr->get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(0.0, sketchptr->get_upper_bound(1));
- }
+TEST_CASE("theta sketch: deserialize update estimation from java as subclass", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_update_estimation_from_java.bin", std::ios::binary);
+ auto sketch = update_theta_sketch::deserialize(is);
+ REQUIRE_FALSE(sketch.is_empty());
+ REQUIRE(sketch.is_estimation_mode());
+ REQUIRE(sketch.get_num_retained() == 5324);
+ REQUIRE(sketch.get_estimate() == Approx(10000.0).margin(10000 * 0.01));
+ REQUIRE(sketch.get_lower_bound(1) < 10000);
+ REQUIRE(sketch.get_upper_bound(1) > 10000);
+}
- void deserialize_compact_empty_from_java_as_subclass() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_compact_empty_from_java.bin", std::ios::binary);
- auto sketch = compact_theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(sketch.is_empty());
- CPPUNIT_ASSERT(!sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(0U, sketch.get_num_retained());
- CPPUNIT_ASSERT_EQUAL(1.0, sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(0.0, sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(0.0, sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(0.0, sketch.get_upper_bound(1));
- }
+TEST_CASE("theta sketch: deserialize compact empty from java as base", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_compact_empty_from_java.bin", std::ios::binary);
+ auto sketchptr = theta_sketch::deserialize(is);
+ REQUIRE(sketchptr->is_empty());
+ REQUIRE_FALSE(sketchptr->is_estimation_mode());
+ REQUIRE(sketchptr->get_num_retained() == 0);
+ REQUIRE(sketchptr->get_theta() == 1.0);
+ REQUIRE(sketchptr->get_estimate() == 0.0);
+ REQUIRE(sketchptr->get_lower_bound(1) == 0.0);
+ REQUIRE(sketchptr->get_upper_bound(1) == 0.0);
+}
- void deserialize_single_item_from_java_as_base() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_compact_single_item_from_java.bin", std::ios::binary);
- auto sketchptr = theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(!sketchptr->is_empty());
- CPPUNIT_ASSERT(!sketchptr->is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1U, sketchptr->get_num_retained());
- CPPUNIT_ASSERT_EQUAL(1.0, sketchptr->get_theta());
- CPPUNIT_ASSERT_EQUAL(1.0, sketchptr->get_estimate());
- CPPUNIT_ASSERT_EQUAL(1.0, sketchptr->get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(1.0, sketchptr->get_upper_bound(1));
- }
+TEST_CASE("theta sketch: deserialize compact empty from java as subclass", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_compact_empty_from_java.bin", std::ios::binary);
+ auto sketch = compact_theta_sketch::deserialize(is);
+ REQUIRE(sketch.is_empty());
+ REQUIRE_FALSE(sketch.is_estimation_mode());
+ REQUIRE(sketch.get_num_retained() == 0);
+ REQUIRE(sketch.get_theta() == 1.0);
+ REQUIRE(sketch.get_estimate() == 0.0);
+ REQUIRE(sketch.get_lower_bound(1) == 0.0);
+ REQUIRE(sketch.get_upper_bound(1) == 0.0);
+}
- void deserialize_single_item_from_java_as_subclass() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_compact_single_item_from_java.bin", std::ios::binary);
- auto sketch = compact_theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(!sketch.is_empty());
- CPPUNIT_ASSERT(!sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(1U, sketch.get_num_retained());
- CPPUNIT_ASSERT_EQUAL(1.0, sketch.get_theta());
- CPPUNIT_ASSERT_EQUAL(1.0, sketch.get_estimate());
- CPPUNIT_ASSERT_EQUAL(1.0, sketch.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(1.0, sketch.get_upper_bound(1));
- }
+TEST_CASE("theta sketch: deserialize single item from java as base", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_compact_single_item_from_java.bin", std::ios::binary);
+ auto sketchptr = theta_sketch::deserialize(is);
+ REQUIRE_FALSE(sketchptr->is_empty());
+ REQUIRE_FALSE(sketchptr->is_estimation_mode());
+ REQUIRE(sketchptr->get_num_retained() == 1);
+ REQUIRE(sketchptr->get_theta() == 1.0);
+ REQUIRE(sketchptr->get_estimate() == 1.0);
+ REQUIRE(sketchptr->get_lower_bound(1) == 1.0);
+ REQUIRE(sketchptr->get_upper_bound(1) == 1.0);
+}
- void deserialize_compact_estimation_from_java_as_base() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_compact_estimation_from_java.bin", std::ios::binary);
- auto sketchptr = theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(!sketchptr->is_empty());
- CPPUNIT_ASSERT(sketchptr->is_estimation_mode());
- CPPUNIT_ASSERT(sketchptr->is_ordered());
- CPPUNIT_ASSERT_EQUAL(4342U, sketchptr->get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.531700444213199, sketchptr->get_theta(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(8166.25234614053, sketchptr->get_estimate(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(7996.956955317471, sketchptr->get_lower_bound(2), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(8339.090301078124, sketchptr->get_upper_bound(2), 1e-10);
-
- // the same construction process in Java must have produced exactly the same sketch
- update_theta_sketch update_sketch = update_theta_sketch::builder().build();
- const int n = 8192;
- for (int i = 0; i < n; i++) update_sketch.update(i);
- CPPUNIT_ASSERT_EQUAL(update_sketch.get_num_retained(), sketchptr->get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_theta(), sketchptr->get_theta(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_estimate(), sketchptr->get_estimate(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_lower_bound(1), sketchptr->get_lower_bound(1), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_upper_bound(1), sketchptr->get_upper_bound(1), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_lower_bound(2), sketchptr->get_lower_bound(2), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_upper_bound(2), sketchptr->get_upper_bound(2), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_lower_bound(3), sketchptr->get_lower_bound(3), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_upper_bound(3), sketchptr->get_upper_bound(3), 1e-10);
- compact_theta_sketch compact_sketch = update_sketch.compact();
- // the sketches are ordered, so the iteration sequence must match exactly
- auto iter = sketchptr->begin();
- for (auto key: compact_sketch) {
- CPPUNIT_ASSERT_EQUAL(key, *iter);
- ++iter;
- }
- }
+TEST_CASE("theta sketch: deserialize single item from java as subclass", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_compact_single_item_from_java.bin", std::ios::binary);
+ auto sketch = compact_theta_sketch::deserialize(is);
+ REQUIRE_FALSE(sketch.is_empty());
+ REQUIRE_FALSE(sketch.is_estimation_mode());
+ REQUIRE(sketch.get_num_retained() == 1);
+ REQUIRE(sketch.get_theta() == 1.0);
+ REQUIRE(sketch.get_estimate() == 1.0);
+ REQUIRE(sketch.get_lower_bound(1) == 1.0);
+ REQUIRE(sketch.get_upper_bound(1) == 1.0);
+}
- void deserialize_compact_estimation_from_java_as_subclass() {
- std::ifstream is;
- is.exceptions(std::ios::failbit | std::ios::badbit);
- is.open(inputPath + "theta_compact_estimation_from_java.bin", std::ios::binary);
- auto sketch = compact_theta_sketch::deserialize(is);
- CPPUNIT_ASSERT(!sketch.is_empty());
- CPPUNIT_ASSERT(sketch.is_estimation_mode());
- CPPUNIT_ASSERT_EQUAL(4342U, sketch.get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.531700444213199, sketch.get_theta(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(8166.25234614053, sketch.get_estimate(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(7996.956955317471, sketch.get_lower_bound(2), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(8339.090301078124, sketch.get_upper_bound(2), 1e-10);
-
- update_theta_sketch update_sketch = update_theta_sketch::builder().build();
- const int n = 8192;
- for (int i = 0; i < n; i++) update_sketch.update(i);
- CPPUNIT_ASSERT_EQUAL(update_sketch.get_num_retained(), sketch.get_num_retained());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_theta(), sketch.get_theta(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_estimate(), sketch.get_estimate(), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_lower_bound(1), sketch.get_lower_bound(1), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_upper_bound(1), sketch.get_upper_bound(1), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_lower_bound(2), sketch.get_lower_bound(2), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_upper_bound(2), sketch.get_upper_bound(2), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_lower_bound(3), sketch.get_lower_bound(3), 1e-10);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(update_sketch.get_upper_bound(3), sketch.get_upper_bound(3), 1e-10);
+TEST_CASE("theta sketch: deserialize compact estimation from java as base", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_compact_estimation_from_java.bin", std::ios::binary);
+ auto sketchptr = theta_sketch::deserialize(is);
+ REQUIRE_FALSE(sketchptr->is_empty());
+ REQUIRE(sketchptr->is_estimation_mode());
+ REQUIRE(sketchptr->is_ordered());
+ REQUIRE(sketchptr->get_num_retained() == 4342);
+ REQUIRE(sketchptr->get_theta() == Approx(0.531700444213199).margin(1e-10));
+ REQUIRE(sketchptr->get_estimate() == Approx(8166.25234614053).margin(1e-10));
+ REQUIRE(sketchptr->get_lower_bound(2) == Approx(7996.956955317471).margin(1e-10));
+ REQUIRE(sketchptr->get_upper_bound(2) == Approx(8339.090301078124).margin(1e-10));
+
+ // the same construction process in Java must have produced exactly the same sketch
+ update_theta_sketch update_sketch = update_theta_sketch::builder().build();
+ const int n = 8192;
+ for (int i = 0; i < n; i++) update_sketch.update(i);
+ REQUIRE(sketchptr->get_num_retained() == update_sketch.get_num_retained());
+ REQUIRE(sketchptr->get_theta() == Approx(update_sketch.get_theta()).margin(1e-10));
+ REQUIRE(sketchptr->get_estimate() == Approx(update_sketch.get_estimate()).margin(1e-10));
+ REQUIRE(sketchptr->get_lower_bound(1) == Approx(update_sketch.get_lower_bound(1)).margin(1e-10));
+ REQUIRE(sketchptr->get_upper_bound(1) == Approx(update_sketch.get_upper_bound(1)).margin(1e-10));
+ REQUIRE(sketchptr->get_lower_bound(2) == Approx(update_sketch.get_lower_bound(2)).margin(1e-10));
+ REQUIRE(sketchptr->get_upper_bound(2) == Approx(update_sketch.get_upper_bound(2)).margin(1e-10));
+ REQUIRE(sketchptr->get_lower_bound(3) == Approx(update_sketch.get_lower_bound(3)).margin(1e-10));
+ REQUIRE(sketchptr->get_upper_bound(3) == Approx(update_sketch.get_upper_bound(3)).margin(1e-10));
+ compact_theta_sketch compact_sketch = update_sketch.compact();
+ // the sketches are ordered, so the iteration sequence must match exactly
+ auto iter = sketchptr->begin();
+ for (auto key: compact_sketch) {
+ REQUIRE(*iter == key);
+ ++iter;
}
+}
- void serialize_deserialize_stream_and_bytes_equivalency() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().build();
- const int n = 8192;
- for (int i = 0; i < n; i++) update_sketch.update(i);
+TEST_CASE("theta sketch: deserialize compact estimation from java as subclass", "[theta_sketch]") {
+ std::ifstream is;
+ is.exceptions(std::ios::failbit | std::ios::badbit);
+ is.open(inputPath + "theta_compact_estimation_from_java.bin", std::ios::binary);
+ auto sketch = compact_theta_sketch::deserialize(is);
+ REQUIRE_FALSE(sketch.is_empty());
+ REQUIRE(sketch.is_estimation_mode());
+ REQUIRE(sketch.get_num_retained() == 4342);
+ REQUIRE(sketch.get_theta() == Approx(0.531700444213199).margin(1e-10));
+ REQUIRE(sketch.get_estimate() == Approx(8166.25234614053).margin(1e-10));
+ REQUIRE(sketch.get_lower_bound(2) == Approx(7996.956955317471).margin(1e-10));
+ REQUIRE(sketch.get_upper_bound(2) == Approx(8339.090301078124).margin(1e-10));
+
+ update_theta_sketch update_sketch = update_theta_sketch::builder().build();
+ const int n = 8192;
+ for (int i = 0; i < n; i++) update_sketch.update(i);
+ REQUIRE(sketch.get_num_retained() == update_sketch.get_num_retained());
+ REQUIRE(sketch.get_theta() == Approx(update_sketch.get_theta()).margin(1e-10));
+ REQUIRE(sketch.get_estimate() == Approx(update_sketch.get_estimate()).margin(1e-10));
+ REQUIRE(sketch.get_lower_bound(1) == Approx(update_sketch.get_lower_bound(1)).margin(1e-10));
+ REQUIRE(sketch.get_upper_bound(1) == Approx(update_sketch.get_upper_bound(1)).margin(1e-10));
+ REQUIRE(sketch.get_lower_bound(2) == Approx(update_sketch.get_lower_bound(2)).margin(1e-10));
+ REQUIRE(sketch.get_upper_bound(2) == Approx(update_sketch.get_upper_bound(2)).margin(1e-10));
+ REQUIRE(sketch.get_lower_bound(3) == Approx(update_sketch.get_lower_bound(3)).margin(1e-10));
+ REQUIRE(sketch.get_upper_bound(3) == Approx(update_sketch.get_upper_bound(3)).margin(1e-10));
+}
+
+TEST_CASE("theta sketch: serialize deserialize stream and bytes equivalency", "[theta_sketch]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().build();
+ const int n = 8192;
+ for (int i = 0; i < n; i++) update_sketch.update(i);
+
+ // update sketch stream and bytes comparison
+ {
+ std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+ update_sketch.serialize(s);
+ auto bytes = update_sketch.serialize();
+ REQUIRE(bytes.size() == s.tellp());
+ for (size_t i = 0; i < bytes.size(); ++i) {
+ REQUIRE(((char*)bytes.data())[i] == (char)s.get());
+ }
- // update sketch stream and bytes comparison
+ // deserialize as base class
{
- std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
- update_sketch.serialize(s);
- auto bytes = update_sketch.serialize();
- CPPUNIT_ASSERT_EQUAL((size_t) s.tellp(), bytes.size());
- for (size_t i = 0; i < bytes.size(); ++i) {
- CPPUNIT_ASSERT_EQUAL((char)s.get(), ((char*)bytes.data())[i]);
+ s.seekg(0); // rewind
+ auto deserialized_sketch_ptr1 = theta_sketch::deserialize(s);
+ auto deserialized_sketch_ptr2 = theta_sketch::deserialize(bytes.data(), bytes.size());
+ REQUIRE(s.tellg() == bytes.size());
+ REQUIRE(deserialized_sketch_ptr2->is_empty() == deserialized_sketch_ptr1->is_empty());
+ REQUIRE(deserialized_sketch_ptr2->is_ordered() == deserialized_sketch_ptr1->is_ordered());
+ REQUIRE(deserialized_sketch_ptr2->get_num_retained() == deserialized_sketch_ptr1->get_num_retained());
+ REQUIRE(deserialized_sketch_ptr2->get_theta() == deserialized_sketch_ptr1->get_theta());
+ REQUIRE(deserialized_sketch_ptr2->get_estimate() == deserialized_sketch_ptr1->get_estimate());
+ REQUIRE(deserialized_sketch_ptr2->get_lower_bound(1) == deserialized_sketch_ptr1->get_lower_bound(1));
+ REQUIRE(deserialized_sketch_ptr2->get_upper_bound(1) == deserialized_sketch_ptr1->get_upper_bound(1));
+ // hash tables must be identical since they are restored from dumps, and iteration is deterministic
+ auto iter = deserialized_sketch_ptr1->begin();
+ for (auto key: *deserialized_sketch_ptr2) {
+ REQUIRE(*iter == key);
+ ++iter;
}
+ }
- // deserialize as base class
- {
- s.seekg(0); // rewind
- auto deserialized_sketch_ptr1 = theta_sketch::deserialize(s);
- auto deserialized_sketch_ptr2 = theta_sketch::deserialize(bytes.data(), bytes.size());
- CPPUNIT_ASSERT_EQUAL(bytes.size(), (size_t) s.tellg());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->is_empty(), deserialized_sketch_ptr2->is_empty());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->is_ordered(), deserialized_sketch_ptr2->is_ordered());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_num_retained(), deserialized_sketch_ptr2->get_num_retained());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_theta(), deserialized_sketch_ptr2->get_theta());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_estimate(), deserialized_sketch_ptr2->get_estimate());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_lower_bound(1), deserialized_sketch_ptr2->get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_upper_bound(1), deserialized_sketch_ptr2->get_upper_bound(1));
- // hash tables must be identical since they are restored from dumps, and iteration is deterministic
- auto iter = deserialized_sketch_ptr1->begin();
- for (auto key: *deserialized_sketch_ptr2) {
- CPPUNIT_ASSERT_EQUAL(key, *iter);
- ++iter;
- }
+ // deserialize as subclass
+ {
+ s.seekg(0); // rewind
+ update_theta_sketch deserialized_sketch1 = update_theta_sketch::deserialize(s);
+ update_theta_sketch deserialized_sketch2 = update_theta_sketch::deserialize(bytes.data(), bytes.size());
+ REQUIRE(s.tellg() == bytes.size());
+ REQUIRE(deserialized_sketch2.is_empty() == deserialized_sketch1.is_empty());
+ REQUIRE(deserialized_sketch2.is_ordered() == deserialized_sketch1.is_ordered());
+ REQUIRE(deserialized_sketch2.get_num_retained() == deserialized_sketch1.get_num_retained());
+ REQUIRE(deserialized_sketch2.get_theta() == deserialized_sketch1.get_theta());
+ REQUIRE(deserialized_sketch2.get_estimate() == deserialized_sketch1.get_estimate());
+ REQUIRE(deserialized_sketch2.get_lower_bound(1) == deserialized_sketch1.get_lower_bound(1));
+ REQUIRE(deserialized_sketch2.get_upper_bound(1) == deserialized_sketch1.get_upper_bound(1));
+ // hash tables must be identical since they are restored from dumps, and iteration is deterministic
+ auto iter = deserialized_sketch1.begin();
+ for (auto key: deserialized_sketch2) {
+ REQUIRE(*iter == key);
+ ++iter;
}
+ }
+ }
- // deserialize as subclass
- {
- s.seekg(0); // rewind
- update_theta_sketch deserialized_sketch1 = update_theta_sketch::deserialize(s);
- update_theta_sketch deserialized_sketch2 = update_theta_sketch::deserialize(bytes.data(), bytes.size());
- CPPUNIT_ASSERT_EQUAL(bytes.size(), (size_t) s.tellg());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.is_empty(), deserialized_sketch2.is_empty());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.is_ordered(), deserialized_sketch2.is_ordered());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_num_retained(), deserialized_sketch2.get_num_retained());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_theta(), deserialized_sketch2.get_theta());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_estimate(), deserialized_sketch2.get_estimate());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_lower_bound(1), deserialized_sketch2.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_upper_bound(1), deserialized_sketch2.get_upper_bound(1));
- // hash tables must be identical since they are restored from dumps, and iteration is deterministic
- auto iter = deserialized_sketch1.begin();
- for (auto key: deserialized_sketch2) {
- CPPUNIT_ASSERT_EQUAL(key, *iter);
- ++iter;
- }
- }
+ // compact sketch stream and bytes comparison
+ {
+ std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+ update_sketch.compact().serialize(s);
+ auto bytes = update_sketch.compact().serialize();
+ REQUIRE(bytes.size() == s.tellp());
+ for (size_t i = 0; i < bytes.size(); ++i) {
+ REQUIRE(((char*)bytes.data())[i] == (char)s.get());
}
- // compact sketch stream and bytes comparison
+ // deserialize as base class
{
- std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
- update_sketch.compact().serialize(s);
- auto bytes = update_sketch.compact().serialize();
- CPPUNIT_ASSERT_EQUAL((size_t) s.tellp(), bytes.size());
- for (size_t i = 0; i < bytes.size(); ++i) {
- CPPUNIT_ASSERT_EQUAL((char)s.get(), ((char*)bytes.data())[i]);
- }
-
- // deserialize as base class
- {
- s.seekg(0); // rewind
- auto deserialized_sketch_ptr1 = theta_sketch::deserialize(s);
- auto deserialized_sketch_ptr2 = theta_sketch::deserialize(bytes.data(), bytes.size());
- CPPUNIT_ASSERT_EQUAL(bytes.size(), (size_t) s.tellg());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->is_empty(), deserialized_sketch_ptr2->is_empty());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->is_ordered(), deserialized_sketch_ptr2->is_ordered());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_num_retained(), deserialized_sketch_ptr2->get_num_retained());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_theta(), deserialized_sketch_ptr2->get_theta());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_estimate(), deserialized_sketch_ptr2->get_estimate());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_lower_bound(1), deserialized_sketch_ptr2->get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch_ptr1->get_upper_bound(1), deserialized_sketch_ptr2->get_upper_bound(1));
- // the sketches are ordered, so the iteration sequence must match exactly
- auto iter = deserialized_sketch_ptr1->begin();
- for (auto key: *deserialized_sketch_ptr2) {
- CPPUNIT_ASSERT_EQUAL(key, *iter);
- ++iter;
- }
+ s.seekg(0); // rewind
+ auto deserialized_sketch_ptr1 = theta_sketch::deserialize(s);
+ auto deserialized_sketch_ptr2 = theta_sketch::deserialize(bytes.data(), bytes.size());
+ REQUIRE(s.tellg() == bytes.size());
+ REQUIRE(deserialized_sketch_ptr2->is_empty() == deserialized_sketch_ptr1->is_empty());
+ REQUIRE(deserialized_sketch_ptr2->is_ordered() == deserialized_sketch_ptr1->is_ordered());
+ REQUIRE(deserialized_sketch_ptr2->get_num_retained() == deserialized_sketch_ptr1->get_num_retained());
+ REQUIRE(deserialized_sketch_ptr2->get_theta() == deserialized_sketch_ptr1->get_theta());
+ REQUIRE(deserialized_sketch_ptr2->get_estimate() == deserialized_sketch_ptr1->get_estimate());
+ REQUIRE(deserialized_sketch_ptr2->get_lower_bound(1) == deserialized_sketch_ptr1->get_lower_bound(1));
+ REQUIRE(deserialized_sketch_ptr2->get_upper_bound(1) == deserialized_sketch_ptr1->get_upper_bound(1));
+ // the sketches are ordered, so the iteration sequence must match exactly
+ auto iter = deserialized_sketch_ptr1->begin();
+ for (auto key: *deserialized_sketch_ptr2) {
+ REQUIRE(*iter == key);
+ ++iter;
}
+ }
- // deserialize as subclass
- {
- s.seekg(0); // rewind
- compact_theta_sketch deserialized_sketch1 = compact_theta_sketch::deserialize(s);
- compact_theta_sketch deserialized_sketch2 = compact_theta_sketch::deserialize(bytes.data(), bytes.size());
- CPPUNIT_ASSERT_EQUAL(bytes.size(), (size_t) s.tellg());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.is_empty(), deserialized_sketch2.is_empty());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.is_ordered(), deserialized_sketch2.is_ordered());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_num_retained(), deserialized_sketch2.get_num_retained());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_theta(), deserialized_sketch2.get_theta());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_estimate(), deserialized_sketch2.get_estimate());
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_lower_bound(1), deserialized_sketch2.get_lower_bound(1));
- CPPUNIT_ASSERT_EQUAL(deserialized_sketch1.get_upper_bound(1), deserialized_sketch2.get_upper_bound(1));
- // the sketches are ordered, so the iteration sequence must match exactly
- auto iter = deserialized_sketch1.begin();
- for (auto key: deserialized_sketch2) {
- CPPUNIT_ASSERT_EQUAL(key, *iter);
- ++iter;
- }
+ // deserialize as subclass
+ {
+ s.seekg(0); // rewind
+ compact_theta_sketch deserialized_sketch1 = compact_theta_sketch::deserialize(s);
+ compact_theta_sketch deserialized_sketch2 = compact_theta_sketch::deserialize(bytes.data(), bytes.size());
+ REQUIRE(s.tellg() == bytes.size());
+ REQUIRE(deserialized_sketch2.is_empty() == deserialized_sketch1.is_empty());
+ REQUIRE(deserialized_sketch2.is_ordered() == deserialized_sketch1.is_ordered());
+ REQUIRE(deserialized_sketch2.get_num_retained() == deserialized_sketch1.get_num_retained());
+ REQUIRE(deserialized_sketch2.get_theta() == deserialized_sketch1.get_theta());
+ REQUIRE(deserialized_sketch2.get_estimate() == deserialized_sketch1.get_estimate());
+ REQUIRE(deserialized_sketch2.get_lower_bound(1) == deserialized_sketch1.get_lower_bound(1));
+ REQUIRE(deserialized_sketch2.get_upper_bound(1) == deserialized_sketch1.get_upper_bound(1));
+ // the sketches are ordered, so the iteration sequence must match exactly
+ auto iter = deserialized_sketch1.begin();
+ for (auto key: deserialized_sketch2) {
+ REQUIRE(*iter == key);
+ ++iter;
}
}
}
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(theta_sketch_test);
-
-#ifdef TEST_BINARY_INPUT_PATH
-const std::string theta_sketch_test::inputPath = TEST_BINARY_INPUT_PATH;
-#else
-const std::string theta_sketch_test::inputPath = "test/";
-#endif
-
+}
} /* namespace datasketches */
diff --git a/theta/test/theta_union_test.cpp b/theta/test/theta_union_test.cpp
index 48d6336..17db018 100644
--- a/theta/test/theta_union_test.cpp
+++ b/theta/test/theta_union_test.cpp
@@ -17,96 +17,81 @@
* under the License.
*/
-#include <cppunit/TestFixture.h>
-#include <cppunit/extensions/HelperMacros.h>
+#include <catch.hpp>
#include <theta_union.hpp>
namespace datasketches {
-class theta_union_test: public CppUnit::TestFixture {
-
- CPPUNIT_TEST_SUITE(theta_union_test);
- CPPUNIT_TEST(empty);
- CPPUNIT_TEST(non_empty_no_retained_keys);
- CPPUNIT_TEST(exact_mode_half_overlap);
- CPPUNIT_TEST(estimation_mode_half_overlap);
- CPPUNIT_TEST(seed_mismatch);
- CPPUNIT_TEST_SUITE_END();
-
- void empty() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- theta_union u = theta_union::builder().build();
- compact_theta_sketch sketch2 = u.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, sketch2.get_num_retained());
- CPPUNIT_ASSERT(sketch2.is_empty());
- CPPUNIT_ASSERT(!sketch2.is_estimation_mode());
-
- u.update(sketch1);
- sketch2 = u.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, sketch2.get_num_retained());
- CPPUNIT_ASSERT(sketch2.is_empty());
- CPPUNIT_ASSERT(!sketch2.is_estimation_mode());
- }
-
- void non_empty_no_retained_keys() {
- update_theta_sketch update_sketch = update_theta_sketch::builder().set_p(0.001).build();
- update_sketch.update(1);
- theta_union u = theta_union::builder().build();
- u.update(update_sketch);
- compact_theta_sketch sketch = u.get_result();
- CPPUNIT_ASSERT_EQUAL(0U, sketch.get_num_retained());
- CPPUNIT_ASSERT(!sketch.is_empty());
- CPPUNIT_ASSERT(sketch.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0.001, sketch.get_theta(), 1e-10);
- }
-
- void exact_mode_half_overlap() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 1000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- value = 500;
- for (int i = 0; i < 1000; i++) sketch2.update(value++);
-
- theta_union u = theta_union::builder().build();
- u.update(sketch1);
- u.update(sketch2);
- compact_theta_sketch sketch3 = u.get_result();
- CPPUNIT_ASSERT(!sketch3.is_empty());
- CPPUNIT_ASSERT(!sketch3.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(1500, sketch3.get_estimate(), 1500 * 0.01);
- }
-
- void estimation_mode_half_overlap() {
- update_theta_sketch sketch1 = update_theta_sketch::builder().build();
- int value = 0;
- for (int i = 0; i < 10000; i++) sketch1.update(value++);
-
- update_theta_sketch sketch2 = update_theta_sketch::builder().build();
- value = 5000;
- for (int i = 0; i < 10000; i++) sketch2.update(value++);
-
- theta_union u = theta_union::builder().build();
- u.update(sketch1);
- u.update(sketch2);
- compact_theta_sketch sketch3 = u.get_result();
- CPPUNIT_ASSERT(!sketch3.is_empty());
- CPPUNIT_ASSERT(sketch3.is_estimation_mode());
- CPPUNIT_ASSERT_DOUBLES_EQUAL(15000, sketch3.get_estimate(), 15000 * 0.01);
- //sketch3.to_stream(std::cerr, true);
- }
-
- void seed_mismatch() {
- update_theta_sketch sketch = update_theta_sketch::builder().build();
- sketch.update(1); // non-empty should not be ignored
- theta_union u = theta_union::builder().set_seed(123).build();
- CPPUNIT_ASSERT_THROW(u.update(sketch), std::invalid_argument);
- }
-
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION(theta_union_test);
+TEST_CASE("theta union: empty", "[theta_union]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ theta_union u = theta_union::builder().build();
+ compact_theta_sketch sketch2 = u.get_result();
+ REQUIRE(sketch2.get_num_retained() == 0);
+ REQUIRE(sketch2.is_empty());
+ REQUIRE_FALSE(sketch2.is_estimation_mode());
+
+ u.update(sketch1);
+ sketch2 = u.get_result();
+ REQUIRE(sketch2.get_num_retained() == 0);
+ REQUIRE(sketch2.is_empty());
+ REQUIRE_FALSE(sketch2.is_estimation_mode());
+}
+
+TEST_CASE("theta union: non empty no retained keys", "[theta_union]") {
+ update_theta_sketch update_sketch = update_theta_sketch::builder().set_p(0.001).build();
+ update_sketch.update(1);
+ theta_union u = theta_union::builder().build();
+ u.update(update_sketch);
+ compact_theta_sketch sketch = u.get_result();
+ REQUIRE(sketch.get_num_retained() == 0);
+ REQUIRE_FALSE(sketch.is_empty());
+ REQUIRE(sketch.is_estimation_mode());
+ REQUIRE(sketch.get_theta() == Approx(0.001).margin(1e-10));
+}
+
+TEST_CASE("theta union: exact mode half overlap", "[theta_union]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 1000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ value = 500;
+ for (int i = 0; i < 1000; i++) sketch2.update(value++);
+
+ theta_union u = theta_union::builder().build();
+ u.update(sketch1);
+ u.update(sketch2);
+ compact_theta_sketch sketch3 = u.get_result();
+ REQUIRE_FALSE(sketch3.is_empty());
+ REQUIRE_FALSE(sketch3.is_estimation_mode());
+ REQUIRE(sketch3.get_estimate() == Approx(1500).margin(1500 * 0.01));
+}
+
+TEST_CASE("theta union: estimation mode half overlap", "[theta_union]") {
+ update_theta_sketch sketch1 = update_theta_sketch::builder().build();
+ int value = 0;
+ for (int i = 0; i < 10000; i++) sketch1.update(value++);
+
+ update_theta_sketch sketch2 = update_theta_sketch::builder().build();
+ value = 5000;
+ for (int i = 0; i < 10000; i++) sketch2.update(value++);
+
+ theta_union u = theta_union::builder().build();
+ u.update(sketch1);
+ u.update(sketch2);
+ compact_theta_sketch sketch3 = u.get_result();
+ REQUIRE_FALSE(sketch3.is_empty());
+ REQUIRE(sketch3.is_estimation_mode());
+ REQUIRE(sketch3.get_estimate() == Approx(15000).margin(15000 * 0.01));
+ //sketch3.to_stream(std::cerr, true);
+}
+
+TEST_CASE("theta union: seed mismatch", "[theta_union]") {
+ update_theta_sketch sketch = update_theta_sketch::builder().build();
+ sketch.update(1); // non-empty should not be ignored
+ theta_union u = theta_union::builder().set_seed(123).build();
+ REQUIRE_THROWS_AS(u.update(sketch), std::invalid_argument);
+}
} /* namespace datasketches */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datasketches.apache.org
For additional commands, e-mail: commits-help@datasketches.apache.org