1+ package ai .chronon .aggregator .test
2+
3+ import ai .chronon .aggregator .base .BoundedUniqueCount
4+ import ai .chronon .api .{StringType , IntType , LongType , DoubleType , FloatType , BinaryType }
5+ import junit .framework .TestCase
6+ import org .junit .Assert ._
7+
8+ import java .util
9+ import scala .jdk .CollectionConverters ._
10+
11+ class BoundedUniqueCountTest extends TestCase {
12+ def testHappyCase (): Unit = {
13+ val boundedDistinctCount = new BoundedUniqueCount [String ](StringType , 5 )
14+ var ir = boundedDistinctCount.prepare(" 1" )
15+ ir = boundedDistinctCount.update(ir, " 1" )
16+ ir = boundedDistinctCount.update(ir, " 2" )
17+
18+ val result = boundedDistinctCount.finalize(ir)
19+ assertEquals(2 , result)
20+ }
21+
22+ def testExceedSize (): Unit = {
23+ val boundedDistinctCount = new BoundedUniqueCount [String ](StringType , 5 )
24+ var ir = boundedDistinctCount.prepare(" 1" )
25+ ir = boundedDistinctCount.update(ir, " 2" )
26+ ir = boundedDistinctCount.update(ir, " 3" )
27+ ir = boundedDistinctCount.update(ir, " 4" )
28+ ir = boundedDistinctCount.update(ir, " 5" )
29+ ir = boundedDistinctCount.update(ir, " 6" )
30+ ir = boundedDistinctCount.update(ir, " 7" )
31+
32+ val result = boundedDistinctCount.finalize(ir)
33+ assertEquals(5 , result)
34+ }
35+
36+ def testMerge (): Unit = {
37+ val boundedDistinctCount = new BoundedUniqueCount [String ](StringType , 5 )
38+ val ir1 = new util.HashSet [Any ](Seq (" 1" , " 2" , " 3" ).asJava)
39+ val ir2 = new util.HashSet [Any ](Seq (" 4" , " 5" , " 6" ).asJava)
40+
41+ val merged = boundedDistinctCount.merge(ir1, ir2)
42+ val result = boundedDistinctCount.finalize(merged)
43+ assertEquals(5 , result) // Should return k=5 when exceeding the limit
44+ }
45+
46+ def testIntTypeHappyCase (): Unit = {
47+ val boundedDistinctCount = new BoundedUniqueCount [Int ](IntType , 5 )
48+ var ir = boundedDistinctCount.prepare(1 )
49+ ir = boundedDistinctCount.update(ir, 1 )
50+ ir = boundedDistinctCount.update(ir, 2 )
51+
52+ val result = boundedDistinctCount.finalize(ir)
53+ assertEquals(2 , result)
54+ }
55+
56+ def testIntTypeExceedSize (): Unit = {
57+ val boundedDistinctCount = new BoundedUniqueCount [Int ](IntType , 5 )
58+ var ir = boundedDistinctCount.prepare(1 )
59+ ir = boundedDistinctCount.update(ir, 2 )
60+ ir = boundedDistinctCount.update(ir, 3 )
61+ ir = boundedDistinctCount.update(ir, 4 )
62+ ir = boundedDistinctCount.update(ir, 5 )
63+ ir = boundedDistinctCount.update(ir, 6 )
64+ ir = boundedDistinctCount.update(ir, 7 )
65+
66+ val result = boundedDistinctCount.finalize(ir)
67+ assertEquals(5 , result)
68+ }
69+
70+ def testIntTypeMerge (): Unit = {
71+ val boundedDistinctCount = new BoundedUniqueCount [Int ](IntType , 5 )
72+ val ir1 = new util.HashSet [Any ](Seq (1 , 2 , 3 ).asJava)
73+ val ir2 = new util.HashSet [Any ](Seq (4 , 5 , 6 ).asJava)
74+
75+ val merged = boundedDistinctCount.merge(ir1, ir2)
76+ val result = boundedDistinctCount.finalize(merged)
77+ assertEquals(5 , result) // Should return k=5 when exceeding the limit
78+ }
79+
80+ def testLongTypeHappyCase (): Unit = {
81+ val boundedDistinctCount = new BoundedUniqueCount [Long ](LongType , 5 )
82+ var ir = boundedDistinctCount.prepare(1L )
83+ ir = boundedDistinctCount.update(ir, 1L )
84+ ir = boundedDistinctCount.update(ir, 2L )
85+
86+ val result = boundedDistinctCount.finalize(ir)
87+ assertEquals(2 , result)
88+ }
89+
90+ def testLongTypeExceedSize (): Unit = {
91+ val boundedDistinctCount = new BoundedUniqueCount [Long ](LongType , 5 )
92+ var ir = boundedDistinctCount.prepare(1L )
93+ ir = boundedDistinctCount.update(ir, 2L )
94+ ir = boundedDistinctCount.update(ir, 3L )
95+ ir = boundedDistinctCount.update(ir, 4L )
96+ ir = boundedDistinctCount.update(ir, 5L )
97+ ir = boundedDistinctCount.update(ir, 6L )
98+ ir = boundedDistinctCount.update(ir, 7L )
99+
100+ val result = boundedDistinctCount.finalize(ir)
101+ assertEquals(5 , result)
102+ }
103+
104+ def testDoubleTypeHappyCase (): Unit = {
105+ val boundedDistinctCount = new BoundedUniqueCount [Double ](DoubleType , 5 )
106+ var ir = boundedDistinctCount.prepare(1.0 )
107+ ir = boundedDistinctCount.update(ir, 1.0 )
108+ ir = boundedDistinctCount.update(ir, 2.5 )
109+
110+ val result = boundedDistinctCount.finalize(ir)
111+ assertEquals(2 , result)
112+ }
113+
114+ def testDoubleTypeExceedSize (): Unit = {
115+ val boundedDistinctCount = new BoundedUniqueCount [Double ](DoubleType , 5 )
116+ var ir = boundedDistinctCount.prepare(1.0 )
117+ ir = boundedDistinctCount.update(ir, 2.5 )
118+ ir = boundedDistinctCount.update(ir, 3.7 )
119+ ir = boundedDistinctCount.update(ir, 4.2 )
120+ ir = boundedDistinctCount.update(ir, 5.8 )
121+ ir = boundedDistinctCount.update(ir, 6.3 )
122+ ir = boundedDistinctCount.update(ir, 7.9 )
123+
124+ val result = boundedDistinctCount.finalize(ir)
125+ assertEquals(5 , result)
126+ }
127+
128+ def testFloatTypeHappyCase (): Unit = {
129+ val boundedDistinctCount = new BoundedUniqueCount [Float ](FloatType , 5 )
130+ var ir = boundedDistinctCount.prepare(1.0f )
131+ ir = boundedDistinctCount.update(ir, 1.0f )
132+ ir = boundedDistinctCount.update(ir, 2.5f )
133+
134+ val result = boundedDistinctCount.finalize(ir)
135+ assertEquals(2 , result)
136+ }
137+
138+ def testFloatTypeExceedSize (): Unit = {
139+ val boundedDistinctCount = new BoundedUniqueCount [Float ](FloatType , 5 )
140+ var ir = boundedDistinctCount.prepare(1.0f )
141+ ir = boundedDistinctCount.update(ir, 2.5f )
142+ ir = boundedDistinctCount.update(ir, 3.7f )
143+ ir = boundedDistinctCount.update(ir, 4.2f )
144+ ir = boundedDistinctCount.update(ir, 5.8f )
145+ ir = boundedDistinctCount.update(ir, 6.3f )
146+ ir = boundedDistinctCount.update(ir, 7.9f )
147+
148+ val result = boundedDistinctCount.finalize(ir)
149+ assertEquals(5 , result)
150+ }
151+
152+ def testBinaryTypeHappyCase (): Unit = {
153+ val boundedDistinctCount = new BoundedUniqueCount [Array [Byte ]](BinaryType , 5 )
154+ val bytes1 = Array [Byte ](1 , 2 , 3 )
155+ val bytes2 = Array [Byte ](4 , 5 , 6 )
156+
157+ var ir = boundedDistinctCount.prepare(bytes1)
158+ ir = boundedDistinctCount.update(ir, bytes1)
159+ ir = boundedDistinctCount.update(ir, bytes2)
160+
161+ val result = boundedDistinctCount.finalize(ir)
162+ assertEquals(2 , result)
163+ }
164+
165+ def testBinaryTypeExceedSize (): Unit = {
166+ val boundedDistinctCount = new BoundedUniqueCount [Array [Byte ]](BinaryType , 5 )
167+ var ir = boundedDistinctCount.prepare(Array [Byte ](1 ))
168+ ir = boundedDistinctCount.update(ir, Array [Byte ](2 ))
169+ ir = boundedDistinctCount.update(ir, Array [Byte ](3 ))
170+ ir = boundedDistinctCount.update(ir, Array [Byte ](4 ))
171+ ir = boundedDistinctCount.update(ir, Array [Byte ](5 ))
172+ ir = boundedDistinctCount.update(ir, Array [Byte ](6 ))
173+ ir = boundedDistinctCount.update(ir, Array [Byte ](7 ))
174+
175+ val result = boundedDistinctCount.finalize(ir)
176+ assertEquals(5 , result)
177+ }
178+
179+ def testBinaryTypeMerge (): Unit = {
180+ val boundedDistinctCount = new BoundedUniqueCount [Array [Byte ]](BinaryType , 5 )
181+ val ir1 = new util.HashSet [Any ](Seq (Array [Byte ](1 ), Array [Byte ](2 ), Array [Byte ](3 )).asJava)
182+ val ir2 = new util.HashSet [Any ](Seq (Array [Byte ](4 ), Array [Byte ](5 ), Array [Byte ](6 )).asJava)
183+
184+ val merged = boundedDistinctCount.merge(ir1, ir2)
185+ val result = boundedDistinctCount.finalize(merged)
186+ assertEquals(5 , result) // Should return k=5 when exceeding the limit
187+ }
188+
189+ def testNumericTypeIrType (): Unit = {
190+ val intBoundedDistinctCount = new BoundedUniqueCount [Int ](IntType , 5 )
191+ val longBoundedDistinctCount = new BoundedUniqueCount [Long ](LongType , 5 )
192+ val doubleBoundedDistinctCount = new BoundedUniqueCount [Double ](DoubleType , 5 )
193+ val floatBoundedDistinctCount = new BoundedUniqueCount [Float ](FloatType , 5 )
194+ val binaryBoundedDistinctCount = new BoundedUniqueCount [Array [Byte ]](BinaryType , 5 )
195+ val stringBoundedDistinctCount = new BoundedUniqueCount [String ](StringType , 5 )
196+
197+ // For numeric and binary types, irType should be ListType(inputType)
198+ assertEquals(ai.chronon.api.ListType (IntType ), intBoundedDistinctCount.irType)
199+ assertEquals(ai.chronon.api.ListType (LongType ), longBoundedDistinctCount.irType)
200+ assertEquals(ai.chronon.api.ListType (DoubleType ), doubleBoundedDistinctCount.irType)
201+ assertEquals(ai.chronon.api.ListType (FloatType ), floatBoundedDistinctCount.irType)
202+ assertEquals(ai.chronon.api.ListType (BinaryType ), binaryBoundedDistinctCount.irType)
203+
204+ // For non-numeric types, irType should be ListType(StringType)
205+ assertEquals(ai.chronon.api.ListType (StringType ), stringBoundedDistinctCount.irType)
206+ }
207+ }
0 commit comments