From ab6bf5268a728e61713afe0eba86c0edd6733bde Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:57:32 +0000 Subject: [PATCH 1/5] Initial plan From b65f5a5fecd9bdb3c2a97474e2a66541a4ff61db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:59:59 +0000 Subject: [PATCH 2/5] Initial exploration of test coverage Co-authored-by: jackrua <155536850+jackrua@users.noreply.github.com> --- .coverage | Bin 0 -> 53248 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .coverage diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..de1dde2cce26fbd9133e8d0c21ff5a0a23f8f198 GIT binary patch literal 53248 zcmeI4TWs6b8GuQV5>4Ic#B~(MP0U_W+lXz&?TR$Zx-3hLG)S{7ZBn#N8kv%gWG0fR zkW?JE=vsCK+F@(o)~CHKdDyTGSb;6TfNki@E-!oAFrXXKZNShzEZOy8=pObTUXSCr zYk)&!4t~OtDDs^DKmYe%4v%E&spC(WF40?--8EeOAz@e$Md5S0E(n4Oj}knhO@SRb zdIPT_v%lW1D$HH@N=bWKDCV9Kv@@k`+HA31{9EB0#YfbW1yh+(=imfxNB{{S0VHt8 z5b%x{mCD$d`07ipQST7fHX6hZo=XRxTsUxIK|gWe^G_`3!7+U*ufsMws~^y9Ygz9T zTW^^iqMN;@*)UwQ*Vf%7615&Uq)F#2I0my8Z8+!mr+YQC3B6p>1`&PR>>BopevYin z_zgmBF1hFi2S5lh+dbMsp9;HA>o#c-oAesQ2}UtxHmCE`Uw%2SR7OU`*NJbFVK?Bf zu*w=ZkeG6~1%euu-K3+h+eWXkM4TDjh%IbbFwTo^V6AO+tFEPY%${#%&oN!o>gnVn zX$)M_ys3dR6k4IbgCHx*Ye-j!1=X#cq+cOX-KI|Oo*?a_XCCEsnt!_ ziFedhK@%TdCv@of_2Y(S$?71XS=8z1R?ANr+FK8t1JTUpOf`aG*fh~}D{KfOy{*wk z2Mc4+>m94UI@bJ%aR?*`)Pks4YtU=ZRB@;c4eJ82jW(GJ&jw}Tb_WuK&b*qdEKIBy zI&lcp=HuPGHJ(kcDh}o z*9_+?It>R>q4v|{qJ}{wDyGAoecj^>I;_?z% zBQBVY9y46xnq8vPCjMajz*;sOy`)ii z=IJwCB@fX{Id4K#D!X=x-XP52pg7eWxDx0Zk*(p|%&N$`;banI$Dm5XB@!E46gb0> zz6~_ciWs=P9-xa_g%?QqX}Z7{wT}e&!wm@_0VIF~kN^@u0!RP}AOR$R1dsp{xbp}| zVn$Tx`ah$+FKE}`2{$Bw1dsp{Kmter2_OL^fCP{L5#}m%m=#SNe6yE|rVlDn3^DW8sCu=KOc_ht&7g zFR9yxemHbOxvqRwnauqx*UX98Z)QI$|4v?!N2TvePiC%V-puS0e<7X~6%fdAGp1z0 zJ5*h=x}<6kdOc!Smo58Twcox#8m?u}_E+2`t2aw;HnPq7|2z&29@)Knchx3s({YIn z_nH`!>8PmH%%17iYM|ou1EAtjo>maDOh^@Om7@mi@m!nuF z;_3JQQ^I9IyR426UD3Xf%VaMpe^sV(Way;wwcO9k{}6vEp3BT+u4mp7hlI=W7U?PZ z1?ipae);#sZ;I{g zR4}9`pO?Kyxmv-l{~zFPz?${{PDAzE2uPwNl<4>WqV^vF{%}JANB{{S z0VIF~kN^@u0!RP}AOR$R1nxirl2lUZ_y1Y#JA(Fa?L+Oi+K*uuHza@rkN^@u0!RP} zAOR$R1dsp{KmthMHWJXXvZ(6W)~S8(z4M~9_{zIuG937n{Py)9TD8;k*2UeLMB7S9+j0gD?8yA;%8$D3Q>|Ct&5E+Bme0`d|FhavLHkJir}h`^&#;Rd z5 zaI{DO2_OL^fCP{L5 Date: Wed, 14 Jan 2026 10:02:04 +0000 Subject: [PATCH 3/5] Add comprehensive tests for core vector classes Co-authored-by: jackrua <155536850+jackrua@users.noreply.github.com> --- .coverage | Bin 53248 -> 53248 bytes .gitignore | 1 + tests/test_bit.py | 72 +++++++++++++++++++++++++++++ tests/test_half_vector.py | 72 +++++++++++++++++++++++++++++ tests/test_sparse_vector.py | 90 ++++++++++++++++++++++++++++++++++++ tests/test_vector.py | 80 ++++++++++++++++++++++++++++++++ 6 files changed, 315 insertions(+) diff --git a/.coverage b/.coverage index de1dde2cce26fbd9133e8d0c21ff5a0a23f8f198..6f242357474e3bb3319ebf453038ae892842cafa 100644 GIT binary patch delta 114 zcmZozz}&Eac>`Mm&k6?qpZqWQukr8VU$I$GU>bj*04ob4rxI&gwDs+6)%ma2Ugwr# z0g9NhOnbleUC!-&`Q_W)U)JuwfB$yX>#s}#%pldwNUHgnfFcS^=eF<4O~3ta?{)6Y IKl|Ao0M}G5pa1{> delta 110 zcmZozz}&Eac>`Mm&l(2)pZqWRZ}9KsU$a?IU>3hGKPw9(rvhtQwDs*x)yxSE2PIj6 z0wyfe-fw-Eb9-NY`F8i0wfpbiXOKuR;AaM@Wk#swV*(1uF`e7KD>pqlt>NJ2pZ)9( E0B_$Y8vp 0 + + def test_from_binary(self): + bit = Bit([True, False, True, False, True, False, True, False]) + binary = bit.to_binary() + restored = Bit.from_binary(binary) + assert restored == bit + + def test_from_binary_error(self): + with pytest.raises(ValueError, match='expected bytes'): + Bit.from_binary('not bytes') + + def test_to_db(self): + bit = Bit([True, False, True]) + assert Bit._to_db(bit) == '101' + + def test_to_db_error(self): + with pytest.raises(ValueError, match='expected bit'): + Bit._to_db([True, False, True]) + + def test_to_db_binary(self): + bit = Bit([True, False, True]) + result = Bit._to_db_binary(bit) + assert isinstance(result, bytes) + + def test_to_db_binary_error(self): + with pytest.raises(ValueError, match='expected bit'): + Bit._to_db_binary([True, False, True]) + + def test_empty_bit(self): + bit = Bit([]) + assert bit.to_list() == [] + assert bit.to_text() == '' + + def test_single_bit(self): + bit = Bit([True]) + assert bit.to_list() == [True] + assert bit.to_text() == '1' + + def test_bytes_constructor(self): + bit = Bit(b'\x01') + assert len(bit.to_list()) == 8 + assert bit.to_text() == '00000001' + + def test_roundtrip_text(self): + original = Bit('10110011') + text = original.to_text() + restored = Bit.from_text(text) + assert restored == original + + def test_roundtrip_binary(self): + original = Bit([True, False, True, True, False, False, True, True]) + binary = original.to_binary() + restored = Bit.from_binary(binary) + assert restored == original diff --git a/tests/test_half_vector.py b/tests/test_half_vector.py index 78b4977..48c9695 100644 --- a/tests/test_half_vector.py +++ b/tests/test_half_vector.py @@ -57,3 +57,75 @@ def test_from_binary(self): assert vec.to_list() == [1.5, 2, 3] assert np.array_equal(vec.to_numpy(), [1.5, 2, 3]) assert vec.to_binary() == data + + def test_to_text(self): + vec = HalfVector([1, 2, 3]) + assert vec.to_text() == '[1.0,2.0,3.0]' + + def test_to_db_none(self): + assert HalfVector._to_db(None) is None + + def test_to_db_vector(self): + vec = HalfVector([1, 2, 3]) + assert HalfVector._to_db(vec) == '[1.0,2.0,3.0]' + + def test_to_db_list(self): + assert HalfVector._to_db([1, 2, 3]) == '[1.0,2.0,3.0]' + + def test_to_db_with_dim(self): + assert HalfVector._to_db([1, 2, 3], 3) == '[1.0,2.0,3.0]' + + def test_to_db_wrong_dim(self): + with pytest.raises(ValueError, match='expected 3 dimensions, not 2'): + HalfVector._to_db([1, 2], 3) + + def test_to_db_binary_none(self): + assert HalfVector._to_db_binary(None) is None + + def test_to_db_binary_vector(self): + vec = HalfVector([1, 2, 3]) + result = HalfVector._to_db_binary(vec) + assert result == pack('>HH3e', 3, 0, 1, 2, 3) + + def test_to_db_binary_list(self): + result = HalfVector._to_db_binary([1, 2, 3]) + assert result == pack('>HH3e', 3, 0, 1, 2, 3) + + def test_from_db_none(self): + assert HalfVector._from_db(None) is None + + def test_from_db_halfvector(self): + vec = HalfVector([1, 2, 3]) + assert HalfVector._from_db(vec) is vec + + def test_from_db_text(self): + result = HalfVector._from_db('[1.5,2,3]') + assert isinstance(result, HalfVector) + assert result.to_list() == [1.5, 2, 3] + + def test_from_db_binary_none(self): + assert HalfVector._from_db_binary(None) is None + + def test_from_db_binary_halfvector(self): + vec = HalfVector([1, 2, 3]) + assert HalfVector._from_db_binary(vec) is vec + + def test_from_db_binary_bytes(self): + data = pack('>HH3e', 3, 0, 1.5, 2, 3) + result = HalfVector._from_db_binary(data) + assert isinstance(result, HalfVector) + assert result.to_list() == [1.5, 2, 3] + + def test_empty_vector(self): + vec = HalfVector([]) + assert vec.dimensions() == 0 + assert vec.to_list() == [] + + def test_single_element(self): + vec = HalfVector([42]) + assert vec.dimensions() == 1 + assert vec.to_list() == [42] + + def test_negative_values(self): + vec = HalfVector([-1, -2, -3]) + assert vec.to_list() == [-1, -2, -3] diff --git a/tests/test_sparse_vector.py b/tests/test_sparse_vector.py index d580f32..0a769f9 100644 --- a/tests/test_sparse_vector.py +++ b/tests/test_sparse_vector.py @@ -110,3 +110,93 @@ def test_from_binary(self): assert vec.to_list() == [1.5, 0, 2, 0, 3, 0] assert np.array_equal(vec.to_numpy(), [1.5, 0, 2, 0, 3, 0]) assert vec.to_binary() == data + + def test_to_text(self): + vec = SparseVector([1, 0, 2, 0, 3, 0]) + assert vec.to_text() == '{1:1.0,3:2.0,5:3.0}/6' + + def test_to_db_none(self): + assert SparseVector._to_db(None) is None + + def test_to_db_vector(self): + vec = SparseVector([1, 0, 2, 0, 3, 0]) + assert SparseVector._to_db(vec) == '{1:1.0,3:2.0,5:3.0}/6' + + def test_to_db_list(self): + result = SparseVector._to_db([1, 0, 2, 0, 3, 0]) + assert result == '{1:1.0,3:2.0,5:3.0}/6' + + def test_to_db_with_dim(self): + result = SparseVector._to_db([1, 0, 2, 0, 3, 0], 6) + assert result == '{1:1.0,3:2.0,5:3.0}/6' + + def test_to_db_wrong_dim(self): + with pytest.raises(ValueError, match='expected 6 dimensions, not 5'): + SparseVector._to_db([1, 0, 2, 0, 3], 6) + + def test_to_db_binary_none(self): + assert SparseVector._to_db_binary(None) is None + + def test_to_db_binary_vector(self): + vec = SparseVector([1, 0, 2, 0, 3, 0]) + result = SparseVector._to_db_binary(vec) + assert isinstance(result, bytes) + + def test_to_db_binary_list(self): + result = SparseVector._to_db_binary([1, 0, 2, 0, 3, 0]) + assert isinstance(result, bytes) + + def test_from_db_none(self): + assert SparseVector._from_db(None) is None + + def test_from_db_sparsevector(self): + vec = SparseVector([1, 0, 2, 0, 3, 0]) + assert SparseVector._from_db(vec) is vec + + def test_from_db_text(self): + result = SparseVector._from_db('{1:1.5,3:2,5:3}/6') + assert isinstance(result, SparseVector) + assert result.to_list() == [1.5, 0, 2, 0, 3, 0] + + def test_from_db_binary_none(self): + assert SparseVector._from_db_binary(None) is None + + def test_from_db_binary_sparsevector(self): + vec = SparseVector([1, 0, 2, 0, 3, 0]) + assert SparseVector._from_db_binary(vec) is vec + + def test_from_db_binary_bytes(self): + data = pack('>iii3i3f', 6, 3, 0, 0, 2, 4, 1.5, 2, 3) + result = SparseVector._from_db_binary(data) + assert isinstance(result, SparseVector) + assert result.to_list() == [1.5, 0, 2, 0, 3, 0] + + def test_empty_sparse_vector(self): + vec = SparseVector({}, 5) + assert vec.dimensions() == 5 + assert vec.indices() == [] + assert vec.values() == [] + assert vec.to_list() == [0, 0, 0, 0, 0] + + def test_single_nonzero(self): + vec = SparseVector({3: 42}, 10) + assert vec.dimensions() == 10 + assert vec.indices() == [3] + assert vec.values() == [42] + + def test_negative_values_sparse(self): + vec = SparseVector([-1, 0, -2, 0, -3]) + assert vec.values() == [-1, -2, -3] + assert vec.to_list() == [-1, 0, -2, 0, -3] + + def test_roundtrip_text_sparse(self): + original = SparseVector([1.5, 0, 2.5, 0, 3.5, 0]) + text = original.to_text() + restored = SparseVector.from_text(text) + assert restored == original + + def test_roundtrip_binary_sparse(self): + original = SparseVector([1.5, 0, 2.5, 0, 3.5, 0]) + binary = original.to_binary() + restored = SparseVector.from_binary(binary) + assert restored == original diff --git a/tests/test_vector.py b/tests/test_vector.py index e5a16fe..ac8b625 100644 --- a/tests/test_vector.py +++ b/tests/test_vector.py @@ -57,3 +57,83 @@ def test_from_binary(self): assert vec.to_list() == [1.5, 2, 3] assert np.array_equal(vec.to_numpy(), [1.5, 2, 3]) assert vec.to_binary() == data + + def test_to_text(self): + vec = Vector([1, 2, 3]) + assert vec.to_text() == '[1.0,2.0,3.0]' + + def test_to_db_none(self): + assert Vector._to_db(None) is None + + def test_to_db_vector(self): + vec = Vector([1, 2, 3]) + assert Vector._to_db(vec) == '[1.0,2.0,3.0]' + + def test_to_db_list(self): + assert Vector._to_db([1, 2, 3]) == '[1.0,2.0,3.0]' + + def test_to_db_with_dim(self): + assert Vector._to_db([1, 2, 3], 3) == '[1.0,2.0,3.0]' + + def test_to_db_wrong_dim(self): + with pytest.raises(ValueError, match='expected 3 dimensions, not 2'): + Vector._to_db([1, 2], 3) + + def test_to_db_binary_none(self): + assert Vector._to_db_binary(None) is None + + def test_to_db_binary_vector(self): + vec = Vector([1, 2, 3]) + result = Vector._to_db_binary(vec) + assert result == pack('>HH3f', 3, 0, 1, 2, 3) + + def test_to_db_binary_list(self): + result = Vector._to_db_binary([1, 2, 3]) + assert result == pack('>HH3f', 3, 0, 1, 2, 3) + + def test_from_db_none(self): + assert Vector._from_db(None) is None + + def test_from_db_ndarray(self): + arr = np.array([1, 2, 3], dtype=np.float32) + assert Vector._from_db(arr) is arr + + def test_from_db_text(self): + result = Vector._from_db('[1.5,2,3]') + expected = np.array([1.5, 2, 3], dtype=np.float32) + assert np.array_equal(result, expected) + + def test_from_db_binary_none(self): + assert Vector._from_db_binary(None) is None + + def test_from_db_binary_ndarray(self): + arr = np.array([1, 2, 3], dtype=np.float32) + assert Vector._from_db_binary(arr) is arr + + def test_from_db_binary_bytes(self): + data = pack('>HH3f', 3, 0, 1.5, 2, 3) + result = Vector._from_db_binary(data) + expected = np.array([1.5, 2, 3], dtype=np.float32) + assert np.array_equal(result, expected) + + def test_empty_vector(self): + vec = Vector([]) + assert vec.dimensions() == 0 + assert vec.to_list() == [] + + def test_single_element(self): + vec = Vector([42]) + assert vec.dimensions() == 1 + assert vec.to_list() == [42] + + def test_negative_values(self): + vec = Vector([-1, -2, -3]) + assert vec.to_list() == [-1, -2, -3] + + def test_float_precision(self): + vec = Vector([1.123456789, 2.987654321]) + # Float32 precision test + result = vec.to_list() + assert len(result) == 2 + assert abs(result[0] - 1.123456789) < 1e-6 + assert abs(result[1] - 2.987654321) < 1e-6 From f779a1b067e107fbc788484bfeb48f8e55baaff7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:04:26 +0000 Subject: [PATCH 4/5] Add edge case tests for equality comparisons, achieve 100% coverage on Vector/HalfVector/Bit Co-authored-by: jackrua <155536850+jackrua@users.noreply.github.com> --- .coverage | Bin 53248 -> 53248 bytes tests/test_bit.py | 5 +++++ tests/test_half_vector.py | 5 +++++ tests/test_sparse_vector.py | 11 +++++++++++ tests/test_vector.py | 5 +++++ 5 files changed, 26 insertions(+) diff --git a/.coverage b/.coverage index 6f242357474e3bb3319ebf453038ae892842cafa..b26616ef7203d9eb8f34c4bd137800040cad2e0b 100644 GIT binary patch delta 82 zcmZozz}&EadBetj=jz+rs`Fp3z0NJg!otXD#xm{w)_1wL_vM#w4}V#^|Ni~kRjbpT_|J7_lTs diff --git a/tests/test_bit.py b/tests/test_bit.py index 076d233..bc8fdf1 100644 --- a/tests/test_bit.py +++ b/tests/test_bit.py @@ -62,6 +62,11 @@ def test_equality(self): assert Bit([True, False, True]) == Bit([True, False, True]) assert Bit([True, False, True]) != Bit([True, False, False]) + def test_equality_with_different_type(self): + assert Bit([True, False, True]) != [True, False, True] + assert Bit([True, False, True]) != "not a bit" + assert Bit([True, False, True]) != None + def test_length(self): assert len(Bit([True, False, True]).to_list()) == 3 assert len(Bit('10101010').to_list()) == 8 diff --git a/tests/test_half_vector.py b/tests/test_half_vector.py index 48c9695..d36774a 100644 --- a/tests/test_half_vector.py +++ b/tests/test_half_vector.py @@ -43,6 +43,11 @@ def test_equality(self): assert HalfVector([1, 2, 3]) == HalfVector([1, 2, 3]) assert HalfVector([1, 2, 3]) != HalfVector([1, 2, 4]) + def test_equality_with_different_type(self): + assert HalfVector([1, 2, 3]) != [1, 2, 3] + assert HalfVector([1, 2, 3]) != "not a vector" + assert HalfVector([1, 2, 3]) != None + def test_dimensions(self): assert HalfVector([1, 2, 3]).dimensions() == 3 diff --git a/tests/test_sparse_vector.py b/tests/test_sparse_vector.py index 0a769f9..70c2cdb 100644 --- a/tests/test_sparse_vector.py +++ b/tests/test_sparse_vector.py @@ -67,6 +67,12 @@ def test_csr_matrix(self): assert vec.to_list() == [1, 0, 2, 0, 3, 0] assert vec.indices() == [0, 2, 4] + def test_sparse_array_wrong_ndim(self): + # 2D array with wrong shape + arr = coo_array(np.array([[1, 0, 2], [0, 3, 0]])) + with pytest.raises(ValueError, match='expected ndim to be 1'): + SparseVector(arr) + def test_repr(self): assert repr(SparseVector([1, 0, 2, 0, 3, 0])) == 'SparseVector({0: 1.0, 2: 2.0, 4: 3.0}, 6)' assert str(SparseVector([1, 0, 2, 0, 3, 0])) == 'SparseVector({0: 1.0, 2: 2.0, 4: 3.0}, 6)' @@ -77,6 +83,11 @@ def test_equality(self): assert SparseVector([1, 0, 2, 0, 3, 0]) == SparseVector({2: 2, 4: 3, 0: 1, 3: 0}, 6) assert SparseVector({}, 1) != SparseVector({}, 2) + def test_equality_with_different_type(self): + assert SparseVector([1, 0, 2, 0, 3, 0]) != [1, 0, 2, 0, 3, 0] + assert SparseVector([1, 0, 2, 0, 3, 0]) != "not a sparse vector" + assert SparseVector([1, 0, 2, 0, 3, 0]) != None + def test_dimensions(self): assert SparseVector([1, 0, 2, 0, 3, 0]).dimensions() == 6 diff --git a/tests/test_vector.py b/tests/test_vector.py index ac8b625..74014c7 100644 --- a/tests/test_vector.py +++ b/tests/test_vector.py @@ -43,6 +43,11 @@ def test_equality(self): assert Vector([1, 2, 3]) == Vector([1, 2, 3]) assert Vector([1, 2, 3]) != Vector([1, 2, 4]) + def test_equality_with_different_type(self): + assert Vector([1, 2, 3]) != [1, 2, 3] + assert Vector([1, 2, 3]) != "not a vector" + assert Vector([1, 2, 3]) != None + def test_dimensions(self): assert Vector([1, 2, 3]).dimensions() == 3 From bd2a0b65c081a7fbcd8999eab0d58be3ddf9e288 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:08:15 +0000 Subject: [PATCH 5/5] Fix misleading comment in test as per code review feedback Co-authored-by: jackrua <155536850+jackrua@users.noreply.github.com> --- tests/test_sparse_vector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sparse_vector.py b/tests/test_sparse_vector.py index 70c2cdb..3e1a27a 100644 --- a/tests/test_sparse_vector.py +++ b/tests/test_sparse_vector.py @@ -68,7 +68,7 @@ def test_csr_matrix(self): assert vec.indices() == [0, 2, 4] def test_sparse_array_wrong_ndim(self): - # 2D array with wrong shape + # 2D array with wrong ndim (not 1D as required) arr = coo_array(np.array([[1, 0, 2], [0, 3, 0]])) with pytest.raises(ValueError, match='expected ndim to be 1'): SparseVector(arr)