WriterStringEscapeScan1680Test.java
package tools.jackson.core.unittest.write;
import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.ObjectWriteContext;
import tools.jackson.core.io.CharTypes;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.core.json.JsonWriteFeature;
import tools.jackson.core.unittest.*;
import static org.assertj.core.api.Assertions.assertThat;
/**
* [core#1680]: {@code WriterBasedJsonGenerator} tests constants instead of the
* escape table when the default table is in use. Verify that every 7-bit char
* is escaped the same as by the (table-driven) UTF-8 generator, for default and
* non-default tables, across short-String, long-String and {@code char[]} paths.
*/
class WriterStringEscapeScan1680Test extends JacksonCoreTestBase
{
// Longer than the Writer output buffer, to go through _writeSegment()
private final static int LONG_LEN = 20_000;
@Test
void defaultTableMatchesConstantCheck()
{
// Must agree with WriterBasedJsonGenerator._needsEscape() for default table
final int[] table = CharTypes.get7BitOutputEscapes();
assertThat(table).hasSize(128);
for (int c = 0; c < table.length; ++c) {
boolean expEscape = (c < 0x20) || (c == '"') || (c == '\\');
assertThat(table[c] != 0)
.as("char 0x%02X", c)
.isEqualTo(expEscape);
}
}
@Test
void defaultEscapes()
{
_verifyAllAscii(JsonFactory.builder().build());
}
@Test
void apostropheQuoting()
{
_verifyAllAscii(JsonFactory.builder().quoteChar('\'').build());
}
@Test
void escapeForwardSlashes()
{
_verifyAllAscii(JsonFactory.builder()
.enable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES).build());
}
@Test
void apostropheQuotingWithEscapedSlashes()
{
_verifyAllAscii(JsonFactory.builder().quoteChar('\'')
.enable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES).build());
}
private void _verifyAllAscii(JsonFactory f)
{
StringBuilder sb = new StringBuilder(LONG_LEN + 10);
for (int c = 0; c < 128; ++c) {
String shortStr = "a" + (char) c + "b";
_verifySame(f, shortStr, c);
// Long: escapable char at start, middle and end
sb.setLength(0);
sb.append((char) c);
while (sb.length() < LONG_LEN / 2) {
sb.append('x');
}
sb.append((char) c);
while (sb.length() < LONG_LEN) {
sb.append('y');
}
sb.append((char) c);
_verifySame(f, sb.toString(), c);
}
}
private void _verifySame(JsonFactory f, String value, int c)
{
final String exp = _writeUTF8(f, value);
assertThat(_writeWriter(f, value, false))
.as("String, char 0x%02X, length %d", c, value.length())
.isEqualTo(exp);
assertThat(_writeWriter(f, value, true))
.as("char[], char 0x%02X, length %d", c, value.length())
.isEqualTo(exp);
}
private String _writeWriter(JsonFactory f, String value, boolean asChars)
{
StringWriter sw = new StringWriter();
try (JsonGenerator g = f.createGenerator(ObjectWriteContext.empty(), sw)) {
g.writeStartArray();
if (asChars) {
char[] ch = value.toCharArray();
g.writeString(ch, 0, ch.length);
} else {
g.writeString(value);
}
g.writeEndArray();
}
return sw.toString();
}
private String _writeUTF8(JsonFactory f, String value)
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (JsonGenerator g = f.createGenerator(ObjectWriteContext.empty(), bytes)) {
g.writeStartArray();
g.writeString(value);
g.writeEndArray();
}
return bytes.toString(StandardCharsets.UTF_8);
}
}