"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const validateAnswers_1 = require("../src/validateAnswers");
const parseExam_1 = __importDefault(require("../src/parser/parseExam"));
const parseExamStructure_1 = require("../src/parser/parseExamStructure");
const exam_engine_generator_1 = require("@digabi/exam-engine-generator");
const exam_engine_mastering_1 = require("@digabi/exam-engine-mastering");
const _ = __importStar(require("lodash"));
let examStructure;
let gradingStructure;
beforeAll(async () => {
    const exam = (0, exam_engine_generator_1.generateExam)({
        maxAnswers: 2,
        sections: [
            {
                questions: [
                    (0, exam_engine_generator_1.question)([(0, exam_engine_generator_1.textAnswer)({ maxLength: 3 })]),
                    (0, exam_engine_generator_1.question)({ questions: [(0, exam_engine_generator_1.question)([(0, exam_engine_generator_1.textAnswer)({ maxLength: 3 })]), (0, exam_engine_generator_1.question)([(0, exam_engine_generator_1.textAnswer)()])] })
                ]
            },
            {
                maxAnswers: 1,
                questions: [
                    (0, exam_engine_generator_1.question)([(0, exam_engine_generator_1.textAnswer)()]),
                    (0, exam_engine_generator_1.question)({ maxAnswers: 1, questions: [(0, exam_engine_generator_1.question)([(0, exam_engine_generator_1.textAnswer)()]), (0, exam_engine_generator_1.question)([(0, exam_engine_generator_1.textAnswer)()])] })
                ]
            }
        ]
    });
    const [masteringResult] = await (0, exam_engine_mastering_1.masterExam)(exam, () => '', () => {
        throw new Error('Boom!');
    });
    examStructure = (0, parseExamStructure_1.parseExamStructure)((0, parseExam_1.default)(masteringResult.xml));
    gradingStructure = masteringResult.gradingStructure;
});
describe('Answer length validation', () => {
    it('returns an error if answer is too long', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestionsWithText('too long', '1'))).toEqual([
            {
                displayNumber: '1',
                type: 'AnswerTooLong',
                characterCount: 8,
                elementType: 'question'
            }
        ]);
    });
    it('returns multiple errors if multiple answers are too long', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestionsWithText('too long', '1', '2.1'))).toEqual([
            {
                displayNumber: '1',
                type: 'AnswerTooLong',
                characterCount: 8,
                elementType: 'question'
            },
            {
                displayNumber: '2.1',
                type: 'AnswerTooLong',
                characterCount: 8,
                elementType: 'question'
            }
        ]);
    });
    it('does not return errors if answer is short enough', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestionsWithText('ok', '1'))).toEqual([]);
    });
});
describe('Extra answers validation', () => {
    it('returns an empty array if answer combinations are valid, nonempty if invalid', () => {
        const allAnswerCombinations = subsets(['1', '2.1', '2.2', '3', '4.1', '4.2']);
        const validAnswerCombinations = [
            // No answers
            [],
            // 1 answer in 1st section
            ['1'],
            ['2.1'],
            ['2.2'],
            ['2.1', '2.2'],
            // 1 answer in 2nd section
            ['3'],
            ['4.1'],
            ['4.2'],
            // 2 answers in 1st section
            ['1', '2.1'],
            ['1', '2.2'],
            ['1', '2.1', '2.2'],
            // 1 answer in both sections
            ['1', '3'],
            ['2.1', '3'],
            ['2.2', '3'],
            ['2.1', '2.2', '3'],
            ['1', '4.1'],
            ['2.1', '4.1'],
            ['2.2', '4.1'],
            ['2.1', '2.2', '4.1'],
            ['1', '4.2'],
            ['2.1', '4.2'],
            ['2.2', '4.2'],
            ['2.1', '2.2', '4.2']
        ];
        const invalidAnswerCombinations = _.differenceWith(allAnswerCombinations, validAnswerCombinations, _.isEqual);
        for (const questions of validAnswerCombinations) {
            expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions(...questions))).toEqual([]);
        }
        for (const questions of invalidAnswerCombinations) {
            expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions(...questions))).not.toEqual([]);
        }
    });
    it('returns an error if question has too many answers', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions('4.1', '4.2'))).toEqual([
            {
                childQuestions: ['4.1', '4.2'],
                displayNumber: '4',
                maxAnswers: 1,
                minAnswers: undefined,
                elementType: 'question',
                type: 'ExtraAnswer'
            }
        ]);
    });
    it('returns an error if section has too many answers', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions('3', '4.1'))).toEqual([
            {
                childQuestions: ['3', '4'],
                displayNumber: '2',
                maxAnswers: 1,
                minAnswers: 0,
                elementType: 'section',
                type: 'ExtraAnswer'
            }
        ]);
    });
    it('returns an error if exam has too many answers', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions('1', '2.1', '3'))).toEqual([
            {
                childQuestions: ['1', '2'],
                displayNumber: '',
                maxAnswers: 2,
                minAnswers: undefined,
                elementType: 'exam',
                type: 'ExtraAnswer'
            }
        ]);
    });
    it('returns two errors if both exam and section have too many answers', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions('1', '3', '4.1'))).toEqual([
            {
                childQuestions: ['1', '2'],
                displayNumber: '',
                maxAnswers: 2,
                minAnswers: undefined,
                elementType: 'exam',
                type: 'ExtraAnswer'
            },
            {
                childQuestions: ['3', '4'],
                displayNumber: '2',
                maxAnswers: 1,
                minAnswers: 0,
                elementType: 'section',
                type: 'ExtraAnswer'
            }
        ]);
    });
    it('returns three errors if exam, section and question have too many answers', () => {
        expect((0, validateAnswers_1.validateAnswers)(examStructure, answerQuestions('1', '3', '4.1', '4.2'))).toEqual([
            {
                childQuestions: ['1', '2'],
                displayNumber: '',
                maxAnswers: 2,
                minAnswers: undefined,
                elementType: 'exam',
                type: 'ExtraAnswer'
            },
            {
                childQuestions: ['3', '4'],
                displayNumber: '2',
                maxAnswers: 1,
                minAnswers: 0,
                elementType: 'section',
                type: 'ExtraAnswer'
            },
            {
                childQuestions: ['4.1', '4.2'],
                displayNumber: '4',
                maxAnswers: 1,
                minAnswers: undefined,
                elementType: 'question',
                type: 'ExtraAnswer'
            }
        ]);
    });
});
const answerQuestions = (...displayNumbers) => answerQuestionsWithText('foo', ...displayNumbers);
const answerQuestionsWithText = (text, ...displayNumbers) => {
    const findQuestionId = (displayNumber) => gradingStructure.questions.find(q => q.displayNumber === displayNumber).id;
    const createAnswer = (questionId) => ({
        questionId,
        type: 'text',
        value: text,
        characterCount: text.length
    });
    const questionIds = displayNumbers.map(findQuestionId);
    const answers = questionIds.map(createAnswer);
    return _.zipObject(questionIds, answers);
};
const subsets = (array) => array.reduce((subsets, value) => subsets.concat(subsets.map(set => [...set, value])), [[]]);
//# sourceMappingURL=validateAnswers.test.js.map