blob: 8e28ad1d848d5c28f7755759b79df97bd606fd8d [file] [log] [blame]
/* 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.io.IOException;
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 java.util.Arrays;
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");
new MockCharsetDecoderForHarmony142(cs, 1.1f, 1);
fail("Assert 0: Should throw IllegalArgumentException.");
} 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);
try {
cs1.newDecoder().onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE).decode(
ByteBuffer.wrap(new byte[] { 0x00, 0x11 }));
fail("Assert 0: should throw CoderMalfunctionError");
} catch (CoderMalfunctionError e) {
// expected
}
MockMalfunctionCharset cs2 = new MockMalfunctionCharset(
"Harmony-124-2", null);
try {
cs2.decode(ByteBuffer.wrap(new byte[] { 0x00, 0x11 }));
fail("Assert 1: Charset.decode should throw CoderMalfunctionError");
} 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;
}
}
public void testInvalidDecoding() throws IOException {
byte[][] invalidSequences = new byte[][] {
// overlong NULL
{ (byte) 0xC0, (byte) 0x80 },
// overlong ascii 'A'
{ (byte) 0xC0, (byte) 0xC1 },
// overlong "/../"
{ (byte) 0x2F, (byte) 0xC0, (byte) 0xAE, (byte) 0x2E, (byte) 0x2F },
// Invalid encoding 2r11111000 (sequence too long)
{ (byte) 0xF8 },
// Invalid encoding 2r10000000 (sequence too short)
{ (byte) 0x80 }
};
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPORT);
/*
* When bytebuffer has a backing array...
*/
for (byte[] bytes : invalidSequences) {
try {
decoder.decode(ByteBuffer.wrap(bytes));
fail("No exception thrown on " + Arrays.toString(bytes));
} catch (MalformedInputException e) {
// expected
}
}
/*
* When bytebuffer has _not_ got a backing array...
*/
for (byte[] bytes : invalidSequences) {
try {
ByteBuffer bb = ByteBuffer.allocateDirect(8);
bb.put(bytes).flip();
decoder.decode(bb);
fail("No exception thrown on " + Arrays.toString(bytes));
} catch (MalformedInputException e) {
// expected
}
}
}
}