• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package org.apache.harmony.nio_char.tests.java.nio.charset;
18 
19 import java.io.IOException;
20 import java.nio.BufferOverflowException;
21 import java.nio.ByteBuffer;
22 import java.nio.CharBuffer;
23 import java.nio.charset.CharacterCodingException;
24 import java.nio.charset.Charset;
25 import java.nio.charset.CharsetDecoder;
26 import java.nio.charset.CharsetEncoder;
27 import java.nio.charset.CoderMalfunctionError;
28 import java.nio.charset.CoderResult;
29 import java.nio.charset.CodingErrorAction;
30 import java.nio.charset.MalformedInputException;
31 import java.util.Arrays;
32 
33 import junit.framework.TestCase;
34 
35 public class CharsetDecoderTest extends TestCase {
36 
37     /**
38 	 * @tests java.nio.charset.CharsetDecoder.CharsetDecoder(Charset, float,
39 	 *        float)
40 	 */
test_ConstructorLjava_nio_charset_CharsetFF()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 {
MockCharsetDecoderForHarmony142(Charset cs, float averageBytesPerChar, float maxBytesPerChar)56 		protected MockCharsetDecoderForHarmony142(Charset cs,
57 				float averageBytesPerChar, float maxBytesPerChar) {
58 			super(cs, averageBytesPerChar, maxBytesPerChar);
59 		}
60 
decodeLoop(ByteBuffer in, CharBuffer out)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 	 */
test_decode()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      */
test_decodeLjava_nio_ByteBuffer()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 
MockMalfunctionCharset(String canonicalName, String[] aliases)133 		public MockMalfunctionCharset(String canonicalName, String[] aliases) {
134 			super(canonicalName, aliases);
135 		}
136 
contains(Charset cs)137 		public boolean contains(Charset cs) {
138 			return false;
139 		}
140 
newDecoder()141 		public CharsetDecoder newDecoder() {
142 			return new MockMalfunctionDecoder(this);
143 		}
144 
newEncoder()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 
MockMalfunctionDecoder(Charset cs)155 		public MockMalfunctionDecoder(Charset cs) {
156 			super(cs, 1, 10);
157 		}
158 
decodeLoop(ByteBuffer in, CharBuffer out)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 
MockMalfunctionEncoder(Charset cs)169 		public MockMalfunctionEncoder(Charset cs) {
170 			super(cs, 1, 3, new byte[] { (byte) '?' });
171 		}
172 
encodeLoop(CharBuffer in, ByteBuffer out)173 		protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
174 			throw new BufferOverflowException();
175 		}
176 	}
177 
178 	/*
179 	 * Test the method decode(ByteBuffer) .
180 	 */
testDecodeLjava_nio_ByteBuffer_ReplaceOverflow()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 
MockMalformedDecoder(Charset cs)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 		 */
decodeLoop(ByteBuffer in, CharBuffer out)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 
testInvalidDecoding()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 
253         /*
254          * When bytebuffer has a backing array...
255          */
256         for (byte[] bytes : invalidSequences) {
257             try {
258                 decoder.decode(ByteBuffer.wrap(bytes));
259                 fail("No exception thrown on " + Arrays.toString(bytes));
260             } catch (MalformedInputException e) {
261                 // 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                 decoder.decode(bb);
273                 fail("No exception thrown on " + Arrays.toString(bytes));
274             } catch (MalformedInputException e) {
275                 // expected
276             }
277         }
278     }
279 
280 }
281