Advanced Chunk Processing Library 0.2.0
A comprehensive C++ library for advanced data chunking strategies and processing operations
Loading...
Searching...
No Matches
test_metrics.cpp
Go to the documentation of this file.
1#include "chunk_metrics.hpp"
2#include "test_base.hpp"
3#include <algorithm>
4#include <atomic>
5#include <chrono>
6#include <condition_variable>
7#include <future>
8#include <iostream>
9#include <limits>
10#include <memory>
11#include <mutex>
12#include <stdexcept>
13#include <thread>
14#include <vector>
15
17protected:
18 std::unique_ptr<chunk_metrics::ChunkQualityAnalyzer<double>> analyzer;
19 std::vector<std::vector<double>> well_separated_chunks;
20 std::vector<std::vector<double>> mixed_cohesion_chunks;
21 std::vector<std::vector<double>> empty_chunks;
22 mutable std::mutex test_mutex_;
23 std::atomic<bool> test_running_{false};
24
25 void SetUp() override {
27
28 try {
29 // Initialize analyzer with proper error checking
30 analyzer = std::make_unique<chunk_metrics::ChunkQualityAnalyzer<double>>();
31 if (!analyzer) {
32 throw std::runtime_error("Failed to create analyzer");
33 }
34
35 // Initialize test data with bounds checking
36 well_separated_chunks = {std::vector<double>{1.0, 1.1, 1.2},
37 std::vector<double>{5.0, 5.1, 5.2},
38 std::vector<double>{10.0, 10.1, 10.2}};
39
40 mixed_cohesion_chunks = {std::vector<double>{1.0, 1.1, 5.0},
41 std::vector<double>{2.0, 2.1, 8.0},
42 std::vector<double>{3.0, 3.1, 9.0}};
43
44 // Validate test data
45 for (const auto& chunk : well_separated_chunks) {
46 if (chunk.empty() || chunk.size() > 1000000) {
47 throw std::runtime_error("Invalid test data in well_separated_chunks");
48 }
49 }
50 for (const auto& chunk : mixed_cohesion_chunks) {
51 if (chunk.empty() || chunk.size() > 1000000) {
52 throw std::runtime_error("Invalid test data in mixed_cohesion_chunks");
53 }
54 }
55
56 } catch (const std::exception& e) {
57 FAIL() << "Setup failed: " << e.what();
58 }
59 }
60
61 void TearDown() override {
62 try {
63 std::lock_guard<std::mutex> lock(test_mutex_);
64
65 if (analyzer) {
66 // Ensure no computations are running
67 std::this_thread::sleep_for(std::chrono::milliseconds(100));
68 analyzer.reset();
69 }
70
73 empty_chunks.clear();
74
75 } catch (...) {
76 // Ensure base teardown still happens
77 }
78
80 }
81
82 // Helper to safely run computations with explicit return type
83 template <typename Func>
84 auto run_safely(Func&& func) -> typename std::invoke_result<Func>::type {
85 if (test_running_.exchange(true)) {
86 throw std::runtime_error("Test already running");
87 }
88
89 struct TestGuard {
90 std::atomic<bool>& flag;
91 TestGuard(std::atomic<bool>& f) : flag(f) {}
92 ~TestGuard() {
93 flag = false;
94 }
95 } guard(test_running_);
96
97 return func();
98 }
99};
100
101TEST_F(ChunkMetricsTest, CohesionCalculation) {
102 ASSERT_TRUE(analyzer != nullptr) << "Analyzer is null";
103 ASSERT_FALSE(well_separated_chunks.empty()) << "Well separated chunks is empty";
104 ASSERT_FALSE(mixed_cohesion_chunks.empty()) << "Mixed cohesion chunks is empty";
105
106 try {
107 double high_cohesion = 0.0;
108 double mixed_cohesion = 0.0;
109
110 bool success = analyzer->compare_cohesion(
111 well_separated_chunks,
112 mixed_cohesion_chunks,
113 high_cohesion,
114 mixed_cohesion
115 );
116
117 ASSERT_TRUE(success) << "Cohesion comparison failed";
118 ASSERT_TRUE(std::isfinite(high_cohesion)) << "High cohesion is not finite";
119 ASSERT_TRUE(std::isfinite(mixed_cohesion)) << "Mixed cohesion is not finite";
120
121 EXPECT_GT(high_cohesion, mixed_cohesion)
122 << "High cohesion (" << high_cohesion
123 << ") should be greater than mixed cohesion (" << mixed_cohesion << ")";
124
125 } catch (const std::exception& e) {
126 FAIL() << "Unexpected exception: " << e.what();
127 }
128}
129
130TEST_F(ChunkMetricsTest, SeparationCalculation) {
131 double separation = analyzer->compute_separation(well_separated_chunks);
132 EXPECT_GT(separation, 0.0);
133 EXPECT_LE(separation, 1.0);
134}
135
136TEST_F(ChunkMetricsTest, SilhouetteScore) {
137 double silhouette = analyzer->compute_silhouette_score(well_separated_chunks);
138 EXPECT_GE(silhouette, -1.0);
139 EXPECT_LE(silhouette, 1.0);
140}
141
142TEST_F(ChunkMetricsTest, QualityScore) {
143 ASSERT_TRUE(analyzer != nullptr);
144
145 try {
146 auto result = run_safely([this]() -> std::pair<double, double> {
147 std::unique_lock<std::mutex> lock(test_mutex_);
148
149 double high_quality = analyzer->compute_quality_score(well_separated_chunks);
150 analyzer->clear_cache();
151 double mixed_quality = analyzer->compute_quality_score(mixed_cohesion_chunks);
152
153 if (!std::isfinite(high_quality) || !std::isfinite(mixed_quality)) {
154 throw std::runtime_error("Invalid quality score results");
155 }
156
157 return std::make_pair(high_quality, mixed_quality);
158 });
159
160 EXPECT_GT(result.first, result.second)
161 << "High quality should be greater than mixed quality";
162 EXPECT_GE(result.first, 0.0) << "Quality score should be non-negative";
163 EXPECT_LE(result.first, 1.0) << "Quality score should not exceed 1.0";
164
165 } catch (const std::exception& e) {
166 FAIL() << "Unexpected exception: " << e.what();
167 }
168}
169
171 auto metrics = analyzer->compute_size_metrics(well_separated_chunks);
172
173 EXPECT_EQ(metrics["average_size"], 3.0);
174 EXPECT_EQ(metrics["max_size"], 3.0);
175 EXPECT_EQ(metrics["min_size"], 3.0);
176 EXPECT_NEAR(metrics["size_variance"], 0.0, 1e-10);
177}
178
180 std::vector<std::vector<double>> empty_chunks;
181 EXPECT_THROW(analyzer->compute_quality_score(empty_chunks), std::invalid_argument);
182 EXPECT_THROW(analyzer->compute_cohesion(empty_chunks), std::invalid_argument);
183 EXPECT_THROW(analyzer->compute_separation(empty_chunks), std::invalid_argument);
184 EXPECT_THROW(analyzer->compute_silhouette_score(empty_chunks), std::invalid_argument);
185 EXPECT_THROW(analyzer->compute_size_metrics(empty_chunks), std::invalid_argument);
186}
187
189 std::vector<std::vector<double>> single_chunk = {{1.0, 2.0, 3.0}};
190 EXPECT_NO_THROW(analyzer->compute_cohesion(single_chunk));
191 EXPECT_THROW(analyzer->compute_separation(single_chunk), std::invalid_argument);
192 EXPECT_THROW(analyzer->compute_silhouette_score(single_chunk), std::invalid_argument);
193 EXPECT_NO_THROW(analyzer->compute_quality_score(single_chunk));
194}
195
197 analyzer->compute_cohesion(well_separated_chunks);
198 analyzer->compute_separation(well_separated_chunks);
199 analyzer->clear_cache();
200 // Verify the function runs without errors
201 EXPECT_NO_THROW(analyzer->compute_cohesion(well_separated_chunks));
202}
Quality metrics and analysis tools for chunk evaluation.
auto run_safely(Func &&func) -> typename std::invoke_result< Func >::type
std::vector< std::vector< double > > mixed_cohesion_chunks
std::vector< std::vector< double > > well_separated_chunks
void SetUp() override
void TearDown() override
std::vector< std::vector< double > > empty_chunks
std::mutex test_mutex_
std::unique_ptr< chunk_metrics::ChunkQualityAnalyzer< double > > analyzer
std::atomic< bool > test_running_
void SetUp() override
Definition test_base.cpp:8
void TearDown() override
Definition test_base.cpp:15
TEST_F(ChunkMetricsTest, CohesionCalculation)