michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: MARIONETTE_TIMEOUT = 60000; michael@0: michael@0: const LEN_7BIT = 160; michael@0: const LEN_7BIT_WITH_8BIT_REF = 153; michael@0: const LEN_7BIT_WITH_16BIT_REF = 152; michael@0: const LEN_UCS2 = 70; michael@0: const LEN_UCS2_WITH_8BIT_REF = 67; michael@0: const LEN_UCS2_WITH_16BIT_REF = 66; michael@0: michael@0: SpecialPowers.setBoolPref("dom.sms.enabled", true); michael@0: let currentStrict7BitEncoding = false; michael@0: SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding", michael@0: currentStrict7BitEncoding); michael@0: SpecialPowers.addPermission("sms", true, document); michael@0: michael@0: let manager = window.navigator.mozMobileMessage; michael@0: ok(manager instanceof MozMobileMessageManager, michael@0: "manager is instance of " + manager.constructor); michael@0: michael@0: function times(str, n) { michael@0: return (new Array(n + 1)).join(str); michael@0: } michael@0: michael@0: let tasks = { michael@0: // List of test fuctions. Each of them should call |tasks.next()| when michael@0: // completed or |tasks.finish()| to jump to the last one. michael@0: _tasks: [], michael@0: _nextTaskIndex: 0, michael@0: michael@0: push: function(func) { michael@0: this._tasks.push(func); michael@0: }, michael@0: michael@0: next: function() { michael@0: let index = this._nextTaskIndex++; michael@0: let task = this._tasks[index]; michael@0: try { michael@0: task(); michael@0: } catch (ex) { michael@0: ok(false, "test task[" + index + "] throws: " + ex); michael@0: // Run last task as clean up if possible. michael@0: if (index != this._tasks.length - 1) { michael@0: this.finish(); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: finish: function() { michael@0: this._tasks[this._tasks.length - 1](); michael@0: }, michael@0: michael@0: run: function() { michael@0: this.next(); michael@0: } michael@0: }; michael@0: michael@0: function addTest(text, strict7BitEncoding, expected) { michael@0: tasks.push(function() { michael@0: if (strict7BitEncoding != currentStrict7BitEncoding) { michael@0: currentStrict7BitEncoding = strict7BitEncoding; michael@0: SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding", michael@0: currentStrict7BitEncoding); michael@0: } michael@0: michael@0: let domRequest = manager.getSegmentInfoForText(text); michael@0: ok(domRequest, "DOMRequest object returned."); michael@0: michael@0: domRequest.onsuccess = function(e) { michael@0: log("Received 'onsuccess' DOMRequest event."); michael@0: michael@0: let result = e.target.result; michael@0: if (!result) { michael@0: ok(false, "getSegmentInfoForText() result is not valid."); michael@0: tasks.finish(); michael@0: return; michael@0: } michael@0: michael@0: is(result.segments, expected[0], "segments"); michael@0: is(result.charsPerSegment, expected[1], "charsPerSegment"); michael@0: is(result.charsAvailableInLastSegment, expected[2], michael@0: "charsAvailableInLastSegment"); michael@0: michael@0: tasks.next(); michael@0: }; michael@0: michael@0: domRequest.onerror = function(e) { michael@0: ok(false, "Failed to call getSegmentInfoForText()."); michael@0: tasks.finish(); michael@0: }; michael@0: }); michael@0: } michael@0: michael@0: // GSM 7Bit Alphabets: michael@0: // michael@0: // 'a' is in GSM default locking shift table, so it takes 1 septet. michael@0: addTest("a", false, [1, LEN_7BIT, LEN_7BIT - 1]); michael@0: // '\u20ac' is in GSM default single shift table, so it takes 2 septets. michael@0: addTest("\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 2]); michael@0: // SP is defined in both locking shift and single shift tables. michael@0: addTest(" ", false, [1, LEN_7BIT, LEN_7BIT - 1]); michael@0: // Some combinations. michael@0: addTest("a\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]); michael@0: addTest("a ", false, [1, LEN_7BIT, LEN_7BIT - 2]); michael@0: addTest("\u20aca", false, [1, LEN_7BIT, LEN_7BIT - 3]); michael@0: addTest("\u20ac ", false, [1, LEN_7BIT, LEN_7BIT - 3]); michael@0: addTest(" \u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]); michael@0: addTest(" a", false, [1, LEN_7BIT, LEN_7BIT - 2]); michael@0: michael@0: // GSM 7Bit Alphabets (multipart): michael@0: // michael@0: // Exactly 160 locking shift table chararacters. michael@0: addTest(times("a", LEN_7BIT), false, [1, LEN_7BIT, 0]); michael@0: // 161 locking shift table chararacters. We'll have |161 - 153 = 8| septets in michael@0: // the 2nd segment. michael@0: addTest(times("a", LEN_7BIT + 1), false, michael@0: [2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 8]); michael@0: // |LEN_7BIT_WITH_8BIT_REF * 2| locking shift table chararacters. michael@0: addTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2), false, michael@0: [2, LEN_7BIT_WITH_8BIT_REF, 0]); michael@0: // |LEN_7BIT_WITH_8BIT_REF * 2 + 1| locking shift table chararacters. michael@0: addTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2 + 1), false, michael@0: [3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 1]); michael@0: // Exactly 80 single shift table chararacters. michael@0: addTest(times("\u20ac", LEN_7BIT / 2), false, [1, LEN_7BIT, 0]); michael@0: // 81 single shift table chararacters. Because |Math.floor(153 / 2) = 76|, it michael@0: // should left 5 septets in the 2nd segment. michael@0: addTest(times("\u20ac", LEN_7BIT / 2 + 1), false, michael@0: [2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 10]); michael@0: // |1 + 2 * 76| single shift table chararacters. We have only |153 - 76 * 2 = 1| michael@0: // space left, but each single shift table character takes 2, so it will be michael@0: // filled in the 3rd segment. michael@0: addTest(times("\u20ac", 1 + 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false, michael@0: [3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 2]); michael@0: // |2 * 76| single shift table chararacters + 1 locking shift table chararacter. michael@0: addTest("a" + times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false, michael@0: [2, LEN_7BIT_WITH_8BIT_REF, 1]); michael@0: addTest(times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)) + "a", false, michael@0: [2, LEN_7BIT_WITH_8BIT_REF, 0]); michael@0: michael@0: // UCS2: michael@0: // michael@0: // '\u6afb' should be encoded as UCS2. michael@0: addTest("\u6afb", false, [1, LEN_UCS2, LEN_UCS2 - 1]); michael@0: // Combination of GSM 7bit alphabets. michael@0: addTest("\u6afba", false, [1, LEN_UCS2, LEN_UCS2 - 2]); michael@0: addTest("\u6afb\u20ac", false, [1, LEN_UCS2, LEN_UCS2 - 2]); michael@0: addTest("\u6afb ", false, [1, LEN_UCS2, LEN_UCS2 - 2]); michael@0: michael@0: // UCS2 (multipart): michael@0: // michael@0: // Exactly 70 UCS2 chararacters. michael@0: addTest(times("\u6afb", LEN_UCS2), false, [1, LEN_UCS2, 0]); michael@0: // 71 UCS2 chararacters. We'll have |71 - 67 = 4| chararacters in the 2nd michael@0: // segment. michael@0: addTest(times("\u6afb", LEN_UCS2 + 1), false, michael@0: [2, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 4]); michael@0: // |LEN_UCS2_WITH_8BIT_REF * 2| ucs2 chararacters. michael@0: addTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2), false, michael@0: [2, LEN_UCS2_WITH_8BIT_REF, 0]); michael@0: // |LEN_7BIT_WITH_8BIT_REF * 2 + 1| ucs2 chararacters. michael@0: addTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2 + 1), false, michael@0: [3, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 1]); michael@0: michael@0: // Strict 7-Bit Encoding: michael@0: // michael@0: // Should have no effect on GSM default alphabet characters. michael@0: addTest("\u0041", true, [1, LEN_7BIT, LEN_7BIT - 1]); michael@0: // "\u00c0"(À) should be mapped to "\u0041"(A). michael@0: addTest("\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 1]); michael@0: // Mixing mapped characters with unmapped ones. michael@0: addTest("\u00c0\u0041", true, [1, LEN_7BIT, LEN_7BIT - 2]); michael@0: addTest("\u0041\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 2]); michael@0: // UCS2 characters should be mapped to '*'. michael@0: addTest("\u1234", true, [1, LEN_7BIT, LEN_7BIT - 1]); michael@0: michael@0: michael@0: // WARNING: All tasks should be pushed before this!!! michael@0: tasks.push(function cleanUp() { michael@0: SpecialPowers.removePermission("sms", document); michael@0: SpecialPowers.clearUserPref("dom.sms.enabled"); michael@0: SpecialPowers.clearUserPref("dom.sms.strict7BitEncoding"); michael@0: finish(); michael@0: }); michael@0: michael@0: tasks.run();