Skip to content

Commit 62b2652

Browse files
Add tests for search functionality in clusters.h.
Fix missing edge cases in clusters.h.
1 parent c244a63 commit 62b2652

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

centrallix-lib/src/clusters.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,15 @@ pXArray ca_sliding_search(
983983
void** maybe_keys,
984984
pXArray maybe_dups)
985985
{
986+
/** Error cases. **/
987+
if (data == NULL
988+
|| num_data == 0
989+
|| window_size == 0
990+
|| similarity == NULL
991+
|| (threshold < 0.0 || 1.0 < threshold)
992+
|| isnan(threshold)
993+
) return NULL;
994+
986995
/** Allocate space for dups (if necessary). **/
987996
pXArray dups = maybe_dups;
988997
if (dups == NULL)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/************************************************************************/
2+
/* Centrallix Application Server System */
3+
/* Centrallix Base Library */
4+
/* */
5+
/* Copyright (C) 2005 LightSys Technology Services, Inc. */
6+
/* */
7+
/* You may use these files and this library under the terms of the */
8+
/* GNU Lesser General Public License, Version 2.1, contained in the */
9+
/* included file "COPYING". */
10+
/* */
11+
/* Module: test_clusters_06.c */
12+
/* Author: Israel Fuller */
13+
/* Creation: November 26th, 2025 */
14+
/* Description: Test the searching functions from clusters.h. */
15+
/************************************************************************/
16+
17+
#include <limits.h>
18+
#include <math.h>
19+
#include <stdbool.h>
20+
#include <stdio.h>
21+
#include <stdlib.h>
22+
23+
/** Test dependencies. **/
24+
#include "test_utils.h"
25+
#include "util.h"
26+
27+
/** Tested module. **/
28+
#include "clusters.h"
29+
30+
31+
static int cmp_dups(const void* v1, const void* v2)
32+
{
33+
const Dup* dup1 = v1;
34+
const Dup* dup2 = v2;
35+
const int r = strcmp(dup1->key1, dup2->key1);
36+
return (r != 0) ? r : strcmp(dup1->key2, dup2->key2);
37+
}
38+
39+
#define EXPECT_DUP(dup, k1, k2, sim_min, sim_max) \
40+
({ \
41+
bool success = true; \
42+
pDup d = (dup); \
43+
success &= EXPECT_STR_EQL(d->key1, k1); \
44+
success &= EXPECT_STR_EQL(d->key2, k2); \
45+
success &= EXPECT_RANGE(d->similarity, sim_min, sim_max, "%g"); \
46+
success; \
47+
})
48+
49+
50+
static bool do_tests(void)
51+
{
52+
bool success = true;
53+
54+
/** Allocate some test data. **/
55+
void* data[] = {
56+
"string",
57+
"string2",
58+
"str",
59+
"hello world",
60+
"data",
61+
"string3",
62+
};
63+
void* keys[] = { "1", "2", "3", "4", "5", "6" };
64+
65+
/** Check error cases. **/
66+
success &= EXPECT_EQL(ca_complete_search(NULL, 6, ca_lev_compare, 0.8, NULL, NULL), NULL, "%p");
67+
success &= EXPECT_EQL(ca_complete_search(data, 0, ca_lev_compare, 0.8, NULL, NULL), NULL, "%p");
68+
success &= EXPECT_EQL(ca_complete_search(data, 6, NULL, 0.8, NULL, NULL), NULL, "%p");
69+
success &= EXPECT_EQL(ca_complete_search(data, 6, ca_lev_compare, 1.1, NULL, NULL), NULL, "%p");
70+
success &= EXPECT_EQL(ca_complete_search(data, 6, ca_lev_compare, -0.1, NULL, NULL), NULL, "%p");
71+
success &= EXPECT_EQL(ca_complete_search(data, 6, ca_lev_compare, INFINITY, NULL, NULL), NULL, "%p");
72+
success &= EXPECT_EQL(ca_complete_search(data, 6, ca_lev_compare, -INFINITY, NULL, NULL), NULL, "%p");
73+
success &= EXPECT_EQL(ca_complete_search(data, 6, ca_lev_compare, NAN, NULL, NULL), NULL, "%p");
74+
75+
/** Test complete search. **/
76+
{
77+
XArray xdups;
78+
if (!check(xaInit(&xdups, 4))) return false;
79+
success &= EXPECT_EQL(ca_complete_search(data, 6, ca_lev_compare, 0.8, keys, &xdups), &xdups, "%p");
80+
pDup* dups = (pDup*)xdups.Items;
81+
for (unsigned int i = 0u; i < xdups.nItems; i++)
82+
{
83+
pDup cur = dups[i];
84+
if (cur->key1 > cur->key2)
85+
{
86+
char* temp = cur->key1;
87+
cur->key1 = cur->key2;
88+
cur->key2 = temp;
89+
}
90+
}
91+
qsort(dups, xdups.nItems, sizeof(pDup), cmp_dups);
92+
success &= EXPECT_EQL(xdups.nItems, 3, "%d");
93+
success &= EXPECT_DUP(dups[0], "1", "2", 0.8, 1.0);
94+
success &= EXPECT_DUP(dups[1], "1", "6", 0.8, 1.0);
95+
success &= EXPECT_DUP(dups[2], "2", "6", 0.8, 1.0);
96+
}
97+
98+
/** Test sliding search: Large window. **/
99+
{
100+
XArray xdups;
101+
if (!check(xaInit(&xdups, 4))) return false;
102+
success &= EXPECT_EQL(ca_sliding_search(data, 6, 5, ca_lev_compare, 0.8, keys, &xdups), &xdups, "%p");
103+
pDup* dups = (pDup*)xdups.Items;
104+
for (unsigned int i = 0u; i < xdups.nItems; i++)
105+
{
106+
pDup cur = dups[i];
107+
if (cur->key1 > cur->key2)
108+
{
109+
char* temp = cur->key1;
110+
cur->key1 = cur->key2;
111+
cur->key2 = temp;
112+
}
113+
}
114+
qsort(dups, xdups.nItems, sizeof(pDup), cmp_dups);
115+
success &= EXPECT_EQL(xdups.nItems, 2, "%d");
116+
success &= EXPECT_DUP(dups[0], "1", "2", 0.8, 1.0);
117+
// success &= EXPECT_DUP(dups[1], "1", "6", 0.8, 1.0); /* Missed. */
118+
success &= EXPECT_DUP(dups[1], "2", "6", 0.8, 1.0);
119+
}
120+
121+
/** Test sliding search: Small window. **/
122+
{
123+
XArray xdups;
124+
if (!check(xaInit(&xdups, 4))) return false;
125+
success &= EXPECT_EQL(ca_sliding_search(data, 6, 2, ca_lev_compare, 0.8, keys, &xdups), &xdups, "%p");
126+
pDup* dups = (pDup*)xdups.Items;
127+
for (unsigned int i = 0u; i < xdups.nItems; i++)
128+
{
129+
pDup cur = dups[i];
130+
if (cur->key1 > cur->key2)
131+
{
132+
char* temp = cur->key1;
133+
cur->key1 = cur->key2;
134+
cur->key2 = temp;
135+
}
136+
}
137+
qsort(dups, xdups.nItems, sizeof(pDup), cmp_dups);
138+
success &= EXPECT_EQL(xdups.nItems, 1, "%d");
139+
success &= EXPECT_DUP(dups[0], "1", "2", 0.8, 1.0);
140+
// success &= EXPECT_DUP(dups[1], "1", "6", 0.8, 1.0); /* Missed. */
141+
// success &= EXPECT_DUP(dups[2], "2", "6", 0.8, 1.0); /* Missed. */
142+
}
143+
144+
return success;
145+
}
146+
147+
long long test(char** tname)
148+
{
149+
*tname = "cluster-06 Searching";
150+
return loop_tests(do_tests);
151+
}

0 commit comments

Comments
 (0)