1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.apache.harmony.tests.java.nio.charset; 18 19import java.io.IOException; 20import java.nio.BufferOverflowException; 21import java.nio.ByteBuffer; 22import java.nio.CharBuffer; 23import java.nio.charset.CharacterCodingException; 24import java.nio.charset.Charset; 25import java.nio.charset.CharsetDecoder; 26import java.nio.charset.CharsetEncoder; 27import java.nio.charset.CoderMalfunctionError; 28import java.nio.charset.CoderResult; 29import java.nio.charset.CodingErrorAction; 30import java.nio.charset.MalformedInputException; 31import java.util.Arrays; 32 33import junit.framework.TestCase; 34 35public class CharsetDecoder2Test extends TestCase { 36 37 /** 38 * @tests java.nio.charset.CharsetDecoder.CharsetDecoder(Charset, float, 39 * float) 40 */ 41 public void test_ConstructorLjava_nio_charset_CharsetFF() { 42 // Regression for HARMONY-142 43 try { 44 Charset cs = Charset.forName("UTF-8"); //$NON-NLS-1$ 45 new MockCharsetDecoderForHarmony142(cs, 1.1f, 1); 46 fail("Assert 0: Should throw IllegalArgumentException."); //$NON-NLS-1$ 47 } catch (IllegalArgumentException e) { 48 // expected 49 } 50 } 51 52 /* 53 * MockCharsetDecoderForHarmony142: for constructor test 54 */ 55 static class MockCharsetDecoderForHarmony142 extends CharsetDecoder { 56 protected MockCharsetDecoderForHarmony142(Charset cs, 57 float averageBytesPerChar, float maxBytesPerChar) { 58 super(cs, averageBytesPerChar, maxBytesPerChar); 59 } 60 61 protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { 62 return null; 63 } 64 } 65 66 /** 67 * @tests java.nio.charset.CharsetDecoder#decode(java.nio.ByteBuffer) 68 */ 69 public void test_decode() throws CharacterCodingException { 70 // Regression for HARMONY-33 71// ByteBuffer bb = ByteBuffer.allocate(1); 72// bb.put(0, (byte) 77); 73// CharsetDecoder decoder = Charset.forName("UTF-16").newDecoder(); 74// decoder.onMalformedInput(CodingErrorAction.REPLACE); 75// decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); 76// decoder.decode(bb); 77 78 // Regression for HARMONY-67 79// byte[] b = new byte[] { (byte) 1 }; 80// ByteBuffer buf = ByteBuffer.wrap(b); 81// CharBuffer charbuf = Charset.forName("UTF-16").decode(buf); 82// assertEquals("Assert 0: charset UTF-16", 1, charbuf.length()); 83// 84// charbuf = Charset.forName("UTF-16BE").decode(buf); 85// assertEquals("Assert 1: charset UTF-16BE", 0, charbuf.length()); 86// 87// charbuf = Charset.forName("UTF-16LE").decode(buf); 88// assertEquals("Assert 2: charset UTF16LE", 0, charbuf.length()); 89 90 // Regression for HARMONY-99 91 CharsetDecoder decoder2 = Charset.forName("UTF-16").newDecoder(); 92 decoder2.onMalformedInput(CodingErrorAction.REPORT); 93 decoder2.onUnmappableCharacter(CodingErrorAction.REPORT); 94 ByteBuffer in = ByteBuffer.wrap(new byte[] { 109, 97, 109 }); 95 try { 96 decoder2.decode(in); 97 fail("Assert 3: MalformedInputException should have thrown"); 98 } catch (MalformedInputException e) { 99 //expected 100 } 101 } 102 103 /* 104 * Test malfunction decode(ByteBuffer) 105 */ 106 public void test_decodeLjava_nio_ByteBuffer() throws Exception { 107 MockMalfunctionCharset cs1 = new MockMalfunctionCharset( 108 "Harmony-124-1", null); //$NON-NLS-1$ 109 try { 110 cs1.newDecoder().onMalformedInput(CodingErrorAction.REPLACE) 111 .onUnmappableCharacter(CodingErrorAction.REPLACE).decode( 112 ByteBuffer.wrap(new byte[] { 0x00, 0x11 })); 113 fail("Assert 0: should throw CoderMalfunctionError"); // NON-NLS-1$ 114 } catch (CoderMalfunctionError e) { 115 // expected 116 } 117 118 MockMalfunctionCharset cs2 = new MockMalfunctionCharset( 119 "Harmony-124-2", null); //$NON-NLS-1$ 120 try { 121 cs2.decode(ByteBuffer.wrap(new byte[] { 0x00, 0x11 })); 122 fail("Assert 1: Charset.decode should throw CoderMalfunctionError"); // NON-NLS-1 123 } catch (CoderMalfunctionError e) { 124 // expected 125 } 126 } 127 128 /* 129 * Mock charset class with malfunction decode & encode. 130 */ 131 static final class MockMalfunctionCharset extends Charset { 132 133 public MockMalfunctionCharset(String canonicalName, String[] aliases) { 134 super(canonicalName, aliases); 135 } 136 137 public boolean contains(Charset cs) { 138 return false; 139 } 140 141 public CharsetDecoder newDecoder() { 142 return new MockMalfunctionDecoder(this); 143 } 144 145 public CharsetEncoder newEncoder() { 146 return new MockMalfunctionEncoder(this); 147 } 148 } 149 150 /* 151 * Mock decoder. decodeLoop always throws unexpected exception. 152 */ 153 static class MockMalfunctionDecoder extends java.nio.charset.CharsetDecoder { 154 155 public MockMalfunctionDecoder(Charset cs) { 156 super(cs, 1, 10); 157 } 158 159 protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { 160 throw new BufferOverflowException(); 161 } 162 } 163 164 /* 165 * Mock encoder. encodeLoop always throws unexpected exception. 166 */ 167 static class MockMalfunctionEncoder extends java.nio.charset.CharsetEncoder { 168 169 public MockMalfunctionEncoder(Charset cs) { 170 super(cs, 1, 3, new byte[] { (byte) '?' }); 171 } 172 173 protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { 174 throw new BufferOverflowException(); 175 } 176 } 177 178 /* 179 * Test the method decode(ByteBuffer) . 180 */ 181 public void testDecodeLjava_nio_ByteBuffer_ReplaceOverflow() 182 throws Exception { 183 String replaceString = "a"; 184 Charset cs = Charset.forName("UTF-8"); 185 MockMalformedDecoder decoder = new MockMalformedDecoder(cs); 186 decoder.onMalformedInput(CodingErrorAction.REPLACE); 187 decoder.replaceWith(replaceString); 188 CharBuffer out = CharBuffer.allocate(1); 189 // MockMalformedDecoder treats the second byte '0x38' as malformed, 190 // but "out" doesn't have enough space for replace string. 191 ByteBuffer in = ByteBuffer.wrap(new byte[] { 0x45, 0x38, 0x45, 0x45 }); 192 CoderResult result = decoder.decode(in, out, false); 193 assertTrue(result.isOverflow()); 194 195 // allocate enough space for "out" 196 out = CharBuffer.allocate(10); 197 // replace string should be put into "out" firstly, 198 // and then decode "in". 199 result = decoder.decode(in, out, true); 200 out.flip(); 201 assertTrue(result.isUnderflow()); 202 assertEquals("bb", out.toString()); 203 } 204 205 /* 206 * Mock decoder. It treats byte whose value is less than "0x40" as 207 * malformed. 208 */ 209 static class MockMalformedDecoder extends java.nio.charset.CharsetDecoder { 210 211 public MockMalformedDecoder(Charset cs) { 212 super(cs, 1, 10); 213 } 214 215 /* 216 * It treats byte whose value is less than "0x40" as malformed. 217 * Otherwise, it's decoded as 'b'. 218 */ 219 protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { 220 while (in.hasRemaining()) { 221 byte b = in.get(); 222 if (b < 0x40) { 223 return CoderResult.malformedForLength(1); 224 } 225 if (!out.hasRemaining()) { 226 return CoderResult.OVERFLOW; 227 } 228 out.put((char) 'b'); 229 } 230 return CoderResult.UNDERFLOW; 231 } 232 } 233 234 235 public void testInvalidDecoding() throws IOException { 236 237 byte[][] invalidSequences = new byte[][] { 238 // overlong NULL 239 { (byte) 0xC0, (byte) 0x80 }, 240 // overlong ascii 'A' 241 { (byte) 0xC0, (byte) 0xC1 }, 242 // overlong "/../" 243 { (byte) 0x2F, (byte) 0xC0, (byte) 0xAE, (byte) 0x2E, (byte) 0x2F }, 244 // Invalid encoding 2r11111000 (sequence too long) 245 { (byte) 0xF8 }, 246 // Invalid encoding 2r10000000 (sequence too short) 247 { (byte) 0x80 } 248 }; 249 250 CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); 251 decoder.onMalformedInput(CodingErrorAction.REPORT); 252 decoder.onUnmappableCharacter(CodingErrorAction.REPORT); 253 254 /* 255 * When bytebuffer has a backing array... 256 */ 257 for (byte[] bytes : invalidSequences) { 258 try { 259 CharBuffer cb = decoder.decode(ByteBuffer.wrap(bytes)); 260 fail("No exception thrown on " + Arrays.toString(bytes) + " '" + cb + "'"); 261 } catch (MalformedInputException expected) { 262 } 263 } 264 265 /* 266 * When bytebuffer has _not_ got a backing array... 267 */ 268 for (byte[] bytes : invalidSequences) { 269 try { 270 ByteBuffer bb = ByteBuffer.allocateDirect(8); 271 bb.put(bytes).flip(); 272 CharBuffer cb = decoder.decode(bb); 273 fail("No exception thrown on " + Arrays.toString(bytes) + " '" + cb + "'"); 274 } catch (MalformedInputException expected) { 275 } 276 } 277 } 278 279} 280