From 4b7cb28786ea96ba9c1b788613965adcbd3e7baf Mon Sep 17 00:00:00 2001 From: padam-prakash Date: Sun, 12 Apr 2026 20:49:32 +0530 Subject: [PATCH 1/3] Add similarity test helper and refactor tests Introduce SimilarityFunctionTestHelper to centralize common null/empty and exact-match checks for similarity functions. Refactor TestEmailMatchTypeFunction and TestOnlyAlphabetsAffineGapSimilarity to use the helper, reorganize and add test cases. --- .../core/executor/TrainingDataFinder.java | 2 +- .../SimilarityFunctionTestHelper.java | 35 ++++ .../function/TestEmailMatchTypeFunction.java | 149 +++++++++++------- .../TestOnlyAlphabetsAffineGapSimilarity.java | 82 ++++++++-- 4 files changed, 195 insertions(+), 73 deletions(-) create mode 100644 common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java diff --git a/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java b/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java index 86e96d54f..8a4708741 100644 --- a/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java +++ b/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java @@ -137,7 +137,7 @@ public void execute() throws ZinggClientException { } } catch (Exception e) { - throw new ZinggClientException("Error while finding tra: ", e); + throw new ZinggClientException("Error while finding trainingData: "+ e); } } diff --git a/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java b/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java new file mode 100644 index 000000000..15d4409bf --- /dev/null +++ b/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java @@ -0,0 +1,35 @@ +package zingg.common.core.similarity.function; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SimilarityFunctionTestHelper { + + /** + * Functional interface for calling similarity functions. + */ + @FunctionalInterface + public interface SimilarityFunction { + Double call(String first, String second); + } + + /** + * Test null and empty handling - used by ALL similarity functions. + */ + public static void testNullAndEmptyHandling(SimilarityFunction function) { + assertEquals(1d, function.call(null, null), "Both null should return 1.0"); + assertEquals(1d, function.call(null, "test"), "First null should return 1.0"); + assertEquals(1d, function.call("test", null), "Second null should return 1.0"); + assertEquals(1d, function.call("", ""), "Both empty should return 1.0"); + assertEquals(1d, function.call("", "test"), "First empty should return 1.0"); + assertEquals(1d, function.call("test", ""), "Second empty should return 1.0"); + } + + /** + * Test exact matches - used by ALL similarity functions. + */ + public static void testExactMatches(SimilarityFunction function) { + assertEquals(1d, function.call("test", "test"), "Exact match should return 1.0"); + assertEquals(1d, function.call("testing similarity", "testing similarity"), + "Exact match of longer string should return 1.0"); + } +} diff --git a/common/core/src/test/java/zingg/common/core/similarity/function/TestEmailMatchTypeFunction.java b/common/core/src/test/java/zingg/common/core/similarity/function/TestEmailMatchTypeFunction.java index 00d6ae121..6571f1a68 100644 --- a/common/core/src/test/java/zingg/common/core/similarity/function/TestEmailMatchTypeFunction.java +++ b/common/core/src/test/java/zingg/common/core/similarity/function/TestEmailMatchTypeFunction.java @@ -1,100 +1,135 @@ package zingg.common.core.similarity.function; - import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; +import static zingg.common.core.similarity.function.SimilarityFunctionTestHelper.*; +/** + * Test class for EmailMatchTypeFunction. + */ public class TestEmailMatchTypeFunction { - - - @Test - public void testFirstEntryNull() { - EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = null; - String second = "xyz321@pqr.co"; - assertEquals(expected.call(first,second.split("@",0)[0]), emailMatchFn.call(first, second)); + + /** + * Test null and empty handling. + */ + public void testNullAndEmptyHandling(SimilarityFunction function) { + SimilarityFunctionTestHelper.testNullAndEmptyHandling(function); } - @Test - public void testFirstEntryEmpty() { - EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = ""; + /** + * Test exact matches. + */ + public void testExactMatches(SimilarityFunction function) { + SimilarityFunctionTestHelper.testExactMatches(function); + } + + /** + * Test exact email match. + */ + public void testBothExact(SimilarityFunction function) { + String first = "xyz321@pqr.co"; String second = "xyz321@pqr.co"; - assertEquals(expected.call(first.split("@",0)[0],second.split("@",0)[0]), emailMatchFn.call(first, second)); + assertEquals(1.0, function.call(first, second), + "Exact email match should return 1.0"); } - @Test - public void testSecondEntryNull() { - EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); + /** + * Test same username with different domain. + */ + public void testFirstPartMatch(SimilarityFunction function) { + String first = "pqr981@abc.in"; + String second = "pqr981@xyz.com"; + assertEquals(1.0, function.call(first, second), + "Same username with different domain should return 1.0"); + } + + /** + * Test different usernames - should delegate to AffineGap. + */ + public void testbothDifferent(SimilarityFunction emailFunc, SimilarityFunction affineGapFunc) { String first = "xyz321@pqr.co"; - String second = null; - assertEquals(expected.call(first.split("@",0)[0],second), emailMatchFn.call(first,second)); + String second = "pqr981@abc.in"; + assertEquals(affineGapFunc.call(first.split("@", 0)[0], second.split("@", 0)[0]), + emailFunc.call(first, second), + "Different usernames should use AffineGap comparison"); } - @Test - public void testSecondEntryEmpty() { - EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); + /** + * Test different usernames with same domain - should delegate to AffineGap. + */ + public void testFirstPartDifferentSecondPartMatch(SimilarityFunction emailFunc, SimilarityFunction affineGapFunc) { + String first = "pqr981@xyz.com"; + String second = "aqr981@xyz.com"; + assertEquals(affineGapFunc.call(first.split("@", 0)[0], second.split("@", 0)[0]), + emailFunc.call(first, second), + "Different usernames should use AffineGap comparison even with same domain"); + } + + /** + * Test first entry empty. + */ + public void testFirstEntryEmpty(SimilarityFunction emailFunc, SimilarityFunction affineGapFunc) { + String first = ""; + String second = "xyz321@pqr.co"; + assertEquals(affineGapFunc.call(first.split("@", 0)[0], second.split("@", 0)[0]), + emailFunc.call(first, second)); + } + + /** + * Test second entry empty. + */ + public void testSecondEntryEmpty(SimilarityFunction emailFunc, SimilarityFunction affineGapFunc) { String first = "xyz321@pqr.co"; String second = ""; - assertEquals(expected.call(first.split("@",0)[0],second.split("@",0)[0]), emailMatchFn.call(first,second)); + assertEquals(affineGapFunc.call(first.split("@", 0)[0], second.split("@", 0)[0]), + emailFunc.call(first, second)); } + @Test - public void testBothEmpty() { + public void testCommonBehavior() { EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = ""; - String second = ""; - assertEquals(expected.call(first.split("@",0)[0],second.split("@",0)[0]), emailMatchFn.call(first,second)); + testNullAndEmptyHandling((a, b) -> emailMatchFn.call(a, b)); + testExactMatches((a, b) -> emailMatchFn.call(a, b)); } @Test - public void testBothNull() { + public void testBothExact() { EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - //AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = null; - String second = null; - assertEquals(1d, emailMatchFn.call(first,second)); + testBothExact((a, b) -> emailMatchFn.call(a, b)); } @Test - public void testBothExact() { + public void testFirstPartMatch() { EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - //AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = "xyz321@pqr.co"; - String second = "xyz321@pqr.co"; - assertEquals(1d, emailMatchFn.call(first,second)); + testFirstPartMatch((a, b) -> emailMatchFn.call(a, b)); } @Test public void testbothDifferent() { EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = "xyz321@pqr.co"; - String second = "pqr981@abc.in"; - assertEquals(expected.call(first.split("@",0)[0],second.split("@",0)[0]), emailMatchFn.call(first,second)); + AffineGapSimilarityFunction affineGap = new AffineGapSimilarityFunction(); + testbothDifferent((a, b) -> emailMatchFn.call(a, b), (a, b) -> affineGap.call(a, b)); } @Test - public void testFirstPartMatch() { + public void testFirstPartDifferentSecondPartMatch() { EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - //AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = "pqr981@abc.in"; - String second = "pqr981@xyz.com"; - assertEquals(1d, emailMatchFn.call(first,second)); + AffineGapSimilarityFunction affineGap = new AffineGapSimilarityFunction(); + testFirstPartDifferentSecondPartMatch((a, b) -> emailMatchFn.call(a, b), (a, b) -> affineGap.call(a, b)); } @Test - public void testFirstPartDifferentSecondPartMatch() { + public void testFirstEntryEmpty() { EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); - AffineGapSimilarityFunction expected = new AffineGapSimilarityFunction(); - String first = "pqr981@xyz.com"; - String second = "aqr981@xyz.com"; - assertEquals(expected.call(first.split("@",0)[0],second.split("@",0)[0]), emailMatchFn.call(first,second)); + AffineGapSimilarityFunction affineGap = new AffineGapSimilarityFunction(); + testFirstEntryEmpty((a, b) -> emailMatchFn.call(a, b), (a, b) -> affineGap.call(a, b)); } + @Test + public void testSecondEntryEmpty() { + EmailMatchTypeFunction emailMatchFn = new EmailMatchTypeFunction(); + AffineGapSimilarityFunction affineGap = new AffineGapSimilarityFunction(); + testSecondEntryEmpty((a, b) -> emailMatchFn.call(a, b), (a, b) -> affineGap.call(a, b)); + + } } diff --git a/common/core/src/test/java/zingg/common/core/similarity/function/TestOnlyAlphabetsAffineGapSimilarity.java b/common/core/src/test/java/zingg/common/core/similarity/function/TestOnlyAlphabetsAffineGapSimilarity.java index 833227e4f..2d763f0c4 100644 --- a/common/core/src/test/java/zingg/common/core/similarity/function/TestOnlyAlphabetsAffineGapSimilarity.java +++ b/common/core/src/test/java/zingg/common/core/similarity/function/TestOnlyAlphabetsAffineGapSimilarity.java @@ -1,38 +1,90 @@ package zingg.common.core.similarity.function; import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static zingg.common.core.similarity.function.SimilarityFunctionTestHelper.*; +/** + * Test class for OnlyAlphabetsAffineGapSimilarity. + */ public class TestOnlyAlphabetsAffineGapSimilarity { - - + + /** + * Test null and empty handling. + */ + public void testNullAndEmptyHandling(SimilarityFunction function) { + SimilarityFunctionTestHelper.testNullAndEmptyHandling(function); + } + + /** + * Test exact matches. + */ + public void testExactMatches(SimilarityFunction function) { + SimilarityFunctionTestHelper.testExactMatches(function); + } + + /** + * Test that strings with same alphabets but different numbers match perfectly. + */ + public void testSameAlphabetsDiffNumbers(SimilarityFunction function) { + double score = function.call("I have 1 number", "I have 3 number"); + assertEquals(1.0, score, "Same alphabets with different numbers should match"); + } + + /** + * Test that strings with different alphabets don't match perfectly. + */ + public void testNotSameAlphabets(SimilarityFunction function) { + double score = function.call("I have 1 number", "I have no number"); + assertTrue(score < 1.0, "Different alphabets should have score < 1.0"); + assertTrue(score > 0.0, "Different alphabets should have score > 0.0"); + } + + /** + * Test same strings without numbers. + */ + public void testSameNoNum(SimilarityFunction function) { + assertEquals(1.0, function.call("I have no number", "I have no number"), + "Same strings without numbers should match"); + } + + /** + * Test different strings without numbers. + */ + public void testDiffNoNumber(SimilarityFunction function) { + assertTrue(function.call("I have a no number", "I have r number") < 1.0, + "Different alphabets should have score < 1.0"); + } + @Test - public void testNotSameAlphabets() { + public void testCommonBehavior() { OnlyAlphabetsAffineGapSimilarity sim = new OnlyAlphabetsAffineGapSimilarity(); - double score = sim.call("I have 1 number", "I have no number"); - assertTrue(1 > score); - assertTrue(0 < score); + testNullAndEmptyHandling((s1, s2) -> sim.call(s1, s2)); + testExactMatches((s1, s2) -> sim.call(s1, s2)); } @Test public void testSameAlphabetsDiffNumbers() { OnlyAlphabetsAffineGapSimilarity sim = new OnlyAlphabetsAffineGapSimilarity(); - double score = sim.call("I have 1 number", "I have 3 number"); - assertEquals(1d, score); + testSameAlphabetsDiffNumbers((s1, s2) -> sim.call(s1, s2)); } - + + @Test + public void testNotSameAlphabets() { + OnlyAlphabetsAffineGapSimilarity sim = new OnlyAlphabetsAffineGapSimilarity(); + testNotSameAlphabets((s1, s2) -> sim.call(s1, s2)); + } + @Test public void testSameNoNum() { OnlyAlphabetsAffineGapSimilarity sim = new OnlyAlphabetsAffineGapSimilarity(); - assertEquals(1d, sim.call("I have no number", "I have no number")); + testSameNoNum((s1, s2) -> sim.call(s1, s2)); } @Test public void testDiffNoNumber() { OnlyAlphabetsAffineGapSimilarity sim = new OnlyAlphabetsAffineGapSimilarity(); - System.out.println(" the sim i s" + sim.call("I have a no number", "I have r number")); - assertTrue(1d > sim.call("I have a no number", "I have r number")); - } -} + testDiffNoNumber((s1, s2) -> sim.call(s1, s2)); + } +} \ No newline at end of file From 3ac0590e0f4e2defb5768c02f10e457707343de7 Mon Sep 17 00:00:00 2001 From: padam-prakash Date: Mon, 13 Apr 2026 11:18:46 +0530 Subject: [PATCH 2/3] Include cause when throwing ZinggClientException Replace string concatenation of the caught exception with passing it as the cause to the ZinggClientException constructor. This preserves the original exception and its stack trace (change in TrainingDataFinder.java catch block). --- .../java/zingg/common/core/executor/TrainingDataFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java b/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java index 8a4708741..35eba99d2 100644 --- a/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java +++ b/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java @@ -137,7 +137,7 @@ public void execute() throws ZinggClientException { } } catch (Exception e) { - throw new ZinggClientException("Error while finding trainingData: "+ e); + throw new ZinggClientException("Error while finding trainingData: ", e); } } From 0f1e9493403f9c925cf0dfd4fd1062aa6db54b96 Mon Sep 17 00:00:00 2001 From: padam-prakash Date: Mon, 13 Apr 2026 12:30:21 +0530 Subject: [PATCH 3/3] Fix wording in exception and test comments Update wording for clarity: change exception message in TrainingDataFinder to "Error while finding training data" and simplify Javadoc comments in SimilarityFunctionTestHelper by removing redundant phrase about usage --- .../java/zingg/common/core/executor/TrainingDataFinder.java | 2 +- .../similarity/function/SimilarityFunctionTestHelper.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java b/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java index 35eba99d2..3dd6e557b 100644 --- a/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java +++ b/common/core/src/main/java/zingg/common/core/executor/TrainingDataFinder.java @@ -137,7 +137,7 @@ public void execute() throws ZinggClientException { } } catch (Exception e) { - throw new ZinggClientException("Error while finding trainingData: ", e); + throw new ZinggClientException("Error while finding training data: ", e); } } diff --git a/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java b/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java index 15d4409bf..e1355aede 100644 --- a/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java +++ b/common/core/src/test/java/zingg/common/core/similarity/function/SimilarityFunctionTestHelper.java @@ -13,7 +13,7 @@ public interface SimilarityFunction { } /** - * Test null and empty handling - used by ALL similarity functions. + * Test null and empty handling. */ public static void testNullAndEmptyHandling(SimilarityFunction function) { assertEquals(1d, function.call(null, null), "Both null should return 1.0"); @@ -25,7 +25,7 @@ public static void testNullAndEmptyHandling(SimilarityFunction function) { } /** - * Test exact matches - used by ALL similarity functions. + * Test exact matches. */ public static void testExactMatches(SimilarityFunction function) { assertEquals(1d, function.call("test", "test"), "Exact match should return 1.0");