@@ -216,6 +216,57 @@ void expectedTokenLengthWithConfigurations()
216216 }
217217 }
218218
219+ // [core#1698]: every parser backend must honor `maxErrorTokenLength`;
220+ // `UTF8DataInputJsonParser` used to accumulate the whole token instead
221+ @ Test
222+ void errorTokenLengthBoundedInAllModes ()
223+ throws Exception
224+ {
225+ final int maxLen = 256 ;
226+ final JsonFactory f = streamFactoryBuilder ()
227+ .errorReportConfiguration (ErrorReportConfiguration .builder ()
228+ .maxErrorTokenLength (maxLen ).build ())
229+ .build ();
230+ // Broken token far longer than the limit: must be truncated, not accumulated in full
231+ final String doc = _buildBrokenJsonOfLength (50 * maxLen );
232+ // limit, plus appended "..."
233+ final String expToken = _brokenToken (maxLen ) + "..." ;
234+
235+ for (int mode : ALL_MODES ) {
236+ try (JsonParser p = createParser (f , mode , doc )) {
237+ p .nextToken ();
238+ p .nextToken ();
239+ fail ("Should not pass, mode: " +mode );
240+ } catch (JsonProcessingException e ) {
241+ assertThat (_unrecognizedToken (e .getMessage ()))
242+ .as ("mode: %d" , mode )
243+ .isEqualTo (expToken );
244+ }
245+ }
246+ }
247+
248+ // Short broken token (below limit) must be reported verbatim, without
249+ // duplicated leading char, in all modes
250+ @ Test
251+ void shortErrorTokenReportedExactlyInAllModes ()
252+ throws Exception
253+ {
254+ final JsonFactory f = newStreamFactory ();
255+ final String doc = "{\" key\" :abc!}" ;
256+
257+ for (int mode : ALL_MODES ) {
258+ try (JsonParser p = createParser (f , mode , doc )) {
259+ p .nextToken ();
260+ p .nextToken ();
261+ fail ("Should not pass, mode: " +mode );
262+ } catch (JsonProcessingException e ) {
263+ assertThat (_unrecognizedToken (e .getMessage ()))
264+ .as ("mode: %d" , mode )
265+ .isEqualTo ("abc" );
266+ }
267+ }
268+ }
269+
219270 @ Test
220271 void nonPositiveErrorTokenConfig ()
221272 {
@@ -318,13 +369,29 @@ private void _testWithMaxErrorTokenLength(int expectedSize, int tokenLen, JsonFa
318369 }
319370 }
320371
372+ // Extracts X from "Unrecognized token 'X': was expecting ..."
373+ private String _unrecognizedToken (String msg )
374+ {
375+ final String prefix = "Unrecognized token '" ;
376+ final int start = msg .indexOf (prefix );
377+ assertThat (start ).as ("message: %s" , msg ).isGreaterThanOrEqualTo (0 );
378+ final int end = msg .indexOf ("': was expecting" , start );
379+ assertThat (end ).as ("message: %s" , msg ).isGreaterThan (start );
380+ return msg .substring (start + prefix .length (), end );
381+ }
382+
321383 private String _buildBrokenJsonOfLength (int len )
322384 {
323- StringBuilder sb = new StringBuilder ("{\" key\" :" );
385+ return "{\" key\" :" + _brokenToken (len ) + "!}" ;
386+ }
387+
388+ // Varied (not repeating single) chars so that duplicated/dropped chars are detectable
389+ private String _brokenToken (int len )
390+ {
391+ StringBuilder sb = new StringBuilder (len );
324392 for (int i = 0 ; i < len ; i ++) {
325- sb .append ("a" );
393+ sb .append (( char ) ( 'a' + ( i % 26 )) );
326394 }
327- sb .append ("!}" );
328395 return sb .toString ();
329396 }
330397}
0 commit comments