Skip to content

Commit

Permalink
Fix array().unique() error paths and add dupe
Browse files Browse the repository at this point in the history
Fixes #1072 and #1073.
  • Loading branch information
Marsup committed Dec 23, 2016
1 parent 045b99c commit 954db98
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 11 deletions.
46 changes: 35 additions & 11 deletions lib/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,9 @@ internals.Array = class extends Any {
number: {},
undefined: {},
boolean: {},
object: [],
function: [],
custom: []
object: new Map(),
function: new Map(),
custom: new Map()
};

for (let i = 0; i < value.length; ++i) {
Expand All @@ -456,21 +456,45 @@ internals.Array = class extends Any {
// All available types are supported, so it's not possible to reach 100% coverage without ignoring this line.
// I still want to keep the test for future js versions with new types (eg. Symbol).
if (/* $lab:coverage:off$ */ records /* $lab:coverage:on$ */) {
if (Array.isArray(records)) {
for (let j = 0; j < records.length; ++j) {
if (comparator(records[j], item)) {
return this.createError('array.unique', { pos: i, value: item }, state, options);
if (records instanceof Map) {
const entries = records.entries();
let current;
while (!(current = entries.next()).done) {
if (comparator(current.value[0], item)) {
const localState = {
key: state.key,
path: (state.path ? state.path + '.' : '') + i,
parent: state.parent,
reference: state.reference
};
return this.createError('array.unique', {
pos: i,
value: item,
dupePos: current.value[1],
dupeValue: current.value[0]
}, localState, options);
}
}

records.push(item);
records.set(item, i);
}
else {
if (records[item]) {
return this.createError('array.unique', { pos: i, value: item }, state, options);
if (records[item] !== undefined) {
const localState = {
key: state.key,
path: (state.path ? state.path + '.' : '') + i,
parent: state.parent,
reference: state.reference
};
return this.createError('array.unique', {
pos: i,
value: item,
dupePos: records[item],
dupeValue: item
}, localState, options);
}

records[item] = true;
records[item] = i;
}
}
}
Expand Down
73 changes: 73 additions & 0 deletions test/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,79 @@ describe('array', () => {
], done);
});

it('errors with the correct details', (done) => {

let error = Joi.array().items(Joi.number()).unique().validate([1, 2, 3, 1, 4]).error;
expect(error).to.be.an.error('"value" position 3 contains a duplicate value');
expect(error.details).to.equal([
{
context: {
key: 'value',
pos: 3,
value: 1,
dupePos: 0,
dupeValue: 1
},
message: '"value" position 3 contains a duplicate value',
path: '3',
type: 'array.unique'
}
]);

error = Joi.array().items(Joi.number()).unique((a, b) => a === b).validate([1, 2, 3, 1, 4]).error;
expect(error).to.be.an.error('"value" position 3 contains a duplicate value');
expect(error.details).to.equal([
{
context: {
key: 'value',
pos: 3,
value: 1,
dupePos: 0,
dupeValue: 1
},
message: '"value" position 3 contains a duplicate value',
path: '3',
type: 'array.unique'
}
]);

error = Joi.object({ a: Joi.array().items(Joi.number()).unique() }).validate({ a: [1, 2, 3, 1, 4] }).error;
expect(error).to.be.an.error('child "a" fails because ["a" position 3 contains a duplicate value]');
expect(error.details).to.equal([
{
context: {
key: 'a',
pos: 3,
value: 1,
dupePos: 0,
dupeValue: 1
},
message: '"a" position 3 contains a duplicate value',
path: 'a.3',
type: 'array.unique'
}
]);

error = Joi.object({ a: Joi.array().items(Joi.number()).unique((a, b) => a === b) }).validate({ a: [1, 2, 3, 1, 4] }).error;
expect(error).to.be.an.error('child "a" fails because ["a" position 3 contains a duplicate value]');
expect(error.details).to.equal([
{
context: {
key: 'a',
pos: 3,
value: 1,
dupePos: 0,
dupeValue: 1
},
message: '"a" position 3 contains a duplicate value',
path: 'a.3',
type: 'array.unique'
}
]);

done();
});

it('ignores duplicates if they are of different types', (done) => {

const schema = Joi.array().unique();
Expand Down

0 comments on commit 954db98

Please sign in to comment.