precis-js
Version:
A JavaScript implementation of RFC 7564 (The PRECIS Framework).
175 lines (129 loc) • 7.93 kB
text/coffeescript
fs = require 'fs'
UnicodeTrie = require 'unicode-trie'
unorm = require 'unorm'
{ucs2} = require 'punycode'
CodepointPropertyReader = require '../../src/unicode/CodepointPropertyReader'
DirectionalityValidator = require '../../src/unicode/DirectionalityValidator'
InvalidCodepointError = require '../../src/error/InvalidCodepointError'
InvalidDirectionalityError = require '../../src/error/InvalidDirectionalityError'
Normalizer = require '../../src/unicode/Normalizer'
precis = require '../../src/constants'
PrecisEnforcer = require '../../src/PrecisEnforcer'
PrecisPreparer = require '../../src/PrecisPreparer'
WidthMapper = require '../../src/unicode/WidthMapper'
describe 'PrecisEnforcer', ->
before ->
trieData = fs.readFileSync __dirname + '/../../data/properties.trie'
widthMappingData = JSON.parse fs.readFileSync __dirname + '/../../data/width-mapping.json'
trie = new UnicodeTrie trieData
= new CodepointPropertyReader trie
= new PrecisPreparer
= new WidthMapper widthMappingData
= new Normalizer unorm
= new DirectionalityValidator
beforeEach ->
= new PrecisEnforcer , , , ,
= stringClass: precis.STRING_CLASS.FREEFORM, normalization: precis.NORMALIZATION.NONE
describe 'enforce()', ->
it 'supports custom width mapping logic', ->
passedCodepoints = null
.mapWidth = (codepoints) -> passedCodepoints = codepoints.slice()
.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
it 'supports custom case mapping logic', ->
passedCodepoints = null
.mapCase = (codepoints) -> passedCodepoints = codepoints.slice()
.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
it 'supports custom normalization logic', ->
passedCodepoints = null
.normalize = (codepoints) -> passedCodepoints = codepoints.slice()
.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
it 'supports custom directionality validation', ->
passedCodepoints = null
.validateDirectionality = (codepoints) -> passedCodepoints = codepoints.slice()
.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
it 'throws an error if the string class is not implemented', ->
assert.throws (=> .enforce stringClass: 111, ''), 'PRECIS string class not implemented.'
describe 'for FreeformClass string class profiles', ->
beforeEach ->
= stringClass: precis.STRING_CLASS.FREEFORM, normalization: precis.NORMALIZATION.NONE
it 'allows characters in the FreeformClass string class', ->
assert.strictEqual .enforce(, ' !'), ' !'
it 'rejects characters outside the FreeformClass string class', ->
assert.throws (=> .enforce , '\u0000'), InvalidCodepointError
assert.throws (=> .enforce , '\u007F'), InvalidCodepointError
assert.throws (=> .enforce , '\u00B7'), InvalidCodepointError
assert.throws (=> .enforce , '\u0378'), InvalidCodepointError
assert.throws (=> .enforce , '\u200C'), InvalidCodepointError
describe 'for profiles with callbacks', ->
it 'calls the custom mapping callback', ->
passedCodepoints = null
passedEnforcer = null
=
stringClass: precis.STRING_CLASS.FREEFORM
normalization: precis.NORMALIZATION.NONE
map: (codepoints, enforcer) ->
passedCodepoints = codepoints.slice()
passedEnforcer = enforcer
.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
assert.strictEqual passedEnforcer,
it 'calls the custom validation callback', ->
passedCodepoints = null
passedEnforcer = null
=
stringClass: precis.STRING_CLASS.FREEFORM
normalization: precis.NORMALIZATION.NONE
validate: (codepoints, enforcer) ->
passedCodepoints = codepoints.slice()
passedEnforcer = enforcer
.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
assert.strictEqual passedEnforcer,
describe 'profile width mapping options', ->
it 'supports width mapping', ->
=
stringClass: precis.STRING_CLASS.FREEFORM
normalization: precis.NORMALIZATION.NONE
widthMapping: precis.WIDTH_MAPPING.EAW
assert.strictEqual .enforce(, '\uFF61'), '\u3002'
describe 'profile case mapping options', ->
beforeEach ->
= stringClass: precis.STRING_CLASS.FREEFORM, normalization: precis.NORMALIZATION.NONE
it 'supports lowercase case mapping', ->
.caseMapping = precis.CASE_MAPPING.LOWERCASE
assert.strictEqual .enforce(, 'Ab\u0370\u0371'), 'ab\u0371\u0371'
describe 'profile normalization options', ->
beforeEach ->
= stringClass: precis.STRING_CLASS.FREEFORM, normalization: precis.NORMALIZATION.NONE
it 'supports NFC normalization', ->
.normalization = precis.NORMALIZATION.C
actual = .enforce , '\u00F6\u0307o\u0308\u0307o\u0307\u0308\u2163'
expected = '\u00F6\u0307\u00F6\u0307\u022F\u0308\u2163'
assert.deepEqual ucs2.decode(actual), ucs2.decode(expected)
it 'supports NFD normalization', ->
.normalization = precis.NORMALIZATION.D
actual = .enforce , '\u00F6\u0307o\u0308\u0307o\u0307\u0308\u2163'
expected = 'o\u0308\u0307o\u0308\u0307o\u0307\u0308\u2163'
assert.deepEqual ucs2.decode(actual), ucs2.decode(expected)
it 'supports NFKC normalization', ->
.normalization = precis.NORMALIZATION.KC
actual = .enforce , '\u00F6\u0307o\u0308\u0307o\u0307\u0308\u2163'
expected = '\u00F6\u0307\u00F6\u0307\u022F\u0308IV'
assert.deepEqual ucs2.decode(actual), ucs2.decode(expected)
it 'supports NFKD normalization', ->
.normalization = precis.NORMALIZATION.KD
actual = .enforce , '\u00F6\u0307o\u0308\u0307o\u0307\u0308\u2163'
expected = 'o\u0308\u0307o\u0308\u0307o\u0307\u0308IV'
assert.deepEqual ucs2.decode(actual), ucs2.decode(expected)
describe 'profile directionality options', ->
it 'supports directionality validation', ->
=
stringClass: precis.STRING_CLASS.FREEFORM
normalization: precis.NORMALIZATION.NONE
directionality: precis.DIRECTIONALITY.BIDI
assert.doesNotThrow => .enforce , 'ab'
assert.throws (=> .enforce , '0'), InvalidDirectionalityError