Package org.fcrepo.server.test

Source Code of org.fcrepo.server.test.JournalBase64Test

/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server.test;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import org.fcrepo.server.journal.helpers.DecodingBase64OutputStream;
import org.fcrepo.server.journal.helpers.EncodingBase64InputStream;

import junit.framework.TestCase;


/**
* Confirm that we can properly encode and decode any data stream that comes
* our way.
*
* @author Jim Blake
*/
public class JournalBase64Test
        extends TestCase {

    private static final String WHITE_SPACE_CHARACTERS = " \t\n\r";

    private static final String BASE64_ENCODING_CHARACTERS =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    public JournalBase64Test(String name) {
        super(name);
    }

    /**
     * Generate a temporary file with all possible bytes in it. Encode it,
     * decode it, test for correctness.
     */
    public void testOnArbitraryBytes() throws IOException {

        // create the source file and fill it.
        File source = createTempFile();
        OutputStream os = new FileOutputStream(source);
        for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
            os.write(i);
        }
        os.close();

        // process the file and test.
        encodeAndDecodeWithAssertions(source);
    }

    /**
     * Generate a temporary file with all sorts of Unicode characters in it,
     * encoded to UTF-8. Encode it, decode it, test for correctness.
     */
    public void testOnUTF8Characters() throws IOException {
        // create the source file and fill it.
        File source = createTempFile();
        Writer writer =
                new OutputStreamWriter(new FileOutputStream(source), "UTF-8");
        for (int i = 0, charValue = 0; i < 256; i++) {
            writer.write(charValue);
            charValue += 131;
        }
        writer.close();

        // process the file and test.
        encodeAndDecodeWithAssertions(source);
    }

    /**
     * Generate a temporary file with a troublesome section in it - this is text
     * that is known to have caused problems with the previous encode/decode
     * scheme. Encode it, decode it, test for correctness.
     */
    public void testOnKnownProblemFile() throws IOException {
        byte[] problemData =
                new byte[] {0x73, 0x00, 0x6F, 0x00, 0x75, 0x00, 0x72, 0x00,
                        0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61,
                        0x00, 0x6E, 0x00, 0x64, 0x00, 0x20, 0x00, 0x6C, 0x00,
                        0x65, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6E, 0x00, 0x69,
                        0x00, 0x6E, 0x00, 0x67, 0x00, 0x20, 0x00, 0x61, 0x00,
                        0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69,
                        0x00, 0x74, 0x00, 0x69, 0x00, 0x65, 0x00, 0x73, 0x00,
                        0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74,
                        0x00, 0x20, 0x00, 0x72, 0x00, 0x65, 0x00, 0x66, 0x00,
                        0x6C, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20,
                        0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00,
                        0x6D, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x75,
                        0x00, 0x6D, 0x00, (byte) 0xE2, 0x00, (byte) 0xAC, 0x20,
                        0x22, 0x21, 0x73, 0x00, 0x20, 0x00, 0x66, 0x00, 0x6F,
                        0x00, 0x75, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x61, 0x00,
                        0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x20,
                        0x00, 0x6F, 0x00, 0x66, 0x00, 0x20, 0x00, 0x70, 0x00,
                        0x6C, 0x00, 0x61, 0x00, 0x79, 0x00, 0x66, 0x00, 0x75,
                        0x00, 0x6C, 0x00, 0x20, 0x00, 0x65, 0x00, 0x78, 0x00,
                        0x68, 0x00, 0x69, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74,
                        0x00, 0x2D, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
                        0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6E,
                        0x00, 0x71, 0x00, 0x75, 0x00, 0x69, 0x00, 0x72, 0x00,
                        0x79, 0x00, 0x20, 0x00};

        // create the source file and fill it.
        File source = createTempFile();
        OutputStream os = new FileOutputStream(source);
        os.write(problemData);
        os.close();

        // process the file and test.
        encodeAndDecodeWithAssertions(source);
    }

    /**
     * Create a temp file that will be deleted when the test is complete.
     */
    private File createTempFile() throws IOException {
        File file = File.createTempFile("test", null);
        System.out.println(file.getPath());
        file.deleteOnExit();
        return file;
    }

    /**
     * Encode the source file to a String, then decode back to a file. Check
     * that the String is valid Base64, and that the target file has the same
     * contents as the source file.
     */
    private void encodeAndDecodeWithAssertions(File source)
            throws FileNotFoundException, IOException {
        // encode the file to a String and test that it is valid Base64
        String encodedString = readClearFileCreateEncodedString(source);
        assertStringContainsValidBase64(encodedString);

        // read the encoded String and encode it to the target file.
        File target = createTempFile();
        writeClearFileFromEncodedString(target, encodedString);

        // test the files.
        assertFileContentsAreEqual(source, target);
    }

    /**
     * Read a file of arbitrary bytes and produce a base-64 encoded String.
     */
    private String readClearFileCreateEncodedString(File source)
            throws IOException {
        // use a small buffer size, not a multiple, so we will do multiple
        // reads.
        EncodingBase64InputStream encoder =
                new EncodingBase64InputStream(new FileInputStream(source), 61);
        StringBuffer encoded = new StringBuffer();
        String chunk;
        while (null != (chunk = encoder.read(35))) {
            encoded.append(chunk);
        }
        encoder.close();

        String encodedString = encoded.toString();
        return encodedString;
    }

    /**
     * Produce a file of arbitrary bytes from a base-64 encoded String. We need
     * to process the String in chunks to simulate the Text events we will get
     * from the XmlReader.
     */
    private void writeClearFileFromEncodedString(File target,
                                                 String encodedString)
            throws FileNotFoundException, IOException {
        int maxChunkSize = 61;
        int length = encodedString.length();

        DecodingBase64OutputStream decoder =
                new DecodingBase64OutputStream(new FileOutputStream(target));

        int start = 0;
        int remainder;
        while (0 < (remainder = length - start)) {
            int chunkSize = Math.min(remainder, maxChunkSize);
            String chunk = encodedString.substring(start, start + chunkSize);
            decoder.write(chunk);
            start += chunkSize;
        }
        decoder.close();
    }

    /**
     * Base64 data should consist only of the 64 pemissible characters and the
     * equals sign, in groups of 4 characters. Equals should appear only at the
     * end, and no more than 2 are allowed. The spec allows any other characters
     * to appear, and they should be ignored, but we'll be a little more strict
     * and only allow white space characters.
     */
    private void assertStringContainsValidBase64(String string) {
        int howManyEqualsSigns = 0;
        int howManyEncodingCharacters = 0;
        for (int i = 0; i < string.length(); i++) {
            char thisChar = string.charAt(i);
            if (thisChar == '=') {
                howManyEqualsSigns++;
            } else if (BASE64_ENCODING_CHARACTERS.indexOf(thisChar) != -1) {
                howManyEncodingCharacters++;
                if (howManyEqualsSigns > 0) {
                    fail("Encoding character at " + i
                            + " follows an equals sign.");
                }
            } else if (WHITE_SPACE_CHARACTERS.indexOf(thisChar) == -1) {
                fail("Character '" + thisChar + "' at " + i
                        + " is not an encoding character, "
                        + "an equals sign, or white space.");
            }
        }
        if (howManyEqualsSigns > 2) {
            fail("Too many equals signs: " + howManyEqualsSigns);
        }
        int totalCharacters = howManyEqualsSigns + howManyEncodingCharacters;
        if (0 != totalCharacters % 4) {
            fail("Number of encoding characters plus equals signs "
                    + "must be a multiple of 4, not " + totalCharacters);
        }
    }

    /**
     * Read the files byte by byte and compare.
     */
    private void assertFileContentsAreEqual(File source, File target)
            throws IOException {
        InputStream sourceStream =
                new BufferedInputStream(new FileInputStream(source));
        InputStream targetStream =
                new BufferedInputStream(new FileInputStream(target));

        for (int i = 0; true; i++) {
            int sourceByte = sourceStream.read();
            int targetByte = targetStream.read();
            if (sourceByte == -1) {
                if (targetByte == -1) {
                    break;
                } else {
                    fail("source file is shorter than target file.");
                }
            } else if (targetByte == -1) {
                fail("target file is shorter than source file.");
            } else if (sourceByte != targetByte) {
                fail("files don't match at byte " + i + ": source="
                        + sourceByte + ", target=" + targetByte);
            }
        }
    }
}
TOP

Related Classes of org.fcrepo.server.test.JournalBase64Test

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.