Add support for array input for all constraints in HangingProtocolService validator (#3322)

Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
This commit is contained in:
Sofien-Sellami 2023-06-29 15:56:40 +01:00 committed by GitHub
parent aeb61f40da
commit e653961858
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 977 additions and 174 deletions

View File

@ -1,69 +1,240 @@
import validate from 'validate.js';
/**
* check if the value is strictly equal to options
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = 'abc' (Fail)
* = ['abc'] (Fail)
* = ['abc', 'def', 'GHI'] (Valid)
* = ['abc', 'GHI', 'def'] (Fail)
* = ['abc', 'def'] (Fail)
*
* value = 'Attenuation Corrected'
* testValue = 'Attenuation Corrected' (Valid)
* testValue = 'Attenuation' (Fail)
*
* value = ['Attenuation Corrected']
* testValue = ['Attenuation Corrected'] (Valid)
* = 'Attenuation Corrected' (Valid)
* = 'Attenuation' (Fail)
*
* */
validate.validators.equals = function(value, options, key) {
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
validate.validators.equals = function(value, options, key, attributes) {
const testValue = options?.value ?? options;
if (value !== testValue) {
return key + 'must equal ' + testValue;
// If options is an array, then we need to validate each element in the array
if (Array.isArray(testValue)) {
// If the array has only one element, then we need to compare the value to that element
if (testValue.length !== dicomArrayValue.length) {
return `${key} must be an array of length ${testValue.length}`;
} else {
for (let i = 0; i < testValue.length; i++) {
if (testValue[i] !== dicomArrayValue[i]) {
return `${key} ${testValue[i]} must equal ${dicomArrayValue[i]}`;
}
}
}
} else if (testValue !== dicomArrayValue[0]) {
return `${key} must equal ${testValue}`;
}
};
/**
* check if the value is not equal to options
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = 'abc' (Valid)
* = ['abc'] (Valid)
* = ['abc', 'def', 'GHI'] (Fail)
* = ['abc', 'GHI', 'def'] (Valid)
* = ['abc', 'def'] (Valid)
*
* value = 'Attenuation Corrected'
* = 'Attenuation Corrected' (Fail)
* = 'Attenuation' (Valid)
*
* value = ['Attenuation Corrected']
* testValue = ['Attenuation Corrected'] (Fail)
* = 'Attenuation Corrected' (Fail)
* = 'Attenuation' (Fail)
* */
validate.validators.doesNotEqual = function(value, options, key) {
const testValue = options?.value ?? options;
if (value === testValue) {
return key + 'cannot equal ' + testValue;
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
if (Array.isArray(testValue)) {
if (testValue.length === dicomArrayValue.length) {
let score = 0;
testValue.forEach((x, i) => {
if (x === dicomArrayValue[i]) {
score++;
}
});
if (score === testValue.length) {
return `${key} must not equal to ${testValue}`;
}
}
} else if (testValue === dicomArrayValue[0]) {
console.debug(dicomArrayValue, testValue);
return `${key} must not equal to ${testValue}`;
}
};
/**
* Check if a value includes one or more specified options.
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = abc (Fail)
* = dog (Fail)
* = [abc] (Valid)
* = [att, abc] (Valid)
* = ['abc', 'def', 'dog'] (Valid)
* = ['cat', 'dog'] (Fail)
*
* value = ['Attenuation Corrected']
* testValue = 'Attenuation Corrected' (Fail)
* = ['Attenuation Corrected', 'Corrected'] (Valid)
* = ['Attenuation', 'Corrected'] (Fail)
*
* value = 'Attenuation Corrected'
* testValue = ['Attenuation Corrected', 'Corrected'] (Valid)
* = ['Attenuation', 'Corrected'] (Fail)
* */
validate.validators.includes = function(value, options, key) {
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
if (Array.isArray(testValue)) {
const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
if (includedValues.length === 0) {
return `${key} must include at least one of the following values: ${testValue.join(
', '
)}`;
}
} else return `${key} ${testValue} must be an array`;
// else if (!value.includes(testValue)) {
// return `${key} ${value} must include ${testValue}`;
// }
};
/**
* Check if a value does not include one or more specified options.
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = ['Corr'] (Valid)
* = 'abc' (Fail)
* = ['abc'] (Fail)
* = [att, cor] (Valid)
* = ['abc', 'def', 'dog'] (Fail)
*
* value = ['Attenuation Corrected']
* testValue = 'Attenuation Corrected' (Fail)
* = ['Attenuation Corrected', 'Corrected'] (Fail)
* = ['Attenuation', 'Corrected'] (Valid)
*
* value = 'Attenuation Corrected'
* testValue = ['Attenuation Corrected', 'Corrected'] (Fail)
* = ['Attenuation', 'Corrected'] (Valid)
* */
validate.validators.doesNotInclude = function(value, options, key) {
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
// if (!Array.isArray(value) || value.length === 1) {
// return `${key} is not allowed as a single value`;
// }
if (Array.isArray(testValue)) {
const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
if (includedValues.length > 0) {
return `${key} must not include the following value: ${includedValues}`;
}
} else return `${key} ${testValue} must be an array`;
};
// Ignore case contains.
// options testValue MUST be in lower case already, otherwise it won't match
validate.validators.containsI = function (value, options, key) {
const testValue = options?.value ?? options;
/**
* @example
* value = 'Attenuation Corrected'
* testValue = Corr (Valid)
* = corr (Valid)
* = [att, cor] (Valid)
* = [Att, Wall] (Valid)
* = [cat, dog] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'def' (Valid)
* = 'dog' (Fail)
* = ['gh', 'de'] (Valid)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.containsI = function(value, options, key) {
const testValue = getTestValue(options);
if (Array.isArray(value)) {
if (
value.some(
item => !validate.validators.containsI(item.toLowerCase(), options, key)
)
value.some(
item => !validate.validators.containsI(item.toLowerCase(), options, key)
)
) {
return undefined;
}
return `No item of ${value.join(',')} contains ${JSON.stringify(
testValue
testValue
)}`;
}
if (Array.isArray(testValue)) {
if (
testValue.some(
subTest => !validate.validators.containsI(value, subTest, key)
)
testValue.some(
subTest =>
!validate.validators.containsI(value, subTest.toLowerCase(), key)
)
) {
return;
}
return `${key} must contain at least one of ${testValue.join(',')}`;
}
if (
testValue &&
value.indexOf &&
value.toLowerCase().indexOf(testValue) === -1
testValue &&
value.indexOf &&
value.toLowerCase().indexOf(testValue.toLowerCase()) === -1
) {
return key + 'must contain any case of' + testValue;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = Corr (Valid)
* = corr (Fail)
* = [att, cor] (Fail)
* = [Att, Wall] (Valid)
* = [cat, dog] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'def' (Valid)
* = 'dog' (Fail)
* = ['cat', 'de'] (Valid)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.contains = function(value, options, key) {
const testValue = options?.value ?? options;
const testValue = getTestValue(options);
if (Array.isArray(value)) {
if (value.some(item => !validate.validators.contains(item, options, key))) {
return undefined;
}
return `No item of ${value.join(',')} contains ${JSON.stringify(
testValue
testValue
)}`;
}
if (Array.isArray(testValue)) {
if (
testValue.some(
subTest => !validate.validators.contains(value, subTest, key)
)
testValue.some(
subTest => !validate.validators.contains(value, subTest, key)
)
) {
return;
}
@ -73,50 +244,235 @@ validate.validators.contains = function(value, options, key) {
return key + 'must contain ' + testValue;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = Corr (Fail)
* = corr (Valid)
* = [att, cor] (Valid)
* = [Att, Wall] (Fail)
* = [cat, dog] (Valid)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'def' (Fail)
* = 'dog' (Valid)
* = ['cat', 'de'] (Fail)
* = ['cat', 'dog'] (Valid)
*
* */
validate.validators.doesNotContain = function(value, options, key) {
if (options && value.indexOf && value.indexOf(options.value) !== -1) {
return key + 'cannot contain ' + options.value;
const containsResult = validate.validators.contains(value, options, key);
if (!containsResult) {
return `No item of ${value} should contain ${getTestValue(options)}`;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = Corr (Fail)
* = corr (Fail)
* = [att, cor] (Fail)
* = [Att, Wall] (Fail)
* = [cat, dog] (Valid)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'DEF' (Fail)
* = 'dog' (Valid)
* = ['cat', 'gh'] (Fail)
* = ['cat', 'dog'] (Valid)
*
* */
validate.validators.doesNotContainI = function(value, options, key) {
const containsResult = validate.validators.containsI(value, options, key);
if (!containsResult) {
return `No item of ${value} should not contain ${getTestValue(options)}`;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = Corr (Fail)
* = Att (Fail)
* = ['cat', 'dog', 'Att'] (Valid)
* = [cat, dog] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'deg' (Valid)
* = ['cat', 'GH'] (Valid)
* = ['cat', 'gh'] (Fail)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.startsWith = function(value, options, key) {
if (options && value.startsWith && !value.startsWith(options.value)) {
return key + 'must start with ' + options.value;
let testValues = getTestValue(options);
if (typeof testValues === 'string') {
testValues = [testValues];
}
if (typeof value === 'string') {
if (!testValues.some(testValue => value.startsWith(testValue))) {
return key + ' must start with any of these values: ' + testValues;
}
} else if (Array.isArray(value)) {
let valid = false;
for (let i = 0; i < value.length; i++) {
for (let j = 0; j < testValues.length; j++) {
if (value[i].startsWith(testValues[j])) {
valid = true; // set valid flag to true if a match is found
break;
}
}
if (valid) {
return undefined; // break out of loop if a match is found
}
}
if (!valid) {
return key + ' must start with any of these values: ' + testValues; // return undefined if no match is found
}
} else {
return 'Value must be a string or an array';
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = TED (Fail)
* = ted (Valid)
* = ['cat', 'dog', 'ted'] (Valid)
* = [cat, dog] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'deg' (Valid)
* = ['cat', 'HI'] (Valid)
* = ['cat', 'hi'] (Fail)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.endsWith = function(value, options, key) {
if (options && value.endsWith && !value.endsWith(options.value)) {
return key + 'must end with ' + options.value;
let testValues = getTestValue(options);
if (typeof testValues === 'string') {
testValues = [testValues];
}
if (typeof value === 'string') {
if (!testValues.some(testValue => value.endsWith(testValue))) {
return key + ' must end with any of these values: ' + testValues;
}
} else if (Array.isArray(value)) {
let valid = false;
for (let i = 0; i < value.length; i++) {
for (let j = 0; j < testValues.length; j++) {
if (value[i].endsWith(testValues[j])) {
valid = true; // set valid flag to true if a match is found
break;
}
}
if (valid) {
return undefined; // break out of loop if a match is found
}
}
if (!valid) {
return key + ' must end with any of these values: ' + testValues; // return undefined if no match is found
}
} else {
return key + ' must be a string or an array';
}
};
const getTestValue = options => options?.value ?? options;
/**
* @example
* value = 30
* testValue = 20 (Valid)
* = 40 (Fail)
*
* */
validate.validators.greaterThan = function(value, options, key) {
const testValue = getTestValue(options);
if (value === undefined || value === null || value <= testValue) {
return key + 'with value ' + value + ' must be greater than ' + testValue;
if (Array.isArray(value) || typeof value === 'string') {
return `${key} is not allowed as an array or string`;
}
if (Array.isArray(testValue)) {
if (testValue.length === 1) {
if (!(value >= testValue[0])) {
return `${key} must be greater than or equal to ${testValue[0]}, but was ${value}`;
}
} else if (testValue.length > 1) {
return key + ' must be an array of length 1';
}
} else {
if (!(value >= testValue)) {
return key + ' must be greater than ' + testValue;
}
}
};
/**
* @example
* value = 30
* testValue = 40 (Valid)
* = 20 (Fail)
*
* */
validate.validators.lessThan = function(value, options, key) {
const testValue = getTestValue(options);
if (Array.isArray(testValue)) {
if (testValue.length === 1) {
if (!(value <= testValue[0])) {
return `${key} must be less than or equal to ${testValue[0]}, but was ${value}`;
}
} else if (testValue.length > 1) {
return key + ' must be an array of length 1';
}
} else {
if (!(value <= testValue)) {
return key + ' must be less than ' + testValue;
}
}
};
/**
* @example
*
* value = 50
* testValue = [10,60] (Valid)
* = [60, 10] (Valid)
* = [0, 10] (Fail)
* = [70, 80] (Fail)
* = 45 (Fail)
* = [45] (Fail)
*
* */
validate.validators.range = function(value, options, key) {
const testValue = getTestValue(options);
if (value === undefined || value < testValue[0] || value > testValue[1]) {
return (
key +
'with value ' +
value +
' must be between ' +
testValue[0] +
' and ' +
testValue[1]
);
}
if (Array.isArray(testValue) && testValue.length === 2) {
const min = Math.min(testValue[0], testValue[1]);
const max = Math.max(testValue[0], testValue[1]);
if (value === undefined || value < min || value > max) {
return `${key} with value ${value} must be between ${min} and ${max}`;
}
} else return `${key} must be an array of length 2`;
};
validate.validators.notNull = value =>
value === null || value === undefined ? 'Value is null' : undefined;
value === null || value === undefined ? 'Value is null' : undefined;
const getTestValue = options => {
if (Array.isArray(options)) {
return options.map(option => option?.value ?? option);
} else {
return options?.value ?? options;
}
};
const dicomTagToArray = value => {
let dicomArrayValue;
if (!Array.isArray(value)) {
dicomArrayValue = [value];
} else {
dicomArrayValue = [...value];
}
return dicomArrayValue;
};
export default validate;

View File

@ -1,139 +1,570 @@
import validate from './validator.js';
describe('validator', () => {
const attributeMap = {
str: 'string',
upper: 'UPPER',
num: 3,
nullValue: null,
list: ['abc', 'def', 'GHI'],
};
const attributeMap = {
str: 'Attenuation Corrected',
upper: 'UPPER',
num: 3,
nullValue: null,
list: ['abc', 'def', 'GHI'],
listStr: ['Attenuation Corrected'],
};
const options = {
format: 'grouped',
};
const options = {
format: 'grouped',
};
describe('contains', () => {
it('returns match any list contains', () => {
expect(
validate(attributeMap, { list: { contains: 'a' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: 'i' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['i'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['a'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z', 'd'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z'] } }, [options])
).not.toBeUndefined();
describe('equals', () => {
it('returned undefined on strictly equals', () => {
expect(
validate(attributeMap, { listStr: { equals: ['Attenuation'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { listStr: { equals: 'Attenuation' } }, [
options,
])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { equals: 'Attenuation Corrected' } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { equals: ['Attenuation Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { str: { equals: 'Attenuation Corrected' } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { equals: { value: 'Attenuation Corrected' } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { str: { equals: ['Attenuation Corrected'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { equals: ['Attenuation'] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { equals: ['abc', 'def', 'GHI'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { equals: ['abc', 'GHI', 'def'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ list: { equals: { value: ['abc', 'def', 'GHI'] } } },
[options]
)
).toBeUndefined();
});
});
});
describe('doesNotEqual', () => {
it('returns undefined if value does not equal ', () => {
expect(
validate(
attributeMap,
{ listStr: { doesNotEqual: 'Attenuation Corrected' } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { doesNotEqual: ['Attenuation Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(attributeMap, { listStr: { doesNotEqual: 'Attenuation' } }, [
options,
])
).toBeUndefined();
describe('containsI', () => {
it('returns match any list contains case insensitive', () => {
expect(
validate(attributeMap, { upper: { containsI: ['bye', 'pre'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: 'hi' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['hi', 'bye'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotEqual: 'Attenuation' } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { doesNotEqual: { value: 'Attenuation' } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotEqual: ['Attenuation'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotEqual: ['abc', 'def'] } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotEqual: ['abc', 'GHI', 'def'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotEqual: ['abc', 'def', 'GHI'] } },
[options]
)
).not.toBeUndefined();
});
});
});
describe('includes', () => {
it('returns match any list includes', () => {
expect(
validate(
attributeMap,
{ listStr: { includes: 'Attenuation Corrected' } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { includes: ['Attenuation Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { includes: ['Attenuation Corrected', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { includes: ['Attenuation', 'Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ str: { includes: ['Attenuation Corrected', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { includes: ['Attenuation', 'Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { includes: ['abc'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { includes: ['GHI', 'HI'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { includes: ['HI', 'bye'] } }, [options])
).not.toBeUndefined();
});
});
describe('doesNotInclude', () => {
it('returns undefined if list does not includes', () => {
expect(
validate(
attributeMap,
{ listStr: { doesNotInclude: 'Attenuation Corrected' } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{
listStr: { doesNotInclude: ['Attenuation Corrected', 'Corrected'] },
},
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { doesNotInclude: ['Attenuation', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { doesNotInclude: ['Attenuation Corrected', 'Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ str: { doesNotInclude: ['Attenuation', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotInclude: ['Corr'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotInclude: 'abc' } }, [options])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotInclude: { value: ['abc'] } } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotInclude: { value: ['att', 'cor'] } } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotInclude: { value: ['abc', 'def', 'dog'] } } },
[options]
)
).not.toBeUndefined();
});
});
describe('containsI', () => {
it('returns match any list contains case insensitive', () => {
expect(
validate(attributeMap, { upper: { containsI: ['hi', 'pre'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: 'hi' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['ghi', 'bye'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
options,
])
).toBeUndefined();
});
});
describe('contains', () => {
it('returns match any list contains', () => {
expect(
validate(attributeMap, { str: { contains: 'Corr' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: { value: 'Corr' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['Corr'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['corr'] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['Att', 'Wall'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: 'GH' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['ab'] } }, [options])
).toBeUndefined();
describe('equals', () => {
it('returned undefined on equals', () => {
expect(
validate(attributeMap, { str: { equals: attributeMap.str } }, [options])
).toBeUndefined();
expect(
validate(
attributeMap,
{ num: { equals: { value: attributeMap.num } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z', 'bc'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z'] } }, [options])
).not.toBeUndefined();
});
});
it('returns error on not equals', () => {
expect(
validate(attributeMap, { str: { equals: 'abc' } }, [options])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ num: { equals: { value: 1 + attributeMap.num } } },
[options]
)
).not.toBeUndefined();
describe('doesNotContain', () => {
it('returns undefined if string does not contain specified value', () => {
expect(
validate(attributeMap, { str: { doesNotContain: ['att', 'wall'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: 'Corr' } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: 'corr' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: { value: 'corr' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: ['att', 'cor'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: ['Att', 'cor'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContain: ['GHI', 'hi'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContain: ['hi'] } }, [options])
).toBeUndefined();
});
});
});
describe('greaterThan', () => {
it('returns undefined on greaterThan', () => {
expect(
validate(
attributeMap,
{ num: { greaterThan: { value: attributeMap.num - 1 } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
options,
])
).toBeUndefined();
describe('doesNotContainI', () => {
it('returns undefined if string does not contain specified value', () => {
expect(
validate(attributeMap, { str: { doesNotContainI: 'corr' } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: 'Corr' } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: ['att', 'cor'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: ['Att', 'wall'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContainI: 'bye' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
options,
])
).not.toBeUndefined();
});
});
describe('startsWith', () => {
it('returns undefined if string starts with specified value', () => {
expect(
validate(attributeMap, { str: { startsWith: { value: 'Atte' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { startsWith: 'Att' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { startsWith: ['cat', 'dog', 'Att'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { startsWith: ['cat', 'dog'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { startsWith: ['GH'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { startsWith: ['de', 'bye'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { startsWith: ['hi', 'bye'] } }, [
options,
])
).not.toBeUndefined();
});
});
describe('endsWith', () => {
it('returns undefined if string ends with specified value', () => {
expect(
validate(attributeMap, { str: { endsWith: 'ted' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: { value: 'ted' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: ['ted'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: ['Att'] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: ['cat', 'dog', 'ted'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { endsWith: ['HI'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { endsWith: ['bc', 'dog', 'ted'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { endsWith: ['bye', 'dog'] } }, [
options,
])
).not.toBeUndefined();
});
});
it('returns error on not greater than', () => {
expect(
validate(
attributeMap,
{ num: { greaterThan: { value: attributeMap.num } } },
[options]
)
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { greaterThan: attributeMap.num } }, [
options,
])
).not.toBeUndefined();
describe('greaterThan', () => {
it('returns undefined on greaterThan', () => {
expect(
validate(
attributeMap,
{ num: { greaterThan: { value: attributeMap.num - 1 } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ num: { greaterThan: [attributeMap.num - 1] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ num: { greaterThan: [attributeMap.num + 1] } },
[options]
)
).not.toBeUndefined();
});
});
it('returns error on undefined value', () => {
expect(
validate(
attributeMap,
{ numUndefined: { greaterThan: { value: 3 } } },
[options]
)
).not.toBeUndefined();
describe('lessThan', () => {
it('returns undefined on lessThan', () => {
expect(
validate(
attributeMap,
{ num: { lessThan: { value: attributeMap.num + 1 } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { lessThan: attributeMap.num + 1 } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { num: { lessThan: [attributeMap.num + 1] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { num: { lessThan: [attributeMap.num - 1] } }, [
options,
])
).not.toBeUndefined();
});
});
describe('range', () => {
it('returns undefined if the value is between', () => {
expect(
validate(
attributeMap,
{ num: { range: [attributeMap.num + 1, attributeMap.num - 1] } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { range: [1, 4] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { num: { range: [1, 2] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { range: [4, 5] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { range: [5] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { range: 5 } }, [options])
).not.toBeUndefined();
});
});
});
});

View File

@ -246,7 +246,23 @@ A list of criteria for the protocol along with the provided points for ranking.
- `constraint`: the constraint that needs to be satisfied for the attribute. It accepts a `validator` which can be
[`equals`, `doesNotEqual`, `contains`, `doesNotContain`, `startsWith`, `endsWidth`]
- | Rule | Single Value | Array Value | Example |
|--- |--- |--- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| equals | === | All members are === in same order | value = ['abc', 'def', 'GHI']<br/>testValue = 'abc' (Fail)<br/><br/> = ['abc'] (Fail)<br/><br/> = ['abc', 'def', 'GHI'] (Valid)<br/><br/> = ['abc', 'GHI', 'def'] (Fail)<br/><br/> = ['abc', 'def'] (Fail)<br/><br/>value = 'Attenuation Corrected'<br/>testValue = 'Attenuation Corrected' (Valid)<br/> = 'Attenuation' (Fail)<br/><br/> value = ['Attenuation Corrected'] <br/> testValue = ['Attenuation Corrected'] (Valid)<br/> = 'Attenuation Corrected' (Valid) <br/> = 'Attenuation' (Fail) <br/> |
| doesNotEqual | !== | Any member is !== for the array, either in value, order, or length | value = ['abc', 'def', 'GHI']<br/>testValue = 'abc' (Valid)<br/> = ['abc'] (Valid)<br/> = ['abc', 'def', 'GHI'] (Fail)<br/> = ['abc', 'GHI', 'def'] (Valid)<br/> = ['abc', 'def'] (Valid)<br/><br/>value = 'Attenuation Corrected'<br/>testValue = 'Attenuation Corrected' (Fail)Valid<br/><br/> = 'Attenuation' (Valid) <br/><br/> value = ['Attenuation Corrected']<br/> testValue = ['Attenuation Corrected'] (Fail) <br/> = 'Attenuation Corrected' (Fail) <br/> = 'Attenuation' (Fail) |
| includes | Not allowed | Value is equal to one of the values of the array | value = ['abc', 'def', 'GHI']<br/>testValue = ['abc'] (Valid)<br/><br/> = abc (Fail)<br/><br/>= [abc] (Fail)<br/><br/> = dog (Fail)<br/><br/> = = [att, abc] (Valid)<br/><br/> = ['abc', 'def', 'dog'] (Valid)<br/><br/> = ['cat', 'dog'] (Fail)<br/><br/><br/> value = 'Attenuation Corrected' <br/> testValue = ['Attenuation Corrected', 'Corrected'] (Valid)<br/>= ['Attenuation', 'Corrected'] (Fail)<br/><br/><br/>value = ['Attenuation Corrected']<br/>testValue = 'Attenuation Corrected' (Fail)<br/> = ['Attenuation Corrected', 'Corrected'] (Valid)<br/> = ['Attenuation', 'Corrected'] (Fail) |
| doesNotInclude | Not allowed | Value is not in one of the values of the array | value = ['abc', 'def', 'GHI']<br/>testValue = Corr (Valid)<br/><br/> = abc (Fail)<br/><br/> = [att, cor] (Valid)<br/><br/> = ['abc', 'def', 'dog'] (Fail)<br/><br/><br/>value = 'Attenuation Corrected' <br/> testValue = ['Attenuation Corrected', 'Corrected'] (Fail) <br/> = ['Attenuation', 'Corrected'] (Valid) <br/><br/><br/>value = ['Attenuation Corrected'] <br/> testValue = 'Attenuation' (Fail)<br/> = ['Attenuation Corrected', 'Corrected'] (Fail) <br/>= ['Attenuation', 'Corrected'] (Valid) |
| containsI | String containment (case insensitive) | String containment (case insensitive) is OK for one of the rule values | value = 'Attenuation Corrected'<br/>testValue = Corr (Valid)<br/> = corr (Valid)<br/><br/> = [att, cor] (Valid)<br/><br/> = [Att, Wall] (Valid)<br/><br/> = [cat, dog] (Fail)<br/><br/><br/><br/>value = ['abc', 'def', 'GHI']<br/>testValue = 'def' (Valid)<br/><br/> = 'dog' (Fail)<br/><br/> = ['gh', 'de'] (Valid)<br/><br/> = ['cat', 'dog'] (Fail)<br/> |
| contains | String containment (case sensitive) | String containment (case sensitive) is OK for one of the rule values | value = 'Attenuation Corrected'<br/>testValue = Corr (Valid)<br/> = corr (Fail)<br/> = [att, cor] (Fail)<br/> = [Att, Wall] (Valid)<br/><br/> = [cat, dog] (Fail)<br/><br/><br/>value = ['abc', 'def', 'GHI']<br/><br/>testValue = 'def' (Valid)<br/> = 'dog' (Fail)<br/><br/> = ['cat', 'de'] (Valid)<br/><br/> = ['cat', 'dog'] (Fail) |
| doesNotContain | String containment is false | String containment is false for all values of the array | value = 'Attenuation Corrected'<br/>testValue = Corr (Fail)<br/><br/><br/> = corr (Valid)<br/><br/> = [att, cor] (Valid)<br/><br/> = [Att, Wall] (Fail)<br/><br/> = [cat, dog] (Valid)<br/><br/>value = ['abc', 'def', 'GHI']<br/>testValue = 'def' (Fail)<br/><br/><br/> = 'dog' (Valid)<br/><br/> = ['cat', 'de'] (Fail)<br/><br/> = ['cat', 'dog'] (Valid) |
| doesNotContainI | String containment is false (case insensitive) | String containment (case insensitive) is false for all values of the array | value = 'Attenuation Corrected'<br/>testValue = Corr (Fail)<br/><br/> = corr (Fail)<br/><br/> = [att, cor] (Fail)<br/><br/> = [Att, Wall] (Fail)<br/><br/> = [cat, dog] (Valid)<br/><br/><br/>value = ['abc', 'def', 'GHI']<br/>testValue = 'DEF' (Fail)<br/><br/> = 'dog' (Valid)<br/><br/> = ['cat', 'gh'] (Fail)<br/><br/> = ['cat', 'dog'] (Valid) |
| startsWith | Value begins with characters | Starts with one of the values of the array | value = 'Attenuation Corrected'<br/>testValue = Corr (Fail)<br/><br/> = Att (Fail)<br/><br/> = ['cat', 'dog', 'Att'] (Valid)<br/><br/> = [cat, dog] (Fail)<br/><br/><br/>value = ['abc', 'def', 'GHI']<br/>testValue = 'deg' (Valid)<br/><br/> = ['cat', 'GH'] (Valid)<br/><br/> = ['cat', 'gh'] (Fail)<br/><br/> = ['cat', 'dog'] (Fail) |
| endsWith | Value ends with characters | ends with one of the value of the array | value = 'Attenuation Corrected'<br/>testValue = TED (Fail)<br/><br/> = ted (Valid)<br/><br/> = ['cat', 'dog', 'ted'] (Valid)<br/><br/> = [cat, dog] (Fail)<br/><br/><br/>value = ['abc', 'def', 'GHI']<br/>testValue = 'deg' (Valid)<br/><br/> = ['cat', 'HI'] (Valid)<br/><br/> = ['cat', 'hi'] (Fail)<br/><br/> = ['cat', 'dog'] (Fail) |
| greaterThan | value is => to rule | Not applicable | value = 30<br/><br/>testValue = 20 (Valid)<br/> = 40 (Fail)<br/><br/> |
| lessThan | value is <= to rule | Not applicable | value = 30<br/><br/>testValue = 40 (Valid)<br/> = 20 (Fail)<br/> |
| range | Not applicable | 2 value requested (min and max) | value = 50<br/><br/>testValue = [10,60] (Valid)<br/> = [60, 10] (Valid)<br/><br/> = [0, 10] (Fail)<br/><br/> = [70, 80] (Fail)<br/><br/> = 45 (Fail)<br/><br/> = [45] (Fail) |
| notNull | Not Applicable | Not Applicable | No value |
A sample of the matching rule is above which matches against the study description to be PETCT
```js