@@ -78,17 +78,66 @@ void testPresenceCondition_WithNot() {
7878 @ Test
7979 void testUniqueValueCondition () {
8080 testExpressionTranslationWithContext (
81- "count(for $x in PathNode/TextField, $y in /*/PathNode/TextField[. = $x ] return $y ) = 1" ,
81+ "count(for $n in PathNode/TextField/normalize-space(text()) , $x in /*/PathNode/TextField/normalize-space(text()) [. = $n ] return $x ) = 1" ,
8282 "ND-Root" , "BT-00-Text is unique in /BT-00-Text" );
8383 }
8484
8585 @ Test
8686 void testUniqueValueCondition_WithNot () {
8787 testExpressionTranslationWithContext (
88- "not(count(for $x in PathNode/TextField, $y in /*/PathNode/TextField[. = $x ] return $y ) = 1)" ,
88+ "not(count(for $n in PathNode/TextField/normalize-space(text()) , $x in /*/PathNode/TextField/normalize-space(text()) [. = $n ] return $x ) = 1)" ,
8989 "ND-Root" , "BT-00-Text is not unique in /BT-00-Text" );
9090 }
9191
92+ @ Test
93+ void testStringUniqueValueCondition_WithLiteralSequence () {
94+ testExpressionTranslationWithContext (
95+ "count(for $n in 'b', $x in ('a','b','c','b')[. = $n] return $x) = 1" ,
96+ "BT-00-Text" , "'b' is unique in ('a', 'b', 'c', 'b')" );
97+ }
98+
99+ @ Test
100+ void testNumericUniqueValueCondition_WithLiteralSequence () {
101+ testExpressionTranslationWithContext (
102+ "count(for $n in 2, $x in (1,2,3,2)[. = $n] return $x) = 1" ,
103+ "BT-00-Number" , "2 is unique in (1, 2, 3, 2)" );
104+ }
105+
106+ @ Test
107+ void testStringUniqueValueCondition_WithRepeatableField () {
108+ testExpressionTranslationWithContext (
109+ "count(for $n in PathNode/TextField/normalize-space(text()), $x in /*/PathNode/RepeatableTextField/normalize-space(text())[. = $n] return $x) = 1" ,
110+ "ND-Root" , "BT-00-Text is unique in /BT-00-Repeatable-Text" );
111+ }
112+
113+ @ Test
114+ void testStringUniqueValueCondition_WithNot () {
115+ testExpressionTranslationWithContext (
116+ "not(count(for $n in 'x', $x in ('a','b','c')[. = $n] return $x) = 1)" ,
117+ "BT-00-Text" , "'x' is not unique in ('a', 'b', 'c')" );
118+ }
119+
120+ @ Test
121+ void testStringUniqueValueCondition_WithRelativeFieldReference () {
122+ testExpressionTranslationWithContext (
123+ "count(for $n in PathNode/TextField/normalize-space(text()), $x in PathNode/RepeatableTextField/normalize-space(text())[. = $n] return $x) = 1" ,
124+ "ND-Root" , "BT-00-Text is unique in BT-00-Repeatable-Text" );
125+ }
126+
127+ @ Test
128+ void testStringUniqueValueCondition_WithFieldReferencePredicate () {
129+ testExpressionTranslationWithContext (
130+ "count(for $n in PathNode/TextField/normalize-space(text()), $x in /*/PathNode/RepeatableTextField[./normalize-space(text()) != '']/normalize-space(text())[. = $n] return $x) = 1" ,
131+ "ND-Root" , "BT-00-Text is unique in /BT-00-Repeatable-Text[BT-00-Repeatable-Text != '']" );
132+ }
133+
134+ @ Test
135+ void testStringUniqueValueCondition_WithFieldInRepeatableNodePredicate () {
136+ testExpressionTranslationWithContext (
137+ "count(for $n in PathNode/TextField/normalize-space(text()), $x in /*/RepeatableNode/TextField[./normalize-space(text()) != '']/normalize-space(text())[. = $n] return $x) = 1" ,
138+ "ND-Root" , "BT-00-Text is unique in /BT-00-Text-In-Repeatable-Node[BT-00-Text-In-Repeatable-Node != '']" );
139+ }
140+
92141
93142 @ Test
94143 void testLikePatternCondition () {
@@ -1791,15 +1840,15 @@ void testScalarFromRepeatableField_ThrowsError() {
17911840 // A repeatable field used as scalar should throw TypeMismatchException.fieldMayRepeat()
17921841 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
17931842 () -> translateExpressionWithContext ("ND-Root" , "BT-00-Repeatable-Text == 'test'" ));
1794- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
1843+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
17951844 }
17961845
17971846 @ Test
17981847 void testScalarFromFieldInRepeatableNode_ThrowsErrorFromRootContext () {
17991848 // Field in ND-RepeatableNode (repeatable) used as scalar from ND-Root should throw
18001849 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
18011850 () -> translateExpressionWithContext ("ND-Root" , "BT-00-Text-In-Repeatable-Node == 'test'" ));
1802- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
1851+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
18031852 }
18041853
18051854 @ Test
@@ -1814,15 +1863,15 @@ void testScalarFromFieldInNestedRepeatableNode_ThrowsErrorFromRootContext() {
18141863 // Field in ND-RepeatableSubSubNode (inside ND-NonRepeatableSubNode inside ND-RepeatableNode) used from root should throw
18151864 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
18161865 () -> translateExpressionWithContext ("ND-Root" , "BT-00-Text-In-RepeatableSubSubNode == 'test'" ));
1817- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
1866+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
18181867 }
18191868
18201869 @ Test
18211870 void testScalarFromFieldInNestedRepeatableNode_ThrowsErrorFromRepeatableNodeContext () {
18221871 // Field in ND-RepeatableSubSubNode used from ND-RepeatableNode should still throw (ND-RepeatableSubSubNode is also repeatable)
18231872 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
18241873 () -> translateExpressionWithContext ("ND-RepeatableNode" , "BT-00-Text-In-RepeatableSubSubNode == 'test'" ));
1825- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
1874+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
18261875 }
18271876
18281877 @ Test
@@ -1837,7 +1886,7 @@ void testScalarFromFieldInNonRepeatableNestedInRepeatable_ThrowsErrorFromRootCon
18371886 // Field in ND-NonRepeatableSubNode (non-repeatable) inside ND-RepeatableNode (repeatable) used from root should throw
18381887 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
18391888 () -> translateExpressionWithContext ("ND-Root" , "BT-00-Text-In-NonRepeatableSubNode == 'test'" ));
1840- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
1889+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
18411890 }
18421891
18431892 @ Test
@@ -1847,6 +1896,14 @@ void testScalarFromFieldInNonRepeatableNestedInRepeatable_OkFromRepeatableNodeCo
18471896 "ND-RepeatableNode" , "BT-00-Text-In-NonRepeatableSubNode == 'test'" );
18481897 }
18491898
1899+ @ Test
1900+ void testRepeatableFieldInUniqueCondition_ThrowsError () {
1901+ // A repeatable field used as needle (left side) in uniqueness condition should throw
1902+ TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
1903+ () -> translateExpressionWithContext ("ND-Root" , "BT-00-Repeatable-Text is unique in /BT-00-Text" ));
1904+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
1905+ }
1906+
18501907 // #endregion: Scalar/Sequence Validation
18511908
18521909 // #region: InvalidIdentifierException Tests --------------------------------
@@ -1906,7 +1963,7 @@ void testScalarFromFieldContextVariable_Repeatable_ThrowsFieldMayRepeat() {
19061963 // A repeatable field context variable used as scalar should throw
19071964 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
19081965 () -> translateExpressionWithContext ("ND-Root" , "for context:$f in BT-00-Repeatable-Text return $f == 'test'" ));
1909- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
1966+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
19101967 }
19111968
19121969 // #endregion: TypeMismatchException - fieldMayRepeat (Context Variables)
@@ -1963,7 +2020,7 @@ void testPredicateComparison_RepeatableFieldAsScalar_ThrowsError() {
19632020 // Pattern: FIELD[REPEATABLE_FIELD == $var] - the repeatable field is used as scalar
19642021 TypeMismatchException ex = assertThrows (TypeMismatchException .class ,
19652022 () -> translateExpressionWithContext ("ND-Root" , "BT-00-Text[BT-00-Repeatable-Text == 'test']" ));
1966- assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SEQUENCE , ex .getErrorCode ());
2023+ assertEquals (TypeMismatchException .ErrorCode .EXPECTED_SCALAR , ex .getErrorCode ());
19672024 }
19682025
19692026 @ Test
0 commit comments