FileDocCategorySizeDatePackage
CharsetDecoderTest.javaAPI DocAndroid 1.5 API9885Wed May 06 22:41:04 BST 2009org.apache.harmony.nio_char.tests.java.nio.charset

CharsetDecoderTest.java

/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.harmony.nio_char.tests.java.nio.charset;

import dalvik.annotation.TestTargetClass;
import dalvik.annotation.TestTargets;
import dalvik.annotation.TestTargetNew;
import dalvik.annotation.TestLevel;

import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderMalfunctionError;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.MalformedInputException;

import junit.framework.TestCase;
@TestTargetClass(CharsetDecoder.class)
public class CharsetDecoderTest extends TestCase {

    /**
     * @tests java.nio.charset.CharsetDecoder.CharsetDecoder(Charset, float,
     *        float)
     */
    @TestTargetNew(
        level = TestLevel.PARTIAL,
        notes = "Checks IllegalArgumentException.",
        method = "CharsetDecoder",
        args = {java.nio.charset.Charset.class, float.class, float.class}
    )
    public void test_ConstructorLjava_nio_charset_CharsetFF() {
        // Regression for HARMONY-142
        try {
            Charset cs = Charset.forName("UTF-8"); //$NON-NLS-1$
            new MockCharsetDecoderForHarmony142(cs, 1.1f, 1);
            fail("Assert 0: Should throw IllegalArgumentException."); //$NON-NLS-1$
        } catch (IllegalArgumentException e) {
            // expected
        }
    }

    /*
     * MockCharsetDecoderForHarmony142: for constructor test
     */
    static class MockCharsetDecoderForHarmony142 extends CharsetDecoder {
        protected MockCharsetDecoderForHarmony142(Charset cs,
                float averageBytesPerChar, float maxBytesPerChar) {
            super(cs, averageBytesPerChar, maxBytesPerChar);
        }

        protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
            return null;
        }
    }
 
    /**
     * @tests java.nio.charset.CharsetDecoder#decode(java.nio.ByteBuffer)
     */
    @TestTargetNew(
        level = TestLevel.PARTIAL,
        notes = "Regression test.",
        method = "decode",
        args = {java.nio.ByteBuffer.class}
    )
    public void test_decode() throws CharacterCodingException {
        // Regression for HARMONY-33
//        ByteBuffer bb = ByteBuffer.allocate(1);
//        bb.put(0, (byte) 77);
//        CharsetDecoder decoder = Charset.forName("UTF-16").newDecoder();
//        decoder.onMalformedInput(CodingErrorAction.REPLACE);
//        decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
//        decoder.decode(bb);

        // Regression for HARMONY-67
//        byte[] b = new byte[] { (byte) 1 };
//        ByteBuffer buf = ByteBuffer.wrap(b);
//        CharBuffer charbuf = Charset.forName("UTF-16").decode(buf);
//        assertEquals("Assert 0: charset UTF-16", 1, charbuf.length());
//
//        charbuf = Charset.forName("UTF-16BE").decode(buf);
//        assertEquals("Assert 1: charset UTF-16BE", 0, charbuf.length());
//
//        charbuf = Charset.forName("UTF-16LE").decode(buf);
//        assertEquals("Assert 2: charset UTF16LE", 0, charbuf.length());
        
        // Regression for HARMONY-99
        CharsetDecoder decoder2 = Charset.forName("UTF-16").newDecoder();
        decoder2.onMalformedInput(CodingErrorAction.REPORT);
        decoder2.onUnmappableCharacter(CodingErrorAction.REPORT);
        ByteBuffer in = ByteBuffer.wrap(new byte[] { 109, 97, 109 });
        try {
            decoder2.decode(in);
            fail("Assert 3: MalformedInputException should have thrown");
        } catch (MalformedInputException e) {
            //expected
        } 
    }
    
    /*
     * Test malfunction decode(ByteBuffer)
     */
    @TestTargetNew(
        level = TestLevel.PARTIAL,
        notes = "Regression test. Checks CoderMalfunctionError",
        method = "decode",
        args = {java.nio.ByteBuffer.class}
    )
    public void test_decodeLjava_nio_ByteBuffer() throws Exception {
        MockMalfunctionCharset cs1 = new MockMalfunctionCharset(
                "Harmony-124-1", null); //$NON-NLS-1$
        try {
            cs1.newDecoder().onMalformedInput(CodingErrorAction.REPLACE)
                    .onUnmappableCharacter(CodingErrorAction.REPLACE).decode(
                            ByteBuffer.wrap(new byte[] { 0x00, 0x11 }));
            fail("Assert 0: should throw CoderMalfunctionError");  // NON-NLS-1$
        } catch (CoderMalfunctionError e) {
            // expected
        }

        MockMalfunctionCharset cs2 = new MockMalfunctionCharset(
                "Harmony-124-2", null); //$NON-NLS-1$
        try {
            cs2.decode(ByteBuffer.wrap(new byte[] { 0x00, 0x11 }));
            fail("Assert 1: Charset.decode should throw CoderMalfunctionError");  // NON-NLS-1
        } catch (CoderMalfunctionError e) {
            // expected
        }
    }
    
    /*
     * Mock charset class with malfunction decode & encode.
     */
    static final class MockMalfunctionCharset extends Charset {

        public MockMalfunctionCharset(String canonicalName, String[] aliases) {
            super(canonicalName, aliases);
        }

        public boolean contains(Charset cs) {
            return false;
        }

        public CharsetDecoder newDecoder() {
            return new MockMalfunctionDecoder(this);
        }

        public CharsetEncoder newEncoder() {
            return new MockMalfunctionEncoder(this);
        }
    }

    /*
     * Mock decoder. decodeLoop always throws unexpected exception.
     */
    static class MockMalfunctionDecoder extends java.nio.charset.CharsetDecoder {

        public MockMalfunctionDecoder(Charset cs) {
            super(cs, 1, 10);
        }

        protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
            throw new BufferOverflowException();
        }
    }

    /*
     * Mock encoder. encodeLoop always throws unexpected exception.
     */
    static class MockMalfunctionEncoder extends java.nio.charset.CharsetEncoder {

        public MockMalfunctionEncoder(Charset cs) {
            super(cs, 1, 3, new byte[] { (byte) '?' });
        }

        protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
            throw new BufferOverflowException();
        }
    } 
    
    /*
     * Test the method decode(ByteBuffer) .
     */
    @TestTargets({
        @TestTargetNew(
            level = TestLevel.PARTIAL,
            notes = "Functional test.",
            method = "decode",
            args = {java.nio.ByteBuffer.class, java.nio.CharBuffer.class, boolean.class}
        ),
        @TestTargetNew(
            level = TestLevel.PARTIAL,
            notes = "Functional test.",
            method = "implOnMalformedInput",
            args = {java.nio.charset.CodingErrorAction.class}
        ),
        @TestTargetNew(
            level = TestLevel.PARTIAL,
            notes = "Functional test.",
            method = "replaceWith",
            args = {java.lang.String.class}
        )
    })
    public void testDecodeLjava_nio_ByteBuffer_ReplaceOverflow()
            throws Exception {
        String replaceString = "a";
        Charset cs = Charset.forName("UTF-8");
        MockMalformedDecoder decoder = new MockMalformedDecoder(cs);
        decoder.onMalformedInput(CodingErrorAction.REPLACE);
        decoder.replaceWith(replaceString);
        CharBuffer out = CharBuffer.allocate(1);
        // MockMalformedDecoder treats the second byte '0x38' as malformed,
        // but "out" doesn't have enough space for replace string.
        ByteBuffer in = ByteBuffer.wrap(new byte[] { 0x45, 0x38, 0x45, 0x45 });
        CoderResult result = decoder.decode(in, out, false);
        assertTrue(result.isOverflow());

        // allocate enough space for "out"
        out = CharBuffer.allocate(10);
        // replace string should be put into "out" firstly,
        // and then decode "in".
        result = decoder.decode(in, out, true);
        out.flip();
        assertTrue(result.isUnderflow());
        assertEquals("bb", out.toString());
    }

    /*
     * Mock decoder. It treats byte whose value is less than "0x40" as
     * malformed.
     */
    static class MockMalformedDecoder extends java.nio.charset.CharsetDecoder {

        public MockMalformedDecoder(Charset cs) {
            super(cs, 1, 10);
        }

        /*
         * It treats byte whose value is less than "0x40" as malformed.
         * Otherwise, it's decoded as 'b'.
         */
        protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
            while (in.hasRemaining()) {
                byte b = in.get();
                if (b < 0x40) {
                    return CoderResult.malformedForLength(1);
                }
                if (!out.hasRemaining()) {
                    return CoderResult.OVERFLOW;
                }
                out.put((char) 'b');
            }
            return CoderResult.UNDERFLOW;
        }
    }
}