com.github.jinahya.verbose.codec.BinaryCodecTest.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jinahya.verbose.codec.BinaryCodecTest.java

Source

/*
 * Copyright 2014 Jin Kwon.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.jinahya.verbose.codec;

import java.io.IOException;
import static java.lang.Runtime.getRuntime;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.ThreadLocalRandom.current;
import java.util.logging.Logger;
import org.apache.commons.lang3.RandomStringUtils;
import static org.testng.Assert.assertEquals;
import org.testng.SkipException;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

/**
 *
 * @author Jin Kwon
 * @param <E>
 * @param <D>
 */
public abstract class BinaryCodecTest<E extends BinaryEncoder, D extends BinaryDecoder> {

    /**
     * logger.
     */
    private static final Logger logger = Logger.getLogger(MethodHandles.lookup().lookupClass().getCanonicalName());

    /**
     * Creates a new instance.
     *
     * @param encoderType
     * @param decoderType
     *
     * @see BinaryEncoderFactory#newInstance(java.lang.Class)
     * @see BinaryDecoderFactory#newInstance(java.lang.Class)
     */
    public BinaryCodecTest(final Class<E> encoderType, final Class<D> decoderType) {

        super();

        encoder = BinaryEncoderFactory.newInstance(requireNonNull(encoderType, "null encoderType"));
        decoder = BinaryDecoderFactory.newInstance(requireNonNull(decoderType, "null decoderType"));
    }

    @BeforeClass
    protected void skipIfEitherEncoderOrDecoderIsNull() {

        if (encoder == null) {
            final String message = "encoder is null. skipping...";
            logger.warning(message);
            throw new SkipException(message);
        }

        if (decoder == null) {
            final String message = "decoder is null. skipping....";
            logger.warning(message);
            throw new SkipException(message);
        }
    }

    protected final void encodeDecode(final ByteBuffer expectedBuffer) {

        expectedBuffer.mark();

        final ByteBuffer encodedBuffer = encoder.encode(expectedBuffer);

        final ByteBuffer actualBuffer = decoder.decode(encodedBuffer);

        expectedBuffer.reset();

        assertEquals(actualBuffer, expectedBuffer);
    }

    /**
     * Tests encoding/decoding for given byte array.
     *
     * @param expectedBytes the decoded byte array.
     *
     * @see HexEncoder#encode(byte[])
     * @see HexDecoder#decode(byte[])
     */
    protected final void encodeDecode(final byte[] expectedBytes) {

        encodeDecode(ByteBuffer.wrap(expectedBytes));
    }

    /**
     * Tests encoding/decoding for given string and charset. This method first
     * encodes given string and then decodes the result and finally asserts the
     * final output equals to given origin string.
     *
     * @param expectedString the original string
     * @param expectedCharset the charset to decode or encode the original
     * string to or from byte array.
     * @param encodedCharset
     *
     * @see HexEncoder#encode(java.lang.String, java.nio.charset.Charset)
     * @see HexDecoder#decode(java.lang.String, java.nio.charset.Charset)
     */
    protected final void encodeDecode(final String expectedString, final Charset expectedCharset,
            final Charset encodedCharset) {

        final String encodedString = encoder.encode(expectedString, expectedCharset, encodedCharset);

        final String actualString = decoder.decode(encodedString, encodedCharset, expectedCharset);

        assertEquals(actualString, expectedString);
    }

    protected final void encodeDecode(final ReadableByteChannel expectedChannel) throws IOException {

        if (expectedChannel == null) {
            throw new NullPointerException("null expectedChannel");
        }

        final Path encodedPath = Files.createTempFile("test", null);
        getRuntime().addShutdownHook(new Thread(() -> {
            try {
                Files.delete(encodedPath);
            } catch (final IOException ioe) {
                ioe.printStackTrace(System.err);
            }
        }));
        final WritableByteChannel encodedChannel = FileChannel.open(encodedPath, StandardOpenOption.WRITE);

        final ByteBuffer decodedBuffer = ByteBuffer.allocate(128);
        final ByteBuffer encodedBuffer = ByteBuffer.allocate(decodedBuffer.capacity() << 1);

        while (expectedChannel.read(decodedBuffer) != -1) {
            decodedBuffer.flip(); // limit -> position; position -> zero
            encoder.encode(decodedBuffer, encodedBuffer);
            encodedBuffer.flip();
            encodedChannel.write(encodedBuffer);
            encodedBuffer.compact(); // position -> n  + 1; limit -> capacity
            decodedBuffer.compact();
        }

        decodedBuffer.flip();
        while (decodedBuffer.hasRemaining()) {
            encoder.encode(decodedBuffer, encodedBuffer);
            encodedBuffer.flip();
            encodedChannel.write(encodedBuffer);
            encodedBuffer.compact();
        }

        encodedBuffer.flip();
        while (encodedBuffer.hasRemaining()) {
            encodedChannel.write(encodedBuffer);
        }
    }

    protected final void encodeDecode(final Path expectedPath) throws IOException {

        if (expectedPath == null) {
            throw new NullPointerException("null expectedPath");
        }

        try (final FileChannel expectedChannel = FileChannel.open(expectedPath, StandardOpenOption.READ)) {
            encodeDecode(expectedChannel);
        }
    }

    @Test(enabled = true, invocationCount = 1)
    public void encodeDecodeEmptyStrings(final Charset encodedCharset) {

        encodeDecode("", UTF_8, encodedCharset);
    }

    @Test(enabled = true, invocationCount = 128)
    public void encodeDecodeRandomStrings(final Charset encodedCharset) {

        final String expectedString = RandomStringUtils.random(current().nextInt(128));

        encodeDecode(expectedString, UTF_8, encodedCharset);
    }

    @Test(enabled = true, invocationCount = 1)
    public void encodeDecodeEmptyBytes() {

        encodeDecode(new byte[0]);
    }

    @Test(enabled = true, invocationCount = 128)
    public void encodeDecodeRandomBytes() {

        final byte[] expected = new byte[current().nextInt(128)];
        current().nextBytes(expected);

        encodeDecode(expected);
    }

    @Test(enabled = true, invocationCount = 128)
    public void encodeDecodeRandomFiles() throws IOException {

        final Path expectedPath = Files.createTempFile("test", null);
        getRuntime().addShutdownHook(new Thread(() -> {
            try {
                Files.delete(expectedPath);
            } catch (final IOException ioe) {
                ioe.printStackTrace(System.err);
            }
        }));
        final byte[] array = new byte[1024];
        final ByteBuffer buffer = ByteBuffer.wrap(array);
        try (final FileChannel decodedChannel = FileChannel.open(expectedPath, StandardOpenOption.WRITE)) {
            final int count = current().nextInt(128);
            for (int i = 0; i < count; i++) {
                current().nextBytes(array);
                decodedChannel.write(buffer);
            }
            decodedChannel.force(false);
        }

        encodeDecode(expectedPath);
    }

    /**
     * hex encoder.
     */
    protected final E encoder;

    /**
     * hex decoder.
     */
    protected final D decoder;

}