michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * Bug 499990 - Locale-aware collation michael@0: * michael@0: * Tests our custom, locale-aware collating sequences. michael@0: */ michael@0: michael@0: // The name of the file containing the strings we'll sort during this test. michael@0: // The file's data is taken from intl/locale/tests/sort/us-ascii_base.txt and michael@0: // and intl/locale/tests/sort/us-ascii_sort.txt. michael@0: const DATA_BASENAME = "locale_collation.txt"; michael@0: michael@0: // The test data from DATA_BASENAME is read into this array. michael@0: var gStrings; michael@0: michael@0: // A collation created from the application's locale. Used by localeCompare(). michael@0: var gLocaleCollation; michael@0: michael@0: // A connection to our in-memory UTF-16-encoded database. michael@0: var gUtf16Conn; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: //// Helper Functions michael@0: michael@0: /** michael@0: * Since we create a UTF-16 database we have to clean it up, in addition to michael@0: * the normal cleanup of Storage tests. michael@0: */ michael@0: function cleanupLocaleTests() michael@0: { michael@0: print("-- Cleaning up test_locale_collation.js suite."); michael@0: gUtf16Conn.close(); michael@0: cleanup(); michael@0: } michael@0: michael@0: /** michael@0: * Creates a test database similar to the default one created in michael@0: * head_storage.js, except that this one uses UTF-16 encoding. michael@0: * michael@0: * @return A connection to the database. michael@0: */ michael@0: function createUtf16Database() michael@0: { michael@0: print("Creating the in-memory UTF-16-encoded database."); michael@0: let conn = getService().openSpecialDatabase("memory"); michael@0: conn.executeSimpleSQL("PRAGMA encoding = 'UTF-16'"); michael@0: michael@0: print("Make sure the encoding was set correctly and is now UTF-16."); michael@0: let stmt = conn.createStatement("PRAGMA encoding"); michael@0: do_check_true(stmt.executeStep()); michael@0: let enc = stmt.getString(0); michael@0: stmt.finalize(); michael@0: michael@0: // The value returned will actually be UTF-16le or UTF-16be. michael@0: do_check_true(enc === "UTF-16le" || enc === "UTF-16be"); michael@0: michael@0: return conn; michael@0: } michael@0: michael@0: /** michael@0: * Compares aActual to aExpected, ensuring that the numbers and orderings of michael@0: * the two arrays' elements are the same. michael@0: * michael@0: * @param aActual michael@0: * An array of strings retrieved from the database. michael@0: * @param aExpected michael@0: * An array of strings to which aActual should be equivalent. michael@0: */ michael@0: function ensureResultsAreCorrect(aActual, aExpected) michael@0: { michael@0: print("Actual results: " + aActual); michael@0: print("Expected results: " + aExpected); michael@0: michael@0: do_check_eq(aActual.length, aExpected.length); michael@0: for (let i = 0; i < aActual.length; i++) michael@0: do_check_eq(aActual[i], aExpected[i]); michael@0: } michael@0: michael@0: /** michael@0: * Synchronously SELECTs all rows from the test table of the given database michael@0: * using the given collation. michael@0: * michael@0: * @param aCollation michael@0: * The name of one of our custom locale collations. The rows are michael@0: * ordered by this collation. michael@0: * @param aConn michael@0: * A connection to either the UTF-8 database or the UTF-16 database. michael@0: * @return The resulting strings in an array. michael@0: */ michael@0: function getResults(aCollation, aConn) michael@0: { michael@0: let results = []; michael@0: let stmt = aConn.createStatement("SELECT t FROM test " + michael@0: "ORDER BY t COLLATE " + aCollation + " ASC"); michael@0: while (stmt.executeStep()) michael@0: results.push(stmt.row.t); michael@0: stmt.finalize(); michael@0: return results; michael@0: } michael@0: michael@0: /** michael@0: * Inserts strings into our test table of the given database in the order given. michael@0: * michael@0: * @param aStrings michael@0: * An array of strings. michael@0: * @param aConn michael@0: * A connection to either the UTF-8 database or the UTF-16 database. michael@0: */ michael@0: function initTableWithStrings(aStrings, aConn) michael@0: { michael@0: print("Initializing test table."); michael@0: michael@0: aConn.executeSimpleSQL("DROP TABLE IF EXISTS test"); michael@0: aConn.createTable("test", "t TEXT"); michael@0: let stmt = aConn.createStatement("INSERT INTO test (t) VALUES (:t)"); michael@0: aStrings.forEach(function (str) { michael@0: stmt.params.t = str; michael@0: stmt.execute(); michael@0: stmt.reset(); michael@0: }); michael@0: stmt.finalize(); michael@0: } michael@0: michael@0: /** michael@0: * Returns a sorting function suitable for passing to Array.prototype.sort(). michael@0: * The returned function uses the application's locale to compare strings. michael@0: * michael@0: * @param aCollation michael@0: * The name of one of our custom locale collations. The sorting michael@0: * strength is computed from this value. michael@0: * @return A function to use as a sorting callback. michael@0: */ michael@0: function localeCompare(aCollation) michael@0: { michael@0: var strength; michael@0: michael@0: switch (aCollation) { michael@0: case "locale": michael@0: strength = Ci.nsICollation.kCollationCaseInSensitive; michael@0: break; michael@0: case "locale_case_sensitive": michael@0: strength = Ci.nsICollation.kCollationAccentInsenstive; michael@0: break; michael@0: case "locale_accent_sensitive": michael@0: strength = Ci.nsICollation.kCollationCaseInsensitiveAscii; michael@0: break; michael@0: case "locale_case_accent_sensitive": michael@0: strength = Ci.nsICollation.kCollationCaseSensitive; michael@0: break; michael@0: default: michael@0: do_throw("Error in test: unknown collation '" + aCollation + "'"); michael@0: break; michael@0: } michael@0: return function (aStr1, aStr2) michael@0: gLocaleCollation.compareString(strength, aStr1, aStr2); michael@0: } michael@0: michael@0: /** michael@0: * Reads in the test data from the file DATA_BASENAME and returns it as an array michael@0: * of strings. michael@0: * michael@0: * @return The test data as an array of strings. michael@0: */ michael@0: function readTestData() michael@0: { michael@0: print("Reading in test data."); michael@0: michael@0: let file = do_get_file(DATA_BASENAME); michael@0: michael@0: let istream = Cc["@mozilla.org/network/file-input-stream;1"]. michael@0: createInstance(Ci.nsIFileInputStream); michael@0: istream.init(file, -1, -1, 0); michael@0: istream.QueryInterface(Components.interfaces.nsILineInputStream); michael@0: michael@0: let line = {}; michael@0: let lines = []; michael@0: while (istream.readLine(line)) michael@0: lines.push(line.value); michael@0: istream.close(); michael@0: michael@0: return lines; michael@0: } michael@0: michael@0: /** michael@0: * Gets the results from the given database using the given collation and michael@0: * ensures that they match gStrings sorted by the same collation. michael@0: * michael@0: * @param aCollation michael@0: * The name of one of our custom locale collations. The rows from the michael@0: * database and the expected results are ordered by this collation. michael@0: * @param aConn michael@0: * A connection to either the UTF-8 database or the UTF-16 database. michael@0: */ michael@0: function runTest(aCollation, aConn) michael@0: { michael@0: ensureResultsAreCorrect(getResults(aCollation, aConn), michael@0: gStrings.slice(0).sort(localeCompare(aCollation))); michael@0: } michael@0: michael@0: /** michael@0: * Gets the results from the UTF-8 database using the given collation and michael@0: * ensures that they match gStrings sorted by the same collation. michael@0: * michael@0: * @param aCollation michael@0: * The name of one of our custom locale collations. The rows from the michael@0: * database and the expected results are ordered by this collation. michael@0: */ michael@0: function runUtf8Test(aCollation) michael@0: { michael@0: runTest(aCollation, getOpenedDatabase()); michael@0: } michael@0: michael@0: /** michael@0: * Gets the results from the UTF-16 database using the given collation and michael@0: * ensures that they match gStrings sorted by the same collation. michael@0: * michael@0: * @param aCollation michael@0: * The name of one of our custom locale collations. The rows from the michael@0: * database and the expected results are ordered by this collation. michael@0: */ michael@0: function runUtf16Test(aCollation) michael@0: { michael@0: runTest(aCollation, gUtf16Conn); michael@0: } michael@0: michael@0: /** michael@0: * Sets up the test suite. michael@0: */ michael@0: function setup() michael@0: { michael@0: print("-- Setting up the test_locale_collation.js suite."); michael@0: michael@0: gStrings = readTestData(); michael@0: michael@0: initTableWithStrings(gStrings, getOpenedDatabase()); michael@0: michael@0: gUtf16Conn = createUtf16Database(); michael@0: initTableWithStrings(gStrings, gUtf16Conn); michael@0: michael@0: let localeSvc = Cc["@mozilla.org/intl/nslocaleservice;1"]. michael@0: getService(Ci.nsILocaleService); michael@0: let collFact = Cc["@mozilla.org/intl/collation-factory;1"]. michael@0: createInstance(Ci.nsICollationFactory); michael@0: gLocaleCollation = collFact.CreateCollation(localeSvc.getApplicationLocale()); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: //// Test Runs michael@0: michael@0: let gTests = [ michael@0: { michael@0: desc: "Case and accent sensitive UTF-8", michael@0: run: function () runUtf8Test("locale_case_accent_sensitive") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case sensitive, accent insensitive UTF-8", michael@0: run: function () runUtf8Test("locale_case_sensitive") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case insensitive, accent sensitive UTF-8", michael@0: run: function () runUtf8Test("locale_accent_sensitive") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case and accent insensitive UTF-8", michael@0: run: function () runUtf8Test("locale") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case and accent sensitive UTF-16", michael@0: run: function () runUtf16Test("locale_case_accent_sensitive") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case sensitive, accent insensitive UTF-16", michael@0: run: function () runUtf16Test("locale_case_sensitive") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case insensitive, accent sensitive UTF-16", michael@0: run: function () runUtf16Test("locale_accent_sensitive") michael@0: }, michael@0: michael@0: { michael@0: desc: "Case and accent insensitive UTF-16", michael@0: run: function () runUtf16Test("locale") michael@0: }, michael@0: ]; michael@0: michael@0: function run_test() michael@0: { michael@0: setup(); michael@0: gTests.forEach(function (test) { michael@0: print("-- Running test: " + test.desc); michael@0: test.run(); michael@0: }); michael@0: }