From e1be2c8f8ba1b1bd5b65b42128cc7b22fd053ac2 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 23 Oct 2018 14:41:15 +0200 Subject: [PATCH] Intl.Segmenter: Add some tests for the constructor. --- .../constructor/locales-invalid.js | 17 ++++++ .../constructor/constructor/locales-valid.js | 34 +++++++++++ .../constructor/newtarget-undefined.js | 24 ++++++++ .../options-granularity-invalid.js | 37 ++++++++++++ .../constructor/options-granularity-valid.js | 28 ++++++++++ .../constructor/options-invalid.js | 15 +++++ .../options-lineBreakStyle-invalid.js | 35 ++++++++++++ .../options-lineBreakStyle-valid.js | 28 ++++++++++ .../options-localeMatcher-invalid.js | 30 ++++++++++ .../constructor/constructor/options-order.js | 56 +++++++++++++++++++ .../constructor/options-throwing-getters.js | 26 +++++++++ .../constructor/options-toobject-prototype.js | 38 +++++++++++++ .../constructor/options-toobject.js | 29 ++++++++++ .../constructor/options-undefined.js | 48 ++++++++++++++++ .../constructor/constructor/subclassing.js | 53 ++++++++++++++++++ 15 files changed, 498 insertions(+) create mode 100644 test/intl402/Segmenter/constructor/constructor/locales-invalid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/locales-valid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/newtarget-undefined.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-granularity-invalid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-granularity-valid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-invalid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-invalid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-valid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-localeMatcher-invalid.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-order.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-throwing-getters.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-toobject-prototype.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-toobject.js create mode 100644 test/intl402/Segmenter/constructor/constructor/options-undefined.js create mode 100644 test/intl402/Segmenter/constructor/constructor/subclassing.js diff --git a/test/intl402/Segmenter/constructor/constructor/locales-invalid.js b/test/intl402/Segmenter/constructor/constructor/locales-invalid.js new file mode 100644 index 0000000000..ece59c79e5 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/locales-invalid.js @@ -0,0 +1,17 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks error cases for the locales argument to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 3. Let _requestedLocales_ be ? CanonicalizeLocaleList(_locales_). +includes: [testIntl.js] +features: [Intl.Segmenter] +---*/ + +for (const [locales, expectedError] of getInvalidLocaleArguments()) { + assert.throws(expectedError, function() { new Intl.Segmenter(locales) }) +} diff --git a/test/intl402/Segmenter/constructor/constructor/locales-valid.js b/test/intl402/Segmenter/constructor/constructor/locales-valid.js new file mode 100644 index 0000000000..08318192cb --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/locales-valid.js @@ -0,0 +1,34 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks various cases for the locales argument to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 3. Let _requestedLocales_ be ? CanonicalizeLocaleList(_locales_). +includes: [testIntl.js] +features: [Intl.Segmenter] +---*/ + +const defaultLocale = new Intl.Segmenter().resolvedOptions().locale; + +const tests = [ + [undefined, defaultLocale, "undefined"], + ["EN", "en", "Single value"], + [[], defaultLocale, "Empty array"], + [["en-GB-oed"], "en-GB", "Grandfathered"], + [["x-private"], defaultLocale, "Private", ["lookup"]], + [["en", "EN"], "en", "Duplicate value (canonical first)"], + [["EN", "en"], "en", "Duplicate value (canonical last)"], + [{ 0: "DE", length: 0 }, defaultLocale, "Object with zero length"], + [{ 0: "DE", length: 1 }, "de", "Object with length"], +]; + +for (const [locales, expected, name, matchers = ["best fit", "lookup"]] of tests) { + for (const localeMatcher of matchers) { + const segmenter = new Intl.Segmenter(locales, { localeMatcher }); + assert.sameValue(segmenter.resolvedOptions().locale, expected, name); + } +} diff --git a/test/intl402/Segmenter/constructor/constructor/newtarget-undefined.js b/test/intl402/Segmenter/constructor/constructor/newtarget-undefined.js new file mode 100644 index 0000000000..2482634884 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/newtarget-undefined.js @@ -0,0 +1,24 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Verifies the NewTarget check for Intl.Segmenter. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 1. If NewTarget is undefined, throw a TypeError exception. +features: [Intl.Segmenter] +---*/ + +assert.throws(TypeError, function() { + Intl.Segmenter(); +}); + +assert.throws(TypeError, function() { + Intl.Segmenter("en"); +}); + +assert.throws(TypeError, function() { + Intl.Segmenter("not-valid-tag"); +}); diff --git a/test/intl402/Segmenter/constructor/constructor/options-granularity-invalid.js b/test/intl402/Segmenter/constructor/constructor/options-granularity-invalid.js new file mode 100644 index 0000000000..36bd0c80c9 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-granularity-invalid.js @@ -0,0 +1,37 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of invalid value for the style option to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 13. Let granularity be ? GetOption(options, "granularity", "string", « "grapheme", "word", "sentence", "line" », "grapheme"). + 14. Set segmenter.[[SegmenterGranularity]] to granularity. +features: [Intl.Segmenter] +---*/ + +const invalidOptions = [ + null, + 1, + "", + "Grapheme", + "GRAPHEME", + "grapheme\0", + "Word", + "WORD", + "word\0", + "Sentence", + "SENTENCE", + "sentence\0", + "Line", + "LINE", + "line\0", +]; + +for (const granularity of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.Segmenter([], { granularity }); + }, `${granularity} is an invalid style option value`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-granularity-valid.js b/test/intl402/Segmenter/constructor/constructor/options-granularity-valid.js new file mode 100644 index 0000000000..c602f2bf47 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-granularity-valid.js @@ -0,0 +1,28 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of valid values for the style option to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 9. Let lineBreakStyle be ? GetOption(options, "lineBreakStyle", "string", « "strict", "normal", "loose" », "normal"). + 15. If granularity is "line", + a. Set segmenter.[[SegmenterLineBreakStyle]] to r.[[lb]]. +features: [Intl.Segmenter] +---*/ + +const validOptions = [ + [undefined, "normal"], + ["strict", "strict"], + ["normal", "normal"], + ["loose", "loose"], + [{ toString() { return "loose"; } }, "loose"], +]; + +for (const [lineBreakStyle, expected] of validOptions) { + const segmenter = new Intl.Segmenter([], { granularity: "line", lineBreakStyle }); + const resolvedOptions = segmenter.resolvedOptions(); + assert.sameValue(resolvedOptions.lineBreakStyle, expected); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-invalid.js b/test/intl402/Segmenter/constructor/constructor/options-invalid.js new file mode 100644 index 0000000000..62c9b6dc29 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-invalid.js @@ -0,0 +1,15 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of a null options argument to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 5. Else + a. Let options be ? ToObject(options). +features: [Intl.Segmenter] +---*/ + +assert.throws(TypeError, function() { new Intl.Segmenter([], null) }) diff --git a/test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-invalid.js b/test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-invalid.js new file mode 100644 index 0000000000..03cbbfbaba --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-invalid.js @@ -0,0 +1,35 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of invalid value for the style option to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 9. Let lineBreakStyle be ? GetOption(options, "lineBreakStyle", "string", « "strict", "normal", "loose" », "normal"). + 15. If granularity is "line", + a. Set segmenter.[[SegmenterLineBreakStyle]] to r.[[lb]]. +features: [Intl.Segmenter] +---*/ + +const invalidOptions = [ + null, + 1, + "", + "Strict", + "STRICT", + "strict\0", + "Normal", + "NORMAL", + "normal\0", + "Loose", + "LOOSE", + "loose\0", +]; + +for (const lineBreakStyle of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.Segmenter([], { lineBreakStyle }); + }, `${lineBreakStyle} is an invalid style option value`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-valid.js b/test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-valid.js new file mode 100644 index 0000000000..c602f2bf47 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-lineBreakStyle-valid.js @@ -0,0 +1,28 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of valid values for the style option to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 9. Let lineBreakStyle be ? GetOption(options, "lineBreakStyle", "string", « "strict", "normal", "loose" », "normal"). + 15. If granularity is "line", + a. Set segmenter.[[SegmenterLineBreakStyle]] to r.[[lb]]. +features: [Intl.Segmenter] +---*/ + +const validOptions = [ + [undefined, "normal"], + ["strict", "strict"], + ["normal", "normal"], + ["loose", "loose"], + [{ toString() { return "loose"; } }, "loose"], +]; + +for (const [lineBreakStyle, expected] of validOptions) { + const segmenter = new Intl.Segmenter([], { granularity: "line", lineBreakStyle }); + const resolvedOptions = segmenter.resolvedOptions(); + assert.sameValue(resolvedOptions.lineBreakStyle, expected); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-localeMatcher-invalid.js b/test/intl402/Segmenter/constructor/constructor/options-localeMatcher-invalid.js new file mode 100644 index 0000000000..a0d367f6f8 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-localeMatcher-invalid.js @@ -0,0 +1,30 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of invalid value for the localeMatcher option to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 7. Let matcher be ? GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit"). +features: [Intl.Segmenter] +---*/ + +const invalidOptions = [ + null, + 1, + "", + "Lookup", + "LOOKUP", + "lookup\0", + "Best fit", + "BEST FIT", + "best\u00a0fit", +]; + +for (const localeMatcher of invalidOptions) { + assert.throws(RangeError, function() { + new Intl.Segmenter([], { localeMatcher }); + }, `${localeMatcher} is an invalid localeMatcher option value`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-order.js b/test/intl402/Segmenter/constructor/constructor/options-order.js new file mode 100644 index 0000000000..75cd81b737 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-order.js @@ -0,0 +1,56 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks the order of operations on the options argument to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 7. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). + 9. Let lineBreakStyle be ? GetOption(options, "lineBreakStyle", "string", « "strict", "normal", "loose" », "normal"). + 13. Let granularity be ? GetOption(options, "granularity", "string", « "grapheme", "word", "sentence", "line" », "grapheme"). +includes: [compareArray.js] +features: [Intl.Segmenter] +---*/ + +const callOrder = []; + +new Intl.Segmenter([], { + get localeMatcher() { + callOrder.push("localeMatcher"); + return { + toString() { + callOrder.push("localeMatcher toString"); + return "best fit"; + } + }; + }, + get lineBreakStyle() { + callOrder.push("lineBreakStyle"); + return { + toString() { + callOrder.push("lineBreakStyle toString"); + return "strict"; + } + }; + }, + get granularity() { + callOrder.push("granularity"); + return { + toString() { + callOrder.push("granularity toString"); + return "word"; + } + }; + }, +}); + +assert.compareArray(callOrder, [ + "localeMatcher", + "localeMatcher toString", + "lineBreakStyle", + "lineBreakStyle toString", + "granularity", + "granularity toString", +]); diff --git a/test/intl402/Segmenter/constructor/constructor/options-throwing-getters.js b/test/intl402/Segmenter/constructor/constructor/options-throwing-getters.js new file mode 100644 index 0000000000..bb34252ba1 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-throwing-getters.js @@ -0,0 +1,26 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks the propagation of exceptions from the options for the Segmenter constructor. +features: [Intl.Segmenter] +---*/ + +function CustomError() {} + +const options = [ + "localeMatcher", + "lineBreakStyle", + "granularity", +]; + +for (const option of options) { + assert.throws(CustomError, () => { + new Intl.Segmenter("en", { + get [option]() { + throw new CustomError(); + } + }); + }, `Exception from ${option} getter should be propagated`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-toobject-prototype.js b/test/intl402/Segmenter/constructor/constructor/options-toobject-prototype.js new file mode 100644 index 0000000000..9b1ad79bb5 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-toobject-prototype.js @@ -0,0 +1,38 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of non-object option arguments to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 5. Else + a. Let options be ? ToObject(options). +features: [Intl.Segmenter] +---*/ + +Object.defineProperties(Object.prototype, { + "lineBreakStyle": { + value: "loose", + }, + "granularity": { + value: "line", + }, +}) + +const optionsArguments = [ + true, + "test", + 7, + Symbol(), +]; + +for (const options of optionsArguments) { + const segmenter = new Intl.Segmenter([], options); + const resolvedOptions = segmenter.resolvedOptions(); + assert.sameValue(resolvedOptions.lineBreakStyle, "loose", + `options argument ${String(options)} should yield the correct value for "lineBreakStyle"`); + assert.sameValue(resolvedOptions.granularity, "line", + `options argument ${String(options)} should yield the correct value for "granularity"`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-toobject.js b/test/intl402/Segmenter/constructor/constructor/options-toobject.js new file mode 100644 index 0000000000..d0581d40ae --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-toobject.js @@ -0,0 +1,29 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of non-object option arguments to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 5. Else + a. Let options be ? ToObject(options). +features: [Intl.Segmenter] +---*/ + +const optionsArguments = [ + true, + "test", + 7, + Symbol(), +]; + +for (const options of optionsArguments) { + const segmenter = new Intl.Segmenter([], options); + const resolvedOptions = segmenter.resolvedOptions(); + assert.sameValue(resolvedOptions.granularity, "grapheme", + `options argument ${String(options)} should yield the correct value for "granularity"`); + assert.sameValue(resolvedOptions.lineBreakStyle, undefined, + `options argument ${String(options)} should yield the correct value for "lineBreakStyle"`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/options-undefined.js b/test/intl402/Segmenter/constructor/constructor/options-undefined.js new file mode 100644 index 0000000000..c91f211788 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/options-undefined.js @@ -0,0 +1,48 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks handling of non-object option arguments to the Segmenter constructor. +info: | + Intl.Segmenter ([ locales [ , options ]]) + + 4. If options is undefined, then + a. Let options be ObjectCreate(null). +features: [Intl.Segmenter] +---*/ + +Object.defineProperties(Object.prototype, { + "localeMatcher": { + "get": function() { + throw new Error("Should not call getter on Object.prototype: localeMatcher"); + }, + }, + + "lineBreakStyle": { + "get": function() { + throw new Error("Should not call getter on Object.prototype: lineBreakStyle"); + }, + }, + + "granularity": { + "get": function() { + throw new Error("Should not call getter on Object.prototype: granularity"); + }, + }, +}); + +const optionsArguments = [ + [], + [[]], + [[], undefined], +]; + +for (const args of optionsArguments) { + const segmenter = new Intl.Segmenter(...args); + const resolvedOptions = segmenter.resolvedOptions(); + assert.sameValue(resolvedOptions.granularity, "grapheme", + `Calling with ${args.length} empty arguments should yield the correct value for "granularity"`); + assert.sameValue(Object.hasOwnProperty(resolvedOptions, "lineBreakStyle"), false, + `Calling with ${args.length} empty arguments should yield the correct value for "lineBreakStyle"`); +} diff --git a/test/intl402/Segmenter/constructor/constructor/subclassing.js b/test/intl402/Segmenter/constructor/constructor/subclassing.js new file mode 100644 index 0000000000..09a02467d2 --- /dev/null +++ b/test/intl402/Segmenter/constructor/constructor/subclassing.js @@ -0,0 +1,53 @@ +// Copyright 2018 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-Intl.Segmenter +description: Checks that Segmenter can be subclassed. +info: | + Intl.Segmenter ( [ locales [ , options ] ] ) + + 2. Let segmenter be ? OrdinaryCreateFromConstructor(NewTarget, "%SegmenterPrototype%", « [[InitializedSegmenter]] »). +includes: [compareArray.js] +features: [Intl.Segmenter] +---*/ + +function segments(iterator) { + return [...iterator].map(result => result.segment); +} + +class CustomSegmenter extends Intl.Segmenter { + constructor(locales, options) { + super(locales, options); + this.isCustom = true; + } +} + +const locale = "de"; +const value = "Hello"; + +const real_segmenter = new Intl.Segmenter(locale); +assert.sameValue(real_segmenter.isCustom, undefined, "Custom property"); + +const custom_segmenter = new CustomSegmenter(locale); +assert.sameValue(custom_segmenter.isCustom, true, "Custom property"); + +assert.compareArray(segments(custom_segmenter.segment(value)), + segments(real_segmenter.segment(value)), + "Direct call"); + +assert.compareArray(segments(Intl.Segmenter.prototype.segment.call(custom_segmenter, value)), + segments(Intl.Segmenter.prototype.segment.call(real_segmenter, value)), + "Indirect call"); + +assert.sameValue(Object.getPrototypeOf(custom_segmenter), CustomSegmenter.prototype, "Prototype"); +assert.sameValue(Object.getPrototypeOf(CustomSegmenter), Intl.Segmenter, + "Object.getPrototypeOf(CustomSegmenter) returns Intl.Segmenter"); +assert.sameValue(Object.getPrototypeOf(CustomSegmenter.prototype), Intl.Segmenter.prototype, + "Object.getPrototypeOf(CustomSegmenter.prototype) returns Intl.Segmenter.prototype"); +assert.sameValue(custom_segmenter instanceof Intl.Segmenter, true, + "The result of `custom_segmenter instanceof Intl.Segmenter` is true"); + +assert.throws(TypeError, function() { + CustomSegmenter(); +});