2 Copyright 2010 Sun Microsystems, Inc.
3 All rights reserved. Use is subject to license terms.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 package testsuite.clusterj;
21 import java.nio.ByteBuffer;
22 import java.nio.CharBuffer;
23 import java.nio.charset.Charset;
24 import java.nio.charset.CharsetEncoder;
25 import java.nio.charset.CoderResult;
27 import java.sql.PreparedStatement;
28 import java.sql.ResultSet;
29 import java.sql.SQLException;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Properties;
35 import testsuite.clusterj.model.CharsetLatin1;
36 import testsuite.clusterj.model.CharsetBig5;
37 import testsuite.clusterj.model.CharsetModel;
38 import testsuite.clusterj.model.CharsetSjis;
39 import testsuite.clusterj.model.CharsetUtf8;
41 /** Test that all characters in supported character sets can be read and written.
43 * 1. Identify which character sets to test.
44 * 2. For each character set, create a table with an id column and three VARCHAR columns
45 * (one with length < 256 another with length > 256, and a third with length > 8000)
46 * with the test character set.
47 * 3. For each table, write a persistent interface that maps the table.
48 * 4. For each persistent interface:
49 * a) create an empty list of String
50 * b) create a CharBuffer containing all mappable characters for the character set from the range 0:65535
51 * c) map the CharBuffer to a ByteBuffer of length equal to the size of the VARCHAR column
52 * d) create a String from the characters in the CharBuffer that could fit into the column
53 * e) add the String to the list of String
54 * f) continue from c) until all characters have been represented in the list of String
55 * g) remove all rows of the table
56 * h) use JDBC or clusterj to write a row in the database for each String in the list
57 * i) use JDBC or clusterj to read all rows and compare the String to the list of Strings
60 public class CharsetTest extends AbstractClusterJModelTest {
63 public void localSetUp() {
64 createSessionFactory();
65 session = sessionFactory.getSession();
66 setAutoCommit(connection, false);
69 public void testLatin1() {
70 writeJDBCreadJDBC("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.SMALL);
71 writeJDBCreadJDBC("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.MEDIUM);
72 writeJDBCreadJDBC("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.LARGE);
74 writeJDBCreadNDB("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.SMALL);
75 writeJDBCreadNDB("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.MEDIUM);
76 writeJDBCreadNDB("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.LARGE);
78 writeNDBreadJDBC("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.SMALL);
79 writeNDBreadJDBC("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.MEDIUM);
80 writeNDBreadJDBC("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.LARGE);
82 writeNDBreadNDB("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.SMALL);
83 writeNDBreadNDB("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.MEDIUM);
84 writeNDBreadNDB("windows-1252", "charsetlatin1", CharsetLatin1.class, ColumnDescriptor.LARGE);
89 public void testUtf8() {
90 writeJDBCreadJDBC("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.SMALL);
91 writeJDBCreadJDBC("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.MEDIUM);
92 writeJDBCreadJDBC("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.LARGE);
94 writeJDBCreadNDB("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.SMALL);
95 writeJDBCreadNDB("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.MEDIUM);
96 writeJDBCreadNDB("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.LARGE);
98 writeNDBreadJDBC("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.SMALL);
99 writeNDBreadJDBC("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.MEDIUM);
100 writeNDBreadJDBC("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.LARGE);
102 writeNDBreadNDB("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.SMALL);
103 writeNDBreadNDB("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.MEDIUM);
104 writeNDBreadNDB("UTF-8", "charsetutf8", CharsetUtf8.class, ColumnDescriptor.LARGE);
109 public void testSjis() {
110 /* These tests are excluded due to a JDBC error:
111 * java.sql.SQLException:
112 * Failed to insert charsetsjis at instance 0 errant string: [... 165 167 168... ]
113 * Incorrect string value: '\xC2\xA5\xC2\xA7\xC2\xA8...' for column 'smallcolumn' at row 1
114 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
115 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
116 at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3558)
117 at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3490)
118 at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)
119 at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2109)
120 at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2648)
121 at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2077)
122 at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1356)
123 at testsuite.clusterj.CharsetTest.writeToJDBC(CharsetTest.java:317)
124 writeJDBCreadJDBC("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.SMALL);
125 writeJDBCreadJDBC("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.MEDIUM);
126 writeJDBCreadJDBC("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.LARGE);
129 writeNDBreadJDBC("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.SMALL);
130 writeNDBreadJDBC("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.MEDIUM);
131 writeNDBreadJDBC("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.LARGE);
133 writeNDBreadNDB("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.SMALL);
134 writeNDBreadNDB("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.MEDIUM);
135 writeNDBreadNDB("SJIS", "charsetsjis", CharsetSjis.class, ColumnDescriptor.LARGE);
140 public void testBig5() {
141 writeJDBCreadJDBC("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.SMALL);
142 writeJDBCreadJDBC("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.MEDIUM);
143 writeJDBCreadJDBC("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.LARGE);
145 writeJDBCreadNDB("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.SMALL);
146 writeJDBCreadNDB("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.MEDIUM);
147 writeJDBCreadNDB("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.LARGE);
149 writeNDBreadJDBC("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.SMALL);
150 writeNDBreadJDBC("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.MEDIUM);
151 writeNDBreadJDBC("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.LARGE);
153 writeNDBreadNDB("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.SMALL);
154 writeNDBreadNDB("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.MEDIUM);
155 writeNDBreadNDB("big5", "charsetbig5", CharsetBig5.class, ColumnDescriptor.LARGE);
160 protected void writeJDBCreadJDBC(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
161 ColumnDescriptor columnDescriptor) {
162 removeAll(modelClass);
163 List<String> result = null;
164 List<String> strings = generateStrings(columnDescriptor, charsetName);
165 List<CharsetModel> instances = generateInstances(columnDescriptor, modelClass, strings);
166 writeToJDBC(columnDescriptor, tableName, instances);
167 result = readFromJDBC(columnDescriptor, tableName);
168 if (debug) System.out.println("Returned results of size " + result.size());
169 // if (debug) System.out.println("Results:\n" + dump(result));
170 verify("writeJDBCreadJDBC", strings, result, columnDescriptor);
173 protected void writeJDBCreadNDB(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
174 ColumnDescriptor columnDescriptor) {
175 removeAll(modelClass);
176 List<String> result = null;
177 List<String> strings = generateStrings(columnDescriptor, charsetName);
178 List<CharsetModel> instances = generateInstances(columnDescriptor, modelClass, strings);
179 writeToJDBC(columnDescriptor, tableName, instances);
180 result = readFromNDB(columnDescriptor, modelClass);
181 if (debug) System.out.println("Returned results of size " + result.size());
182 // if (debug) System.out.println("Results: " + dump(result));
183 verify("writeJDBCreadNDB", strings, result, columnDescriptor);
186 protected void writeNDBreadJDBC(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
187 ColumnDescriptor columnDescriptor) {
188 removeAll(modelClass);
189 List<String> result = null;
190 List<String> strings = generateStrings(columnDescriptor, charsetName);
191 List<CharsetModel> instances = generateInstances(columnDescriptor, modelClass, strings);
192 writeToNDB(columnDescriptor, instances);
193 result = readFromJDBC(columnDescriptor, tableName);
194 if (debug) System.out.println("Returned results of size " + result.size());
195 // if (debug) System.out.println("Results: " + dump(result));
196 verify("writeNDBreadJDBC", strings, result, columnDescriptor);
199 protected void writeNDBreadNDB(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
200 ColumnDescriptor columnDescriptor) {
201 removeAll(modelClass);
202 List<String> result = null;
203 List<String> strings = generateStrings(columnDescriptor, charsetName);
204 List<CharsetModel> instances = generateInstances(columnDescriptor, modelClass, strings);
205 writeToNDB(columnDescriptor, instances);
206 result = readFromNDB(columnDescriptor, modelClass);
207 if (debug) System.out.println("Returned results of size " + result.size());
208 // if (debug) System.out.println("Results: " + dump(result));
209 verify("writeNDBreadNDB", strings, result, columnDescriptor);
212 private void verify(String where, List<String> expecteds, List<String> actuals, ColumnDescriptor columnDescriptor) {
214 for (int i = 0; i < expecteds.size(); ++i) {
215 String expected = expecteds.get(i);
216 String actual = actuals.get(i);
217 int expectedLength = expected.length();
218 int actualLength = actual.length();
219 errorIfNotEqual(where + " got failure on size of column data for column width " + columnDescriptor.columnWidth + " at row " + i, expectedLength, actualLength);
220 if (expectedLength != actualLength)
222 for (int j = 0; j < expected.length(); ++j) {
223 if (--maxErrors > 0) {
224 errorIfNotEqual("Failure to match column data for column width " + columnDescriptor.columnWidth + " at row " + i + " column " + j,
225 expected.codePointAt(j), actual.codePointAt(j));
231 protected List<String> generateStrings(ColumnDescriptor columnDescriptor,
232 String charsetName) {
233 List<String> result = new ArrayList<String>();
234 Charset charset = Charset.forName(charsetName);
235 CharBuffer allChars = CharBuffer.allocate(65536);
236 CharsetEncoder encoder = charset.newEncoder();
237 // add all encodable characters to the buffer
239 // for (int i = 0; i < 65536; ++i) {
240 for (int i = 0; i < 65536; ++i) {
241 Character ch = (char)i;
242 if (encoder.canEncode(ch)) {
247 if (debug) System.out.print(charsetName + " has " + count + " encodable characters");
250 int width = columnDescriptor.getColumnWidth();
251 // encode all the characters that fit into the output byte buffer
252 boolean done = false;
253 byte[] bytes = new byte[width];
255 int begin = allChars.position();
257 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
258 CoderResult coderResult = encoder.encode(allChars, byteBuffer, false);
259 int end = allChars.position();
260 int length = end - begin;
265 char[] chars = new char[length];
267 allChars.get(chars, 0, length);
268 String encodable = String.copyValueOf(chars);
269 result.add(encodable);
270 if (coderResult.isUnderflow()) {
274 if (debug) System.out.println(" in " + result.size() + " row(s) of size " + columnDescriptor.columnWidth);
278 protected List<CharsetModel> generateInstances(ColumnDescriptor columnDescriptor,
279 Class<? extends CharsetModel> modelClass, List<String> strings) {
280 List<CharsetModel> result = new ArrayList<CharsetModel>();
281 for (int i = 0; i < strings.size(); ++i) {
282 CharsetModel instance = session.newInstance(modelClass);
284 columnDescriptor.set(instance, strings.get(i));
285 result.add(instance);
287 if (debug) System.out.println("Created " + result.size() + " instances of " + modelClass.getName());
291 protected void writeToJDBC(ColumnDescriptor columnDescriptor,
292 String tableName, List<CharsetModel> instances) {
293 StringBuffer buffer = new StringBuffer("INSERT INTO ");
294 buffer.append(tableName);
295 buffer.append(" (id, ");
296 buffer.append(columnDescriptor.getColumnName());
297 buffer.append(") VALUES (?, ?)");
298 String statement = buffer.toString();
299 if (debug) System.out.println(statement);
300 PreparedStatement preparedStatement = null;
304 Properties extraProperties = new Properties();
305 extraProperties.put("characterEncoding", "utf8");
306 getConnection(extraProperties);
307 setAutoCommit(connection, false);
308 preparedStatement = connection.prepareStatement(statement);
309 if (debug) System.out.println(preparedStatement.toString());
310 for (i = 0; i < instances.size(); ++i) {
311 CharsetModel instance = instances.get(i);
312 preparedStatement.setInt(1, instance.getId());
313 value = columnDescriptor.get(instance);
314 preparedStatement.setString(2, value);
315 // if (debug) System.out.println("Value set to column is size " + value.length());
316 // if (debug) System.out.println(" value " + value);
317 preparedStatement.execute();
320 } catch (SQLException e) {
321 throw new RuntimeException("Failed to insert " + tableName + " at instance " + i + " errant string: " + dump(value), e);
325 protected void writeToNDB(ColumnDescriptor columnDescriptor, List<CharsetModel> instances) {
326 session.currentTransaction().begin();
327 for (CharsetModel instance: instances) {
328 session.makePersistent(instance);
330 session.currentTransaction().commit();
333 protected List<String> readFromNDB(ColumnDescriptor columnDescriptor,
334 Class<? extends CharsetModel> modelClass) {
335 List<String> result = new ArrayList<String>();
336 session.currentTransaction().begin();
338 boolean done = false;
340 CharsetModel instance = session.find(modelClass, i++);
341 if (instance != null) {
342 result.add(columnDescriptor.get(instance));
347 session.currentTransaction().commit();
351 protected List<String> readFromJDBC(ColumnDescriptor columnDescriptor,
353 List<String> result = new ArrayList<String>();
354 StringBuffer buffer = new StringBuffer("SELECT id, ");
355 buffer.append(columnDescriptor.getColumnName());
356 buffer.append(" FROM ");
357 buffer.append(tableName);
358 buffer.append(" ORDER BY ID");
359 String statement = buffer.toString();
360 if (debug) System.out.println(statement);
361 PreparedStatement preparedStatement = null;
364 preparedStatement = connection.prepareStatement(statement);
365 ResultSet rs = preparedStatement.executeQuery();
367 String columnData = rs.getString(2);
368 result.add(columnData);
372 } catch (SQLException e) {
373 throw new RuntimeException("Failed to read " + tableName + " at instance " + i, e);
378 protected enum ColumnDescriptor {
379 SMALL(200, "smallcolumn", new InstanceHandler() {
380 public void set(CharsetModel instance, String value) {
381 instance.setSmallColumn(value);
383 public String get(CharsetModel instance) {
384 return instance.getSmallColumn();
387 MEDIUM(500, "mediumcolumn", new InstanceHandler() {
388 public void set(CharsetModel instance, String value) {
389 instance.setMediumColumn(value);
391 public String get(CharsetModel instance) {
392 return instance.getMediumColumn();
395 LARGE(10000, "largecolumn", new InstanceHandler() {
396 public void set(CharsetModel instance, String value) {
397 instance.setLargeColumn(value);
399 public String get(CharsetModel instance) {
400 return instance.getLargeColumn();
404 private int columnWidth;
406 private String columnName;
408 private InstanceHandler instanceHandler;
410 public String getColumnName() {
414 public String get(CharsetModel instance) {
415 return instanceHandler.get(instance);
418 public void set(CharsetModel instance, String string) {
419 this.instanceHandler.set(instance, string);
422 public int getColumnWidth() {
426 private ColumnDescriptor(int width, String name, InstanceHandler instanceHandler) {
427 this.columnWidth = width;
428 this.columnName = name;
429 this.instanceHandler = instanceHandler;
432 private interface InstanceHandler {
433 void set(CharsetModel instance, String value);
434 String get(CharsetModel instance);
439 /** The instances for testing. */
440 protected List<CharsetModel> charsetTypes = new ArrayList<CharsetModel>();