First commit
This commit is contained in:
422
node_modules/@ldapjs/change/index.test.js
generated
vendored
Normal file
422
node_modules/@ldapjs/change/index.test.js
generated
vendored
Normal file
@ -0,0 +1,422 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { BerReader } = require('@ldapjs/asn1')
|
||||
const Attribute = require('@ldapjs/attribute')
|
||||
const Change = require('./index')
|
||||
|
||||
tap.test('constructor', t => {
|
||||
t.test('throws for bad operation', async t => {
|
||||
t.throws(
|
||||
() => new Change({ operation: 'bad' }),
|
||||
Error('invalid operation type: bad')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('throws for bad modification', async t => {
|
||||
t.throws(
|
||||
() => new Change({ modification: 'bad' }),
|
||||
Error('modification must be an Attribute')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('creates an instance', async t => {
|
||||
const change = new Change({
|
||||
modification: new Attribute()
|
||||
})
|
||||
t.equal(change.operation, 'add')
|
||||
t.type(change.modification, Attribute)
|
||||
t.equal(Object.prototype.toString.call(change), '[object LdapChange]')
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('modification', t => {
|
||||
t.test('gets', async t => {
|
||||
const attr = new Attribute()
|
||||
const change = new Change({ modification: attr })
|
||||
t.equal(change.modification, attr)
|
||||
})
|
||||
|
||||
t.test('sets', async t => {
|
||||
const attr1 = new Attribute()
|
||||
const attr2 = new Attribute()
|
||||
const change = new Change({ modification: attr1 })
|
||||
t.equal(change.modification, attr1)
|
||||
change.modification = attr2
|
||||
t.equal(change.modification, attr2)
|
||||
t.not(attr1, attr2)
|
||||
})
|
||||
|
||||
t.test('throws if value is not attribute-like', async t => {
|
||||
const change = new Change({ modification: new Attribute() })
|
||||
t.throws(
|
||||
() => { change.modification = { foo: 'foo' } },
|
||||
Error('modification must be an Attribute')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('converts attribute-like to Attribute', async t => {
|
||||
const change = new Change({
|
||||
modification: {
|
||||
type: 'dn=foo,dc=example,dc=com',
|
||||
values: []
|
||||
}
|
||||
})
|
||||
t.equal(
|
||||
Object.prototype.toString.call(change.modification),
|
||||
'[object LdapAttribute]'
|
||||
)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('.operation', t => {
|
||||
const attr = new Attribute()
|
||||
const change = new Change({ modification: attr })
|
||||
|
||||
t.test('throws for unrecognized operation', async t => {
|
||||
t.throws(
|
||||
() => { change.operation = 'bad' },
|
||||
Error('invalid operation type: bad')
|
||||
)
|
||||
t.throws(
|
||||
() => { change.operation = 0xff },
|
||||
Error('invalid operation type: 0xff')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('sets and gets', async t => {
|
||||
change.operation = 0
|
||||
t.equal(change.operation, 'add')
|
||||
change.operation = 'add'
|
||||
t.equal(change.operation, 'add')
|
||||
|
||||
change.operation = 1
|
||||
t.equal(change.operation, 'delete')
|
||||
change.operation = 'delete'
|
||||
t.equal(change.operation, 'delete')
|
||||
|
||||
change.operation = 2
|
||||
t.equal(change.operation, 'replace')
|
||||
change.operation = 'replace'
|
||||
t.equal(change.operation, 'replace')
|
||||
|
||||
change.operation = 'Replace'
|
||||
t.equal(change.operation, 'replace')
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('.pojo', t => {
|
||||
t.test('returns a plain object', async t => {
|
||||
const change = new Change({
|
||||
modification: new Attribute()
|
||||
})
|
||||
const expected = {
|
||||
operation: 'add',
|
||||
modification: {
|
||||
type: '',
|
||||
values: []
|
||||
}
|
||||
}
|
||||
t.strictSame(change.pojo, expected)
|
||||
t.strictSame(change.toJSON(), expected)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('toBer', t => {
|
||||
t.test('serializes to ber', async t => {
|
||||
const expected = Buffer.from([
|
||||
0x30, 0x15, // sequence, 21 bytes
|
||||
0x0a, 0x01, 0x00, // enumerated value 0
|
||||
0x30, 0x10, // sequence, 16 bytes
|
||||
0x04, 0x02, // string, 2 bytes
|
||||
0x63, 0x6e, // 'cn'
|
||||
0x31, 0x0a, // sequence of strings, 10 bytes
|
||||
0x04, 0x03, // string, 3 bytes
|
||||
0x66, 0x6f, 0x6f, // 'foo'
|
||||
0x04, 0x03, // string 3 bytes
|
||||
0x62, 0x61, 0x72
|
||||
])
|
||||
const change = new Change({
|
||||
modification: {
|
||||
type: 'cn',
|
||||
values: ['foo', 'bar']
|
||||
}
|
||||
})
|
||||
const ber = change.toBer()
|
||||
t.equal(expected.compare(ber.buffer), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#apply', t => {
|
||||
t.test('throws if change is not a Change', async t => {
|
||||
t.throws(
|
||||
() => Change.apply({}, {}),
|
||||
Error('change must be an instance of Change')
|
||||
)
|
||||
})
|
||||
|
||||
t.test('applies to a target with no type', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = {}
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['new']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('applies to a target with a scalar type', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = { cn: 'old' }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('applies to a target with an array type', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = { cn: ['old'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('add operation adds only new values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new', 'foo']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = { cn: ['old', 'new'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new', 'foo']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('delete operation removes property', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'delete',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['new'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {})
|
||||
})
|
||||
|
||||
t.test('delete operation removes values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['remove_me']
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'delete',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['remove_me', 'keep_me'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['keep_me']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('replace removes empty set', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: []
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'replace',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['old'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {})
|
||||
})
|
||||
|
||||
t.test('replace removes values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new_set']
|
||||
})
|
||||
const change = new Change({
|
||||
operation: 'replace',
|
||||
modification: attr
|
||||
})
|
||||
const target = { cn: ['old_set'] }
|
||||
Change.apply(change, target)
|
||||
t.strictSame(target, {
|
||||
cn: ['new_set']
|
||||
})
|
||||
})
|
||||
|
||||
t.test('scalar option works for new single values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = {}
|
||||
Change.apply(change, target, true)
|
||||
t.strictSame(target, {
|
||||
cn: 'new'
|
||||
})
|
||||
})
|
||||
|
||||
t.test('scalar option is ignored for multiple values', async t => {
|
||||
const attr = new Attribute({
|
||||
type: 'cn',
|
||||
values: ['new']
|
||||
})
|
||||
const change = new Change({ modification: attr })
|
||||
const target = {
|
||||
cn: ['old']
|
||||
}
|
||||
Change.apply(change, target, true)
|
||||
t.strictSame(target, {
|
||||
cn: ['old', 'new']
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#isChange', t => {
|
||||
t.test('true for instance', async t => {
|
||||
const change = new Change({ modification: new Attribute() })
|
||||
t.equal(Change.isChange(change), true)
|
||||
})
|
||||
|
||||
t.test('false for non-object', async t => {
|
||||
t.equal(Change.isChange([]), false)
|
||||
})
|
||||
|
||||
t.test('true for shape match', async t => {
|
||||
const change = {
|
||||
operation: 'add',
|
||||
modification: {
|
||||
type: '',
|
||||
values: []
|
||||
}
|
||||
}
|
||||
t.equal(Change.isChange(change), true)
|
||||
|
||||
change.operation = 0
|
||||
change.modification = new Attribute()
|
||||
t.equal(Change.isChange(change), true)
|
||||
})
|
||||
|
||||
t.test('false for shape mis-match', async t => {
|
||||
const change = {
|
||||
operation: 'add',
|
||||
mod: {
|
||||
type: '',
|
||||
values: []
|
||||
}
|
||||
}
|
||||
t.equal(Change.isChange(change), false)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#compare', t => {
|
||||
t.test('throws if params are not changes', async t => {
|
||||
const change = new Change({ modification: new Attribute() })
|
||||
const expected = Error('can only compare Change instances')
|
||||
t.throws(
|
||||
() => Change.compare({}, change),
|
||||
expected
|
||||
)
|
||||
t.throws(
|
||||
() => Change.compare(change, {}),
|
||||
expected
|
||||
)
|
||||
})
|
||||
|
||||
t.test('orders add first', async t => {
|
||||
const change1 = new Change({ modification: new Attribute() })
|
||||
const change2 = new Change({
|
||||
operation: 'delete',
|
||||
modification: new Attribute()
|
||||
})
|
||||
|
||||
t.equal(Change.compare(change1, change2), -1)
|
||||
|
||||
change2.operation = 'replace'
|
||||
t.equal(Change.compare(change1, change2), -1)
|
||||
})
|
||||
|
||||
t.test('orders delete above add', async t => {
|
||||
const change1 = new Change({ modification: new Attribute() })
|
||||
const change2 = new Change({
|
||||
operation: 'delete',
|
||||
modification: new Attribute()
|
||||
})
|
||||
|
||||
t.equal(Change.compare(change2, change1), 1)
|
||||
})
|
||||
|
||||
t.test('orders by attribute for same operation', async t => {
|
||||
const change1 = new Change({ modification: new Attribute() })
|
||||
const change2 = new Change({ modification: new Attribute() })
|
||||
t.equal(Change.compare(change1, change2), 0)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test('#fromBer', t => {
|
||||
t.test('creates instance', async t => {
|
||||
const bytes = [
|
||||
0x30, 0x15, // sequence, 21 bytes
|
||||
0x0a, 0x01, 0x00, // enumerated value 0
|
||||
0x30, 0x10, // sequence, 16 bytes
|
||||
0x04, 0x02, // string, 2 bytes
|
||||
0x63, 0x6e, // 'cn'
|
||||
0x31, 0x0a, // sequence of strings, 10 bytes
|
||||
0x04, 0x03, // string, 3 bytes
|
||||
0x66, 0x6f, 0x6f, // 'foo'
|
||||
0x04, 0x03, // string 3 bytes
|
||||
0x62, 0x61, 0x72
|
||||
]
|
||||
const reader = new BerReader(Buffer.from(bytes))
|
||||
const change = Change.fromBer(reader)
|
||||
t.strictSame(change.pojo, {
|
||||
operation: 'add',
|
||||
modification: {
|
||||
type: 'cn',
|
||||
values: ['foo', 'bar']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
Reference in New Issue
Block a user