precis-js
Version:
A JavaScript implementation of RFC 7564 (The PRECIS Framework).
186 lines (141 loc) • 9.61 kB
text/coffeescript
{ucs2} = require 'punycode'
CodepointPropertyReader = require '../../src/unicode/CodepointPropertyReader'
DirectionalityValidator = require '../../src/unicode/DirectionalityValidator'
EmptyStringError = require '../../src/error/EmptyStringError'
InvalidCodepointError = require '../../src/error/InvalidCodepointError'
InvalidDirectionalityError = require '../../src/error/InvalidDirectionalityError'
NicknameProfile = require '../../src/profile/NicknameProfile'
Normalizer = require '../../src/unicode/Normalizer'
OpaqueStringProfile = require '../../src/profile/OpaqueStringProfile'
precis = require '../../src/enforce'
PrecisEnforcer = require '../../src/PrecisEnforcer'
PrecisPreparer = require '../../src/PrecisPreparer'
UsernameCaseMappedProfile = require '../../src/profile/UsernameCaseMappedProfile'
UsernameCasePreservedProfile = require '../../src/profile/UsernameCasePreservedProfile'
WidthMapper = require '../../src/unicode/WidthMapper'
describe 'enforce', ->
it 'produces the correct exports', ->
assert.instanceOf precis.enforcer, PrecisEnforcer
assert.instanceOf precis.preparer, PrecisPreparer
assert.instanceOf precis.propertyReader, CodepointPropertyReader
assert.strictEqual precis.PrecisPreparer, PrecisPreparer
assert.strictEqual precis.error.EmptyStringError, EmptyStringError
assert.strictEqual precis.error.InvalidCodepointError, InvalidCodepointError
assert.strictEqual precis.error.InvalidDirectionalityError, InvalidDirectionalityError
assert.strictEqual precis.profile.NicknameProfile, NicknameProfile
assert.strictEqual precis.profile.OpaqueStringProfile, OpaqueStringProfile
assert.strictEqual precis.profile.UsernameCaseMappedProfile, UsernameCaseMappedProfile
assert.strictEqual precis.profile.UsernameCasePreservedProfile, UsernameCasePreservedProfile
assert.strictEqual precis.unicode.CodepointPropertyReader, CodepointPropertyReader
assert.strictEqual precis.unicode.DirectionalityValidator, DirectionalityValidator
assert.strictEqual precis.unicode.Normalizer, Normalizer
assert.strictEqual precis.unicode.WidthMapper, WidthMapper
describe 'prepare()', ->
it 'throws an error if the string class is not implemented', ->
assert.throws (-> precis.prepare 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.deepEqual precis.prepare(, ' !'), [0x0020, 0x0021]
it 'rejects characters outside the FreeformClass string class', ->
assert.throws (=> precis.prepare , "\u0000"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u007F"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u00B7"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u0378"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u200C"), InvalidCodepointError
describe 'for IdentifierClass string class profiles', ->
beforeEach ->
= stringClass: precis.STRING_CLASS.IDENTIFIER, normalization: precis.NORMALIZATION.NONE
it 'allows characters in the IdentifierClass string class', ->
assert.deepEqual precis.prepare(, '!'), [0x0021]
it 'rejects characters outside the IdentifierClass string class', ->
assert.throws (=> precis.prepare , "\u0000"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u0020"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u007F"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u00B7"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u0378"), InvalidCodepointError
assert.throws (=> precis.prepare , "\u200C"), InvalidCodepointError
describe 'enforce()', ->
it 'throws an error if the string class is not implemented', ->
assert.throws (-> precis.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 precis.enforce(, ' !'), ' !'
it 'rejects characters outside the FreeformClass string class', ->
assert.throws (=> precis.enforce , '\u0000'), InvalidCodepointError
assert.throws (=> precis.enforce , '\u007F'), InvalidCodepointError
assert.throws (=> precis.enforce , '\u00B7'), InvalidCodepointError
assert.throws (=> precis.enforce , '\u0378'), InvalidCodepointError
assert.throws (=> precis.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
precis.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
assert.strictEqual passedEnforcer, precis.enforcer
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
precis.enforce , 'ab'
assert.deepEqual passedCodepoints, [97, 98]
assert.strictEqual passedEnforcer, precis.enforcer
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 precis.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 precis.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 = precis.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 = precis.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 = precis.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 = precis.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 => precis.enforce , 'ab'
assert.throws (=> precis.enforce , '0'), InvalidDirectionalityError