Skip to content

Commit aef1eed

Browse files
authored
[Java] Handle nullValue when validating value range for EnumType. (#817)
* [Java] Validate EnumType value is in the valid range, including custom ranges and nullValue handling. * [Java] Allow value out of range if it is the nullValue. * [Java] Do not allow nullValue in as an enum constant.
1 parent d792092 commit aef1eed

File tree

3 files changed

+100
-8
lines changed

3 files changed

+100
-8
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@
2929
import java.util.Map;
3030

3131
import static uk.co.real_logic.sbe.xml.Presence.OPTIONAL;
32-
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.handleError;
33-
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.handleWarning;
34-
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.checkForValidName;
35-
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getAttributeValue;
36-
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getAttributeValueOrNull;
32+
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.*;
3733

3834
/**
3935
* SBE enum type for representing an enumeration of values.
@@ -156,8 +152,17 @@ else if (presence() == OPTIONAL)
156152
encodedDataType.minValue().longValue() : encodingType.minValue().longValue();
157153
final long maxValue = null != encodedDataType && null != encodedDataType.maxValue() ?
158154
encodedDataType.maxValue().longValue() : encodingType.maxValue().longValue();
155+
final long nullLongValue = null != nullValue ? nullValue.longValue() :
156+
encodingType.nullValue().longValue();
159157

160-
if (value < minValue || value > maxValue)
158+
if (nullLongValue == value)
159+
{
160+
handleError(
161+
node,
162+
"validValue " + v.name() + " uses nullValue: " +
163+
(null != nullValue ? nullValue : encodingType.nullValue()));
164+
}
165+
else if (value < minValue || value > maxValue)
161166
{
162167
handleError(
163168
node,

sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package uk.co.real_logic.sbe.xml;
1717

1818
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.params.ParameterizedTest;
20+
import org.junit.jupiter.params.provider.ValueSource;
1921
import org.w3c.dom.Document;
2022
import org.w3c.dom.NodeList;
2123
import org.xml.sax.SAXException;
@@ -31,14 +33,14 @@
3133
import javax.xml.xpath.XPathFactory;
3234
import java.io.ByteArrayInputStream;
3335
import java.io.IOException;
36+
import java.io.InputStream;
3437
import java.util.HashMap;
3538
import java.util.List;
3639
import java.util.Map;
3740

3841
import static org.hamcrest.MatcherAssert.assertThat;
3942
import static org.hamcrest.core.Is.is;
40-
import static org.junit.jupiter.api.Assertions.assertNotNull;
41-
import static org.junit.jupiter.api.Assertions.assertThrows;
43+
import static org.junit.jupiter.api.Assertions.*;
4244
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse;
4345

4446
public class EnumTypeTest
@@ -223,6 +225,61 @@ public void shouldThrowExceptionWhenDuplicateNameSpecified()
223225
parseTestXmlWithMap("/types/enum", testXmlString));
224226
}
225227

228+
@Test
229+
public void shouldThrowExceptionWhenImplicitNullValueIsUsed()
230+
{
231+
final String testXmlString =
232+
"<types>" +
233+
"<enum name=\"test\" encodingType=\"uint8\">" +
234+
" <validValue name=\"one\">1</validValue>" +
235+
" <validValue name=\"invalidNullValue\">255</validValue>" +
236+
"</enum>" +
237+
"</types>";
238+
239+
assertThrows(IllegalArgumentException.class, () ->
240+
parseTestXmlWithMap("/types/enum", testXmlString));
241+
}
242+
243+
@Test
244+
public void shouldThrowExceptionWhenExplicitNullValueIsUsed()
245+
{
246+
final String testXmlString =
247+
"<types>" +
248+
"<enum name=\"test\" encodingType=\"uint8\" presence=\"optional\" nullValue=\"5\">" +
249+
" <validValue name=\"one\">1</validValue>" +
250+
" <validValue name=\"invalidNullValue\">5</validValue>" +
251+
"</enum>" +
252+
"</types>";
253+
254+
assertThrows(IllegalArgumentException.class, () ->
255+
parseTestXmlWithMap("/types/enum", testXmlString));
256+
}
257+
258+
@ParameterizedTest
259+
@ValueSource(longs = { (long)Integer.MIN_VALUE - 1, (long)Integer.MAX_VALUE + 1 })
260+
public void shouldThrowExceptionWhenIntValueIsOutOfRange(final long value)
261+
{
262+
final String testXmlString =
263+
"<types>" +
264+
"<enum name=\"test\" encodingType=\"int32\">" +
265+
" <validValue name=\"X\">" + value + "</validValue>" +
266+
"</enum>" +
267+
"</types>";
268+
269+
final NumberFormatException exception = assertThrows(NumberFormatException.class, () ->
270+
parseTestXmlWithMap("/types/enum", testXmlString));
271+
assertEquals("For input string: \"" + value + "\"", exception.getMessage());
272+
}
273+
274+
@Test
275+
public void shouldThrowExceptionIfEnumValueIsOutOfCustomValueRange() throws IOException
276+
{
277+
final InputStream file = Tests.getLocalResource("error-handler-enum-violates-min-max-value-range.xml");
278+
final IllegalStateException exception = assertThrows(IllegalStateException.class,
279+
() -> parse(file, ParserOptions.builder().suppressOutput(true).build()));
280+
assertEquals("had 4 errors", exception.getMessage());
281+
}
282+
226283
@Test
227284
public void shouldHandleEncodingTypesWithNamedTypes() throws Exception
228285
{
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<messageSchema package="SBE tests"
3+
id="13"
4+
semanticVersion="5.2"
5+
description="Unit Test"
6+
byteOrder="littleEndian">
7+
<types>
8+
<composite name="messageHeader" description="Message identifiers and length of message root">
9+
<type name="blockLength" primitiveType="uint16"/>
10+
<type name="templateId" primitiveType="uint16"/>
11+
<type name="schemaId" primitiveType="uint16"/>
12+
<type name="version" primitiveType="uint16"/>
13+
</composite>
14+
<type name="EnumValueRange" primitiveType="int32" minValue="1" maxValue="5"/>
15+
<enum name="EnumWithCustomEncodingType" encodingType="EnumValueRange">
16+
<validValue name="INVALID_ZERO">0</validValue>
17+
<validValue name="ONE">1</validValue>
18+
<validValue name="FIVE">5</validValue>
19+
<validValue name="INVALID_SIX">6</validValue>
20+
<validValue name="INVALID_NULL_VALUE">-2147483648</validValue>
21+
</enum>
22+
<enum name="EnumWithCustomEncodingTypeOptional" encodingType="EnumValueRange" presence="optional" nullValue="3">
23+
<validValue name="INVALID_THREE">3</validValue>
24+
<validValue name="FOUR">4</validValue>
25+
</enum>
26+
</types>
27+
<message name="Message" id="1">
28+
<field name="ref1" id="1" type="EnumWithCustomEncodingType"/>
29+
</message>
30+
</messageSchema>

0 commit comments

Comments
 (0)