Commit 631fd661 authored by Gianfranco Harres's avatar Gianfranco Harres

Issue #37: Add new type validation typeof

parent 4cff3cbf
Pipeline #21745 passed with stages
in 1 minute and 53 seconds
......@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.0.7 - 01-10-2019
### Added
- Validation type TYPEOF #37 (Gianfranco)
## 1.0.6 - 30-09-2019
### Added
- QueryBuilder Class #47 (Gianfranco)
......
{
"name": "form-creator-api",
"version": "1.0.6",
"version": "1.0.7",
"description": "RESTful API used to manage and answer forms.",
"main": "index.js",
"scripts": {
......
......@@ -897,9 +897,9 @@ describe("Read and Write on Database", () => {
};
const inputObj2: Input = {
placement: 0
, description: "Description Question 3 Form 6"
, question: "Question 3 Form 6"
placement: 1
, description: "Description Question 2 Form 6"
, question: "Question 2 Form 6"
, enabled: true
, type: InputType.RADIO
, sugestions: [
......@@ -912,18 +912,16 @@ describe("Read and Write on Database", () => {
};
const inputObj3: Input = {
placement: 1
, description: "Description Question 2 Form 6"
, question: "Question 2 Form 6"
placement: 2
, description: "Description Question 3 Form 6"
, question: "Question 3 Form 6"
, enabled: true
, type: InputType.SELECT
, sugestions: [
{ value: "Sugestion 1", placement: 0 }
, { value: "Sugestion 2", placement: 1 }
]
, validation: [
{ type: ValidationType.MANDATORY, arguments: [] }
]
, validation: []
, id: 20
};
......@@ -944,4 +942,119 @@ describe("Read and Write on Database", () => {
done();
});
});
it("should insert a input with typeof validation", (done) => {
const inputObj1: Input = {
placement: 0
, description: "Description Question 1 Form 7"
, question: "Question 1 form 7"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["int"] }
]
, id: 21
};
const inputObj2: Input = {
placement: 1
, description: "Description Question 2 Form 7"
, question: "Question 2 form 7"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["int"] }
]
, id: 22
};
const inputObj3: Input = {
placement: 2
, description: "Description Question 3 Form 7"
, question: "Question 3 form 7"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["float"] }
]
, id: 23
};
const inputObj4: Input = {
placement: 3
, description: "Description Question 4 Form 7"
, question: "Question 4 form 7"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["float"] }
]
, id: 24
};
const inputObj5: Input = {
placement: 4
, description: "Description Question 1 Form 8"
, question: "Question 1 form 8"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["date"] }
]
, id: 25
};
const inputObj6: Input = {
placement: 5
, description: "Description Question 2 Form 8"
, question: "Question 2 form 8"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["date"] }
]
, id: 26
};
const inputObj7: Input = {
placement: 6
, description: "Description Question 3 Form 8"
, question: "Question 3 form 8"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["invalid"] }
]
, id: 27
};
const formObj: Form = {
title: "Form Title 7"
, description: "Form Description 7"
, inputs: [
inputObj1
, inputObj2
, inputObj3
, inputObj4
, inputObj5
, inputObj6
, inputObj7
]
, id: 7
};
dbhandler.form.write(formObj, (err: Error, formResult: Form) => {
expect(err).to.be.a("null");
TestHandler.testForm(formObj, formResult);
done();
});
});
});
......@@ -17,13 +17,13 @@
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
*/
/**
* Available Input types
*/
export enum InputType {
/** Text type, when input is a text */
/** Text type, when input is a text */
TEXT,
CHECKBOX,
RADIO,
......@@ -40,19 +40,21 @@ export enum UpdateType {
}
/**
* Available Validation types
* Available Validation types.
*/
export enum ValidationType {
/** Used as error code. No suitable validation found. */
NONE,
/** Regex type, when input need a regex to validate */
REGEX,
/** Mandatory type, when input is mandatory */
MANDATORY,
/** MaxChars type, when input has maximum char limit */
MAXCHAR,
/** MinChars type, when input has minimum char limit */
MINCHAR
/** Used as error code. No suitable validation found. */
NONE,
/** Regex type, when input need a regex to validate. */
REGEX,
/** Mandatory type, when input is mandatory. */
MANDATORY,
/** MaxChars type, when input has maximum char limit. */
MAXCHAR,
/** MinChars type, when input has minimum char limit. */
MINCHAR,
/** TypeOf type, when input needs to be a certain type. */
TYPEOF
}
/**
......@@ -63,7 +65,7 @@ export class EnumHandler {
/**
* Parse an enum(Input type) to string.
* @param a - Input type to be stringified.
* @returns - Input Type as string
* @returns - Input Type as string.
*/
public static stringifyInputType(a: InputType): string {
switch (a) {
......@@ -116,6 +118,8 @@ export class EnumHandler {
return "maxchar";
case ValidationType.MINCHAR:
return "minchar";
case ValidationType.TYPEOF:
return "typeof";
default:
return "";
}
......@@ -136,6 +140,8 @@ export class EnumHandler {
return ValidationType.MAXCHAR;
case "minchar":
return ValidationType.MINCHAR;
case "typeof":
return ValidationType.TYPEOF;
default:
return ValidationType.NONE;
}
......
......@@ -31,11 +31,11 @@
* ValidationError: Extends Error class
* Has a dict that allow us to know which answer is invalide
*/
export class ValidationError extends Error{
export class ValidationError extends Error {
/** A dict that allows user to know which Input Answer is invalid. */
public readonly validationDict: ValidationDict;
constructor(validationDict: ValidationDict, ...params: any[]){
constructor(validationDict: ValidationDict, ...params: any[]) {
super(...params);
this.validationDict = validationDict;
}
......
......@@ -184,4 +184,79 @@ describe("Validation Handler", () => {
done();
});
});
it("should test when input is number", (done) => {
const inputAnswerOpt1: InputAnswerOptions = {
idInput: 21
, placement: 0
, value: "Not a number"
};
const inputAnswerOpt2: InputAnswerOptions = {
idInput: 22
, placement: 0
, value: "25"
};
const inputAnswerOpt3: InputAnswerOptions = {
idInput: 23
, placement: 0
, value: "Not a Float"
};
const inputAnswerOpt4: InputAnswerOptions = {
idInput: 24
, placement: 0
, value: "1.83"
};
const inputAnswerOpt5: InputAnswerOptions = {
idInput: 25
, placement: 0
, value: "Not a date"
};
const inputAnswerOpt6: InputAnswerOptions = {
idInput: 26
, placement: 0
, value: "02/02/2002"
};
const inputAnswerOpt7: InputAnswerOptions = {
idInput: 27
, placement: 0
, value: "Invalid argument causes invalid answer"
};
const inputAnswerOptionsDict: InputAnswerOptionsDict = {
21: [inputAnswerOpt1]
, 22: [inputAnswerOpt2]
, 23: [inputAnswerOpt3]
, 24: [inputAnswerOpt4]
, 25: [inputAnswerOpt5]
, 26: [inputAnswerOpt6]
, 27: [inputAnswerOpt7]
};
dbhandler.form.read(7, (error: Error, form: Form) => {
const formAnswerOptions: FormAnswerOptions = {
form
, timestamp: new Date()
, inputsAnswerOptions: inputAnswerOptionsDict
};
const formAnswer = new FormAnswer(OptHandler.formAnswer(formAnswerOptions));
try {
ValidationHandler.validateFormAnswer(formAnswer);
} catch (e) {
expect(e.validationDict["21"]).to.be.equal("Input answer must be a int");
expect(e.validationDict["22"]).to.be.undefined;
expect(e.validationDict["23"]).to.be.equal("Input answer must be a float");
expect(e.validationDict["24"]).to.be.undefined;
expect(e.validationDict["25"]).to.be.equal("Input answer must be a date");
expect(e.validationDict["26"]).to.be.undefined;
expect(e.validationDict["27"]).to.be.equal("Input answer must be a invalid");
}
done();
});
});
});
......@@ -35,91 +35,110 @@ export class ValidationHandler {
* @param regex - Regex to validate answer.
* @returns - true if answer match regex, else false.
*/
private static validateByRegex(answer: string, regex: string): boolean{
private static validateByRegex(answer: string, regex: string): boolean {
const regexp = new RegExp(regex);
return regexp.test(answer);
}
/**
* Validate if is null, undefined nor ""
* Validate if is null, undefined nor "".
* @param answer - answer to be validated.
* @returns - true if not null, "" nor undefined, else false.
*/
private static validateMandatory(answer: string): boolean{
private static validateMandatory(answer: string): boolean {
return ((!answer) === false);
}
/**
* Validate if answer has minimum number of chars
* Validate if answer has minimum number of chars.
* @param answer - Answer to be validated.
* @param size - Minimum size that answer should have.
* @returns - true if has at least Size chars, else false.
*/
private static validateMinChar(answer: string, size: string): boolean{
return (answer !== null && answer !== undefined && parseInt(size, 10) <= answer.length);
private static validateMinChar(answer: string, size: string): boolean {
return (answer !== null && answer !== undefined && parseInt(size, 10) <= answer.length);
}
/**
* Validate if answer has minimum number of chars
* Validate if answer has minimum number of chars.
* @param answer - Answer to be validated.
* @param size - Maximum size that answer should have.
* @returns - true if has at max Size chars, else false.
*/
private static validateMaxChar(answer: string, size: string): boolean{
return (answer !== null && answer !== undefined && parseInt(size, 10) >= answer.length);
private static validateMaxChar(answer: string, size: string): boolean {
return (answer !== null && answer !== undefined && parseInt(size, 10) >= answer.length);
}
private static validateTypeOf(answer: string, type: string): boolean {
// Using string here to avoid validate validations
if (type === "int") {
return(!isNaN(parseInt(answer, 10)));
} else if (type === "float") {
return(!isNaN(parseFloat(answer)));
} else if (type === "date") {
return((new Date(answer)).toString() !== "Invalid Date");
} else {
return(false);
}
}
/**
* Validate if answer has minimum number of chars
* Validate if answer has minimum number of chars.
* @param input - Input to validate answer.
* @param answer - Answer of input
* @param answer - Answer of input.
* @returns - A string with all errors.
*/
private static validateInput(input: Input, answer: string): string{
private static validateInput(input: Input, answer: string): string {
const errors: string[] = [];
for ( const validation of input.validation){
for ( const validation of input.validation) {
switch (validation.type) {
case ValidationType.REGEX:
if (!this.validateByRegex(answer, validation.arguments[0])){
if (!this.validateByRegex(answer, validation.arguments[0])) {
errors.push("RegEx do not match");
}
break;
case ValidationType.MANDATORY:
if (!(this.validateMandatory(answer))){
if (!(this.validateMandatory(answer))) {
errors.push("Input answer is mandatory");
}
break;
case ValidationType.MAXCHAR:
if (!(this.validateMaxChar(answer, validation.arguments[0]))){
if (!(this.validateMaxChar(answer, validation.arguments[0]))) {
errors.push("Input answer must be lower than " + validation.arguments[0]);
}
break;
case ValidationType.MINCHAR:
if (!(this.validateMinChar(answer, validation.arguments[0]))){
if (!(this.validateMinChar(answer, validation.arguments[0]))) {
errors.push("Input answer must be greater than " + validation.arguments[0]);
}
break;
case ValidationType.TYPEOF:
if (!(this.validateTypeOf(answer, validation.arguments[0]))) {
errors.push("Input answer must be a " + validation.arguments[0]) + " type";
}
break;
}
}
return errors.join(";");
}
public static validateFormAnswer(formAnswer: FormAnswer): void{
/**
* Validate if form answer is valid.
* @param formAnswer - FormAnswer to be validated.
*/
public static validateFormAnswer(formAnswer: FormAnswer): void {
const errorsDict: ValidationDict = {};
for ( const input of formAnswer.form.inputs){
for (const answer of formAnswer.inputAnswers[input.id]){
for (const input of formAnswer.form.inputs) {
for (const answer of formAnswer.inputAnswers[input.id]) {
const error: string = this.validateInput(input, answer.value);
if (error !== "" && error !== undefined){
if (error !== "" && error !== undefined) {
errorsDict[input.id] = error;
}
}
}
if ( Object.keys(errorsDict).length > 0){
if ( Object.keys(errorsDict).length > 0) {
throw new ValidationError(errorsDict, "Validation Error");
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment