From a339909ed51043b83cafbd42238bd98b31c9d705 Mon Sep 17 00:00:00 2001 From: "linear-code[bot]" <222613912+linear-code[bot]@users.noreply.github.com> Date: Tue, 3 Nov 2026 15:46:04 +0000 Subject: [PATCH] fix(Segments): Standardise regex matching in the Java server-side SDK Match regex segment conditions from the start of the trait value without requiring a full-string match, per the Flagsmith documentation. Generated with [Linear](https://linear.app/flagsmith/agent-session/558e4f47-74c1-4a67-950a-c3bb7765c695) Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com> --- .../flagengine/segments/SegmentEvaluator.java | 2 +- .../flagengine/unit/segments/SegmentModelTest.java | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/flagsmith/flagengine/segments/SegmentEvaluator.java b/src/main/java/com/flagsmith/flagengine/segments/SegmentEvaluator.java index d6722059..2c81af91 100644 --- a/src/main/java/com/flagsmith/flagengine/segments/SegmentEvaluator.java +++ b/src/main/java/com/flagsmith/flagengine/segments/SegmentEvaluator.java @@ -197,7 +197,7 @@ private static Boolean contextMatchesCondition( if (contextValue != null) { try { Pattern pattern = Pattern.compile(conditionValue.toString()); - return pattern.matcher(contextValue.toString()).find(); + return pattern.matcher(contextValue.toString()).lookingAt(); } catch (PatternSyntaxException pse) { return false; } diff --git a/src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java b/src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java index ce0da7c6..ec6cdfe7 100644 --- a/src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java +++ b/src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java @@ -81,6 +81,16 @@ private static Stream conditionTestData() { Arguments.of(SegmentConditions.REGEX, "FOO", "[a-z]+", false), Arguments.of(SegmentConditions.REGEX, 42, "[a-z]+", false), Arguments.of(SegmentConditions.REGEX, 42, "\\d+", true), + Arguments.of(SegmentConditions.REGEX, "production", "prod", true), + Arguments.of(SegmentConditions.REGEX, "nonproduction", "prod", false), + Arguments.of(SegmentConditions.REGEX, "development", "prod|dev", true), + Arguments.of(SegmentConditions.REGEX, "nondev", "prod|dev", false), + Arguments.of(SegmentConditions.REGEX, "jane@example.com", "@example\\.com$", false), + Arguments.of(SegmentConditions.REGEX, "jane@example.com", "^[^@]+@example\\.com$", true), + Arguments.of(SegmentConditions.REGEX, "jane@example.com.br", "^[^@]+@example\\.com$", false), + Arguments.of(SegmentConditions.REGEX, "Production", "prod", false), + Arguments.of(SegmentConditions.REGEX, "Production", "[Pp]rod", true), + Arguments.of(SegmentConditions.REGEX, "a)(b", "a)(b", false), Arguments.of(SegmentConditions.MODULO, 2, "2|0", true), Arguments.of(SegmentConditions.MODULO, 3, "2|0", false), Arguments.of(SegmentConditions.MODULO, 2.0, "2|0", true), @@ -113,7 +123,7 @@ public void testSegmentConditionMatchesTraitValue( Object traitValue, Object conditionValue, Boolean expectedResponse) { - + // Given final EvaluationContext context = EngineMappers.mapContextAndIdentityDataToContext( FlagsmithTestHelper.evaluationContext(), "foo", Collections.singletonMap("foo", traitValue)); @@ -125,8 +135,10 @@ public void testSegmentConditionMatchesTraitValue( .withOperator(condition).withProperty("foo") .withValue(conditionValue))))); + // When Boolean actualResult = SegmentEvaluator.isContextInSegment(context, segmentContext); + // Then assertEquals(expectedResponse, actualResult); }