GeneratorMiscTest.java

package tools.jackson.core.unittest.write;

import java.io.*;

import org.junit.jupiter.api.Test;

import tools.jackson.core.*;
import tools.jackson.core.ObjectReadContext;
import tools.jackson.core.ObjectWriteContext;
import tools.jackson.core.exc.StreamWriteException;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.core.unittest.*;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Set of basic unit tests for verifying basic generator
 * features.
 */
@SuppressWarnings("resource")
public class GeneratorMiscTest
    extends JacksonCoreTestBase
{
    private final JsonFactory JSON_F = newStreamFactory();

    /*
    /**********************************************************
    /* Tests for closing, status
    /**********************************************************
     */

    @Test
    void isClosed() throws Exception
    {
        for (int i = 0; i < 2; ++i) {
            boolean stream = ((i & 1) == 0);
            ObjectWriteContext writeCtxt = ObjectWriteContext.empty();
            JsonGenerator g = stream ?
                    JSON_F.createGenerator(writeCtxt, new StringWriter())
                : JSON_F.createGenerator(writeCtxt, new ByteArrayOutputStream(), JsonEncoding.UTF8)
                ;
            assertFalse(g.isClosed());
            g.writeStartArray();
            g.writeNumber(-1);
            g.writeEndArray();
            assertFalse(g.isClosed());
            g.close();
            assertTrue(g.isClosed());
            g.close();
            assertTrue(g.isClosed());
        }
    }

    /*
    /**********************************************************
    /* Tests for raw output
    /**********************************************************
     */

    @Test
    void raw() throws Exception
    {
        StringWriter sw = new StringWriter();
        JsonGenerator gen = JSON_F.createGenerator(ObjectWriteContext.empty(), sw);
        gen.writeStartArray();
        gen.writeRaw("-123, true");
        gen.writeRaw(", \"x\"  ");
        gen.writeEndArray();
        gen.close();


        JsonParser jp = createParserUsingReader(sw.toString());
        assertToken(JsonToken.START_ARRAY, jp.nextToken());
        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
        assertEquals(-123, jp.getIntValue());
        assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
        assertToken(JsonToken.VALUE_STRING, jp.nextToken());
        assertEquals("x", jp.getString());
        assertToken(JsonToken.END_ARRAY, jp.nextToken());
        jp.close();
    }

    @Test
    void rawValue() throws Exception
    {
        StringWriter sw = new StringWriter();
        JsonGenerator gen = JSON_F.createGenerator(ObjectWriteContext.empty(), sw);
        gen.writeStartArray();
        gen.writeRawValue("7");
        gen.writeRawValue("[ null ]");
        gen.writeRawValue("false");
        gen.writeEndArray();
        gen.close();

        JsonParser jp = createParserUsingReader(sw.toString());
        assertToken(JsonToken.START_ARRAY, jp.nextToken());

        assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
        assertEquals(7, jp.getIntValue());
        assertToken(JsonToken.START_ARRAY, jp.nextToken());
        assertToken(JsonToken.VALUE_NULL, jp.nextToken());
        assertToken(JsonToken.END_ARRAY, jp.nextToken());
        assertToken(JsonToken.VALUE_FALSE, jp.nextToken());

        assertToken(JsonToken.END_ARRAY, jp.nextToken());
        jp.close();
    }

    /*
    /**********************************************************
    /* Tests for object writing
    /**********************************************************
     */

    /**
     * Unit test that tries to trigger buffer-boundary conditions
     */
    @Test
    void longerObjects() throws Exception
    {
        _testLongerObjects(JSON_F, 0);
        _testLongerObjects(JSON_F, 1);
        _testLongerObjects(JSON_F, 2);
    }

    public void _testLongerObjects(JsonFactory jf, int mode)
    {
        JsonGenerator g;
        ByteArrayOutputStream bout = new ByteArrayOutputStream(200);
        final ObjectWriteContext writeCtxt = ObjectWriteContext.empty();

        switch (mode) {
        case 0:
            try {
                g = jf.createGenerator(writeCtxt, new OutputStreamWriter(bout, "UTF-8"));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            break;
        case 1:
            g = jf.createGenerator(writeCtxt, bout, JsonEncoding.UTF8);
            break;
        case 2:
            {
                DataOutputStream dout = new DataOutputStream(bout);
                g = jf.createGenerator(writeCtxt, (DataOutput) dout);
            }

            break;
        default:
            fail("Unknown mode "+mode);
            g = null;
        }

        g.writeStartObject();

        for (int rounds = 0; rounds < 1500; ++rounds) {
            for (int letter = 'a'; letter <= 'z'; ++letter) {
                for (int index = 0; index < 20; ++index) {
                    String name;
                    if (letter > 'f') {
                        name = "X"+letter+index;
                    } else if (letter > 'p') {
                        name = ""+letter+index;
                    } else {
                        name = "__"+index+letter;
                    }
                    g.writeName(name);
                    g.writeNumber(index-1);
                }
                g.writeRaw('\n');
            }
        }
        g.writeEndObject();
        g.close();

        byte[] json = bout.toByteArray();
        JsonParser jp = jf.createParser(ObjectReadContext.empty(), json);
        assertToken(JsonToken.START_OBJECT, jp.nextToken());
        for (int rounds = 0; rounds < 1500; ++rounds) {
        for (int letter = 'a'; letter <= 'z'; ++letter) {
            for (int index = 0; index < 20; ++index) {
                assertToken(JsonToken.PROPERTY_NAME, jp.nextToken());
                String name;
                if (letter > 'f') {
                    name = "X"+letter+index;
                } else if (letter > 'p') {
                    name = ""+letter+index;
                } else {
                    name = "__"+index+letter;
                }
                assertEquals(name, jp.currentName());
                assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
                assertEquals(index-1, jp.getIntValue());
            }
        }
        }
        assertToken(JsonToken.END_OBJECT, jp.nextToken());
        jp.close();
    }

    /*
    /**********************************************************
    /* Tests, other
    /**********************************************************
     */

    // NOTE: test for binary data under `base64/` tests
    @Test
    void asEmbedded() throws Exception
    {
        StringWriter sw = new StringWriter();
        try (JsonGenerator g = JSON_F.createGenerator(ObjectWriteContext.empty(), sw)) {
            g.writeEmbeddedObject(null);
        }
        assertEquals("null", sw.toString());

        ByteArrayOutputStream bytes =  new ByteArrayOutputStream(100);
        try (JsonGenerator g = JSON_F.createGenerator(ObjectWriteContext.empty(), bytes)) {
            g.writeEmbeddedObject(null);
        }
        assertEquals("null", utf8String(bytes));

        // also, for fun, try illegal unknown thingy

        try (JsonGenerator g = JSON_F.createGenerator(ObjectWriteContext.empty(), bytes)) {
            // try writing a Class object
            g.writeEmbeddedObject(getClass());
            fail("Expected an exception");
        } catch (StreamWriteException e) {
            verifyException(e, "No native support for");
        }
    }

    @Test
    void capabilitiesAccess() throws Exception {
        try (JsonGenerator g = JSON_F.createGenerator(ObjectWriteContext.empty(), new StringWriter())) {
            assertFalse(g.streamWriteCapabilities().isEnabled(StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY));
            assertFalse(g.has(StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY));
            assertTrue(g.has(StreamWriteCapability.CAN_WRITE_FORMATTED_NUMBERS));
        }
        try (JsonGenerator g = JSON_F.createGenerator(ObjectWriteContext.empty(), new ByteArrayOutputStream())) {
            assertFalse(g.streamWriteCapabilities().isEnabled(StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY));
            assertFalse(g.has(StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY));
            assertFalse(g.has(StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY));
        }
    }
}