Commit ade7c4fa authored by Gianfranco Harres's avatar Gianfranco Harres

Issue #41: Add dependency between fields

parent 54eef470
Pipeline #21824 passed with stages
in 1 minute and 8 seconds
......@@ -4,6 +4,13 @@ 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.10 - 10-10-2019
### Added
- Validation type DEPENDENCY #41 (Gianfranco)
### Changed
- ValidateInput method to receive a vector of inputs
## 1.0.9 - 09-10-2019
### Added
- Validation type MAXANSWERS #38 (Gianfranco)
......
{
"name": "form-creator-api",
"version": "1.0.9",
"version": "1.0.10",
"description": "RESTful API used to manage and answer forms.",
"main": "index.js",
"scripts": {
......
......@@ -923,7 +923,10 @@ describe("Read and Write on Database", () => {
{ value: "Sugestion 1", placement: 0 }
, { value: "Sugestion 2", placement: 1 }
]
, validation: []
, validation: [
{ type: ValidationType.DEPENDENCY, arguments: ["19", "1"] }
, { type: ValidationType.DEPENDENCY, arguments: ["20", "1"] }
]
, id: 20
};
......@@ -945,6 +948,19 @@ describe("Read and Write on Database", () => {
, id: 21
};
const inputObj5: Input = {
placement: 4
, description: "Description Question 5 Form 6"
, question: "Question 5 Form 6"
, enabled: true
, type: InputType.TEXT
, sugestions: []
, validation: [
{ type: ValidationType.DEPENDENCY, arguments: ["18", "2"] }
]
, id: 22
};
const formObj: Form = {
title: "Form Title 6"
, description: "Form Description 6"
......@@ -953,6 +969,7 @@ describe("Read and Write on Database", () => {
, inputObj2
, inputObj3
, inputObj4
, inputObj5
]
, id: 6
};
......@@ -977,7 +994,7 @@ describe("Read and Write on Database", () => {
{ type: ValidationType.TYPEOF, arguments: ["int"] }
, { type: ValidationType.MAXANSWERS, arguments: ["2"] }
]
, id: 22
, id: 23
};
const inputObj2: Input = {
......@@ -991,7 +1008,7 @@ describe("Read and Write on Database", () => {
{ type: ValidationType.TYPEOF, arguments: ["int"] }
, { type: ValidationType.MAXANSWERS, arguments: ["1"] }
]
, id: 23
, id: 24
};
const inputObj3: Input = {
......@@ -1004,7 +1021,7 @@ describe("Read and Write on Database", () => {
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["float"] }
]
, id: 24
, id: 25
};
const inputObj4: Input = {
......@@ -1017,7 +1034,7 @@ describe("Read and Write on Database", () => {
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["float"] }
]
, id: 25
, id: 26
};
const inputObj5: Input = {
......@@ -1031,7 +1048,7 @@ describe("Read and Write on Database", () => {
{ type: ValidationType.TYPEOF, arguments: ["date"] }
, { type: ValidationType.MAXANSWERS, arguments: ["2"] }
]
, id: 26
, id: 27
};
const inputObj6: Input = {
......@@ -1044,7 +1061,7 @@ describe("Read and Write on Database", () => {
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["date"] }
]
, id: 27
, id: 28
};
const inputObj7: Input = {
......@@ -1057,8 +1074,9 @@ describe("Read and Write on Database", () => {
, validation: [
{ type: ValidationType.TYPEOF, arguments: ["invalid"] }
, { type: ValidationType.MAXANSWERS, arguments: ["invalid"] }
, { type: ValidationType.DEPENDENCY, arguments: ["28", "invalid"] }
]
, id: 28
, id: 29
};
const formObj: Form = {
......
......@@ -134,6 +134,8 @@ describe("Enum Handler", () => {
const validationSomeCheckboxCapitalized = EnumHandler.parseValidationType("SOMECHECKBOX");
const validationMaxAnswers = EnumHandler.parseValidationType("maxanswers");
const validationMaxAnswersCapitalized = EnumHandler.parseValidationType("MAXANSWERS");
const validationDependency = EnumHandler.parseValidationType("dependency");
const validationDependencyCapitalized = EnumHandler.parseValidationType("DEPENDENCY");
const validationNone = EnumHandler.parseValidationType("");
const validatioFOOL = EnumHandler.parseValidationType("fool");
......@@ -151,6 +153,8 @@ describe("Enum Handler", () => {
expect(validationSomeCheckboxCapitalized).to.be.equal(ValidationType.SOMECHECKBOX);
expect(validationMaxAnswers).to.be.equal(ValidationType.MAXANSWERS);
expect(validationMaxAnswersCapitalized).to.be.equal(ValidationType.MAXANSWERS);
expect(validationDependency).to.be.equal(ValidationType.DEPENDENCY);
expect(validationDependencyCapitalized).to.be.equal(ValidationType.DEPENDENCY);
expect(validationNone).to.be.equal(ValidationType.NONE);
expect(validatioFOOL).to.be.equal(ValidationType.NONE);
});
......
......@@ -58,7 +58,9 @@ export enum ValidationType {
/** SomeCheckbox type, when at least one checkbox must be selected. */
SOMECHECKBOX,
/** MAXANSWERS type, when input has maximum answer limit. */
MAXANSWERS
MAXANSWERS,
/** DEPENDENCY type, when input depends on another input. */
DEPENDENCY
}
/**
......@@ -128,6 +130,8 @@ export class EnumHandler {
return "somecheckbox";
case ValidationType.MAXANSWERS:
return "maxanswers";
case ValidationType.DEPENDENCY:
return "dependency";
default:
return "";
}
......@@ -154,6 +158,8 @@ export class EnumHandler {
return ValidationType.SOMECHECKBOX;
case "maxanswers":
return ValidationType.MAXANSWERS;
case "dependency":
return ValidationType.DEPENDENCY;
default:
return ValidationType.NONE;
}
......
......@@ -188,70 +188,70 @@ describe("Validation Handler", () => {
it("should test when input is number", (done) => {
const inputAnswerOpt1: InputAnswerOptions = {
idInput: 22
idInput: 23
, placement: 0
, value: "Not a number"
};
const inputAnswerOpt2: InputAnswerOptions = {
idInput: 22
idInput: 23
, placement: 0
, value: "23"
};
const inputAnswerOpt3: InputAnswerOptions = {
idInput: 22
idInput: 23
, placement: 0
, value: "24"
};
const inputAnswerOpt4: InputAnswerOptions = {
idInput: 23
idInput: 24
, placement: 0
, value: "25"
};
const inputAnswerOpt5: InputAnswerOptions = {
idInput: 24
idInput: 25
, placement: 0
, value: "Not a Float"
};
const inputAnswerOpt6: InputAnswerOptions = {
idInput: 25
idInput: 26
, placement: 0
, value: "1.83"
};
const inputAnswerOpt7: InputAnswerOptions = {
idInput: 26
idInput: 27
, placement: 0
, value: "Not a date"
};
const inputAnswerOpt8: InputAnswerOptions = {
idInput: 27
idInput: 28
, placement: 0
, value: "02/02/2002"
};
const inputAnswerOpt9: InputAnswerOptions = {
idInput: 28
idInput: 29
, placement: 0
, value: "Invalid argument causes invalid answer"
};
const inputAnswerOptionsDict: InputAnswerOptionsDict = {
22: [
23: [
inputAnswerOpt1
, inputAnswerOpt2
, inputAnswerOpt3
]
, 23: [inputAnswerOpt4]
, 24: [inputAnswerOpt5]
, 25: [inputAnswerOpt6]
, 26: [inputAnswerOpt7]
, 27: [inputAnswerOpt8]
, 28: [inputAnswerOpt9]
, 24: [inputAnswerOpt4]
, 25: [inputAnswerOpt5]
, 26: [inputAnswerOpt6]
, 27: [inputAnswerOpt7]
, 28: [inputAnswerOpt8]
, 29: [inputAnswerOpt9]
};
dbhandler.form.read(7, (error: Error, form: Form) => {
......@@ -264,13 +264,13 @@ describe("Validation Handler", () => {
try {
ValidationHandler.validateFormAnswer(formAnswer);
} catch (e) {
expect(e.validationDict["22"]).to.be.equal("Input answer must be a int;Number of input answers must be lower than 2");
expect(e.validationDict["23"]).to.be.undefined;
expect(e.validationDict["24"]).to.be.equal("Input answer must be a float");
expect(e.validationDict["25"]).to.be.undefined;
expect(e.validationDict["26"]).to.be.equal("Input answer must be a date");
expect(e.validationDict["27"]).to.be.undefined;
expect(e.validationDict["28"]).to.be.equal("Input answer must be a invalid;Number of input answers must be lower than invalid");
expect(e.validationDict["23"]).to.be.equal("Input answer must be a int;Number of input answers must be lower than 2");
expect(e.validationDict["24"]).to.be.undefined;
expect(e.validationDict["25"]).to.be.equal("Input answer must be a float");
expect(e.validationDict["26"]).to.be.undefined;
expect(e.validationDict["27"]).to.be.equal("Input answer must be a date");
expect(e.validationDict["28"]).to.be.undefined;
expect(e.validationDict["29"]).to.be.equal("Input answer must be a invalid;Number of input answers must be lower than invalid;Must answer question with id 28 and placement invalid");
}
done();
});
......@@ -286,22 +286,28 @@ describe("Validation Handler", () => {
const inputAnswerOpt2: InputAnswerOptions = {
idInput: 19
, placement: 0
, placement: 1
, value: "true"
};
const inputAnswerOpt3: InputAnswerOptions = {
idInput: 20
, placement: 0
, placement: 1
, value: "true"
};
const inputAnswerOpt4: InputAnswerOptions = {
idInput: 21
, placement: 1
, placement: 0
, value: "true"
};
const inputAnswerOpt5: InputAnswerOptions = {
idInput: 22
, placement: 0
, value: "Answer question 5 form 6"
};
const inputAnswerOptionsDict: InputAnswerOptionsDict = {
18: [
inputAnswerOpt1
......@@ -309,6 +315,7 @@ describe("Validation Handler", () => {
, 19: [inputAnswerOpt2]
, 20: [inputAnswerOpt3]
, 21: [inputAnswerOpt4]
, 22: [inputAnswerOpt5]
};
dbhandler.form.read(6, (error: Error, form: Form) => {
......@@ -325,6 +332,7 @@ describe("Validation Handler", () => {
expect(e.validationDict["19"]).to.be.undefined;
expect(e.validationDict["20"]).to.be.undefined;
expect(e.validationDict["21"]).to.be.undefined;
expect(e.validationDict["22"]).to.be.equal("Must answer question with id 18 and placement 2");
}
done();
});
......
......@@ -96,13 +96,13 @@ export class ValidationHandler {
* @returns - true if has at minimum one checkbox marked, else false.
*/
private static validateSomeCheckbox(input: Input, inputAnswers: InputAnswerDict): boolean {
let booll: boolean = false;
let result: boolean = false;
for (const answer of inputAnswers[input.id]) {
if ((answer.value === "true") && this.inputSugestionExists(input, answer.placement)) {
booll = true;
result = true;
}
}
return booll;
return result;
}
/**
......@@ -112,15 +112,22 @@ export class ValidationHandler {
* @returns - True if sugestion exists, else false.
*/
private static inputSugestionExists(input: Input, placement: number): boolean {
let booll: boolean = false;
let result: boolean = false;
for (const sugestion of input.sugestions) {
if (sugestion.placement === placement) {
booll = true;
result = true;
}
}
return booll;
return result;
}
/**
* Validate if a input has a minimum number of answers.
* @param inputAnswers - Dictionary of InputAnswers to be verified.
* @param id - Input to be searched.
* @param argument - Max number of answers.
* @returns - True if has minimum answers, else false.
*/
private static validateMaxAnswers(inputAnswers: InputAnswerDict, id: number, argument: string): boolean {
const max: number = parseInt(argument, 10);
// Verify if argument is an integer
......@@ -131,6 +138,25 @@ export class ValidationHandler {
}
}
/**
* Validate if exists a answer for a dependent input.
* @param inputAnswers - Dictionary of InputAnswers to be verified.
* @param argument - Placement of the dependent input.
* @returns - True if the input was answered, else false.
*/
private static validateDependency(inputAnswers: InputAnswer[], argument: string): boolean {
let result: boolean = false;
const placement: number = parseInt(argument, 10);
if (!(isNaN(placement))) {
for (const inputAnswer of inputAnswers) {
if (inputAnswer.placement === placement) {
result = (inputAnswer.value === "true");
}
}
}
return result;
}
/**
* Validate if answer has minimum number of chars.
* @param input - Input to validate answer.
......@@ -195,6 +221,13 @@ export class ValidationHandler {
errors.push("Number of input answers must be lower than " + validation.arguments[0]);
}
break;
case ValidationType.DEPENDENCY:
const id: number = parseInt(validation.arguments[0], 10);
if (!(isNaN(id)) && !(this.validateDependency(inputAnswers[id], validation.arguments[1]))) {
errors.push("Must answer question with id " + validation.arguments[0] + " and placement " + validation.arguments[1]);
}
break;
}
}
......
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