diff --git a/.Jenkinsfile b/.Jenkinsfile new file mode 100644 index 00000000..da96dfe5 --- /dev/null +++ b/.Jenkinsfile @@ -0,0 +1,34 @@ +pipeline { + agent { + label 'master' + } + stages { + stage('Frontend Tests') { + agent { + docker { + image 'btamas/puppeteer-git' + reuseNode true + } + } + environment { + HOME = '.' + PARALLEL_TESTS = 2 + } + options { + skipDefaultCheckout() + } + steps { + dir('.') { + sh( + label: 'Setup frontend toolchain', + script: 'npm install' + ) + sh ( + label : 'Run frontend tests', + script: 'npm run test' + ) + } + } + } + } +} \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..5905ed96 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,71 @@ +{ + "env" : { + "browser" : true, + "es6" : true, + "qunit" : true, + "node" : true + }, + "globals" : { + "ENVIRONMENT" : true + }, + "plugins" : ["es", "jsdoc"], + "parserOptions" : { + "sourceType" : "module", + "ecmaVersion" : 2015 + }, + "extends" : "eslint:recommended", + "rules" : { + "array-bracket-newline" : ["warn", "consistent"], + "arrow-body-style" : ["error", "as-needed"], + "arrow-spacing" : ["warn", { "before" : true, "after" : true }], + "brace-style" : ["warn", "1tbs"], + "consistent-this" : ["error", "self"], + "eqeqeq" : ["error", "smart"], + "es/no-classes" : ["error"], + "es/no-generators" : ["error"], + "func-call-spacing" : ["error"], + "implicit-arrow-linebreak" : ["error"], + "indent" : ["warn", 4, { "SwitchCase" : 1, "MemberExpression" : "off" }], + "jsdoc/check-alignment" : ["warn"], + "jsdoc/check-param-names" : ["warn"], + "jsdoc/require-param" : ["warn"], + "jsdoc/require-param-name" : ["warn"], + "jsdoc/require-param-type" : ["warn"], + "jsdoc/require-returns" : ["warn"], + "jsdoc/require-returns-check" : ["warn"], + "jsdoc/require-returns-type" : ["warn"], + "linebreak-style" : ["error", "unix"], + "new-parens" : ["error"], + "no-alert" : ["error"], + "no-caller" : ["error"], + "no-confusing-arrow" : ["error", { "allowParens" : false }], + "no-console" : ["error"], + "no-debugger" : ["error"], + "no-duplicate-imports" : ["error"], + "no-eval" : ["error"], + "no-extend-native" : ["error"], + "no-extra-bind" : ["error"], + "no-implicit-globals" : ["error"], + "no-implied-eval" : ["error"], + "no-lone-blocks" : ["error"], + "no-multi-assign" : ["error"], + "no-new-func" : ["error"], + "no-script-url" : ["error"], + "no-self-compare" : ["error"], + "no-sequences" : ["error"], + "no-shadow" : ["error", { "hoist" : "functions" }], + "no-template-curly-in-string" : ["error"], + "no-throw-literal" : ["error"], + "no-trailing-spaces" : ["error"], + "no-undefined" : ["error"], + "no-use-before-define" : ["error", { "functions" : false }], + "no-useless-call" : ["error"], + "no-useless-computed-key" : ["error"], + "no-useless-rename" : ["error"], + "prefer-rest-params" : ["error"], + "prefer-spread" : ["error"], + "prefer-template" : ["error"], + "semi" : ["error", "always"], + "vars-on-top" : ["error"] + } + } \ No newline at end of file diff --git a/.gitignore b/.gitignore index ad46b308..e4f46fda 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,5 @@ typings/ # next.js build output .next + +dist diff --git a/README.md b/README.md new file mode 100644 index 00000000..1bce6dc0 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# tao-item-runner-qti-fe + +QTI Item Runner frontend library of TAO. + +Available scripts in the project: + +- `HOST= PORT= npm run test `: run test suite + - `HOST` (optional environment variable, default: 127.0.0.1): Test server listen host + - `PORT` (optional environment variable, default: 8082): Test server listen port + - `testname` (optional): Specific test to run. If it is not provided, all will be ran. +- `HOST= PORT= npm run test:keepAlive`: start test server + - `HOST` (optional environment variable, default: 127.0.0.1): Test server listen host + - `PORT` (optional environment variable, default: 8082): Test server listen port +- `npm run build`: build for production into `dist` directory +- `npm run build:watch`: build for production into `dist` directory and watch for changes +- `npm run lint`: check syntax of code diff --git a/build/external-alias.js b/build/external-alias.js new file mode 100644 index 00000000..1ef432e4 --- /dev/null +++ b/build/external-alias.js @@ -0,0 +1,31 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA ; + */ + +export default (externals = []) => ({ + name: 'external-alias', // this name will show up in warnings and errors + resolveId(source, importer) { + if (importer && externals.find(external => source.startsWith(external))) { + return { + id: source, + external: true, + moduleSideEffects: true + }; + } + return null; // other ids should be handled as usually + } +}); diff --git a/build/path.js b/build/path.js new file mode 100644 index 00000000..a3cee063 --- /dev/null +++ b/build/path.js @@ -0,0 +1,33 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA ; + */ + +/** + * This file contains path definitions for build scripts. + */ +const path = require('path'); +const rootPath = path.resolve(__dirname, '..'); +const srcDir = path.resolve(rootPath, 'src'); + +module.exports = { + rootPath, + srcDir, + testDir: path.resolve(rootPath, 'test'), + outputDir: path.resolve(rootPath, 'dist'), + testOutputDir: path.resolve(rootPath, 'test'), + aliases: { taoQtiItem: srcDir, build: path.resolve(rootPath, 'build') } +}; diff --git a/build/rollup.config.js b/build/rollup.config.js new file mode 100644 index 00000000..46e02808 --- /dev/null +++ b/build/rollup.config.js @@ -0,0 +1,144 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA ; + */ + +import path from 'path'; +import glob from 'glob'; +import alias from 'rollup-plugin-alias'; +import handlebarsPlugin from 'rollup-plugin-handlebars-plus'; +import externalAlias from './external-alias'; +import resolve from 'rollup-plugin-node-resolve'; +import json from 'rollup-plugin-json'; + +const { srcDir, outputDir, aliases } = require('./path'); +const Handlebars = require('handlebars'); + +/** + * Support of handlebars 1.3.0 + * TODO remove once migrated to hbs >= 3.0.0 + */ +const originalVisitor = Handlebars.Visitor; +Handlebars.Visitor = function() { + return originalVisitor.call(this); +}; +Handlebars.Visitor.prototype = Object.create(originalVisitor.prototype); +Handlebars.Visitor.prototype.accept = function() { + try { + originalVisitor.prototype.accept.apply(this, arguments); + } catch (e) {} +}; +/* --------------------------------------------------------- */ + +const inputs = glob.sync(path.join(srcDir, '**', '*.js')); + +/** + * Define all modules as external, so rollup won't bundle them together. + */ +const localExternals = inputs.map( + input => + `taoQtiItem/${path + .relative(srcDir, input) + .replace(/\\/g, '/') + .replace(/\.js$/, '')}` +); + +export default inputs.map(input => { + const name = path.relative(srcDir, input).replace(/\.js$/, ''); + const dir = path.dirname(path.relative(srcDir, input)); + + return { + input, + output: { + dir: path.join(outputDir, dir), + format: 'amd', + name + }, + external: [ + 'jquery', + 'lodash', + 'handlebars', + 'i18n', + 'module', + 'context', + 'async', + 'require', + + 'raphael', + 'scale.raphael', + 'lib/gamp/gamp', + 'class', + 'mathJax', + 'nouislider', + 'interact', + 'select2', + 'ckeditor', + 'iframeNotifier', + + 'qtiInfoControlContext', + 'qtiCustomInteractionContext', + + ...localExternals + ], + plugins: [ + externalAlias([ + 'core', + 'util', + 'ui', + 'lib', + 'taoItems/runner', + 'taoItems/assets', + 'taoItems/scoring', + 'taoQtiItem/portableElementRegistry' + ]), + alias({ + resolve: ['.js', '.json', '.tpl'], + ...aliases + }), + resolve(), + handlebarsPlugin({ + handlebars: { + id: 'handlebars', + options: { + sourceMap: false + }, + module: Handlebars + }, + helpers: ['build/tpl.js'], + templateExtension: '.tpl' + }), + json({ + preferConst: false + }), + /** + * The following hack is necessary because expressions.js wants to export an object + * containing a key named 'default', and expressions/engine.js needs to import the whole thing. + * By omitting a line from Rollup's generated bundle, we can preserve the full object. + */ + { + name: 'expressions_helper', + generateBundle(options, bundle) { + if (options.name.match(/expressions[\/\\]engine/)) { + bundle['engine.js'].code = bundle['engine.js'].code.replace( + /expressionProcessors\.hasOwnProperty\('default'\)/, + false + ); + } + } + } + ] + }; +}); diff --git a/build/testrunner.js b/build/testrunner.js new file mode 100644 index 00000000..e0f129d7 --- /dev/null +++ b/build/testrunner.js @@ -0,0 +1,79 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA ; + */ + +const glob = require('glob'); +const path = require('path'); +const { runQunitPuppeteer, printResultSummary, printFailedTests } = require('node-qunit-puppeteer'); +const promiseLimit = require('promise-limit'); + +const webServer = require('./webserver'); + +const { testDir } = require('./path'); + +const TESTNAME = process.argv[2] || '*'; + +let hasFailed = false; +const limit = promiseLimit(process.env.PARALLEL_TESTS || 5); + +webServer.then(({ host, port }) => + Promise.all( + glob.sync(path.join(testDir, '**', TESTNAME, '**', 'test.html')).map(testFile => { + const test = path.relative(testDir, testFile); + const qunitArgs = { + // Path to qunit tests suite + targetUrl: `http://${host}:${port}/test/${test}`, + // (optional, 30000 by default) global timeout for the tests suite + timeout: 30000, + // (optional, false by default) should the browser console be redirected or not + redirectConsole: false, + puppeteerArgs: [ + '--no-sandbox', + '--disable-gpu', + '--disable-popup-blocking', + '--autoplay-policy=no-user-gesture-required' + ] + }; + + return limit(() => + runQunitPuppeteer(qunitArgs) + .then(result => { + if (TESTNAME === '*') { + process.stdout.write('.'); + } else { + process.stdout.write(`${testFile} `); + printResultSummary(result, console); + console.log(); + } + + if (result.stats.failed > 0) { + console.log(`\n${testFile}`); + printFailedTests(result, console); + hasFailed = true; + } + }) + .catch(ex => { + console.error(testFile); + console.error(ex); + }) + ); + }) + ).then(() => { + console.log(); + process.exit(hasFailed ? -1 : 0); + }) +); diff --git a/build/tpl.js b/build/tpl.js new file mode 100644 index 00000000..d1f226b3 --- /dev/null +++ b/build/tpl.js @@ -0,0 +1,126 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2013-2019 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); + * + * + */ +/** + * ORGINAL VERSION: + * https://github.com/epeli/requirejs-hbs + * Copyright 2013 Esa-Matti Suuronen + * MIT License : https://github.com/epeli/requirejs-hbs/blob/master/LICENSE + * + * MODIFIED VERSION: + * @author Bertrand Chevrier for OAT SA + * - Minor code refactoring + * - i18n helper has been added + * - dompurify helper has been added + */ + +import __ from 'i18n'; +import _ from 'lodash'; +import DOMPurify from 'lib/dompurify/purify'; + +export default hb => { + //register a i18n helper + hb.registerHelper('__', function(key) { + return __(key); + }); + + /** + * Register dompurify helper + * + * https://github.com/cure53/DOMPurify + * with config SAFE_FOR_TEMPLATES: true + * to make output safe for template systems + */ + hb.registerHelper('dompurify', function(context) { + return DOMPurify.sanitize(context); + }); + + /** + * Register join helper + * + * Example : + * var values = {a:v1, b:v2, c:v3}; + * Using {{{join attributes '=' ' ' '"'}}} will return : a="v1" b="v2" c="v3" + * Using {{{join values null ' or ' '*'}}} will return : *v1* or *v2* or *v3* + */ + hb.registerHelper('join', function(arr, keyValueGlue, fragmentGlue, wrapper) { + var fragments = []; + + keyValueGlue = typeof keyValueGlue === 'string' ? keyValueGlue : undefined; + fragmentGlue = typeof fragmentGlue === 'string' ? fragmentGlue : ' '; + wrapper = typeof wrapper === 'string' ? wrapper : '"'; + + _.forIn(arr, function(value, key) { + var fragment = ''; + if (value !== null || value !== undefined) { + if (typeof value === 'boolean') { + value = value ? 'true' : 'false'; + } else if (typeof value === 'object') { + value = _.values(value).join(' '); + } + } else { + value = ''; + } + if (keyValueGlue !== undefined) { + fragment += key + keyValueGlue; + } + fragment += wrapper + value + wrapper; + fragments.push(fragment); + }); + + return fragments.join(fragmentGlue); + }); + + //register a classic "for loop" helper + //it also adds a local variable "i" as the index in each iteration loop + hb.registerHelper('for', function(startIndex, stopIndex, increment, options) { + var ret = ''; + startIndex = parseInt(startIndex); + stopIndex = parseInt(stopIndex); + increment = parseInt(increment); + + for (var i = startIndex; i < stopIndex; i += increment) { + ret += options.fn(_.extend({}, this, { i: i })); + } + + return ret; + }); + + hb.registerHelper('equal', function(var1, var2, options) { + if (var1 == var2) { + return options.fn(this); + } else { + return options.inverse(this); + } + }); + + // register a "get property" helper + // it gets the named property from the provided context + hb.registerHelper('property', function(name, context) { + return context[name] || ''; + }); + + // register an 'includes' helper + // it checks if value is in array + hb.registerHelper('includes', function(haystack, needle, options) { + if (_.contains(haystack, needle)) { + return options.fn(this); + } + }); +}; diff --git a/build/webserver.js b/build/webserver.js new file mode 100644 index 00000000..e057cbcb --- /dev/null +++ b/build/webserver.js @@ -0,0 +1,54 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA ; + */ + +const HttpServer = require('http-server'); +const fs = require('fs'); +const path = require('path'); + +const HOST = process.env.HOST || '127.0.0.1'; +const PORT = process.env.PORT || '8082'; +const ROOT = path.resolve(__dirname, '..'); + +module.exports = new Promise(resolve => + new HttpServer.createServer({ + root: ROOT, + cache: -1, + before: [ + (req, res) => { + if (req.method === 'POST') { + res.writeHead(200, { 'Content-Type': 'application/json' }); + fs.readFile(path.join(__dirname, '..', req.url), (err, data) => { + if (err) throw err; + res.end(data.toString()); + }); + } else { + res.emit('next'); + } + } + ] + }).listen(PORT, HOST, err => { + if (err) { + console.log(err); + process.exit(-1); + } + + console.log(`Server is listening on http://${HOST}:${PORT}/ and serving ${ROOT}`); + + resolve({ host: HOST, port: PORT }); + }) +); diff --git a/environment/config.js b/environment/config.js new file mode 100644 index 00000000..66737283 --- /dev/null +++ b/environment/config.js @@ -0,0 +1,105 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA ; + */ + +requirejs.config({ + baseUrl: '/', + paths: { + css: '/node_modules/require-css/css', + json: '/node_modules/requirejs-plugins/src/json', + text: '/node_modules/requirejs-plugins/lib/text', + + /* TEST related */ + 'qunit-parameterize': '/environment/qunit2-parameterize', + 'qunit-assert-close': '/node_modules/qunit-assert-close/qunit-assert-close', + qunit: '/node_modules/qunit/qunit/qunit', + qunitStyle: '/node_modules/qunit/qunit/qunit', + 'taoQtiItem/test': '/test', + + taoQtiItem: '/dist', + core: '/node_modules/@oat-sa/tao-core-sdk/dist/core', + util: '/node_modules/@oat-sa/tao-core-sdk/dist/util', + ui: '/node_modules/@oat-sa/tao-core-ui/dist', + lib: '/node_modules/@oat-sa/tao-core-libs/dist', + 'taoItems/runner': '/node_modules/@oat-sa/tao-item-runner/dist/runner', + 'taoItems/assets': '/node_modules/@oat-sa/tao-item-runner/dist/assets', + 'taoItems/scoring': '/node_modules/@oat-sa/tao-item-runner/dist/scoring', + jquery: '/node_modules/jquery/jquery', + lodash: '/node_modules/lodash/lodash', + moment: '/node_modules/moment/min/moment-with-locales', + handlebars: '/node_modules/handlebars/dist/handlebars.amd', + + /* LIBS */ + 'lib/popper/tooltip': '/node_modules/tooltip.js/dist/umd/tooltip', + popper: '/node_modules/popper.js/dist/umd/popper', + select2: '/node_modules/select2/select2', + interact: '/node_modules/interactjs/dist/interact', + 'lib/dompurify/purify': '/node_modules/dompurify/dist/purify', + 'lib/gamp/gamp': '/node_modules/gamp/src/gamp', + 'lib/simulator': '/lib/simulator', + iframeNotifier: '/lib/iframeNotifier', + class: 'lib/class', + async: '/node_modules/async/lib/async', + nouislider: '/lib/sliders/jquery.nouislider', + ckeditor: '/lib/ckeditor/ckeditor', + raphael: '/node_modules/raphael/raphael', + 'scale.raphael': '/lib/raphael/scale.raphael' + /* LIBS END */ + }, + shim: { + 'qunit-parameterize': { + deps: ['qunit'] + }, + 'qunit-assert-close': { + deps: ['qunit'] + }, + ckeditor: { + exports: 'CKEDITOR' + } + }, + waitSeconds: 15 +}); + +define('qunitLibs', ['qunit', 'css!qunitStyle']); +define('qunitEnv', ['qunitLibs', 'qunit-parameterize'], function() { + requirejs.config({ nodeIdCompat: true }); +}); + +define('context', ['module'], function(module) { + return module.config(); +}); + +define('i18n', [], () => text => text); + +define('taoQtiItem/portableElementRegistry/ciRegistry', [], () => ({ + resetProviders() { + throw new Error('Not implemented'); + }, + registerProvider() { + throw new Error('Not implemented'); + } +})); +define('taoQtiItem/portableElementRegistry/icRegistry', [], () => ({ + resetProviders() { + throw new Error('Not implemented'); + }, + registerProvider() { + throw new Error('Not implemented'); + } +})); +define('taoQtiItem/portableElementRegistry/provider/sideLoadingProviderFactory', [], () => {}); +define('taoQtiItem/portableElementRegistry/assetManager/portableAssetStrategy', [], () => {}); diff --git a/environment/qunit2-parameterize.js b/environment/qunit2-parameterize.js new file mode 100644 index 00000000..21f4384e --- /dev/null +++ b/environment/qunit2-parameterize.js @@ -0,0 +1,172 @@ +/* + * Parameterize v 0.4 + * A QUnit Addon For Running Parameterized Tests + * https://github.com/AStepaniuk/qunit-parameterize + * Released under the MIT license. + */ +QUnit.extend(QUnit, { + cases: (function() { + 'use strict'; + var currentCases = null, + clone = function(testCase) { + var result = {}, + p = null; + + for (p in testCase) { + if (testCase.hasOwnProperty(p)) { + result[p] = testCase[p]; + } + } + + return result; + }, + + createTest = function(methodName, title, callback, parameters) { + + QUnit[methodName](title, function(assert) { + return callback.call(this, parameters, assert); + }); + }, + + iterateTestCases = function(methodName, title, callback) { + var i = 0, + parameters = null, + testCaseTitle = null; + + if (!currentCases || currentCases.length === 0) { + // setup test which will always fail + QUnit.test(title, function(assert) { + assert.ok(false, "No test cases are provided"); + }); + return; + } + + for (i = 0; i < currentCases.length; i += 1) { + parameters = currentCases[i]; + + testCaseTitle = title; + if (parameters.title) { + testCaseTitle += "[" + parameters.title + "]"; + } + + if (parameters._skip === true) { + methodName = 'skip'; + } + + createTest(methodName, testCaseTitle, callback, parameters); + } + }, + + getLength = function(arr) { + return arr ? arr.length : 0; + }, + + getItem = function(arr, idx) { + return arr ? arr[idx] : undefined; + }, + + mix = function(testCase, mixData) { + var result = null, + p = null; + + if (testCase && mixData) { + result = clone(testCase); + + for (p in mixData) { + if (mixData.hasOwnProperty(p)) { + if (p !== "title") { + if (!(result.hasOwnProperty(p))) { + result[p] = mixData[p]; + } + } else { + result[p] = [result[p], mixData[p]].join(""); + } + } + } + + } else if (testCase) { + result = testCase; + } else if (mixData) { + result = mixData; + } else { + // return null or undefined whatever testCase is + result = testCase; + } + + return result; + }; + + return { + + init: function(testCasesList) { + currentCases = testCasesList; + return this; + }, + + sequential: function(addData) { + var casesLength = getLength(currentCases), + addDataLength = getLength(addData), + length = casesLength > addDataLength ? casesLength : addDataLength, + newCases = [], + i = 0, + currentCaseI = null, + dataI = null, + newCase = null; + + for (i = 0; i < length; i += 1) { + currentCaseI = getItem(currentCases, i); + dataI = getItem(addData, i); + newCase = mix(currentCaseI, dataI); + + if (newCase) { + newCases.push(newCase); + } + } + + currentCases = newCases; + + return this; + }, + + combinatorial: function(mixData) { + var current = (currentCases && currentCases.length > 0) ? currentCases : [null], + currentLength = current.length, + mixDataLength = 0, + newCases = [], + i = 0, + j = 0, + currentCaseI = null, + dataJ = null, + newCase = null; + + mixData = (mixData && mixData.length > 0) ? mixData : [null]; + mixDataLength = mixData.length; + + for (i = 0; i < currentLength; i += 1) { + for (j = 0; j < mixDataLength; j += 1) { + currentCaseI = current[i]; + dataJ = mixData[j]; + newCase = mix(currentCaseI, dataJ); + + if (newCase) { + newCases.push(newCase); + } + } + } + + currentCases = newCases; + + return this; + }, + + test: function(title, callback) { + iterateTestCases("test", title, callback); + return this; + }, + + getCurrentTestCases: function () { + return currentCases; + } + }; + }()) +}); \ No newline at end of file diff --git a/environment/require.js b/environment/require.js new file mode 100644 index 00000000..acd22384 --- /dev/null +++ b/environment/require.js @@ -0,0 +1,2145 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors. + * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, setTimeout, opera */ + +var requirejs, require, define; +(function (global, setTimeout) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.3.6', + commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + //Could match something like ')//comment', do not lose the prefix to comment. + function commentReplace(match, singlePrefix) { + return singlePrefix || ''; + } + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value === 'object' && value && + !isArray(value) && !isFunction(value) && + !(value instanceof RegExp)) { + + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + function defaultOnError(err) { + throw err; + } + + //Allow getting a global that is expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttps://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite an existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + //Defaults. Do not set a default for map + //config to speed up normalize(), which + //will run faster if there is no default. + waitSeconds: 7, + baseUrl: './', + paths: {}, + bundles: {}, + pkgs: {}, + shim: {}, + config: {} + }, + registry = {}, + //registry of just enabled modules, to speed + //cycle breaking code when lots of modules + //are registered, but not activated. + enabledRegistry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + bundlesMap = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; i < ary.length; i++) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + // If at the start, or previous value is still .., + // keep them so that when converted to a path it may + // still work when converted to a path, even though + // as an ID it is less than ideal. In larger point + // releases, may be better to just kick out an error. + if (i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1] === '..') { + continue; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, + foundMap, foundI, foundStarMap, starI, normalizedBaseParts, + baseParts = (baseName && baseName.split('/')), + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name) { + name = name.split('/'); + lastIndex = name.length - 1; + + // If wanting node ID compatibility, strip .js from end + // of IDs. Have to do this here, and not in nameToUrl + // because node allows either .js or non .js to map + // to same file. + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + // Starts with a '.' so need the baseName + if (name[0].charAt(0) === '.' && baseParts) { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + name = normalizedBaseParts.concat(name); + } + + trimDots(name); + name = name.join('/'); + } + + //Apply map config if available. + if (applyMap && map && (baseParts || starMap)) { + nameParts = name.split('/'); + + outerLoop: for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break outerLoop; + } + } + } + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + // If the name points to a package's name, use + // the package main instead. + pkgMain = getOwn(config.pkgs, name); + + return pkgMain ? pkgMain : name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + + //Custom require that does not do map translation, since + //ID is "absolute", already mapped/resolved. + context.makeRequire(null, { + skipMap: true + })([id]); + + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (isNormalized) { + normalizedName = name; + } else if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + // If nested plugin references, then do not try to + // normalize, as it will not normalize correctly. This + // places a restriction on resourceIds, and the longer + // term solution is not to normalize until plugins are + // loaded and all normalizations to allow for async + // loading of a loader plugin. But for now, fixes the + // common uses. Details in #1131 + normalizedName = name.indexOf('!') === -1 ? + normalize(name, parentName, applyMap) : + name; + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + mod = getModule(depMap); + if (mod.error && name === 'error') { + fn(mod.error); + } else { + mod.on(name, fn); + } + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + each(globalDefQueue, function(queueItem) { + var id = queueItem[0]; + if (typeof id === 'string') { + context.defQueueMap[id] = true; + } + defQueue.push(queueItem); + }); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return (defined[mod.map.id] = mod.exports); + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return getOwn(config.config, mod.map.id) || {}; + }, + exports: mod.exports || (mod.exports = {}) + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + delete enabledRegistry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(enabledRegistry, function (mod) { + var map = mod.map, + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks if the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + // Only fetch if not already in the defQueue. + if (!hasProp(context.defQueueMap, id)) { + this.fetch(); + } + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. However, + //only do it for define()'d modules. require + //errbacks should not be called for failures in + //their callbacks (#699). However if a global + //onError is set, use that. + if ((this.events.error && this.map.isDefine) || + req.onError !== defaultOnError) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + // Favor return value over exports. If node/cjs in play, + // then will not have a return value anyway. Favor + // module.exports assignment over exports object. + if (this.map.isDefine && exports === undefined) { + cjsModule = this.module; + if (cjsModule) { + exports = cjsModule.exports; + } else if (this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = this.map.isDefine ? [this.map.id] : null; + err.requireType = this.map.isDefine ? 'define' : 'require'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + var resLoadMaps = []; + each(this.depMaps, function (depMap) { + resLoadMaps.push(depMap.normalizedMap || depMap); + }); + req.onResourceLoad(context, this.map, resLoadMaps); + } + } + + //Clean up + cleanRegistry(id); + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + bundleId = getOwn(bundlesMap, this.map.id), + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap, + true); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.map.normalizedMap = normalizedMap; + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + //If a paths config, then just load that file instead to + //resolve the plugin, as it is built into that paths layer. + if (bundleId) { + this.map.url = context.nameToUrl(bundleId); + this.load(); + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + enabledRegistry[this.map.id] = this; + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + if (this.undefed) { + return; + } + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', bind(this, this.errback)); + } else if (this.events.error) { + // No direct errback on this module, but something + // else is listening for errors, so be sure to + // propagate the error correctly. + on(depMap, 'error', bind(this, function(err) { + this.emit('error', err); + })); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + context.defQueueMap = {}; + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + defQueueMap: {}, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + onError: onError, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + // Convert old style urlArgs string to a function. + if (typeof cfg.urlArgs === 'string') { + var urlArgs = cfg.urlArgs; + cfg.urlArgs = function(id, url) { + return (url.indexOf('?') === -1 ? '?' : '&') + urlArgs; + }; + } + + //Save off the paths since they require special processing, + //they are additive. + var shim = config.shim, + objs = { + paths: true, + bundles: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (!config[prop]) { + config[prop] = {}; + } + mixin(config[prop], value, true, true); + } else { + config[prop] = value; + } + }); + + //Reverse map the bundles + if (cfg.bundles) { + eachProp(cfg.bundles, function (value, prop) { + each(value, function (v) { + if (v !== prop) { + bundlesMap[v] = prop; + } + }); + }); + } + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location, name; + + pkgObj = typeof pkgObj === 'string' ? {name: pkgObj} : pkgObj; + + name = pkgObj.name; + location = pkgObj.location; + if (location) { + config.paths[name] = pkgObj.location; + } + + //Save pointer to main module ID for pkg name. + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, ''); + }); + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id, null, true); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap, localRequire); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var ext, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext, true); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + mod.undefed = true; + removeScript(id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + //Clean queued defines too. Go backwards + //in array so that the splices do not + //mess up the iteration. + eachReverse(defQueue, function(args, i) { + if (args[0] === id) { + defQueue.splice(i, 1); + } + }); + delete context.defQueueMap[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overridden by + * the optimizer. Not shown here to keep code compact. + */ + enable: function (depMap) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + context.defQueueMap = {}; + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext, skipExt) { + var paths, syms, i, parentModule, url, + parentPath, bundleId, + pkgMain = getOwn(config.pkgs, moduleName); + + if (pkgMain) { + moduleName = pkgMain; + } + + bundleId = getOwn(bundlesMap, moduleName); + + if (bundleId) { + return context.nameToUrl(bundleId, ext, skipExt); + } + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs && !/^blob\:/.test(url) ? + url + config.urlArgs(moduleName, url) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callback function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + var parents = []; + eachProp(registry, function(value, key) { + if (key.indexOf('_@r') !== 0) { + each(value.depMaps, function(depMap) { + if (depMap.id === data.id) { + parents.push(key); + return true; + } + }); + } + }); + return onError(makeError('scripterror', 'Script error for "' + data.id + + (parents.length ? + '", needed by: ' + parents.join(', ') : + '"'), evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = defaultOnError; + + /** + * Creates the node for the load command. Only used in browser envs. + */ + req.createNode = function (config, moduleName, url) { + var node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + return node; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = req.createNode(config, moduleName, url); + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/requirejs/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/requirejs/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEventListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //Calling onNodeCreated after all properties on the node have been + //set, but before it is placed in the DOM. + if (config.onNodeCreated) { + config.onNodeCreated(node, config, moduleName, url); + } + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + try { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation is that a build has been done so + //that only one script needs to be loaded anyway. This may need + //to be reevaluated if other use cases become common. + + // Post a task to the event loop to work around a bug in WebKit + // where the worker gets garbage-collected after calling + // importScripts(): https://webkit.org/b/153317 + setTimeout(function() {}, 0); + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } catch (e) { + context.onError(makeError('importscripts', + 'importScripts failed for ' + + moduleName + ' at ' + url, + e, + [moduleName])); + } + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser && !cfg.skipDataMain) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Preserve dataMain in case it is a path (i.e. contains '?') + mainScript = dataMain; + + //Set final baseUrl if there is not already an explicit one, + //but only do so if the data-main value is not a loader plugin + //module ID. + if (!cfg.baseUrl && mainScript.indexOf('!') === -1) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = mainScript.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + } + + //Strip off any trailing .js since mainScript is now + //like a module name. + mainScript = mainScript.replace(jsSuffixRegExp, ''); + + //If mainScript is still a path, fall back to dataMain + if (req.jsExtRegExp.test(mainScript)) { + mainScript = dataMain; + } + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = null; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps && isFunction(callback)) { + deps = []; + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, commentReplace) + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + if (context) { + context.defQueue.push([name, deps, callback]); + context.defQueueMap[name] = true; + } else { + globalDefQueue.push([name, deps, callback]); + } + }; + + define.amd = { + jQuery: true + }; + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this, (typeof setTimeout === 'undefined' ? undefined : setTimeout))); \ No newline at end of file diff --git a/lib/ckeditor/ckeditor.js b/lib/ckeditor/ckeditor.js new file mode 100644 index 00000000..1c0a8d75 --- /dev/null +++ b/lib/ckeditor/ckeditor.js @@ -0,0 +1,1224 @@ +/* +Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +(function(){if(!window.CKEDITOR||!window.CKEDITOR.dom)window.CKEDITOR||(window.CKEDITOR=function(){var a=/(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i,f={timestamp:"I9PC",version:"4.4.8 TAO-1",revision:"fa320b59f",rnd:Math.floor(900*Math.random())+100,_:{pending:[],basePathSrcPattern:a},status:"unloaded",basePath:function(){var b=window.CKEDITOR_BASEPATH||"";if(!b)for(var e=document.getElementsByTagName("script"),c=0;c=0;o--)if(k[o].priority<=d){k.splice(o+1,0,h);return{removeListener:f}}k.unshift(h)}return{removeListener:f}},once:function(){var a=Array.prototype.slice.call(arguments),b=a[1];a[1]=function(e){e.removeListener();return b.apply(this, +arguments)};return this.on.apply(this,a)},capture:function(){CKEDITOR.event.useCapture=1;var a=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return a},fire:function(){var a=0,b=function(){a=1},e=0,c=function(){e=1};return function(d,h,j){var k=f(this)[d],d=a,l=e;a=e=0;if(k){var o=k.listeners;if(o.length)for(var o=o.slice(0),n,m=0;m=0&&e.listeners.splice(c,1)}},removeAllListeners:function(){var a=f(this),b;for(b in a)delete a[b]},hasListeners:function(a){return(a=f(this)[a])&&a.listeners.length>0}}}()),CKEDITOR.editor||(CKEDITOR.editor=function(){CKEDITOR._.pending.push([this,arguments]);CKEDITOR.event.call(this)},CKEDITOR.editor.prototype.fire= +function(a,f){a in{instanceReady:1,loaded:1}&&(this[a]=true);return CKEDITOR.event.prototype.fire.call(this,a,f,this)},CKEDITOR.editor.prototype.fireOnce=function(a,f){a in{instanceReady:1,loaded:1}&&(this[a]=true);return CKEDITOR.event.prototype.fireOnce.call(this,a,f,this)},CKEDITOR.event.implementOn(CKEDITOR.editor.prototype)),CKEDITOR.env||(CKEDITOR.env=function(){var a=navigator.userAgent.toLowerCase(),f={ie:a.indexOf("trident/")>-1,webkit:a.indexOf(" applewebkit/")>-1,air:a.indexOf(" adobeair/")> +-1,mac:a.indexOf("macintosh")>-1,quirks:document.compatMode=="BackCompat"&&(!document.documentMode||document.documentMode<10),mobile:a.indexOf("mobile")>-1,iOS:/(ipad|iphone|ipod)/.test(a),isCustomDomain:function(){if(!this.ie)return false;var b=document.domain,a=window.location.hostname;return b!=a&&b!="["+a+"]"},secure:location.protocol=="https:"};f.gecko=navigator.product=="Gecko"&&!f.webkit&&!f.ie;if(f.webkit)a.indexOf("chrome")>-1?f.chrome=true:f.safari=true;var c=0;if(f.ie){c=f.quirks||!document.documentMode? +parseFloat(a.match(/msie (\d+)/)[1]):document.documentMode;f.ie9Compat=c==9;f.ie8Compat=c==8;f.ie7Compat=c==7;f.ie6Compat=c<7||f.quirks}if(f.gecko){var g=a.match(/rv:([\d\.]+)/);if(g){g=g[1].split(".");c=g[0]*1E4+(g[1]||0)*100+(g[2]||0)*1}}f.air&&(c=parseFloat(a.match(/ adobeair\/(\d+)/)[1]));f.webkit&&(c=parseFloat(a.match(/ applewebkit\/(\d+)/)[1]));f.version=c;f.isCompatible=f.iOS&&c>=534||!f.mobile&&(f.ie&&c>6||f.gecko&&c>=2E4||f.air&&c>=1||f.webkit&&c>=522||false);f.hidpi=window.devicePixelRatio>= +2;f.needsBrFiller=f.gecko||f.webkit||f.ie&&c>10;f.needsNbspFiller=f.ie&&c<11;f.cssClass="cke_browser_"+(f.ie?"ie":f.gecko?"gecko":f.webkit?"webkit":"unknown");if(f.quirks)f.cssClass=f.cssClass+" cke_browser_quirks";if(f.ie)f.cssClass=f.cssClass+(" cke_browser_ie"+(f.quirks?"6 cke_browser_iequirks":f.version));if(f.air)f.cssClass=f.cssClass+" cke_browser_air";if(f.iOS)f.cssClass=f.cssClass+" cke_browser_ios";if(f.hidpi)f.cssClass=f.cssClass+" cke_hidpi";return f}()),"unloaded"==CKEDITOR.status&&function(){CKEDITOR.event.implementOn(CKEDITOR); +CKEDITOR.loadFullCore=function(){if(CKEDITOR.status!="basic_ready")CKEDITOR.loadFullCore._load=1;else{delete CKEDITOR.loadFullCore;var a=document.createElement("script");a.type="text/javascript";a.src=CKEDITOR.basePath+"ckeditor.js";document.getElementsByTagName("head")[0].appendChild(a)}};CKEDITOR.loadFullCoreTimeout=0;CKEDITOR.add=function(a){(this._.pending||(this._.pending=[])).push(a)};(function(){CKEDITOR.domReady(function(){var a=CKEDITOR.loadFullCore,f=CKEDITOR.loadFullCoreTimeout;if(a){CKEDITOR.status= +"basic_ready";a&&a._load?a():f&&setTimeout(function(){CKEDITOR.loadFullCore&&CKEDITOR.loadFullCore()},f*1E3)}})})();CKEDITOR.status="basic_loaded"}(),CKEDITOR.dom={},function(){var a=[],f=CKEDITOR.env.gecko?"-moz-":CKEDITOR.env.webkit?"-webkit-":CKEDITOR.env.ie?"-ms-":"",c=/&/g,g=/>/g,b=/"+ +a+""):e.push('');return e.join("")},htmlEncode:function(a){return(""+a).replace(c,"&").replace(g,">").replace(b,"<")},htmlDecode:function(b){return b.replace(i,"&").replace(d,">").replace(h,"<")},htmlEncodeAttr:function(a){return a.replace(e,""").replace(b,"<").replace(g,">")},htmlDecodeAttr:function(b){return b.replace(j,'"').replace(h,"<").replace(d,">")},getNextNumber:function(){var b=0;return function(){return++b}}(), +getNextId:function(){return"cke_"+this.getNextNumber()},override:function(b,a){var e=a(b);e.prototype=b.prototype;return e},setTimeout:function(b,a,e,d,c){c||(c=window);e||(e=c);return c.setTimeout(function(){d?b.apply(e,[].concat(d)):b.apply(e)},a||0)},trim:function(){var b=/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;return function(a){return a.replace(b,"")}}(),ltrim:function(){var b=/^[ \t\n\r]+/g;return function(a){return a.replace(b,"")}}(),rtrim:function(){var b=/[ \t\n\r]+$/g;return function(a){return a.replace(b, +"")}}(),indexOf:function(b,a){if(typeof a=="function")for(var e=0,d=b.length;e=0?b[e]:null},bind:function(b,a){return function(){return b.apply(a,arguments)}},createClass:function(b){var a=b.$,e=b.base,d=b.privates||b._,c=b.proto,b=b.statics;!a&&(a=function(){e&&this.base.apply(this,arguments)});if(d)var i=a,a=function(){var b= +this._||(this._={}),a;for(a in d){var e=d[a];b[a]=typeof e=="function"?CKEDITOR.tools.bind(e,this):e}i.apply(this,arguments)};if(e){a.prototype=this.prototypedCopy(e.prototype);a.prototype.constructor=a;a.base=e;a.baseProto=e.prototype;a.prototype.base=function(){this.base=e.prototype.base;e.apply(this,arguments);this.base=arguments.callee}}c&&this.extend(a.prototype,c,true);b&&this.extend(a,b,true);return a},addFunction:function(b,e){return a.push(function(){return b.apply(e||this,arguments)})-1}, +removeFunction:function(b){a[b]=null},callFunction:function(b){var e=a[b];return e&&e.apply(window,Array.prototype.slice.call(arguments,1))},cssLength:function(){var b=/^-?\d+\.?\d*px$/,a;return function(e){a=CKEDITOR.tools.trim(e+"")+"px";return b.test(a)?a:e||""}}(),convertToPx:function(){var b;return function(a){if(!b){b=CKEDITOR.dom.element.createFromHtml('
',CKEDITOR.document);CKEDITOR.document.getBody().append(b)}if(!/%$/.test(a)){b.setStyle("width", +a);return b.$.clientWidth}return a}}(),repeat:function(b,a){return Array(a+1).join(b)},tryThese:function(){for(var b,a=0,e=arguments.length;a]*?>)|^/i, +'$&\n + + + +
+
+
+
+ +
+
+ + diff --git a/test/qtiCommonRenderer/interactions/associate/test.js b/test/qtiCommonRenderer/interactions/associate/test.js new file mode 100644 index 00000000..41a68a3b --- /dev/null +++ b/test/qtiCommonRenderer/interactions/associate/test.js @@ -0,0 +1,623 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/rivals.json', + 'ui/interactUtils' +], function($, _, qtiItemRunner, associateData, interactUtils) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('Associate Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correclty', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(21); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal($container.children('.qti-item').length, 1, 'the container contains a the root element .qti-item'); + assert.equal($container.find('.qti-itemBody').length, 1, 'the container contains a the body element .qti-itemBody'); + assert.equal($container.find('.qti-interaction').length, 1, 'the container contains an interaction .qti-interaction'); + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains a associate interaction .qti-associateInteraction'); + assert.equal($container.find('.qti-associateInteraction .qti-prompt-container').length, 1, 'the interaction contains a prompt'); + assert.equal($container.find('.qti-associateInteraction .instruction-container').length, 1, 'the interaction contains a instruction box'); + assert.equal($container.find('.qti-associateInteraction .choice-area').length, 1, 'the interaction contains a choice list'); + assert.equal($container.find('.qti-associateInteraction .qti-choice').length, 6, 'the interaction has 6 choices'); + assert.equal($container.find('.qti-associateInteraction .result-area').length, 1, 'the interaction has a result area'); + + //Check DOM data + assert.equal($container.children('.qti-item').data('identifier'), 'associate', 'the .qti-item node has the right identifier'); + + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(1)').data('identifier'), 'A', 'the 1st choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(2)').data('identifier'), 'C', 'the 2nd choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(3)').data('identifier'), 'D', 'the 3rd choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(4)').data('identifier'), 'L', 'the 4th choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(5)').data('identifier'), 'M', 'the 5th choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(6)').data('identifier'), 'P', 'the 6th choice has the right identifier'); + + assert.equal($container.find('.qti-associateInteraction .result-area').children().length, 3, 'the interaction has 3 pairs area according to maxAssocation'); + assert.equal($container.find('.qti-associateInteraction .result-area .target').length, 6, 'the interaction has 6 target box according to maxAssocation (3 pairs)'); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to activate a choice', function(assert) { + var ready = assert.async(); + assert.expect(11); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + var $antonio; + var $target; + + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains an associate interaction .qti-associateInteraction'); + + $antonio = $('.qti-choice[data-identifier="A"]', $container); + assert.equal($antonio.length, 1, "the A choice exists"); + + $target = $('.result-area .target', $container).first(); + assert.equal($target.length, 1, 'the target exists'); + + assert.ok(!$antonio.hasClass('active'), 'The choice is not active'); + assert.ok(!$target.hasClass('empty'), 'The target is not highlighted'); + + interactUtils.tapOn($antonio, function() { + assert.ok($antonio.hasClass('active'), 'The choice is active'); + assert.ok($target.hasClass('empty'), 'The target is highlighted'); + + interactUtils.tapOn($antonio, function() { + assert.ok(!$antonio.hasClass('active'), 'The choice is not active anymore'); + assert.ok(!$target.hasClass('empty'), 'The target is not highlighted anymore'); + + ready(); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('enables to create a pair', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(20); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + var $antonio; + var $capulet; + var $target1; + var $target2; + + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains an associate interaction .qti-associateInteraction'); + + $antonio = $('.qti-choice[data-identifier="A"]', $container); + assert.equal($antonio.length, 1, "the A choice exists"); + + $capulet = $('.qti-choice[data-identifier="C"]', $container); + assert.equal($capulet.length, 1, "the C choice exists"); + + $target1 = $('.result-area li:first-child .lft', $container); + assert.equal($target1.length, 1, 'the target exists'); + + $target2 = $('.result-area li:first-child .rgt', $container); + assert.equal($target2.length, 1, 'the target exists'); + + interactUtils.tapOn($antonio, function() { + interactUtils.tapOn($target1, function() { + interactUtils.tapOn($capulet, function() { + interactUtils.tapOn($target2); + }, 10); + }, 10); + }, 10); + + }) + .on('statechange', function(state) { + var $antonio; + var $capulet; + var $target1; + var $target2; + + $antonio = $('.qti-choice[data-identifier="A"]', $container); + assert.equal($antonio.length, 1, "the A choice exists"); + assert.ok($antonio.hasClass("deactivated"), "the A choice is deactivated"); + + $capulet = $('.qti-choice[data-identifier="C"]', $container); + assert.equal($capulet.length, 1, "the C choice exists"); + assert.ok($capulet.hasClass("deactivated"), "the C choice is deactivated"); + + $target1 = $('.result-area li:first-child .lft', $container); + assert.equal($target1.length, 1, 'the target exists'); + assert.ok($target1.hasClass('filled'), 'the target is filled'); + assert.equal($target1.text().trim(), 'Antonio', 'the target contains the choice text'); + + $target2 = $('.result-area li:first-child .rgt', $container); + assert.equal($target2.length, 1, 'the target exists'); + assert.ok($target2.hasClass('filled'), 'the target is filled'); + assert.equal($target2.text().trim(), 'Capulet', 'the target contains the choice text'); + + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual(state.RESPONSE.response, {list: {pair: [['A', 'C']]}}, 'The pair is in the response'); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to use a choice multiple times', function(assert) { + var ready = assert.async(); + var pChoiceMatchMax; + var $container = $('#' + fixtureContainerId); + + assert.expect(14); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + pChoiceMatchMax = associateData.body.elements.interaction_associateinteraction_54787e6dad70d437146538.choices.choice_simpleassociablechoice_54787e6dadcdd949770698.attributes.matchMax; + assert.equal(pChoiceMatchMax, 2, 'The matchMax attributes of the P choice is set at 2'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + var $prospero; + var $target1; + var $target2; + + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains an associate interaction .qti-associateInteraction'); + + $prospero = $('.qti-choice[data-identifier="P"]', $container); + assert.equal($prospero.length, 1, "the A choice exists"); + assert.ok(!$prospero.hasClass("deactivated"), "the P choice is not deactivated"); + + $target1 = $('.result-area li:first-child .lft', $container); + assert.equal($target1.length, 1, 'the target exists'); + + $target2 = $('.result-area li:first-child .rgt', $container); + assert.equal($target2.length, 1, 'the target exists'); + + interactUtils.tapOn($prospero, function() { + interactUtils.tapOn($target1, function() { + assert.ok($target1.hasClass('filled'), 'the target is filled'); + assert.equal($target1.text().trim(), 'Prospero', 'the target contains the choice text'); + assert.ok(!$prospero.hasClass('deactivated'), 'the P choice is still not deactivated'); + + interactUtils.tapOn($prospero, function() { + + interactUtils.tapOn($target2, function() { + assert.ok($target2.hasClass('filled'), 'the target is filled'); + assert.equal($target2.text().trim(), 'Prospero', 'the target contains the choice text'); + assert.ok($prospero.hasClass('deactivated'), 'the P choice is now deactivated'); + + ready(); + }, 10); + }, 10); + }, 10); + }, 10); + + }) + .init() + .render($container); + }); + + QUnit.test('enables to replace a choice', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(10); + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner("qti", associateData) + .on("render", function() { + var $antonio = $('.qti-choice[data-identifier="A"]', $container); + var $capulet = $('.qti-choice[data-identifier="C"]', $container); + + var $target1 = $('.result-area li:first-child .lft', $container); + + // Set Choice + interactUtils.tapOn($antonio, function() { + interactUtils.tapOn($target1, function() { + assert.ok($antonio.hasClass('deactivated'), 'Antonio is deactivated'); + assert.equal($antonio.innerText, $target1.innerText, 'Antonio has been added to the result area'); + assert.ok(!$capulet.hasClass('deactivated'), 'Capulet is not deactivated'); + + // Replace by bringing another choice to the same target + interactUtils.tapOn($capulet, function() { + interactUtils.tapOn($target1, function() { + assert.equal($capulet.innerText, $target1.innerText, 'Capulet has replaced Antonio in the result area'); + assert.ok(!$antonio.hasClass('deactivated'), 'Antonio is not deactivated anymore'); + assert.ok($capulet.hasClass('deactivated'), 'Capulet is now deactivated'); + + // Replace by bringing the target to another choice + interactUtils.tapOn($target1, function() { + interactUtils.tapOn($antonio, function() { + assert.ok($antonio.hasClass('deactivated'), 'Antonio is deactivated'); + assert.equal($antonio.innerText, $target1.innerText, 'Antonio has been added to the result area'); + assert.ok(!$capulet.hasClass('deactivated'), 'Capulet is not deactivated'); + + ready(); + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('enables to switch pairs', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId), + stateChangeCounter = 0; + + assert.expect(4); + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner("qti", associateData) + .on("render", function() { + var $antonio = $('.qti-choice[data-identifier="A"]', $container); + var $capulet = $('.qti-choice[data-identifier="C"]', $container); + var $lysander = $('.qti-choice[data-identifier="L"]', $container); + var $montague = $('.qti-choice[data-identifier="M"]', $container); + + var $target1 = $('.result-area li:first-child .lft', $container); + var $target2 = $('.result-area li:first-child .rgt', $container); + var $target3 = $('.result-area li:last-child .lft', $container); + var $target4 = $('.result-area li:last-child .rgt', $container); + + // Set first pair + interactUtils.tapOn($antonio, function() { + interactUtils.tapOn($target1, function() { + interactUtils.tapOn($capulet, function() { + interactUtils.tapOn($target2, function() { + + // Set second pair + interactUtils.tapOn($lysander, function() { + interactUtils.tapOn($target3, function() { + interactUtils.tapOn($montague, function() { + interactUtils.tapOn($target4, function() { + + // Switch pair + interactUtils.tapOn($target2, function() { + interactUtils.tapOn($target4); + + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + + }) + .on('statechange', function(state) { + stateChangeCounter++; + + if (stateChangeCounter === 1) { + assert.deepEqual(state.RESPONSE.response, {list: {pair: [['A', 'C']]}}, 'The pair is in the response'); + } else if (stateChangeCounter === 2) { + assert.deepEqual(state.RESPONSE.response, {list: {pair: [['A', 'C'], ['L', 'M']]}}, 'The second pair is in the response'); + } else if (stateChangeCounter === 4) { + assert.deepEqual(state.RESPONSE.response, {list: {pair: [['A', 'M'], ['L', 'C']]}}, 'The pairs have been switched'); + ready(); + } + + }) + .init() + .render($container); + }); + + QUnit.test('enables remove a choice', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId), + stateChangeCounter = 0; + + assert.expect(5); + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner("qti", associateData) + .on("render", function() { + var $antonio = $('.qti-choice[data-identifier="A"]', $container); + var $capulet = $('.qti-choice[data-identifier="C"]', $container); + + var $target1 = $('.result-area li:first-child .lft', $container); + var $target2 = $('.result-area li:first-child .rgt', $container); + + interactUtils.tapOn($antonio, function() { + interactUtils.tapOn($target1, function() { + interactUtils.tapOn($capulet, function() { + interactUtils.tapOn($target2, function() { + + // Remove antonio! + interactUtils.tapOn($target1, function() { + var $removeChoice = $('.remove-choice'); + interactUtils.tapOn($removeChoice); + + }, 10); + }, 10); + }, 10); + }, 10); + }, 10); + + }) + .on("statechange", function(state) { + var $antonio = $('.qti-choice[data-identifier="A"]', $container); + stateChangeCounter++; + + if (stateChangeCounter === 1) { + assert.ok($antonio.hasClass('deactivated'), 'Antonio is deactivated'); + assert.deepEqual(state.RESPONSE.response, {list: {pair: [['A', 'C']]}}, 'The pair is in the response'); + } else if (stateChangeCounter === 2) { + assert.ok(!$antonio.hasClass('deactivated'), 'Antonio can be selected'); + assert.deepEqual(state.RESPONSE.response, {list: {pair: []}}, 'The choice has been removed'); + ready(); + } + + }) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(17); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('error', function(err) { + assert.ok(false, err.message); + ready(); + }) + .on('render', function() { + var $antonio; + var $capulet; + var $target1; + var $target2; + + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains an associate interaction .qti-associateInteraction'); + + $antonio = $('.qti-choice[data-identifier="A"]', $container); + assert.equal($antonio.length, 1, "the A choice exists"); + assert.ok(!$antonio.hasClass("deactivated"), "the A choice is not deactivated"); + + $capulet = $('.qti-choice[data-identifier="C"]', $container); + assert.equal($capulet.length, 1, "the C choice exists"); + assert.ok(!$capulet.hasClass("deactivated"), "the C choice is not deactivated"); + + $target1 = $('.result-area li:first-child .lft', $container); + assert.equal($target1.length, 1, 'the target exists'); + assert.ok(!$target1.hasClass('filled'), 'the target is not filled'); + + $target2 = $('.result-area li:first-child .rgt', $container); + assert.equal($target2.length, 1, 'the target exists'); + assert.ok(!$target2.hasClass('filled'), 'the target is not filled'); + + this.setState({RESPONSE: {response: {list: {pair: [['A', 'C']]}}}}); + + _.delay(function() { + + assert.ok($antonio.hasClass('deactivated'), 'the A choice is deactivated'); + assert.ok($capulet.hasClass('deactivated'), 'the C choice is deactivated'); + assert.ok($target1.hasClass('filled'), 'the target is filled'); + assert.equal($target1.text().trim(), 'Antonio', 'the target contains the choice text'); + assert.ok($target2.hasClass('filled'), 'the target is filled'); + assert.equal($target2.text().trim(), 'Capulet', 'the target contains the choice text'); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(4); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + var self = this; + var $antonio; + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + $antonio = $('.qti-choice[data-identifier="A"]', $container); + assert.equal($antonio.length, 1, "the A choice exists"); + + interactUtils.tapOn($antonio, function() { + + assert.deepEqual(self.getState(), {RESPONSE: {response: {list: {pair: []}}}}, 'Click does not trigger response once destroyed'); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(14); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + var self = this; + var $antonio; + var $capulet; + var $target1; + var $target2; + + $antonio = $('.qti-choice[data-identifier="A"]', $container); + assert.equal($antonio.length, 1, "the A choice exists"); + + $capulet = $('.qti-choice[data-identifier="C"]', $container); + assert.equal($capulet.length, 1, "the C choice exists"); + + $target1 = $('.result-area li:first-child .lft', $container); + assert.equal($target1.length, 1, 'the target exists'); + + $target2 = $('.result-area li:first-child .rgt', $container); + assert.equal($target2.length, 1, 'the target exists'); + + interactUtils.tapOn($antonio, function() { + interactUtils.tapOn($target1, function() { + interactUtils.tapOn($capulet, function() { + interactUtils.tapOn($target2, function() { + var interaction; + + assert.ok($antonio.hasClass('deactivated'), 'the A choice is deactivated'); + assert.ok($capulet.hasClass('deactivated'), 'the C choice is deactivated'); + assert.ok($target1.hasClass('filled'), 'the target is filled'); + assert.ok($target2.hasClass('filled'), 'the target is filled'); + + //Call reset Response manually + interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + + assert.ok(!$antonio.hasClass('deactivated'), 'the A choice is not deactivated anymore'); + assert.ok(!$capulet.hasClass('deactivated'), 'the C choice is not deactivated anymore'); + assert.ok(!$target1.hasClass('filled'), 'the target is not filled anymore'); + assert.ok(!$target2.hasClass('filled'), 'the target is not filled anymore'); + + ready(); + }, 100); + }, 10); + }, 10); + }, 10); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('restores order of shuffled choices', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + var shuffled; + + assert.expect(10); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + //Hack the item data to set the shuffle attributes to true + shuffled = _.cloneDeep(associateData); + shuffled.body.elements.interaction_associateinteraction_54787e6dad70d437146538.attributes.shuffle = true; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains a choice interaction .qti-associateInteraction'); + assert.equal($container.find('.qti-associateInteraction .qti-choice').length, 6, 'the interaction has 6 choices'); + + this.setState({ + RESPONSE: { + response: {list: {pair: []}}, + order: ['M', 'L', 'C', 'D', 'A', 'P'] + } + }); + + _.delay(function() { + + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(1)').data('identifier'), 'M', 'the 1st choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(2)').data('identifier'), 'L', 'the 2nd choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(3)').data('identifier'), 'C', 'the 3rd choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(4)').data('identifier'), 'D', 'the 4th choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(5)').data('identifier'), 'A', 'the 5th choice has the right identifier'); + assert.equal($container.find('.qti-associateInteraction .qti-choice:nth-child(6)').data('identifier'), 'P', 'the 6th choice has the right identifier'); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + var $container = $('#' + outsideContainerId); + + assert.expect(4); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', associateData) + .on('render', function() { + + assert.equal($container.find('.qti-interaction.qti-associateInteraction').length, 1, 'the container contains a choice interaction .qti-associateInteraction'); + assert.equal($container.find('.qti-associateInteraction .qti-choice').length, 6, 'the interaction has 6 choices'); + + ready(); + }) + .on('statechange', function(state) { + document.getElementById('display-response').textContent = JSON.stringify(state); + }) + .on('error', function(err) { + assert.ok(false, err.message); + ready(); + }) + .init() + .render($container); + }); + +}); + diff --git a/test/qtiCommonRenderer/interactions/choice/test.html b/test/qtiCommonRenderer/interactions/choice/test.html new file mode 100644 index 00000000..a74e0a04 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/choice/test.html @@ -0,0 +1,26 @@ + + + + + Choice Interaction Test + + + + +
+
+
+
+ +
+ + diff --git a/test/qtiCommonRenderer/interactions/choice/test.js b/test/qtiCommonRenderer/interactions/choice/test.js new file mode 100644 index 00000000..aebfb356 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/choice/test.js @@ -0,0 +1,621 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/space-shuttle.json', + 'json!taoQtiItem/test/samples/json/space-shuttle-m.json', + 'json!taoQtiItem/test/samples/json/space-shuttle-ident.json' +], function($, _, qtiItemRunner, choiceData, multipleChoiceData, badIdentChoiceData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('Choice Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correclty', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(17); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', choiceData) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-choiceInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-choiceInteraction .choice-area').length, + 1, + 'the interaction contains a choice list' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'space-shuttle-30-years-of-adventure', + 'the .qti-item node has the right identifier' + ); + + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(1)').data('identifier'), + 'Discovery', + 'the 1st choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(2)').data('identifier'), + 'Challenger', + 'the 2nd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(3)').data('identifier'), + 'Pathfinder', + 'the 3rd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(4)').data('identifier'), + 'Atlantis', + 'the 4th choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(5)').data('identifier'), + 'Endeavour', + 'the 5th choice has the right identifier' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to select a choice', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(8); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', choiceData) + .on('render', function() { + var $discovery = $('.qti-choice[data-identifier="Discovery"]', $container); + + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + assert.equal($discovery.length, 1, 'the Discovery choice exists'); + + $discovery.trigger('click'); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { base: { identifier: 'Discovery' } } }, + 'The discovery response is selected' + ); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to select a unique choice', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + var changes = 0; + + assert.expect(11); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', choiceData) + .on('render', function() { + var $discovery = $('.qti-choice[data-identifier="Discovery"]', $container); + var $challenger = $('.qti-choice[data-identifier="Challenger"]', $container); + + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + assert.equal($discovery.length, 1, 'the Discovery choice exists'); + assert.equal($discovery.length, 1, 'the Challenger choice exists'); + + $discovery.trigger('click'); + _.delay(function() { + $challenger.trigger('click'); + }, 200); + }) + .on('statechange', function(state) { + if (++changes === 2) { + //Check the response is challenger + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { base: { identifier: 'Challenger' } } }, + 'The Challenger response is selected' + ); + + //Challenger is checked instead of Discovery + assert.ok( + !$('[data-identifier="Discovery"] input', $container).prop('checked'), + 'Discovery is not checked' + ); + assert.ok( + $('[data-identifier="Challenger"] input', $container).prop('checked'), + 'Challenger is now checked' + ); + + ready(); + } + }) + .init() + .render($container); + }); + + QUnit.test('enables to select multiple choices', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + var changes = 0; + + assert.expect(11); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', multipleChoiceData) + .on('render', function() { + var $discovery = $('.qti-choice[data-identifier="Discovery"]', $container); + var $challenger = $('.qti-choice[data-identifier="Challenger"]', $container); + + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + assert.equal( + $container.find('.qti-choiceInteraction .instruction-container').length, + 1, + 'the interaction contains an instruction box' + ); + assert.equal( + $container.find('.qti-choiceInteraction .instruction-container').children().length, + 2, + 'the interaction has 2 instructions' + ); + assert.equal($discovery.length, 1, 'the Discovery choice exists'); + assert.equal($discovery.length, 1, 'the Challenger choice exists'); + + $discovery.trigger('click'); + _.delay(function() { + $challenger.trigger('click'); + }, 200); + }) + .on('statechange', function(state) { + if (++changes === 2) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: ['Discovery', 'Challenger'] } } }, + 'Discovery AND Challenger are selected' + ); + ready(); + } + }) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(4); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', choiceData) + .on('render', function() { + assert.ok( + !$('[data-identifier="Atlantis"] input', $container).prop('checked'), + 'Atlantis is not checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Atlantis' } } } }); + + assert.ok( + $('[data-identifier="Atlantis"] input', $container).prop('checked'), + 'Atlantis is now checked' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(5); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', choiceData) + .on('render', function() { + var $discovery = $('.qti-choice[data-identifier="Discovery"]', $container); + var interaction = this._item.getInteractions()[0]; + var self = this; + + //Call destroy manually + interaction.renderer.destroy(interaction); + + assert.equal($discovery.length, 1, 'the Discovery choice exists'); + + $discovery.trigger('click'); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: null } } }, + 'Click does not trigger response once destroyed' + ); + assert.equal( + $container.find('.qti-choiceInteraction .instruction-container').children().length, + 0, + 'there is no instructions anymore' + ); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(7); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', choiceData) + .on('render', function() { + var $discovery = $('.qti-choice[data-identifier="Discovery"]', $container); + var self = this; + + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + assert.equal($discovery.length, 1, 'the Discovery choice exists'); + + $discovery.trigger('click'); + + _.delay(function() { + var interaction = self._item.getInteractions()[0]; + + assert.ok($('input', $discovery).prop('checked'), 'Discovery is now checked'); + + //Call destroy manually + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + assert.ok(!$('input', $discovery).prop('checked'), 'Discovery is not checked checked anymore'); + + ready(); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('restores order of shuffled choices', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + var shuffled; + + assert.expect(9); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + //Hack the item data to set the shuffle attr to true + shuffled = _.cloneDeep(choiceData); + shuffled.body.elements.interaction_choiceinteraction_546cb89e04090230494786.attributes.shuffle = true; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + this.setState({ + RESPONSE: { + response: { base: null }, + order: ['Challenger', 'Atlantis', 'Pathfinder', 'Discovery', 'Endeavour'] + } + }); + + _.delay(function() { + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(1)').data('identifier'), + 'Challenger', + 'the 1st choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(2)').data('identifier'), + 'Atlantis', + 'the 2nd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(3)').data('identifier'), + 'Pathfinder', + 'the 3rd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(4)').data('identifier'), + 'Discovery', + 'the 4th choice has the right identifier' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice:nth-child(5)').data('identifier'), + 'Endeavour', + 'the 5th choice has the right identifier' + ); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('get eliminated choices state', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + var $discovery, $challenger, $pathfinder, $atlantis, $endeavour; + var shuffled; + + assert.expect(11); + + //Hack the item data to set the eliminable behaviour on + shuffled = _.cloneDeep(choiceData); + shuffled.body.elements.interaction_choiceinteraction_546cb89e04090230494786.attributes.class = 'eliminable'; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + var self = this; + + $discovery = $container.find('.qti-choiceInteraction .qti-choice[data-identifier=Discovery]'); + $challenger = $container.find('.qti-choiceInteraction .qti-choice[data-identifier=Challenger]'); + $pathfinder = $container.find('.qti-choiceInteraction .qti-choice[data-identifier=Pathfinder]'); + $atlantis = $container.find('.qti-choiceInteraction .qti-choice[data-identifier=Atlantis]'); + $endeavour = $container.find('.qti-choiceInteraction .qti-choice[data-identifier=Endeavour]'); + + // All choices start not eliminated + assert.ok(!$discovery.hasClass('eliminated'), 'Discovery starts not eliminated'); + assert.ok(!$challenger.hasClass('eliminated'), 'Challenger starts not eliminated'); + assert.ok(!$pathfinder.hasClass('eliminated'), 'Pathfinder starts not eliminated'); + assert.ok(!$atlantis.hasClass('eliminated'), 'Atlantis starts not eliminated'); + assert.ok(!$endeavour.hasClass('eliminated'), 'Endeavour starts not eliminated'); + + // Click 'eliminate' + $discovery.find('[data-eliminable=trigger]').click(); + + // Set 'eliminated' state manually + this.setState({ + RESPONSE: { + response: { base: null }, + eliminated: ['Atlantis'] + } + }); + + _.delay(function() { + assert.ok($discovery.hasClass('eliminated'), 'Discovery', 'Discovery has been eliminated'); + assert.ok(!$challenger.hasClass('eliminated'), 'Challenger', 'Challenger has not been eliminated'); + assert.ok(!$pathfinder.hasClass('eliminated'), 'Pathfinder', 'Pathfinder has not been eliminated'); + assert.ok($atlantis.hasClass('eliminated'), 'Atlantis', 'Atlantis has been eliminated'); + assert.ok(!$endeavour.hasClass('eliminated'), 'Endeavour', 'Endeavour has not been eliminated'); + assert.deepEqual( + self.getState().RESPONSE.eliminated, + ['Discovery', 'Atlantis'], + 'state is correct' + ); + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('restores eliminated choices', function(assert) { + var ready = assert.async(); + + // Note: toggling state via events makes for unruly state management (and thus this mess of a test) + var $eliminator; + var $choice; + var $container = $('#' + fixtureContainerId); + var shuffled; + + assert.expect(3); + + //Hack the item data to set the eliminable behaviour on + shuffled = _.cloneDeep(choiceData); + shuffled.body.elements.interaction_choiceinteraction_546cb89e04090230494786.attributes.class = 'eliminable'; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + $choice = $container.find('.qti-choiceInteraction .qti-choice[data-identifier=Discovery]'); + $eliminator = $choice.find('[data-eliminable="trigger"]'); + + // 1) is not eliminated + assert.ok(!$choice.hasClass('eliminated'), 'Discovery is not eliminated'); + + _.delay(function() { + // 2) is eliminated + assert.ok($choice.hasClass('eliminated'), 'Discovery has been eliminated'); + + _.delay(function() { + // 3) is un-eliminated + assert.ok(!$choice.hasClass('eliminated'), 'Discovery has been un-eliminated'); + + ready(); + }, 100); + + // 2 -> 3 - un-eliminates item + $eliminator.click(); + }, 100); + + // 1 -> 2 - eliminate item + $eliminator.click(); + }) + .init() + .render($container); + }); + + QUnit.test('check dashes and dots in the identifier', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(4); + + runner = qtiItemRunner('qti', badIdentChoiceData) + .on('render', function() { + var $discovery = $('.qti-choice[data-identifier="Discovery-new.dot"]', $container); + assert.equal($discovery.length, 1, 'the Discovery-new.dot choice exists'); + $discovery.trigger('click'); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { base: { identifier: 'Discovery-new.dot' } } }, + 'The Discovery-new.dot response is selected' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + var $container = $('#' + outsideContainerId); + + assert.expect(4); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + qtiItemRunner('qti', choiceData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-choiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-choiceInteraction' + ); + assert.equal( + $container.find('.qti-choiceInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + ready(); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/extendedText/test.html b/test/qtiCommonRenderer/interactions/extendedText/test.html new file mode 100644 index 00000000..e53b8da1 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/extendedText/test.html @@ -0,0 +1,35 @@ + + + + + Extended Text Interaction Test + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + diff --git a/test/qtiCommonRenderer/interactions/extendedText/test.js b/test/qtiCommonRenderer/interactions/extendedText/test.js new file mode 100644 index 00000000..743ebbb5 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/extendedText/test.js @@ -0,0 +1,576 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/postcard.json', + 'json!taoQtiItem/test/samples/json/formated-card.json', + 'lib/simulator/jquery.keystroker', + 'ckeditor' +], function($, _, qtiItemRunner, itemDataPlain, itemDataXhtml, keystroker, ckEditor) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container-'; + + /** PLAIN **/ + + QUnit.module('Extended Text Interaction - plain format', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correctly', function(assert) { + var ready = assert.async(); + assert.expect(10); + + var $container = $('#' + fixtureContainerId + '0'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataPlain) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + assert.equal( + $container.find('.qti-extendedTextInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-extendedTextInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'extendedText', + 'the .qti-item node has the right identifier' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to input a response', function(assert) { + var ready = assert.async(); + assert.expect(16); + + var $container = $('#' + fixtureContainerId + '1'); + var responsesStack = [ + { response: { base: { string: 't' } } }, + { response: { base: { string: 'te' } } }, + { response: { base: { string: 'tes' } } }, + { response: { base: { string: 'test' } } } + ]; + var stackPtr = 0; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataPlain) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + + keystroker.puts($container.find('textarea'), 'test'); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual(state.RESPONSE, responsesStack[stackPtr++], 'A text is entered'); + if (stackPtr === responsesStack.length) { + assert.ok(true, 'A text is fully entered'); + ready(); + } + }) + .init() + .render($container); + }); + + QUnit.test('enables to load a response', function(assert) { + var ready = assert.async(); + assert.expect(5); + + var $container = $('#' + fixtureContainerId + '2'); + var response = { base: { string: 'test' } }; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataPlain) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + + var interaction = this._item.getInteractions()[0]; + interaction.renderer.setResponse(interaction, response); + + assert.deepEqual( + this.getState(), + { RESPONSE: { response: response } }, + 'the response state is equal to the loaded response' + ); + + assert.equal( + $container.find('textarea').val(), + response.base.string, + 'the textarea displays the loaded response' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + assert.expect(5); + + var $container = $('#' + fixtureContainerId + '3'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataPlain) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + var self = this; + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + assert.equal( + $container.find('.qti-interaction.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + + keystroker.puts($container.find('textarea'), 'test'); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: { string: 'test' } } } }, + 'The response state is still related to text content' + ); + assert.equal( + $container.find('.qti-extendedTextInteraction .instruction-container').children().length, + 0, + 'there is no instructions anymore' + ); + + ready(); + }, 100); + }) + .on('statechange', function() { + assert.ok(false, 'Text input does not trigger response once destroyed'); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + assert.expect(5); + + var $container = $('#' + fixtureContainerId + '4'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataPlain) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + var self = this; + + assert.equal( + $container.find('.qti-interaction.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + + keystroker.puts($container.find('textarea'), 'test'); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: { string: 'test' } } } }, + 'A response is set' + ); + + //Call destroy manually + var interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: { string: '' } } } }, + 'The response is cleared' + ); + + ready(); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + /** XHTML **/ + + QUnit.module('Extended Text Interaction - XHTML format', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correctly', function(assert) { + var ready = assert.async(); + assert.expect(11); + + var $container = $('#' + fixtureContainerId + '5'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataXhtml) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + assert.equal( + $container.find('.qti-extendedTextInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-extendedTextInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'extendedText', + 'the .qti-item node has the right identifier' + ); + assert.ok( + typeof $('.qti-extendedTextInteraction', $container).data('editor') === 'string', + 'The interaction has the editor instance name' + ); + + _.delay(ready, 10); + }) + .init() + .render($container); + }); + + QUnit.test('enables to input a response', function(assert) { + var ready = assert.async(); + assert.expect(6); + + var $container = $('#' + fixtureContainerId + '6'); + var response = 'test'; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataXhtml) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + var $interaction = $('.qti-extendedTextInteraction', $container); + assert.equal( + $interaction.length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + + var editor = ckEditor.instances[$interaction.data('editor')]; + + assert.ok(typeof editor === 'object', 'the interaction is link to the ck instance'); + + editor.setData(response); + + assert.deepEqual( + this.getState(), + { RESPONSE: { response: { base: { string: response } } } }, + 'the response state is equal to the loaded response' + ); + assert.equal(editor.getData(), response, 'the editor displays the loaded response'); + + _.delay(ready, 10); + }) + .init() + .render($container); + }); + + QUnit.test('enables to load a response', function(assert) { + var ready = assert.async(); + assert.expect(5); + + var $container = $('#' + fixtureContainerId + '7'); + + //Var $container = $('#outside-container'); + var response = { base: { string: 'test' } }; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataXhtml) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + var self = this; + + //Set the state + runner.setState({ RESPONSE: { response: response } }); + + assert.equal( + $container.find('.qti-extendedTextInteraction').length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + assert.deepEqual( + self.getState(), + { RESPONSE: { response: response } }, + 'the response state is equal to the loaded response' + ); + + //Ck set the text with a little delay + _.delay(function() { + assert.equal( + $('.qti-extendedTextInteraction iframe.cke_wysiwyg_frame', $container) + .contents() + .find('body') + .text(), + 'test', + 'the state text is inserted' + ); + + _.delay(function() { + ready(); + }, 10); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + assert.expect(6); + + var $container = $('#' + fixtureContainerId + '9'); + var response = 'test'; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataXhtml) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + var self = this; + + var interaction = self._item.getInteractions()[0]; + var $interaction = $('.qti-extendedTextInteraction', $container); + assert.equal( + $interaction.length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + + var editor = ckEditor.instances[$interaction.data('editor')]; + + editor.setData(response); + + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: { string: response } } } }, + 'A response is set' + ); + + _.delay(function() { + interaction.renderer.resetResponse(interaction); + + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: { string: '' } } } }, + 'The response is cleared' + ); + assert.equal(editor.getData(), '', 'the editor is cleared'); + + _.delay(ready, 10); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + assert.expect(8); + + var $container = $('#' + fixtureContainerId + '8'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemDataXhtml) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + var self = this; + + //Call destroy manually + var interaction = self._item.getInteractions()[0]; + var $interaction = $('.qti-extendedTextInteraction', $container); + assert.equal( + $interaction.length, + 1, + 'the container contains a text interaction .qti-extendedTextInteraction' + ); + var editorName = $interaction.data('editor'); + + assert.ok(typeof editorName === 'string' && editorName.length > 0, 'the editor name is set'); + assert.ok(typeof ckEditor.instances[editorName] === 'object', 'the editor instance is available'); + + _.delay(function() { + interaction.renderer.destroy(interaction); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: { string: '' } } } }, + 'The response state is cleared' + ); + assert.equal( + $container.find('.qti-extendedTextInteraction .instruction-container').children().length, + 0, + 'there is no instructions anymore' + ); + assert.ok( + typeof ckEditor.instances[editorName] === 'undefined', + 'the editor instance is not available anymore' + ); + + _.delay(ready, 10); + }, 10); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + assert.expect(1); + + var $container = $('#outside-container'); + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', itemDataXhtml) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .on('render', function() { + ready(); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/gapMatch/test.html b/test/qtiCommonRenderer/interactions/gapMatch/test.html new file mode 100644 index 00000000..35c51270 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/gapMatch/test.html @@ -0,0 +1,25 @@ + + + + + GapMatch Interaction Test + + + + +
+
+
+
+
+ + diff --git a/test/qtiCommonRenderer/interactions/gapMatch/test.js b/test/qtiCommonRenderer/interactions/gapMatch/test.js new file mode 100644 index 00000000..1a3334cf --- /dev/null +++ b/test/qtiCommonRenderer/interactions/gapMatch/test.js @@ -0,0 +1,358 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'core/mouseEvent', + 'ui/interactUtils', + 'json!taoQtiItem/test/samples/json/tao-item.json' +], function( + $, + _, + qtiItemRunner, + triggerMouseEvent, + interactUtils, + gapMatchData +) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('GapMatch Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correclty', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(30); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal($container.children('.qti-item').length, 1, 'the container contains a the root element .qti-item'); + assert.equal($container.find('.qti-itemBody').length, 1, 'the container contains a the body element .qti-itemBody'); + assert.equal($container.find('.qti-interaction').length, 1, 'the container contains an interaction .qti-interaction'); + assert.equal($container.find('.qti-interaction.qti-gapMatchInteraction').length, 1, 'the container contains a choice interaction .qti-gapMatchInteraction'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-prompt-container').length, 1, 'the interaction contains a prompt'); + assert.equal($container.find('.qti-gapMatchInteraction .instruction-container').length, 1, 'the interaction contains a instruction box'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area').length, 1, 'the interaction contains a choice area'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').length, 10, 'the interaction has 10 choices'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container').length, 1, 'the interaction contains a flow container'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice.qti-gap').length, 6, 'the interaction contains 6 gaps'); + + //Check DOM data + assert.equal($container.children('.qti-item').data('identifier'), 'i13806271719128107', 'the .qti-item node has the right identifier'); + + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(0).data('identifier'), 'Text_1', 'the 1st choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(1).data('identifier'), 'Text_2', 'the 2nd choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(2).data('identifier'), 'Text_3', 'the 3rd choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(3).data('identifier'), 'Text_4', 'the 4th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(4).data('identifier'), 'Text_5', 'the 5th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(5).data('identifier'), 'Text_6', 'the 6th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(6).data('identifier'), 'Text_7', 'the 7th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(7).data('identifier'), 'Text_8', 'the 8th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(8).data('identifier'), 'Text_9', 'the 9th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(9).data('identifier'), 'Text_10', 'the 10th choice of the 1st match group has the right identifier'); + + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice').eq(0).data('identifier'), 'Gap_6', 'the 1st choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice').eq(1).data('identifier'), 'Gap_1', 'the 2nd choice of the 2nd match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice').eq(2).data('identifier'), 'Gap_2', 'the 3rd choice of the 3rd match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice').eq(3).data('identifier'), 'Gap_3', 'the 4th choice of the 3rd match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice').eq(4).data('identifier'), 'Gap_4', 'the 5th choice of the 3rd match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-flow-container .qti-choice').eq(5).data('identifier'), 'Gap_5', 'the 6th choice of the 3rd match group has the right identifier'); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to activate a choice', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(10); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $at; + var $gap; + + assert.equal($container.find('.qti-interaction.qti-gapMatchInteraction').length, 1, 'the container contains a choice interaction .qti-gapMatchInteraction'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-choice').length, 16, 'the interaction has 16 choices including gaps'); + + $at = $('.qti-choice[data-identifier="Text_1"]', $container); + assert.equal($at.length, 1, 'the Authoring tool choice exists'); + + $gap = $('.gapmatch-content[data-identifier="Gap_6"]', $container); + assert.equal($gap.length, 1, 'the gap exists'); + + assert.ok(!$at.hasClass('active'), 'The choice is not active'); + assert.ok(!$gap.hasClass('empty'), 'The gap is not highlighted'); + + interactUtils.tapOn($at, function() { + + assert.ok($at.hasClass('active'), 'The choice is now active'); + assert.ok($gap.hasClass('empty'), 'The gap is now highlighted'); + + ready(); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('enables to fill a gap with a choice', function(assert) { + var ready = assert.async(); + assert.expect(9); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $at; + var $gap; + + assert.equal($container.find('.qti-interaction.qti-gapMatchInteraction').length, 1, 'the container contains a choice interaction .qti-gapMatchInteraction'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-choice').length, 16, 'the interaction has 16 choices including gaps'); + + $at = $('.qti-choice[data-identifier="Text_1"]', $container); + assert.equal($at.length, 1, 'the Authoring tool choice exists'); + + $gap = $('.gapmatch-content[data-identifier="Gap_6"]', $container); + assert.equal($gap.length, 1, 'the gap exists'); + + interactUtils.tapOn($at, function() { + interactUtils.tapOn($gap); + }, 10); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual(state.RESPONSE, {response: {list: {directedPair: [['Text_1', 'Gap_6']]}}}, 'The pair CR is selected'); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(9); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $at; + var $gap; + + assert.equal($container.find('.qti-interaction.qti-gapMatchInteraction').length, 1, 'the container contains a choice interaction .qti-gapMatchInteraction'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-choice').length, 16, 'the interaction has 16 choices including gaps'); + + $at = $('.qti-choice[data-identifier="Text_1"]', $container); + assert.equal($at.length, 1, 'the Authoring tool choice exists'); + + $gap = $('.gapmatch-content[data-identifier="Gap_6"]', $container); + assert.equal($gap.length, 1, 'the gap exists'); + + assert.ok(!$gap.hasClass('filled'), 'The gap is not filled'); + + this.setState({RESPONSE: {response: {list: {directedPair: [['Text_1', 'Gap_6']]}}}}); + + _.delay(function() { + assert.ok($gap.hasClass('filled'), 'The gap is now filled'); + assert.equal($gap.text().trim(), 'authoring tool', 'The gap contains the choice text'); + + ready(); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(5); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var self = this; + var $at; + var $gap; + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + $at = $('.qti-choice[data-identifier="Text_1"]', $container); + assert.equal($at.length, 1, 'the Authoring tool choice exists'); + + $gap = $('.gapmatch-content[data-identifier="Gap_6"]', $container); + assert.equal($gap.length, 1, 'the gap exists'); + + interactUtils.tapOn($at, function() { + + interactUtils.tapOn($gap, function() { + assert.deepEqual(self.getState(), {'RESPONSE': {response: {list: {directedPair: []}}}}, 'Click does not trigger response once destroyed'); + + ready(); + }, 100); + }, 10); + + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(10); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var self = this; + var $gap; + var $at; + + $at = $('.qti-choice[data-identifier="Text_1"]', $container); + assert.equal($at.length, 1, 'the Authoring tool choice exists'); + + $gap = $('.gapmatch-content[data-identifier="Gap_6"]', $container); + assert.equal($gap.length, 1, 'the gap exists'); + + interactUtils.tapOn($at, function() { + + interactUtils.tapOn($gap, function() { + + assert.ok($gap.hasClass('filled'), 'The gap is now filled'); + assert.equal($gap.text().trim(), 'authoring tool', 'The gap contains the choice text'); + + interactUtils.tapOn($gap, function() { + var interaction; + + assert.ok($gap.hasClass('active'), 'The gap is now active'); + + //Call destroy manually + interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + + assert.ok(!$gap.hasClass('filled'), 'The gap is not filled anymore'); + assert.ok(!$gap.hasClass('active'), 'The gap is not active anymore'); + assert.equal($gap.text(), '', 'The gap is now empty'); + + ready(); + }, 100); + }, 100); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('restores order of shuffled choices', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + var shuffled; + + assert.expect(14); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + //Hack the item data to set the shuffle attr to true + shuffled = _.cloneDeep(gapMatchData); + shuffled.body.elements.interaction_gapmatchinteraction_547dd4d24d2d0146858817.attributes.shuffle = true; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + + assert.equal($container.find('.qti-interaction.qti-gapMatchInteraction').length, 1, 'the container contains a choice interaction .qti-gapMatchInteraction'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-choice').length, 16, 'the interaction has 16 choices including gaps'); + + this.setState({ + RESPONSE: { + response: {list: {directedPair: []}}, + order: ['Text_6', 'Text_4', 'Text_7', 'Text_8', 'Text_9', 'Text_1', 'Text_10', 'Text_2', 'Text_3', 'Text_5'] + } + }); + + _.delay(function() { + + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(0).data('identifier'), 'Text_6', 'the 1st choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(1).data('identifier'), 'Text_4', 'the 2nd choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(2).data('identifier'), 'Text_7', 'the 3rd choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(3).data('identifier'), 'Text_8', 'the 4th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(4).data('identifier'), 'Text_9', 'the 5th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(5).data('identifier'), 'Text_1', 'the 6th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(6).data('identifier'), 'Text_10', 'the 7th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(7).data('identifier'), 'Text_2', 'the 8th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(8).data('identifier'), 'Text_3', 'the 9th choice of the 1st match group has the right identifier'); + assert.equal($container.find('.qti-gapMatchInteraction .choice-area .qti-choice').eq(9).data('identifier'), 'Text_5', 'the 10th choice of the 1st match group has the right identifier'); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + var $container = $('#' + outsideContainerId); + + assert.expect(4); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + qtiItemRunner('qti', gapMatchData) + .on('render', function() { + + assert.equal($container.find('.qti-interaction.qti-gapMatchInteraction').length, 1, 'the container contains a choice interaction .qti-gapMatchInteraction'); + assert.equal($container.find('.qti-gapMatchInteraction .qti-choice').length, 16, 'the interaction has 16 choices including gaps'); + + ready(); + }) + .init() + .render($container); + }); +}); + diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/40362ca9572a15d02fe64.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/40362ca9572a15d02fe64.png new file mode 100644 index 00000000..b960ecea Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/40362ca9572a15d02fe64.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/7d245069572a15b9d3c36.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/7d245069572a15b9d3c36.png new file mode 100644 index 00000000..0dc70d97 Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/7d245069572a15b9d3c36.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/8a76ca47572a15cf2e375.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/8a76ca47572a15cf2e375.png new file mode 100644 index 00000000..e22ff9ca Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/8a76ca47572a15cf2e375.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/95062a73572a15ceea28b.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/95062a73572a15ceea28b.png new file mode 100644 index 00000000..02e55c89 Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/95062a73572a15ceea28b.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/b1826119572a15cfb23fc.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/b1826119572a15cfb23fc.png new file mode 100644 index 00000000..8fb92e6e Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/b1826119572a15cfb23fc.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/c416ff4b572a15d03d8cc.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/c416ff4b572a15d03d8cc.png new file mode 100644 index 00000000..ebd6ab84 Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/c416ff4b572a15d03d8cc.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/c4d94866572a15cf0a9ed.png b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/c4d94866572a15cf0a9ed.png new file mode 100644 index 00000000..5dd0d011 Binary files /dev/null and b/test/qtiCommonRenderer/interactions/graphicGapMatch/assets/c4d94866572a15cf0a9ed.png differ diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.json b/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.json new file mode 100644 index 00000000..9cf4d744 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.json @@ -0,0 +1,444 @@ +{ + "identifier": "i1462375832429680", + "serial": "item_572c46126a06d137875703", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1462375832429680", + "title": "dragdrop 1", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint25", + "class": "" + }, + "body": { + "serial": "container_containeritembody_572c46126a037264760863", + "body": "\n
\n
\n {{interaction_graphicgapmatchinteraction_572c46126f8ec049436337}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicgapmatchinteraction_572c46126f8ec049436337": { + "serial": "interaction_graphicgapmatchinteraction_572c46126f8ec049436337", + "qtiClass": "graphicGapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "class": "responsive" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "choices": { + "choice_associablehotspot_572c4612730fd692514259": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_572c4612730fd692514259", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "5,324,111,361" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "choice_associablehotspot_572c46127370e937989288": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_572c46127370e937989288", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "147,324,273,359" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "choice_associablehotspot_572c46127381e163483557": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_572c46127381e163483557", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "355,95,497,148" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "choice_associablehotspot_572c461273920528987273": { + "identifier": "associablehotspot_4", + "serial": "choice_associablehotspot_572c461273920528987273", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "355,156,498,213" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "choice_associablehotspot_572c461273a1b739418251": { + "identifier": "associablehotspot_5", + "serial": "choice_associablehotspot_572c461273a1b739418251", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_5", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "356,219,500,270" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "choice_associablehotspot_572c461273bec716482645": { + "identifier": "associablehotspot_6", + "serial": "choice_associablehotspot_572c461273bec716482645", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_6", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "354,275,499,324" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + }, + "prompt": { + "serial": "container_containerstatic_572c461270611227659202", + "body": "\n

Please draw the TAO architecture<\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "object": { + "serial": "object_572c461273d37967006094", + "qtiClass": "object", + "attributes": { + "data": "assets\/7d245069572a15b9d3c36.png", + "type": "image\/png", + "width": 500, + "height": 375 + }, + "debug": { + "relatedItem": "" + } + }, + "gapImgs": { + "choice_gapimg_572c461271716439965389": { + "identifier": "gapimg_1", + "serial": "choice_gapimg_572c461271716439965389", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_1", + "fixed": false, + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "object": { + "serial": "object_572c461272068710826754", + "qtiClass": "object", + "attributes": { + "data": "assets\/95062a73572a15ceea28b.png", + "type": "image\/png", + "width": 142, + "height": 58 + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + }, + "choice_gapimg_572c461272225600171775": { + "identifier": "gapimg_2", + "serial": "choice_gapimg_572c461272225600171775", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_2", + "fixed": false, + "matchMin": "1", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "object": { + "serial": "object_572c461272326573994097", + "qtiClass": "object", + "attributes": { + "data": "assets\/c4d94866572a15cf0a9ed.png", + "type": "image\/png", + "width": 140, + "height": 58 + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + }, + "choice_gapimg_572c46127245c512891045": { + "identifier": "gapimg_3", + "serial": "choice_gapimg_572c46127245c512891045", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_3", + "fixed": false, + "matchMin": "1", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "object": { + "serial": "object_572c461272570410087311", + "qtiClass": "object", + "attributes": { + "data": "assets\/8a76ca47572a15cf2e375.png", + "type": "image\/png", + "width": 142, + "height": 58 + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + }, + "choice_gapimg_572c4612726dc466174632": { + "identifier": "gapimg_4", + "serial": "choice_gapimg_572c4612726dc466174632", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_4", + "fixed": false, + "matchMin": "1", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "object": { + "serial": "object_572c4612727d1201174170", + "qtiClass": "object", + "attributes": { + "data": "assets\/b1826119572a15cfb23fc.png", + "type": "image\/png", + "width": 141, + "height": 58 + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + }, + "choice_gapimg_572c4612728e9905158106": { + "identifier": "gapimg_5", + "serial": "choice_gapimg_572c4612728e9905158106", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_5", + "fixed": false, + "matchMin": "1", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "object": { + "serial": "object_572c4612729c4054847634", + "qtiClass": "object", + "attributes": { + "data": "assets\/40362ca9572a15d02fe64.png", + "type": "image\/png", + "width": 131, + "height": 51 + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + }, + "choice_gapimg_572c461272ad6059617391": { + "identifier": "gapimg_6", + "serial": "choice_gapimg_572c461272ad6059617391", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_6", + "fixed": false, + "matchMin": "1", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "object": { + "serial": "object_572c461272bac452956085", + "qtiClass": "object", + "attributes": { + "data": "assets\/c416ff4b572a15d03d8cc.png", + "type": "image\/png", + "width": 133, + "height": 51 + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + } + } + } + } + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + } + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_572c46126d8c8088640547": { + "identifier": "SCORE", + "serial": "outcomedeclaration_572c46126d8c8088640547", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_572c46126c78d916424021": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_572c46126c78d916424021", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "associablehotspot_1 gapimg_5", + "associablehotspot_2 gapimg_6", + "associablehotspot_3 gapimg_3", + "associablehotspot_4 gapimg_2", + "associablehotspot_5 gapimg_1", + "associablehotspot_6 gapimg_4" + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_572c461275a6c850881117", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_572c46126a06d137875703" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.xml b/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.xml new file mode 100644 index 00000000..716d65b2 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + +

+
+ + +

Please draw the TAO architecture

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/test.html b/test/qtiCommonRenderer/interactions/graphicGapMatch/test.html new file mode 100644 index 00000000..a2668e4e --- /dev/null +++ b/test/qtiCommonRenderer/interactions/graphicGapMatch/test.html @@ -0,0 +1,27 @@ + + + + + Graphic gap match Interaction Test + + + + +
+
+
+
+ +
+
+ + diff --git a/test/qtiCommonRenderer/interactions/graphicGapMatch/test.js b/test/qtiCommonRenderer/interactions/graphicGapMatch/test.js new file mode 100644 index 00000000..c6a61d4f --- /dev/null +++ b/test/qtiCommonRenderer/interactions/graphicGapMatch/test.js @@ -0,0 +1,504 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'core/mouseEvent', + 'ui/interactUtils', + 'json!taoQtiItem/test/qtiCommonRenderer/interactions/graphicGapMatch/sample.json' +], function($, _, qtiItemRunner, triggerMouseEvent, interactUtils, gapMatchData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + //Override asset loading in order to resolve it from the runtime location + var strategies = [ + { + name: 'default', + handle: function defaultStrategy(url) { + if (/assets/.test(url.toString())) { + return '/test/qtiCommonRenderer/interactions/graphicGapMatch/' + url.toString(); + } + return url.toString(); + } + } + ]; + + QUnit.module('Graphic GapMatch Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correctly', function(assert) { + var ready = assert.async(); + assert.expect(20); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-graphicGapMatchInteraction').length, + 1, + 'the container contains a choice interaction .qti-graphicGapMatchInteraction' + ); + assert.equal( + $container.find('.qti-graphicGapMatchInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-graphicGapMatchInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-graphicGapMatchInteraction .block-listing').length, + 1, + 'the interaction contains a choice area' + ); + assert.equal( + $container.find('.qti-graphicGapMatchInteraction .block-listing .qti-choice').length, + 6, + 'the interaction has 6 choices' + ); + assert.equal( + $container.find('.qti-graphicGapMatchInteraction .main-image-box').length, + 1, + 'the interaction contains a image' + ); + assert.equal( + $container.find('.qti-graphicGapMatchInteraction .main-image-box rect').length, + 6, + 'the interaction contains 6 gaps' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'i1462375832429680', + 'the .qti-item node has the right identifier' + ); + + assert.equal( + $container + .find('.qti-graphicGapMatchInteraction .block-listing .qti-choice') + .eq(0) + .data('identifier'), + 'gapimg_1', + 'the 1st block has the right identifier' + ); + assert.equal( + $container + .find('.qti-graphicGapMatchInteraction .block-listing .qti-choice') + .eq(1) + .data('identifier'), + 'gapimg_2', + 'the 2nd block has the right identifier' + ); + assert.equal( + $container + .find('.qti-graphicGapMatchInteraction .block-listing .qti-choice') + .eq(2) + .data('identifier'), + 'gapimg_3', + 'the 3rd block has the right identifier' + ); + assert.equal( + $container + .find('.qti-graphicGapMatchInteraction .block-listing .qti-choice') + .eq(3) + .data('identifier'), + 'gapimg_4', + 'the 4th block has the right identifier' + ); + assert.equal( + $container + .find('.qti-graphicGapMatchInteraction .block-listing .qti-choice') + .eq(4) + .data('identifier'), + 'gapimg_5', + 'the 5th block has the right identifier' + ); + assert.equal( + $container + .find('.qti-graphicGapMatchInteraction .block-listing .qti-choice') + .eq(5) + .data('identifier'), + 'gapimg_6', + 'the 6th block has the right identifier' + ); + + ready(); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('enables to activate a gap filler', function(assert) { + var ready = assert.async(); + assert.expect(5); + + var $container = $('#' + fixtureContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var $hotspot = $('.main-image-box rect', $container).eq(5); + var borderColorInactive = '#8d949e'; + + assert.ok(!$gapFiller.hasClass('active'), 'The gap filler is not active'); + assert.strictEqual($hotspot.attr('stroke'), borderColorInactive, 'The hotspot is not highlighted'); + + interactUtils.tapOn( + $gapFiller, + function() { + assert.ok($gapFiller.hasClass('active'), 'The gap filler is now active'); + assert.notStrictEqual( + $hotspot.attr('stroke'), + borderColorInactive, + 'The hotspot is now highlighted' + ); + + ready(); + }, + 200 + ); // Safety delay for the border color to start changing, could be shortened by removing the animation + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('enables to fill a hotspot', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var $container = $('#' + fixtureContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var $hotspot = $('.main-image-box rect', $container).eq(5); + + interactUtils.tapOn( + $gapFiller, + function() { + interactUtils.tapOn($hotspot); + }, + 50 + ); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { list: { directedPair: [['gapimg_1', 'associablehotspot_6']] } } }, + 'The pair is selected' + ); + + ready(); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('enables to fill a hotspot with two gap fillers', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var stateChangeCounter = 0; + var $container = $('#' + fixtureContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var $gapFiller2 = $('.qti-choice[data-identifier="gapimg_3"]', $container); + var $hotspot = $('.main-image-box rect', $container).eq(5); + + interactUtils.tapOn( + $gapFiller, + function() { + interactUtils.tapOn( + $hotspot, + function() { + interactUtils.tapOn( + $gapFiller2, + function() { + // We click on the image, but the click should be redirected to the underlying shape + var $gapFillerOnHotspot = $container + .find('.main-image-box image', $container) + .eq(1); + interactUtils.tapOn($gapFillerOnHotspot); + }, + 10 + ); + }, + 300 + ); // We need to wait for the animation to end in order for the click event to be bound + }, + 10 + ); + }) + .on('statechange', function(state) { + stateChangeCounter++; + if (stateChangeCounter === 1) { + assert.deepEqual( + state.RESPONSE, + { response: { list: { directedPair: [['gapimg_1', 'associablehotspot_6']] } } }, + 'The first pair is selected' + ); + } else if (stateChangeCounter === 2) { + assert.deepEqual( + state.RESPONSE, + { + response: { + list: { + directedPair: [ + ['gapimg_1', 'associablehotspot_6'], + ['gapimg_3', 'associablehotspot_6'] + ] + } + } + }, + 'The 2 pairs are selected' + ); + + ready(); + } + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('enables to remove a gap filler', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var stateChangeCounter = 0; + var $container = $('#' + fixtureContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var $hotspot = $('.main-image-box rect', $container).eq(5); + + interactUtils.tapOn( + $gapFiller, + function() { + interactUtils.tapOn( + $hotspot, + function() { + var $gapFillerOnHotspot = $container.find('.main-image-box image', $container).eq(1); + + interactUtils.tapOn($gapFillerOnHotspot); + + assert.equal( + $container.find('.main-image-box image').length, + 1, // This is the canvas image + 'there are no filled gaps' + ); + }, + 300 + ); // We need to wait for the animation to end in order for the click event to be bound + }, + 10 + ); + }) + .on('statechange', function(state) { + stateChangeCounter++; + if (stateChangeCounter === 1) { + assert.deepEqual( + state.RESPONSE, + { response: { list: { directedPair: [['gapimg_1', 'associablehotspot_6']] } } }, + 'The pair is selected' + ); + } else if (stateChangeCounter === 2) { + assert.deepEqual(state.RESPONSE, { response: { list: { directedPair: [] } } }, 'Response is empty'); + ready(); + } + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + assert.expect(2); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var gapFillerImgSrc = $gapFiller.find('img').attr('src'); + + this.setState({ + RESPONSE: { response: { list: { directedPair: [['gapimg_1', 'associablehotspot_6']] } } } + }); + + _.delay(function() { + var $gapFillerOnHotspot = $container.find('.main-image-box image', $container).eq(1); + assert.equal($gapFillerOnHotspot.attr('href'), gapFillerImgSrc, 'state has been restored'); + + ready(); + }, 300); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + assert.expect(2); + + var $container = $('#' + fixtureContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var self = this; + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var $hotspot = $('.main-image-box rect', $container).eq(5); + + interactUtils.tapOn( + $gapFiller, + function() { + interactUtils.tapOn( + $hotspot, + function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { list: { directedPair: [] } } } }, + 'Click does not trigger response once destroyed' + ); + ready(); + }, + 10 + ); + }, + 10 + ); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var $container = $('#' + fixtureContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', gapMatchData) + .on('render', function() { + var self = this; + + var $gapFiller = $('.qti-choice[data-identifier="gapimg_1"]', $container); + var gapFillerImgSrc = $gapFiller.find('img').attr('src'); + var $hotspot = $('.main-image-box rect', $container).eq(5); + + interactUtils.tapOn( + $gapFiller, + function() { + interactUtils.tapOn( + $hotspot, + function() { + var $gapFillerOnHotspot = $container.find('.main-image-box image').eq(1); + assert.equal( + $gapFillerOnHotspot.attr('href'), + gapFillerImgSrc, + 'gap filler is on canvas' + ); + + _.delay(function() { + // Reset response manually + var interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + assert.equal( + $container.find('.main-image-box image').length, + 1, // This is the canvas image + 'there is no filled gap' + ); + + ready(); + }, 100); + }, 100); + }, + 300 + ); + }, + 100 + ); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + assert.expect(1); + + var $container = $('#' + outsideContainerId); + assert.equal($container.length, 1, 'the item container exists'); + + qtiItemRunner('qti', gapMatchData) + .on('render', function() { + ready(); + }) + .on('statechange', function(state) { + document.getElementById('response-display').textContent = JSON.stringify(state); + }) + .assets(strategies) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/inlineChoice/test.html b/test/qtiCommonRenderer/interactions/inlineChoice/test.html new file mode 100644 index 00000000..f5c37cac --- /dev/null +++ b/test/qtiCommonRenderer/interactions/inlineChoice/test.html @@ -0,0 +1,26 @@ + + + + + InlineChoice Interaction Test + + + + +
+
+
+
+ +
+ + diff --git a/test/qtiCommonRenderer/interactions/inlineChoice/test.js b/test/qtiCommonRenderer/interactions/inlineChoice/test.js new file mode 100644 index 00000000..b086aeae --- /dev/null +++ b/test/qtiCommonRenderer/interactions/inlineChoice/test.js @@ -0,0 +1,397 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/richardIII-1.json' +], function($, _, qtiItemRunner, inlineChoiceData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('Inline Choice Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correclty', function(assert) { + var ready = assert.async(); + assert.expect(17); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', inlineChoiceData) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('select.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('select.qti-interaction.qti-inlineChoiceInteraction').length, + 1, + 'the container contains a choice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option').length, + 5, + 'the interaction has 5 options' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + //Check select2 + assert.equal( + $container.find('.select2-container.qti-interaction.qti-inlineChoiceInteraction').length, + 1, + 'select2 is initialized' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'inlineChoice', + 'the .qti-item node has the right identifier' + ); + + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(1)').val(), + '', + 'the 1st choice has no value' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(1)').text(), + '', + 'the 1st choice is empty' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(2)').val(), + 'empty', + 'the 2nd choice has a value of "empty"' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(3)').data('identifier'), + 'G', + 'the 3rd choice has the right identifier' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(4)').data('identifier'), + 'L', + 'the 4th choice has the right identifier' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(5)').data('identifier'), + 'Y', + 'the 5th choice has the right identifier' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to select a choice', function(assert) { + var ready = assert.async(); + assert.expect(8); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', inlineChoiceData) + .on('render', function() { + var $select = $('select.qti-inlineChoiceInteraction', $container); + assert.equal( + $select.length, + 1, + 'the container contains an inlineChoice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + var $select2Container = $('.select2-container', $container); + assert.equal($select2Container.length, 1, 'select2 is initialized'); + + $select.select2('val', 'L').trigger('change'); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { base: { identifier: 'L' } } }, + 'The lancaster response is selected' + ); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + assert.expect(6); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', inlineChoiceData) + .on('render', function() { + var $select = $('select.qti-inlineChoiceInteraction', $container); + assert.equal( + $select.length, + 1, + 'the container contains an inlineChoice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + assert.equal($select.select2('val'), '', 'There is no choice selected'); + + this.setState({ RESPONSE: { response: { base: { identifier: 'G' } } } }); + + _.delay(function() { + assert.equal($select.select2('val'), 'G', 'The G choice is selected'); + + ready(); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + assert.expect(6); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', inlineChoiceData) + .on('render', function() { + var self = this; + + var $select = $('select.qti-inlineChoiceInteraction', $container); + assert.equal( + $select.length, + 1, + 'the container contains an inlineChoice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + var $select2Container = $('.select2-container', $container); + assert.equal($select2Container.length, 1, 'select2 is initialized'); + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + _.delay(function() { + $select.select2('val', 'L').trigger('change'); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { base: null } } }, + 'Updating the values does not trigger response once destroyed' + ); + + ready(); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + assert.expect(7); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', inlineChoiceData) + .on('render', function() { + var self = this; + + var $select = $('select.qti-inlineChoiceInteraction', $container); + assert.equal( + $select.length, + 1, + 'the container contains an inlineChoice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + var $select2Container = $('.select2-container', $container); + assert.equal($select2Container.length, 1, 'select2 is initialized'); + + $select.select2('val', 'L').trigger('change'); + + _.delay(function() { + assert.equal($select.val(), 'L', 'The value is set to Lancaster'); + + //Call destroy manually + var interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + assert.equal($select.val(), 'empty', 'The value is now empty'); + ready(); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('restores order of shuffled choices', function(assert) { + var ready = assert.async(); + assert.expect(10); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + //Hack the item data to set the shuffle attr to true + var shuffled = _.cloneDeep(inlineChoiceData); + shuffled.body.elements.interaction_inlinechoiceinteraction_547464dbc7afc574464937.attributes.shuffle = true; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + var self = this; + + var $select = $('select.qti-inlineChoiceInteraction', $container); + assert.equal( + $select.length, + 1, + 'the container contains an inlineChoice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + this.setState({ + RESPONSE: { + response: { base: null }, + order: ['Y', 'G', 'L'] + } + }); + + _.delay(function() { + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(1)').val(), + '', + 'the 1st choice has no value' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(1)').text(), + '', + 'the 1st choice is empty' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(2)').val(), + 'empty', + 'the 2nd choice has a value of "empty"' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(3)').data('identifier'), + 'Y', + 'the 3rd choice has the right identifier' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(4)').data('identifier'), + 'G', + 'the 4th choice has the right identifier' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option:nth-child(5)').data('identifier'), + 'L', + 'the 5th choice has the right identifier' + ); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var $container = $('#' + outsideContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', inlineChoiceData) + .on('render', function() { + var $select = $('select.qti-inlineChoiceInteraction', $container); + assert.equal( + $select.length, + 1, + 'the container contains an inlineChoice interaction .qti-inlineChoiceInteraction' + ); + assert.equal( + $container.find('select.qti-inlineChoiceInteraction option[data-identifier]').length, + 3, + 'the interaction has 3 choices' + ); + + ready(); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/match/test.html b/test/qtiCommonRenderer/interactions/match/test.html new file mode 100644 index 00000000..17f7ee13 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/match/test.html @@ -0,0 +1,26 @@ + + + + + Match Interaction Test + + + + +
+
+
+
+ +
+ + diff --git a/test/qtiCommonRenderer/interactions/match/test.js b/test/qtiCommonRenderer/interactions/match/test.js new file mode 100644 index 00000000..19290830 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/match/test.js @@ -0,0 +1,476 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/characters.json' +], function($, _, qtiItemRunner, matchData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('Match Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correclty', function(assert) { + var ready = assert.async(); + assert.expect(20); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-matchInteraction').length, + 1, + 'the container contains a choice interaction .qti-matchInteraction' + ); + assert.equal( + $container.find('.qti-matchInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-matchInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-matchInteraction .match-interaction-area').length, + 1, + 'the interaction contains an interaction area' + ); + assert.equal( + $container.find('.qti-matchInteraction .match-interaction-area table').length, + 1, + 'the interaction contains a table element' + ); + assert.equal( + $container.find('.qti-matchInteraction .qti-choice').length, + 7, + 'the interaction has 7 choices' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'match', + 'the .qti-item node has the right identifier' + ); + + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(0) + .data('identifier'), + 'C', + 'the 1st choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(1) + .data('identifier'), + 'D', + 'the 2nd choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(2) + .data('identifier'), + 'L', + 'the 3rd choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(3) + .data('identifier'), + 'P', + 'the 4th choice of the 1st match group has the right identifier' + ); + + assert.equal( + $container + .find('.qti-matchInteraction tbody .qti-choice') + .eq(0) + .data('identifier'), + 'R', + 'the 1st choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction tbody .qti-choice') + .eq(1) + .data('identifier'), + 'M', + 'the 2nd choice of the 2nd match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction tbody .qti-choice') + .eq(2) + .data('identifier'), + 'T', + 'the 3rd choice of the 3rd match group has the right identifier' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to select a choice', function(assert) { + var ready = assert.async(); + assert.expect(8); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-matchInteraction').length, + 1, + 'the container contains a choice interaction .qti-matchInteraction' + ); + assert.equal( + $container.find('.qti-matchInteraction .qti-choice').length, + 7, + 'the interaction has 5 choices' + ); + + var $cr = $('tbody tr:eq(0) td:eq(0) input', $container); + assert.equal($cr.length, 1, 'the CR pair exists'); + + $cr.click(); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { list: { directedPair: [['C', 'R']] } } }, + 'The pair CR is selected' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to select multiple choices', function(assert) { + var ready = assert.async(); + assert.expect(9); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-matchInteraction').length, + 1, + 'the container contains a choice interaction .qti-matchInteraction' + ); + assert.equal( + $container.find('.qti-matchInteraction .qti-choice').length, + 7, + 'the interaction has 5 choices' + ); + + var $cr = $('tbody tr:eq(0) td:eq(0) input', $container); + assert.equal($cr.length, 1, 'the CR pair exists'); + + var $dt = $('tbody tr:eq(2) td:eq(1) input', $container); + assert.equal($dt.length, 1, 'the DT pair exists'); + + $cr.prop('checked', true); + $dt.click(); + }) + .on('statechange', function(state) { + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { list: { directedPair: [['C', 'R'], ['D', 'T']] } } }, + 'The pair CR is selected' + ); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + assert.expect(8); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + var $cr = $('tbody tr:eq(0) td:eq(0) input', $container); + assert.equal($cr.length, 1, 'the CR pair exists'); + + var $dt = $('tbody tr:eq(2) td:eq(1) input', $container); + assert.equal($dt.length, 1, 'the DT pair exists'); + + assert.ok(!$cr.prop('checked'), 'The CR pair is not checked'); + assert.ok(!$dt.prop('checked'), 'The DT pair is not checked'); + + this.setState({ RESPONSE: { response: { list: { directedPair: [['C', 'R'], ['D', 'T']] } } } }); + + _.delay(function() { + assert.ok($cr.prop('checked'), 'The CR pair is now checked'); + assert.ok($dt.prop('checked'), 'The DT pair is now checked'); + + ready(); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + var self = this; + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + var $cr = $('tbody tr:eq(0) td:eq(0)', $container); + assert.equal($cr.length, 1, 'the CR pair exists'); + + $cr.click(); + + _.delay(function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { list: { directedPair: [] } } } }, + 'Click does not trigger response once destroyed' + ); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + assert.expect(6); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + var self = this; + + var $cr = $('tbody tr:eq(0) td:eq(0) input', $container); + assert.equal($cr.length, 1, 'the CR pair exists'); + + var $dt = $('tbody tr:eq(2) td:eq(1) input', $container); + assert.equal($dt.length, 1, 'the DT pair exists'); + + $cr.click(); + $dt.click(); + + _.delay(function() { + //Call destroy manually + var interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + assert.ok(!$cr.prop('checked'), 'The CR pair is not checked anymore'); + assert.ok(!$dt.prop('checked'), 'The DT pair is not checked anymore'); + + ready(); + }, 100); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.test('restores order of shuffled choices', function(assert) { + var ready = assert.async(); + assert.expect(11); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + //Hack the item data to set the shuffle attr to true + var shuffled = _.cloneDeep(matchData); + shuffled.body.elements.interaction_matchinteraction_547481b197d23287450469.attributes.shuffle = true; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + var self = this; + + assert.equal( + $container.find('.qti-interaction.qti-matchInteraction').length, + 1, + 'the container contains a choice interaction .qti-matchInteraction' + ); + assert.equal( + $container.find('.qti-matchInteraction .qti-choice').length, + 7, + 'the interaction has 7 choices' + ); + + this.setState({ + RESPONSE: { + response: { base: null }, + order: [['P', 'L', 'C', 'D'], ['M', 'T', 'R']] + } + }); + + _.delay(function() { + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(0) + .data('identifier'), + 'P', + 'the 1st choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(1) + .data('identifier'), + 'L', + 'the 2nd choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(2) + .data('identifier'), + 'C', + 'the 3rd choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction thead .qti-choice') + .eq(3) + .data('identifier'), + 'D', + 'the 4th choice of the 1st match group has the right identifier' + ); + + assert.equal( + $container + .find('.qti-matchInteraction tbody .qti-choice') + .eq(0) + .data('identifier'), + 'M', + 'the 1st choice of the 1st match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction tbody .qti-choice') + .eq(1) + .data('identifier'), + 'T', + 'the 2nd choice of the 2nd match group has the right identifier' + ); + assert.equal( + $container + .find('.qti-matchInteraction tbody .qti-choice') + .eq(2) + .data('identifier'), + 'R', + 'the 3rd choice of the 3rd match group has the right identifier' + ); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var $container = $('#' + outsideContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', matchData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-matchInteraction').length, + 1, + 'the container contains a choice interaction .qti-matchInteraction' + ); + assert.equal( + $container.find('.qti-matchInteraction .qti-choice').length, + 7, + 'the interaction has 5 choices' + ); + + ready(); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/media/test.html b/test/qtiCommonRenderer/interactions/media/test.html new file mode 100644 index 00000000..98871ff0 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/media/test.html @@ -0,0 +1,28 @@ + + + + + Media Interaction Test + + + + +
+
+
+
+
+
+
+ +
+ + diff --git a/test/qtiCommonRenderer/interactions/media/test.js b/test/qtiCommonRenderer/interactions/media/test.js new file mode 100644 index 00000000..280e9b0d --- /dev/null +++ b/test/qtiCommonRenderer/interactions/media/test.js @@ -0,0 +1,381 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/media/video.json', + 'json!taoQtiItem/test/samples/json/media/audio.json' +], function($, _, qtiItemRunner, videoItemData, audioItemData) { + 'use strict'; + + var isHeadless = /(PhantomJS|HeadlessChrome)/.test(navigator.userAgent); + var videoSampleUrl = '/test/samples/json/media/sample.mp4'; + var audioSampleUrl = '/test/samples/json/media/sample.mp3'; + + QUnit.module('Media Interaction'); + + QUnit.test('video renders correctly', function(assert) { + var ready = assert.async(); + var $container; + var runner; + + assert.expect(13); + + $container = $('#item-container-video'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + $container.one('playerrendered', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container exists'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-mediaInteraction').length, + 1, + 'the container contains a choice interaction .qti-mediaInteraction' + ); + assert.equal( + $container.find('.qti-mediaInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-mediaInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-mediaInteraction video').length, + 1, + 'the interaction contains a video tag' + ); + assert.equal( + $container.find('.qti-mediaInteraction video source').length, + 1, + 'the interaction contains a video source tag' + ); + assert.equal( + $container.find('.qti-mediaInteraction video source').attr('src'), + videoSampleUrl, + 'the interaction has proper file attached' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'i1429259831305858', + 'the .qti-item node has the right identifier' + ); + runner.clear(); + + ready(); + }); + runner = qtiItemRunner('qti', videoItemData) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .assets(function(url) { + if (/\.mp4$/.test(url.toString())) { + return videoSampleUrl; + } + return url.toString(); + }) + .init() + .render($container); + }); + + QUnit.test('audio renders correctly', function(assert) { + var ready = assert.async(); + var $container; + var runner; + + assert.expect(15); + + $container = $('#item-container-audio'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + $container.one('playerrendered', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container exists'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-mediaInteraction').length, + 1, + 'the container contains a choice interaction .qti-mediaInteraction' + ); + assert.equal( + $container.find('.qti-mediaInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-mediaInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-mediaInteraction audio').length, + 1, + 'the interaction contains an audio tag' + ); + assert.equal( + $container.find('.qti-mediaInteraction audio source').length, + 1, + 'the interaction contains an audio source tag' + ); + assert.equal( + $container.find('.qti-mediaInteraction audio source').attr('src'), + audioSampleUrl, + 'the interaction has proper file attached' + ); + assert.equal( + $container.find('.qti-mediaInteraction audio source').attr('type'), + 'audio/mpeg', + 'the interaction has proper file type' + ); + assert.equal( + $container.find('.qti-mediaInteraction .control [data-control=play]').length, + 1, + 'the interaction has a play button' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'i1429259831305858', + 'the .qti-item node has the right identifier' + ); + runner.clear(); + ready(); + }); + + runner = qtiItemRunner('qti', audioItemData) + .on('error', function(e) { + assert.ok(false, e); + ready(); + }) + .assets(function(url) { + if (/\.mp3$/.test(url.toString())) { + return audioSampleUrl; + } + return url.toString(); + }) + .init() + .render($container); + }); + + QUnit.test('get state', function(assert) { + var ready = assert.async(); + var $container; + var runner; + + assert.expect(5); + + $container = $('#item-container-getstate'); + + assert.equal($container.find('.qti-mediaInteraction').length, 0, 'The media interaction is not yet rendered'); + + $container.one('playerrendered', function() { + var $mediaInteraction = $container.find('.qti-mediaInteraction'); + var $play = $('.control [data-control=play]', $mediaInteraction); + var toState = setTimeout(function() { + var state = runner.getState(); + assert.ok(state.RESPONSE.player.position > 0, 'The player position has changed'); + runner.clear(); + ready(); + }, 1000); + + assert.equal($mediaInteraction.length, 1, 'The mediaInteraction is rendered'); + assert.equal($play.length, 1, 'The play button is rendered'); + + setTimeout(function() { + //The media player doesnt work properly in PhantomJS, + //so we just skip the test : + if ($('.mediaplayer', $mediaInteraction).hasClass('error')) { + assert.ok(true, 'Skipping'); + clearTimeout(toState); + + ready(); + } else { + $play.click(); + } + }, 250); + }); + if (runner) { + runner.clear(); + } + runner = qtiItemRunner('qti', audioItemData) + .on('init', function() { + var state = this.getState(); + + assert.deepEqual( + state, + { + RESPONSE: { + response: { + base: { + integer: 0 + } + }, + player: { + position: 0, + muted: false, + volume: 100 + } + } + }, + 'The default state is correct' + ); + }) + .on('error', function(err) { + assert.ok(false, err); + ready(); + }) + .assets(function(url) { + if (/\.mp3$/.test(url.toString())) { + return audioSampleUrl; + } + return url.toString(); + }) + .init() + .render($container); + }); + // + + // + if (!isHeadless) { + QUnit.test('set state', function(assert) { + var ready = assert.async(); + var $container; + var runner; + + assert.expect(3); + + $container = $('#item-container-setstate'); + + assert.equal( + $container.find('.qti-mediaInteraction').length, + 0, + 'The media interaction is not yet rendered' + ); + + $container.on('playerrendered', function() { + var $mediaInteraction = $container.find('.qti-mediaInteraction'); + assert.equal($mediaInteraction.length, 1, 'The mediaInteraction is rendered'); + if ($('.mediaplayer', $mediaInteraction).hasClass('error') || isHeadless) { + assert.ok(true, 'Skipping'); + } else { + setTimeout(function() { + var state = runner.getState(); + + //The media player doesnt work properly in PhantomJS, + //so we just skip the test : + if ($('.mediaplayer', $mediaInteraction).hasClass('error') || isHeadless) { + assert.ok(true, 'Skipping'); + } else { + assert.ok(state.RESPONSE.player.position > 0, 'The player position has changed'); + } + $container.off('playerrendered'); + runner.clear(); + ready(); + }, 250); + } + }); + + runner = qtiItemRunner('qti', audioItemData) + .on('init', function() { + this.setState({ + RESPONSE: { + response: { + base: { + integer: 0 + } + }, + player: { + position: 1.1, + muted: false, + volume: 90 + } + } + }); + }) + .on('error', function(err) { + assert.ok(false, err); + ready(); + }) + .assets(function(url) { + if (/\.mp3$/.test(url.toString())) { + return audioSampleUrl; + } + return url.toString(); + }) + .init() + .render($container); + }); + QUnit.module('Visual Test'); + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + var $container; + var runner; + + assert.expect(4); + + $container = $('#visual-test'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + $container.off('playerrendered'); + + $container.one('playerrendered', function() { + assert.equal( + $container.find('.qti-interaction.qti-mediaInteraction').length, + 1, + 'the container contains a choice interaction .qti-mediaInteraction' + ); + assert.equal($container.find('.qti-mediaInteraction video').length, 1, 'the interaction has element'); + + ready(); + }); + runner = qtiItemRunner('qti', videoItemData) + .assets(function(url) { + if (/\.mp4$/.test(url.toString())) { + return videoSampleUrl; + } + return url.toString(); + }) + .init() + .render($container); + }); + } +}); diff --git a/test/qtiCommonRenderer/interactions/order/test.html b/test/qtiCommonRenderer/interactions/order/test.html new file mode 100644 index 00000000..02dc1eae --- /dev/null +++ b/test/qtiCommonRenderer/interactions/order/test.html @@ -0,0 +1,27 @@ + + + + + Order Interaction Test + + + + +
+
+
+
+ +
+
+ + diff --git a/test/qtiCommonRenderer/interactions/order/test.js b/test/qtiCommonRenderer/interactions/order/test.js new file mode 100644 index 00000000..2e84cd55 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/order/test.js @@ -0,0 +1,590 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'core/mouseEvent', + 'ui/interactUtils', + 'json!taoQtiItem/test/samples/json/history.json' +], function($, _, qtiItemRunner, triggerMouseEvent, interactUtils, orderData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('Order Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correctly', function(assert) { + var ready = assert.async(); + assert.expect(18); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-orderInteraction').length, + 1, + 'the container contains a choice interaction .qti-orderInteraction' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-orderInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-orderInteraction .choice-area').length, + 1, + 'the interaction contains a choice list' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area').length, + 1, + 'the interaction contains a result area' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'periods-of-history', + 'the .qti-item node has the right identifier' + ); + + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(1)').data('identifier'), + 'Prehistory', + 'the 1st choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(2)').data('identifier'), + 'Antiquity', + 'the 2nd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(3)').data('identifier'), + 'MiddleAges', + 'the 3rd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(4)').data('identifier'), + 'ModernEra', + 'the 4th choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(5)').data('identifier'), + 'ContemporaryEra', + 'the 5th choice has the right identifier' + ); + + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to select a choice', function(assert) { + var ready = assert.async(); + assert.expect(10); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + var $prehistory = $('.qti-choice[data-identifier="Prehistory"]', $container); + + assert.equal( + $container.find('.qti-interaction.qti-orderInteraction').length, + 1, + 'the container contains a choice interaction .qti-orderInteraction' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + assert.equal($prehistory.length, 1, 'the Prehistory choice exists'); + + interactUtils.tapOn($prehistory); + }) + .on('statechange', function(state) { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 4, + 'the choice list contains now 4 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 1, + 'the result list contains now 1 choice' + ); + + assert.ok(typeof state === 'object', 'The state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'The state has a response object'); + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: ['Prehistory'] } } }, + 'The Prehistory response is selected' + ); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('enables to remove a choice', function(assert) { + var ready = assert.async(); + assert.expect(7); + + var $container = $('#' + fixtureContainerId); + var changes = 0; + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + var $prehistory = $('.qti-choice[data-identifier="Prehistory"]', $container); + + interactUtils.tapOn( + $prehistory, + function() { + interactUtils.tapOn( + $prehistory, + function() { + var $removeChoice = $('.icon-remove-from-selection', $container); + interactUtils.tapOn($removeChoice); + }, + 100 + ); + }, + 100 + ); + }) + .on('statechange', function(state) { + changes++; + if (changes === 1) { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 4, + 'the choice list contains now 4 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 1, + 'the result list contains now 1 choice' + ); + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: ['Prehistory'] } } }, + 'The Prehistory response is selected' + ); + } else if (changes === 2) { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 5, + 'the choice list contains now 5 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 0, + 'the result list contains now 0 choice' + ); + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: [] } } }, + 'The Prehistory response has been removed from selection' + ); + + ready(); + } + }) + .init() + .render($container); + }); + + QUnit.test('enables to reorder choices', function(assert) { + var ready = assert.async(); + assert.expect(12); + + var $container = $('#' + fixtureContainerId); + var changes = 0; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-orderInteraction').length, + 1, + 'the container contains a choice interaction .qti-orderInteraction' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + var $prehistory = $('.qti-choice[data-identifier="Prehistory"]', $container); + assert.equal($prehistory.length, 1, 'the Prehistory choice exists'); + + var $antiquity = $('.qti-choice[data-identifier="Antiquity"]', $container); + assert.equal($antiquity.length, 1, 'the Antiquity choice exists'); + + interactUtils.tapOn( + $prehistory, + function() { + interactUtils.tapOn( + $antiquity, + function() { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 3, + 'the choice list contains now 3 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 2, + 'the result list contains now 2 choice' + ); + + interactUtils.tapOn( + $antiquity, + function() { + assert.ok($antiquity.hasClass('active'), 'The antiquity choice is now active'); + + interactUtils.tapOn($('.icon-move-before')); + }, + 10 + ); + }, + 10 + ); + }, + 10 + ); + }) + .on('statechange', function(state) { + changes++; + if (changes === 1) { + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: ['Prehistory'] } } }, + 'The response is ok' + ); + } else if (changes === 2) { + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: ['Prehistory', 'Antiquity'] } } }, + 'The response is ok' + ); + } else if (changes === 3) { + assert.deepEqual( + state.RESPONSE, + { response: { list: { identifier: ['Antiquity', 'Prehistory'] } } }, + 'The response follows the reordering' + ); + ready(); + } + }) + .init() + .render($container); + }); + + QUnit.test('set the default response', function(assert) { + var ready = assert.async(); + assert.expect(6); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 5, + 'the choice list contains all choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 0, + 'the result list contains no choices' + ); + + this.setState({ RESPONSE: { response: { list: { identifier: ['Antiquity', 'Prehistory'] } } } }); + + _.delay(function() { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 3, + 'the choice list contains now 3 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 2, + 'the result list contains now 2 choices' + ); + + ready(); + }, 10); + }) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + var self = this; + + //Call destroy manually + var interaction = this._item.getInteractions()[0]; + interaction.renderer.destroy(interaction); + + var $prehistory = $('.qti-choice[data-identifier="Prehistory"]', $container); + assert.equal($prehistory.length, 1, 'the Prehistory choice exists'); + + interactUtils.tapOn( + $prehistory, + function() { + assert.deepEqual( + self.getState(), + { RESPONSE: { response: { list: { identifier: [] } } } }, + 'Click does not trigger response once destroyed' + ); + + ready(); + }, + 100 + ); + }) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + assert.expect(11); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + var self = this; + + assert.equal( + $container.find('.qti-interaction.qti-orderInteraction').length, + 1, + 'the container contains a choice interaction .qti-orderInteraction' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + var $prehistory = $('.qti-choice[data-identifier="Prehistory"]', $container); + assert.equal($prehistory.length, 1, 'the Prehistory choice exists'); + + interactUtils.tapOn( + $prehistory, + function() { + interactUtils.tapOn( + $prehistory, + function() { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 4, + 'the choice list contains now 4 choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 1, + 'the result list contains now 1 choice' + ); + assert.ok($prehistory.hasClass('active'), 'the Prehistory choice is active'); + + //Call resetResponse manually + var interaction = self._item.getInteractions()[0]; + interaction.renderer.resetResponse(interaction); + + _.delay(function() { + assert.equal( + $container.find('.qti-orderInteraction .choice-area .qti-choice').length, + 5, + 'the choice list contains all choices' + ); + assert.equal( + $container.find('.qti-orderInteraction .result-area .qti-choice').length, + 0, + 'the result list contains no choices anymore' + ); + assert.ok(!$prehistory.hasClass('active'), 'the Prehistory choice is not active'); + + ready(); + }, 100); + }, + 100 + ); + }, + 100 + ); + }) + .init() + .render($container); + }); + + QUnit.test('restores order of shuffled choices', function(assert) { + var ready = assert.async(); + assert.expect(9); + + var $container = $('#' + fixtureContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + //Hack the item data to set the shuffle attr to true + var shuffled = _.cloneDeep(orderData); + shuffled.body.elements.interaction_orderinteraction_547481ffc8c1b803673841.attributes.shuffle = true; + + runner = qtiItemRunner('qti', shuffled) + .on('render', function() { + var self = this; + + assert.equal( + $container.find('.qti-interaction.qti-orderInteraction').length, + 1, + 'the container contains a choice interaction .qti-orderInteraction' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + this.setState({ + RESPONSE: { + response: { list: { identifier: [] } }, + order: ['ContemporaryEra', 'Antiquity', 'ModernEra', 'MiddleAges', 'Prehistory'] + } + }); + + _.delay(function() { + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(1)').data('identifier'), + 'ContemporaryEra', + 'the 1st choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(2)').data('identifier'), + 'Antiquity', + 'the 2nd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(3)').data('identifier'), + 'ModernEra', + 'the 3rd choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(4)').data('identifier'), + 'MiddleAges', + 'the 4th choice has the right identifier' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice:nth-child(5)').data('identifier'), + 'Prehistory', + 'the 5th choice has the right identifier' + ); + + ready(); + }, 100); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var $container = $('#' + outsideContainerId); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', orderData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-orderInteraction').length, + 1, + 'the container contains a choice interaction .qti-orderInteraction' + ); + assert.equal( + $container.find('.qti-orderInteraction .qti-choice').length, + 5, + 'the interaction has 5 choices' + ); + + ready(); + }) + .on('statechange', function(state) { + document.getElementById('display-response').textContent = JSON.stringify(state); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/selectPoint/assets/us.jpg b/test/qtiCommonRenderer/interactions/selectPoint/assets/us.jpg new file mode 100644 index 00000000..e83a9031 Binary files /dev/null and b/test/qtiCommonRenderer/interactions/selectPoint/assets/us.jpg differ diff --git a/test/qtiCommonRenderer/interactions/selectPoint/qti.json b/test/qtiCommonRenderer/interactions/selectPoint/qti.json new file mode 100644 index 00000000..02c13721 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/selectPoint/qti.json @@ -0,0 +1,182 @@ +{ + "identifier": "i14862478187486450", + "serial": "item_589665700e6aa547084007", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14862478187486450", + "title": "Select Point Interaction", + "label": "Select Point Interaction", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint43", + "class": "" + }, + "body": { + "serial": "container_containeritembody_589665700e692347974427", + "body": "\n
\n
\n {{interaction_selectpointinteraction_5896657031abe915479781}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_selectpointinteraction_5896657031abe915479781": { + "serial": "interaction_selectpointinteraction_5896657031abe915479781", + "qtiClass": "selectPointInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 0, + "minChoices": 0, + "class": "responsive" + }, + "debug": { + "relatedItem": "item_589665700e6aa547084007" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_5896657037d17805246232", + "body": "\n

Select the state of Iowa.<\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_589665700e6aa547084007" + } + }, + "object": { + "serial": "object_589665703bc0e529145041", + "qtiClass": "object", + "attributes": { + "data": "assets\/us.jpg", + "type": "image\/jpeg", + "width": 4726, + "height": 2960 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_589665700e6aa547084007" + } + }, + "debug": { + "relatedItem": "item_589665700e6aa547084007" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_5896657027530643871378": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5896657027530643871378", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_589665700e6aa547084007" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5896657020e2b342908780": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5896657020e2b342908780", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "point" + }, + "debug": { + "relatedItem": "item_589665700e6aa547084007" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [ + { + "shape": "poly", + "coords": "2498,1276,2404,923,2863,917,2957,1093,2857,1299", + "mappedValue": "1" + } + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response_point", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 1, + "lowerBound": "0", + "upperBound": "1" + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_589665703f539403159372", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_589665700e6aa547084007" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponsePoint", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} diff --git a/test/qtiCommonRenderer/interactions/selectPoint/test.html b/test/qtiCommonRenderer/interactions/selectPoint/test.html new file mode 100644 index 00000000..5b2ad715 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/selectPoint/test.html @@ -0,0 +1,27 @@ + + + + + Select Point Interaction Test + + + + +

+
+
+
+ +
+
+ + diff --git a/test/qtiCommonRenderer/interactions/selectPoint/test.js b/test/qtiCommonRenderer/interactions/selectPoint/test.js new file mode 100644 index 00000000..15e2c3a8 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/selectPoint/test.js @@ -0,0 +1,304 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2015 (original work) Open Assessment Technologies SA ; + */ + +define([ + 'jquery', + 'core/mouseEvent', + 'taoQtiItem/runner/qtiItemRunner', + 'taoQtiItem/qtiCommonRenderer/renderers/interactions/SelectPointInteraction', + 'json!taoQtiItem/test/qtiCommonRenderer/interactions/selectPoint/qti.json' +], function($, triggerMouseEvent, qtiItemRunner, selectPointRenderer, selectPointData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + //Override asset loading in order to resolve it from the runtime location + var strategies = [ + { + name: 'default', + handle: function defaultStrategy(url) { + if (/assets/.test(url.toString())) { + return '/test/qtiCommonRenderer/interactions/selectPoint/' + url.toString(); + } + return url.toString(); + } + } + ]; + + QUnit.module('Renderer API'); + + QUnit.test('QTI class', function(assert) { + assert.expect(2); + + assert.equal(typeof selectPointRenderer, 'object', 'The renderer is an object'); + assert.equal(selectPointRenderer.qtiClass, 'selectPointInteraction', 'The renderer class is correct'); + }); + + QUnit.cases + .init([ + { name: 'template', title: 'template' }, + { name: 'render', title: 'render' }, + { name: 'getContainer', title: 'getContainer' }, + { name: 'setResponse', title: 'setResponse' }, + { name: 'getResponse', title: 'getResponse' }, + { name: 'resetResponse', title: 'resetResponse' }, + { name: 'destroy', title: 'destroy' }, + { name: 'setState', title: 'setState' }, + { name: 'getState', title: 'getState' } + ]) + .test('expose method', function(data, assert) { + assert.equal( + typeof selectPointRenderer[data.name], + 'function', + 'The selectPointRenderer exposes the method ' + data.name + ); + }); + + QUnit.module('Select Point Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('renders correctly', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(11); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', selectPointData) + .on('render', function() { + //Check DOM + assert.equal($container.children().length, 1, 'the container a elements'); + assert.equal( + $container.children('.qti-item').length, + 1, + 'the container contains a the root element .qti-item' + ); + assert.equal( + $container.find('.qti-itemBody').length, + 1, + 'the container contains a the body element .qti-itemBody' + ); + assert.equal( + $container.find('.qti-interaction').length, + 1, + 'the container contains an interaction .qti-interaction' + ); + assert.equal( + $container.find('.qti-interaction.qti-selectPointInteraction').length, + 1, + 'the container contains a choice interaction .qti-selectPointInteraction' + ); + assert.equal( + $container.find('.qti-selectPointInteraction .qti-prompt-container').length, + 1, + 'the interaction contains a prompt' + ); + assert.equal( + $container.find('.qti-selectPointInteraction .instruction-container').length, + 1, + 'the interaction contains a instruction box' + ); + assert.equal( + $container.find('.qti-selectPointInteraction .main-image-box').length, + 1, + 'the interaction contains a image' + ); + + //Check DOM data + assert.equal( + $container.children('.qti-item').data('identifier'), + 'i14862478187486450', + 'the .qti-item node has the right identifier' + ); + + ready(); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('destroys', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(3); + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', selectPointData) + .on('render', function() { + var interaction = this._item.getInteractions()[0]; + var $imageBox = $('.main-image-box', $container); + + assert.equal($imageBox.children().length, 1, 'the image box has elements'); + interaction.renderer.destroy(interaction); + assert.equal($imageBox.children().length, 0, 'the image box has no elements'); + + ready(); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('resets the response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(3); + + assert.equal($container.length, 1, 'the item container exists'); + + runner = qtiItemRunner('qti', selectPointData) + .on('render', function() { + var interaction = this._item.getInteractions()[0]; + var $canvas = $('.main-image-box svg', $container); + + triggerMouseEvent($canvas.find('image').get(0), 'click', { bubbles: true }); + + setTimeout(function() { + var $target; + + $target = $canvas.find('path'); + assert.equal($target.length, 1, 'a target exists on image'); + + interaction.renderer.resetResponse(interaction); + + $target = $canvas.find('path'); + assert.equal($target.length, 0, 'no target exists on image'); + + ready(); + }, 50); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('clicking target removes it from interaction', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(2); + + runner = qtiItemRunner('qti', selectPointData) + .on('render', function() { + var $canvas = $('.main-image-box svg', $container); + + triggerMouseEvent($canvas.find('image').get(0), 'click', { bubbles: true }); + + setTimeout(function() { + var $target; + + $target = $canvas.find('path'); + assert.equal($target.length, 1, 'click placed target on image'); + + triggerMouseEvent($canvas.find('rect').get(0), 'click', { bubbles: true }); + + setTimeout(function() { + $target = $canvas.find('path'); + assert.equal($target.length, 0, 'another click removed target from image'); + + ready(); + }, 50); + }, 50); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('set the response', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(2); + + runner = qtiItemRunner('qti', selectPointData) + .on('render', function() { + var interaction = this._item.getInteractions()[0]; + var $canvas = $('.main-image-box svg', $container); + + assert.equal($('path', $canvas).length, 0, 'There is no target'); + + interaction.renderer.setResponse(interaction, { list: { point: [[50, 50]] } }); + setTimeout(function() { + assert.equal($('path', $canvas).length, 1, 'A target have been created'); + ready(); + }, 50); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.test('set multiple responses', function(assert) { + var ready = assert.async(); + var $container = $('#' + fixtureContainerId); + + assert.expect(2); + + runner = qtiItemRunner('qti', selectPointData) + .on('render', function() { + var interaction = this._item.getInteractions()[0]; + var $canvas = $('.main-image-box svg', $container); + + assert.equal($('path', $canvas).length, 0, 'There is no target'); + + interaction.renderer.setResponse(interaction, { list: { point: [[50, 50], [100, 100]] } }); + setTimeout(function() { + assert.equal($('path', $canvas).length, 2, 'Two targets have been created'); + ready(); + }, 50); + }) + .assets(strategies) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + var $container = $('#' + outsideContainerId); + + assert.expect(1); + + assert.equal($container.length, 1, 'the item container exists'); + + qtiItemRunner('qti', selectPointData) + .on('render', function() { + ready(); + }) + .on('statechange', function(state) { + document.getElementById('response-display').textContent = JSON.stringify(state); + }) + .assets(strategies) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/interactions/textEntry/test.html b/test/qtiCommonRenderer/interactions/textEntry/test.html new file mode 100644 index 00000000..e0e35105 --- /dev/null +++ b/test/qtiCommonRenderer/interactions/textEntry/test.html @@ -0,0 +1,29 @@ + + + + + Text Entry Interaction Test + + + + +
+
+
+
+
+
+
+ +
+ + diff --git a/test/qtiCommonRenderer/interactions/textEntry/test.js b/test/qtiCommonRenderer/interactions/textEntry/test.js new file mode 100644 index 00000000..c688334e --- /dev/null +++ b/test/qtiCommonRenderer/interactions/textEntry/test.js @@ -0,0 +1,224 @@ +define([ + 'jquery', + 'lodash', + 'i18n', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/text-entry-noconstraint.json', + 'json!taoQtiItem/test/samples/json/text-entry-length.json', + 'json!taoQtiItem/test/samples/json/text-entry-pattern.json' +], function($, _, __, qtiItemRunner, textEntryData, textEntryLengthConstrainedData, textEntryPatternConstrainedData) { + 'use strict'; + + var runner; + var fixtureContainerId = 'item-container'; + var outsideContainerId = 'outside-container'; + + QUnit.module('Text Entry Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + function getTooltipContent($input) { + var content = getTooltip($input); + if (content) { + return content.find('.tooltip-body').html(); + } + } + + function getTooltip($input) { + var instance = $input.data('$tooltip'); + if (instance && instance.popperInstance.popper) { + return $(instance.popperInstance.popper); + } + } + + QUnit.test('Lenght constraint', function(assert) { + var ready = assert.async(); + + var $container = $('#fixture-length-constraint'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + runner = qtiItemRunner('qti', textEntryLengthConstrainedData) + .on('render', function() { + var $input = $container.find('.qti-interaction.qti-textEntryInteraction'); + + assert.equal( + $input.length, + 1, + 'the container contains a text entry interaction .qti-textEntryInteraction' + ); + + $input.val(''); + $input.focus(); + assert.equal( + getTooltipContent($input), + __('%d characters allowed', 5), + 'the instruction message is correct' + ); + assert.ok(getTooltip($input).is(':visible'), 'info tooltip is visible'); + + $input.val('123'); + $input.keyup(); + assert.equal(getTooltipContent($input), __('%d/%d', 3, 5), 'the instruction message is correct'); + assert.ok(getTooltip($input).is(':visible'), 'info tooltip is visible'); + + $input.val('12345'); + $input.keyup(); + assert.equal(getTooltipContent($input), __('%d/%d', 5, 5), 'the warning message is correct'); + assert.ok(getTooltip($input).is(':visible'), 'warning tooltip is visible'); + assert.ok($input.hasClass('maxed'), 'has state maxed'); + + $input.val('1234'); + $input.keyup(); + assert.equal(getTooltipContent($input), __('%d/%d', 4, 5), 'the instruction message is correct'); + assert.ok(getTooltip($input).is(':visible'), 'info tooltip is visible'); + assert.ok(!$input.hasClass('maxed'), 'has state maxed removed'); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('Pattern constraint - incorrect', function(assert) { + var ready = assert.async(2); + + var $container = $('#pattern-constraint-incorrect'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', textEntryPatternConstrainedData) + .on('render', function() { + var $input = $container.find('.qti-interaction.qti-textEntryInteraction'); + + assert.equal( + $input.length, + 1, + 'the container contains a text entry interaction .qti-textEntryInteraction' + ); + + $input.val(''); + $input.focus(); + assert.equal(getTooltipContent($input), __('This is not a valid answer')); + + $input.val('123'); + $input.keyup(); + ready(); + }) + .on('responsechange', function(state) { + var $input = $container.find('.qti-interaction.qti-textEntryInteraction'); + assert.equal( + getTooltipContent($input), + __('This is not a valid answer'), + 'the error message is correct' + ); + assert.ok(getTooltip($input).is(':visible'), 'the error tooltip is visible after an invalid response'); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('Pattern constraint - correct', function(assert) { + var ready = assert.async(2); + + var $container = $('#pattern-constraint-correct'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', textEntryPatternConstrainedData) + .on('render', function() { + var $input = $container.find('.qti-interaction.qti-textEntryInteraction'); + + assert.equal( + $input.length, + 1, + 'the container contains a text entry interaction .qti-textEntryInteraction' + ); + + $input.val(''); + $input.focus(); + assert.equal(getTooltipContent($input), __('This is not a valid answer')); + + $input.val('PARIS'); + $input.keyup(); + ready(); + }) + .on('responsechange', function(state) { + var $input = $container.find('.qti-interaction.qti-textEntryInteraction'); + assert.equal( + getTooltipContent($input), + __('This is not a valid answer'), + 'the error tooltip is hidden after a correct response' + ); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('set/get response', function(assert) { + var ready = assert.async(); + + var $container = $('#set-get-response'); + var state = { RESPONSE: { response: { base: { string: 'PARIS' } } } }; + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', textEntryData) + .on('render', function() { + ready(); + var $input = $container.find('.qti-interaction.qti-textEntryInteraction'); + + assert.equal( + $input.length, + 1, + 'the container contains a text entry interaction .qti-textEntryInteraction' + ); + assert.equal($input.val(), '', 'the text input is initially empty'); + + this.setState(state); + + assert.equal($input.val(), 'PARIS', 'the text input has been correctly set'); + assert.deepEqual(this.getState(state), state, 'state is correct'); + + $input.keyup(); //Trigger the response changed event + }) + .on('statechange', function(retrivedState) { + assert.deepEqual(retrivedState, state, 'statechange state is correct'); + }) + .init() + .render($container); + }); + + QUnit.module('Visual Test'); + + QUnit.test('Display and play', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var $container = $('#outside-container'); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + qtiItemRunner('qti', textEntryLengthConstrainedData) + .on('render', function() { + assert.equal( + $container.find('.qti-interaction.qti-textEntryInteraction').length, + 1, + 'the container contains a text entry interaction .qti-textEntryInteraction' + ); + + ready(); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiCommonRenderer/renderers/include/test.html b/test/qtiCommonRenderer/renderers/include/test.html new file mode 100644 index 00000000..6a2a73e6 --- /dev/null +++ b/test/qtiCommonRenderer/renderers/include/test.html @@ -0,0 +1,25 @@ + + + + + QTI Item include renderer Test + + + + +
+
+
+
+
+ + diff --git a/test/qtiCommonRenderer/renderers/include/test.js b/test/qtiCommonRenderer/renderers/include/test.js new file mode 100644 index 00000000..6d12cc4a --- /dev/null +++ b/test/qtiCommonRenderer/renderers/include/test.js @@ -0,0 +1,67 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2019 (original work) Open Assessment Technologies SA; + */ + +/** + * Test the include renderer taoQtiItem/qtiCommonRenderer/renderers/Include + * + * @author Martin Nicholson + */ + +define([ + 'jquery', + 'taoQtiItem/qtiItem/core/Loader', + 'taoQtiItem/qtiCommonRenderer/renderers/Renderer', + 'json!taoQtiItem/test/samples/json/with-stimulus.json' +], function($, QtiLoader, QtiRenderer, itemData) { + 'use strict'; + + QUnit.module('HTML rendering'); + + QUnit.test('renders an item', function(assert) { + var ready = assert.async(); + var renderer = new QtiRenderer({ baseUrl: './' }); + + assert.expect(6); + + new QtiLoader().loadItemData(itemData, function(item) { + renderer.load(function() { + var result, $result; + + item.setRenderer(this); + + result = item.render({}); + + assert.ok(typeof result === 'string', 'The renderer creates a string'); + assert.ok(result.length > 0, 'The renderer create some output'); + + $result = $(result); + + assert.ok($result.hasClass('qti-item'), 'The result is a qti item'); + assert.equal($('.qti-itemBody', $result).length, 1, 'The result contains an item body'); + assert.equal($('.qti-include', $result).length, 1, 'The result contains a qti include'); + assert.equal( + $('.qti-include', $result).data('href'), + 'taomedia://mediamanager/http_2_tao12_0_local_1_first_0_rdf_3_i1550672688604730', + 'The qti include has the expected href attribute' + ); + + ready(); + }, this.getLoadedClasses()); + }); + }); +}); diff --git a/test/qtiCommonRenderer/renderers/renderer/test.html b/test/qtiCommonRenderer/renderers/renderer/test.html new file mode 100644 index 00000000..190d5deb --- /dev/null +++ b/test/qtiCommonRenderer/renderers/renderer/test.html @@ -0,0 +1,25 @@ + + + + + QTI Item core renderer Test + + + + +
+
+
+
+
+ + diff --git a/test/qtiCommonRenderer/renderers/renderer/test.js b/test/qtiCommonRenderer/renderers/renderer/test.js new file mode 100644 index 00000000..847f4db3 --- /dev/null +++ b/test/qtiCommonRenderer/renderers/renderer/test.js @@ -0,0 +1,108 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/qtiItem/core/Loader', + 'taoQtiItem/qtiCommonRenderer/renderers/Renderer', + 'json!taoQtiItem/test/samples/json/space-shuttle.json' +], function($, _, QtiLoader, QtiRenderer, itemData) { + 'use strict'; + + var containerId = 'item-container'; + + QUnit.module('HTML rendering'); + + QUnit.test('renders an item', function(assert) { + var ready = assert.async(); + var renderer = new QtiRenderer({ baseUrl: './' }); + + assert.expect(5); + + new QtiLoader().loadItemData(itemData, function(item) { + renderer.load(function() { + var result, $result; + + item.setRenderer(this); + + result = item.render({}); + + assert.ok(typeof result === 'string', 'The renderer creates a string'); + assert.ok(result.length > 0, 'The renderer create some output'); + + $result = $(result); + + assert.ok($result.hasClass('qti-item'), 'The result is a qti item'); + assert.equal($('.qti-itemBody', $result).length, 1, 'The result contains an item body'); + assert.equal( + $('.qti-choiceInteraction', $result).length, + 1, + 'The result contains a choice interaction' + ); + + ready(); + }, this.getLoadedClasses()); + }); + }); + + QUnit.test('renders decorated interactions', function(assert) { + var ready = assert.async(); + + //Set up decorator + var renderer = new QtiRenderer({ + baseUrl: './', + decorators: { + before: function preRender(element) { + if (element.qtiClass === 'choiceInteraction') { + return '

pre

'; + } + }, + after: function postRender(element, qtiSubclass) { + if (element.qtiClass === 'choiceInteraction') { + return '

post

'; + } + } + } + }); + + assert.expect(8); + + new QtiLoader().loadItemData(itemData, function(item) { + renderer.load(function() { + var result, $result; + + item.setRenderer(this); + + result = item.render({}); + + assert.ok(typeof result === 'string', 'The renderer creates a string'); + assert.ok(result.length > 0, 'The renderer create some output'); + + $result = $(result); + + assert.ok($result.hasClass('qti-item'), 'The result is a qti item'); + assert.equal( + $('.qti-choiceInteraction', $result).length, + 1, + 'The result contains a choice interaction' + ); + + assert.equal($('.pre-choice', $result).length, 1, 'The pre decorator has been inserted'); + assert.ok( + $('.qti-choiceInteraction', $result) + .prev() + .hasClass('pre-choice'), + 'The pre decorator is previous the choice interaction' + ); + + assert.equal($('.post-choice', $result).length, 1, 'The post decorator has been inserted'); + assert.ok( + $('.qti-choiceInteraction', $result) + .next() + .hasClass('post-choice'), + 'The post decorator is next to the choice interaction' + ); + + ready(); + }, this.getLoadedClasses()); + }); + }); +}); diff --git a/test/qtiCommonRenderer/static/tooltip/test.html b/test/qtiCommonRenderer/static/tooltip/test.html new file mode 100644 index 00000000..f5e8bea8 --- /dev/null +++ b/test/qtiCommonRenderer/static/tooltip/test.html @@ -0,0 +1,26 @@ + + + + + Tooltip common renderer + + + + + + +
+
+
+
+
+ + diff --git a/test/qtiCommonRenderer/static/tooltip/test.js b/test/qtiCommonRenderer/static/tooltip/test.js new file mode 100644 index 00000000..3293495d --- /dev/null +++ b/test/qtiCommonRenderer/static/tooltip/test.js @@ -0,0 +1,156 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2017 (original work) Open Assessment Technologies SA; + */ +/** + * @author Christophe Noël + */ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'taoQtiItem/qtiItem/core/Tooltip', + 'json!taoQtiItem/test/samples/json/static/tooltip.json', + 'ui/tooltip' +], function($, _, qtiItemRunner, Tooltip, itemData, tooltip) { + 'use strict'; + + var runner; + var fixtureContainerId = '#item-container'; + var outsideContainerId = '#outside-container'; + + QUnit.module('Order Interaction', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.module('Tooltip renderer'); + + QUnit.test('renders correctly', function(assert) { + var ready = assert.async(); + var $container = $(fixtureContainerId); + + assert.expect(16); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + var $allTooltips, $tooltipContent, $tooltip, contentId; + + assert.equal($container.children().length, 1, 'the container has an element'); + + $allTooltips = $container.find('[data-qti-class="_tooltip"]'); + + assert.equal($allTooltips.length, 4, '4 tooltips have been found'); + + $allTooltips.get(0).dispatchEvent(new Event('mouseenter')); + $allTooltips.trigger('mouseenter'); + + _.delay(function() { + $tooltip = $allTooltips.eq(0); + contentId = $tooltip.attr('aria-describedby'); + $tooltipContent = $('#' + contentId); + assert.equal( + $tooltip.html().trim(), + 'inline interaction container', + 'tooltip 1 has the correct target' + ); + assert.equal($tooltipContent.length, 1, 'tooltip 1 has a content'); + assert.equal( + $tooltipContent.text().trim(), + 'This is a container for inline choices and inline text entries.', + 'tooltip content is correct' + ); + + $tooltip = $allTooltips.eq(1); + $tooltip.data('$tooltip').show(); + contentId = $tooltip.attr('aria-describedby'); + $tooltipContent = $('#' + contentId); + assert.equal($tooltip.html().trim(), 'tooltip', 'tooltip 2 has the correct target'); + assert.equal($tooltipContent.length, 1, 'tooltip 2 has a content'); + assert.equal( + $tooltipContent.text().trim(), + 'Some say that the word "tooltip" does not really exist.', + 'tooltip content is correct' + ); + + $tooltip = $allTooltips.eq(2); + $tooltip.data('$tooltip').show(); + contentId = $tooltip.attr('aria-describedby'); + $tooltipContent = $('#' + contentId); + assert.equal( + $tooltip.html().trim(), + 'QTI prompt', + 'tooltip 3 has the correct target' + ); + assert.equal($tooltipContent.length, 1, 'tooltip 3 has a content'); + assert.equal( + $tooltipContent.text().trim(), + 'The text before the question.', + 'tooltip content is correct' + ); + + $tooltip = $allTooltips.eq(3); + $tooltip.data('$tooltip').show(); + contentId = $tooltip.attr('aria-describedby'); + $tooltipContent = $('#' + contentId); + assert.equal($tooltip.html().trim(), 'strange word', 'tooltip 4 has the correct target'); + assert.equal($tooltipContent.length, 1, 'tooltip 4 has a content'); + assert.equal( + $tooltipContent.text().trim(), + 'But it will not be revealed here.', + 'tooltip content is correct' + ); + + ready(); + }, 200); + }) + .on('error', function(err) { + window.console.log(err); + }) + .init() + .render($container); + }); + + QUnit.module('Visual test'); + + QUnit.test('display and play', function(assert) { + var ready = assert.async(); + var $container = $(outsideContainerId); + + assert.expect(3); + + assert.equal($container.length, 1, 'the item container exists'); + assert.equal($container.children().length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.equal($container.children().length, 1, 'the container has an element'); + + ready(); + }) + .on('error', function(err) { + window.console.log(err); + }) + .init() + .render($container); + }); +}); diff --git a/test/qtiItem/container/test.html b/test/qtiItem/container/test.html new file mode 100644 index 00000000..f7934262 --- /dev/null +++ b/test/qtiItem/container/test.html @@ -0,0 +1,25 @@ + + + + + QTI Item container helper + + + + +
+
+
+
+
+ + diff --git a/test/qtiItem/container/test.js b/test/qtiItem/container/test.js new file mode 100644 index 00000000..35a62c85 --- /dev/null +++ b/test/qtiItem/container/test.js @@ -0,0 +1,75 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2016 (original work) Open Assessment Technologies SA + **/ +define(['taoQtiItem/qtiItem/core/feedbacks/ModalFeedback', 'taoQtiItem/qtiItem/helper/container'], function( + ModalFeedback, + container +) { + 'use strict'; + + QUnit.test('set/getEncodedData', function(assert) { + var fb = new ModalFeedback(); + fb.body('

AAA

'); + + //Set data + container.setEncodedData(fb, 'customData1', 'customValueA'); + assert.equal(fb.body(), '

AAA

'); + assert.equal(container.hasEncodedData(fb, 'customData1', 'customValueA'), true); + assert.equal(container.getEncodedData(fb, 'customData1'), 'customValueA'); + + //Edit data + container.setEncodedData(fb, 'customData1', 'customValueB'); + assert.equal(fb.body(), '

AAA

'); + assert.equal(container.hasEncodedData(fb, 'customData1', 'customValueB'), true); + assert.equal(container.getEncodedData(fb, 'customData1'), 'customValueB'); + + //Set another data + container.setEncodedData(fb, 'customData2', 'customValueC'); + assert.equal( + fb.body(), + '

AAA

' + ); + assert.equal(container.hasEncodedData(fb, 'customData1', 'customValueB'), true); + assert.equal(container.getEncodedData(fb, 'customData1'), 'customValueB'); + assert.equal(container.hasEncodedData(fb, 'customData2', 'customValueC'), true); + assert.equal(container.getEncodedData(fb, 'customData2'), 'customValueC'); + }); + + QUnit.test('removeEncodedData', function(assert) { + var fb = new ModalFeedback(); + fb.body('

AAA

'); + + //Set data + container.setEncodedData(fb, 'customData1', 'customValueA'); + assert.equal(container.getEncodedData(fb, 'customData1'), 'customValueA'); + assert.equal(fb.body(), '

AAA

'); + + //Remove data + container.removeEncodedData(fb, 'customData1'); + assert.equal(container.getEncodedData(fb, 'customData1'), undefined); + assert.equal(fb.body(), '

AAA

'); + + //Try removgin again + container.removeEncodedData(fb, 'customData1'); + assert.equal(container.getEncodedData(fb, 'customData1'), undefined); + + //Reset data + container.setEncodedData(fb, 'customData1', 'customValueB'); + assert.equal(container.getEncodedData(fb, 'customData1'), 'customValueB'); + assert.equal(fb.body(), '

AAA

'); + }); +}); diff --git a/test/qtiItem/helper/simpleParser/test.html b/test/qtiItem/helper/simpleParser/test.html new file mode 100755 index 00000000..52a9dac6 --- /dev/null +++ b/test/qtiItem/helper/simpleParser/test.html @@ -0,0 +1,45 @@ + + + + + Qti SimpleParser Test + + + + +
+
+ + diff --git a/test/qtiItem/helper/simpleParser/test.js b/test/qtiItem/helper/simpleParser/test.js new file mode 100755 index 00000000..7c59cf1c --- /dev/null +++ b/test/qtiItem/helper/simpleParser/test.js @@ -0,0 +1,218 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2014 (original work) Open Assessment Technologies SA; + */ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/qtiItem/helper/simpleParser', + 'text!taoQtiItem/test/samples/qtiv2p1/extended_text_rubric/qti.xml', + 'taoQtiItem/qtiItem/core/Loader', + 'taoQtiItem/qtiItem/core/Container', + 'taoQtiItem/qtiXmlRenderer/renderers/Renderer' +], function($, _, simpleParser, sampleXML, Loader, Container, XmlRenderer) { + 'use strict'; + + QUnit.module('This is a very old test'); + + QUnit.test('parse inline sample', function(assert) { + var ready = assert.async(); + var $rubricBlockXml = $(sampleXML).find('rubricBlock'); + var mathNs = 'm'; //for 'http://www.w3.org/1998/Math/MathML' + var data = simpleParser.parse($rubricBlockXml, { + ns: { + math: mathNs + } + }); + var loader; + + assert.ok(data.body.body, 'has body'); + assert.equal(_.size(data.body.elements), 4, 'elements ok'); + + loader = new Loader(); + loader.loadRequiredClasses(data, function() { + var xmlRenderer; + var container = new Container(); + this.loadContainer(container, data.body); + + xmlRenderer = new XmlRenderer({ shuffleChoices: false }); + xmlRenderer.load(function() { + var xml = container.render(this); + + var $container = $('').html(xml); + var containerData = simpleParser.parse($container, { + ns: { + math: mathNs + } + }); + var containerBis = new Container(); + loader.loadContainer(containerBis, containerData.body); + + ready(); + assert.equal(xml.length, containerBis.render(this).length); + }); + }); + }); + + QUnit.module('Parser test'); + + QUnit.cases + .init([ + { + title: 'img', + xml: '
this is an image: . How cool is that???
', + expectedBody: 'this is an image: {{img_XXX}}. How cool is that???', + expectedElement: 'img', + expectedAttributes: { src: 'my/image.png' } + }, + { + title: 'printedVariable', + xml: + '
this is a printedVariable: . How cool is that???
', + expectedBody: 'this is a printedVariable: {{printedVariable_XXX}}. How cool is that???', + expectedElement: 'printedVariable', + expectedAttributes: { + identifier: 'SCORE_TOTAL', + base: '10', + powerForm: 'false', + delimiter: ';', + mappingIndicator: '=', + format: '%2g', + index: '-1', + field: 'test' + } + } + ]) + .test('Simple elements parsing: ', function(data, assert) { + var parsed = simpleParser.parse(data.xml); + var serialRegexp = /{{([a-z_]+)_[0-9a-z]*}}/i; + + var body = parsed.body, + parsedBody = body.body.replace(serialRegexp, '{{$1_XXX}}'), + bodyElementsSerials = Object.keys(body.elements), + serial = bodyElementsSerials[0]; + + assert.expect(4); + + assert.equal(bodyElementsSerials.length, 1, '1 element has been found'); + assert.equal(parsedBody, data.expectedBody, 'parsed body is correct: ' + parsedBody); + assert.equal( + serial.indexOf(data.expectedElement), + 0, + 'element is of the expected type, with serial ' + bodyElementsSerials[0] + ); + assert.deepEqual( + body.elements[serial].attributes, + data.expectedAttributes, + 'element has the expected attributes' + ); + }); + + QUnit.cases + .init([ + { + title: 'regular tooltip', + xml: + '
this is a tooltip: ' + + 'my Target' + + '' + + '. How cool is that???
', + expectedBody: 'this is a tooltip: {{_tooltip_XXX}}. How cool is that???', + expectedElement: '_tooltip', + expectedAttributes: { + 'aria-describedby': '_tooltip-63etvf7pktf2jb16d2a09y' + }, + expectedTarget: 'my Target', + expectedContent: 'my Content' + }, + { + title: 'empty tooltip', + xml: + '
this is a tooltip: ' + + '' + + '' + + '. How cool is that???
', + expectedBody: 'this is a tooltip: {{_tooltip_XXX}}. How cool is that???', + expectedElement: '_tooltip', + expectedAttributes: { + 'aria-describedby': '_tooltip-63etvf7pktf2jb16d2a09y' + }, + expectedTarget: '', + expectedContent: '' + } + ]) + .test('Valid tooltip parsing: ', function(data, assert) { + var parsed = simpleParser.parse(data.xml); + var serialRegexp = /{{([a-z_]+)_[0-9a-z]*}}/i; + + var body = parsed.body, + parsedBody = body.body.replace(serialRegexp, '{{$1_XXX}}'), + bodyElementsSerials = Object.keys(body.elements), + serial = bodyElementsSerials[0], + tooltip = body.elements[serial]; + + assert.expect(8); + + assert.equal(bodyElementsSerials.length, 1, '1 element has been found'); + assert.equal(parsedBody, data.expectedBody, 'parsed body is correct: ' + parsedBody); + assert.equal( + serial.indexOf(data.expectedElement), + 0, + 'element is of the expected type, with serial ' + bodyElementsSerials[0] + ); + assert.deepEqual(tooltip.attributes, data.expectedAttributes, 'element has the expected attributes'); + + assert.equal(tooltip.content, data.expectedContent, 'tooltip has the correct content'); + assert.equal(tooltip.body.body, data.expectedTarget, 'tooltip has the correct target'); + assert.ok(!_.isUndefined(tooltip.elements), 'tooltip has an element property'); + assert.ok(!_.isUndefined(tooltip.body.elements), 'tooltip body has an element property'); + }); + + QUnit.cases + .init([ + { + title: 'orphan target', + xml: + '
this is a tooltip: ' + + 'my Target' + + '. How cool is that???
', + expectedBody: + 'this is a tooltip: my Target. How cool is that???' + }, + { + title: 'orphan content', + xml: + '
this is a tooltip: ' + + '' + + '. How cool is that???
', + expectedBody: + 'this is a tooltip: . How cool is that???' + } + ]) + .test('Incomplete tooltip parsing: ', function(data, assert) { + var parsed = simpleParser.parse(data.xml); + var serialRegexp = /{{([a-z_]+)_[0-9a-z]*}}/i; + + var body = parsed.body, + parsedBody = body.body.replace(serialRegexp, '{{$1_XXX}}'), + bodyElementsSerials = Object.keys(body.elements || {}); + + assert.expect(2); + + assert.equal(bodyElementsSerials.length, 0, 'no elements have been found'); + assert.equal(parsedBody, data.expectedBody, 'parsed body is correct: ' + parsedBody); + }); +}); diff --git a/test/qtiItem/helper/xmlNsHandler/test.html b/test/qtiItem/helper/xmlNsHandler/test.html new file mode 100644 index 00000000..fbc72f9c --- /dev/null +++ b/test/qtiItem/helper/xmlNsHandler/test.html @@ -0,0 +1,21 @@ + + + + + XML Namespace Handler Test + + + + +
+
+ + diff --git a/test/qtiItem/helper/xmlNsHandler/test.js b/test/qtiItem/helper/xmlNsHandler/test.js new file mode 100644 index 00000000..c07a6d9b --- /dev/null +++ b/test/qtiItem/helper/xmlNsHandler/test.js @@ -0,0 +1,129 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2017 (original work) Open Assessment Technologies SA; + */ +define([ + 'taoQtiItem/qtiItem/helper/xmlNsHandler', + 'text!taoQtiItem/test/samples/qtiv2p2/xml_namespaces/with-ns.xml', + 'text!taoQtiItem/test/samples/qtiv2p2/xml_namespaces/without-ns.xml' +], function(xmlNsHandler, nsXml, noNsXml) { + 'use strict'; + + var getXmlDoc = function getXmlDoc(xmlStr) { + return new DOMParser().parseFromString(xmlStr, 'text/xml'); + }; + + QUnit.test('Strip prefixes', function(assert) { + var xml, prefixed, i; + + xml = getXmlDoc(nsXml); + assert.equal( + !!xml.documentElement.getAttribute('xmlns:originalPrefix'), + true, + 'Initially the XML has a namespace for HTML5 elements' + ); + + prefixed = xml.querySelectorAll('ruby, rt, rb'); + i = prefixed.length; + while (i--) { + assert.equal( + prefixed[i].prefix, + 'originalPrefix', + 'Initially this <' + prefixed[i].localName + '> element has an HTML5 prefix' + ); + } + + // Remove ns and re-initialize + nsXml = xmlNsHandler.stripNs(nsXml); + xml = getXmlDoc(nsXml); + + prefixed = xml.querySelectorAll('ruby, rt, rb'); + i = prefixed.length; + while (i--) { + assert.equal( + prefixed[i].prefix, + null, + 'After stripNs() this <' + prefixed[i].localName + '> element has no longer an HTML5 prefix' + ); + } + }); + + QUnit.test('Restore prefixes', function(assert) { + var xml, prefixed, i; + + xml = getXmlDoc(nsXml); + assert.equal( + !!xml.documentElement.getAttribute('xmlns:originalPrefix'), + true, + 'Initially the XML uses the prefix "originalPrefix" for the namespace for HTML5 elements' + ); + + // Remove, than restore ns and re-initialize + nsXml = xmlNsHandler.stripNs(nsXml); + nsXml = xmlNsHandler.restoreNs(nsXml, { originalPrefix: 'http://www.imsglobal.org/xsd/imsqtiv2p2_html5_v1p0' }); + xml = getXmlDoc(nsXml); + + prefixed = xml.querySelectorAll('ruby, rt, rb'); + i = prefixed.length; + while (i--) { + assert.equal( + prefixed[i].prefix, + 'originalPrefix', + '<' + prefixed[i].localName + '> element has the prefix "originalPrefix"' + ); + } + }); + + QUnit.test('Add required namespace and prefixes', function(assert) { + var xml, prefixed, i; + + xml = getXmlDoc(noNsXml); + assert.equal( + !xml.documentElement.getAttribute('xmlns:originalPrefix'), + true, + 'Initially the XML has no namespace for HTML5 elements' + ); + assert.equal( + xml.documentElement.getAttribute('xmlns'), + 'http://www.imsglobal.org/xsd/imsqti_v2p1', + 'Initially the QTI version is 2.1' + ); + + // Add some code that requires namespacing. In real life this would for instance come from CK-Editor + noNsXml = noNsXml.replace('__PLACEHOLDER__', '北海道ほっかいどう'); + noNsXml = xmlNsHandler.restoreNs(noNsXml, {}); + + // Qh5 is the default prefix + xml = getXmlDoc(noNsXml); + assert.equal( + !!xml.documentElement.getAttribute('xmlns:qh5'), + true, + 'After adding elements that require an HTML5 namespace XML has the attribute "xmlns:qh5"' + ); + + assert.equal( + xml.documentElement.getAttribute('xmlns'), + 'http://www.imsglobal.org/xsd/imsqti_v2p2', + 'The QTI version is now 2.2' + ); + + prefixed = xml.querySelectorAll('ruby, rt, rb'); + i = prefixed.length; + while (i--) { + assert.equal(prefixed[i].prefix, 'qh5', '<' + prefixed[i].localName + '> element has the prefix "qh5"'); + } + }); +}); diff --git a/test/qtiItem/maxScore/data/associate-correct.json b/test/qtiItem/maxScore/data/associate-correct.json new file mode 100644 index 00000000..b9a055d9 --- /dev/null +++ b/test/qtiItem/maxScore/data/associate-correct.json @@ -0,0 +1,326 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58fdf58979ccb848272169", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fdf58979cb0148399374", + "body": "\n
\n
\n {{interaction_associateinteraction_58fdf58980cb4613690390}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_associateinteraction_58fdf58980cb4613690390": { + "serial": "interaction_associateinteraction_58fdf58980cb4613690390", + "qtiClass": "associateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 0, + "minAssociations": 0 + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + }, + "choices": { + "choice_simpleassociablechoice_58fdf58983a84881203423": { + "identifier": "choice_1", + "serial": "choice_simpleassociablechoice_58fdf58983a84881203423", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdf58984cda151851701", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "choice_simpleassociablechoice_58fdf58984db8772394427": { + "identifier": "choice_2", + "serial": "choice_simpleassociablechoice_58fdf58984db8772394427", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdf58984dec101589575", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "choice_simpleassociablechoice_58fdf58984e63595993061": { + "identifier": "choice_3", + "serial": "choice_simpleassociablechoice_58fdf58984e63595993061", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdf58984e91684936719", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "choice_simpleassociablechoice_58fdf58984f01171321650": { + "identifier": "choice_4", + "serial": "choice_simpleassociablechoice_58fdf58984f01171321650", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdf58984f2b070776519", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "choice_simpleassociablechoice_58fdf58984f9c582397525": { + "identifier": "choice_5", + "serial": "choice_simpleassociablechoice_58fdf58984f9c582397525", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdf58984fc5568177842", + "body": "choice #5", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "choice_simpleassociablechoice_58fdf58985032525316746": { + "identifier": "choice_6", + "serial": "choice_simpleassociablechoice_58fdf58985032525316746", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdf5898505a126176292", + "body": "choice #6", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58fdf58982d5e268047177", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + } + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58fdf5897c496604834350": { + "serial": "stylesheet_58fdf5897c496604834350", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + } + } + }, + "outcomes": { + "outcomedeclaration_58fdf5897e8ad054055546": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fdf5897e8ad054055546", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fdf5897d88a508474633": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fdf5897d88a508474633", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_3 choice_4\n ", + "\n choice_3 choice_5\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fdf58987740985374916", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fdf58979ccb848272169" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/associate-map.json b/test/qtiItem/maxScore/data/associate-map.json new file mode 100644 index 00000000..03605572 --- /dev/null +++ b/test/qtiItem/maxScore/data/associate-map.json @@ -0,0 +1,321 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58fdfc9154d2d116165046", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fdfc9154d12703336358", + "body": "\n
\n
\n {{interaction_associateinteraction_58fdfc915cb60553869971}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_associateinteraction_58fdfc915cb60553869971": { + "serial": "interaction_associateinteraction_58fdfc915cb60553869971", + "qtiClass": "associateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 0, + "minAssociations": 0 + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + }, + "choices": { + "choice_simpleassociablechoice_58fdfc915e603803848381": { + "identifier": "choice_1", + "serial": "choice_simpleassociablechoice_58fdfc915e603803848381", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdfc915f28b597824124", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "choice_simpleassociablechoice_58fdfc915f338263278834": { + "identifier": "choice_2", + "serial": "choice_simpleassociablechoice_58fdfc915f338263278834", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdfc915f367537903332", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "choice_simpleassociablechoice_58fdfc915f3ed319686888": { + "identifier": "choice_3", + "serial": "choice_simpleassociablechoice_58fdfc915f3ed319686888", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdfc915f418362668857", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "choice_simpleassociablechoice_58fdfc915f493632234261": { + "identifier": "choice_4", + "serial": "choice_simpleassociablechoice_58fdfc915f493632234261", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdfc915f4bd671265854", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "choice_simpleassociablechoice_58fdfc915f53c029168236": { + "identifier": "choice_5", + "serial": "choice_simpleassociablechoice_58fdfc915f53c029168236", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdfc915f565696718924", + "body": "choice #5", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "choice_simpleassociablechoice_58fdfc915f5e1934738842": { + "identifier": "choice_6", + "serial": "choice_simpleassociablechoice_58fdfc915f5e1934738842", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fdfc915f609661584645", + "body": "choice #6", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58fdfc915ddd4684479792", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + } + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58fdfc91575a7627604315": { + "serial": "stylesheet_58fdfc91575a7627604315", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + } + } + }, + "outcomes": { + "outcomedeclaration_58fdfc915b034642888662": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fdfc915b034642888662", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fdfc91590be744736300": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fdfc91590be744736300", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + }, + "defaultValue": [], + "mapping": { + "choice_3 choice_4": "1", + "choice_3 choice_5": "2", + "choice_1 choice_2": "-1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_3 choice_4\n ", + "\n choice_3 choice_5\n ", + "\n choice_1 choice_2\n " + ], + "mappingAttributes": { + "defaultValue": "-0.2" + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fdfc9160f50286676376", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fdfc9154d2d116165046" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/associate-matchmax.json b/test/qtiItem/maxScore/data/associate-matchmax.json new file mode 100644 index 00000000..e9b25452 --- /dev/null +++ b/test/qtiItem/maxScore/data/associate-matchmax.json @@ -0,0 +1,323 @@ +{ + "identifier": "i14960604448137185", + "serial": "item_592c14d47432d391483371", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14960604448137185", + "title": "associate", + "label": "associate", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint52", + "class": "" + }, + "body": { + "serial": "container_containeritembody_592c14d47430c234928182", + "body": "\n
\n
\n {{interaction_associateinteraction_592c14d47e1d7354050299}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_associateinteraction_592c14d47e1d7354050299": { + "serial": "interaction_associateinteraction_592c14d47e1d7354050299", + "qtiClass": "associateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 0, + "minAssociations": 0 + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + }, + "choices": { + "choice_simpleassociablechoice_592c14d480d97193601364": { + "identifier": "choice_1", + "serial": "choice_simpleassociablechoice_592c14d480d97193601364", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show", + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592c14d48211f427835956", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "choice_simpleassociablechoice_592c14d4821bf969027581": { + "identifier": "choice_2", + "serial": "choice_simpleassociablechoice_592c14d4821bf969027581", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show", + "matchMax": 2, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592c14d4821f0251765920", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "choice_simpleassociablechoice_592c14d482265769107568": { + "identifier": "choice_3", + "serial": "choice_simpleassociablechoice_592c14d482265769107568", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show", + "matchMax": 3, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592c14d482291716920447", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "choice_simpleassociablechoice_592c14d482330559803680": { + "identifier": "choice_4", + "serial": "choice_simpleassociablechoice_592c14d482330559803680", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show", + "matchMax": 4, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592c14d48235f637882854", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "choice_simpleassociablechoice_592c14d4823cf953162796": { + "identifier": "choice_5", + "serial": "choice_simpleassociablechoice_592c14d4823cf953162796", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show", + "matchMax": 5, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592c14d4823fa338494063", + "body": "choice #5", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "choice_simpleassociablechoice_592c14d482464541333001": { + "identifier": "choice_6", + "serial": "choice_simpleassociablechoice_592c14d482464541333001", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592c14d48248d077526868", + "body": "choice #6", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + } + }, + "prompt": { + "serial": "container_containerstatic_592c14d480119482260566", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + } + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_592c14d4781ce424547476": { + "serial": "stylesheet_592c14d4781ce424547476", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + } + } + }, + "outcomes": { + "outcomedeclaration_592c14d47b8e0002788631": { + "identifier": "SCORE", + "serial": "outcomedeclaration_592c14d47b8e0002788631", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_592c14d47a3b5383510187": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_592c14d47a3b5383510187", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "debug": { + "relatedItem": "item_592c14d47432d391483371" + }, + "defaultValue": [], + "mapping": { + "choice_3 choice_5": 5 + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 1 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_592c14d484de6790245849", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_592c14d47432d391483371" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/choice-correct-multiple.json b/test/qtiItem/maxScore/data/choice-correct-multiple.json new file mode 100644 index 00000000..b379d5cb --- /dev/null +++ b/test/qtiItem/maxScore/data/choice-correct-multiple.json @@ -0,0 +1,250 @@ +{ + "identifier": "i14915736639201476", + "serial": "item_58eb45eb9f0b6413971897", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14915736639201476", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58eb45eb9f099473210554", + "body": "\n
\n
\n {{interaction_choiceinteraction_58eb45eba8e1b211271087}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58eb45eba8e1b211271087": { + "serial": "interaction_choiceinteraction_58eb45eba8e1b211271087", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + }, + "choices": { + "choice_simplechoice_58eb45ebabd5e747595669": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58eb45ebabd5e747595669", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb45ebacad6036803292", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + }, + "choice_simplechoice_58eb45ebacb6d291461658": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58eb45ebacb6d291461658", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb45ebacb90951669900", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + }, + "choice_simplechoice_58eb45ebacbfe296921104": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58eb45ebacbfe296921104", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb45ebacc1d718594772", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58eb45ebab1b9726163750", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + } + } + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58eb45eba27ae795589860": { + "serial": "stylesheet_58eb45eba27ae795589860", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + } + } + }, + "outcomes": { + "outcomedeclaration_58eb45eba636a358211292": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58eb45eba636a358211292", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58eb45eba485a510638650": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58eb45eba485a510638650", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_1\n ", + "\n choice_2\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58eb45ebaf4f5005154271", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58eb45eb9f0b6413971897" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/choice-correct-noresponse.json b/test/qtiItem/maxScore/data/choice-correct-noresponse.json new file mode 100644 index 00000000..a3dfa18e --- /dev/null +++ b/test/qtiItem/maxScore/data/choice-correct-noresponse.json @@ -0,0 +1,246 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee27c3af324537241199", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee27c3af30a651421531", + "body": "\n
\n
\n {{interaction_choiceinteraction_58ee27c3b5ad3473009419}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58ee27c3b5ad3473009419": { + "serial": "interaction_choiceinteraction_58ee27c3b5ad3473009419", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + }, + "choices": { + "choice_simplechoice_58ee27c3b78a6332809803": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58ee27c3b78a6332809803", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee27c3b801e984531470", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + }, + "choice_simplechoice_58ee27c3b80a8925797732": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58ee27c3b80a8925797732", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee27c3b80c9891632582", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + }, + "choice_simplechoice_58ee27c3b8134777332662": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58ee27c3b8134777332662", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee27c3b8152630348362", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ee27c3b7157671245174", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee27c3b1f4c794462373": { + "serial": "stylesheet_58ee27c3b1f4c794462373", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee27c3b4029000107998": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee27c3b4029000107998", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee27c3b3410961448017": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee27c3b3410961448017", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee27c3bb544523241053", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee27c3af324537241199" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/choice-map-maxchoice3.json b/test/qtiItem/maxScore/data/choice-map-maxchoice3.json new file mode 100644 index 00000000..c0fb71ea --- /dev/null +++ b/test/qtiItem/maxScore/data/choice-map-maxchoice3.json @@ -0,0 +1,248 @@ +{ + "identifier": "i14915736639201476", + "serial": "item_58eb4dfbcf8e3811501413", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14915736639201476", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58eb4dfbcf8c0131676926", + "body": "\n
\n
\n {{interaction_choiceinteraction_58eb4dfbd97d1815765277}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58eb4dfbd97d1815765277": { + "serial": "interaction_choiceinteraction_58eb4dfbd97d1815765277", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "choices": { + "choice_simplechoice_58eb4dfbdc6ad124242327": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58eb4dfbdc6ad124242327", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb4dfbdd345401120830", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "choice_simplechoice_58eb4dfbdd403693379607": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58eb4dfbdd403693379607", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb4dfbdd427681740403", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "choice_simplechoice_58eb4dfbdd497865024566": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58eb4dfbdd497865024566", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb4dfbdd4b5671809883", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58eb4dfbdba9d065569790", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + } + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58eb4dfbd2afb932441788": { + "serial": "stylesheet_58eb4dfbd2afb932441788", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + } + }, + "outcomes": { + "outcomedeclaration_58eb4dfbd6bfc394601979": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58eb4dfbd6bfc394601979", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58eb4dfbd4a74001643639": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58eb4dfbd4a74001643639", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "defaultValue": [], + "mapping": { + "choice_1": "2", + "choice_2": "-1", + "choice_3": "1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_1\n ", + "\n choice_2\n " + ], + "mappingAttributes": { + "defaultValue": 0, + "upperBound": "5" + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58eb4dfbdfa8d290880211", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/choice-map-upperbound2.json b/test/qtiItem/maxScore/data/choice-map-upperbound2.json new file mode 100644 index 00000000..08b2544a --- /dev/null +++ b/test/qtiItem/maxScore/data/choice-map-upperbound2.json @@ -0,0 +1,248 @@ +{ + "identifier": "i14915736639201476", + "serial": "item_58eb4dfbcf8e3811501413", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14915736639201476", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58eb4dfbcf8c0131676926", + "body": "\n
\n
\n {{interaction_choiceinteraction_58eb4dfbd97d1815765277}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58eb4dfbd97d1815765277": { + "serial": "interaction_choiceinteraction_58eb4dfbd97d1815765277", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "choices": { + "choice_simplechoice_58eb4dfbdc6ad124242327": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58eb4dfbdc6ad124242327", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb4dfbdd345401120830", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "choice_simplechoice_58eb4dfbdd403693379607": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58eb4dfbdd403693379607", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb4dfbdd427681740403", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "choice_simplechoice_58eb4dfbdd497865024566": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58eb4dfbdd497865024566", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58eb4dfbdd4b5671809883", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58eb4dfbdba9d065569790", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + } + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58eb4dfbd2afb932441788": { + "serial": "stylesheet_58eb4dfbd2afb932441788", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + } + } + }, + "outcomes": { + "outcomedeclaration_58eb4dfbd6bfc394601979": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58eb4dfbd6bfc394601979", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58eb4dfbd4a74001643639": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58eb4dfbd4a74001643639", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "defaultValue": [], + "mapping": { + "choice_1": "2", + "choice_2": "-1", + "choice_3": "1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_1\n ", + "\n choice_2\n " + ], + "mappingAttributes": { + "defaultValue": 0, + "upperBound": "2" + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58eb4dfbdfa8d290880211", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58eb4dfbcf8e3811501413" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/composite-choice-correct-map.json b/test/qtiItem/maxScore/data/composite-choice-correct-map.json new file mode 100644 index 00000000..ace9cc8a --- /dev/null +++ b/test/qtiItem/maxScore/data/composite-choice-correct-map.json @@ -0,0 +1,404 @@ +{ + "identifier": "i14919775831610479", + "serial": "item_58edc70bd4abf261072461", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14919775831610479", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58edc70bd4aa3283011363", + "body": "\n
\n
\n {{interaction_choiceinteraction_58edc70bdaee1604331175}}\n <\/div>\n <\/div>\n
\n
\n {{interaction_choiceinteraction_58edc70bdcf90782059877}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58edc70bdaee1604331175": { + "serial": "interaction_choiceinteraction_58edc70bdaee1604331175", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "choices": { + "choice_simplechoice_58edc70bdc705808234206": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58edc70bdc705808234206", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc70bdcda8642762943", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "choice_simplechoice_58edc70bdce48879425036": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58edc70bdce48879425036", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc70bdce69753122659", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "choice_simplechoice_58edc70bdcedf288095544": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58edc70bdcedf288095544", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc70bdcefd831953041", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58edc70bdc036115959204", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + } + }, + "interaction_choiceinteraction_58edc70bdcf90782059877": { + "serial": "interaction_choiceinteraction_58edc70bdcf90782059877", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "choices": { + "choice_simplechoice_58edc70bdd05c296037768": { + "identifier": "choice_4", + "serial": "choice_simplechoice_58edc70bdd05c296037768", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc70bdd07a680953841", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "choice_simplechoice_58edc70bdd0e8307025057": { + "identifier": "choice_5", + "serial": "choice_simplechoice_58edc70bdd0e8307025057", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc70bdd105292101072", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "choice_simplechoice_58edc70bdd16e797934519": { + "identifier": "choice_6", + "serial": "choice_simplechoice_58edc70bdd16e797934519", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc70bdd189466694147", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58edc70bdcff5820817261", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + } + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58edc70bd6d28352843885": { + "serial": "stylesheet_58edc70bd6d28352843885", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + } + } + }, + "outcomes": { + "outcomedeclaration_58edc70bd9833188172650": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58edc70bd9833188172650", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58edc70bd80c0725410046": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58edc70bd80c0725410046", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_58edc70bd9136744008770": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_58edc70bd9136744008770", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "defaultValue": [], + "mapping": { + "choice_4": "1", + "choice_5": "0.5", + "choice_6": "-2" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_4\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58edc70bde6e4978616752", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58edc70bd4abf261072461" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/composite-choice-correct.json b/test/qtiItem/maxScore/data/composite-choice-correct.json new file mode 100644 index 00000000..71dee748 --- /dev/null +++ b/test/qtiItem/maxScore/data/composite-choice-correct.json @@ -0,0 +1,401 @@ +{ + "identifier": "i14919775831610479", + "serial": "item_58edc63a733ae890333698", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14919775831610479", + "title": "Item 14", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58edc63a73392227398116", + "body": "\n
\n
\n {{interaction_choiceinteraction_58edc63a7d387866338302}}\n <\/div>\n <\/div>\n
\n
\n {{interaction_choiceinteraction_58edc63a8171b778308383}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58edc63a7d387866338302": { + "serial": "interaction_choiceinteraction_58edc63a7d387866338302", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "choices": { + "choice_simplechoice_58edc63a808f9269184001": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58edc63a808f9269184001", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc63a81517769460172", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "choice_simplechoice_58edc63a815c4308995814": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58edc63a815c4308995814", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc63a815e7643170758", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "choice_simplechoice_58edc63a81661124759211": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58edc63a81661124759211", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc63a81680255870587", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58edc63a7fbde441107942", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + } + }, + "interaction_choiceinteraction_58edc63a8171b778308383": { + "serial": "interaction_choiceinteraction_58edc63a8171b778308383", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "choices": { + "choice_simplechoice_58edc63a8184e065503535": { + "identifier": "choice_4", + "serial": "choice_simplechoice_58edc63a8184e065503535", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc63a8186f513349509", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "choice_simplechoice_58edc63a818e1749191036": { + "identifier": "choice_5", + "serial": "choice_simplechoice_58edc63a818e1749191036", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc63a818ff031839646", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "choice_simplechoice_58edc63a81969192389189": { + "identifier": "choice_6", + "serial": "choice_simplechoice_58edc63a81969192389189", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58edc63a81998545042621", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58edc63a817d8044703772", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + } + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58edc63a76861405511303": { + "serial": "stylesheet_58edc63a76861405511303", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + } + } + }, + "outcomes": { + "outcomedeclaration_58edc63a7a7fb605247525": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58edc63a7a7fb605247525", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58edc63a78b82830257238": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58edc63a78b82830257238", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_58edc63a7a3de641303549": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_58edc63a7a3de641303549", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_4\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58edc63a8450c671394502", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58edc63a733ae890333698" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/custom-rp.json b/test/qtiItem/maxScore/data/custom-rp.json new file mode 100644 index 00000000..cd8e5548 --- /dev/null +++ b/test/qtiItem/maxScore/data/custom-rp.json @@ -0,0 +1,643 @@ +{ + "identifier": "Choicemultiple_871212949", + "serial": "item_54fd4c4a4ff94909004775", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Choicemultiple_871212949", + "title": "choice (multiple, point per answer)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54fd4c4a4ff5c508220978", + "body": "
\n\t\tWelche Naturr\u00e4ume finden sich im Freistaat Sachsen?\n\t\t<\/div>\n\t\t{{interaction_choiceinteraction_54fd4c4a56c54049364130}}", + "elements": { + "interaction_choiceinteraction_54fd4c4a56c54049364130": { + "serial": "interaction_choiceinteraction_54fd4c4a56c54049364130", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_27966883", + "shuffle": true, + "maxChoices": 0, + "minChoices": 0 + }, + "choices": { + "choice_simplechoice_54fd4c4a58d7c687477684": { + "identifier": "choice_934383202", + "serial": "choice_simplechoice_54fd4c4a58d7c687477684", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_934383202", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a595d5472846889", + "body": "Erzgebirge", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a5973d210081507": { + "identifier": "choice_2022864592", + "serial": "choice_simplechoice_54fd4c4a5973d210081507", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2022864592", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a5979e381036513", + "body": "Lausitz", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a59885697450564": { + "identifier": "choice_1534527094", + "serial": "choice_simplechoice_54fd4c4a59885697450564", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1534527094", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a598d6015267070", + "body": "Vogtland", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a599b6341083202": { + "identifier": "choice_921260236", + "serial": "choice_simplechoice_54fd4c4a599b6341083202", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_921260236", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a59a04237231882", + "body": "Harz", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a59ae5054348153": { + "identifier": "choice_1757121272", + "serial": "choice_simplechoice_54fd4c4a59ae5054348153", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1757121272", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a59b34934662454", + "body": "Alpen", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54fd4c4a58505021948896", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + } + }, + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54fd4c4a540a3718842863": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54fd4c4a540a3718842863", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54fd4c4a554ad612900133": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54fd4c4a554ad612900133", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54fd4c4a55584224333269": { + "identifier": "FEEDBACK_5714028", + "serial": "outcomedeclaration_54fd4c4a55584224333269", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_5714028", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a556a8142933374": { + "identifier": "FEEDBACK_8958131", + "serial": "outcomedeclaration_54fd4c4a556a8142933374", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_8958131", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a557c3758485518": { + "identifier": "FEEDBACK_1634627", + "serial": "outcomedeclaration_54fd4c4a557c3758485518", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_1634627", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a558c9451328046": { + "identifier": "FEEDBACK_20327592", + "serial": "outcomedeclaration_54fd4c4a558c9451328046", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_20327592", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a559c2463027304": { + "identifier": "FEEDBACK_5765523", + "serial": "outcomedeclaration_54fd4c4a559c2463027304", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_5765523", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a55ab8116211309": { + "identifier": "FEEDBACK_15433735", + "serial": "outcomedeclaration_54fd4c4a55ab8116211309", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_15433735", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a55bac167900885": { + "identifier": "FEEDBACK_21035203", + "serial": "outcomedeclaration_54fd4c4a55bac167900885", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_21035203", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54fd4c4a52da4633936855": { + "identifier": "RESPONSE_27966883", + "serial": "responsedeclaration_54fd4c4a52da4633936855", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_27966883", + "cardinality": "multiple", + "baseType": "identifier" + }, + "correctResponses": [ + "choice_934383202", + "choice_2022864592", + "choice_1534527094" + ], + "mapping": { + "choice_934383202": "1.0", + "choice_2022864592": "1.0", + "choice_1534527094": "1.0", + "choice_921260236": "-1.0", + "choice_1757121272": "-2.0" + }, + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54fd4c4a5b556422874833", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t\t\t<\/match>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/equal>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tchoice_2022864592<\/baseValue>\n\t\t\t\t\t\t\n\t\t\t\t\t<\/member>\n\t\t\t\t<\/not>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tchoice_934383202<\/baseValue>\n\t\t\t\t\t\t\n\t\t\t\t\t<\/member>\n\t\t\t\t<\/not>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tchoice_1534527094<\/baseValue>\n\t\t\t\t\t\t\n\t\t\t\t\t<\/member>\n\t\t\t\t<\/not>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_921260236<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/member>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_1757121272<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/member>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + ] + } + ] + }, + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_5714028" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_8958131" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1634627" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_2022864592" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_20327592" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_934383202" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_5765523" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_1534527094" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_15433735" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_921260236" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_21035203" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_1757121272" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/extended-text-manual-scoring-with-correct.json b/test/qtiItem/maxScore/data/extended-text-manual-scoring-with-correct.json new file mode 100644 index 00000000..a6aac06b --- /dev/null +++ b/test/qtiItem/maxScore/data/extended-text-manual-scoring-with-correct.json @@ -0,0 +1,215 @@ +{ + "identifier": "i14933007086493522", + "serial": "item_5901f75bd33d1885215991", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14933007086493522", + "title": "extended text", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5901f75bd33b6859922172", + "body": "\n
\n
\n {{interaction_extendedtextinteraction_5901f75bd9b88945651508}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_extendedtextinteraction_5901f75bd9b88945651508": { + "serial": "interaction_extendedtextinteraction_5901f75bd9b88945651508", + "qtiClass": "extendedTextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "minStrings": 0, + "format": "plain" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_5901f75bdc23c988002278", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + } + } + } + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + } + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_5901f75bd5a98427159893": { + "serial": "stylesheet_5901f75bd5a98427159893", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + } + } + }, + "outcomes": { + "outcomedeclaration_5901f75bd7f3b881619834": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5901f75bd7f3b881619834", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": null + }, + "outcomedeclaration_5901f75bd8f2c675873584": { + "identifier": "OUTCOME_1", + "serial": "outcomedeclaration_5901f75bd8f2c675873584", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "OUTCOME_1", + "cardinality": "single", + "baseType": "float", + "interpretation": "Manual scoring", + "normalMaximum": 3, + "normalMinimum": 0 + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": null + }, + "outcomedeclaration_5901f75bd8f2c67587xxxx": { + "identifier": "OUTCOME_X", + "serial": "outcomedeclaration_5901f75bd8f2c67587xxxx", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "OUTCOME_X", + "cardinality": "single", + "baseType": "float", + "interpretation": "some description" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5901f75bd6f65683540800": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5901f75bd6f65683540800", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n \n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_5901f75bde109736204519", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/extended-text-manual-scoring.json b/test/qtiItem/maxScore/data/extended-text-manual-scoring.json new file mode 100644 index 00000000..6d35569d --- /dev/null +++ b/test/qtiItem/maxScore/data/extended-text-manual-scoring.json @@ -0,0 +1,213 @@ +{ + "identifier": "i14933007086493522", + "serial": "item_5901f75bd33d1885215991", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14933007086493522", + "title": "extended text", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5901f75bd33b6859922172", + "body": "\n
\n
\n {{interaction_extendedtextinteraction_5901f75bd9b88945651508}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_extendedtextinteraction_5901f75bd9b88945651508": { + "serial": "interaction_extendedtextinteraction_5901f75bd9b88945651508", + "qtiClass": "extendedTextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "minStrings": 0, + "format": "plain" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_5901f75bdc23c988002278", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + } + } + } + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + } + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_5901f75bd5a98427159893": { + "serial": "stylesheet_5901f75bd5a98427159893", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + } + } + }, + "outcomes": { + "outcomedeclaration_5901f75bd7f3b881619834": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5901f75bd7f3b881619834", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": null + }, + "outcomedeclaration_5901f75bd8f2c675873584": { + "identifier": "OUTCOME_1", + "serial": "outcomedeclaration_5901f75bd8f2c675873584", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "OUTCOME_1", + "cardinality": "single", + "baseType": "float", + "interpretation": "Manual scoring", + "normalMaximum": 3, + "normalMinimum": 0 + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": null + }, + "outcomedeclaration_5901f75bd8f2c67587xxxx": { + "identifier": "OUTCOME_X", + "serial": "outcomedeclaration_5901f75bd8f2c67587xxxx", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "OUTCOME_X", + "cardinality": "single", + "baseType": "float", + "interpretation": "some description" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5901f75bd6f65683540800": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5901f75bd6f65683540800", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_5901f75bde109736204519", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_5901f75bd33d1885215991" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/extended-text.json b/test/qtiItem/maxScore/data/extended-text.json new file mode 100644 index 00000000..1eed5e1e --- /dev/null +++ b/test/qtiItem/maxScore/data/extended-text.json @@ -0,0 +1,183 @@ +{ + "identifier": "i14933007086493522", + "serial": "item_5901f6ba86c0e030774949", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14933007086493522", + "title": "extended text", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5901f6ba86bee710286714", + "body": "\n
\n
\n {{interaction_extendedtextinteraction_5901f6ba9106a284762486}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_extendedtextinteraction_5901f6ba9106a284762486": { + "serial": "interaction_extendedtextinteraction_5901f6ba9106a284762486", + "qtiClass": "extendedTextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "minStrings": 0, + "format": "plain" + }, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_5901f6ba94c78114364716", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + } + } + } + }, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + } + }, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_5901f6ba8a4c5305883865": { + "serial": "stylesheet_5901f6ba8a4c5305883865", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + } + } + }, + "outcomes": { + "outcomedeclaration_5901f6ba8e751335880497": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5901f6ba8e751335880497", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5901f6ba8cb2c765601609": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5901f6ba8cb2c765601609", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n \n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_5901f6ba97952998555231", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_5901f6ba86c0e030774949" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/gapmatch-correct.json b/test/qtiItem/maxScore/data/gapmatch-correct.json new file mode 100644 index 00000000..0d5ca911 --- /dev/null +++ b/test/qtiItem/maxScore/data/gapmatch-correct.json @@ -0,0 +1,263 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58f5e075e7fc5525417389", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58f5e075e7fa4972781911", + "body": "\n
\n
\n {{interaction_gapmatchinteraction_58f5e075f2b72704979804}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_gapmatchinteraction_58f5e075f2b72704979804": { + "serial": "interaction_gapmatchinteraction_58f5e075f2b72704979804", + "qtiClass": "gapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false + }, + "body": { + "serial": "container_containergap_58f5e07600524506240650", + "body": "\n \n \n \n \n

Lorem ipsum\n\n {{choice_gap_58f5e07602e87389112639}} sit amet,\n\n {{choice_gap_58f5e0760325b925730888}} adipisicing ...\n\n <\/p>\n ", + "elements": { + "choice_gap_58f5e07602e87389112639": { + "identifier": "gap_2", + "serial": "choice_gap_58f5e07602e87389112639", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_2", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + } + }, + "choice_gap_58f5e0760325b925730888": { + "identifier": "gap_1", + "serial": "choice_gap_58f5e0760325b925730888", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_1", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + } + } + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + } + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "choices": { + "choice_gaptext_58f5e076011d5118318479": { + "identifier": "choice_7", + "serial": "choice_gaptext_58f5e076011d5118318479", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "text": "choice #1" + }, + "choice_gaptext_58f5e07602a4b393732526": { + "identifier": "choice_11", + "serial": "choice_gaptext_58f5e07602a4b393732526", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_11", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "text": "consectetur" + }, + "choice_gaptext_58f5e07602aa5550850405": { + "identifier": "choice_12", + "serial": "choice_gaptext_58f5e07602aa5550850405", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_12", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "text": "dolor" + } + }, + "prompt": { + "serial": "container_containerstatic_58f5e0760015a698903539", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + } + } + } + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + } + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58f5e075eb921366156364": { + "serial": "stylesheet_58f5e075eb921366156364", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + } + } + }, + "outcomes": { + "outcomedeclaration_58f5e075efa95291911203": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58f5e075efa95291911203", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58f5e075ede73619627566": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58f5e075ede73619627566", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_11 gap_2\n ", + "\n choice_12 gap_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58f5e0760634f329472616", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58f5e075e7fc5525417389" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/gapmatch-map-matchmax.json b/test/qtiItem/maxScore/data/gapmatch-map-matchmax.json new file mode 100644 index 00000000..56ba07b4 --- /dev/null +++ b/test/qtiItem/maxScore/data/gapmatch-map-matchmax.json @@ -0,0 +1,284 @@ +{ + "identifier": "i1496326012103773", + "serial": "item_5930219fca4f2010398033", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1496326012103773", + "title": "Item 12", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint52", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5930219fca4d0542092830", + "body": "\n

\n
\n {{interaction_gapmatchinteraction_5930219fed70b732896556}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_gapmatchinteraction_5930219fed70b732896556": { + "serial": "interaction_gapmatchinteraction_5930219fed70b732896556", + "qtiClass": "gapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false + }, + "body": { + "serial": "container_containergap_5930219ff2744567210225", + "body": "\n \n \n \n \n

Lorem\n\n {{choice_gap_593021a00679b319057676}} dolor sit\n\n {{choice_gap_593021a007a0e953251879}}, consectetur\n\n {{choice_gap_593021a007a40308615323}} ...\n\n <\/p>\n ", + "elements": { + "choice_gap_593021a00679b319057676": { + "identifier": "gap_1", + "serial": "choice_gap_593021a00679b319057676", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_1", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + }, + "choice_gap_593021a007a0e953251879": { + "identifier": "gap_2", + "serial": "choice_gap_593021a007a0e953251879", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_2", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + }, + "choice_gap_593021a007a40308615323": { + "identifier": "gap_3", + "serial": "choice_gap_593021a007a40308615323", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_3", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + } + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "choices": { + "choice_gaptext_593021a00075e849553908": { + "identifier": "choice_2", + "serial": "choice_gaptext_593021a00075e849553908", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "text": "ipsum" + }, + "choice_gaptext_593021a005979558618867": { + "identifier": "choice_3", + "serial": "choice_gaptext_593021a005979558618867", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "text": "amet" + }, + "choice_gaptext_593021a0059de518877248": { + "identifier": "choice_4", + "serial": "choice_gaptext_593021a0059de518877248", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "text": "adipisicing" + } + }, + "prompt": { + "serial": "container_containerstatic_5930219ff1c43478899988", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + } + } + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_5930219fd60f3961354579": { + "serial": "stylesheet_5930219fd60f3961354579", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + } + } + }, + "outcomes": { + "outcomedeclaration_5930219fe29e1966430648": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5930219fe29e1966430648", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "defaultValue": null + }, + "outcomedeclaration_5930219fe8e7f079484912": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_5930219fe8e7f079484912", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_5930219fdcc0b406038032": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5930219fdcc0b406038032", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "defaultValue": [], + "mapping": { + "choice_2 gap_1": "2", + "choice_3 gap_2": "2", + "choice_4 gap_3": "2" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 2 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_593021a00d2fe510205964", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_5930219fca4f2010398033" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/gapmatch-map.json b/test/qtiItem/maxScore/data/gapmatch-map.json new file mode 100644 index 00000000..1921a82f --- /dev/null +++ b/test/qtiItem/maxScore/data/gapmatch-map.json @@ -0,0 +1,295 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58fa1c4a8b966603270966", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fa1c4a8b945678068315", + "body": "\n

\n
\n {{interaction_gapmatchinteraction_58fa1c4a97da2623687350}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_gapmatchinteraction_58fa1c4a97da2623687350": { + "serial": "interaction_gapmatchinteraction_58fa1c4a97da2623687350", + "qtiClass": "gapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false + }, + "body": { + "serial": "container_containergap_58fa1c4a99951180290138", + "body": "\n \n \n \n \n \n \n

Lorem ipsum\n\n {{choice_gap_58fa1c4a9c4b9449004690}} sit amet,\n\n {{choice_gap_58fa1c4a9c93d009825417}} adipisicing ...\n\n <\/p>\n ", + "elements": { + "choice_gap_58fa1c4a9c4b9449004690": { + "identifier": "gap_2", + "serial": "choice_gap_58fa1c4a9c4b9449004690", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_2", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + } + }, + "choice_gap_58fa1c4a9c93d009825417": { + "identifier": "gap_1", + "serial": "choice_gap_58fa1c4a9c93d009825417", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_1", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + } + } + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + } + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "choices": { + "choice_gaptext_58fa1c4a9a6d6716242166": { + "identifier": "choice_1", + "serial": "choice_gaptext_58fa1c4a9a6d6716242166", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "text": "choice #1" + }, + "choice_gaptext_58fa1c4a9bfc0657440156": { + "identifier": "choice_2", + "serial": "choice_gaptext_58fa1c4a9bfc0657440156", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "text": "choice #2" + }, + "choice_gaptext_58fa1c4a9c013391199571": { + "identifier": "choice_3", + "serial": "choice_gaptext_58fa1c4a9c013391199571", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "text": "choice #3" + }, + "choice_gaptext_58fa1c4a9c05b538942409": { + "identifier": "choice_4", + "serial": "choice_gaptext_58fa1c4a9c05b538942409", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "text": "consectetur" + }, + "choice_gaptext_58fa1c4a9c09e233437260": { + "identifier": "choice_5", + "serial": "choice_gaptext_58fa1c4a9c09e233437260", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "text": "dolor" + } + }, + "prompt": { + "serial": "container_containerstatic_58fa1c4a99556495801142", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + } + } + } + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + } + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58fa1c4a8fae7789677110": { + "serial": "stylesheet_58fa1c4a8fae7789677110", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + } + } + }, + "outcomes": { + "outcomedeclaration_58fa1c4a9495a916707593": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fa1c4a9495a916707593", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fa1c4a9215d727729481": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fa1c4a9215d727729481", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "defaultValue": [], + "mapping": { + "choice_4 gap_1": "1.5", + "choice_5 gap_1": "1", + "choice_4 gap_2": "2", + "choice_5 gap_2": "0", + "choice_3 gap_1": "-1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_4 gap_2\n ", + "\n choice_5 gap_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fa1c4a9f6a9809474445", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fa1c4a8b966603270966" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/gapmatch-matchmax.json b/test/qtiItem/maxScore/data/gapmatch-matchmax.json new file mode 100644 index 00000000..8e79b304 --- /dev/null +++ b/test/qtiItem/maxScore/data/gapmatch-matchmax.json @@ -0,0 +1,334 @@ +{ + "identifier": "i14961523262234191", + "serial": "item_592e7e8160379327705733", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14961523262234191", + "title": "match", + "label": "match", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint52", + "class": "" + }, + "body": { + "serial": "container_containeritembody_592e7e8160355546090534", + "body": "\n

\n
\n {{interaction_gapmatchinteraction_592e7e8167dca557914561}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_gapmatchinteraction_592e7e8167dca557914561": { + "serial": "interaction_gapmatchinteraction_592e7e8167dca557914561", + "qtiClass": "gapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false + }, + "body": { + "serial": "container_containergap_592e7e818e53b811436459", + "body": "\n \n \n \n \n \n \n \n \n

Lorem ipsum dolor sit amet\n\n\n {{choice_gap_592e7e81913d0359079073}}\n {{choice_gap_592e7e8191892405085244}}\n ...\n\n <\/p>\n ", + "elements": { + "choice_gap_592e7e81913d0359079073": { + "identifier": "gap_1", + "serial": "choice_gap_592e7e81913d0359079073", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_1", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + } + }, + "choice_gap_592e7e8191892405085244": { + "identifier": "gap_2", + "serial": "choice_gap_592e7e8191892405085244", + "qtiClass": "gap", + "attributes": { + "identifier": "gap_2", + "fixed": false, + "required": false + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + } + } + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + } + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "choices": { + "choice_gaptext_592e7e818fc3b252798220": { + "identifier": "choice_1", + "serial": "choice_gaptext_592e7e818fc3b252798220", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": "choice #1" + }, + "choice_gaptext_592e7e8190f6b709358909": { + "identifier": "choice_2", + "serial": "choice_gaptext_592e7e8190f6b709358909", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": "choice #2" + }, + "choice_gaptext_592e7e8190fc7602772829": { + "identifier": "choice_3", + "serial": "choice_gaptext_592e7e8190fc7602772829", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": "choice #3" + }, + "choice_gaptext_592e7e8191015920483748": { + "identifier": "choice_4", + "serial": "choice_gaptext_592e7e8191015920483748", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": "choice #4" + }, + "choice_gaptext_592e7e819105b905478372": { + "identifier": "choice_5", + "serial": "choice_gaptext_592e7e819105b905478372", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": ", consectetur" + }, + "choice_gaptext_592e7e81910a1380120059": { + "identifier": "choice_6", + "serial": "choice_gaptext_592e7e81910a1380120059", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": "adipisicing" + }, + "choice_gaptext_592e7e81910e3883111888": { + "identifier": "choice_7", + "serial": "choice_gaptext_592e7e81910e3883111888", + "qtiClass": "gapText", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "text": "choice #7" + } + }, + "prompt": { + "serial": "container_containerstatic_592e7e818e1f9531174945", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + } + } + } + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + } + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_592e7e8162a67156663511": { + "serial": "stylesheet_592e7e8162a67156663511", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + } + } + }, + "outcomes": { + "outcomedeclaration_592e7e8166272393354538": { + "identifier": "SCORE", + "serial": "outcomedeclaration_592e7e8166272393354538", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "defaultValue": null + }, + "outcomedeclaration_592e7e8167155052746933": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_592e7e8167155052746933", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "defaultValue": "3" + } + }, + "responses": { + "responsedeclaration_592e7e8163f71567114566": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_592e7e8163f71567114566", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "defaultValue": [], + "mapping": { + "choice_3 gap_1": "1", + "choice_5 gap_2": "2" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_3 gap_1\n ", + "\n choice_5 gap_2\n " + ], + "mappingAttributes": { + "defaultValue": 2 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_592e7e819380b565030711", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_592e7e8160379327705733" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphic-associate-correct.json b/test/qtiItem/maxScore/data/graphic-associate-correct.json new file mode 100644 index 00000000..dbfbfc0e --- /dev/null +++ b/test/qtiItem/maxScore/data/graphic-associate-correct.json @@ -0,0 +1,247 @@ +{ + "identifier": "i14930461572410513", + "serial": "item_58fe18fcc4d10772301217", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930461572410513", + "title": "Item 16", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fe18fcc4cf5277215409", + "body": "\n

\n
\n {{interaction_graphicassociateinteraction_58fe18fccc210908559828}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicassociateinteraction_58fe18fccc210908559828": { + "serial": "interaction_graphicassociateinteraction_58fe18fccc210908559828", + "qtiClass": "graphicAssociateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxAssociations": 0, + "minAssociations": 0, + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + }, + "choices": { + "choice_associablehotspot_58fe18fccfda5984757087": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_58fe18fccfda5984757087", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "119,57,18" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + } + }, + "choice_associablehotspot_58fe18fcd0920450261866": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_58fe18fcd0920450261866", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "120,175,16" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + } + }, + "choice_associablehotspot_58fe18fcd096f956941730": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_58fe18fcd096f956941730", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "26,104,7" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + } + }, + "choice_associablehotspot_58fe18fcd09b6335944171": { + "identifier": "associablehotspot_4", + "serial": "choice_associablehotspot_58fe18fcd09b6335944171", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "187,90,5" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58fe18fccdb6e950615341", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + } + }, + "object": { + "serial": "object_58fe18fcd0a08570617643", + "qtiClass": "object", + "attributes": { + "data": "daoism.jpg", + "type": "image\/jpeg", + "width": 230, + "height": 229 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + } + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_58fe18fcc900c932588655": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fe18fcc900c932588655", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fe18fcc7f4a051749643": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fe18fcc7f4a051749643", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n associablehotspot_1 associablehotspot_2\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fe18fcd2669077940449", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fe18fcc4d10772301217" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphic-associate-map.json b/test/qtiItem/maxScore/data/graphic-associate-map.json new file mode 100644 index 00000000..f12c4799 --- /dev/null +++ b/test/qtiItem/maxScore/data/graphic-associate-map.json @@ -0,0 +1,245 @@ +{ + "identifier": "i14930461572410513", + "serial": "item_58fe193261bff134518272", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930461572410513", + "title": "Item 16", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fe193261be7887746683", + "body": "\n
\n
\n {{interaction_graphicassociateinteraction_58fe193266a51302511465}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicassociateinteraction_58fe193266a51302511465": { + "serial": "interaction_graphicassociateinteraction_58fe193266a51302511465", + "qtiClass": "graphicAssociateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxAssociations": 0, + "minAssociations": 0, + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + }, + "choices": { + "choice_associablehotspot_58fe193268ed7115245966": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_58fe193268ed7115245966", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "119,57,18" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + } + }, + "choice_associablehotspot_58fe193269667140744214": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_58fe193269667140744214", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "120,175,16" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + } + }, + "choice_associablehotspot_58fe1932696b4193612849": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_58fe1932696b4193612849", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "26,104,7" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + } + }, + "choice_associablehotspot_58fe1932696f4920474741": { + "identifier": "associablehotspot_4", + "serial": "choice_associablehotspot_58fe1932696f4920474741", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "187,90,5" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58fe19326777a457729217", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + } + }, + "object": { + "serial": "object_58fe193269749312719491", + "qtiClass": "object", + "attributes": { + "data": "daoism.jpg", + "type": "image\/jpeg", + "width": 230, + "height": 229 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + } + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_58fe193264f29945331421": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fe193264f29945331421", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fe193263ece904835378": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fe193263ece904835378", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "debug": { + "relatedItem": "item_58fe193261bff134518272" + }, + "defaultValue": [], + "mapping": { + "associablehotspot_1 associablehotspot_2": "-0.85", + "associablehotspot_3 associablehotspot_4": "0.75", + "associablehotspot_2 associablehotspot_4": "0.45", + "associablehotspot_1 associablehotspot_3": "-0.55" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n associablehotspot_1 associablehotspot_2\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fe19326a6f3931216856", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fe193261bff134518272" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphic-associate-matchmax.json b/test/qtiItem/maxScore/data/graphic-associate-matchmax.json new file mode 100644 index 00000000..5895d92a --- /dev/null +++ b/test/qtiItem/maxScore/data/graphic-associate-matchmax.json @@ -0,0 +1,240 @@ +{ + "identifier": "i14962231775235198", + "serial": "item_592e8e936ba26799088857", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14962231775235198", + "title": "graphic assoc", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint52", + "class": "" + }, + "body": { + "serial": "container_containeritembody_592e8e936ba09042458380", + "body": "\n
\n
\n {{interaction_graphicassociateinteraction_592e8e9373a54870104235}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicassociateinteraction_592e8e9373a54870104235": { + "serial": "interaction_graphicassociateinteraction_592e8e9373a54870104235", + "qtiClass": "graphicAssociateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxAssociations": 0, + "minAssociations": 0, + "class": "responsive" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + }, + "choices": { + "choice_associablehotspot_592e8e93771ef462445715": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_592e8e93771ef462445715", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "67,45,5" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + } + }, + "choice_associablehotspot_592e8e9377e26689495137": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_592e8e9377e26689495137", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "129,100,5" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + } + }, + "choice_associablehotspot_592e8e9377e76139154481": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_592e8e9377e76139154481", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "circle", + "coords": "332,89,25" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + } + } + }, + "prompt": { + "serial": "container_containerstatic_592e8e93751d3859463612", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + } + }, + "object": { + "serial": "object_592e8e9377ecc415282558", + "qtiClass": "object", + "attributes": { + "data": "taomedia:\/\/mediamanager\/http_2_tao_0_local_1_mytao_0_rdf_3_i14962232291474201", + "type": "image\/gif", + "width": 428, + "height": 276 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + } + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_592e8e93709e5087630162": { + "identifier": "SCORE", + "serial": "outcomedeclaration_592e8e93709e5087630162", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + }, + "defaultValue": null + }, + "outcomedeclaration_592e8e9371e8a389892983": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_592e8e9371e8a389892983", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + }, + "defaultValue": "11" + } + }, + "responses": { + "responsedeclaration_592e8e936ed9f903042572": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_592e8e936ed9f903042572", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + }, + "defaultValue": [], + "mapping": { + "associablehotspot_1 associablehotspot_2": "1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n associablehotspot_1 associablehotspot_2\n " + ], + "mappingAttributes": { + "defaultValue": 2 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_592e8e937979b151311057", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_592e8e936ba26799088857" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphic-gap-correct.json b/test/qtiItem/maxScore/data/graphic-gap-correct.json new file mode 100644 index 00000000..42e8a2a8 --- /dev/null +++ b/test/qtiItem/maxScore/data/graphic-gap-correct.json @@ -0,0 +1,392 @@ +{ + "identifier": "i14930461572410513", + "serial": "item_58fefcee63887006001955", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930461572410513", + "title": "Item 16", + "label": "Item 16", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fefcee6386e873134384", + "body": "\n
\n
\n {{interaction_graphicgapmatchinteraction_58fefcee69ed7042401963}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicgapmatchinteraction_58fefcee69ed7042401963": { + "serial": "interaction_graphicgapmatchinteraction_58fefcee69ed7042401963", + "qtiClass": "graphicGapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "choices": { + "choice_associablehotspot_58fefcee6ccde324774086": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_58fefcee6ccde324774086", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "14,15,24,25" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "choice_associablehotspot_58fefcee6d30b710066834": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_58fefcee6d30b710066834", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "90,28,100,38" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "choice_associablehotspot_58fefcee6d356012389200": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_58fefcee6d356012389200", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "50,90,75,115" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "choice_associablehotspot_58fefcee6d395772822873": { + "identifier": "associablehotspot_4", + "serial": "choice_associablehotspot_58fefcee6d395772822873", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "170,41,195,66" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "choice_associablehotspot_58fefcee6d3cf844239757": { + "identifier": "associablehotspot_5", + "serial": "choice_associablehotspot_58fefcee6d3cf844239757", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_5", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "167,116,177,126" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "choice_associablehotspot_58fefcee6d40b884369334": { + "identifier": "associablehotspot_6", + "serial": "choice_associablehotspot_58fefcee6d40b884369334", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_6", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "105,68,130,93" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "choice_associablehotspot_58fefcee6d447411540553": { + "identifier": "associablehotspot_7", + "serial": "choice_associablehotspot_58fefcee6d447411540553", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_7", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "109,161,140,183" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58fefcee6addd997074327", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "object": { + "serial": "object_58fefcee6d493474314325", + "qtiClass": "object", + "attributes": { + "data": "daoism.jpg", + "type": "image\/jpeg", + "width": 230, + "height": 229 + }, + "debug": { + "relatedItem": "" + } + }, + "gapImgs": { + "choice_gapimg_58fefcee6bd9b706307713": { + "identifier": "gapimg_1", + "serial": "choice_gapimg_58fefcee6bd9b706307713", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_1", + "fixed": false, + "matchMin": "0", + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "object": { + "serial": "object_58fefcee6c70e692322336", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + } + }, + "choice_gapimg_58fefcee6c781109246143": { + "identifier": "gapimg_2", + "serial": "choice_gapimg_58fefcee6c781109246143", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_2", + "fixed": false, + "matchMin": "0", + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "object": { + "serial": "object_58fefcee6c7c2707722853", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + } + }, + "choice_gapimg_58fefcee6c80c429703646": { + "identifier": "gapimg_3", + "serial": "choice_gapimg_58fefcee6c80c429703646", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_3", + "fixed": false, + "matchMin": "0", + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "object": { + "serial": "object_58fefcee6c845347424062", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + } + } + } + } + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58fefcee65c73846555919": { + "serial": "stylesheet_58fefcee65c73846555919", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + } + } + }, + "outcomes": { + "outcomedeclaration_58fefcee68180226694501": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fefcee68180226694501", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fefcee670f0996099942": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fefcee670f0996099942", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n gapimg_2 associablehotspot_3\n ", + "\n gapimg_2 associablehotspot_4\n ", + "\n gapimg_3 associablehotspot_7\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fefcee6ed9d823891605", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fefcee63887006001955" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphic-gap-infinite.json b/test/qtiItem/maxScore/data/graphic-gap-infinite.json new file mode 100644 index 00000000..14fdcaac --- /dev/null +++ b/test/qtiItem/maxScore/data/graphic-gap-infinite.json @@ -0,0 +1,391 @@ +{ + "identifier": "i14930461572410513", + "serial": "item_58ff0ef0ebda1332345043", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930461572410513", + "title": "Item 16", + "label": "Item 16", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ff0ef0ebd87417100058", + "body": "\n
\n
\n {{interaction_graphicgapmatchinteraction_58ff0ef0f2a6e123174630}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicgapmatchinteraction_58ff0ef0f2a6e123174630": { + "serial": "interaction_graphicgapmatchinteraction_58ff0ef0f2a6e123174630", + "qtiClass": "graphicGapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "choices": { + "choice_associablehotspot_58ff0ef1011fa352808331": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_58ff0ef1011fa352808331", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "14,15,24,25" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef1017d5875422571": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_58ff0ef1017d5875422571", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "90,28,100,38" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef101820457779251": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_58ff0ef101820457779251", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "50,90,75,115" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef101863499083872": { + "identifier": "associablehotspot_4", + "serial": "choice_associablehotspot_58ff0ef101863499083872", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "170,41,195,66" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef1018a4730585459": { + "identifier": "associablehotspot_5", + "serial": "choice_associablehotspot_58ff0ef1018a4730585459", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_5", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "167,116,177,126" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef1018e3851865848": { + "identifier": "associablehotspot_6", + "serial": "choice_associablehotspot_58ff0ef1018e3851865848", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_6", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "105,68,130,93" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef10191f065594039": { + "identifier": "associablehotspot_7", + "serial": "choice_associablehotspot_58ff0ef10191f065594039", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_7", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "109,161,140,183" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ff0ef0f33bd857335888", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "object": { + "serial": "object_58ff0ef101970637612886", + "qtiClass": "object", + "attributes": { + "data": "daoism.jpg", + "type": "image\/jpeg", + "width": 230, + "height": 229 + }, + "debug": { + "relatedItem": "" + } + }, + "gapImgs": { + "choice_gapimg_58ff0ef100200371357495": { + "identifier": "gapimg_1", + "serial": "choice_gapimg_58ff0ef100200371357495", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_1", + "fixed": false, + "matchMin": "0", + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "object": { + "serial": "object_58ff0ef100bd2483147611", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "choice_gapimg_58ff0ef100c52661606684": { + "identifier": "gapimg_2", + "serial": "choice_gapimg_58ff0ef100c52661606684", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_2", + "fixed": false, + "matchMin": "0", + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "object": { + "serial": "object_58ff0ef100c99915172399", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "choice_gapimg_58ff0ef100ce6443956538": { + "identifier": "gapimg_3", + "serial": "choice_gapimg_58ff0ef100ce6443956538", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_3", + "fixed": false, + "matchMin": "0", + "matchMax": "0" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "object": { + "serial": "object_58ff0ef100d22505820240", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + } + } + } + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ff0ef0ee0ff888387647": { + "serial": "stylesheet_58ff0ef0ee0ff888387647", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "outcomes": { + "outcomedeclaration_58ff0ef0f0cba953915650": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ff0ef0f0cba953915650", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ff0ef0ef6db122365810": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ff0ef0ef6db122365810", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "defaultValue": [], + "mapping": { + "gapimg_2 associablehotspot_3": "-1", + "gapimg_2 associablehotspot_4": "2", + "gapimg_3 associablehotspot_7": "0.5", + "gapimg_1 associablehotspot_3": "-0.25" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n gapimg_2 associablehotspot_3\n ", + "\n gapimg_2 associablehotspot_4\n ", + "\n gapimg_3 associablehotspot_7\n " + ], + "mappingAttributes": { + "defaultValue": 1 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ff0ef10310a390500677", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphic-gap-map.json b/test/qtiItem/maxScore/data/graphic-gap-map.json new file mode 100644 index 00000000..1ce63c2b --- /dev/null +++ b/test/qtiItem/maxScore/data/graphic-gap-map.json @@ -0,0 +1,391 @@ +{ + "identifier": "i14930461572410513", + "serial": "item_58ff0ef0ebda1332345043", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930461572410513", + "title": "Item 16", + "label": "Item 16", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ff0ef0ebd87417100058", + "body": "\n
\n
\n {{interaction_graphicgapmatchinteraction_58ff0ef0f2a6e123174630}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicgapmatchinteraction_58ff0ef0f2a6e123174630": { + "serial": "interaction_graphicgapmatchinteraction_58ff0ef0f2a6e123174630", + "qtiClass": "graphicGapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "choices": { + "choice_associablehotspot_58ff0ef1011fa352808331": { + "identifier": "associablehotspot_1", + "serial": "choice_associablehotspot_58ff0ef1011fa352808331", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "14,15,24,25" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef1017d5875422571": { + "identifier": "associablehotspot_2", + "serial": "choice_associablehotspot_58ff0ef1017d5875422571", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "90,28,100,38" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef101820457779251": { + "identifier": "associablehotspot_3", + "serial": "choice_associablehotspot_58ff0ef101820457779251", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "50,90,75,115" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef101863499083872": { + "identifier": "associablehotspot_4", + "serial": "choice_associablehotspot_58ff0ef101863499083872", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "170,41,195,66" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef1018a4730585459": { + "identifier": "associablehotspot_5", + "serial": "choice_associablehotspot_58ff0ef1018a4730585459", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_5", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "167,116,177,126" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef1018e3851865848": { + "identifier": "associablehotspot_6", + "serial": "choice_associablehotspot_58ff0ef1018e3851865848", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_6", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "105,68,130,93" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "choice_associablehotspot_58ff0ef10191f065594039": { + "identifier": "associablehotspot_7", + "serial": "choice_associablehotspot_58ff0ef10191f065594039", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "associablehotspot_7", + "fixed": false, + "matchMax": 0, + "matchMin": 0, + "shape": "rect", + "coords": "109,161,140,183" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ff0ef0f33bd857335888", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "object": { + "serial": "object_58ff0ef101970637612886", + "qtiClass": "object", + "attributes": { + "data": "daoism.jpg", + "type": "image\/jpeg", + "width": 230, + "height": 229 + }, + "debug": { + "relatedItem": "" + } + }, + "gapImgs": { + "choice_gapimg_58ff0ef100200371357495": { + "identifier": "gapimg_1", + "serial": "choice_gapimg_58ff0ef100200371357495", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_1", + "fixed": false, + "matchMin": "0", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "object": { + "serial": "object_58ff0ef100bd2483147611", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "choice_gapimg_58ff0ef100c52661606684": { + "identifier": "gapimg_2", + "serial": "choice_gapimg_58ff0ef100c52661606684", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_2", + "fixed": false, + "matchMin": "0", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "object": { + "serial": "object_58ff0ef100c99915172399", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "choice_gapimg_58ff0ef100ce6443956538": { + "identifier": "gapimg_3", + "serial": "choice_gapimg_58ff0ef100ce6443956538", + "qtiClass": "gapImg", + "attributes": { + "identifier": "gapimg_3", + "fixed": false, + "matchMin": "0", + "matchMax": "1" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "object": { + "serial": "object_58ff0ef100d22505820240", + "qtiClass": "object", + "attributes": { + "data": "training_css3.png", + "type": "image\/png", + "width": 28, + "height": 28 + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + } + } + } + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ff0ef0ee0ff888387647": { + "serial": "stylesheet_58ff0ef0ee0ff888387647", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + } + } + }, + "outcomes": { + "outcomedeclaration_58ff0ef0f0cba953915650": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ff0ef0f0cba953915650", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ff0ef0ef6db122365810": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ff0ef0ef6db122365810", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "defaultValue": [], + "mapping": { + "gapimg_2 associablehotspot_3": "-1", + "gapimg_2 associablehotspot_4": "2", + "gapimg_3 associablehotspot_7": "0.5", + "gapimg_1 associablehotspot_3": "-0.25" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n gapimg_2 associablehotspot_3\n ", + "\n gapimg_2 associablehotspot_4\n ", + "\n gapimg_3 associablehotspot_7\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ff0ef10310a390500677", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ff0ef0ebda1332345043" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/graphicorder-map.json b/test/qtiItem/maxScore/data/graphicorder-map.json new file mode 100644 index 00000000..f27c3ad1 --- /dev/null +++ b/test/qtiItem/maxScore/data/graphicorder-map.json @@ -0,0 +1,241 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ef3b81ed9e0871596281", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ef3b81ed9c5268212295", + "body": "\n
\n
\n {{interaction_graphicorderinteraction_58ef3b81f3cea278427384}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_graphicorderinteraction_58ef3b81f3cea278427384": { + "serial": "interaction_graphicorderinteraction_58ef3b81f3cea278427384", + "qtiClass": "graphicOrderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + }, + "choices": { + "choice_hotspotchoice_58ef3b8201db3779943701": { + "identifier": "hotspot_1", + "serial": "choice_hotspotchoice_58ef3b8201db3779943701", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "hotspot_1", + "fixed": false, + "shape": "circle", + "coords": "31,40,5" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + } + }, + "choice_hotspotchoice_58ef3b82025d9656816764": { + "identifier": "hotspot_2", + "serial": "choice_hotspotchoice_58ef3b82025d9656816764", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "hotspot_2", + "fixed": false, + "shape": "circle", + "coords": "141,116,14" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + } + }, + "choice_hotspotchoice_58ef3b820261a454407204": { + "identifier": "hotspot_3", + "serial": "choice_hotspotchoice_58ef3b820261a454407204", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "hotspot_3", + "fixed": false, + "shape": "circle", + "coords": "263,31,11" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ef3b8200b35600269435", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + } + }, + "object": { + "serial": "object_58ef3b820266a459283039", + "qtiClass": "object", + "attributes": { + "data": "splintercell.gif", + "type": "image\/gif", + "width": 428, + "height": 276 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + } + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ef3b81efd87919587405": { + "serial": "stylesheet_58ef3b81efd87919587405", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + } + } + }, + "outcomes": { + "outcomedeclaration_58ef3b81f23bc194868751": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ef3b81f23bc194868751", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ef3b81f1206279403405": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ef3b81f1206279403405", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n hotspot_1\n ", + "\n hotspot_2\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ef3b820446e998894829", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ef3b81ed9e0871596281" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/hotspot-correct.json b/test/qtiItem/maxScore/data/hotspot-correct.json new file mode 100644 index 00000000..aa6beaf8 --- /dev/null +++ b/test/qtiItem/maxScore/data/hotspot-correct.json @@ -0,0 +1,228 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ef23941277f094905602", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ef239412760628032476", + "body": "\n
\n
\n {{interaction_hotspotinteraction_58ef23941fac1298685588}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_hotspotinteraction_58ef23941fac1298685588": { + "serial": "interaction_hotspotinteraction_58ef23941fac1298685588", + "qtiClass": "hotspotInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 0, + "minChoices": 0, + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + }, + "choices": { + "choice_hotspotchoice_58ef239424ad4142528670": { + "identifier": "hotspot_1", + "serial": "choice_hotspotchoice_58ef239424ad4142528670", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "hotspot_1", + "fixed": false, + "shape": "circle", + "coords": "234,32,23" + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + } + }, + "choice_hotspotchoice_58ef23942550b970600327": { + "identifier": "hotspot_2", + "serial": "choice_hotspotchoice_58ef23942550b970600327", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "hotspot_2", + "fixed": false, + "shape": "circle", + "coords": "94,115,15" + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ef239422191672309804", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + } + }, + "object": { + "serial": "object_58ef239425563029262504", + "qtiClass": "object", + "attributes": { + "data": "background.gif", + "type": "image\/gif", + "width": 428, + "height": 276 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + } + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ef239416dc0087007775": { + "serial": "stylesheet_58ef239416dc0087007775", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + } + } + }, + "outcomes": { + "outcomedeclaration_58ef23941c111744250505": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ef23941c111744250505", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ef239418e63439601982": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ef239418e63439601982", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ef23941277f094905602" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n hotspot_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ef239427553544829175", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ef23941277f094905602" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/hottext-correct.json b/test/qtiItem/maxScore/data/hottext-correct.json new file mode 100644 index 00000000..700e5493 --- /dev/null +++ b/test/qtiItem/maxScore/data/hottext-correct.json @@ -0,0 +1,233 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ef201046324478479635", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ef2010462be026079528", + "body": "\n
\n
\n {{interaction_hottextinteraction_58ef20104cc44065788479}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_hottextinteraction_58ef20104cc44065788479": { + "serial": "interaction_hottextinteraction_58ef20104cc44065788479", + "qtiClass": "hottextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 0, + "minChoices": 0 + }, + "body": { + "serial": "container_containerhottext_58ef20104dfb1550927906", + "body": "\n \n

Lorem ipsum\n\n {{choice_hottext_58ef20104e9b5184532523}} sit amet,\n\n {{choice_hottext_58ef20104f334319078951}} adipisicing ...\n\n <\/p>\n ", + "elements": { + "choice_hottext_58ef20104e9b5184532523": { + "identifier": "hottext_1", + "serial": "choice_hottext_58ef20104e9b5184532523", + "qtiClass": "hottext", + "attributes": { + "identifier": "hottext_1", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_58ef20104f29a583314526", + "body": "dolor", + "elements": {}, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + }, + "choice_hottext_58ef20104f334319078951": { + "identifier": "hottext_2", + "serial": "choice_hottext_58ef20104f334319078951", + "qtiClass": "hottext", + "attributes": { + "identifier": "hottext_2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_58ef20104f356090567208", + "body": "consectetur", + "elements": {}, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + } + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + }, + "prompt": { + "serial": "container_containerstatic_58ef20104dd7a213478699", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + } + } + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ef201048c3a190131531": { + "serial": "stylesheet_58ef201048c3a190131531", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + } + } + }, + "outcomes": { + "outcomedeclaration_58ef20104af60386896815": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ef20104af60386896815", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ef201049fe9366038368": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ef201049fe9366038368", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ef201046324478479635" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "hottext_1" + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ef201051a30350480686", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ef201046324478479635" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/inlinechoice-correct-noresponse.json b/test/qtiItem/maxScore/data/inlinechoice-correct-noresponse.json new file mode 100644 index 00000000..79cd6eb4 --- /dev/null +++ b/test/qtiItem/maxScore/data/inlinechoice-correct-noresponse.json @@ -0,0 +1,216 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee354acd140342635001", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee354acd123769646132", + "body": "\n

\n
\n

Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_inlinechoiceinteraction_58ee354ad2fe4693636901}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_inlinechoiceinteraction_58ee354ad2fe4693636901": { + "serial": "interaction_inlinechoiceinteraction_58ee354ad2fe4693636901", + "qtiClass": "inlineChoiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "required": false + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "choices": { + "choice_inlinechoice_58ee354ad4187447154168": { + "identifier": "choice_1", + "serial": "choice_inlinechoice_58ee354ad4187447154168", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "text": "choice #1" + }, + "choice_inlinechoice_58ee354ad4975962973239": { + "identifier": "choice_2", + "serial": "choice_inlinechoice_58ee354ad4975962973239", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "text": "choice #2" + }, + "choice_inlinechoice_58ee354ad49b7884281330": { + "identifier": "choice_3", + "serial": "choice_inlinechoice_58ee354ad49b7884281330", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "text": "choice #3" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + } + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee354acf2f7679471541": { + "serial": "stylesheet_58ee354acf2f7679471541", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee354ad13e6440086686": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee354ad13e6440086686", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee354ad0700345191314": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee354ad0700345191314", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee354ad6be0038254476", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee354acd140342635001" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/inlinechoice-correct.json b/test/qtiItem/maxScore/data/inlinechoice-correct.json new file mode 100644 index 00000000..96c63cf7 --- /dev/null +++ b/test/qtiItem/maxScore/data/inlinechoice-correct.json @@ -0,0 +1,218 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee3746b6b88066405203", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee3746b6b61281403655", + "body": "\n

\n
\n

Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_inlinechoiceinteraction_58ee3746bd9db510037512}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_inlinechoiceinteraction_58ee3746bd9db510037512": { + "serial": "interaction_inlinechoiceinteraction_58ee3746bd9db510037512", + "qtiClass": "inlineChoiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "required": false + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "choices": { + "choice_inlinechoice_58ee3746bea87938162031": { + "identifier": "choice_1", + "serial": "choice_inlinechoice_58ee3746bea87938162031", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "text": "choice #1" + }, + "choice_inlinechoice_58ee3746bf22c659377535": { + "identifier": "choice_2", + "serial": "choice_inlinechoice_58ee3746bf22c659377535", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "text": "choice #2" + }, + "choice_inlinechoice_58ee3746bf270776279519": { + "identifier": "choice_3", + "serial": "choice_inlinechoice_58ee3746bf270776279519", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "text": "choice #3" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + } + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee3746b9532109076639": { + "serial": "stylesheet_58ee3746b9532109076639", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee3746bbe81966027911": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee3746bbe81966027911", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee3746bacd2952580401": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee3746bacd2952580401", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee3746c11e4411473995", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee3746b6b88066405203" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/inlinechoice-map.json b/test/qtiItem/maxScore/data/inlinechoice-map.json new file mode 100644 index 00000000..8bf9ec81 --- /dev/null +++ b/test/qtiItem/maxScore/data/inlinechoice-map.json @@ -0,0 +1,215 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee38775c61e155645861", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee38775c603500967570", + "body": "\n

\n
\n

Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_inlinechoiceinteraction_58ee387764037273565779}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_inlinechoiceinteraction_58ee387764037273565779": { + "serial": "interaction_inlinechoiceinteraction_58ee387764037273565779", + "qtiClass": "inlineChoiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "required": false + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "choices": { + "choice_inlinechoice_58ee387765101305737213": { + "identifier": "choice_1", + "serial": "choice_inlinechoice_58ee387765101305737213", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "text": "choice #1" + }, + "choice_inlinechoice_58ee3877658b8023885791": { + "identifier": "choice_2", + "serial": "choice_inlinechoice_58ee3877658b8023885791", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "text": "choice #2" + }, + "choice_inlinechoice_58ee3877658f6755063022": { + "identifier": "choice_3", + "serial": "choice_inlinechoice_58ee3877658f6755063022", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "text": "choice #3" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + } + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee38775f1da153251026": { + "serial": "stylesheet_58ee38775f1da153251026", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee387762523743004366": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee387762523743004366", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee387760981216414679": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee387760981216414679", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "defaultValue": [], + "mapping": { + "choice_1": "2", + "choice_2": "0.5", + "choice_3": "-1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_1\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee387767108480043266", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee38775c61e155645861" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/match-correct.json b/test/qtiItem/maxScore/data/match-correct.json new file mode 100644 index 00000000..53c04912 --- /dev/null +++ b/test/qtiItem/maxScore/data/match-correct.json @@ -0,0 +1,333 @@ +{ + "identifier": "i14930425198330510", + "serial": "item_58fe0776d5974496136621", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930425198330510", + "title": "Item 15", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fe0776d591e703702638", + "body": "\n

\n
\n {{interaction_matchinteraction_58fe0776db6f0287938721}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_matchinteraction_58fe0776db6f0287938721": { + "serial": "interaction_matchinteraction_58fe0776db6f0287938721", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 0, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_58fe0776dc81e285677404", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "choices": [ + { + "choice_simpleassociablechoice_58fe0776dcf6a139491030": { + "identifier": "choice_1", + "serial": "choice_simpleassociablechoice_58fe0776dcf6a139491030", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776ddb30337381523", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "choice_simpleassociablechoice_58fe0776ddbd8323259819": { + "identifier": "choice_2", + "serial": "choice_simpleassociablechoice_58fe0776ddbd8323259819", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776ddc08160949168", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "choice_simpleassociablechoice_58fe0776ddc7e332708155": { + "identifier": "choice_5", + "serial": "choice_simpleassociablechoice_58fe0776ddc7e332708155", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776ddca9756225454", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + } + }, + { + "choice_simpleassociablechoice_58fe0776ddd25559292110": { + "identifier": "choice_3", + "serial": "choice_simpleassociablechoice_58fe0776ddd25559292110", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776ddd50476408683", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "choice_simpleassociablechoice_58fe0776dddbb235025331": { + "identifier": "choice_4", + "serial": "choice_simpleassociablechoice_58fe0776dddbb235025331", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776ddde4460203647", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "choice_simpleassociablechoice_58fe0776dde4c987704695": { + "identifier": "choice_6", + "serial": "choice_simpleassociablechoice_58fe0776dde4c987704695", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776dde74987345581", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "choice_simpleassociablechoice_58fe0776ddeda611594545": { + "identifier": "choice_7", + "serial": "choice_simpleassociablechoice_58fe0776ddeda611594545", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe0776ddf02677801436", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + } + } + ] + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + } + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_58fe0776d9a9e059269556": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fe0776d9a9e059269556", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fe0776d891f839469431": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fe0776d891f839469431", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_2 choice_3\n ", + "\n choice_1 choice_6\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fe0776dffa0397636797", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fe0776d5974496136621" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/match-map.json b/test/qtiItem/maxScore/data/match-map.json new file mode 100644 index 00000000..137e7abb --- /dev/null +++ b/test/qtiItem/maxScore/data/match-map.json @@ -0,0 +1,332 @@ +{ + "identifier": "i14930425198330510", + "serial": "item_58fe127150720405989603", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14930425198330510", + "title": "Item 15", + "label": "Item 15", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58fe1271506ff007591642", + "body": "\n
\n
\n {{interaction_matchinteraction_58fe127155895946551177}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_matchinteraction_58fe127155895946551177": { + "serial": "interaction_matchinteraction_58fe127155895946551177", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 0, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_58fe12715675d625556723", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "choices": [ + { + "choice_simpleassociablechoice_58fe127156d75415180862": { + "identifier": "choice_1", + "serial": "choice_simpleassociablechoice_58fe127156d75415180862", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157761323046741", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "choice_simpleassociablechoice_58fe127157832183768298": { + "identifier": "choice_2", + "serial": "choice_simpleassociablechoice_58fe127157832183768298", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157867480897352", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "choice_simpleassociablechoice_58fe1271578fc667165586": { + "identifier": "choice_5", + "serial": "choice_simpleassociablechoice_58fe1271578fc667165586", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157932746307060", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + } + }, + { + "choice_simpleassociablechoice_58fe1271579d4713295276": { + "identifier": "choice_3", + "serial": "choice_simpleassociablechoice_58fe1271579d4713295276", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157a05184323075", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "choice_simpleassociablechoice_58fe127157a8f600647047": { + "identifier": "choice_4", + "serial": "choice_simpleassociablechoice_58fe127157a8f600647047", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157aba621174036", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "choice_simpleassociablechoice_58fe127157b40470084765": { + "identifier": "choice_6", + "serial": "choice_simpleassociablechoice_58fe127157b40470084765", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157b6e450713071", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "choice_simpleassociablechoice_58fe127157bf5109902794": { + "identifier": "choice_7", + "serial": "choice_simpleassociablechoice_58fe127157bf5109902794", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_58fe127157c1d665558692", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + } + } + ] + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + } + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_58fe1271540fa841137909": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58fe1271540fa841137909", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58fe127152fdb761578711": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58fe127152fdb761578711", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_58fe127150720405989603" + }, + "defaultValue": [], + "mapping": { + "choice_2 choice_3": "2", + "choice_1 choice_6": "1", + "choice_2 choice_4": "-1", + "choice_1 choice_4": "-2", + "choice_5 choice_4": "0.25" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n choice_2 choice_3\n ", + "\n choice_1 choice_6\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58fe127158cff978576949", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58fe127150720405989603" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/match-matchmax.json b/test/qtiItem/maxScore/data/match-matchmax.json new file mode 100644 index 00000000..2ef6cac8 --- /dev/null +++ b/test/qtiItem/maxScore/data/match-matchmax.json @@ -0,0 +1,284 @@ +{ + "identifier": "i14961523262234191", + "serial": "item_592d7bda57a84528898113", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14961523262234191", + "title": "match", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint52", + "class": "" + }, + "body": { + "serial": "container_containeritembody_592d7bda57a66493021937", + "body": "\n
\n
\n {{interaction_matchinteraction_592d7bda61e94062834907}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_matchinteraction_592d7bda61e94062834907": { + "serial": "interaction_matchinteraction_592d7bda61e94062834907", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 0, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_592d7bda63d85566256736", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "choices": [ + { + "choice_simpleassociablechoice_592d7bda64942262732562": { + "identifier": "choice_1", + "serial": "choice_simpleassociablechoice_592d7bda64942262732562", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592d7bda65d0a695536540", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "choice_simpleassociablechoice_592d7bda65dbb717521305": { + "identifier": "choice_2", + "serial": "choice_simpleassociablechoice_592d7bda65dbb717521305", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592d7bda65deb099247700", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + } + }, + { + "choice_simpleassociablechoice_592d7bda65e6c441752567": { + "identifier": "choice_3", + "serial": "choice_simpleassociablechoice_592d7bda65e6c441752567", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592d7bda65e99975615053", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "choice_simpleassociablechoice_592d7bda65f07645101073": { + "identifier": "choice_4", + "serial": "choice_simpleassociablechoice_592d7bda65f07645101073", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show", + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_592d7bda65f31341879827", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + } + } + ] + } + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_592d7bda5b1f0406913715": { + "serial": "stylesheet_592d7bda5b1f0406913715", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + } + } + }, + "outcomes": { + "outcomedeclaration_592d7bda5f095828076766": { + "identifier": "SCORE", + "serial": "outcomedeclaration_592d7bda5f095828076766", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + }, + "defaultValue": null + }, + "outcomedeclaration_592d7bda60dfb849190165": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_592d7bda60dfb849190165", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + }, + "defaultValue": "2" + } + }, + "responses": { + "responsedeclaration_592d7bda5d5f2160540443": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_592d7bda5d5f2160540443", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + }, + "defaultValue": [], + "mapping": { + "choice_1 choice_3": "2" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 5 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_592d7bda67ecd495382312", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_592d7bda57a84528898113" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/order-correct.json b/test/qtiItem/maxScore/data/order-correct.json new file mode 100644 index 00000000..87ab973a --- /dev/null +++ b/test/qtiItem/maxScore/data/order-correct.json @@ -0,0 +1,291 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee3dfaac173268960733", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee3dfaac156056914505", + "body": "\n
\n
\n {{interaction_orderinteraction_58ee3dfab53cd679507470}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_orderinteraction_58ee3dfab53cd679507470": { + "serial": "interaction_orderinteraction_58ee3dfab53cd679507470", + "qtiClass": "orderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + }, + "choices": { + "choice_simplechoice_58ee3dfab7f8b841510182": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58ee3dfab7f8b841510182", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3dfab89f7799782311", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "choice_simplechoice_58ee3dfab8a93568240471": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58ee3dfab8a93568240471", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3dfab8ab4958658517", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "choice_simplechoice_58ee3dfab8b21266272659": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58ee3dfab8b21266272659", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3dfab8b3e845708576", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "choice_simplechoice_58ee3dfab8bc1556029123": { + "identifier": "choice_4", + "serial": "choice_simplechoice_58ee3dfab8bc1556029123", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3dfab8bdf571092931", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "choice_simplechoice_58ee3dfab8c3f342487778": { + "identifier": "choice_5", + "serial": "choice_simplechoice_58ee3dfab8c3f342487778", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3dfab8c59600989303", + "body": "choice #5", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ee3dfab7545733722062", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee3dfaaf3b7019120575": { + "serial": "stylesheet_58ee3dfaaf3b7019120575", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee3dfab2c1b175498122": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee3dfab2c1b175498122", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee3dfab11d2272119418": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee3dfab11d2272119418", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n choice_1\n ", + "\n choice_2\n ", + "\n choice_3\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee3dfabad28432471358", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee3dfaac173268960733" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/order-noresponse.json b/test/qtiItem/maxScore/data/order-noresponse.json new file mode 100644 index 00000000..fdbd15f9 --- /dev/null +++ b/test/qtiItem/maxScore/data/order-noresponse.json @@ -0,0 +1,245 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee3d5534726064139584", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee3d5534701334237542", + "body": "\n
\n
\n {{interaction_orderinteraction_58ee3d553a9af548340442}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_orderinteraction_58ee3d553a9af548340442": { + "serial": "interaction_orderinteraction_58ee3d553a9af548340442", + "qtiClass": "orderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + }, + "choices": { + "choice_simplechoice_58ee3d553c876787735124": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58ee3d553c876787735124", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3d553d015840525870", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + }, + "choice_simplechoice_58ee3d553d0b2293721730": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58ee3d553d0b2293721730", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3d553d0d4378226603", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + }, + "choice_simplechoice_58ee3d553d13f699992945": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58ee3d553d13f699992945", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ee3d553d15d135017445", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ee3d553c05a635963916", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee3d5536e19245330709": { + "serial": "stylesheet_58ee3d5536e19245330709", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee3d5538efa360772590": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee3d5538efa360772590", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee3d5538260193947796": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee3d5538260193947796", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee3d553edc4005941742", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee3d5534726064139584" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/pci-custom.json b/test/qtiItem/maxScore/data/pci-custom.json new file mode 100644 index 00000000..9fba5536 --- /dev/null +++ b/test/qtiItem/maxScore/data/pci-custom.json @@ -0,0 +1,185 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee6e0b6ae78809425962", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee6e0b6ae5c668992904", + "body": "\n
\n
\n {{interaction_portablecustominteraction_58ee6e0b76827428325525}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_portablecustominteraction_58ee6e0b76827428325525": { + "serial": "interaction_portablecustominteraction_58ee6e0b76827428325525", + "qtiClass": "customInteraction", + "attributes": { + "responseIdentifier": "RESPONSE" + }, + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + }, + "choices": {}, + "typeIdentifier": "likertScaleInteraction", + "markup": "\n
\n
<\/div>\n
    <\/ul>\n <\/div>\n ", + "version": "0.0.0", + "entryPoint": "", + "libraries": [], + "stylesheets": [], + "mediaFiles": [], + "properties": { + "level": "5", + "label-min": "min", + "label-max": "max" + } + } + }, + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + } + }, + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee6e0b6d36b158656137": { + "serial": "stylesheet_58ee6e0b6d36b158656137", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee6e0b6fa32076990898": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee6e0b6fa32076990898", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee6e0b6ebfe580144987": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee6e0b6ebfe580144987", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "integer" + }, + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee6e0b77ff5212012896", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee6e0b6ae78809425962" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} diff --git a/test/qtiItem/maxScore/data/qti.xml b/test/qtiItem/maxScore/data/qti.xml new file mode 100644 index 00000000..de5e803e --- /dev/null +++ b/test/qtiItem/maxScore/data/qti.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + 4 + + + + +
    +
    + + + ipsum + amet + adipisicing +

    Lorem + + dolor sit + + , consectetur + + ... + +

    +
    +
    +
    +
    + +
    \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/selectpoint-map.json b/test/qtiItem/maxScore/data/selectpoint-map.json new file mode 100644 index 00000000..92ac612d --- /dev/null +++ b/test/qtiItem/maxScore/data/selectpoint-map.json @@ -0,0 +1,216 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ef25a944e72594804656", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ef25a944e55377792798", + "body": "\n
    \n
    \n {{interaction_selectpointinteraction_58ef25a94b3da336266585}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_selectpointinteraction_58ef25a94b3da336266585": { + "serial": "interaction_selectpointinteraction_58ef25a94b3da336266585", + "qtiClass": "selectPointInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 0, + "minChoices": 0, + "class": "responsive" + }, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_58ef25a94c404312665549", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + } + }, + "object": { + "serial": "object_58ef25a94ce76261290623", + "qtiClass": "object", + "attributes": { + "data": "background.gif", + "type": "image\/gif", + "width": 428, + "height": 276 + }, + "debug": { + "relatedItem": "" + } + } + } + }, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + } + }, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "html5": "html5", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "pci": "http:\/\/www.imsglobal.org\/xsd\/portableCustomInteraction", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ef25a9471b7544473166": { + "serial": "stylesheet_58ef25a9471b7544473166", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + } + } + }, + "outcomes": { + "outcomedeclaration_58ef25a949678922192998": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ef25a949678922192998", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ef25a94864d447751919": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ef25a94864d447751919", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "point" + }, + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [ + { + "shape": "circle", + "coords": "179,115,61", + "mappedValue": "-1" + }, + { + "shape": "circle", + "coords": "26,57,7", + "mappedValue": "2" + }, + { + "shape": "circle", + "coords": "18,14,5", + "mappedValue": "4" + }, + { + "shape": "ellipse", + "coords": "10,32,5,5", + "mappedValue": "-1" + }, + { + "shape": "circle", + "coords": "48,22,8", + "mappedValue": "2" + } + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response_point", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ef25a94e68d850578158", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ef25a944e72594804656" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponsePoint", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/slider-correct.json b/test/qtiItem/maxScore/data/slider-correct.json new file mode 100644 index 00000000..377b6241 --- /dev/null +++ b/test/qtiItem/maxScore/data/slider-correct.json @@ -0,0 +1,186 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ef3e3d4e042770118811", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ef3e3d4e024181509007", + "body": "\n
    \n
    \n {{interaction_sliderinteraction_58ef3e3d54ff7021132819}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_sliderinteraction_58ef3e3d54ff7021132819": { + "serial": "interaction_sliderinteraction_58ef3e3d54ff7021132819", + "qtiClass": "sliderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "lowerBound": 0, + "upperBound": 100, + "step": 1, + "stepLabel": false, + "orientation": "horizontal", + "reverse": false + }, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_58ef3e3d5779f936251489", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + } + } + } + }, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + } + }, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ef3e3d5092a803703952": { + "serial": "stylesheet_58ef3e3d5092a803703952", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + } + } + }, + "outcomes": { + "outcomedeclaration_58ef3e3d52d66600944714": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ef3e3d52d66600944714", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ef3e3d51d87614258125": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ef3e3d51d87614258125", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "integer" + }, + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n 38\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ef3e3d59689840119919", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ef3e3d4e042770118811" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/textentry-correct-impossible-patternmask.json b/test/qtiItem/maxScore/data/textentry-correct-impossible-patternmask.json new file mode 100644 index 00000000..5a2782c6 --- /dev/null +++ b/test/qtiItem/maxScore/data/textentry-correct-impossible-patternmask.json @@ -0,0 +1,175 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58f07536a11bd781065211", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58f07536a11a0271917006", + "body": "\n
    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_textentryinteraction_58f07536ab56e395709059}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_58f07536ab56e395709059": { + "serial": "interaction_textentryinteraction_58f07536ab56e395709059", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "patternMask": "^[\\s\\S]{0,3}$", + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + } + }, + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58f07536a4b13223850483": { + "serial": "stylesheet_58f07536a4b13223850483", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + } + } + }, + "outcomes": { + "outcomedeclaration_58f07536a898f939434724": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58f07536a898f939434724", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58f07536a6d48712981947": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58f07536a6d48712981947", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n ABCD\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58f07536b06ee518443539", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58f07536a11bd781065211" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/textentry-correct.json b/test/qtiItem/maxScore/data/textentry-correct.json new file mode 100644 index 00000000..e7b3f7a1 --- /dev/null +++ b/test/qtiItem/maxScore/data/textentry-correct.json @@ -0,0 +1,175 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee417ff125e595852471", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee417ff1244045363356", + "body": "\n

    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_textentryinteraction_58ee418003611073061503}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_58ee418003611073061503": { + "serial": "interaction_textentryinteraction_58ee418003611073061503", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + } + }, + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee417ff3709433115810": { + "serial": "stylesheet_58ee417ff3709433115810", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee418001b9f954198408": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee418001b9f954198408", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee4180009e7163518595": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee4180009e7163518595", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "\n A\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee418007f1e831976227", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee417ff125e595852471" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/textentry-map-impossible-patternmask.json b/test/qtiItem/maxScore/data/textentry-map-impossible-patternmask.json new file mode 100644 index 00000000..5c0080ff --- /dev/null +++ b/test/qtiItem/maxScore/data/textentry-map-impossible-patternmask.json @@ -0,0 +1,172 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58f07c297383f397607601", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58f07c2973823774124907", + "body": "\n

    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_textentryinteraction_58f07c297b5a8610845961}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_58f07c297b5a8610845961": { + "serial": "interaction_textentryinteraction_58f07c297b5a8610845961", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "patternMask": "^[\\s\\S]{0,3}$", + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_58f07c297383f397607601" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_58f07c297383f397607601" + } + }, + "debug": { + "relatedItem": "item_58f07c297383f397607601" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58f07c29761cd728785229": { + "serial": "stylesheet_58f07c29761cd728785229", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58f07c297383f397607601" + } + } + }, + "outcomes": { + "outcomedeclaration_58f07c29790ab699722417": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58f07c29790ab699722417", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58f07c297383f397607601" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58f07c2977a04721560400": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58f07c2977a04721560400", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_58f07c297383f397607601" + }, + "defaultValue": [], + "mapping": { + "ABCD": "1", + "ABC": "0.5", + "AB": "-1" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n ABCD\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58f07c297e6ef278432972", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58f07c297383f397607601" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/textentry-map.json b/test/qtiItem/maxScore/data/textentry-map.json new file mode 100644 index 00000000..b692b05f --- /dev/null +++ b/test/qtiItem/maxScore/data/textentry-map.json @@ -0,0 +1,172 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee4214dd6a9499081656", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee4214dd689892272777", + "body": "\n

    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\n\n {{interaction_textentryinteraction_58ee4214e5b38107830587}}\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_58ee4214e5b38107830587": { + "serial": "interaction_textentryinteraction_58ee4214e5b38107830587", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + } + }, + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee4214e04f7575632619": { + "serial": "stylesheet_58ee4214e04f7575632619", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee4214e37ea409883721": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee4214e37ea409883721", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee4214e1d9d981860768": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee4214e1d9d981860768", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + }, + "defaultValue": [], + "mapping": { + "A": "-1", + "B": "2", + "C": "0" + }, + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/map_response", + "correctResponses": [ + "\n A\n " + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee4214e9d0f113543333", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee4214dd6a9499081656" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/upload-choice-correct.json b/test/qtiItem/maxScore/data/upload-choice-correct.json new file mode 100644 index 00000000..51c705ad --- /dev/null +++ b/test/qtiItem/maxScore/data/upload-choice-correct.json @@ -0,0 +1,330 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ef1a9b205fc209247971", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ef1a9b205e0313771293", + "body": "\n

    \n
    \n {{interaction_choiceinteraction_58ef1a9b273e7751888295}}\n <\/div>\n <\/div>\n
    \n
    \n {{interaction_uploadinteraction_58ef1a9b2adc8408009571}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_58ef1a9b273e7751888295": { + "serial": "interaction_choiceinteraction_58ef1a9b273e7751888295", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "choices": { + "choice_simplechoice_58ef1a9b29f76448584269": { + "identifier": "choice_1", + "serial": "choice_simplechoice_58ef1a9b29f76448584269", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ef1a9b2a95c919481399", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + }, + "choice_simplechoice_58ef1a9b2aa02155175493": { + "identifier": "choice_2", + "serial": "choice_simplechoice_58ef1a9b2aa02155175493", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ef1a9b2aa24881719850", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + }, + "choice_simplechoice_58ef1a9b2aa99364768304": { + "identifier": "choice_3", + "serial": "choice_simplechoice_58ef1a9b2aa99364768304", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_58ef1a9b2aaf4226157753", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + } + }, + "prompt": { + "serial": "container_containerstatic_58ef1a9b29508989674126", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + } + }, + "interaction_uploadinteraction_58ef1a9b2adc8408009571": { + "serial": "interaction_uploadinteraction_58ef1a9b2adc8408009571", + "qtiClass": "uploadInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1" + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_58ef1a9b2b00b036217844", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + } + } + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ef1a9b22f67166646852": { + "serial": "stylesheet_58ef1a9b22f67166646852", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + } + } + }, + "outcomes": { + "outcomedeclaration_58ef1a9b251c1764806456": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ef1a9b251c1764806456", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ef1a9b24465535971969": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ef1a9b24465535971969", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_58ef1a9b24ecb369048081": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_58ef1a9b24ecb369048081", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "file" + }, + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ef1a9b2caa2306910628", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ef1a9b205fc209247971" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/data/upload.json b/test/qtiItem/maxScore/data/upload.json new file mode 100644 index 00000000..373b7802 --- /dev/null +++ b/test/qtiItem/maxScore/data/upload.json @@ -0,0 +1,179 @@ +{ + "identifier": "i1492000233609482", + "serial": "item_58ee6d65088b6054172459", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1492000233609482", + "title": "Item 14", + "label": "Item 14", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint48", + "class": "" + }, + "body": { + "serial": "container_containeritembody_58ee6d6508896432709876", + "body": "\n
    \n
    \n {{interaction_uploadinteraction_58ee6d65109ee027924659}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_uploadinteraction_58ee6d65109ee027924659": { + "serial": "interaction_uploadinteraction_58ee6d65109ee027924659", + "qtiClass": "uploadInteraction", + "attributes": { + "responseIdentifier": "RESPONSE" + }, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_58ee6d651237c252778979", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + } + } + } + }, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + } + }, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_58ee6d650b55a268921242": { + "serial": "stylesheet_58ee6d650b55a268921242", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + } + } + }, + "outcomes": { + "outcomedeclaration_58ee6d650df8e252521961": { + "identifier": "SCORE", + "serial": "outcomedeclaration_58ee6d650df8e252521961", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_58ee6d650cdf1785279785": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_58ee6d650cdf1785279785", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "file" + }, + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_58ee6d651494d933103458", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_58ee6d65088b6054172459" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/qtiItem/maxScore/test.html b/test/qtiItem/maxScore/test.html new file mode 100644 index 00000000..c43d1e93 --- /dev/null +++ b/test/qtiItem/maxScore/test.html @@ -0,0 +1,25 @@ + + + + + QTI Item max score helper + + + + +
    +
    +
    +
    +
    + + diff --git a/test/qtiItem/maxScore/test.js b/test/qtiItem/maxScore/test.js new file mode 100644 index 00000000..0e20755c --- /dev/null +++ b/test/qtiItem/maxScore/test.js @@ -0,0 +1,446 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2017 (original work) Open Assessment Technologies SA + **/ +define([ + 'lodash', + 'taoQtiItem/qtiItem/core/Element', + 'taoQtiItem/qtiItem/core/Loader', + 'taoQtiItem/qtiItem/helper/maxScore', + 'json!taoQtiItem/test/qtiItem/maxScore/data/choice-correct-noresponse.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/choice-correct-multiple.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/choice-map-maxchoice3.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/choice-map-upperbound2.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/composite-choice-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/composite-choice-correct-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/inlinechoice-correct-noresponse.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/inlinechoice-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/inlinechoice-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/order-noresponse.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/order-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/textentry-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/textentry-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/textentry-correct-impossible-patternmask.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/textentry-map-impossible-patternmask.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/extended-text.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/extended-text-manual-scoring.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/extended-text-manual-scoring-with-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/upload.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/pci-custom.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/custom-rp.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/upload-choice-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/hottext-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/hotspot-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/selectpoint-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphicorder-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/slider-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/gapmatch-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/gapmatch-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/associate-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/associate-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/match-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/match-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphic-associate-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphic-associate-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphic-gap-correct.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphic-gap-map.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/associate-matchmax.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/match-matchmax.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/gapmatch-matchmax.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/gapmatch-map-matchmax.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphic-gap-infinite.json', + 'json!taoQtiItem/test/qtiItem/maxScore/data/graphic-associate-matchmax.json' +], function( + _, + Element, + Loader, + maxScore, + dataChoiceCorrectNoResponse, + dataChoiceCorrectMultiple, + dataChoiceMaxchoice3, + dataChoiceUpperbound2, + dataCompositeChoiceCorrect, + dataCompositeChoiceCorrectMap, + dataInlineChoiceCorrectNoResponse, + dataInlineChoiceCorrect, + dataInlineChoiceMap, + dataOrderNoResponse, + dataOrder, + dataTextentryCorrect, + dataTextentryMap, + dataTextentryCorrectImpossiblePatternMask, + dataTextentryMapImpossiblePatternMask, + dataExtendedText, + dataExtendedTextManualScoring, + dataExtendedTextManualScoringWithCorrect, + dataUpload, + dataPci, + dataCustomRp, + dataUploadChoice, + dataHottextCorrect, + dataHotspotCorrect, + dataSelectpointMap, + dataGraphicOrderCorrect, + dataSliderCorrect, + dataGapmatchCorrect, + dataGapmatchMap, + dataAssociateCorrect, + dataAssociateMap, + dataMatchCorrect, + dataMatchMap, + dataGraphicAssociateCorrect, + dataGraphicAssociateMap, + dataGraphicGapCorrect, + dataGraphicGapMap, + dataAssociateMatchmax, + dataMatchMatchmax, + dataGapMatchMatchmax, + dataGapMatchMapMatchmax, + dataGapMatchInfinite, + dataGraphicAssocMatchmax +) { + 'use strict'; + + var cases = [ + { title: 'single choice correct', data: dataChoiceCorrectMultiple, expectedMaximum: 1, maxScore: 1 }, + { + title: 'single choice correct - no correct response', + data: dataChoiceCorrectNoResponse, + expectedMaximum: 0, + maxScore: 0 + }, + + //If _ignoreMinChoice is turned to false, expect the expectedMaximumto be 0 instead of 1 + { + title: 'single choice correct - impossible min choice', + data: dataChoiceCorrectMultiple, + expectedMaximum: 1, + maxScore: 1, + changeData: function(data) { + data.body.elements.interaction_choiceinteraction_58eb45eba8e1b211271087.attributes.minChoices = 3; + return data; + } + }, + { title: 'single choice map - maxChoice 3', data: dataChoiceMaxchoice3, expectedMaximum: 3, maxScore: 3 }, + { + title: 'single choice map - map default > 3', + data: dataChoiceMaxchoice3, + expectedMaximum: 3, + maxScore: 3, + changeData: function(data) { + data.responses.responsedeclaration_58eb4dfbd4a74001643639.mappingAttributes.defaultValue = 3; + data.responses.responsedeclaration_58eb4dfbd4a74001643639.mappingAttributes.upperBound = 0; + return data; + } + }, + { + title: 'single choice map - map default > 3 and 2 map entries', + data: dataChoiceMaxchoice3, + expectedMaximum: 5, + maxScore: 5, + changeData: function(data) { + data.responses.responsedeclaration_58eb4dfbd4a74001643639.mappingAttributes.defaultValue = 3; + data.responses.responsedeclaration_58eb4dfbd4a74001643639.mappingAttributes.upperBound = 0; + delete data.responses.responsedeclaration_58eb4dfbd4a74001643639.mapping.choice_3; + return data; + } + }, + { + title: 'single choice map - no map entries', + data: dataChoiceMaxchoice3, + expectedMaximum: 0, + maxScore: 0, + changeData: function(data) { + //Note: when the mapping entry is empty, it is not QTI compliant + data.responses.responsedeclaration_58eb4dfbd4a74001643639.mapping = {}; + data.responses.responsedeclaration_58eb4dfbd4a74001643639.mappingAttributes.defaultValue = 1; + return data; + } + }, + { title: 'single choice map - upperBound 2', data: dataChoiceUpperbound2, expectedMaximum: 2, maxScore: 2 }, + { title: 'composite choice correct', data: dataCompositeChoiceCorrect, expectedMaximum: 2, maxScore: 2 }, + { + title: 'composite choice correct and map', + data: dataCompositeChoiceCorrectMap, + expectedMaximum: 2.5, + maxScore: 2.5 + }, + { + title: 'inline choice correct - no correct response', + data: dataInlineChoiceCorrectNoResponse, + expectedMaximum: 0, + maxScore: 0 + }, + { title: 'inline choice correct', data: dataInlineChoiceCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'inline choice map', data: dataInlineChoiceMap, expectedMaximum: 2, maxScore: 2 }, + { title: 'order - no correct response', data: dataOrderNoResponse, expectedMaximum: 0, maxScore: 0 }, + { title: 'order', data: dataOrder, expectedMaximum: 1, maxScore: 1 }, + { title: 'text entry - correct', data: dataTextentryCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'text entry - map', data: dataTextentryMap, expectedMaximum: 2, maxScore: 2 }, + { + title: 'text entry - correct but impossible pattern mask', + data: dataTextentryCorrectImpossiblePatternMask, + expectedMaximum: 0, + maxScore: 0 + }, + { + title: 'text entry - map but some impossible pattern mask', + data: dataTextentryMapImpossiblePatternMask, + expectedMaximum: 0.5, + maxScore: 0.5 + }, + { title: 'extended text', data: dataExtendedText, expectedMaximum: 1, maxScore: 1 }, + { + title: 'extended text - manual scoring', + data: dataExtendedTextManualScoring, + expectedMaximum: 0, + maxScore: 3 + }, + { + title: 'extended text - manual scoring with correct', + data: dataExtendedTextManualScoringWithCorrect, + expectedMaximum: 1, + maxScore: 4 + }, + { title: 'upload', data: dataUpload, expectedMaximum: undefined, maxScore: undefined }, + { title: 'custom interaction', data: dataPci, expectedMaximum: undefined, maxScore: undefined }, + { title: 'custom response processing', data: dataCustomRp, expectedMaximum: undefined, maxScore: undefined }, + { + title: 'upload and choice - correct', + data: dataUploadChoice, + expectedMaximum: undefined, + maxScore: undefined + }, + { title: 'hottext - correct', data: dataHottextCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'hotspot - correct', data: dataHotspotCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'select point - map response', data: dataSelectpointMap, expectedMaximum: 8, maxScore: 8 }, + { title: 'graphic order - correct', data: dataGraphicOrderCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'slider - correct', data: dataSliderCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'gap match - correct', data: dataGapmatchCorrect, expectedMaximum: 1, maxScore: 1 }, + { + title: 'gap match - correct matchMax', + data: dataGapmatchCorrect, + expectedMaximum: 0, + maxScore: 0, + changeData: function(data) { + data.responses.responsedeclaration_58f5e075ede73619627566.correctResponses = [ + 'choice_11 gap_2', + 'choice_11 gap_1' + ]; + return data; + } + }, + { + title: 'gap match - correct gap', + data: dataGapmatchCorrect, + expectedMaximum: 0, + maxScore: 0, + changeData: function(data) { + data.responses.responsedeclaration_58f5e075ede73619627566.correctResponses = [ + 'choice_11 gap_1', + 'choice_12 gap_1' + ]; + return data; + } + }, + { title: 'gap match - map', data: dataGapmatchMap, expectedMaximum: 3, maxScore: 3 }, + { + title: 'gap match - map (no match max)', + data: dataGapmatchMap, + expectedMaximum: 3.5, + maxScore: 3.5, + changeData: function(data) { + data.body.elements.interaction_gapmatchinteraction_58fa1c4a97da2623687350.choices.choice_gaptext_58fa1c4a9c05b538942409.attributes.matchMax = 0; + return data; + } + }, + { title: 'associate - correct', data: dataAssociateCorrect, expectedMaximum: 1, maxScore: 1 }, + { + title: 'associate - correct impossible', + data: dataAssociateCorrect, + expectedMaximum: 0, + maxScore: 0, + changeData: function(data) { + data.body.elements.interaction_associateinteraction_58fdf58980cb4613690390.choices.choice_simpleassociablechoice_58fdf58984e63595993061.attributes.matchMax = 1; + return data; + } + }, + { title: 'associate - map', data: dataAssociateMap, expectedMaximum: 3, maxScore: 3 }, + { + title: 'associate - map - matchMax=1', + data: dataAssociateMap, + expectedMaximum: 2, + maxScore: 2, + changeData: function(data) { + data.body.elements.interaction_associateinteraction_58fdfc915cb60553869971.choices.choice_simpleassociablechoice_58fdfc915f3ed319686888.attributes.matchMax = 1; + return data; + } + }, + { + title: 'associate - map - maxAssociations=1', + data: dataAssociateMap, + expectedMaximum: 2, + maxScore: 2, + changeData: function(data) { + data.body.elements.interaction_associateinteraction_58fdfc915cb60553869971.attributes.maxAssociations = 1; + return data; + } + }, + + //If _ignoreMinChoice is turned to false, expect the expectedMaximumto be 2.8 instead of 3 + { + title: 'associate - map - minAssociations=3', + data: dataAssociateMap, + expectedMaximum: 3, + maxScore: 3, + changeData: function(data) { + data.body.elements.interaction_associateinteraction_58fdfc915cb60553869971.attributes.minAssociations = 3; + return data; + } + }, + + //If _ignoreMinChoice is turned to false, expect the expectedMaximumto be 2.4 instead of 3 + { + title: 'associate - map - minAssociations=5', + data: dataAssociateMap, + expectedMaximum: 3, + maxScore: 3, + changeData: function(data) { + data.body.elements.interaction_associateinteraction_58fdfc915cb60553869971.attributes.minAssociations = 5; + return data; + } + }, + { + title: 'associate - map - map default > 0', + data: dataAssociateMap, + expectedMaximum: 5, + maxScore: 5, + changeData: function(data) { + data.responses.responsedeclaration_58fdfc91590be744736300.mappingAttributes.defaultValue = 1; + data.body.elements.interaction_associateinteraction_58fdfc915cb60553869971.attributes.maxAssociations = 4; + return data; + } + }, + { title: 'match - correct', data: dataMatchCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'match - map', data: dataMatchMap, expectedMaximum: 3.25, maxScore: 3.25 }, + { title: 'graphic associate - correct', data: dataGraphicAssociateCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'graphic associate - map', data: dataGraphicAssociateMap, expectedMaximum: 1.2, maxScore: 1.2 }, + { title: 'graphic gap match - correct', data: dataGraphicGapCorrect, expectedMaximum: 1, maxScore: 1 }, + { title: 'graphic gap match - map', data: dataGraphicGapMap, expectedMaximum: 2.5, maxScore: 2.5 }, + { + title: 'associate - match max - favorable mapping', + data: dataAssociateMatchmax, + expectedMaximum: 15, + maxScore: 15 + }, + { + title: 'associate - match max - favorable mapping disrupt', + data: dataAssociateMatchmax, + expectedMaximum: 14, + maxScore: 14, + changeData: function(data) { + data.responses.responsedeclaration_592c14d47a3b5383510187.mapping['choice_1 choice_2'] = 5; //Mess up the order + delete data.responses.responsedeclaration_592c14d47a3b5383510187.mapping['choice_3 choice_5']; + return data; + } + }, + { + title: 'associate - match max - unfavorable mapping', + data: dataAssociateMatchmax, + expectedMaximum: 11, + maxScore: 11, + changeData: function(data) { + data.responses.responsedeclaration_592c14d47a3b5383510187.mapping['choice_3 choice_5'] = 0.5; + return data; + } + }, + { + title: 'associate - match max - unfavorable mapping', + data: dataAssociateMatchmax, + expectedMaximum: 11, + maxScore: 11, + changeData: function(data) { + data.responses.responsedeclaration_592c14d47a3b5383510187.mapping['choice_1 choice_1'] = 100; //Impossible + delete data.responses.responsedeclaration_592c14d47a3b5383510187.mapping['choice_3 choice_5']; + return data; + } + }, + { title: 'match - match max - favorable mapping', data: dataMatchMatchmax, expectedMaximum: 17, maxScore: 17 }, + { + title: 'gap match - match max = 0 - favorable mapping', + data: dataGapMatchMatchmax, + expectedMaximum: 4, + maxScore: 4 + }, + { + title: 'gap match - match max = 1 - neutral mapping', + data: dataGapMatchMapMatchmax, + expectedMaximum: 6, + maxScore: 6 + }, + { + title: 'gap match - inifinite score', + data: dataGapMatchInfinite, + expectedMaximum: undefined, + maxScore: undefined + }, + { + title: 'gap association - match max - favorable mapping', + data: dataGraphicAssocMatchmax, + expectedMaximum: 5, + maxScore: 5 + } + ]; + + QUnit.cases.init(cases).test('setNormalMaximum', function(settings, assert) { + var ready = assert.async(); + + var loader = new Loader(); + var data = _.cloneDeep(settings.data); + + if (_.isFunction(settings.changeData)) { + data = settings.changeData(data); + } + + loader.loadItemData(data, function(item) { + var outcomeScore, outcomeMaxScore; + + ready(); + assert.ok(Element.isA(item, 'assessmentItem'), 'item loaded'); + + outcomeScore = item.getOutcomeDeclaration('SCORE'); + assert.ok(_.isUndefined(outcomeScore.attr('normalMaximum')), 'normalMaximum initially undefined'); + + maxScore.setNormalMaximum(item); + assert.equal( + outcomeScore.attr('normalMaximum'), + settings.expectedMaximum, + 'calculated normalMaximum is correct' + ); + + maxScore.setMaxScore(item); + if (!_.isUndefined(settings.maxScore)) { + assert.expect(5); + outcomeMaxScore = item.getOutcomeDeclaration('MAXSCORE'); + assert.ok(Element.isA(outcomeMaxScore, 'outcomeDeclaration'), 'MAXSCORE outcome exists'); + assert.equal(outcomeMaxScore.getDefaultValue(), settings.maxScore); + } else { + assert.expect(4); + assert.ok(_.isUndefined(item.getOutcomeDeclaration('MAXSCORE')), 'MAXSCORE undefined'); + } + }); + }); +}); diff --git a/test/qtiRunner/modalFeedback/inlineRenderer/test.html b/test/qtiRunner/modalFeedback/inlineRenderer/test.html new file mode 100644 index 00000000..83f0367d --- /dev/null +++ b/test/qtiRunner/modalFeedback/inlineRenderer/test.html @@ -0,0 +1,25 @@ + + + + + QTI Item "Inline" Modal Feedback renderer Test + + + + +
    +
    +
    +
    +
    + + diff --git a/test/qtiRunner/modalFeedback/inlineRenderer/test.js b/test/qtiRunner/modalFeedback/inlineRenderer/test.js new file mode 100644 index 00000000..2bf5de22 --- /dev/null +++ b/test/qtiRunner/modalFeedback/inlineRenderer/test.js @@ -0,0 +1,214 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/qtiItem/core/Element', + 'taoQtiItem/qtiItem/core/Loader', + 'taoQtiItem/qtiCommonRenderer/renderers/Renderer', + 'taoQtiItem/qtiCommonRenderer/helpers/container', + 'taoQtiItem/qtiRunner/modalFeedback/inlineRenderer', + 'json!taoQtiItem/test/samples/json/inlineModalFeedback.json' +], function($, _, Element, QtiLoader, QtiRenderer, containerHelper, inlineRenderer, itemData) { + var containerId = '#item-container'; + var item; + + QUnit.module('Modal Feedback rendering', { + afterEach: function(assert) { + if (item instanceof Element) { + item.unset(); + containerHelper.clear(); + } + } + }); + + var testCases = [ + { + title: 'choice interaction', + itemSession: { + FEEDBACK_1: { base: { identifier: 'feedbackModal_1' } }, + FEEDBACK_3: { base: { identifier: 'feedbackModal_3' } } + }, + feedbacks: { + choice: [ + { + identifier: 'feedbackModal_1', + title: 'modal feedback title', + text: 'right', + style: 'positive' + }, + { + identifier: 'feedbackModal_3', + title: '', + text: 'thiss is right', + style: '' + } + ], + order: [], + inline: [] + } + }, + { + title: 'choice & order interactions', + itemSession: { + FEEDBACK_2: { base: { identifier: 'feedbackModal_2' } }, + FEEDBACK_4: { base: { identifier: 'feedbackModal_4' } }, + FEEDBACK_5: { base: { identifier: 'feedbackModal_5' } } //FeedbackModal_5 has the same content as the feedbackModal_4 so it won\'t be displayed + }, + feedbacks: { + choice: [ + { + identifier: 'feedbackModal_2', + title: 'modal feedback title', + text: 'wrong', + style: 'negative' + } + ], + order: [ + { + identifier: 'feedbackModal_4', + title: '', + text: 'Correct', + style: 'positive' + } + ], + inline: [] + } + }, + { + title: 'choice & inline interactions', + itemSession: { + FEEDBACK_1: { base: { identifier: 'feedbackModal_1' } }, + FEEDBACK_3: { base: { identifier: 'feedbackModal_3' } }, + FEEDBACK_6: { base: { identifier: 'feedbackModal_6' } }, + FEEDBACK_7: { base: { identifier: 'feedbackModal_7' } }, //Feedback #6 and #7 have the same title and text but even with different style, only the first one shall be displayed + FEEDBACK_8: { base: { identifier: 'feedbackModal_8' } }, + FEEDBACK_9: { base: { identifier: 'feedbackModal_9' } } //Feedback #9 and #7 have the same title, text and style. The are related to inline iteractions that are both in the same block so contaier, so only the first one #7 will be displayed + }, + feedbacks: { + choice: [ + { + identifier: 'feedbackModal_1', + title: 'modal feedback title', + text: 'right', + style: 'positive' + }, + { + identifier: 'feedbackModal_3', + title: '', + text: 'thiss is right', + style: '' + } + ], + order: [], + inline: [ + { + identifier: 'feedbackModal_6', + title: '', + text: 'correct', + style: 'positive' + }, + { + identifier: 'feedbackModal_8', + title: 'modal feedback title', + text: 'Some feedback text.', + style: '' + } + ] + } + } + ]; + + QUnit.cases.init(testCases).test('renders an item', function(testCase, assert) { + var ready = assert.async(); + + var renderer = new QtiRenderer({ baseUrl: './' }); + + new QtiLoader().loadItemData(itemData, function(_item) { + var loader = this; + renderer.load(function() { + var result, $result, count; + + item = _item; + item.setRenderer(this); + + result = item.render({}); + + assert.ok(typeof result === 'string', 'The renderer creates a string'); + assert.ok(result.length > 0, 'The renderer create some output'); + + $result = $(result); + + var $choiceInteraction = $('.qti-choiceInteraction', $result); + var $orderInteraction = $('.qti-orderInteraction', $result); + var $textEntryInteraction = $('.qti-textEntryInteraction', $result); + var $inlineChoiceInteraction = $('.qti-inlineChoiceInteraction', $result); + var $inlineInteractionContainer = $inlineChoiceInteraction.parent('.col-12'); + + assert.ok($result.hasClass('qti-item'), 'The result is a qti item'); + assert.equal($('.qti-itemBody', $result).length, 1, 'The result contains an item body'); + assert.equal($choiceInteraction.length, 1, 'The result contains a choice interaction'); + assert.equal($orderInteraction.length, 1, 'The result contains an order interaction'); + assert.equal($textEntryInteraction.length, 1, 'The result contains a text enry interaction'); + assert.equal($inlineChoiceInteraction.length, 1, 'The result contains an inline choice interaction'); + assert.equal($inlineInteractionContainer.length, 1, 'Inline interaction container found'); + assert.equal($('.qti-modalFeedback', $result).length, 0, 'no modal feedback yet'); + + //Render in dom + $(containerId).append($result); + count = inlineRenderer.showFeedbacks(item, loader, renderer, testCase.itemSession, _.noop, function() { + var feedbacks; + + ready(); + + assert.equal( + $('.qti-modalFeedback', $choiceInteraction).length, + testCase.feedbacks.choice.length, + 'modal feedbacks below choice interaction' + ); + assert.equal( + $('.qti-modalFeedback', $orderInteraction).length, + testCase.feedbacks.order.length, + 'modal feedbacks below order interaction' + ); + assert.equal( + $('.qti-modalFeedback', $inlineInteractionContainer).length, + testCase.feedbacks.inline.length, + 'modal feedbacks below inline block' + ); + + feedbacks = testCase.feedbacks.choice.concat(testCase.feedbacks.order, testCase.feedbacks.inline); + assert.equal(feedbacks.length, count, 'number of feedbacks matches'); + + _.each(feedbacks, function(fb) { + var $feedback = $result.find('[data-identifier=' + fb.identifier + ']'); + assert.equal($feedback.length, 1, 'found feedback dom element for ' + fb.identifier); + if (fb.style) { + assert.ok($feedback.hasClass(fb.style), 'style class correctly set'); + } else { + assert.equal( + $feedback.attr('class').trim(), + 'qti-modalFeedback', + 'the unique css class must be qti-modalFeedback' + ); + } + + if (fb.title) { + assert.equal($feedback.children('.qti-title').length, 1, 'title found'); + assert.equal($feedback.children('.qti-title').text(), fb.title, 'title text ok'); + } else { + assert.equal($feedback.children('.qti-title').length, 0, 'no title'); + } + assert.equal($feedback.find('.modal-body').length, 1, 'feedback body found'); + assert.equal( + $feedback + .find('.modal-body') + .text() + .trim(), + fb.text, + 'feedback body found' + ); + }); + }); + }, loader.getLoadedClasses()); + }); + }); +}); diff --git a/test/qtiRunner/modalFeedback/modalRenderer/test.html b/test/qtiRunner/modalFeedback/modalRenderer/test.html new file mode 100644 index 00000000..823f56b2 --- /dev/null +++ b/test/qtiRunner/modalFeedback/modalRenderer/test.html @@ -0,0 +1,25 @@ + + + + + QTI Item "Modal" Modal Feedback renderer Test + + + + +
    +
    +
    +
    +
    + + diff --git a/test/qtiRunner/modalFeedback/modalRenderer/test.js b/test/qtiRunner/modalFeedback/modalRenderer/test.js new file mode 100644 index 00000000..344a59e3 --- /dev/null +++ b/test/qtiRunner/modalFeedback/modalRenderer/test.js @@ -0,0 +1,184 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/qtiItem/core/Element', + 'taoQtiItem/qtiItem/core/Loader', + 'taoQtiItem/qtiCommonRenderer/renderers/Renderer', + 'taoQtiItem/qtiCommonRenderer/helpers/container', + 'taoQtiItem/qtiRunner/modalFeedback/modalRenderer', + 'json!taoQtiItem/test/samples/json/inlineModalFeedback.json' +], function($, _, Element, QtiLoader, QtiRenderer, containerHelper, modalRenderer, itemData) { + var containerId = '#item-container'; + var item; + + QUnit.module('Modal Feedback rendering', { + afterEach: function(assert) { + if (item instanceof Element) { + item.unset(); + containerHelper.clear(); + } + } + }); + + var testCases = [ + { + title: 'choice interaction', + itemSession: { + FEEDBACK_1: { base: { identifier: 'feedbackModal_1' } }, + FEEDBACK_3: { base: { identifier: 'feedbackModal_3' } } + }, + feedbacks: [ + { + identifier: 'feedbackModal_1', + title: 'modal feedback title', + text: 'right', + style: 'positive' + }, + { + identifier: 'feedbackModal_3', + title: '', + text: 'thiss is right', + style: '' + } + ] + }, + { + title: 'choice & order interactions', + itemSession: { + FEEDBACK_2: { base: { identifier: 'feedbackModal_2' } }, + FEEDBACK_4: { base: { identifier: 'feedbackModal_4' } }, + FEEDBACK_5: { base: { identifier: 'feedbackModal_5' } } //FeedbackModal_5 has the same content as the feedbackModal_4 so it won\'t be displayed + }, + feedbacks: [ + { + identifier: 'feedbackModal_2', + title: 'modal feedback title', + text: 'wrong', + style: 'negative' + }, + { + identifier: 'feedbackModal_4', + title: '', + text: 'Correct', + style: 'positive' + } + ] + }, + { + title: 'choice & inline interactions', + itemSession: { + FEEDBACK_1: { base: { identifier: 'feedbackModal_1' } }, + FEEDBACK_3: { base: { identifier: 'feedbackModal_3' } }, + FEEDBACK_6: { base: { identifier: 'feedbackModal_6' } }, + FEEDBACK_7: { base: { identifier: 'feedbackModal_7' } }, //Feedback #6 and #7 have the same title and text but even with different style, only the first one shall be displayed + FEEDBACK_8: { base: { identifier: 'feedbackModal_8' } }, + FEEDBACK_9: { base: { identifier: 'feedbackModal_9' } } //Feedback #9 and #7 have the same title, text and style. The are related to inline iteractions that are both in the same block so contaier, so only the first one #7 will be displayed + }, + feedbacks: [ + { + identifier: 'feedbackModal_1', + title: 'modal feedback title', + text: 'right', + style: 'positive' + }, + { + identifier: 'feedbackModal_3', + title: '', + text: 'thiss is right', + style: '' + }, + { + identifier: 'feedbackModal_6', + title: '', + text: 'correct', + style: 'positive' + }, + { + identifier: 'feedbackModal_8', + title: 'modal feedback title', + text: 'Some feedback text.', + style: '' + } + ] + } + ]; + + QUnit.cases.init(testCases).test('renders an item', function(testCase, assert) { + var ready = assert.async(); + + var renderer = new QtiRenderer({ baseUrl: './' }); + + new QtiLoader().loadItemData(itemData, function(_item) { + var loader = this; + renderer.load(function() { + var result, $result, count; + + item = _item; + item.setRenderer(this); + + result = item.render({}); + + assert.ok(typeof result === 'string', 'The renderer creates a string'); + assert.ok(result.length > 0, 'The renderer create some output'); + + $result = $(result); + + var $choiceInteraction = $('.qti-choiceInteraction', $result); + var $orderInteraction = $('.qti-orderInteraction', $result); + var $textEntryInteraction = $('.qti-textEntryInteraction', $result); + var $inlineChoiceInteraction = $('.qti-inlineChoiceInteraction', $result); + var $inlineInteractionContainer = $inlineChoiceInteraction.parent('.col-12'); + + assert.ok($result.hasClass('qti-item'), 'The result is a qti item'); + assert.equal($('.qti-itemBody', $result).length, 1, 'The result contains an item body'); + assert.equal($choiceInteraction.length, 1, 'The result contains a choice interaction'); + assert.equal($orderInteraction.length, 1, 'The result contains an order interaction'); + assert.equal($textEntryInteraction.length, 1, 'The result contains a text enry interaction'); + assert.equal($inlineChoiceInteraction.length, 1, 'The result contains an inline choice interaction'); + assert.equal($inlineInteractionContainer.length, 1, 'Inline interaction container found'); + assert.equal($('.qti-modalFeedback', $result).length, 0, 'no modal feedback yet'); + + //Render in dom + $(containerId).append($result); + count = modalRenderer.showFeedbacks(item, loader, renderer, testCase.itemSession, _.noop, function() { + ready(); + assert.equal( + $('.qti-modalFeedback', $result).length, + testCase.feedbacks.length, + 'feedback modal rendered' + ); + + _.each(testCase.feedbacks, function(fb) { + var $feedback = $result.find('[data-identifier=' + fb.identifier + ']'); + assert.equal($feedback.length, 1, 'found feedback dom element for ' + fb.identifier); + if (fb.style) { + assert.ok($feedback.hasClass(fb.style), 'style class correctly set'); + } else { + assert.equal( + $feedback.attr('class').trim(), + 'modal qti-modalFeedback', + 'the unique css class must be qti-modalFeedback' + ); + } + + if (fb.title) { + assert.equal($feedback.children('.qti-title').length, 1, 'title found'); + assert.equal($feedback.children('.qti-title').text(), fb.title, 'title text ok'); + } else { + assert.equal($feedback.children('.qti-title').length, 0, 'no title'); + } + assert.equal($feedback.find('.modal-body').length, 1, 'feedback body found'); + assert.equal( + $feedback + .find('.modal-body') + .text() + .trim(), + fb.text, + 'feedback body found' + ); + }); + }); + }, loader.getLoadedClasses()); + }); + }); +}); diff --git a/test/runner/images/CBG.png b/test/runner/images/CBG.png new file mode 100755 index 00000000..144b2929 Binary files /dev/null and b/test/runner/images/CBG.png differ diff --git a/test/runner/images/EBG.png b/test/runner/images/EBG.png new file mode 100755 index 00000000..38af8170 Binary files /dev/null and b/test/runner/images/EBG.png differ diff --git a/test/runner/images/EDI.png b/test/runner/images/EDI.png new file mode 100755 index 00000000..557365c9 Binary files /dev/null and b/test/runner/images/EDI.png differ diff --git a/test/runner/images/GLA.png b/test/runner/images/GLA.png new file mode 100755 index 00000000..49eec0f2 Binary files /dev/null and b/test/runner/images/GLA.png differ diff --git a/test/runner/images/MAN.png b/test/runner/images/MAN.png new file mode 100755 index 00000000..c7f957f2 Binary files /dev/null and b/test/runner/images/MAN.png differ diff --git a/test/runner/images/MCH.png b/test/runner/images/MCH.png new file mode 100755 index 00000000..b72dc0f5 Binary files /dev/null and b/test/runner/images/MCH.png differ diff --git a/test/runner/images/airport.png b/test/runner/images/airport.png new file mode 100755 index 00000000..438db841 Binary files /dev/null and b/test/runner/images/airport.png differ diff --git a/test/runner/images/blue_door.png b/test/runner/images/blue_door.png new file mode 100755 index 00000000..48cda567 Binary files /dev/null and b/test/runner/images/blue_door.png differ diff --git a/test/runner/images/bus.png b/test/runner/images/bus.png new file mode 100755 index 00000000..c23fd4e1 Binary files /dev/null and b/test/runner/images/bus.png differ diff --git a/test/runner/images/green_door.png b/test/runner/images/green_door.png new file mode 100755 index 00000000..11ef633a Binary files /dev/null and b/test/runner/images/green_door.png differ diff --git a/test/runner/images/house.png b/test/runner/images/house.png new file mode 100755 index 00000000..e4a7a9c3 Binary files /dev/null and b/test/runner/images/house.png differ diff --git a/test/runner/images/open_car.png b/test/runner/images/open_car.png new file mode 100755 index 00000000..5a80f1a9 Binary files /dev/null and b/test/runner/images/open_car.png differ diff --git a/test/runner/images/open_goat.png b/test/runner/images/open_goat.png new file mode 100755 index 00000000..9b37b0a6 Binary files /dev/null and b/test/runner/images/open_goat.png differ diff --git a/test/runner/images/plane.png b/test/runner/images/plane.png new file mode 100755 index 00000000..c6882e75 Binary files /dev/null and b/test/runner/images/plane.png differ diff --git a/test/runner/images/postcard.png b/test/runner/images/postcard.png new file mode 100755 index 00000000..763abec3 Binary files /dev/null and b/test/runner/images/postcard.png differ diff --git a/test/runner/images/red_door.png b/test/runner/images/red_door.png new file mode 100755 index 00000000..92ac3039 Binary files /dev/null and b/test/runner/images/red_door.png differ diff --git a/test/runner/images/sign.png b/test/runner/images/sign.png new file mode 100755 index 00000000..72200caa Binary files /dev/null and b/test/runner/images/sign.png differ diff --git a/test/runner/images/train.png b/test/runner/images/train.png new file mode 100755 index 00000000..e13b702a Binary files /dev/null and b/test/runner/images/train.png differ diff --git a/test/runner/images/uk.png b/test/runner/images/uk.png new file mode 100755 index 00000000..2ce5e2da Binary files /dev/null and b/test/runner/images/uk.png differ diff --git a/test/runner/images/ukair.png b/test/runner/images/ukair.png new file mode 100755 index 00000000..421480f1 Binary files /dev/null and b/test/runner/images/ukair.png differ diff --git a/test/runner/images/ukairtags.png b/test/runner/images/ukairtags.png new file mode 100755 index 00000000..a01ddc1b Binary files /dev/null and b/test/runner/images/ukairtags.png differ diff --git a/test/runner/interactions/choice/test.html b/test/runner/interactions/choice/test.html new file mode 100644 index 00000000..23781081 --- /dev/null +++ b/test/runner/interactions/choice/test.html @@ -0,0 +1,26 @@ + + + + + Choice Interaction in QtiItemRunner Test + + + + +
    +
    +
    +
    + +
    + + diff --git a/test/runner/interactions/choice/test.js b/test/runner/interactions/choice/test.js new file mode 100644 index 00000000..4fd916cc --- /dev/null +++ b/test/runner/interactions/choice/test.js @@ -0,0 +1,335 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/space-shuttle.json' +], function($, _, qtiItemRunner, itemData) { + 'use strict'; + + var runner; + var containerId = 'item-container'; + + QUnit.module('Init', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('Item data loading', function(assert) { + var ready = assert.async(); + assert.expect(2); + + runner = qtiItemRunner('qti', itemData) + .on('init', function() { + assert.ok(typeof this._item === 'object', 'The item data is loaded and mapped to an object'); + assert.ok(typeof this._item.bdy === 'object', 'The item contains a body object'); + + ready(); + }) + .init(); + }); + + QUnit.module('Render', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('Item rendering', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.equal(container.children.length, 1, 'the container has children'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.module('Clear'); + + QUnit.test('Clear Item', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.equal(container.children.length, 1, 'the container has children'); + + this.clear(); + }) + .on('clear', function() { + assert.equal(container.children.length, 0, 'the container children are removed'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.module('State', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('get state after changes', function(assert) { + var ready = assert.async(); + assert.expect(12); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('error', function(e) { + console.error(e); + }) + .on('render', function() { + //Default state + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.equal(state.RESPONSE.response.base, null, 'the default state contains a null base'); + + //Change something + $('[data-identifier="Discovery"]', $(container)).click(); + + //Debugger; + + state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.identifier, 'Discovery', 'the contains the selected choice'); + + //Change something else + $('[data-identifier="Atlantis"]', $(container)).click(); + + state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.identifier, 'Atlantis', 'the contains the selected choice'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('set state', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Atlantis' } } } }); + + assert.ok( + $('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('set multiple states', function(assert) { + var ready = assert.async(); + assert.expect(8); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Atlantis' } } } }); + + assert.ok( + $('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + //Change something + $('[data-identifier="Discovery"]', $(container)).click(); + + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + assert.ok( + $('[data-identifier="Discovery"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Challenger' } } } }); + + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + assert.ok( + !$('[data-identifier="Discovery"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + assert.ok( + $('[data-identifier="Challenger"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('listen state changes', function(assert) { + var ready = assert.async(); + assert.expect(10); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('statechange', function(state) { + assert.ok( + $('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.identifier, 'Atlantis', 'the contains the selected choice'); + + ready(); + }) + .on('render', function() { + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.equal(state.RESPONSE.response.base, null, 'the default state contains a null base'); + + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + + $('[data-identifier="Atlantis"]', $(container)).click(); + }) + .init() + .render(container); + }); + + QUnit.module('Get responses', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('no responses set', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + var responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base, null, 'the response contains a null base property'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('get responses after changes', function(assert) { + var ready = assert.async(); + assert.expect(7); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + var responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base, null, 'the response contains a null base property'); + + //The user set response + $('[data-identifier="Atlantis"]', $(container)).click(); + + responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base.identifier, 'Atlantis', 'the response contains the set value'); + + ready(); + }) + .init() + .render(container); + }); +}); diff --git a/test/runner/interactions/textentry/test.html b/test/runner/interactions/textentry/test.html new file mode 100644 index 00000000..b25298e6 --- /dev/null +++ b/test/runner/interactions/textentry/test.html @@ -0,0 +1,26 @@ + + + + + Text Entry Interaction in QtiItemRunner Test + + + + +
    +
    +
    +
    + +
    + + diff --git a/test/runner/interactions/textentry/test.js b/test/runner/interactions/textentry/test.js new file mode 100644 index 00000000..e08a3c28 --- /dev/null +++ b/test/runner/interactions/textentry/test.js @@ -0,0 +1,327 @@ +define([ + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/richardIII-2.json' +], function($, _, qtiItemRunner, itemData) { + 'use strict'; + + var runner; + var containerId = 'item-container'; + + QUnit.module('Init', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('Item data loading', function(assert) { + var ready = assert.async(); + assert.expect(2); + + runner = qtiItemRunner('qti', itemData) + .on('init', function() { + assert.ok(typeof this._item === 'object', 'The item data is loaded and mapped to an object'); + assert.ok(typeof this._item.bdy === 'object', 'The item contains a body object'); + + ready(); + }) + .init(); + }); + + QUnit.module('Render', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('Item rendering', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.equal(container.children.length, 1, 'the container has children'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.module('Clear'); + + QUnit.test('Clear Item', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.equal(container.children.length, 1, 'the container has children'); + + this.clear(); + }) + .on('clear', function() { + assert.equal(container.children.length, 0, 'the container children are removed'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.module('State', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('get state after changes', function(assert) { + var ready = assert.async(); + assert.expect(12); + + $('#item-container').remove(); + $('#qunit-fixture').append('
    '); + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('error', function(e) { + console.error(e); + }) + .on('render', function() { + //Default state + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.equal(state.RESPONSE.response.base.string, '', 'the default state contains an empty string'); + + //Change something + $('input.qti-textEntryInteraction', $(container)) + .val('foo') + .trigger('change'); + + state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.string, 'foo', 'the contains the entered string'); + + //Change something else + $('input.qti-textEntryInteraction', $(container)) + .val('bar') + .trigger('change'); + + state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.string, 'bar', 'the contains the entered string'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('set state', function(assert) { + var ready = assert.async(); + assert.expect(3); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + assert.equal($('input.qti-textEntryInteraction', $(container)).val(), '', 'The current value is empty'); + + this.setState({ RESPONSE: { response: { base: { string: 'beebop' } } } }); + + assert.equal( + $('input.qti-textEntryInteraction', $(container)).val(), + 'beebop', + 'The current value matches the given state' + ); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('set multiple states', function(assert) { + var ready = assert.async(); + assert.expect(5); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + //Default state + assert.equal($('input.qti-textEntryInteraction', $(container)).val(), '', 'The current value is empty'); + + //Set state + this.setState({ RESPONSE: { response: { base: { string: 'bidiboop' } } } }); + assert.equal( + $('input.qti-textEntryInteraction', $(container)).val(), + 'bidiboop', + 'The current value matches the given state' + ); + + //Change something + $('input.qti-textEntryInteraction', $(container)) + .val('babar') + .trigger('change'); + assert.equal( + $('input.qti-textEntryInteraction', $(container)).val(), + 'babar', + 'The current value matches the given state' + ); + + //Change a new time the state + this.setState({ RESPONSE: { response: { base: { string: 'badabeloowap' } } } }); + assert.equal( + $('input.qti-textEntryInteraction', $(container)).val(), + 'badabeloowap', + 'The current value matches the given state' + ); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('listen state changes', function(assert) { + var ready = assert.async(); + assert.expect(9); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('statechange', function(state) { + assert.equal( + $('input.qti-textEntryInteraction', $(container)).val(), + 'woopsy', + 'The current value matches the given state' + ); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.string, 'woopsy', 'the contains the entered string'); + + ready(); + }) + .on('render', function() { + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.equal(state.RESPONSE.response.base.string, '', 'the default state contains an empty string'); + + $('input.qti-textEntryInteraction', $(container)) + .val('woopsy') + .trigger('keyup'); + }) + .init() + .render(container); + }); + + QUnit.module('Get responses', { + afterEach: function(assert) { + if (runner) { + runner.clear(); + } + } + }); + + QUnit.test('no responses set', function(assert) { + var ready = assert.async(); + assert.expect(4); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + var responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base.string, '', 'the response contains an empty string'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('get responses after changes', function(assert) { + var ready = assert.async(); + assert.expect(7); + + var container = document.getElementById(containerId); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + runner = qtiItemRunner('qti', itemData) + .on('render', function() { + var responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base.string, '', 'the response contains an empty string'); + + //The user set response + $('input.qti-textEntryInteraction', $(container)) + .val('kisscool') + .trigger('change'); + + responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base.string, 'kisscool', 'the default state contains an empty string'); + + ready(); + }) + .init() + .render(container); + }); +}); diff --git a/test/runner/manual.html b/test/runner/manual.html new file mode 100644 index 00000000..fde7da44 --- /dev/null +++ b/test/runner/manual.html @@ -0,0 +1,186 @@ + + + + + QtiItemRunner Demo Test + + + + + +
    +

    ItemRunner demo

    +
    + + +
    +
    +
    +

    Item rendering

    +
    +
    +
    +
    +
    +

    Output data

    + Clear +
    +
    +
    + + diff --git a/test/runner/provider/manager/userModules/data/qti.json b/test/runner/provider/manager/userModules/data/qti.json new file mode 100644 index 00000000..732630d7 --- /dev/null +++ b/test/runner/provider/manager/userModules/data/qti.json @@ -0,0 +1,232 @@ +{ + "identifier": "i14678948287836113", + "serial": "item_57836705797ab656391988", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14678948287836113", + "title": "sample", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint15", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5783670579791381982950", + "body": "\n
    \n
    \n {{interaction_choiceinteraction_578367057b478016316295}}\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_578367057b478016316295": { + "serial": "interaction_choiceinteraction_578367057b478016316295", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + }, + "choices": { + "choice_simplechoice_578367057c77c545375965": { + "identifier": "choice_1", + "serial": "choice_simplechoice_578367057c77c545375965", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_578367057ccdd498619635", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + }, + "choice_simplechoice_578367057ce9e033241106": { + "identifier": "choice_2", + "serial": "choice_simplechoice_578367057ce9e033241106", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_578367057cec8120765233", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + }, + "choice_simplechoice_578367057d014734843825": { + "identifier": "choice_3", + "serial": "choice_simplechoice_578367057d014734843825", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_578367057d038499095673", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + } + }, + "prompt": { + "serial": "container_containerstatic_578367057c19d931335341", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + } + } + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + } + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "outcomes": { + "outcomedeclaration_578367057ab57935154871": { + "identifier": "SCORE", + "serial": "outcomedeclaration_578367057ab57935154871", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_578367057a786008089355": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_578367057a786008089355", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_57836705797ab656391988" + }, + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_578367057de24704365653", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_57836705797ab656391988" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} diff --git a/test/runner/provider/manager/userModules/data/userModule1.js b/test/runner/provider/manager/userModules/data/userModule1.js new file mode 100644 index 00000000..f7988148 --- /dev/null +++ b/test/runner/provider/manager/userModules/data/userModule1.js @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); + * + */ +/** + * @author Christophe Noël + */ +define([], function () { + 'use strict'; + + return { + exec: function exec() { + if (!window.__userModulesTest) { + window.__userModulesTest = {}; + } + window.__userModulesTest.module1 = 'userModule1 loaded'; + } + }; +}); + diff --git a/test/runner/provider/manager/userModules/data/userModule2.js b/test/runner/provider/manager/userModules/data/userModule2.js new file mode 100644 index 00000000..14f523c5 --- /dev/null +++ b/test/runner/provider/manager/userModules/data/userModule2.js @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); + * + */ +/** + * @author Christophe Noël + */ +define([], function () { + 'use strict'; + + return { + exec: function exec() { + if (!window.__userModulesTest) { + window.__userModulesTest = {}; + } + window.__userModulesTest.module2 = 'userModule2 loaded'; + } + }; +}); + diff --git a/test/runner/provider/manager/userModules/test.html b/test/runner/provider/manager/userModules/test.html new file mode 100644 index 00000000..5c2423b7 --- /dev/null +++ b/test/runner/provider/manager/userModules/test.html @@ -0,0 +1,21 @@ + + + + + User Modules + + + + +
    +
    + + diff --git a/test/runner/provider/manager/userModules/test.js b/test/runner/provider/manager/userModules/test.js new file mode 100644 index 00000000..f17c9c2b --- /dev/null +++ b/test/runner/provider/manager/userModules/test.js @@ -0,0 +1,121 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); + * + */ +/** + * @author Christophe Noël + */ +define([ + 'jquery', + 'taoQtiItem/runner/provider/manager/userModules', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/runner/provider/manager/userModules/data/qti.json' +], function($, userModules, qtiItemRunner, itemData) { + 'use strict'; + + QUnit.module('userModules'); + + QUnit.test('module', function(assert) { + assert.expect(1); + + assert.ok(typeof userModules === 'object', 'The module expose an object'); + }); + + QUnit.test('loader should require user modules defined in config', function(assert) { + var ready = assert.async(); + assert.expect(3); + + userModules + .load(['taoQtiItem/test/runner/provider/manager/userModules/data/userModule1']) + .then(function() { + assert.ok(window.__userModulesTest, 'global __userModulesTest exists'); + assert.ok(window.__userModulesTest.module1, 'global __userModulesTest has a module1 property'); + assert.equal(window.__userModulesTest.module1, 'userModule1 loaded', 'module1 has the right value'); + ready(); + }) + .catch(function(err) { + assert.ok(false, 'error in user module loading: ' + err.message); + ready(); + }); + }); + + QUnit.test('loader should be called by itemRunner', function(assert) { + var ready = assert.async(); + var $container = $('#qunit-fixture'); + + require.config({ + config: { + 'taoQtiItem/runner/provider/manager/userModules': { + userModules: ['taoQtiItem/test/runner/provider/manager/userModules/data/userModule2'] + } + } + }); + + assert.expect(3); + + qtiItemRunner('qti', itemData) + .on('render', function() { + assert.ok(window.__userModulesTest, 'global __userModulesTest exists'); + assert.ok(window.__userModulesTest.module2, 'global __userModulesTest has a module2 property'); + assert.equal(window.__userModulesTest.module2, 'userModule2 loaded', 'module2 has the right value'); + ready(); + }) + .on('error', function(err) { + assert.ok(false, 'error in user module loading: ' + err.message); + ready(); + }) + .init() + .render($container); + }); + + QUnit.test('loader should work if no modules are defined', function(assert) { + var ready = assert.async(); + assert.expect(1); + + userModules + .load([]) + .then(function() { + assert.ok(true, 'no errors have been thrown'); + ready(); + }) + .catch(function(err) { + assert.ok(false, 'error in user module loading: ' + err.message); + ready(); + }); + }); + + // Please disable coverage in QUnit UI for this test to pass + QUnit.test('should return an error if module is not found', function(assert) { + var ready = assert.async(); + assert.expect(1); + + require.config({ + waitSeconds: 1 + }); + + userModules + .load(['i/do/not/exist']) + .then(function() { + assert.ok(false, 'an error should have been thrown'); + ready(); + }) + .catch(function() { + assert.ok(true, 'error in user module loading:'); + ready(); + }); + }); +}); diff --git a/test/runner/provider/pic-mock-1.js b/test/runner/provider/pic-mock-1.js new file mode 100644 index 00000000..38ec1693 --- /dev/null +++ b/test/runner/provider/pic-mock-1.js @@ -0,0 +1,5 @@ +define(['taoQtiItem/test/runner/provider/portableLib/pic-mock'], function (mock) { + 'use strict'; + + mock.pic('picMock1'); +}); diff --git a/test/runner/provider/pic-mock-2.js b/test/runner/provider/pic-mock-2.js new file mode 100644 index 00000000..99fb1f91 --- /dev/null +++ b/test/runner/provider/pic-mock-2.js @@ -0,0 +1,5 @@ +define(['taoQtiItem/test/runner/provider/portableLib/pic-mock'], function (mock) { + 'use strict'; + + mock.pic('picMock2'); +}); diff --git a/test/runner/provider/pic-mock-3.js b/test/runner/provider/pic-mock-3.js new file mode 100644 index 00000000..60768f69 --- /dev/null +++ b/test/runner/provider/pic-mock-3.js @@ -0,0 +1,5 @@ +define(['taoQtiItem/test/runner/provider/portableLib/pic-mock'], function (mock) { + 'use strict'; + + mock.pic('picMock3'); +}); diff --git a/test/runner/provider/pic-mock-studentToolbar.js b/test/runner/provider/pic-mock-studentToolbar.js new file mode 100644 index 00000000..cd19948c --- /dev/null +++ b/test/runner/provider/pic-mock-studentToolbar.js @@ -0,0 +1,5 @@ +define(['taoQtiItem/test/runner/provider/portableLib/pic-mock'], function (mock) { + 'use strict'; + + mock.pic('studentToolbar', true); +}); diff --git a/test/runner/provider/portableLib/pic-mock.js b/test/runner/provider/portableLib/pic-mock.js new file mode 100644 index 00000000..8a7d8dd5 --- /dev/null +++ b/test/runner/provider/portableLib/pic-mock.js @@ -0,0 +1,97 @@ +define([ + 'taoQtiItem/portableLib/jquery_2_1_1', + 'taoQtiItem/portableLib/OAT/sts/common', + 'qtiInfoControlContext' +], +function ($, common, qtiInfoControlContext) { + 'use strict'; + + /** + * Create a PIC mock + * @param {String} typeIdentifier + * @param {Boolean} [preventInit] + */ + var mockFactory = function(typeIdentifier, preventInit) { + var picMock = { + /** + * The component identifier + * @type {String|Number} + */ + id: -1, + + /** + * Gets the type of this component + * @returns {string} + */ + getTypeIdentifier: function () { + return typeIdentifier; + }, + + /** + * Initialize the PIC + * + * @param {String} id + * @param {Node} dom + * @param {Object} config - json + */ + initialize: function (id, dom, config) { + this.id = id; + this.dom = dom; + this.config = config || {}; + this.state = {}; + + var $container = $(dom); + + if (!preventInit) { + common.init($container, this.config); + } + }, + + /** + * Reverse operation performed by render() + * After this function is executed, only the initial naked markup remains + * Event listeners are removed and the state and the response are reset + */ + destroy: function () { + $(this.dom).remove(); + }, + + /** + * Restore the state of the interaction from the serializedState. + * + * @param {Object} serializedState - json format + */ + setSerializedState: function (serializedState) { + this.state = serializedState; + }, + + /** + * Get the current state of the interaction as a string. + * It enables saving the state for later usage. + * @returns {Object} json format + */ + getSerializedState: function () { + return this.state || {}; + } + }; + + qtiInfoControlContext.register(picMock); + }; + + /** + * Build a PIC module + * @param {String} moduleName + * @param {String} [typeIdentifier] + * @param {Boolean} [preventInit] + */ + var moduleFactory = function(moduleName, typeIdentifier, preventInit) { + define(moduleName, [], function() { + mockFactory(typeIdentifier || moduleName, preventInit); + }); + }; + + return { + pic : mockFactory, + module : moduleFactory + }; +}); diff --git a/test/runner/provider/test.html b/test/runner/provider/test.html new file mode 100644 index 00000000..e8d06cd8 --- /dev/null +++ b/test/runner/provider/test.html @@ -0,0 +1,36 @@ + + + + + QTI Item Runtime Provider Test + + + + +
    +
    +
    +
    + +
    + + diff --git a/test/runner/provider/test.js b/test/runner/provider/test.js new file mode 100644 index 00000000..1a10c324 --- /dev/null +++ b/test/runner/provider/test.js @@ -0,0 +1,526 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2014 (original work) Open Assessment Technlogies SA (under the project TAO-PRODUCT); + * + */ + +/** + * @author Bertrand Chevrier + */ +define([ + 'jquery', + 'lodash', + 'taoItems/runner/api/itemRunner', + 'taoQtiItem/runner/provider/qti', + 'taoQtiItem/portableElementRegistry/icRegistry', + 'json!taoQtiItem/test/samples/json/space-shuttle.json' +], function($, _, itemRunner, qtiRuntimeProvider, icRegistry, itemData) { + 'use strict'; + + var runner; + var containerId = 'item-container'; + + QUnit.module('Provider API'); + + QUnit.test('module', function(assert) { + assert.ok(typeof qtiRuntimeProvider !== 'undefined', 'The module exports something'); + assert.ok(typeof qtiRuntimeProvider === 'object', 'The module exports an object'); + assert.ok( + typeof qtiRuntimeProvider.init === 'function' || typeof qtiRuntimeProvider.render === 'function', + 'The provider expose an init or a render method' + ); + }); + + QUnit.module('Register the provider', { + afterEach: function(assert) { + itemRunner.providers = null; + } + }); + + QUnit.test('register the qti provider', function(assert) { + assert.expect(4); + + assert.ok(typeof itemRunner.providers === 'undefined', 'the runner has no providers'); + + itemRunner.register('qti', qtiRuntimeProvider); + + assert.ok(typeof itemRunner.providers === 'object', 'the runner has now providers'); + assert.ok(typeof itemRunner.providers.qti === 'object', 'the runner has now the qti providers'); + assert.equal(itemRunner.providers.qti, qtiRuntimeProvider, 'the runner has now the qti providers'); + }); + + QUnit.module('Provider init', { + afterEach: function(assert) { + itemRunner.providers = null; + } + }); + + QUnit.test('Item data loading', function(assert) { + var ready = assert.async(); + assert.expect(2); + + itemRunner.register('qti', qtiRuntimeProvider); + + itemRunner('qti', itemData) + .on('init', function() { + assert.ok(typeof this._item === 'object', 'The item data is loaded and mapped to an object'); + assert.ok(typeof this._item.bdy === 'object', 'The item contains a body object'); + + ready(); + }) + .init(); + }); + + QUnit.test('Loading wrong data', function(assert) { + var ready = assert.async(); + assert.expect(2); + + itemRunner.register('qti', qtiRuntimeProvider); + + itemRunner('qti', { foo: true }) + .on('error', function(message) { + assert.ok(true, 'The provider triggers an error event'); + assert.ok(typeof message === 'string', 'The error is a string'); + + ready(); + }) + .init(); + }); + + QUnit.module('Provider render', { + afterEach: function(assert) { + //Reset the provides + runner.clear(); + itemRunner.providers = null; + } + }); + + QUnit.test('Item rendering', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(3); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('render', function() { + assert.equal(container.children.length, 1, 'the container has children'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('Issue in rendering', function(assert) { + var ready = assert.async(); + var count = 0; + var container = document.getElementById(containerId); + + assert.expect(4); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('init', function() { + this._item.renderer = null; + this.render(container); + }) + .on('error', function(message) { + assert.ok(true, 'The provider triggers an error event'); + assert.ok(typeof message === 'string', 'The error is a string'); + if (count > 0) { + ready(); + } + count++; + }) + .init(); + }); + + QUnit.module('Provider clear', { + afterEach: function(assert) { + itemRunner.providers = null; + } + }); + + QUnit.test('Clear a rendered item', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(6); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + itemRunner.register('qti', qtiRuntimeProvider); + + itemRunner('qti', itemData) + .on('render', function() { + assert.equal(typeof this._item, 'object', 'the item instance is attached to the runner'); + assert.equal(container.children.length, 1, 'the container has children'); + + this.clear(); + }) + .on('clear', function() { + assert.equal(container.children.length, 0, 'the container children are removed'); + assert.equal(this._item, null, 'the item instance is also cleared'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('Clear a rendered item asynchronosuly', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(6); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + assert.equal(container.children.length, 0, 'the container has no children'); + + itemRunner.register('qti', qtiRuntimeProvider); + + itemRunner('qti', itemData) + .on('render', function() { + assert.equal(typeof this._item, 'object', 'the item instance is attached to the runner'); + assert.equal(container.children.length, 1, 'the container has children'); + + // Mock the getInteractions() method to return interaction with async clear step + this._item.getInteractions = function() { + return [ + { + clear: function() { + return new Promise(function(resolve) { + setTimeout(resolve, 10); + }); + } + } + ]; + }; + + this.clear(); + }) + .on('clear', function() { + assert.equal(container.children.length, 0, 'the container children are removed'); + assert.equal(this._item, null, 'the item instance is also cleared'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.module('Provider state', { + afterEach: function(assert) { + //Reset the provides + runner.clear(); + itemRunner.providers = null; + } + }); + + QUnit.test('default state structure', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(4); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('render', function() { + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response === 'object', 'the state contains the interaction response'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('get state after changes', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(12); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('error', function(e) { + assert.ok(false, 'Unexpected error : ' + e.message); + }) + .on('render', function() { + //Default state + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.equal(state.RESPONSE.response.base, null, 'the default state contains a null base'); + + //Change something + $('[data-identifier="Discovery"]', $(container)).click(); + + //Debugger; + + state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.identifier, 'Discovery', 'the contains the selected choice'); + + //Change something else + $('[data-identifier="Atlantis"]', $(container)).click(); + + state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.identifier, 'Atlantis', 'the contains the selected choice'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('set state', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(3); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('render', function() { + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Atlantis' } } } }); + + assert.ok( + $('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('set multiple states', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(8); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('render', function() { + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Atlantis' } } } }); + + assert.ok( + $('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + //Change something + $('[data-identifier="Discovery"]', $(container)).click(); + + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + assert.ok( + $('[data-identifier="Discovery"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + this.setState({ RESPONSE: { response: { base: { identifier: 'Challenger' } } } }); + + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + assert.ok( + !$('[data-identifier="Discovery"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + assert.ok( + $('[data-identifier="Challenger"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('listen state changes', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(10); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('statechange', function(state) { + assert.ok( + $('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is checked' + ); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.ok(typeof state.RESPONSE.response.base === 'object', 'the contains a base object'); + assert.equal(state.RESPONSE.response.base.identifier, 'Atlantis', 'the contains the selected choice'); + + ready(); + }) + .on('render', function() { + var state = this.getState(); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the interaction response identifier'); + assert.equal(state.RESPONSE.response.base, null, 'the default state contains a null base'); + + assert.ok( + !$('[data-identifier="Atlantis"] input', $(container)).prop('checked'), + 'The choice is not checked' + ); + + $('[data-identifier="Atlantis"]', $(container)).click(); + }) + .init() + .render(container); + }); + + QUnit.module('Provider responses', { + afterEach: function(assert) { + runner.clear(); + itemRunner.providers = null; + } + }); + + QUnit.test('no responses set', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(4); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('render', function() { + var responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base, null, 'the response contains a null base property'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.test('get responses after changes', function(assert) { + var ready = assert.async(); + var container = document.getElementById(containerId); + + assert.expect(7); + + assert.ok(container instanceof HTMLElement, 'the item container exists'); + + itemRunner.register('qti', qtiRuntimeProvider); + + runner = itemRunner('qti', itemData) + .on('render', function() { + var responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base, null, 'the response contains a null base property'); + + //The user set response + $('[data-identifier="Atlantis"]', $(container)).click(); + + responses = this.getResponses(); + + assert.ok(typeof responses === 'object', 'the response is an object'); + assert.ok( + typeof responses.RESPONSE === 'object', + 'the response contains the interaction response identifier' + ); + assert.equal(responses.RESPONSE.base.identifier, 'Atlantis', 'the response contains the set value'); + + ready(); + }) + .init() + .render(container); + }); + + QUnit.module('Provider PIC', { + beforeEach: function(assert) { + icRegistry.resetProviders(); + }, + afterEach: function(assert) { + runner.clear(); + itemRunner.providers = null; + icRegistry.resetProviders(); + } + }); +}); diff --git a/test/runner/qtiItemRunner/test.html b/test/runner/qtiItemRunner/test.html new file mode 100644 index 00000000..993930a4 --- /dev/null +++ b/test/runner/qtiItemRunner/test.html @@ -0,0 +1,24 @@ + + + + + QTI Item Runner Test + + + + +
    +
    +
    +
    + + diff --git a/test/runner/qtiItemRunner/test.js b/test/runner/qtiItemRunner/test.js new file mode 100644 index 00000000..fe606d2d --- /dev/null +++ b/test/runner/qtiItemRunner/test.js @@ -0,0 +1,26 @@ +define([ + + 'jquery', + 'lodash', + 'taoQtiItem/runner/qtiItemRunner', + 'json!taoQtiItem/test/samples/json/space-shuttle.json' +], function($, _, qtiItemRunner, itemData) { + + var containerId = 'item-container'; + + QUnit.module('Runner API'); + + QUnit.test('module', function(assert) { + assert.ok(typeof qtiItemRunner !== 'undefined', 'The module exports something'); + assert.ok(typeof qtiItemRunner === 'function', 'The module exports a function'); + }); + + QUnit.module('QTI Provider'); + + QUnit.test('provider registered', function(assert) { + assert.ok(typeof qtiItemRunner.providers !== 'undefined', 'The runner has providers'); + assert.ok(typeof qtiItemRunner.providers.qti !== 'undefined', 'The runner has a QTI provider'); + }); + +}); + diff --git a/test/samples/json/airports-tags.json b/test/samples/json/airports-tags.json new file mode 100644 index 00000000..25788b00 --- /dev/null +++ b/test/samples/json/airports-tags.json @@ -0,0 +1,315 @@ +{ + "identifier": "graphicGapfill", + "serial": "item_547dd6fb51df7350746356", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "graphicGapfill", + "title": "Airport Tags", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd6fb51dde189297394", + "body": "

    The International Air Transport Association assigns three-letter codes to identify\n\t\t\tairports worldwide. For example, London Heathrow has code LHR.

    \n {{interaction_graphicgapmatchinteraction_547dd6fb53c17021201802}}", + "elements": { + "interaction_graphicgapmatchinteraction_547dd6fb53c17021201802": { + "serial": "interaction_graphicgapmatchinteraction_547dd6fb53c17021201802", + "qtiClass": "graphicGapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE" + }, + "choices": { + "choice_associablehotspot_547dd6fb54a8a653063086": { + "identifier": "A", + "serial": "choice_associablehotspot_547dd6fb54a8a653063086", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "A", + "fixed": false, + "matchMax": 1, + "matchMin": 0, + "shape": "rect", + "coords": "12,108,39,121" + } + }, + "choice_associablehotspot_547dd6fb54b4c164428247": { + "identifier": "B", + "serial": "choice_associablehotspot_547dd6fb54b4c164428247", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "B", + "fixed": false, + "matchMax": 1, + "matchMin": 0, + "shape": "rect", + "coords": "128,103,155,126" + } + }, + "choice_associablehotspot_547dd6fb54ba1094618755": { + "identifier": "C", + "serial": "choice_associablehotspot_547dd6fb54ba1094618755", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "C", + "fixed": false, + "matchMax": 1, + "matchMin": 0, + "shape": "rect", + "coords": "66,165,93,178" + } + } + }, + "prompt": { + "serial": "container_containerstatic_547dd6fb53e6a437556529", + "body": "Some of the labels on the following diagram are missing: can you identify the\n\t\t\t\tcorrect three-letter codes for the unlabelled airports?", + "elements": [], + "debug": { + "relatedItem": "item_547dd6fb51df7350746356" + } + }, + "object": { + "serial": "object_547dd6fb54c08483199416", + "qtiClass": "object", + "attributes": { + "data": "images/ukairtags.png", + "type": "image/png", + "width": 206, + "height": 280 + } + }, + "gapImgs": { + "choice_gapimg_547dd6fb542be279257915": { + "identifier": "CBG", + "serial": "choice_gapimg_547dd6fb542be279257915", + "qtiClass": "gapImg", + "attributes": { + "identifier": "CBG", + "fixed": false, + "matchMax": "1" + }, + "object": { + "serial": "object_547dd6fb54578961495493", + "qtiClass": "object", + "attributes": { + "data": "images/CBG.png", + "type": "image/png", + "width": 20, + "height": 9 + }, + "_alt": "CBG" + } + }, + "choice_gapimg_547dd6fb5462c543193792": { + "identifier": "EBG", + "serial": "choice_gapimg_547dd6fb5462c543193792", + "qtiClass": "gapImg", + "attributes": { + "identifier": "EBG", + "fixed": false, + "matchMax": "1" + }, + "object": { + "serial": "object_547dd6fb54686327849583", + "qtiClass": "object", + "attributes": { + "data": "images/EBG.png", + "type": "image/png", + "width": 18, + "height": 9 + }, + "_alt": "EBG" + } + }, + "choice_gapimg_547dd6fb546fd560271021": { + "identifier": "EDI", + "serial": "choice_gapimg_547dd6fb546fd560271021", + "qtiClass": "gapImg", + "attributes": { + "identifier": "EDI", + "fixed": false, + "matchMax": "1" + }, + "object": { + "serial": "object_547dd6fb54755642489802", + "qtiClass": "object", + "attributes": { + "data": "images/EDI.png", + "type": "image/png", + "width": 14, + "height": 9 + }, + "_alt": "EDI" + } + }, + "choice_gapimg_547dd6fb547c9317819025": { + "identifier": "GLA", + "serial": "choice_gapimg_547dd6fb547c9317819025", + "qtiClass": "gapImg", + "attributes": { + "identifier": "GLA", + "fixed": false, + "matchMax": "1" + }, + "object": { + "serial": "object_547dd6fb5481d064597808", + "qtiClass": "object", + "attributes": { + "data": "images/GLA.png", + "type": "image/png", + "width": 17, + "height": 9 + }, + "_alt": "GLA" + } + }, + "choice_gapimg_547dd6fb5488f647796994": { + "identifier": "MAN", + "serial": "choice_gapimg_547dd6fb5488f647796994", + "qtiClass": "gapImg", + "attributes": { + "identifier": "MAN", + "fixed": false, + "matchMax": "1" + }, + "object": { + "serial": "object_547dd6fb548e2260770351", + "qtiClass": "object", + "attributes": { + "data": "images/MAN.png", + "type": "image/png", + "width": 21, + "height": 9 + }, + "_alt": "MAN" + } + }, + "choice_gapimg_547dd6fb54952611354381": { + "identifier": "MCH", + "serial": "choice_gapimg_547dd6fb54952611354381", + "qtiClass": "gapImg", + "attributes": { + "identifier": "MCH", + "fixed": false, + "matchMax": "1" + }, + "object": { + "serial": "object_547dd6fb549a4091507443", + "qtiClass": "object", + "attributes": { + "data": "images/MCH.png", + "type": "image/png", + "width": 22, + "height": 9 + }, + "_alt": "MCH" + } + } + } + } + }, + "debug": { + "relatedItem": "item_547dd6fb51df7350746356" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd6fb52617408465258": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd6fb52617408465258", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd6fb5208d219650630": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd6fb5208d219650630", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "correctResponses": [ + "GLA A", + "EDI B", + "MAN C" + ], + "mapping": { + "GLA A": "1", + "EDI B": "1", + "MAN C": "1" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": -1, + "lowerBound": "0" + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd6fb54dc4659379769", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } +} diff --git a/test/samples/json/airports.json b/test/samples/json/airports.json new file mode 100644 index 00000000..62a4f76b --- /dev/null +++ b/test/samples/json/airports.json @@ -0,0 +1,196 @@ +{ + "identifier": "hotspot", + "serial": "item_547dd7675fc72790128029", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "hotspot", + "title": "UK Airports (Take 1)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd7675fc5b795885077", + "body": "

    The picture illustrates four of the most popular destinations for air travellers arriving\n\t\t\tin the United Kingdom: London, Manchester, Edinburgh and Glasgow.

    \n {{interaction_hotspotinteraction_547dd76760ec1571962262}}", + "elements": { + "interaction_hotspotinteraction_547dd76760ec1571962262": { + "serial": "interaction_hotspotinteraction_547dd76760ec1571962262", + "qtiClass": "hotspotInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 1, + "minChoices": 0 + }, + "choices": { + "choice_hotspotchoice_547dd76761348200388715": { + "identifier": "A", + "serial": "choice_hotspotchoice_547dd76761348200388715", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "A", + "fixed": false, + "shape": "circle", + "coords": "77,115,8" + } + }, + "choice_hotspotchoice_547dd7676141d836502877": { + "identifier": "B", + "serial": "choice_hotspotchoice_547dd7676141d836502877", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "B", + "fixed": false, + "shape": "circle", + "coords": "118,184,8" + } + }, + "choice_hotspotchoice_547dd7676145b568812300": { + "identifier": "C", + "serial": "choice_hotspotchoice_547dd7676145b568812300", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "C", + "fixed": false, + "shape": "circle", + "coords": "150,235,8" + } + }, + "choice_hotspotchoice_547dd76761494167929323": { + "identifier": "D", + "serial": "choice_hotspotchoice_547dd76761494167929323", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "D", + "fixed": false, + "shape": "circle", + "coords": "96,114,8" + } + } + }, + "prompt": { + "serial": "container_containerstatic_547dd7676119f548179467", + "body": "Which one is Glasgow?", + "elements": [], + "debug": { + "relatedItem": "item_547dd7675fc72790128029" + } + }, + "object": { + "serial": "object_547dd767614dd836286343", + "qtiClass": "object", + "attributes": { + "data": "images/ukair.png", + "type": "image/png", + "width": 206, + "height": 280 + }, + "_alt": "UK Map" + } + } + }, + "debug": { + "relatedItem": "item_547dd7675fc72790128029" + } + }, + "namespaces": { + "": "http://www.imsglobal.org/xsd/imsqti_v2p1", + "xsi": "http://www.w3.org/2001/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd76760303339965052": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd76760303339965052", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd7675fed8737745796": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd7675fed8737745796", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "A" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd76761689992638661", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/characters.json b/test/samples/json/characters.json new file mode 100644 index 00000000..066cfada --- /dev/null +++ b/test/samples/json/characters.json @@ -0,0 +1,276 @@ +{ + "identifier": "match", + "serial": "item_547481b19675c725296684", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "match", + "title": "Characters and Plays", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547481b196742400134428", + "body": "{{interaction_matchinteraction_547481b197d23287450469}}", + "elements": { + "interaction_matchinteraction_547481b197d23287450469": { + "serial": "interaction_matchinteraction_547481b197d23287450469", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 4, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_547481b1980fe842580798", + "body": "Match the following characters to the Shakespeare play they appeared in:", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + }, + "choices": [{ + "choice_simpleassociablechoice_547481b198301862830282": { + "identifier": "C", + "serial": "choice_simpleassociablechoice_547481b198301862830282", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "C", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b1984ca957130034", + "body": "Capulet", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + }, + "choice_simpleassociablechoice_547481b1985e9014015123": { + "identifier": "D", + "serial": "choice_simpleassociablechoice_547481b1985e9014015123", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "D", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b19864c882047727", + "body": "Demetrius", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + }, + "choice_simpleassociablechoice_547481b198742482177856": { + "identifier": "L", + "serial": "choice_simpleassociablechoice_547481b198742482177856", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "L", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b1987a0199791197", + "body": "Lysander", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + }, + "choice_simpleassociablechoice_547481b19888a260388540": { + "identifier": "P", + "serial": "choice_simpleassociablechoice_547481b19888a260388540", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "P", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b1988e7086855540", + "body": "Prospero", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + } + }, { + "choice_simpleassociablechoice_547481b1989ee614159529": { + "identifier": "R", + "serial": "choice_simpleassociablechoice_547481b1989ee614159529", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "R", + "fixed": false, + "matchMax": 4, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b198a58375511408", + "body": "Romeo and Juliet", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + }, + "choice_simpleassociablechoice_547481b198b48089571446": { + "identifier": "M", + "serial": "choice_simpleassociablechoice_547481b198b48089571446", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "M", + "fixed": false, + "matchMax": 4, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b198ba1597191333", + "body": "A Midsummer-Night's Dream", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + }, + "choice_simpleassociablechoice_547481b198c8d000816227": { + "identifier": "T", + "serial": "choice_simpleassociablechoice_547481b198c8d000816227", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "T", + "fixed": false, + "matchMax": 4, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_547481b198ce6732960289", + "body": "The Tempest", + "elements": [], + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + } + } + }] + } + }, + "debug": { + "relatedItem": "item_547481b19675c725296684" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547481b196bb7821724948": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547481b196bb7821724948", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547481b196a31719500963": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547481b196a31719500963", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "correctResponses": [ + "C R", + "D M", + "L M", + "P T" + ], + "mapping": { + "C R": "1", + "D M": "0.5", + "L M": "0.5", + "P T": "1" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547481b199034063638270", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } +} diff --git a/test/samples/json/chocolate.json b/test/samples/json/chocolate.json new file mode 100644 index 00000000..ce2a8dda --- /dev/null +++ b/test/samples/json/chocolate.json @@ -0,0 +1,86 @@ +{ + "identifier": "upload", + "serial": "item_547dd8964dec1443421987", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "upload", + "title": "Chocolate Factory", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd8964deb0046274992", + "body": "

    A chocolate factory produces several types of chocolate, some of which have nut centres.\n The chocolates are mixed together and are randomly packed into cartons of ten.

    \n {{interaction_uploadinteraction_547dd8964f8af556377191}}", + "elements": { + "interaction_uploadinteraction_547dd8964f8af556377191": { + "serial": "interaction_uploadinteraction_547dd8964f8af556377191", + "qtiClass": "uploadInteraction", + "attributes": { + "responseIdentifier": "RESPONSE" + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_547dd8964fb1d729819370", + "body": "Build a spreadsheet to simulate 50 cartons of chocolates when each carton\n contains 10 chocolates, and when one-seventh of the chocolates have nut centres.\n Your spreadsheet should include 50 rows representing the 50 cartons, each row\n containing 10 columns to represent the chocolates.", + "elements": [], + "debug": { + "relatedItem": "item_547dd8964dec1443421987" + } + } + } + }, + "debug": { + "relatedItem": "item_547dd8964dec1443421987" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd8964e5fc752122714": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd8964e5fc752122714", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd8964e16b185243843": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd8964e16b185243843", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "file" + }, + "correctResponses": [], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_547dd8964fd04625229819", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "" + } +} diff --git a/test/samples/json/choice-custom.json b/test/samples/json/choice-custom.json new file mode 100644 index 00000000..6e4379a3 --- /dev/null +++ b/test/samples/json/choice-custom.json @@ -0,0 +1,468 @@ +{ + "identifier": "RC123413", + "serial": "item_5641f690083bd746318424", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "RC123413", + "title": "RC123413", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint12", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5641f6900839a280057995", + "body": "\n
    \n
    \n

    Question<\/h2>\n
    \n
    \n

    \n Sugar plum gummies lemon<\/strong>\n <\/h3>\n <\/div>\n
    \n

    Pie donut sweet jelly. Powder dessert cotton candy pie candy canes gummies gingerbread marshmallow pie.<\/p>\n <\/div>\n {{interaction_choiceinteraction_5641f69009a40825558139}}\n

    \n

    Fruitcake tiramisu sesame snaps apple pie apple pie tootsie roll tart tart toffee ?<\/span>\n <\/p>\n <\/div>\n {{interaction_choiceinteraction_5641f6900c582655102180}}\n <\/div>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_5641f69009a40825558139": { + "serial": "interaction_choiceinteraction_5641f69009a40825558139", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 1, + "minChoices": 1, + "orientation": "vertical", + "class": "at-enable" + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + }, + "choices": { + "choice_simplechoice_5641f6900a08e629980725": { + "identifier": "A", + "serial": "choice_simplechoice_5641f6900a08e629980725", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "A", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900a1d4325209031", + "body": "\n

    Wafer tart oat cake tart ice cream marzipan.<\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "choice_simplechoice_5641f6900ab20193935586": { + "identifier": "B", + "serial": "choice_simplechoice_5641f6900ab20193935586", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "B", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900ab66812115674", + "body": "\n

    (correct : +1) Topping tootsie roll halvah jelly liquorice. <\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "choice_simplechoice_5641f6900b3ea391149047": { + "identifier": "C", + "serial": "choice_simplechoice_5641f6900b3ea391149047", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "C", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900b42e363082844", + "body": "\n

    Tart oat cake jelly chocolate bar cheesecake candy bonbon.<\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "choice_simplechoice_5641f6900bc91624342632": { + "identifier": "D", + "serial": "choice_simplechoice_5641f6900bc91624342632", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "D", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900bce5427355728", + "body": "\n

    Ice cream wafer candy pie chocolate bar toffee. <\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5641f69009f24014960240", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + } + }, + "interaction_choiceinteraction_5641f6900c582655102180": { + "serial": "interaction_choiceinteraction_5641f6900c582655102180", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE2", + "shuffle": false, + "maxChoices": 1, + "minChoices": 1, + "orientation": "vertical", + "class": "at-enable" + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + }, + "choices": { + "choice_simplechoice_5641f6900c6af630554690": { + "identifier": "A2", + "serial": "choice_simplechoice_5641f6900c6af630554690", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "A2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900c6ef869969312", + "body": "\n

    \u201cCroissant oat cake candy canes chocolate bar.\u201d Gummi bears<\/span>\n <\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "choice_simplechoice_5641f6900ceab832836875": { + "identifier": "B2", + "serial": "choice_simplechoice_5641f6900ceab832836875", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "B2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900ceee387307258", + "body": "\n

    \u201cPudding gingerbread gummies. It apple pie jelly-o <\/span> sesame (apple pie)<\/span>\n <\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "choice_simplechoice_5641f6900d667324081403": { + "identifier": "C2", + "serial": "choice_simplechoice_5641f6900d667324081403", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "C2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900d6aa886743474", + "body": "\n

    \u201cJelly beans dessert chocolate cake carrot cake pudding chupa chups cotton candy halvah lollipop. .\u201d ( chupa chups)<\/span>\n <\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "choice_simplechoice_5641f6900de42691700779": { + "identifier": "D2", + "serial": "choice_simplechoice_5641f6900de42691700779", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "D2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_5641f6900de86202155678", + "body": "\n

    (correct : +1) \u201cDonut muffin gummies gingerbread bonbon. .\u201d (sugar plum)<\/span>\n <\/p>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5641f6900c678855219397", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + } + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + } + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xi": "http:\/\/www.w3.org\/2001\/XInclude", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_5641f69009282133684581": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5641f69009282133684581", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float", + "normalMaximum": 2, + "normalMinimum": 0 + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_5641f69008d97604648546": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5641f69008d97604648546", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + }, + "correctResponses": [ + "B" + ], + "mapping": { + "A": "-1.0", + "B": "1.0", + "C": "-1.0", + "D": "-1.0" + }, + "areaMapping": [ + ], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_5641f690090e0029667799": { + "identifier": "RESPONSE2", + "serial": "responsedeclaration_5641f690090e0029667799", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE2", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5641f690083bd746318424" + }, + "correctResponses": [ + "D2" + ], + "mapping": { + "A2": "-1.0", + "B2": "-1.0", + "C2": "-1.0", + "D2": "1.0" + }, + "areaMapping": [ + ], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_custom_5641f6900f1aa829038713", + "qtiClass": "responseProcessing", + "attributes": [ + ], + "debug": { + "relatedItem": "" + }, + "processingType": "custom", + "data": "\n \n \n \n \n \n 1<\/baseValue>\n <\/equal>\n <\/not>\n \n 0.0<\/baseValue>\n <\/setOutcomeValue>\n <\/responseIf>\n \n \n \n \n 1.0<\/baseValue>\n <\/sum>\n <\/setOutcomeValue>\n \n \n \n \n 1<\/baseValue>\n <\/equal>\n \n \n \n 1.0<\/baseValue>\n <\/sum>\n <\/setOutcomeValue>\n <\/responseIf>\n <\/responseCondition>\n <\/responseElse>\n <\/responseCondition>\n <\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1.0" + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE2" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1.0" + } + ] + } + } + ] + } + } + ] + } + } + ] + } +} diff --git a/test/samples/json/choice-feedback-complex.json b/test/samples/json/choice-feedback-complex.json new file mode 100644 index 00000000..df45e0db --- /dev/null +++ b/test/samples/json/choice-feedback-complex.json @@ -0,0 +1,418 @@ +{ + "identifier": "i14474112607310141", + "serial": "item_5645e03ff26bd406036269", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14474112607310141", + "title": "Item 15", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint12", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5645e03ff269d998927873", + "body": "\n\t\t

    \n\t\t\t
    \n\t\t\t\t{{interaction_choiceinteraction_5645e04000930591648397}}\n\t\t\t<\/div>\n\t\t<\/div>\n\t", + "elements": { + "interaction_choiceinteraction_5645e04000930591648397": { + "serial": "interaction_choiceinteraction_5645e04000930591648397", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "choices": { + "choice_simplechoice_5645e040012ff888285719": { + "identifier": "choice_1", + "serial": "choice_simplechoice_5645e040012ff888285719", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5645e04001423019002740", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "choice_simplechoice_5645e04001902542430593": { + "identifier": "choice_2", + "serial": "choice_simplechoice_5645e04001902542430593", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5645e04001952673174733", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "choice_simplechoice_5645e04001e10878741590": { + "identifier": "choice_3", + "serial": "choice_simplechoice_5645e04001e10878741590", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5645e04001e5f343227103", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5645e04000cb2348703415", + "body": "Question ?", + "elements": {}, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + } + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_5645e03ff2cd7438307389": { + "serial": "stylesheet_5645e03ff2cd7438307389", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + } + }, + "outcomes": { + "outcomedeclaration_5645e03ff3412404382828": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5645e03ff3412404382828", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "defaultValue": null + }, + "outcomedeclaration_5645e03ff36d7566461815": { + "identifier": "FEEDBACK_1", + "serial": "outcomedeclaration_5645e03ff36d7566461815", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_1", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "defaultValue": null + }, + "outcomedeclaration_5645e03ff3753918032313": { + "identifier": "FEEDBACK_2", + "serial": "outcomedeclaration_5645e03ff3753918032313", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_2", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5645e03ff3175000255943": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5645e03ff3175000255943", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "correctResponses": [ + "\n\t\t\t\tchoice_1\n\t\t\t" + ], + "mapping": [ + ], + "areaMapping": [ + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": { + "response_simplefeedbackrule_5645e04002d63322457766": { + "serial": "response_simplefeedbackrule_5645e04002d63322457766", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5645e03ff3175000255943", + "comparedValue": 0, + "condition": "incorrect", + "feedbackOutcome": "outcomedeclaration_5645e03ff36d7566461815", + "feedbackThen": "feedback_modalfeedback_5645e03ff3c84902893881", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5645e04002e57534107364": { + "serial": "response_simplefeedbackrule_5645e04002e57534107364", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5645e03ff3175000255943", + "comparedValue": "0", + "condition": "gt", + "feedbackOutcome": "outcomedeclaration_5645e03ff3753918032313", + "feedbackThen": "feedback_modalfeedback_5645e040000df565348032", + "feedbackElse": "" + } + } + } + }, + "feedbacks": { + "feedback_modalfeedback_5645e03ff3c84902893881": { + "identifier": "feedbackModal_1", + "serial": "feedback_modalfeedback_5645e03ff3c84902893881", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_1", + "outcomeIdentifier": "FEEDBACK_1", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5645e03ff3d42464390374", + "body": "Wrong", + "elements": {}, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "feedback_modalfeedback_5645e040000df565348032": { + "identifier": "feedbackModal_2", + "serial": "feedback_modalfeedback_5645e040000df565348032", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_2", + "outcomeIdentifier": "FEEDBACK_2", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5645e040001cb321222804", + "body": "Good", + "elements": {}, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + }, + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + } + } + }, + "responseProcessing": { + "serial": "response_templatesdriven_5645e040030c9591056222", + "qtiClass": "responseProcessing", + "attributes": [ + ], + "debug": { + "relatedItem": "item_5645e03ff26bd406036269" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_1" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "gt", + "expressions": [ + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_2" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_2" + } + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/choice-feedback.json b/test/samples/json/choice-feedback.json new file mode 100644 index 00000000..ae6f3a67 --- /dev/null +++ b/test/samples/json/choice-feedback.json @@ -0,0 +1,368 @@ +{ + "identifier": "i14474112607310141", + "serial": "item_5645db8ae1f6a946379475", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14474112607310141", + "title": "Item 13", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint12", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5645db8ae1f4a523430469", + "body": "\n\t\t
    \n\t\t\t
    \n\t\t\t\t{{interaction_choiceinteraction_5645db8ae43b8038570385}}\n\t\t\t<\/div>\n\t\t<\/div>\n\t", + "elements": { + "interaction_choiceinteraction_5645db8ae43b8038570385": { + "serial": "interaction_choiceinteraction_5645db8ae43b8038570385", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + }, + "choices": { + "choice_simplechoice_5645db8ae4d33424482475": { + "identifier": "choice_1", + "serial": "choice_simplechoice_5645db8ae4d33424482475", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5645db8ae4e61487810800", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "choice_simplechoice_5645db8ae52de667810589": { + "identifier": "choice_2", + "serial": "choice_simplechoice_5645db8ae52de667810589", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5645db8ae532f116878251", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "choice_simplechoice_5645db8ae577d969254917": { + "identifier": "choice_3", + "serial": "choice_simplechoice_5645db8ae577d969254917", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5645db8ae57cd046801580", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5645db8ae473d939594884", + "body": "Question ?", + "elements": {}, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + } + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + "stylesheet_5645db8ae258f449580917": { + "serial": "stylesheet_5645db8ae258f449580917", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + } + }, + "outcomes": { + "outcomedeclaration_5645db8ae2e02379737646": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5645db8ae2e02379737646", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + }, + "defaultValue": null + }, + "outcomedeclaration_5645db8ae30d0317283814": { + "identifier": "FEEDBACK_1", + "serial": "outcomedeclaration_5645db8ae30d0317283814", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_1", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5645db8ae2b66137166014": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5645db8ae2b66137166014", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + }, + "correctResponses": [ + "\n\t\t\t\tchoice_1\n\t\t\t" + ], + "mapping": [ + ], + "areaMapping": [ + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": { + "response_simplefeedbackrule_5645db8ae6626240360736": { + "serial": "response_simplefeedbackrule_5645db8ae6626240360736", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5645db8ae2b66137166014", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5645db8ae30d0317283814", + "feedbackThen": "feedback_modalfeedback_5645db8ae3563806222083", + "feedbackElse": "feedback_modalfeedback_5645db8ae3bf4610963918" + } + } + } + }, + "feedbacks": { + "feedback_modalfeedback_5645db8ae3563806222083": { + "identifier": "feedbackModal_1", + "serial": "feedback_modalfeedback_5645db8ae3563806222083", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_1", + "outcomeIdentifier": "FEEDBACK_1", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5645db8ae3614345367588", + "body": "Right", + "elements": {}, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "feedback_modalfeedback_5645db8ae3bf4610963918": { + "identifier": "feedbackModal_2", + "serial": "feedback_modalfeedback_5645db8ae3bf4610963918", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_2", + "outcomeIdentifier": "FEEDBACK_1", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5645db8ae3ca8767487724", + "body": "Wrong", + "elements": {}, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + }, + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + } + } + }, + "responseProcessing": { + "serial": "response_templatesdriven_5645db8ae6834040329470", + "qtiClass": "responseProcessing", + "attributes": [ + ], + "debug": { + "relatedItem": "item_5645db8ae1f6a946379475" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_2" + } + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/customrp/Choicemultiple_2014410822.json b/test/samples/json/customrp/Choicemultiple_2014410822.json new file mode 100644 index 00000000..c57a0867 --- /dev/null +++ b/test/samples/json/customrp/Choicemultiple_2014410822.json @@ -0,0 +1,321 @@ +{ + "identifier": "Choicemultiple_2014410822", + "serial": "item_54eee7e293dec834786872", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Choicemultiple_2014410822", + "title": "choice (multiple)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e293dca711004067", + "body": "
    Welche St\u00e4dte verf\u00fcgen nicht<\/b> \u00fcber einen Internationalen Flughafen?<\/div>\n\t\t{{interaction_choiceinteraction_54eee7e29587e008835740}}", + "elements": { + "interaction_choiceinteraction_54eee7e29587e008835740": { + "serial": "interaction_choiceinteraction_54eee7e29587e008835740", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_13390220", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0 + }, + "choices": { + "choice_simplechoice_54eee7e295f0e149379540": { + "identifier": "choice_998819535", + "serial": "choice_simplechoice_54eee7e295f0e149379540", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_998819535", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e296084479999718", + "body": "Leipzig", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e293dec834786872" + } + } + }, + "choice_simplechoice_54eee7e296174656152767": { + "identifier": "choice_693643701", + "serial": "choice_simplechoice_54eee7e296174656152767", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_693643701", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e2961b8330325074", + "body": "Chemnitz", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e293dec834786872" + } + } + }, + "choice_simplechoice_54eee7e29627c456578906": { + "identifier": "choice_1658152974", + "serial": "choice_simplechoice_54eee7e29627c456578906", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1658152974", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e2962be388438612", + "body": "Dresden", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e293dec834786872" + } + } + }, + "choice_simplechoice_54eee7e296382435739685": { + "identifier": "choice_853818748", + "serial": "choice_simplechoice_54eee7e296382435739685", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_853818748", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e2963d2942480168", + "body": "Zwickau", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e293dec834786872" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54eee7e295d49495402105", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e293dec834786872" + } + } + } + }, + "debug": { + "relatedItem": "item_54eee7e293dec834786872" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e294d80799248410": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e294d80799248410", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e295133639495498": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e295133639495498", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e2951dd803849934": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e2951dd803849934", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e295281517864135": { + "identifier": "FEEDBACK_32452563", + "serial": "outcomedeclaration_54eee7e295281517864135", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_32452563", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e29534a134313274": { + "identifier": "FEEDBACK_12539715", + "serial": "outcomedeclaration_54eee7e29534a134313274", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_12539715", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e294a80959346863": { + "identifier": "RESPONSE_13390220", + "serial": "responsedeclaration_54eee7e294a80959346863", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_13390220", + "cardinality": "multiple", + "baseType": "identifier" + }, + "correctResponses": [ + "choice_693643701", + "choice_853818748" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e296c2c499331606", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_13390220" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIfs": [{ + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_13390220" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_13390220" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }], + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/Choicemultiple_871212949.json b/test/samples/json/customrp/Choicemultiple_871212949.json new file mode 100644 index 00000000..d086cdd8 --- /dev/null +++ b/test/samples/json/customrp/Choicemultiple_871212949.json @@ -0,0 +1,654 @@ +{ + "identifier": "Choicemultiple_871212949", + "serial": "item_54fd4c4a4ff94909004775", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Choicemultiple_871212949", + "title": "choice (multiple, point per answer)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54fd4c4a4ff5c508220978", + "body": "
    \n\t\tWelche Naturr\u00e4ume finden sich im Freistaat Sachsen?\n\t\t<\/div>\n\t\t{{interaction_choiceinteraction_54fd4c4a56c54049364130}}", + "elements": { + "interaction_choiceinteraction_54fd4c4a56c54049364130": { + "serial": "interaction_choiceinteraction_54fd4c4a56c54049364130", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_27966883", + "shuffle": true, + "maxChoices": 0, + "minChoices": 0 + }, + "choices": { + "choice_simplechoice_54fd4c4a58d7c687477684": { + "identifier": "choice_934383202", + "serial": "choice_simplechoice_54fd4c4a58d7c687477684", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_934383202", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a595d5472846889", + "body": "Erzgebirge", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a5973d210081507": { + "identifier": "choice_2022864592", + "serial": "choice_simplechoice_54fd4c4a5973d210081507", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2022864592", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a5979e381036513", + "body": "Lausitz", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a59885697450564": { + "identifier": "choice_1534527094", + "serial": "choice_simplechoice_54fd4c4a59885697450564", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1534527094", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a598d6015267070", + "body": "Vogtland", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a599b6341083202": { + "identifier": "choice_921260236", + "serial": "choice_simplechoice_54fd4c4a599b6341083202", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_921260236", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a59a04237231882", + "body": "Harz", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + }, + "choice_simplechoice_54fd4c4a59ae5054348153": { + "identifier": "choice_1757121272", + "serial": "choice_simplechoice_54fd4c4a59ae5054348153", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1757121272", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd4c4a59b34934662454", + "body": "Alpen", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54fd4c4a58505021948896", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + } + } + }, + "debug": { + "relatedItem": "item_54fd4c4a4ff94909004775" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54fd4c4a540a3718842863": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54fd4c4a540a3718842863", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54fd4c4a553c3771081613": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54fd4c4a553c3771081613", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "3.0" + }, + "outcomedeclaration_54fd4c4a554ad612900133": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54fd4c4a554ad612900133", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54fd4c4a55584224333269": { + "identifier": "FEEDBACK_5714028", + "serial": "outcomedeclaration_54fd4c4a55584224333269", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_5714028", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a556a8142933374": { + "identifier": "FEEDBACK_8958131", + "serial": "outcomedeclaration_54fd4c4a556a8142933374", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_8958131", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a557c3758485518": { + "identifier": "FEEDBACK_1634627", + "serial": "outcomedeclaration_54fd4c4a557c3758485518", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_1634627", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a558c9451328046": { + "identifier": "FEEDBACK_20327592", + "serial": "outcomedeclaration_54fd4c4a558c9451328046", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_20327592", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a559c2463027304": { + "identifier": "FEEDBACK_5765523", + "serial": "outcomedeclaration_54fd4c4a559c2463027304", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_5765523", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a55ab8116211309": { + "identifier": "FEEDBACK_15433735", + "serial": "outcomedeclaration_54fd4c4a55ab8116211309", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_15433735", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd4c4a55bac167900885": { + "identifier": "FEEDBACK_21035203", + "serial": "outcomedeclaration_54fd4c4a55bac167900885", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_21035203", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54fd4c4a52da4633936855": { + "identifier": "RESPONSE_27966883", + "serial": "responsedeclaration_54fd4c4a52da4633936855", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_27966883", + "cardinality": "multiple", + "baseType": "identifier" + }, + "correctResponses": [ + "choice_934383202", + "choice_2022864592", + "choice_1534527094" + ], + "mapping": { + "choice_934383202": "1.0", + "choice_2022864592": "1.0", + "choice_1534527094": "1.0", + "choice_921260236": "-1.0", + "choice_1757121272": "-2.0" + }, + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54fd4c4a5b556422874833", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t\t\t<\/match>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/equal>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tchoice_2022864592<\/baseValue>\n\t\t\t\t\t\t\n\t\t\t\t\t<\/member>\n\t\t\t\t<\/not>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tchoice_934383202<\/baseValue>\n\t\t\t\t\t\t\n\t\t\t\t\t<\/member>\n\t\t\t\t<\/not>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tchoice_1534527094<\/baseValue>\n\t\t\t\t\t\t\n\t\t\t\t\t<\/member>\n\t\t\t\t<\/not>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_921260236<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/member>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_1757121272<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/member>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + ] + } + ] + }, + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_5714028" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_8958131" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1634627" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_2022864592" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_20327592" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_934383202" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_5765523" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_1534527094" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_15433735" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_921260236" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_21035203" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "member", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_1757121272" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27966883" + } + } + ] + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/customrp/Choicesingle_853928446.json b/test/samples/json/customrp/Choicesingle_853928446.json new file mode 100644 index 00000000..0ea50ce2 --- /dev/null +++ b/test/samples/json/customrp/Choicesingle_853928446.json @@ -0,0 +1,543 @@ +{ + "identifier": "Choicesingle_853928446", + "serial": "item_54eee7e3805d2784784133", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Choicesingle_853928446", + "title": "choice (single)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e3805b3131143517", + "body": "
    Das Bundesland Sachsen hat die folgende Flagge...<\/div>\n\t\t{{interaction_choiceinteraction_54eee7e38108f147645516}}", + "elements": { + "interaction_choiceinteraction_54eee7e38108f147645516": { + "serial": "interaction_choiceinteraction_54eee7e38108f147645516", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_30705996", + "shuffle": true, + "maxChoices": 1, + "minChoices": 0 + }, + "choices": { + "choice_simplechoice_54eee7e381276828751971": { + "identifier": "choice_685440446", + "serial": "choice_simplechoice_54eee7e381276828751971", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_685440446", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e3812be148258442", + "body": "{{img_54eee7e3813cc466081550}}", + "elements": { + "img_54eee7e3813cc466081550": { + "serial": "img_54eee7e3813cc466081550", + "qtiClass": "img", + "attributes": { + "src": "media\/3d92a0b7b7be4480a582f62ce823d908.jpg", + "alt": "flag" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e3805d2784784133" + } + } + }, + "choice_simplechoice_54eee7e3816b9043141084": { + "identifier": "choice_1542121788", + "serial": "choice_simplechoice_54eee7e3816b9043141084", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1542121788", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e3816fd981700789", + "body": "{{img_54eee7e381753941064532}}", + "elements": { + "img_54eee7e381753941064532": { + "serial": "img_54eee7e381753941064532", + "qtiClass": "img", + "attributes": { + "src": "media\/65fe9d73f0b24800ab836b3bf6973639.jpg", + "alt": "flag" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e3805d2784784133" + } + } + }, + "choice_simplechoice_54eee7e381879241657364": { + "identifier": "choice_313388598", + "serial": "choice_simplechoice_54eee7e381879241657364", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_313388598", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e3818bb998185165", + "body": "{{img_54eee7e381901688228506}}", + "elements": { + "img_54eee7e381901688228506": { + "serial": "img_54eee7e381901688228506", + "qtiClass": "img", + "attributes": { + "src": "media\/d9a879873c1f44c7ad0428278ebdcd10.jpg", + "alt": "flag" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e3805d2784784133" + } + } + }, + "choice_simplechoice_54eee7e381a28405018704": { + "identifier": "choice_2057964872", + "serial": "choice_simplechoice_54eee7e381a28405018704", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2057964872", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e381a69118501295", + "body": "{{img_54eee7e381aae917464933}}", + "elements": { + "img_54eee7e381aae917464933": { + "serial": "img_54eee7e381aae917464933", + "qtiClass": "img", + "attributes": { + "src": "media\/90e3978ab9fd44a1838f6fc9a8a02d30.jpg", + "alt": "flag" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e3805d2784784133" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54eee7e381201933090908", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e3805d2784784133" + } + } + } + }, + "debug": { + "relatedItem": "item_54eee7e3805d2784784133" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e38083a313262514": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e38083a313262514", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e3808f2223713853": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e3808f2223713853", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e380992045513092": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e380992045513092", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e380a30086595650": { + "identifier": "FEEDBACK_12552501", + "serial": "outcomedeclaration_54eee7e380a30086595650", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_12552501", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e380afb156020702": { + "identifier": "FEEDBACK_17794055", + "serial": "outcomedeclaration_54eee7e380afb156020702", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_17794055", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e380bb8210560045": { + "identifier": "FEEDBACK_31451854", + "serial": "outcomedeclaration_54eee7e380bb8210560045", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_31451854", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e380c74824837381": { + "identifier": "FEEDBACK_21527026", + "serial": "outcomedeclaration_54eee7e380c74824837381", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_21527026", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e380d75468450571": { + "identifier": "FEEDBACK_25663374", + "serial": "outcomedeclaration_54eee7e380d75468450571", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_25663374", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e38076b372668805": { + "identifier": "RESPONSE_30705996", + "serial": "responsedeclaration_54eee7e38076b372668805", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_30705996", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "choice_685440446" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e381f9e675073896", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_1542121788<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_313388598<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tchoice_2057964872<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_30705996" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIf": { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_30705996" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_30705996" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_12552501" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_17794055" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_31451854" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_1542121788" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_30705996" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_21527026" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_313388598" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_30705996" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_25663374" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "choice_2057964872" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_30705996" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/Choicetruefalse_176040516.json b/test/samples/json/customrp/Choicetruefalse_176040516.json new file mode 100644 index 00000000..6f7fd5e9 --- /dev/null +++ b/test/samples/json/customrp/Choicetruefalse_176040516.json @@ -0,0 +1,344 @@ +{ + "identifier": "Choicetruefalse_176040516", + "serial": "item_54eee7e3f0cdb623928305", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Choicetruefalse_176040516", + "title": "choice (true-false)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e3f0cba295551275", + "body": "
    \n\t\tDas Bundesland Sachsen ist eines der neuen Bundesl\u00e4nder und geh\u00f6rte damit zur\u00a0ehemaligen Deutschen Demokratischen Republik (DDR).\n\t\t<\/div>\n\t\t{{interaction_choiceinteraction_54eee7e3f1464077289601}}", + "elements": { + "interaction_choiceinteraction_54eee7e3f1464077289601": { + "serial": "interaction_choiceinteraction_54eee7e3f1464077289601", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_27628688", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0 + }, + "choices": { + "choice_simplechoice_54eee7e3f15dc367396896": { + "identifier": "choice_1164834606", + "serial": "choice_simplechoice_54eee7e3f15dc367396896", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1164834606", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e3f1626033860330", + "body": "Richtig", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e3f0cdb623928305" + } + } + }, + "choice_simplechoice_54eee7e3f16eb885260974": { + "identifier": "choice_1416143937", + "serial": "choice_simplechoice_54eee7e3f16eb885260974", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1416143937", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e3f1729328606473", + "body": "Falsch", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e3f0cdb623928305" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54eee7e3f1598046109415", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e3f0cdb623928305" + } + } + } + }, + "debug": { + "relatedItem": "item_54eee7e3f0cdb623928305" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e3f0f40544431816": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e3f0f40544431816", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e3f0ff8891192944": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e3f0ff8891192944", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e3f1097738126784": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e3f1097738126784", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e3f1134236176880": { + "identifier": "FEEDBACK_10516488", + "serial": "outcomedeclaration_54eee7e3f1134236176880", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_10516488", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e3f1201191289690": { + "identifier": "FEEDBACK_10171297", + "serial": "outcomedeclaration_54eee7e3f1201191289690", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_10171297", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e3f0e73905405954": { + "identifier": "RESPONSE_27628688", + "serial": "responsedeclaration_54eee7e3f0e73905405954", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_27628688", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "choice_1164834606" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e3f1fb2345286877", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27628688" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIf": { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_27628688" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_27628688" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_10516488" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_10171297" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/Hotspot_278940407.json b/test/samples/json/customrp/Hotspot_278940407.json new file mode 100644 index 00000000..433e1998 --- /dev/null +++ b/test/samples/json/customrp/Hotspot_278940407.json @@ -0,0 +1,449 @@ +{ + "identifier": "Hotspot_278940407", + "serial": "item_54eee7e46c5cd351482190", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Hotspot_278940407", + "title": "hotspot", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e46c5ab420910784", + "body": "
    Dresden ist die Landeshauptstadt des Freistaates Sachsen. \n\t\tW\u00e4hle die Stadt Dresden in der gezeigten Skizze des Bundeslandes aus.<\/div>\n\t\t{{interaction_hotspotinteraction_54eee7e46cf9c427112900}}", + "elements": { + "interaction_hotspotinteraction_54eee7e46cf9c427112900": { + "serial": "interaction_hotspotinteraction_54eee7e46cf9c427112900", + "qtiClass": "hotspotInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 1, + "minChoices": 0 + }, + "choices": { + "choice_hotspotchoice_54eee7e46d3ae995242045": { + "identifier": "Choice0", + "serial": "choice_hotspotchoice_54eee7e46d3ae995242045", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice0", + "fixed": false, + "shape": "circle", + "coords": "141,28,12" + } + }, + "choice_hotspotchoice_54eee7e46d485091611562": { + "identifier": "Choice1", + "serial": "choice_hotspotchoice_54eee7e46d485091611562", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice1", + "fixed": false, + "shape": "circle", + "coords": "60,77,12" + } + }, + "choice_hotspotchoice_54eee7e46d521418365821": { + "identifier": "Choice2", + "serial": "choice_hotspotchoice_54eee7e46d521418365821", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice2", + "fixed": false, + "shape": "circle", + "coords": "82,119,12" + } + }, + "choice_hotspotchoice_54eee7e46d5ba601219844": { + "identifier": "Choice3", + "serial": "choice_hotspotchoice_54eee7e46d5ba601219844", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice3", + "fixed": false, + "shape": "circle", + "coords": "206,112,12" + } + }, + "choice_hotspotchoice_54eee7e46d686852514676": { + "identifier": "Choice4", + "serial": "choice_hotspotchoice_54eee7e46d686852514676", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice4", + "fixed": false, + "shape": "circle", + "coords": "131,181,12" + } + }, + "choice_hotspotchoice_54eee7e46d729237145138": { + "identifier": "Choice5", + "serial": "choice_hotspotchoice_54eee7e46d729237145138", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice5", + "fixed": false, + "shape": "circle", + "coords": "183,160,12" + } + }, + "choice_hotspotchoice_54eee7e46d7ce936401603": { + "identifier": "Choice6", + "serial": "choice_hotspotchoice_54eee7e46d7ce936401603", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice6", + "fixed": false, + "shape": "circle", + "coords": "239,129,12" + } + }, + "choice_hotspotchoice_54eee7e46d864536862331": { + "identifier": "Choice7", + "serial": "choice_hotspotchoice_54eee7e46d864536862331", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice7", + "fixed": false, + "shape": "circle", + "coords": "79,199,12" + } + }, + "choice_hotspotchoice_54eee7e46d8f7105574103": { + "identifier": "Choice8", + "serial": "choice_hotspotchoice_54eee7e46d8f7105574103", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice8", + "fixed": false, + "shape": "circle", + "coords": "315,103,12" + } + }, + "choice_hotspotchoice_54eee7e46d98a970046203": { + "identifier": "Choice9", + "serial": "choice_hotspotchoice_54eee7e46d98a970046203", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice9", + "fixed": false, + "shape": "circle", + "coords": "387,109,12" + } + }, + "choice_hotspotchoice_54eee7e46da1e936640860": { + "identifier": "Choice10", + "serial": "choice_hotspotchoice_54eee7e46da1e936640860", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice10", + "fixed": false, + "shape": "circle", + "coords": "143,230,12" + } + }, + "choice_hotspotchoice_54eee7e46dab3940543797": { + "identifier": "Choice11", + "serial": "choice_hotspotchoice_54eee7e46dab3940543797", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "Choice11", + "fixed": false, + "shape": "circle", + "coords": "36,244,12" + } + } + }, + "prompt": { + "serial": "container_containerstatic_54eee7e46d0a3962357940", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e46c5cd351482190" + } + }, + "object": { + "serial": "object_54eee7e46db5b057009586", + "qtiClass": "object", + "attributes": { + "data": "media\/735c5df9735b455e9bd4b366ab37d908.jpg", + "type": "image\/jpg" + } + } + } + }, + "debug": { + "relatedItem": "item_54eee7e46c5cd351482190" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e46c86f520399810": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e46c86f520399810", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e46c92e932204690": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e46c92e932204690", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e46c9d1093650477": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e46c9d1093650477", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e46ca72493477069": { + "identifier": "FEEDBACK_25412685", + "serial": "outcomedeclaration_54eee7e46ca72493477069", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_25412685", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e46cb3c083061233": { + "identifier": "FEEDBACK_29642729", + "serial": "outcomedeclaration_54eee7e46cb3c083061233", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_29642729", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e46c79d934804408": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54eee7e46c79d934804408", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "Choice6" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e46dffa783686154", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIf": { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_25412685" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_29642729" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/Hottext_801974120.json b/test/samples/json/customrp/Hottext_801974120.json new file mode 100644 index 00000000..3c0c2d76 --- /dev/null +++ b/test/samples/json/customrp/Hottext_801974120.json @@ -0,0 +1,471 @@ +{ + "identifier": "Hottext_801974120", + "serial": "item_54eee7e4dcf12993796022", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Hottext_801974120", + "title": "hottext", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e4dcef2906032621", + "body": "

    Geburtenrate in Sachsen<\/p>\n\t\t

    \n\t\t\tSind die Fakten alle korrekt? \n\t\t\tSuche drei Fehler!<\/i>\n\t\t<\/p>\n\t\t{{interaction_hottextinteraction_54eee7e4dd86e073557270}}", + "elements": { + "interaction_hottextinteraction_54eee7e4dd86e073557270": { + "serial": "interaction_hottextinteraction_54eee7e4dd86e073557270", + "qtiClass": "hottextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 0, + "minChoices": 0 + }, + "body": { + "serial": "container_containerhottext_54eee7e4dda20513507611", + "body": "

    Die Bev\u00f6lkerungszahl Sachsens ist seit ca. {{choice_hottext_54eee7e4ddac5259060524}} r\u00fcckl\u00e4ufig. Hatte Sachsen Anfang 1990 noch {{choice_hottext_54eee7e4ddbf3647387819}}, waren es Ende 2008 nur noch ann\u00e4hernd 4,2 Millionen. F\u00fcr das Jahr 2020 wird ein R\u00fcckgang der Einwohnerzahlen auf etwa {{choice_hottext_54eee7e4ddcc6211116372}} prognostiziert. Einzig die Einwohnerzahlen der St\u00e4dte {{choice_hottext_54eee7e4ddd84566565122}}, {{choice_hottext_54eee7e4dde3d485973987}} und {{choice_hottext_54eee7e4ddef4009720200}} konnten in den vergangenen Jahren Zuw\u00e4chse verzeichnen.\n\t\t\t\tParallel zur Verringerung der Einwohnerzahl im Freistatt Sachsen stieg das Durchschnittsalter von {{choice_hottext_54eee7e4ddfaa971564590}} 1990 auf fast {{choice_hottext_54eee7e4de05f574048504}} im Jahr 2008. Im Jahr 2020 wird der \u00bbDurchschnittssachse\u00ab fast {{choice_hottext_54eee7e4de110895741601}} alt sein.<\/div>", + "elements": { + "choice_hottext_54eee7e4ddac5259060524": { + "identifier": "Choice0", + "serial": "choice_hottext_54eee7e4ddac5259060524", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice0", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4ddb4f367066864", + "body": "1950", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4ddbf3647387819": { + "identifier": "Choice1", + "serial": "choice_hottext_54eee7e4ddbf3647387819", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice1", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4ddc35904615782", + "body": "5,7 Millionen Einwohner", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4ddcc6211116372": { + "identifier": "Choice2", + "serial": "choice_hottext_54eee7e4ddcc6211116372", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4ddd06600341151", + "body": "3,9 Millionen", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4ddd84566565122": { + "identifier": "Choice3", + "serial": "choice_hottext_54eee7e4ddd84566565122", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice3", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4dddc3627583022", + "body": "Chemnitz", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4dde3d485973987": { + "identifier": "Choice4", + "serial": "choice_hottext_54eee7e4dde3d485973987", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice4", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4dde7b208943715", + "body": "Dresden", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4ddef4009720200": { + "identifier": "Choice5", + "serial": "choice_hottext_54eee7e4ddef4009720200", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice5", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4ddf32041120418", + "body": "Leipzig", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4ddfaa971564590": { + "identifier": "Choice6", + "serial": "choice_hottext_54eee7e4ddfaa971564590", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice6", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4ddfe7464761914", + "body": "39 Jahren", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4de05f574048504": { + "identifier": "Choice7", + "serial": "choice_hottext_54eee7e4de05f574048504", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice7", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4de09d176535455", + "body": "46 Jahre", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + }, + "choice_hottext_54eee7e4de110895741601": { + "identifier": "Choice8", + "serial": "choice_hottext_54eee7e4de110895741601", + "qtiClass": "hottext", + "attributes": { + "identifier": "Choice8", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54eee7e4de14e519142080", + "body": "54 Jahre", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + } + }, + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + }, + "prompt": { + "serial": "container_containerstatic_54eee7e4dd978411781499", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + } + } + }, + "debug": { + "relatedItem": "item_54eee7e4dcf12993796022" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e4dd183973166743": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e4dd183973166743", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e4dd23e130961520": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e4dd23e130961520", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e4dd2dc710012900": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e4dd2dc710012900", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e4dd379589046486": { + "identifier": "FEEDBACK_31186754", + "serial": "outcomedeclaration_54eee7e4dd379589046486", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_31186754", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e4dd442681082867": { + "identifier": "FEEDBACK_17440045", + "serial": "outcomedeclaration_54eee7e4dd442681082867", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_17440045", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e4dd0af965359702": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54eee7e4dd0af965359702", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "correctResponses": [ + "Choice1", + "Choice3", + "Choice8" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e4de90c267461807", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIf": { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_31186754" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_17440045" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/Matchmultiple_1038910213.json b/test/samples/json/customrp/Matchmultiple_1038910213.json new file mode 100644 index 00000000..5fe8a899 --- /dev/null +++ b/test/samples/json/customrp/Matchmultiple_1038910213.json @@ -0,0 +1,535 @@ +{ + "identifier": "Matchmultiple_1038910213", + "serial": "item_54eee7e5581ed574089532", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Matchmultiple_1038910213", + "title": "match (multiple)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e5581cc398912206", + "body": "
    Das Bundesland Sachsen besitzt viele kulturelle und historische Sehensw\u00fcrdigkeiten. \n\tWelche Sehensw\u00fcrdigkeit geh\u00f6rt zu welcher Stadt?<\/div>\n\t\t{{interaction_matchinteraction_54eee7e558b97947684668}}", + "elements": { + "interaction_matchinteraction_54eee7e558b97947684668": { + "serial": "interaction_matchinteraction_54eee7e558b97947684668", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": true, + "maxAssociations": 0, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_54eee7e558d8b233574709", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + }, + "choices": [ + { + "choice_simpleassociablechoice_54eee7e558e69303474151": { + "identifier": "Match21853614", + "serial": "choice_simpleassociablechoice_54eee7e558e69303474151", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match21853614", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e558f8c384476387", + "body": "{{img_54eee7e558fde975821355}}", + "elements": { + "img_54eee7e558fde975821355": { + "serial": "img_54eee7e558fde975821355", + "qtiClass": "img", + "attributes": { + "src": "media\/6561883b00fd435f9a9106c3f562ad55.jpg", + "alt": "" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e559149950663885": { + "identifier": "Match6887188", + "serial": "choice_simpleassociablechoice_54eee7e559149950663885", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match6887188", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5591c8480200462", + "body": "{{img_54eee7e559211673514485}}", + "elements": { + "img_54eee7e559211673514485": { + "serial": "img_54eee7e559211673514485", + "qtiClass": "img", + "attributes": { + "src": "media\/095e88097efe4e7f98fe1e878dcea4df.jpg", + "alt": "" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e559333573139982": { + "identifier": "Match23738841", + "serial": "choice_simpleassociablechoice_54eee7e559333573139982", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match23738841", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5593ad859501062", + "body": "{{img_54eee7e5593ef444959495}}", + "elements": { + "img_54eee7e5593ef444959495": { + "serial": "img_54eee7e5593ef444959495", + "qtiClass": "img", + "attributes": { + "src": "media\/c6640477db8249678663bc00aab883a5.jpg", + "alt": "" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e55950d834957414": { + "identifier": "Match16519624", + "serial": "choice_simpleassociablechoice_54eee7e55950d834957414", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match16519624", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e559584251721711", + "body": "{{img_54eee7e5595c9055088256}}", + "elements": { + "img_54eee7e5595c9055088256": { + "serial": "img_54eee7e5595c9055088256", + "qtiClass": "img", + "attributes": { + "src": "media\/e819855de2ac4c559d39fc8a27b19d1c.jpg", + "alt": "" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e5596ec862413265": { + "identifier": "Match15952430", + "serial": "choice_simpleassociablechoice_54eee7e5596ec862413265", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match15952430", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e559773764257947", + "body": "{{img_54eee7e5597ba139163786}}", + "elements": { + "img_54eee7e5597ba139163786": { + "serial": "img_54eee7e5597ba139163786", + "qtiClass": "img", + "attributes": { + "src": "media\/1d65a7270ea0482ab8135e876bed3f25.jpg", + "alt": "" + } + } + }, + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + } + }, + { + "choice_simpleassociablechoice_54eee7e5598fe377866242": { + "identifier": "Match12582080", + "serial": "choice_simpleassociablechoice_54eee7e5598fe377866242", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match12582080", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e559979546306768", + "body": "Chemnitz", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e559a54673759775": { + "identifier": "Match7003951", + "serial": "choice_simpleassociablechoice_54eee7e559a54673759775", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match7003951", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e559acc111794542", + "body": "Dresden", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e559b89480603369": { + "identifier": "Match6457581", + "serial": "choice_simpleassociablechoice_54eee7e559b89480603369", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match6457581", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e559c00661989555", + "body": "Leipzig", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + }, + "choice_simpleassociablechoice_54eee7e559cbb668834937": { + "identifier": "Match17531354", + "serial": "choice_simpleassociablechoice_54eee7e559cbb668834937", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match17531354", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e559d32498238568", + "body": "Freiberg", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + } + } + } + ] + } + }, + "debug": { + "relatedItem": "item_54eee7e5581ed574089532" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e55845a636484454": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e55845a636484454", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e558511527149259": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e558511527149259", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e5585af313891543": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e5585af313891543", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e55864c172420027": { + "identifier": "FEEDBACK_31052549", + "serial": "outcomedeclaration_54eee7e55864c172420027", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_31052549", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e55870f417598658": { + "identifier": "FEEDBACK_13697523", + "serial": "outcomedeclaration_54eee7e55870f417598658", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_13697523", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e558383272667476": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54eee7e558383272667476", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "correctResponses": [ + "Match15952430 Match12582080", + "Match21853614 Match7003951", + "Match6887188 Match7003951", + "Match16519624 Match17531354", + "Match23738841 Match6457581" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e55a1c4519186185", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIf": { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_31052549" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_13697523" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} + diff --git a/test/samples/json/customrp/Matchsingle_143114773 b/test/samples/json/customrp/Matchsingle_143114773 new file mode 100644 index 00000000..143c9884 --- /dev/null +++ b/test/samples/json/customrp/Matchsingle_143114773 @@ -0,0 +1,469 @@ +{ + "identifier": "Matchsingle_143114773", + "serial": "item_54eee7e5c8aaa548102458", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Matchsingle_143114773", + "title": "match (single)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e5c8a7d179439777", + "body": "
    Der wichtigste, gr\u00f6\u00dfte und einzig schiffbare Fluss des Bundeslandes Sachsens ist die Elbe. Die verschiedene Quellfl\u00fcsse der Elbe durchziehen die s\u00e4chsischen St\u00e4dte. \n\t\tOrdne anhand des Flusslaufs die Quellfl\u00fcsse den gegebenen St\u00e4dten zu.<\/div>\n\t\t{{interaction_matchinteraction_54eee7e5c9297614178329}}", + "elements": { + "interaction_matchinteraction_54eee7e5c9297614178329": { + "serial": "interaction_matchinteraction_54eee7e5c9297614178329", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": true, + "maxAssociations": 0, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_54eee7e5c93eb338486801", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + }, + "choices": [ + { + "choice_simpleassociablechoice_54eee7e5c9436327002973": { + "identifier": "Match29886762", + "serial": "choice_simpleassociablechoice_54eee7e5c9436327002973", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match29886762", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c94c1450520552", + "body": "Wei\u00dferitz", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + }, + "choice_simpleassociablechoice_54eee7e5c9590460098741": { + "identifier": "Match5256823", + "serial": "choice_simpleassociablechoice_54eee7e5c9590460098741", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match5256823", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c960b494931731", + "body": "Mulde", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + }, + "choice_simpleassociablechoice_54eee7e5c96ca670098334": { + "identifier": "Match4430647", + "serial": "choice_simpleassociablechoice_54eee7e5c96ca670098334", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match4430647", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c9744963215917", + "body": "Saale", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + }, + "choice_simpleassociablechoice_54eee7e5c9801339176447": { + "identifier": "Match1403839", + "serial": "choice_simpleassociablechoice_54eee7e5c9801339176447", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match1403839", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c9878633789385", + "body": "Spree", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + } + }, + { + "choice_simpleassociablechoice_54eee7e5c9948627597693": { + "identifier": "Match30518135", + "serial": "choice_simpleassociablechoice_54eee7e5c9948627597693", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match30518135", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c99c3443238519", + "body": "Dresden", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + }, + "choice_simpleassociablechoice_54eee7e5c9a7f238286789": { + "identifier": "Match2607634", + "serial": "choice_simpleassociablechoice_54eee7e5c9a7f238286789", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match2607634", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c9af7615307392", + "body": "Leipzig", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + }, + "choice_simpleassociablechoice_54eee7e5c9bc0474327570": { + "identifier": "Match8604807", + "serial": "choice_simpleassociablechoice_54eee7e5c9bc0474327570", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match8604807", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c9c47448012609", + "body": "Halle", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + }, + "choice_simpleassociablechoice_54eee7e5c9d13190431997": { + "identifier": "Match5570831", + "serial": "choice_simpleassociablechoice_54eee7e5c9d13190431997", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match5570831", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54eee7e5c9d8b253650956", + "body": "Bautzen", + "elements": [], + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + } + } + } + ] + } + }, + "debug": { + "relatedItem": "item_54eee7e5c8aaa548102458" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e5c8d33096749086": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e5c8d33096749086", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e5c8dec312760354": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e5c8dec312760354", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e5c8ea7295718069": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e5c8ea7295718069", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e5c8f45437931168": { + "identifier": "FEEDBACK_26962107", + "serial": "outcomedeclaration_54eee7e5c8f45437931168", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_26962107", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e5c9009590755408": { + "identifier": "FEEDBACK_18190857", + "serial": "outcomedeclaration_54eee7e5c9009590755408", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_18190857", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e5c8c5d567875768": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54eee7e5c8c5d567875768", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "correctResponses": [ + "Match29886762 Match30518135", + "Match5256823 Match2607634", + "Match4430647 Match8604807", + "Match1403839 Match5570831" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e5ca228025289236", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIf": { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_26962107" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_18190857" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/Matchsingle_143114773.json b/test/samples/json/customrp/Matchsingle_143114773.json new file mode 100644 index 00000000..46c11086 --- /dev/null +++ b/test/samples/json/customrp/Matchsingle_143114773.json @@ -0,0 +1,471 @@ +{ + "identifier": "Matchsingle_143114773", + "serial": "item_54fd520d03630257725457", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Matchsingle_143114773", + "title": "match (single)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54fd520d035de642441567", + "body": "
    Der wichtigste, gr\u00f6\u00dfte und einzig schiffbare Fluss des Bundeslandes Sachsens ist die Elbe. Die verschiedene Quellfl\u00fcsse der Elbe durchziehen die s\u00e4chsischen St\u00e4dte. \n\t\tOrdne anhand des Flusslaufs die Quellfl\u00fcsse den gegebenen St\u00e4dten zu.<\/div>\n\t\t{{interaction_matchinteraction_54fd520d098d9162419996}}", + "elements": { + "interaction_matchinteraction_54fd520d098d9162419996": { + "serial": "interaction_matchinteraction_54fd520d098d9162419996", + "qtiClass": "matchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": true, + "maxAssociations": 0, + "minAssociations": 0 + }, + "prompt": { + "serial": "container_containerstatic_54fd520d0ad68147758576", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + }, + "choices": [ + { + "choice_simpleassociablechoice_54fd520d0b5e4557055483": { + "identifier": "Match29886762", + "serial": "choice_simpleassociablechoice_54fd520d0b5e4557055483", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match29886762", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0c238665365750", + "body": "Wei\u00dferitz", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + }, + "choice_simpleassociablechoice_54fd520d0c3bc469866283": { + "identifier": "Match5256823", + "serial": "choice_simpleassociablechoice_54fd520d0c3bc469866283", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match5256823", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0c46b814806251", + "body": "Mulde", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + }, + "choice_simpleassociablechoice_54fd520d0c569750140170": { + "identifier": "Match4430647", + "serial": "choice_simpleassociablechoice_54fd520d0c569750140170", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match4430647", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0c60d866435057", + "body": "Saale", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + }, + "choice_simpleassociablechoice_54fd520d0c701725111596": { + "identifier": "Match1403839", + "serial": "choice_simpleassociablechoice_54fd520d0c701725111596", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match1403839", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0c7a2135725272", + "body": "Spree", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + } + }, + { + "choice_simpleassociablechoice_54fd520d0c8b3343629113": { + "identifier": "Match30518135", + "serial": "choice_simpleassociablechoice_54fd520d0c8b3343629113", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match30518135", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0c956947736786", + "body": "Dresden", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + }, + "choice_simpleassociablechoice_54fd520d0ca4d097402566": { + "identifier": "Match2607634", + "serial": "choice_simpleassociablechoice_54fd520d0ca4d097402566", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match2607634", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0caee040630477", + "body": "Leipzig", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + }, + "choice_simpleassociablechoice_54fd520d0cbe2890007380": { + "identifier": "Match8604807", + "serial": "choice_simpleassociablechoice_54fd520d0cbe2890007380", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match8604807", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0cc83149508823", + "body": "Halle", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + }, + "choice_simpleassociablechoice_54fd520d0cd76212720758": { + "identifier": "Match5570831", + "serial": "choice_simpleassociablechoice_54fd520d0cd76212720758", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "Match5570831", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54fd520d0ce17492277064", + "body": "Bautzen", + "elements": [], + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + } + } + } + ] + } + }, + "debug": { + "relatedItem": "item_54fd520d03630257725457" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54fd520d07122996496900": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54fd520d07122996496900", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54fd520d0859c075523966": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54fd520d0859c075523966", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54fd520d0868d442393526": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54fd520d0868d442393526", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54fd520d087a0200668145": { + "identifier": "FEEDBACK_26962107", + "serial": "outcomedeclaration_54fd520d087a0200668145", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_26962107", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd520d088ab271434927": { + "identifier": "FEEDBACK_18190857", + "serial": "outcomedeclaration_54fd520d088ab271434927", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_18190857", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54fd520d06427661251590": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54fd520d06427661251590", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "correctResponses": [ + "Match29886762 Match30518135", + "Match5256823 Match2607634", + "Match4430647 Match8604807", + "Match1403839 Match5570831" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54fd520d0e46e680618246", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIfs": [ + { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + ], + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_26962107" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_18190857" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/customrp/Order_913967682.json b/test/samples/json/customrp/Order_913967682.json new file mode 100644 index 00000000..eb187e69 --- /dev/null +++ b/test/samples/json/customrp/Order_913967682.json @@ -0,0 +1,399 @@ +{ + "identifier": "Order_913967682", + "serial": "item_54fd50ab1aecd653644198", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "Order_913967682", + "title": "order", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54fd50ab1ae9f358613892", + "body": "
    \n\t\t\tSortiere die genannten Parteien nach Ihrer Sitzverteilung im Landtag Sachsen.\n\t\t\tBeginne mit der st\u00e4rksten Partei.\n\t\t<\/div>\n\t\t{{interaction_orderinteraction_54fd50ab1d8ad073547353}}", + "elements": { + "interaction_orderinteraction_54fd50ab1d8ad073547353": { + "serial": "interaction_orderinteraction_54fd50ab1d8ad073547353", + "qtiClass": "orderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": true + }, + "choices": { + "choice_simplechoice_54fd50ab1f465475141497": { + "identifier": "Choice0", + "serial": "choice_simplechoice_54fd50ab1f465475141497", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Choice0", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd50ab1fbb0745345560", + "body": "CDU", + "elements": [], + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + } + }, + "choice_simplechoice_54fd50ab1fd2a349932615": { + "identifier": "Choice1", + "serial": "choice_simplechoice_54fd50ab1fd2a349932615", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Choice1", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd50ab1fd85356565382", + "body": "Die Linke", + "elements": [], + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + } + }, + "choice_simplechoice_54fd50ab1fe66787081541": { + "identifier": "Choice2", + "serial": "choice_simplechoice_54fd50ab1fe66787081541", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Choice2", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd50ab1feb9960895025", + "body": "SDP", + "elements": [], + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + } + }, + "choice_simplechoice_54fd50ab1ff93215922930": { + "identifier": "Choice3", + "serial": "choice_simplechoice_54fd50ab1ff93215922930", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Choice3", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd50ab1ffe2009756212", + "body": "Gr\u00fcne", + "elements": [], + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + } + }, + "choice_simplechoice_54fd50ab200bc735901510": { + "identifier": "Choice4", + "serial": "choice_simplechoice_54fd50ab200bc735901510", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Choice4", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd50ab2010b980467935", + "body": "NPD", + "elements": [], + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54fd50ab1ee09905293046", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + } + } + }, + "debug": { + "relatedItem": "item_54fd50ab1aecd653644198" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54fd50ab1c15e995846249": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54fd50ab1c15e995846249", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54fd50ab1c5d0167007200": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54fd50ab1c5d0167007200", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54fd50ab1c698102137296": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54fd50ab1c698102137296", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54fd50ab1c757738389463": { + "identifier": "FEEDBACK_14455851", + "serial": "outcomedeclaration_54fd50ab1c757738389463", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_14455851", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54fd50ab1c847433076979": { + "identifier": "FEEDBACK_23266699", + "serial": "outcomedeclaration_54fd50ab1c847433076979", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_23266699", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54fd50ab1bce3704164022": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54fd50ab1bce3704164022", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "correctResponses": [ + "Choice0", + "Choice1", + "Choice2", + "Choice3", + "Choice4" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54fd50ab219c8261837818", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/isNull>\n\t\t\t\t\n\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElseIf>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseElse>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + } + ] + }, + "responseElseIfs": [ + { + "qtiClass": "responseElseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + ], + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_14455851" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_23266699" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/customrp/TextEntry_883368511.json b/test/samples/json/customrp/TextEntry_883368511.json new file mode 100644 index 00000000..2dc5ed33 --- /dev/null +++ b/test/samples/json/customrp/TextEntry_883368511.json @@ -0,0 +1,322 @@ +{ + "identifier": "TextEntry_883368511", + "serial": "item_54eee7e6b313f932931476", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "TextEntry_883368511", + "title": "textEntry", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e6b3120716639424", + "body": "
    Mit 1215 Metern ist der {{interaction_textentryinteraction_54eee7e6b3a35655574355}} die h\u00f6chste Erhebung im Bundesland Sachsen.<\/div>", + "elements": { + "interaction_textentryinteraction_54eee7e6b3a35655574355": { + "serial": "interaction_textentryinteraction_54eee7e6b3a35655574355", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "base": 10 + }, + "choices": [] + } + }, + "debug": { + "relatedItem": "item_54eee7e6b313f932931476" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e6b33cf749098097": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e6b33cf749098097", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e6b3488024676441": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e6b3488024676441", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e6b3526565696517": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e6b3526565696517", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e6b35c2111458043": { + "identifier": "FEEDBACK_13836328", + "serial": "outcomedeclaration_54eee7e6b35c2111458043", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_13836328", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e6b3682101402948": { + "identifier": "FEEDBACK_4493676", + "serial": "outcomedeclaration_54eee7e6b3682101402948", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_4493676", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e6b32d8224185871": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_54eee7e6b32d8224185871", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "string" + }, + "correctResponses": [ + "Fichtelberg" + ], + "mapping": { + "Fichtelberg": "1.0" + }, + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e6b40ff354489267", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t\t\t<\/match>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/equal>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + ] + } + ] + }, + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_13836328" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_4493676" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/TextEntrynumeric_2040297025.json b/test/samples/json/customrp/TextEntrynumeric_2040297025.json new file mode 100644 index 00000000..6ec9b4c4 --- /dev/null +++ b/test/samples/json/customrp/TextEntrynumeric_2040297025.json @@ -0,0 +1,467 @@ +{ + "identifier": "TextEntrynumeric_2040297025", + "serial": "item_54eee7e72d523928870944", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "TextEntrynumeric_2040297025", + "title": "textEntry (numeric)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e72d503419349811", + "body": "
    Das Bundesland Sachsen grenzt an {{interaction_textentryinteraction_54eee7e72dd70410792878}} andere deutsche Bundesl\u00e4nder und {{interaction_textentryinteraction_54eee7e72deb1352618389}} L\u00e4nder au\u00dferhalb Deutschlands.<\/div>", + "elements": { + "interaction_textentryinteraction_54eee7e72dd70410792878": { + "serial": "interaction_textentryinteraction_54eee7e72dd70410792878", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "base": 10 + }, + "choices": [] + }, + "interaction_textentryinteraction_54eee7e72deb1352618389": { + "serial": "interaction_textentryinteraction_54eee7e72deb1352618389", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_2", + "base": 10 + }, + "choices": [] + } + }, + "debug": { + "relatedItem": "item_54eee7e72d523928870944" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e72d863437475870": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e72d863437475870", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e72d91c293295387": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e72d91c293295387", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "2.0" + }, + "outcomedeclaration_54eee7e72d9ba246153996": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e72d9ba246153996", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e72da56920415625": { + "identifier": "FEEDBACK_1666978", + "serial": "outcomedeclaration_54eee7e72da56920415625", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_1666978", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e72db19332447122": { + "identifier": "FEEDBACK_9473961", + "serial": "outcomedeclaration_54eee7e72db19332447122", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_9473961", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e72d6ba722266575": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_54eee7e72d6ba722266575", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "float" + }, + "correctResponses": [ + "4.0" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + }, + "responsedeclaration_54eee7e72d7a9024788652": { + "identifier": "RESPONSE_2", + "serial": "responsedeclaration_54eee7e72d7a9024788652", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_2", + "cardinality": "single", + "baseType": "float" + }, + "correctResponses": [ + "2.0" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e72e34d335209624", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/equal>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t1.0<\/baseValue>\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/equal>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t1.0<\/baseValue>\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t\t\t<\/match>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/equal>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1.0" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1.0" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + ] + } + ] + }, + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1666978" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_9473961" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/TextEntrynumeric_770468849.json b/test/samples/json/customrp/TextEntrynumeric_770468849.json new file mode 100644 index 00000000..e5ea6ea9 --- /dev/null +++ b/test/samples/json/customrp/TextEntrynumeric_770468849.json @@ -0,0 +1,353 @@ +{ + "identifier": "TextEntrynumeric_770468849", + "serial": "item_54eee7e79d24e456603416", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "TextEntrynumeric_770468849", + "title": "textEntry (numeric, relative)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e79d22d178319461", + "body": "

    Wieviele Einwohner hat der Freistaat Sachsen?<\/p>\n\t\t

    \n\t\t\t{{interaction_textentryinteraction_54eee7e79da07387679306}} Mio. (Stand: 31. August 2011)<\/div>", + "elements": { + "interaction_textentryinteraction_54eee7e79da07387679306": { + "serial": "interaction_textentryinteraction_54eee7e79da07387679306", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "base": 10 + }, + "choices": [] + } + }, + "debug": { + "relatedItem": "item_54eee7e79d24e456603416" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e79d4ef796571442": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e79d4ef796571442", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e79d5ae573784280": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e79d5ae573784280", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "1.0" + }, + "outcomedeclaration_54eee7e79d653229380619": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e79d653229380619", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e79d6f5988036088": { + "identifier": "FEEDBACK_18920566", + "serial": "outcomedeclaration_54eee7e79d6f5988036088", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_18920566", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e79d7bd904995786": { + "identifier": "FEEDBACK_23396239", + "serial": "outcomedeclaration_54eee7e79d7bd904995786", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_23396239", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e79d400175555045": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_54eee7e79d400175555045", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "float" + }, + "correctResponses": [ + "4.136" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e79ded5449720367", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t<\/equal>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t1.0<\/baseValue>\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t\t\t<\/match>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/equal>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "customOperator", + "attributes": { + "class": "taoQtiItem/scoring/processor/expressions/operators/custom/equal", + "toleranceMode": "relative", + "tolerance": "5.0", + "includeLowerBound": "true", + "includeUpperBound": "true" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1.0" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + ] + } + ] + }, + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_18920566" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_23396239" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/TextEntrysubset_806481421.json b/test/samples/json/customrp/TextEntrysubset_806481421.json new file mode 100644 index 00000000..e06ffc70 --- /dev/null +++ b/test/samples/json/customrp/TextEntrysubset_806481421.json @@ -0,0 +1,666 @@ +{ + "identifier": "TextEntrysubset_806481421", + "serial": "item_54eee7e81747f155204467", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "TextEntrysubset_806481421", + "title": "textEntry (subset)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54eee7e81745f056968667", + "body": "

    Das Bundesland Sachsen enth\u00e4lt die drei kreisfreien St\u00e4dte:<\/p>\n\t

    \n\t\t{{interaction_textentryinteraction_54eee7e817e3c146827376}}\n\t\t\n\t\t{{interaction_textentryinteraction_54eee7e817f54906279630}}\n\t\t\n\t\t{{interaction_textentryinteraction_54eee7e818041265071778}}\n\t<\/div>", + "elements": { + "interaction_textentryinteraction_54eee7e817e3c146827376": { + "serial": "interaction_textentryinteraction_54eee7e817e3c146827376", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "base": 10 + }, + "choices": [] + }, + "interaction_textentryinteraction_54eee7e817f54906279630": { + "serial": "interaction_textentryinteraction_54eee7e817f54906279630", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_2", + "base": 10 + }, + "choices": [] + }, + "interaction_textentryinteraction_54eee7e818041265071778": { + "serial": "interaction_textentryinteraction_54eee7e818041265071778", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_3", + "base": 10 + }, + "choices": [] + } + }, + "debug": { + "relatedItem": "item_54eee7e81747f155204467" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54eee7e817909415238259": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54eee7e817909415238259", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0.0" + }, + "outcomedeclaration_54eee7e8179cf558984077": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_54eee7e8179cf558984077", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "3.0" + }, + "outcomedeclaration_54eee7e817a7b019243281": { + "identifier": "FEEDBACKBASIC", + "serial": "outcomedeclaration_54eee7e817a7b019243281", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACKBASIC", + "cardinality": "single", + "baseType": "identifier" + }, + "defaultValue": "empty" + }, + "outcomedeclaration_54eee7e817b17273473827": { + "identifier": "FEEDBACK_10699829", + "serial": "outcomedeclaration_54eee7e817b17273473827", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_10699829", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + }, + "outcomedeclaration_54eee7e817bf3933615446": { + "identifier": "FEEDBACK_235860", + "serial": "outcomedeclaration_54eee7e817bf3933615446", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_235860", + "cardinality": "single", + "baseType": "boolean", + "view": [ + "testConstructor" + ] + }, + "defaultValue": "false" + } + }, + "responses": { + "responsedeclaration_54eee7e817617375210638": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_54eee7e817617375210638", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "string" + }, + "correctResponses": [], + "mapping": { + "Dresden": "1.0", + "Chemnitz": "1.0", + "Leipzig": "1.0" + }, + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + }, + "responsedeclaration_54eee7e81773a090292777": { + "identifier": "RESPONSE_2", + "serial": "responsedeclaration_54eee7e81773a090292777", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_2", + "cardinality": "single", + "baseType": "string" + }, + "correctResponses": [], + "mapping": { + "Dresden": "1.0", + "Chemnitz": "1.0", + "Leipzig": "1.0" + }, + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + }, + "responsedeclaration_54eee7e817833491139707": { + "identifier": "RESPONSE_3", + "serial": "responsedeclaration_54eee7e817833491139707", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_3", + "cardinality": "single", + "baseType": "string" + }, + "correctResponses": [], + "mapping": { + "Dresden": "1.0", + "Chemnitz": "1.0", + "Leipzig": "1.0" + }, + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_54eee7e818980642690453", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<\/isNull>\n\t\t\t\t\t<\/not>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<\/isNull>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<\/stringMatch>\n\t\t\t\t\t<\/not>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<\/isNull>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<\/stringMatch>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<\/stringMatch>\n\t\t\t\t\t<\/not>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/sum>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/isNull>\n\t\t\t\t<\/not>\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tempty<\/baseValue>\n\t\t\t\t\t\t<\/match>\n\t\t\t\t\t<\/not>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t<\/equal>\n\t\t\t\t<\/and>\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t<\/setOutcomeValue>\n\t\t\t<\/responseIf>\n\t\t<\/responseCondition>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tcorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tincorrect<\/baseValue>\n\t\t\t\t\t\n\t\t\t\t<\/match>\n\t\t\t<\/and>\n\t\t<\/setOutcomeValue>\n\t<\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + } + ] + }, + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "stringMatch", + "attributes": { + "caseSensitive": "false" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "stringMatch", + "attributes": { + "caseSensitive": "false" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + } + ] + }, + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "stringMatch", + "attributes": { + "caseSensitive": "false" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "isNull", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "empty" + } + ] + } + ] + }, + { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "MAXSCORE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACKBASIC" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + } + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_10699829" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "correct" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + }, + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_235860" + }, + "expression": { + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "incorrect" + }, + { + "qtiClass": "variable", + "attributes": { + "identifier": "FEEDBACKBASIC" + } + } + ] + } + ] + } + } + ] + } +} diff --git a/test/samples/json/customrp/andAnd.json b/test/samples/json/customrp/andAnd.json new file mode 100644 index 00000000..7bd15e23 --- /dev/null +++ b/test/samples/json/customrp/andAnd.json @@ -0,0 +1,223 @@ +{ + "type": "qti", + "data": { + "identifier": "andAnd", + "serial": "item_570e0b3f9d679965077104", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "andAnd", + "title": "andAnd", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint15", + "class": "" + }, + "body": { + "serial": "container_containeritembody_570e0b3f9d654202329748", + "body": "
    {{interaction_textentryinteraction_570e0b3f9edd2775967056}} and {{interaction_textentryinteraction_570e0b3f9f3a8122278710}}<\/div>", + "elements": { + "interaction_textentryinteraction_570e0b3f9edd2775967056": { + "serial": "interaction_textentryinteraction_570e0b3f9edd2775967056", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 10, + "class": "", + "id": "r1" + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + }, + "choices": {} + }, + "interaction_textentryinteraction_570e0b3f9f3a8122278710": { + "serial": "interaction_textentryinteraction_570e0b3f9f3a8122278710", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_2", + "base": 10, + "expectedLength": 10, + "class": "", + "id": "r2" + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + } + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_570e0b3f9e60b716575993": { + "identifier": "SCORE", + "serial": "outcomedeclaration_570e0b3f9e60b716575993", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float", + "normalMaximum": 1, + "normalMinimum": 0 + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_570e0b3f9e0c1460580188": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_570e0b3f9e0c1460580188", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + }, + "mapping": [], + "areaMapping": [], + "howMatch": null, + "correctResponses": [ 1234 ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_570e0b3f9e456011320875": { + "identifier": "RESPONSE_2", + "serial": "responsedeclaration_570e0b3f9e456011320875", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_2", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_570e0b3f9d679965077104" + }, + "mapping": [], + "areaMapping": [], + "howMatch": null, + "correctResponses": [ 42 ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_custom_570e0b3fa0a7e390290134", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "" + }, + "processingType": "custom", + "data": "", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "and", + "expressions": [{ + "qtiClass": "and", + "expressions": [ + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "boolean" + }, + "value": true + }, { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }] + }, { + "qtiClass": "equal", + "attributes": { + "toleranceMode": "exact" + }, + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_2" + } + }] + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + } + }] + } + }, + "assets": [] +} diff --git a/test/samples/json/customrp/custom_record.json b/test/samples/json/customrp/custom_record.json new file mode 100644 index 00000000..64c4c4d2 --- /dev/null +++ b/test/samples/json/customrp/custom_record.json @@ -0,0 +1,175 @@ +{ + "type": "qti", + "data": { + "identifier": "i1468246257550489", + "serial": "item_5784ed91a8f8f520320995", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1468246257550489", + "title": "Item 16", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint15", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5784ed91a8f74666402209", + "body": "\n
    \n
    \n QQQ\n <\/div>\n <\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5784ed91a8f8f520320995" + } + }, + "debug": { + "relatedItem": "item_5784ed91a8f8f520320995" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1", + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": {}, + "outcomes": { + "outcomedeclaration_5784ed91ad60f883015879": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5784ed91ad60f883015879", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5784ed91a8f8f520320995" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5784ed91ac168519849035": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5784ed91ac168519849035", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "record" + }, + "debug": { + "relatedItem": "item_5784ed91a8f8f520320995" + }, + "mapping": [], + "areaMapping": [], + "howMatch": null, + "correctResponses": { + "fieldA": { + "value": "yes", + "fieldIdentifier": "fieldA", + "cardinality": "single", + "baseType": "string" + }, + "fieldB": { + "value": "2", + "fieldIdentifier": "fieldB", + "baseType": "integer" + } + }, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_custom_5784ed91afefe440941847", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "" + }, + "processingType": "custom", + "data": "\n \n \n \n \n \n <\/fieldValue>\n \n \n <\/fieldValue>\n <\/match>\n \n 2.0<\/baseValue>\n <\/setOutcomeValue>\n <\/responseIf>\n \n \n -1.0<\/baseValue>\n <\/setOutcomeValue>\n <\/responseElse>\n <\/responseCondition>\n <\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "fieldValue", + "attributes": { + "fieldIdentifier": "fieldA" + }, + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + { + "qtiClass": "fieldValue", + "attributes": { + "fieldIdentifier": "fieldA" + }, + "expressions": [ + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "2.0" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "-1.0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" + } +} \ No newline at end of file diff --git a/test/samples/json/customrp/order.json b/test/samples/json/customrp/order.json new file mode 100644 index 00000000..56f35c8e --- /dev/null +++ b/test/samples/json/customrp/order.json @@ -0,0 +1,200 @@ +{ + "identifier": "order", + "serial": "item_54fd564835524083023723", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "order", + "title": "Grand Prix of Bahrain", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0-RC01" + }, + "body": { + "serial": "container_containeritembody_54fd5648354eb270188009", + "body": "{{interaction_orderinteraction_54fd56483a8a6486484054}}", + "elements": { + "interaction_orderinteraction_54fd56483a8a6486484054": { + "serial": "interaction_orderinteraction_54fd56483a8a6486484054", + "qtiClass": "orderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": true + }, + "choices": { + "choice_simplechoice_54fd56483c815917874527": { + "identifier": "DriverA", + "serial": "choice_simplechoice_54fd56483c815917874527", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "DriverA", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd56483d085994114755", + "body": "Rubens Barrichello", + "elements": [], + "debug": { + "relatedItem": "item_54fd564835524083023723" + } + } + }, + "choice_simplechoice_54fd56483d1f9878327686": { + "identifier": "DriverB", + "serial": "choice_simplechoice_54fd56483d1f9878327686", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "DriverB", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_54fd56483d258164684266", + "body": "Jenson Button", + "elements": [], + "debug": { + "relatedItem": "item_54fd564835524083023723" + } + } + }, + "choice_simplechoice_54fd56483d347768181968": { + "identifier": "DriverC", + "serial": "choice_simplechoice_54fd56483d347768181968", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "DriverC", + "fixed": true + }, + "body": { + "serial": "container_containerstatic_54fd56483d3bd757433282", + "body": "Michael Schumacher", + "elements": [], + "debug": { + "relatedItem": "item_54fd564835524083023723" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54fd56483c075635705749", + "body": "The following F1 drivers finished on the podium in the first ever Grand Prix of\n\t\t\t\tBahrain. Can you rearrange them into the correct finishing order?", + "elements": [], + "debug": { + "relatedItem": "item_54fd564835524083023723" + } + } + } + }, + "debug": { + "relatedItem": "item_54fd564835524083023723" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54fd564838bb4125597054": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54fd564838bb4125597054", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_54fd564837d49107453257": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54fd564837d49107453257", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "correctResponses": [ + "DriverC", + "DriverA", + "DriverB" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_54fd56483e125467187007", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/edinburgh.json b/test/samples/json/edinburgh.json new file mode 100644 index 00000000..ffa4fc27 --- /dev/null +++ b/test/samples/json/edinburgh.json @@ -0,0 +1,149 @@ +{ + "identifier": "selectPoint", + "serial": "item_547dd7f954387167462245", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "selectPoint", + "title": "Where is Edinburgh?", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd7f954374226937307", + "body": "{{interaction_selectpointinteraction_547dd7f9559e9023877499}}", + "elements": { + "interaction_selectpointinteraction_547dd7f9559e9023877499": { + "serial": "interaction_selectpointinteraction_547dd7f9559e9023877499", + "qtiClass": "selectPointInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 1, + "minChoices": 0 + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_547dd7f955b31619148792", + "body": "Mark Edinburgh on this map of the United Kingdom.", + "elements": [], + "debug": { + "relatedItem": "item_547dd7f954387167462245" + } + }, + "object": { + "serial": "object_547dd7f955c7e163656237", + "qtiClass": "object", + "attributes": { + "data": "images/uk.png", + "type": "image/png", + "width": 196, + "height": 280 + }, + "_alt": "UK Map" + } + } + }, + "debug": { + "relatedItem": "item_547dd7f954387167462245" + } + }, + "namespaces": { + "": "http://www.imsglobal.org/xsd/imsqti_v2p1", + "xsi": "http://www.w3.org/2001/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd7f954767033663297": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd7f954767033663297", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd7f954608553411332": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd7f954608553411332", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "point" + }, + "correctResponses": [ + "102 113" + ], + "mapping": [], + "areaMapping": [{ + "shape": "circle", + "coords": "102,113,16", + "mappedValue": "1" + }], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response_point", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd7f955e2b502421773", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponsePoint", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } +} diff --git a/test/samples/json/elections.json b/test/samples/json/elections.json new file mode 100644 index 00000000..410497c8 --- /dev/null +++ b/test/samples/json/elections.json @@ -0,0 +1,175 @@ +{ + "identifier": "elections-in-the-united-states-2004", + "serial": "item_547dd870b8246359831084", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "elections-in-the-united-states-2004", + "title": "Elections in the United States, 2004", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd870b8234231383872", + "body": "

    \n\t\t\tThe 4th of November 2004, Georges W. Bush (Republican) wins the US elections against John Kerry\n\t\t\t(Democrat). After a first mandate leading the United States of America, Bush remains president for 4\n\t\t\tmore years. During these elections, 114.3 million votes were counted.\n\t\t

    \n {{interaction_sliderinteraction_547dd870b9e7a456519135}}\n

    \n {{img_547dd870ba543784273322}}\n

    ", + "elements": { + "interaction_sliderinteraction_547dd870b9e7a456519135": { + "serial": "interaction_sliderinteraction_547dd870b9e7a456519135", + "qtiClass": "sliderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "lowerBound": 0, + "upperBound": 100, + "step": 1, + "stepLabel": false, + "id": "interaction" + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_547dd870ba310409928521", + "body": "In your opinion, what was the percentage (%) of Republican voters during the 2004 US elections? If needed,\n\t\t\t\thelp yourself with the map below.", + "elements": [], + "debug": { + "relatedItem": "item_547dd870b8246359831084" + } + } + }, + "img_547dd870ba543784273322": { + "serial": "img_547dd870ba543784273322", + "qtiClass": "img", + "attributes": { + "src": "img/map.jpg", + "alt": "Presidential popular votes by county.", + "id": "map" + } + } + }, + "debug": { + "relatedItem": "item_547dd870b8246359831084" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": { + "stylesheet_547dd870b8b37980869211": { + "serial": "stylesheet_547dd870b8b37980869211", + "qtiClass": "stylesheet", + "attributes": { + "href": "style.css", + "type": "text/css", + "media": "screen", + "title": "Elections in the United States, 2004" + } + } + }, + "outcomes": { + "outcomedeclaration_547dd870b99b7459925385": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd870b99b7459925385", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd870b91b2970776577": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd870b91b2970776577", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "integer" + }, + "correctResponses": [ + "51" + ], + "mapping": { + "42": "0.1", + "43": "0.2", + "44": "0.3", + "45": "0.4", + "46": "0.5", + "47": "0.6", + "48": "0.7", + "49": "0.8", + "50": "0.9", + "51": "1.0", + "52": "0.9", + "53": "0.8", + "54": "0.7", + "55": "0.6", + "56": "0.5", + "57": "0.4", + "58": "0.3", + "59": "0.2", + "60": "0.1" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd870ba8e0645967860", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } +} diff --git a/test/samples/json/es6.json b/test/samples/json/es6.json new file mode 100644 index 00000000..8e7299bd --- /dev/null +++ b/test/samples/json/es6.json @@ -0,0 +1,416 @@ +{ + "identifier": "i14338425488286109", + "serial": "item_5576b71e3bd72041243459", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i14338425488286109", + "title": "Item 22", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1-dev" + }, + "body": { + "serial": "container_containeritembody_5576b71e3bd44704736669", + "body": "
    \n
    \n \n Look at the ES6 code and answer the questions<\/span>\n <\/strong>\n <\/div>\n <\/div>\n
    \n
    \n
    function* foo(){\n  let x = 0;\n  while(x < 5){\n    x++;\n    yield x;\n  }\n  return x;\n}\n \nlet bar = [];\nfor(let x of foo()){\n  bar.push(x);\n}\n \nlet [,,c] = bar;\n \nconsole.log(c);<\/pre>\n      <\/div>\n      
    \n {{interaction_choiceinteraction_5576b71e3d78e875266879}}\n <\/div>\n <\/div>\n
    \n
    \n {{interaction_choiceinteraction_5576b71e3e5f7396796365}}\n <\/div>\n <\/div>", + "elements": { + "interaction_choiceinteraction_5576b71e3d78e875266879": { + "serial": "interaction_choiceinteraction_5576b71e3d78e875266879", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "choices": { + "choice_simplechoice_5576b71e3df0d808018523": { + "identifier": "choice_1", + "serial": "choice_simplechoice_5576b71e3df0d808018523", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3e0ce426932339", + "body": "nothing", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "choice_simplechoice_5576b71e3e1ca057278989": { + "identifier": "choice_2", + "serial": "choice_simplechoice_5576b71e3e1ca057278989", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3e231325193568", + "body": "1<\/em>", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "choice_simplechoice_5576b71e3e322293627299": { + "identifier": "choice_3", + "serial": "choice_simplechoice_5576b71e3e322293627299", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3e385360773425", + "body": "3<\/em>", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "choice_simplechoice_5576b71e3e46d398690235": { + "identifier": "choice_4", + "serial": "choice_simplechoice_5576b71e3e46d398690235", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3e4d2639550717", + "body": "undefined<\/em>", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5576b71e3dcaa200724246", + "body": "What does this code output in the console", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + } + }, + "interaction_choiceinteraction_5576b71e3e5f7396796365": { + "serial": "interaction_choiceinteraction_5576b71e3e5f7396796365", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "choices": { + "choice_simplechoice_5576b71e3e80e584291536": { + "identifier": "choice_5", + "serial": "choice_simplechoice_5576b71e3e80e584291536", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3e873971495128", + "body": "An Iterator", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "choice_simplechoice_5576b71e3e94d313189498": { + "identifier": "choice_6", + "serial": "choice_simplechoice_5576b71e3e94d313189498", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3e9ae596249262", + "body": "A Symbol", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "choice_simplechoice_5576b71e3ea7e032996872": { + "identifier": "choice_7", + "serial": "choice_simplechoice_5576b71e3ea7e032996872", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5576b71e3eadf221213617", + "body": "A generator", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5576b71e3e720280165542", + "body": "What's the name the function* structure ?", + "elements": {}, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + } + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": { + "stylesheet_5576b71e3c582994711148": { + "serial": "stylesheet_5576b71e3c582994711148", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + } + } + }, + "outcomes": { + "outcomedeclaration_5576b71e3cf96183878359": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5576b71e3cf96183878359", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5576b71e3cb6c519108482": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5576b71e3cb6c519108482", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "correctResponses": [ + "choice_3" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_5576b71e3ce31644366077": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_5576b71e3ce31644366077", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "correctResponses": + "choice_7" + , + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_5576b71e3f406202435057", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_5576b71e3bd72041243459" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + } + ] + } +} diff --git a/test/samples/json/flying-home.json b/test/samples/json/flying-home.json new file mode 100644 index 00000000..5fd65f76 --- /dev/null +++ b/test/samples/json/flying-home.json @@ -0,0 +1,195 @@ +{ + "identifier": "graphicOrder", + "serial": "item_547dd734651aa272971469", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "graphicOrder", + "title": "Flying Home", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd73465191813531642", + "body": "

    Lorna is flying back home to the UK. Ideally, she would like to fly in directly to her\n\t\t\thome town of Glasgow. Edinburgh is her second choice and, if necessary, she could fly\n\t\t\tinto London and pick up an internal connecting flight. Although she has been offered a\n\t\t\tcheap flight to Manchester it remains her least favourite option as connecting flights\n\t\t\tto Glasgow are not very reliable from there.

    \n {{interaction_graphicorderinteraction_547dd734662de783873637}}", + "elements": { + "interaction_graphicorderinteraction_547dd734662de783873637": { + "serial": "interaction_graphicorderinteraction_547dd734662de783873637", + "qtiClass": "graphicOrderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE" + }, + "choices": { + "choice_hotspotchoice_547dd734669b5397676078": { + "identifier": "A", + "serial": "choice_hotspotchoice_547dd734669b5397676078", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "A", + "fixed": false, + "shape": "circle", + "coords": "77,115,8" + } + }, + "choice_hotspotchoice_547dd73466aa1509482181": { + "identifier": "B", + "serial": "choice_hotspotchoice_547dd73466aa1509482181", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "B", + "fixed": false, + "shape": "circle", + "coords": "118,184,8" + } + }, + "choice_hotspotchoice_547dd73466ae3712668688": { + "identifier": "C", + "serial": "choice_hotspotchoice_547dd73466ae3712668688", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "C", + "fixed": false, + "shape": "circle", + "coords": "150,235,8" + } + }, + "choice_hotspotchoice_547dd73466b20205726368": { + "identifier": "D", + "serial": "choice_hotspotchoice_547dd73466b20205726368", + "qtiClass": "hotspotChoice", + "attributes": { + "identifier": "D", + "fixed": false, + "shape": "circle", + "coords": "96,114,8" + } + } + }, + "prompt": { + "serial": "container_containerstatic_547dd734666ae901036932", + "body": "Mark the airports shown on the map according to Lorna's preferences.", + "elements": [], + "debug": { + "relatedItem": "item_547dd734651aa272971469" + } + }, + "object": { + "serial": "object_547dd73466b6d608435192", + "qtiClass": "object", + "attributes": { + "data": "images/ukair.png", + "type": "image/png", + "width": 206, + "height": 280 + }, + "_alt": "UK Map" + } + } + }, + "debug": { + "relatedItem": "item_547dd734651aa272971469" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd7346556b677678795": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd7346556b677678795", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd7346544f639101653": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd7346544f639101653", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "correctResponses": [ + "A", + "D", + "C", + "B" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd73466d3a315823347", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/formated-card.json b/test/samples/json/formated-card.json new file mode 100644 index 00000000..d1024027 --- /dev/null +++ b/test/samples/json/formated-card.json @@ -0,0 +1,133 @@ +{ + "identifier": "extendedText", + "serial": "item_555600ae567b2175433182", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "extendedText", + "title": "Writing a Postcard", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0.1" + }, + "body": { + "serial": "container_containeritembody_555600ae5678c065265738", + "body": "
    \n
    \n

    Read this postcard from your English pen-friend, Sam.<\/p>\n

    \n {{img_555600ae589e4816387779}}\n <\/p>\n <\/div>\n

    \n {{interaction_extendedtextinteraction_555600ae5805f503322627}}\n <\/div>\n <\/div>", + "elements": { + "interaction_extendedtextinteraction_555600ae5805f503322627": { + "serial": "interaction_extendedtextinteraction_555600ae5805f503322627", + "qtiClass": "extendedTextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "patternMask": "\/^(?:(?:[^\\s\\:\\!\\?\\;\\\u2026\\\u20ac]+)[\\s\\:\\!\\?\\;\\\u2026\\\u20ac]*){0,50}$\/", + "minStrings": 0, + "format": "xhtml" + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + }, + "choices": {}, + "prompt": { + "serial": "container_containerstatic_555600ae587dd468760533", + "body": "Write Sam a short letter.\u00a0 Answer the questions.\u00a0 Write 50 words.<\/em>", + "elements": {}, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + } + } + }, + "img_555600ae589e4816387779": { + "serial": "img_555600ae589e4816387779", + "qtiClass": "img", + "attributes": { + "src": "images\/postcard.png", + "alt": "postcard", + "width": "100%" + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + } + } + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + } + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": { + "stylesheet_555600ae56fa9052117496": { + "serial": "stylesheet_555600ae56fa9052117496", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + } + } + }, + "outcomes": { + "outcomedeclaration_555600ae5788d747947578": { + "identifier": "SCORE", + "serial": "outcomedeclaration_555600ae5788d747947578", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_555600ae57568623654802": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_555600ae57568623654802", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_555600ae567b2175433182" + }, + "correctResponses": [], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_custom_555600ae59220089386409", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "" + }, + "processingType": "custom", + "data": "", + "responseRules": [] + } +} diff --git a/test/samples/json/history.json b/test/samples/json/history.json new file mode 100644 index 00000000..7cc94ee1 --- /dev/null +++ b/test/samples/json/history.json @@ -0,0 +1,236 @@ +{ + "identifier": "periods-of-history", + "serial": "item_547481ffc7445711059654", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "periods-of-history", + "title": "Periods of History", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547481ffc7431683168069", + "body": "

    The history of mankind is an unfailing source of\ninspiration for every human being. But before knowing in-depth the\nhistory of the world, you should know its major periods.

    {{interaction_orderinteraction_547481ffc8c1b803673841}}\n
    ", + "elements": { + "interaction_orderinteraction_547481ffc8c1b803673841": { + "serial": "interaction_orderinteraction_547481ffc8c1b803673841", + "qtiClass": "orderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "id": "interaction", + "maxChoices": 4 + }, + "choices": { + "choice_simplechoice_547481ffc8ede696148422": { + "identifier": "Prehistory", + "serial": "choice_simplechoice_547481ffc8ede696148422", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Prehistory", + "fixed": false, + "id": "Prehistory" + }, + "body": { + "serial": "container_containerstatic_547481ffc8f61600710070", + "body": "Prehistory", + "elements": [], + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + } + }, + "choice_simplechoice_547481ffc8fdf820005158": { + "identifier": "Antiquity", + "serial": "choice_simplechoice_547481ffc8fdf820005158", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Antiquity", + "fixed": false, + "id": "Antiquity" + }, + "body": { + "serial": "container_containerstatic_547481ffc9000308440815", + "body": "Antiquity", + "elements": [], + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + } + }, + "choice_simplechoice_547481ffc9069153919004": { + "identifier": "MiddleAges", + "serial": "choice_simplechoice_547481ffc9069153919004", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "MiddleAges", + "fixed": false, + "id": "MiddleAges" + }, + "body": { + "serial": "container_containerstatic_547481ffc9088868830591", + "body": "Middle Ages : : In the history of Europe, the Middle Ages or medieval period lasted from the 5th to the 15th century. It began with the fall of the Western Roman Empire and merged into the Renaissance and the Age of Discovery. The Middle Ages is the middle period of the three traditional divisions of Western history: classical antiquity, the medieval period, and the modern period. The medieval period is itself subdivided into the Early, High, and Late Middle Ages.", + "elements": [], + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + } + }, + "choice_simplechoice_547481ffc90ee936344449": { + "identifier": "ModernEra", + "serial": "choice_simplechoice_547481ffc90ee936344449", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "ModernEra", + "fixed": false, + "id": "ModernEra" + }, + "body": { + "serial": "container_containerstatic_547481ffc910c364964850", + "body": "Modern Era", + "elements": [], + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + } + }, + "choice_simplechoice_547481ffc916f507312761": { + "identifier": "ContemporaryEra", + "serial": "choice_simplechoice_547481ffc916f507312761", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "ContemporaryEra", + "fixed": false, + "id": "ContemporaryEra" + }, + "body": { + "serial": "container_containerstatic_547481ffc918d027900688", + "body": "Contemporary Era", + "elements": [], + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_547481ffc8df6161124029", + "body": "Use your mouse to drag and drop periods of history in the correct\norder, from the top to the bottom of the screen. When your answer\nis correctly set, click the Validate button.", + "elements": [], + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + } + } + }, + "debug": { + "relatedItem": "item_547481ffc7445711059654" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": { + }, + "outcomes": { + "outcomedeclaration_547481ffc89d5513551552": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547481ffc89d5513551552", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "integer" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547481ffc88ce269348905": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547481ffc88ce269348905", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "identifier" + }, + "correctResponses": [ + "Prehistory", + "Antiquity", + "MiddleAges", + "ModernEra", + "ContemporaryEra" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547481ffc9336026044001", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/inlineModalFeedback.json b/test/samples/json/inlineModalFeedback.json new file mode 100644 index 00000000..71862a7c --- /dev/null +++ b/test/samples/json/inlineModalFeedback.json @@ -0,0 +1,1706 @@ +{ + "identifier": "i1452154573951559", + "serial": "item_5693b5fcf2627607993150", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1452154573951559", + "title": "Item 12", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-sprint17", + "class": "" + }, + "body": { + "serial": "container_containeritembody_5693b5fcf260a483341775", + "body": "\n
    \n
    \n {{interaction_choiceinteraction_5693b5fd07a38879270839}}\n <\/div>\n
    \n {{interaction_orderinteraction_5693b5fd0b3fa511907370}}\n <\/div>\n <\/div>\n
    \n
    Plusieurs variations de Lorem Ipsum peuvent \u00eatre trouv\u00e9es ici ou l\u00e0, mais la majeure partie d'entre elles a \u00e9t\u00e9 alt\u00e9r\u00e9e par l'addition d'humour ou de mots al\u00e9atoires qui ne ressemblent pas une seconde \u00e0 du texte {{interaction_textentryinteraction_5693b5fd0d809029281373}}. Si vous voulez utiliser un passage du Lorem Ipsum, vous devez \u00eatre s\u00fbr qu'il n'y a rien d'embarrassant cach\u00e9 dans le texte. Tous les g\u00e9n\u00e9rateurs de Lorem Ipsum sur Internet tendent \u00e0 reproduire le m\u00eame extrait sans fin, ce qui fait de lipsum.com le seul vrai g\u00e9n\u00e9rateur de Lorem Ipsum. Iil utilise un dictionnaire de plus de 200 mots latins, en combinaison de \u00a0{{interaction_inlinechoiceinteraction_5693b5fd0da03570969231}}plusieurs structures de phrases, pour g\u00e9n\u00e9rer un Lorem Ipsum irr\u00e9prochable. Le Lorem Ipsum ainsi obtenu ne contient aucune r\u00e9p\u00e9tition, ni ne contient des mots farfelus, ou des touches d'humour.<\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_5693b5fd07a38879270839": { + "serial": "interaction_choiceinteraction_5693b5fd07a38879270839", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "choices": { + "choice_simplechoice_5693b5fd086c7296103210": { + "identifier": "choice_1", + "serial": "choice_simplechoice_5693b5fd086c7296103210", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd08786813443209", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "choice_simplechoice_5693b5fd09052611995928": { + "identifier": "choice_2", + "serial": "choice_simplechoice_5693b5fd09052611995928", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0908d263098734", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "choice_simplechoice_5693b5fd09905707261459": { + "identifier": "choice_3", + "serial": "choice_simplechoice_5693b5fd09905707261459", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd09940636392226", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "choice_simplechoice_5693b5fd0a1b0789264674": { + "identifier": "choice_4", + "serial": "choice_simplechoice_5693b5fd0a1b0789264674", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0a1e9595189237", + "body": "choice #4", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "choice_simplechoice_5693b5fd0aaac302074911": { + "identifier": "choice_5", + "serial": "choice_simplechoice_5693b5fd0aaac302074911", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0aae7344125138", + "body": "choice #5", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5693b5fd07ce0043711983", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "interaction_orderinteraction_5693b5fd0b3fa511907370": { + "serial": "interaction_orderinteraction_5693b5fd0b3fa511907370", + "qtiClass": "orderInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "shuffle": false, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "choices": { + "choice_simplechoice_5693b5fd0bd70871984446": { + "identifier": "choice_6", + "serial": "choice_simplechoice_5693b5fd0bd70871984446", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0bdb1067477041", + "body": "choice #1", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "choice_simplechoice_5693b5fd0c5fb727510437": { + "identifier": "choice_7", + "serial": "choice_simplechoice_5693b5fd0c5fb727510437", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0c633798155878", + "body": "choice #2", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "choice_simplechoice_5693b5fd0ce94425015632": { + "identifier": "choice_8", + "serial": "choice_simplechoice_5693b5fd0ce94425015632", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_8", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0cece784725857", + "body": "choice #3", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "prompt": { + "serial": "container_containerstatic_5693b5fd0b50d240757035", + "body": "", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "interaction_textentryinteraction_5693b5fd0d809029281373": { + "serial": "interaction_textentryinteraction_5693b5fd0d809029281373", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_2", + "base": 10, + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "choices": {} + }, + "interaction_inlinechoiceinteraction_5693b5fd0da03570969231": { + "serial": "interaction_inlinechoiceinteraction_5693b5fd0da03570969231", + "qtiClass": "inlineChoiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_3", + "shuffle": false, + "required": false + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "choices": { + "choice_inlinechoice_5693b5fd0db30396685801": { + "identifier": "choice_9", + "serial": "choice_inlinechoice_5693b5fd0db30396685801", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_9", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "text": "choice #1" + }, + "choice_inlinechoice_5693b5fd0db75859726587": { + "identifier": "choice_10", + "serial": "choice_inlinechoice_5693b5fd0db75859726587", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_10", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "text": "choice #2" + }, + "choice_inlinechoice_5693b5fd0dbae163724963": { + "identifier": "choice_11", + "serial": "choice_inlinechoice_5693b5fd0dbae163724963", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "choice_11", + "fixed": false, + "showHide": "show" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "text": "choice #3" + } + } + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": { + "stylesheet_5693b5fcf2d9b789037714": { + "serial": "stylesheet_5693b5fcf2d9b789037714", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "outcomes": { + "outcomedeclaration_5693b5fcf3af6466606451": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5693b5fcf3af6466606451", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3dd7206642690": { + "identifier": "FEEDBACK_1", + "serial": "outcomedeclaration_5693b5fcf3dd7206642690", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_1", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3e0a126994821": { + "identifier": "FEEDBACK_2", + "serial": "outcomedeclaration_5693b5fcf3e0a126994821", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_2", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3e33566644974": { + "identifier": "FEEDBACK_3", + "serial": "outcomedeclaration_5693b5fcf3e33566644974", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_3", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3e5c828133651": { + "identifier": "FEEDBACK_4", + "serial": "outcomedeclaration_5693b5fcf3e5c828133651", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_4", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3e83121743970": { + "identifier": "FEEDBACK_5", + "serial": "outcomedeclaration_5693b5fcf3e83121743970", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_5", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3eaa251847950": { + "identifier": "FEEDBACK_6", + "serial": "outcomedeclaration_5693b5fcf3eaa251847950", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_6", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3ed0028662708": { + "identifier": "FEEDBACK_7", + "serial": "outcomedeclaration_5693b5fcf3ed0028662708", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_7", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3ef7598961380": { + "identifier": "FEEDBACK_8", + "serial": "outcomedeclaration_5693b5fcf3ef7598961380", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_8", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3f1c986762850": { + "identifier": "FEEDBACK_9", + "serial": "outcomedeclaration_5693b5fcf3f1c986762850", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_9", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3f43985795302": { + "identifier": "FEEDBACK_10", + "serial": "outcomedeclaration_5693b5fcf3f43985795302", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_10", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3f69476241034": { + "identifier": "FEEDBACK_11", + "serial": "outcomedeclaration_5693b5fcf3f69476241034", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_11", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + }, + "outcomedeclaration_5693b5fcf3f8f334851994": { + "identifier": "FEEDBACK_12", + "serial": "outcomedeclaration_5693b5fcf3f8f334851994", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "FEEDBACK_12", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5693b5fcf331d319058977": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5693b5fcf331d319058977", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "mapping": [ + ], + "areaMapping": [ + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "choice_1" + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": { + "response_simplefeedbackrule_5693b5fd0ebd4814560914": { + "serial": "response_simplefeedbackrule_5693b5fd0ebd4814560914", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf331d319058977", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3dd7206642690", + "feedbackThen": "feedback_modalfeedback_5693b5fd0013b203796511", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0ec70093909127": { + "serial": "response_simplefeedbackrule_5693b5fd0ec70093909127", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf331d319058977", + "comparedValue": 0, + "condition": "incorrect", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3e0a126994821", + "feedbackThen": "feedback_modalfeedback_5693b5fd00b3b998884436", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0ecdb118145384": { + "serial": "response_simplefeedbackrule_5693b5fd0ecdb118145384", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf331d319058977", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3e33566644974", + "feedbackThen": "feedback_modalfeedback_5693b5fd01691505296817", + "feedbackElse": "" + } + } + }, + "responsedeclaration_5693b5fcf384d878235179": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_5693b5fcf384d878235179", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "ordered", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "mapping": [ + ], + "areaMapping": [ + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "choice_6", + "choice_7" + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": { + "response_simplefeedbackrule_5693b5fd0ed42860596199": { + "serial": "response_simplefeedbackrule_5693b5fd0ed42860596199", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf384d878235179", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3e5c828133651", + "feedbackThen": "feedback_modalfeedback_5693b5fd02041503394066", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0eda6194957665": { + "serial": "response_simplefeedbackrule_5693b5fd0eda6194957665", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf384d878235179", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3e83121743970", + "feedbackThen": "feedback_modalfeedback_5693b5fd0299e647946185", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0ee2c433342374": { + "serial": "response_simplefeedbackrule_5693b5fd0ee2c433342374", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf384d878235179", + "comparedValue": 0, + "condition": "incorrect", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3f43985795302", + "feedbackThen": "feedback_modalfeedback_5693b5fd059c0517610274", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0eebb301613364": { + "serial": "response_simplefeedbackrule_5693b5fd0eebb301613364", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf384d878235179", + "comparedValue": 0, + "condition": "incorrect", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3f69476241034", + "feedbackThen": "feedback_modalfeedback_5693b5fd06341755142772", + "feedbackElse": "" + } + } + }, + "responsedeclaration_5693b5fcf390a823025404": { + "identifier": "RESPONSE_2", + "serial": "responsedeclaration_5693b5fcf390a823025404", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_2", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "mapping": [ + ], + "areaMapping": [ + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "ok" + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": { + "response_simplefeedbackrule_5693b5fd0ef24825855172": { + "serial": "response_simplefeedbackrule_5693b5fd0ef24825855172", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf390a823025404", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3eaa251847950", + "feedbackThen": "feedback_modalfeedback_5693b5fd03334090324173", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0ef89026683633": { + "serial": "response_simplefeedbackrule_5693b5fd0ef89026683633", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf390a823025404", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3ed0028662708", + "feedbackThen": "feedback_modalfeedback_5693b5fd03d5d073573971", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0efed494446572": { + "serial": "response_simplefeedbackrule_5693b5fd0efed494446572", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf390a823025404", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3ef7598961380", + "feedbackThen": "feedback_modalfeedback_5693b5fd046c8229793649", + "feedbackElse": "" + } + } + }, + "responsedeclaration_5693b5fcf399a360382718": { + "identifier": "RESPONSE_3", + "serial": "responsedeclaration_5693b5fcf399a360382718", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_3", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "mapping": [ + ], + "areaMapping": [ + ], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [ + "choice_9" + ], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": { + "response_simplefeedbackrule_5693b5fd0f051051955427": { + "serial": "response_simplefeedbackrule_5693b5fd0f051051955427", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf399a360382718", + "comparedValue": 0, + "condition": "correct", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3f1c986762850", + "feedbackThen": "feedback_modalfeedback_5693b5fd0504f367448702", + "feedbackElse": "" + }, + "response_simplefeedbackrule_5693b5fd0f0d4198789499": { + "serial": "response_simplefeedbackrule_5693b5fd0f0d4198789499", + "qtiClass": "_simpleFeedbackRule", + "comparedOutcome": "responsedeclaration_5693b5fcf399a360382718", + "comparedValue": 0, + "condition": "incorrect", + "feedbackOutcome": "outcomedeclaration_5693b5fcf3f8f334851994", + "feedbackThen": "feedback_modalfeedback_5693b5fd06d69761893710", + "feedbackElse": "" + } + } + } + }, + "feedbacks": { + "feedback_modalfeedback_5693b5fd0013b203796511": { + "identifier": "feedbackModal_1", + "serial": "feedback_modalfeedback_5693b5fd0013b203796511", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_1", + "outcomeIdentifier": "FEEDBACK_1", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0019c224916636", + "body": "\n
    right<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd00b3b998884436": { + "identifier": "feedbackModal_2", + "serial": "feedback_modalfeedback_5693b5fd00b3b998884436", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_2", + "outcomeIdentifier": "FEEDBACK_2", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5693b5fd00b96194999763", + "body": "\n
    wrong \n{{img_5693b5fd00c0b285814628}}\n<\/div>\n ", + "elements": { + "img_5693b5fd00c0b285814628": { + "serial": "img_5693b5fd00c0b285814628", + "qtiClass": "img", + "attributes": { + "src": "images.jpg", + "alt": "images", + "width": "51%" + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd01691505296817": { + "identifier": "feedbackModal_3", + "serial": "feedback_modalfeedback_5693b5fd01691505296817", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_3", + "outcomeIdentifier": "FEEDBACK_3", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd016ed250485436", + "body": "\n
    thiss is right<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd02041503394066": { + "identifier": "feedbackModal_4", + "serial": "feedback_modalfeedback_5693b5fd02041503394066", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_4", + "outcomeIdentifier": "FEEDBACK_4", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd020a0037739552", + "body": "\n
    Correct<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd0299e647946185": { + "identifier": "feedbackModal_5", + "serial": "feedback_modalfeedback_5693b5fd0299e647946185", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_5", + "outcomeIdentifier": "FEEDBACK_5", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd029fd418191161", + "body": "\n
    correct<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd03334090324173": { + "identifier": "feedbackModal_6", + "serial": "feedback_modalfeedback_5693b5fd03334090324173", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_6", + "outcomeIdentifier": "FEEDBACK_6", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd03396465715977", + "body": "\n
    correct<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd03d5d073573971": { + "identifier": "feedbackModal_7", + "serial": "feedback_modalfeedback_5693b5fd03d5d073573971", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_7", + "outcomeIdentifier": "FEEDBACK_7", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd03dc2297311839", + "body": "\n
    correct<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd046c8229793649": { + "identifier": "feedbackModal_8", + "serial": "feedback_modalfeedback_5693b5fd046c8229793649", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_8", + "outcomeIdentifier": "FEEDBACK_8", + "showHide": "show", + "title": "modal feedback title" + }, + "body": { + "serial": "container_containerstatic_5693b5fd0472d649477493", + "body": "\n
    Some feedback text.<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd0504f367448702": { + "identifier": "feedbackModal_9", + "serial": "feedback_modalfeedback_5693b5fd0504f367448702", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_9", + "outcomeIdentifier": "FEEDBACK_9", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd050b8846100030", + "body": "\n
    correct<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd059c0517610274": { + "identifier": "feedbackModal_10", + "serial": "feedback_modalfeedback_5693b5fd059c0517610274", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_10", + "outcomeIdentifier": "FEEDBACK_10", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd05a2b155001086", + "body": "\n
    wrong<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd06341755142772": { + "identifier": "feedbackModal_11", + "serial": "feedback_modalfeedback_5693b5fd06341755142772", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_11", + "outcomeIdentifier": "FEEDBACK_11", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd063b0365499154", + "body": "\n
    wrong<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "feedback_modalfeedback_5693b5fd06d69761893710": { + "identifier": "feedbackModal_12", + "serial": "feedback_modalfeedback_5693b5fd06d69761893710", + "qtiClass": "modalFeedback", + "attributes": { + "identifier": "feedbackModal_12", + "outcomeIdentifier": "FEEDBACK_12", + "showHide": "show", + "title": "" + }, + "body": { + "serial": "container_containerstatic_5693b5fd06ddd231744616", + "body": "\n
    wrong<\/div>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + }, + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + } + } + }, + "responseProcessing": { + "serial": "response_templatesdriven_5693b5fd0f2cc932881970", + "qtiClass": "responseProcessing", + "attributes": [ + ], + "debug": { + "relatedItem": "item_5693b5fcf2627607993150" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_1" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_1" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_2" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_2" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_3" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_3" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_4" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_4" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_5" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_5" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_10" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_10" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_11" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_11" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_6" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_6" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_7" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_7" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_2" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_2" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_8" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_8" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "sum", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "SCORE" + } + }, + { + "qtiClass": "baseValue", + "attributes": { + "baseType": "integer" + }, + "value": "1" + } + ] + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_9" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_9" + } + } + ] + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "not", + "expressions": [ + { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_3" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_3" + } + } + ] + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "FEEDBACK_12" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "identifier" + }, + "value": "feedbackModal_12" + } + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/test/samples/json/lowcost-flying.json b/test/samples/json/lowcost-flying.json new file mode 100644 index 00000000..bfdd50d6 --- /dev/null +++ b/test/samples/json/lowcost-flying.json @@ -0,0 +1,205 @@ +{ + "identifier": "graphicAssociate", + "serial": "item_547dd6b98b5d9725406677", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "graphicAssociate", + "title": "Low-cost Flying", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd6b98b5c1339656603", + "body": "

    Frizz, a new low cost airline, already operates a service connecting Manchester and\n\t\t\tEdinburgh but has recently opened two new routes: a service between London and Edinburgh\n\t\t\tand one between London and Manchester.

    \n {{interaction_graphicassociateinteraction_547dd6b98d28d814892882}}", + "elements": { + "interaction_graphicassociateinteraction_547dd6b98d28d814892882": { + "serial": "interaction_graphicassociateinteraction_547dd6b98d28d814892882", + "qtiClass": "graphicAssociateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxAssociations": 3, + "minAssociations": 0 + }, + "choices": { + "choice_associablehotspot_547dd6b98d92f499532741": { + "identifier": "A", + "serial": "choice_associablehotspot_547dd6b98d92f499532741", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "A", + "fixed": false, + "matchMax": 3, + "matchMin": 0, + "shape": "circle", + "coords": "77,115,8" + } + }, + "choice_associablehotspot_547dd6b98db4e771189683": { + "identifier": "B", + "serial": "choice_associablehotspot_547dd6b98db4e771189683", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "B", + "fixed": false, + "matchMax": 3, + "matchMin": 0, + "shape": "circle", + "coords": "118,184,8" + } + }, + "choice_associablehotspot_547dd6b98dbf4037425744": { + "identifier": "C", + "serial": "choice_associablehotspot_547dd6b98dbf4037425744", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "C", + "fixed": false, + "matchMax": 3, + "matchMin": 0, + "shape": "circle", + "coords": "150,235,8" + } + }, + "choice_associablehotspot_547dd6b98dc89745742172": { + "identifier": "D", + "serial": "choice_associablehotspot_547dd6b98dc89745742172", + "qtiClass": "associableHotspot", + "attributes": { + "identifier": "D", + "fixed": false, + "matchMax": 3, + "matchMin": 0, + "shape": "circle", + "coords": "96,114,8" + } + } + }, + "prompt": { + "serial": "container_containerstatic_547dd6b98d3ff769595498", + "body": "Mark the airline's new routes on the airport map:", + "elements": [], + "debug": { + "relatedItem": "item_547dd6b98b5d9725406677" + } + }, + "object": { + "serial": "object_547dd6b98dd47368788870", + "qtiClass": "object", + "attributes": { + "data": "images/ukair.png", + "type": "image/png", + "width": 206, + "height": 280 + }, + "_alt": "UK Map" + } + } + }, + "debug": { + "relatedItem": "item_547dd6b98b5d9725406677" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd6b98be6c947256752": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd6b98be6c947256752", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd6b98b875594184481": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd6b98b875594184481", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "correctResponses": [ + "C B", + "C D" + ], + "mapping": { + "A B": "-1", + "A C": "-1", + "A D": "-1", + "B C": "1", + "B D": "-1", + "C D": "1" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": 0, + "lowerBound": "0" + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd6b98e0c2599340802", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } +} diff --git a/test/samples/json/media/audio.json b/test/samples/json/media/audio.json new file mode 100644 index 00000000..0aa42019 --- /dev/null +++ b/test/samples/json/media/audio.json @@ -0,0 +1,159 @@ +{ + "identifier": "i1429259831305858", + "serial": "item_5530c8298a9b6075951451", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1429259831305858", + "title": "Item title", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0.0" + }, + "body": { + "serial": "container_containeritembody_5530c8298a976705403298", + "body": "
    \n
    \n {{interaction_mediainteraction_5530c82990e4d481234371}}\n <\/div>\n <\/div>", + "elements": { + "interaction_mediainteraction_5530c82990e4d481234371": { + "serial": "interaction_mediainteraction_5530c82990e4d481234371", + "qtiClass": "mediaInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "autostart": false, + "minPlays": 0, + "maxPlays": 0, + "loop": false + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_5530c82992230509730174", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_5530c8298a9b6075951451" + } + }, + "object": { + "serial": "object_5530c82992e1b401216320", + "qtiClass": "object", + "attributes": { + "data": "sample.mp3", + "type": "audio\/mpeg", + "width": 395, + "height": 30 + } + } + } + }, + "debug": { + "relatedItem": "item_5530c8298a9b6075951451" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": { + }, + "outcomes": { + "outcomedeclaration_5530c8298f185097883591": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5530c8298f185097883591", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5530c8298e640583330185": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5530c8298e640583330185", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "integer" + }, + "correctResponses": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_5530c82993d8f206059909", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + } +} diff --git a/test/samples/json/media/sample.mp3 b/test/samples/json/media/sample.mp3 new file mode 100644 index 00000000..38d65399 Binary files /dev/null and b/test/samples/json/media/sample.mp3 differ diff --git a/test/samples/json/media/sample.mp4 b/test/samples/json/media/sample.mp4 new file mode 100644 index 00000000..295e9e22 Binary files /dev/null and b/test/samples/json/media/sample.mp4 differ diff --git a/test/samples/json/media/video.json b/test/samples/json/media/video.json new file mode 100644 index 00000000..3e314881 --- /dev/null +++ b/test/samples/json/media/video.json @@ -0,0 +1,159 @@ +{ + "identifier": "i1429259831305858", + "serial": "item_5530c8298a9b6075951451", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1429259831305858", + "title": "Item title", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0.0" + }, + "body": { + "serial": "container_containeritembody_5530c8298a976705403298", + "body": "
    \n
    \n {{interaction_mediainteraction_5530c82990e4d481234371}}\n <\/div>\n <\/div>", + "elements": { + "interaction_mediainteraction_5530c82990e4d481234371": { + "serial": "interaction_mediainteraction_5530c82990e4d481234371", + "qtiClass": "mediaInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "autostart": false, + "minPlays": 0, + "maxPlays": 0, + "loop": false + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_5530c82992230509730174", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_5530c8298a9b6075951451" + } + }, + "object": { + "serial": "object_5530c82992e1b401216320", + "qtiClass": "object", + "attributes": { + "data": "sample.mp4", + "type": "video\/mp4", + "width": 395, + "height": 270 + } + } + } + }, + "debug": { + "relatedItem": "item_5530c8298a9b6075951451" + } + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": { + }, + "outcomes": { + "outcomedeclaration_5530c8298f185097883591": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5530c8298f185097883591", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5530c8298e640583330185": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5530c8298e640583330185", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "integer" + }, + "correctResponses": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_5530c82993d8f206059909", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + } +} diff --git a/test/samples/json/pluto.json b/test/samples/json/pluto.json new file mode 100644 index 00000000..baea0b28 --- /dev/null +++ b/test/samples/json/pluto.json @@ -0,0 +1,425 @@ +{ + "type": "qti", + "data": { + "identifier": "i143015279126631876", + "serial": "item_55a61df4b73e7377599938", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i143015279126631876", + "title": "Pluto", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.1.0-rc01" + }, + "body": { + "serial": "container_containeritembody_55a61df4b73c4975672160", + "body": "\n
    \n
    \n
    \n

    Pluto<\/strong> (minor-planet designation: 134340 Pluto) is a dwarf planet in the Kuiper belt, a ring of trans-Neptunian objects. It was the first such object to be discovered. It is the largest and second-most massive known dwarf planet in the Solar System and the ninth-largest and tenth-most-massive known object directly orbiting the Sun. It is the largest known trans-Neptunian object by volume but is less massive than Eris, a dwarf planet in the scattered disc. Like other Kuiper belt objects, Pluto is primarily made of ice and rock[14] and is relatively small\u2014about one-sixth the mass of the Moon and one-third its volume. It has a moderately eccentric and inclined orbit during which it ranges from 30 to 49\u00a0astronomical units (4.4\u20137.3 billion\u00a0km) from the Sun. This means that Pluto periodically comes closer to the Sun than Neptune, but a stable orbital resonance with Neptune prevents them from colliding. In 2014, Pluto was 32.6 AU from the Sun. Light from the Sun takes about 5.5 hours to reach Pluto at its average distance (39.4\u00a0AU).[15]<\/p>\n

    Pluto was discovered in 1930 by Clyde Tombaugh, and was originally considered the ninth planet from the Sun. After 1992, its status as a planet fell into question following the discovery of several similarly sized objects in the Kuiper belt. In 2005, Eris, which is 27% more massive than Pluto, was discovered, which led the International Astronomical Union (IAU) to define the term \"planet\" formally for the first time the following year.[16] This definition excluded Pluto and reclassified it as a member of the new \"dwarf planet\" category (and specifically as a plutoid).[17] Some astronomers believe Pluto should still be considered a planet.[18][19][20]<\/p>\n

    Pluto has five known moons: Charon (the largest, with a diameter just over half that of Pluto), Styx, Nix, Kerberos, and Hydra.[21] Pluto and Charon are sometimes considered a binary system because the barycenter of their orbits does not lie within either body.[22] The IAU has not formalized a definition for binary dwarf planets, and Charon is officially classified as a moon of Pluto.[23]<\/p>\n

    On 14 July 2015, the New Horizons spacecraft became the first spacecraft to flyby Pluto.[24][25] On its brief flyby, New Horizons made detailed measurements and observations of Pluto, and its moons.[26]<\/p>\n <\/div>\n <\/div>\n

    \n
    \n {{interaction_choiceinteraction_55a61df4b8c7b443971321}}\n <\/div>\n
    \n {{interaction_choiceinteraction_55a61df4bb741463851762}}\n <\/div>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_55a61df4b8c7b443971321": { + "serial": "interaction_choiceinteraction_55a61df4b8c7b443971321", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + }, + "choices": { + "choice_simplechoice_55a61df4b99ff374060196": { + "identifier": "choice_1", + "serial": "choice_simplechoice_55a61df4b99ff374060196", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4b9bc3449052826", + "body": "A dwarf planet", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "choice_simplechoice_55a61df4ba271594680909": { + "identifier": "choice_2", + "serial": "choice_simplechoice_55a61df4ba271594680909", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4ba2e1670644886", + "body": "A star", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "choice_simplechoice_55a61df4ba95d717107524": { + "identifier": "choice_3", + "serial": "choice_simplechoice_55a61df4ba95d717107524", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4ba9c9259737491", + "body": "An asteriod", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "choice_simplechoice_55a61df4bb014804651519": { + "identifier": "choice_4", + "serial": "choice_simplechoice_55a61df4bb014804651519", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_4", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4bb07f278203545", + "body": "A Neptun Moon", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + } + }, + "prompt": { + "serial": "container_containerstatic_55a61df4b9176422119353", + "body": "\n Pluto is a<\/strong>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + } + }, + "interaction_choiceinteraction_55a61df4bb741463851762": { + "serial": "interaction_choiceinteraction_55a61df4bb741463851762", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE_1", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + }, + "choices": { + "choice_simplechoice_55a61df4bbe54395236773": { + "identifier": "choice_5", + "serial": "choice_simplechoice_55a61df4bbe54395236773", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_5", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4bbec8394327553", + "body": "Kerberos", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "choice_simplechoice_55a61df4bc4b0581277275": { + "identifier": "choice_6", + "serial": "choice_simplechoice_55a61df4bc4b0581277275", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_6", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4bc521306794065", + "body": "Ganymede", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "choice_simplechoice_55a61df4bcb00215431629": { + "identifier": "choice_7", + "serial": "choice_simplechoice_55a61df4bcb00215431629", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_7", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4bcb6f258723331", + "body": "Europa", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "choice_simplechoice_55a61df4bd14a955563675": { + "identifier": "choice_8", + "serial": "choice_simplechoice_55a61df4bd14a955563675", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_8", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_55a61df4bd1c0142808761", + "body": "Calypso", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + } + }, + "prompt": { + "serial": "container_containerstatic_55a61df4bb88f799674734", + "body": "\n Which one is a Pluto Moon ?<\/strong>\n ", + "elements": {}, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + } + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + }, + "namespaces": { + "xml": "http:\/\/www.w3.org\/XML\/1998\/namespace", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance", + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1" + }, + "stylesheets": { + "stylesheet_55a61df4b7b8f022829903": { + "serial": "stylesheet_55a61df4b7b8f022829903", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + } + } + }, + "outcomes": { + "outcomedeclaration_55a61df4b8518275183836": { + "identifier": "SCORE", + "serial": "outcomedeclaration_55a61df4b8518275183836", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_55a61df4b8126364249414": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_55a61df4b8126364249414", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + }, + "correctResponses": [ + "choice_1" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + }, + "responsedeclaration_55a61df4b83ba637315106": { + "identifier": "RESPONSE_1", + "serial": "responsedeclaration_55a61df4b83ba637315106", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE_1", + "cardinality": "single", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_55a61df4b73e7377599938" + }, + "correctResponses": [ + "choice_6" + ], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_custom_55a61df4be352734831695", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "" + }, + "processingType": "custom", + "data": "\n \n \n \n \n \n <\/match>\n \n 1<\/baseValue>\n <\/setOutcomeValue>\n \n \n \n \n \n <\/match>\n \n 2<\/baseValue>\n <\/setOutcomeValue>\n <\/responseIf>\n <\/responseCondition>\n <\/responseIf>\n <\/responseCondition>\n <\/responseProcessing>", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }, + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE_1" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE_1" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "2" + } + } + ] + } + } + ] + } + } + ] + } + }, + "assets": { + "css": { + "style\/custom\/tao-user-styles.css": "style\/custom\/tao-user-styles.css" + } + } +} diff --git a/test/samples/json/postcard.json b/test/samples/json/postcard.json new file mode 100644 index 00000000..12bc5309 --- /dev/null +++ b/test/samples/json/postcard.json @@ -0,0 +1,100 @@ +{ + "identifier": "extendedText", + "serial": "item_547d89b1d6c23267948888", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "extendedText", + "title": "Writing a Postcard", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547d89b1d6c0c246247099", + "body": "

    Read this postcard from your English pen-friend, Sam.

    \n
    \n {{object_547d89b1db1ca294674790}}\n
    \n {{interaction_extendedtextinteraction_547d89b1d9db7634390944}}", + "elements": { + "interaction_extendedtextinteraction_547d89b1d9db7634390944": { + "serial": "interaction_extendedtextinteraction_547d89b1d9db7634390944", + "qtiClass": "extendedTextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 500, + "minStrings": 0, + "expectedLines": 15, + "format": "plain" + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_547d89b1daf57997005360", + "body": "Write Sam a long letter. Answer the questions. Write 150 words (500 chars).", + "elements": [], + "debug": { + "relatedItem": "item_547d89b1d6c23267948888" + } + } + }, + "object_547d89b1db1ca294674790": { + "serial": "object_547d89b1db1ca294674790", + "qtiClass": "object", + "attributes": { + "data": "images/postcard.png", + "type": "image/png" + }, + "_alt": "\n
    \n

    Here is a postcard of my town. Please send me
    a postcard from your town.\n\t\t\t\t\t\tWhat size is your
    town? What is the nicest part of your town?
    \n\t\t\t\t\t\tWhere do you go in the evenings?
    Sam.

    \n
    \n " + } + }, + "debug": { + "relatedItem": "item_547d89b1d6c23267948888" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547d89b1d8d81678487868": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547d89b1d8d81678487868", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547d89b1d82c0946659679": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547d89b1d82c0946659679", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "correctResponses": [], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_547d89b1dbc80108048924", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "" + } + } diff --git a/test/samples/json/postcards.json b/test/samples/json/postcards.json new file mode 100644 index 00000000..72690a8b --- /dev/null +++ b/test/samples/json/postcards.json @@ -0,0 +1,100 @@ +{ + "identifier": "extendedTextMultiple", + "serial": "item_547d8a1386e24123048974", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "extendedTextMultiple", + "title": "Writing a Postcard", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547d8a1386e12595458266", + "body": "

    Read this postcard from your English pen-friend, Sam.

    \n
    \n {{object_547d8a13879a0498683612}}\n
    \n {{interaction_extendedtextinteraction_547d8a1387652196321125}}", + "elements": { + "interaction_extendedtextinteraction_547d8a1387652196321125": { + "serial": "interaction_extendedtextinteraction_547d8a1387652196321125", + "qtiClass": "extendedTextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 2, + "maxStrings": 5, + "minStrings": 0, + "format": "plain" + }, + "choices": [], + "prompt": { + "serial": "container_containerstatic_547d8a1387879706061649", + "body": "Count from 1 to 5", + "elements": [], + "debug": { + "relatedItem": "item_547d8a1386e24123048974" + } + } + }, + "object_547d8a13879a0498683612": { + "serial": "object_547d8a13879a0498683612", + "qtiClass": "object", + "attributes": { + "data": "images/postcard.png", + "type": "image/png" + }, + "_alt": "\n
    \n

    Here is a postcard of my town. Please send me
    a postcard from your town.\n\t\t\t\t\t\tWhat size is your
    town? What is the nicest part of your town?
    \n\t\t\t\t\t\tWhere do you go in the evenings?
    Sam.

    \n
    \n " + } + }, + "debug": { + "relatedItem": "item_547d8a1386e24123048974" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547d8a1387403735234720": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547d8a1387403735234720", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547d8a13870b8831331129": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547d8a13870b8831331129", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "ordered", + "baseType": "integer" + }, + "correctResponses": [], + "mapping": [], + "areaMapping": [], + "howMatch": null, + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_custom_547d8a1387bc1834140531", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "custom", + "data": "" + } +} diff --git a/test/samples/json/richardIII-1.json b/test/samples/json/richardIII-1.json new file mode 100644 index 00000000..2e0ceb2f --- /dev/null +++ b/test/samples/json/richardIII-1.json @@ -0,0 +1,161 @@ +{ + "identifier": "inlineChoice", + "serial": "item_547464dbc71ca216551726", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "inlineChoice", + "title": "Richard III (Take 2)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547464dbc71b2977728057", + "body": "

    Identify the missing word in this famous quote from Shakespeare's Richard III.

    \n
    \n

    Now is the winter of our discontent
    Made glorious summer by this sun of\n\t\t\t\t\t{{interaction_inlinechoiceinteraction_547464dbc7afc574464937}};
    And all the clouds that lour'd upon our house
    \n\t\t\t\tIn the deep bosom of the ocean buried.

    \n
    ", + "elements": { + "interaction_inlinechoiceinteraction_547464dbc7afc574464937": { + "serial": "interaction_inlinechoiceinteraction_547464dbc7afc574464937", + "qtiClass": "inlineChoiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "required": false + }, + "choices": { + "choice_inlinechoice_547464dbc7c3c465126979": { + "identifier": "G", + "serial": "choice_inlinechoice_547464dbc7c3c465126979", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "G", + "fixed": false + }, + "text": "Gloucester" + }, + "choice_inlinechoice_547464dbc7ce2756509667": { + "identifier": "L", + "serial": "choice_inlinechoice_547464dbc7ce2756509667", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "L", + "fixed": false + }, + "text": "Lancaster" + }, + "choice_inlinechoice_547464dbc7d18579789437": { + "identifier": "Y", + "serial": "choice_inlinechoice_547464dbc7d18579789437", + "qtiClass": "inlineChoice", + "attributes": { + "identifier": "Y", + "fixed": false + }, + "text": "York" + } + } + } + }, + "debug": { + "relatedItem": "item_547464dbc71ca216551726" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547464dbc7894288258313": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547464dbc7894288258313", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547464dbc747b652530353": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547464dbc747b652530353", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "Y" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547464dbc7ed2120730680", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/richardIII-2.json b/test/samples/json/richardIII-2.json new file mode 100644 index 00000000..82def67e --- /dev/null +++ b/test/samples/json/richardIII-2.json @@ -0,0 +1,133 @@ +{ + "identifier": "textEntry", + "serial": "item_54748138548cd268375778", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "textEntry", + "title": "Richard III (Take 3)", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_54748138548b7862153553", + "body": "

    Identify the missing word in this famous quote from Shakespeare's Richard III.

    \n
    \n

    Now is the winter of our discontent
    Made glorious summer by this sun of\n\t\t\t\t\t{{interaction_textentryinteraction_547481385553c671856068}};
    \n\t\t\t\tAnd all the clouds that lour'd upon our house
    In the deep bosom of the ocean\n\t\t\t\tburied.

    \n
    ", + "elements": { + "interaction_textentryinteraction_547481385553c671856068": { + "serial": "interaction_textentryinteraction_547481385553c671856068", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 15 + }, + "choices": [] + } + }, + "debug": { + "relatedItem": "item_54748138548cd268375778" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_5474813854cfa847285210": { + "identifier": "SCORE", + "serial": "outcomedeclaration_5474813854cfa847285210", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_5474813854b8b603267818": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_5474813854b8b603267818", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "correctResponses": [ + "York" + ], + "mapping": { + "York": "1", + "york": "0.5" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_5474813856025271209814", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/rivals.json b/test/samples/json/rivals.json new file mode 100644 index 00000000..7e171045 --- /dev/null +++ b/test/samples/json/rivals.json @@ -0,0 +1,256 @@ +{ + "identifier": "associate", + "serial": "item_54787e6dacd93524247481", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "associate", + "title": "Shakespearian Rivals", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_54787e6dacd7b198753836", + "body": "{{interaction_associateinteraction_54787e6dad70d437146538}}", + "elements": { + "interaction_associateinteraction_54787e6dad70d437146538": { + "serial": "interaction_associateinteraction_54787e6dad70d437146538", + "qtiClass": "associateInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxAssociations": 3, + "minAssociations": 0 + }, + "choices": { + "choice_simpleassociablechoice_54787e6dad92f863480296": { + "identifier": "A", + "serial": "choice_simpleassociablechoice_54787e6dad92f863480296", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "A", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54787e6dad9e8693592338", + "body": "Antonio", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + }, + "choice_simpleassociablechoice_54787e6dada72153507621": { + "identifier": "C", + "serial": "choice_simpleassociablechoice_54787e6dada72153507621", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "C", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54787e6dadaa2616211247", + "body": "Capulet", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + }, + "choice_simpleassociablechoice_54787e6dadb13033133436": { + "identifier": "D", + "serial": "choice_simpleassociablechoice_54787e6dadb13033133436", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "D", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54787e6dadb40695876709", + "body": "Demetrius", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + }, + "choice_simpleassociablechoice_54787e6dadbae997640332": { + "identifier": "L", + "serial": "choice_simpleassociablechoice_54787e6dadbae997640332", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "L", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54787e6dadbda418176012", + "body": "Lysander", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + }, + "choice_simpleassociablechoice_54787e6dadc47042575691": { + "identifier": "M", + "serial": "choice_simpleassociablechoice_54787e6dadc47042575691", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "M", + "fixed": false, + "matchMax": 1, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54787e6dadc72722745137", + "body": "Montague", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + }, + "choice_simpleassociablechoice_54787e6dadcdd949770698": { + "identifier": "P", + "serial": "choice_simpleassociablechoice_54787e6dadcdd949770698", + "qtiClass": "simpleAssociableChoice", + "attributes": { + "identifier": "P", + "fixed": false, + "matchMax": 2, + "matchMin": 0 + }, + "body": { + "serial": "container_containerstatic_54787e6dadd08544977300", + "body": "Prospero", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_54787e6dad853189369793", + "body": "Hidden in this list of characters from famous Shakespeare plays are three pairs\n\t\t\t\tof rivals. Can you match each character to his adversary?", + "elements": [], + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + } + } + }, + "debug": { + "relatedItem": "item_54787e6dacd93524247481" + } + }, + "namespaces": { + "": "http://www.imsglobal.org/xsd/imsqti_v2p1", + "xsi": "http://www.w3.org/2001/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_54787e6dad4d2957887549": { + "identifier": "SCORE", + "serial": "outcomedeclaration_54787e6dad4d2957887549", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_54787e6dacfde493993694": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_54787e6dacfde493993694", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "pair" + }, + "correctResponses": [ + "A P", + "C M", + "D L" + ], + "mapping": { + "A P": "2", + "C M": "1", + "D L": "1" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_54787e6dade83075046789", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } +} diff --git a/test/samples/json/sentence-error.json b/test/samples/json/sentence-error.json new file mode 100644 index 00000000..8391ec31 --- /dev/null +++ b/test/samples/json/sentence-error.json @@ -0,0 +1,248 @@ +{ + "identifier": "hottext", + "serial": "item_547dd79b8be3e240017126", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "hottext", + "title": "Identifying Sentence Errors", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd79b8be24092340443", + "body": "{{rubricblock_547dd79b8cfda580861579}}\n {{interaction_hottextinteraction_547dd79b8d52c373545736}}", + "elements": { + "rubricblock_547dd79b8cfda580861579": { + "serial": "rubricblock_547dd79b8cfda580861579", + "qtiClass": "rubricBlock", + "attributes": { + "view": [ + "candidate" + ] + }, + "body": { + "serial": "container_containerstatic_547dd79b8d195914915139", + "body": "

    Select the error in the following passage of text (or No Error if there is\n\t\t\t\tnone).

    ", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + }, + "interaction_hottextinteraction_547dd79b8d52c373545736": { + "serial": "interaction_hottextinteraction_547dd79b8d52c373545736", + "qtiClass": "hottextInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "maxChoices": 1, + "minChoices": 0 + }, + "body": { + "serial": "container_containerhottext_547dd79b8d7f1931717195", + "body": "

    Sponsors of the Olympic Games {{choice_hottext_547dd79b8d9f4774514379}}\n\t\t\t\tadvertising time on United States television {{choice_hottext_547dd79b8daf5284589059}}\n\t\t\t\t{{choice_hottext_547dd79b8db64175149202}} a dozen international firms {{choice_hottext_547dd79b8dbcb263172857}} names are familiar to American consumers.\n\t\t\t\t\t{{choice_hottext_547dd79b8dc33869435046}}\n\t\t\t

    ", + "elements": { + "choice_hottext_547dd79b8d9f4774514379": { + "identifier": "A", + "serial": "choice_hottext_547dd79b8d9f4774514379", + "qtiClass": "hottext", + "attributes": { + "identifier": "A", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_547dd79b8da85686601510", + "body": "who bought", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + }, + "choice_hottext_547dd79b8daf5284589059": { + "identifier": "B", + "serial": "choice_hottext_547dd79b8daf5284589059", + "qtiClass": "hottext", + "attributes": { + "identifier": "B", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_547dd79b8db12833964282", + "body": "includes", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + }, + "choice_hottext_547dd79b8db64175149202": { + "identifier": "C", + "serial": "choice_hottext_547dd79b8db64175149202", + "qtiClass": "hottext", + "attributes": { + "identifier": "C", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_547dd79b8db7f317164150", + "body": "at least", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + }, + "choice_hottext_547dd79b8dbcb263172857": { + "identifier": "D", + "serial": "choice_hottext_547dd79b8dbcb263172857", + "qtiClass": "hottext", + "attributes": { + "identifier": "D", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_547dd79b8dbe9417605168", + "body": "whose", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + }, + "choice_hottext_547dd79b8dc33869435046": { + "identifier": "E", + "serial": "choice_hottext_547dd79b8dc33869435046", + "qtiClass": "hottext", + "attributes": { + "identifier": "E", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_547dd79b8dc4d467233914", + "body": "No error.", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + } + }, + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + }, + "prompt": { + "serial": "container_containerstatic_547dd79b8d656623958489", + "body": "", + "elements": [], + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + } + } + }, + "debug": { + "relatedItem": "item_547dd79b8be3e240017126" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd79b8c688752696559": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd79b8c688752696559", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_547dd79b8c587771102769": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd79b8c587771102769", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "B" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd79b8dee5275459776", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/space-shuttle-ident.json b/test/samples/json/space-shuttle-ident.json new file mode 100644 index 00000000..27670ae0 --- /dev/null +++ b/test/samples/json/space-shuttle-ident.json @@ -0,0 +1,229 @@ +{ + "identifier": "space-shuttle-30-years-of-adventure", + "serial": "item_546cb89e037d2926817182", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "space-shuttle-30-years-of-adventure", + "title": "The Space Shuttle, 30 years of adventure", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_546cb89e037ba814681360", + "body": "

    \n\t\t\tDuring more than 30 years, the American Space Shuttle transported 355 astronauts in space over 135\n\t\t\torbital launchings from Cap Canaveral, Florida. This 2046-ton Behemoth traveled 870 million kilometers\n\t\t\taround the Earth from 12th of April 1981 to 21st of July 2011. The National Aeronautics and Space\n\t\t\tAdministration (NASA) built 5 Space Shuttles: Columbia, Challenger, Discovery, Atlantis and Endeavour.\n\t\t

    \n {{interaction_choiceinteraction_546cb89e04090230494786}}", + "elements": { + "interaction_choiceinteraction_546cb89e04090230494786": { + "serial": "interaction_choiceinteraction_546cb89e04090230494786", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0, + "id": "interaction" + }, + "choices": { + "choice_simplechoice_546cb89e0432c350250658": { + "identifier": "Discovery", + "serial": "choice_simplechoice_546cb89e0432c350250658", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Discovery-new.dot", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e043a1762658686", + "body": "Discovery", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04418434995288": { + "identifier": "Challenger", + "serial": "choice_simplechoice_546cb89e04418434995288", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Challenger", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04431616309193", + "body": "Challenger", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04495918665650": { + "identifier": "Pathfinder", + "serial": "choice_simplechoice_546cb89e04495918665650", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Pathfinder", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e044ad359477207", + "body": "Pathfinder", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e0450e812009296": { + "identifier": "Atlantis", + "serial": "choice_simplechoice_546cb89e0450e812009296", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Atlantis", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04526961278319", + "body": "Atlantis", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04585740349986": { + "identifier": "Endeavour", + "serial": "choice_simplechoice_546cb89e04585740349986", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Endeavour", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e0459d917435110", + "body": "Endeavour", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_546cb89e0420f262955533", + "body": "Which was the last Space Shuttle going into space during the STS-135 mission in July 2011?", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": { + + }, + "outcomes": { + "outcomedeclaration_546cb89e03e9a471001669": { + "identifier": "SCORE", + "serial": "outcomedeclaration_546cb89e03e9a471001669", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "integer" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_546cb89e03b1a704637243": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_546cb89e03b1a704637243", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "Atlantis" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_546cb89e0472b442135529", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "template": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/space-shuttle-m.json b/test/samples/json/space-shuttle-m.json new file mode 100644 index 00000000..03c3ac3a --- /dev/null +++ b/test/samples/json/space-shuttle-m.json @@ -0,0 +1,230 @@ +{ + "identifier": "space-shuttle-30-years-of-adventure", + "serial": "item_546cb89e037d2926817182", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "space-shuttle-30-years-of-adventure", + "title": "The Space Shuttle, 30 years of adventure", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_546cb89e037ba814681360", + "body": "

    \n\t\t\tDuring more than 30 years, the American Space Shuttle transported 355 astronauts in space over 135\n\t\t\torbital launchings from Cap Canaveral, Florida. This 2046-ton Behemoth traveled 870 million kilometers\n\t\t\taround the Earth from 12th of April 1981 to 21st of July 2011. The National Aeronautics and Space\n\t\t\tAdministration (NASA) built 5 Space Shuttles: Columbia, Challenger, Discovery, Atlantis and Endeavour.\n\t\t

    \n {{interaction_choiceinteraction_546cb89e04090230494786}}", + "elements": { + "interaction_choiceinteraction_546cb89e04090230494786": { + "serial": "interaction_choiceinteraction_546cb89e04090230494786", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 2, + "minChoices": 1, + "id": "interaction" + }, + "choices": { + "choice_simplechoice_546cb89e0432c350250658": { + "identifier": "Discovery", + "serial": "choice_simplechoice_546cb89e0432c350250658", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Discovery", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e043a1762658686", + "body": "Discovery", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04418434995288": { + "identifier": "Challenger", + "serial": "choice_simplechoice_546cb89e04418434995288", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Challenger", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04431616309193", + "body": "Challenger", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04495918665650": { + "identifier": "Pathfinder", + "serial": "choice_simplechoice_546cb89e04495918665650", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Pathfinder", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e044ad359477207", + "body": "Pathfinder", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e0450e812009296": { + "identifier": "Atlantis", + "serial": "choice_simplechoice_546cb89e0450e812009296", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Atlantis", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04526961278319", + "body": "Atlantis", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04585740349986": { + "identifier": "Endeavour", + "serial": "choice_simplechoice_546cb89e04585740349986", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Endeavour", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e0459d917435110", + "body": "Endeavour", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_546cb89e0420f262955533", + "body": "Which was the last Space Shuttle going into space during the STS-135 mission in July 2011?", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + }, + "namespaces": { + "": "http://www.imsglobal.org/xsd/imsqti_v2p1", + "xsi": "http://www.w3.org/2001/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p1": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p1\/imsqti_v2p1.xsd" + }, + "stylesheets": { + + }, + "outcomes": { + "outcomedeclaration_546cb89e03e9a471001669": { + "identifier": "SCORE", + "serial": "outcomedeclaration_546cb89e03e9a471001669", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "integer" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_546cb89e03b1a704637243": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_546cb89e03b1a704637243", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "correctResponses": [ + "Atlantis", "Pathfinder" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_546cb89e0472b442135529", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/space-shuttle-pic.json b/test/samples/json/space-shuttle-pic.json new file mode 100644 index 00000000..2c7dd375 --- /dev/null +++ b/test/samples/json/space-shuttle-pic.json @@ -0,0 +1,323 @@ +{ + "identifier": "space-shuttle-30-years-of-adventure", + "serial": "item_546cb89e037d2926817182", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "space-shuttle-30-years-of-adventure", + "title": "The Space Shuttle, 30 years of adventure", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_546cb89e037ba814681360", + "body": "{{portableinfocontrol_556f08e21039e128137685}} {{portableinfocontrol_556f08e211b49955612514}} {{portableinfocontrol_556f08e211bf6383569033}} {{portableinfocontrol_556f08e211c79279799350}}

    \n\t\t\tDuring more than 30 years, the American Space Shuttle transported 355 astronauts in space over 135\n\t\t\torbital launchings from Cap Canaveral, Florida. This 2046-ton Behemoth traveled 870 million kilometers\n\t\t\taround the Earth from 12th of April 1981 to 21st of July 2011. The National Aeronautics and Space\n\t\t\tAdministration (NASA) built 5 Space Shuttles: Columbia, Challenger, Discovery, Atlantis and Endeavour.\n\t\t

    \n {{interaction_choiceinteraction_546cb89e04090230494786}}", + "elements": { + "portableinfocontrol_556f08e21039e128137685": { + "serial": "portableinfocontrol_556f08e21039e128137685", + "qtiClass": "infoControl", + "attributes": { + "id": "mock-1", + "title": "PIC Mock 1", + "class": "sts-scope sts-tmp-element" + }, + "debug": { + "relatedItem": "item_556f08e1e8b38617090200" + }, + "typeIdentifier": "picMock1", + "markup": "
    \n <\/span>\n
    \n \n <\/div>\n <\/div>", + "libraries": [ + + ], + "properties": { + "movable": "", + "theme": "tao-light", + "position": "7", + "toolbarId": "sts-studentToolbar" + }, + "entryPoint": "pic-mock-1.js" + }, + "portableinfocontrol_556f08e211b49955612514": { + "serial": "portableinfocontrol_556f08e211b49955612514", + "qtiClass": "infoControl", + "attributes": { + "id": "mock-2", + "title": "PIC Mock 2", + "class": "sts-scope sts-tmp-element" + }, + "debug": { + "relatedItem": "item_556f08e1e8b38617090200" + }, + "typeIdentifier": "picMock2", + "markup": "
    \n <\/span>\n
    \n \n <\/div>\n <\/div>", + "libraries": [ + + ], + "properties": { + "is": { + + }, + "position": "-1", + "toolbarId": "sts-studentToolbar" + }, + "entryPoint": "pic-mock-2.js" + }, + "portableinfocontrol_556f08e211bf6383569033": { + "serial": "portableinfocontrol_556f08e211bf6383569033", + "qtiClass": "infoControl", + "attributes": { + "id": "mock-3", + "title": "PIC Mock 3", + "class": "sts-scope sts-tmp-element" + }, + "debug": { + "relatedItem": "item_556f08e1e8b38617090200" + }, + "typeIdentifier": "picMock3", + "markup": "
    \n <\/span>\n
    \n \n <\/div>\n <\/div>", + "libraries": [ + + ], + "properties": { + "movable": "", + "theme": "tao-light", + "position": "3", + "toolbarId": "sts-studentToolbar" + }, + "entryPoint": "pic-mock-3.js" + }, + "portableinfocontrol_556f08e211c79279799350": { + "serial": "portableinfocontrol_556f08e211c79279799350", + "qtiClass": "infoControl", + "attributes": { + "title": "Student Toolbar", + "class": "sts-scope" + }, + "debug": { + "relatedItem": "item_556f08e1e8b38617090200" + }, + "typeIdentifier": "studentToolbar", + "markup": "
    \n
    \n
    \n
    Student Toolbar<\/div>\n <\/div>\n
    \n \n <\/div>\n <\/div>\n <\/div>", + "libraries": [ + + ], + "properties": { + "position": "100", + "toolbarId": "sts-studentToolbar" + }, + "entryPoint": "pic-mock-studentToolbar.js" + }, + "interaction_choiceinteraction_546cb89e04090230494786": { + "serial": "interaction_choiceinteraction_546cb89e04090230494786", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0, + "id": "interaction" + }, + "choices": { + "choice_simplechoice_546cb89e0432c350250658": { + "identifier": "Discovery", + "serial": "choice_simplechoice_546cb89e0432c350250658", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Discovery", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e043a1762658686", + "body": "Discovery", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04418434995288": { + "identifier": "Challenger", + "serial": "choice_simplechoice_546cb89e04418434995288", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Challenger", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04431616309193", + "body": "Challenger", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04495918665650": { + "identifier": "Pathfinder", + "serial": "choice_simplechoice_546cb89e04495918665650", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Pathfinder", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e044ad359477207", + "body": "Pathfinder", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e0450e812009296": { + "identifier": "Atlantis", + "serial": "choice_simplechoice_546cb89e0450e812009296", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Atlantis", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04526961278319", + "body": "Atlantis", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04585740349986": { + "identifier": "Endeavour", + "serial": "choice_simplechoice_546cb89e04585740349986", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Endeavour", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e0459d917435110", + "body": "Endeavour", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_546cb89e0420f262955533", + "body": "Which was the last Space Shuttle going into space during the STS-135 mission in July 2011?", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": { + + }, + "outcomes": { + "outcomedeclaration_546cb89e03e9a471001669": { + "identifier": "SCORE", + "serial": "outcomedeclaration_546cb89e03e9a471001669", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "integer" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_546cb89e03b1a704637243": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_546cb89e03b1a704637243", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "Atlantis" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_546cb89e0472b442135529", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "template": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/space-shuttle.json b/test/samples/json/space-shuttle.json new file mode 100644 index 00000000..5e564ea1 --- /dev/null +++ b/test/samples/json/space-shuttle.json @@ -0,0 +1,229 @@ +{ + "identifier": "space-shuttle-30-years-of-adventure", + "serial": "item_546cb89e037d2926817182", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "space-shuttle-30-years-of-adventure", + "title": "The Space Shuttle, 30 years of adventure", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_546cb89e037ba814681360", + "body": "

    \n\t\t\tDuring more than 30 years, the American Space Shuttle transported 355 astronauts in space over 135\n\t\t\torbital launchings from Cap Canaveral, Florida. This 2046-ton Behemoth traveled 870 million kilometers\n\t\t\taround the Earth from 12th of April 1981 to 21st of July 2011. The National Aeronautics and Space\n\t\t\tAdministration (NASA) built 5 Space Shuttles: Columbia, Challenger, Discovery, Atlantis and Endeavour.\n\t\t

    \n {{interaction_choiceinteraction_546cb89e04090230494786}}", + "elements": { + "interaction_choiceinteraction_546cb89e04090230494786": { + "serial": "interaction_choiceinteraction_546cb89e04090230494786", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 1, + "minChoices": 0, + "id": "interaction" + }, + "choices": { + "choice_simplechoice_546cb89e0432c350250658": { + "identifier": "Discovery", + "serial": "choice_simplechoice_546cb89e0432c350250658", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Discovery", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e043a1762658686", + "body": "Discovery", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04418434995288": { + "identifier": "Challenger", + "serial": "choice_simplechoice_546cb89e04418434995288", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Challenger", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04431616309193", + "body": "Challenger", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04495918665650": { + "identifier": "Pathfinder", + "serial": "choice_simplechoice_546cb89e04495918665650", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Pathfinder", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e044ad359477207", + "body": "Pathfinder", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e0450e812009296": { + "identifier": "Atlantis", + "serial": "choice_simplechoice_546cb89e0450e812009296", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Atlantis", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e04526961278319", + "body": "Atlantis", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + }, + "choice_simplechoice_546cb89e04585740349986": { + "identifier": "Endeavour", + "serial": "choice_simplechoice_546cb89e04585740349986", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "Endeavour", + "fixed": false + }, + "body": { + "serial": "container_containerstatic_546cb89e0459d917435110", + "body": "Endeavour", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_546cb89e0420f262955533", + "body": "Which was the last Space Shuttle going into space during the STS-135 mission in July 2011?", + "elements": [], + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + } + } + }, + "debug": { + "relatedItem": "item_546cb89e037d2926817182" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": { + + }, + "outcomes": { + "outcomedeclaration_546cb89e03e9a471001669": { + "identifier": "SCORE", + "serial": "outcomedeclaration_546cb89e03e9a471001669", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "integer" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_546cb89e03b1a704637243": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_546cb89e03b1a704637243", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "identifier" + }, + "correctResponses": [ + "Atlantis" + ], + "mapping": [], + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_546cb89e0472b442135529", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "template": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/match_correct", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + }] + } + }] + } +} diff --git a/test/samples/json/static/tooltip.json b/test/samples/json/static/tooltip.json new file mode 100644 index 00000000..d3f66d9a --- /dev/null +++ b/test/samples/json/static/tooltip.json @@ -0,0 +1,344 @@ +{ + "identifier": "i150833872240374", + "serial": "item_59e9b565a9b14814497792", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i150833872240374", + "title": "Tooltip", + "label": "Tooltip", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint62", + "class": "" + }, + "body": { + "serial": "container_containeritembody_59e9b565a9b02826435565", + "body": "\n
    \n
    \n

    This text is inside a {{_tooltip_59e9b565ac8be629025767}}.<\/p>\n

    This tooltip has no content I'm undefined<\/span><\/p>\n

    This tooltip does not reference any content I'm orphan<\/span><\/p>\n

    This valid tooltip {{_tooltip_59e9b565ac967883613059}}, has a content in a div far, far away.<\/p>\n

    This tooltip content does not have any target. No one will ever see me...<\/span><\/p>\n <\/div>\n <\/div>\n

    \n
    \n {{interaction_choiceinteraction_59e9b565ab808931368091}}\n <\/div>\n <\/div>\n
    \n
    \n

    This is another inline container.<\/p>\n .\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_choiceinteraction_59e9b565ab808931368091": { + "serial": "interaction_choiceinteraction_59e9b565ab808931368091", + "qtiClass": "choiceInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false, + "maxChoices": 0, + "minChoices": 0, + "orientation": "vertical" + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "choices": { + "choice_simplechoice_59e9b565ac2d7694431284": { + "identifier": "choice_1", + "serial": "choice_simplechoice_59e9b565ac2d7694431284", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_1", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_59e9b565ac450304689519", + "body": "This choice has a {{_tooltip_59e9b565ac4f2147830720}} with a strange meaning", + "elements": { + "_tooltip_59e9b565ac4f2147830720": { + "serial": "_tooltip_59e9b565ac4f2147830720", + "qtiClass": "_tooltip", + "attributes": { + "data-role": "tooltip-target", + "aria-describedby": "tooltip_2" + }, + "body": { + "serial": "container_containertooltip_59e9b565ac507824646132", + "body": "strange word", + "elements": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "content": "But it will not<\/i> be revealed here." + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "choice_simplechoice_59e9b565ac68f513290603": { + "identifier": "choice_2", + "serial": "choice_simplechoice_59e9b565ac68f513290603", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_2", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_59e9b565ac6af195738855", + "body": "Not this one", + "elements": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "choice_simplechoice_59e9b565ac71b199545752": { + "identifier": "choice_3", + "serial": "choice_simplechoice_59e9b565ac71b199545752", + "qtiClass": "simpleChoice", + "attributes": { + "identifier": "choice_3", + "fixed": false, + "showHide": "show" + }, + "body": { + "serial": "container_containerstatic_59e9b565ac731977965163", + "body": "Neither has this one", + "elements": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + } + }, + "prompt": { + "serial": "container_containerstatic_59e9b565abc66891279392", + "body": "\n

    This is a text inside a {{_tooltip_59e9b565abe07561361524}} <\/p>\n ", + "elements": { + "_tooltip_59e9b565abe07561361524": { + "serial": "_tooltip_59e9b565abe07561361524", + "qtiClass": "_tooltip", + "attributes": { + "data-role": "tooltip-target", + "aria-describedby": "tooltip_3" + }, + "body": { + "serial": "container_containertooltip_59e9b565abf19328341890", + "body": "QTI prompt", + "elements": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "content": "The text before the question." + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + } + }, + "_tooltip_59e9b565ac8be629025767": { + "serial": "_tooltip_59e9b565ac8be629025767", + "qtiClass": "_tooltip", + "attributes": { + "data-role": "tooltip-target", + "aria-describedby": "tooltip_1" + }, + "body": { + "serial": "container_containertooltip_59e9b565ac8cc252151254", + "body": "inline interaction container", + "elements": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "content": "This is a container for inline choices<\/strong> and inline text entries<\/strong>." + }, + "_tooltip_59e9b565ac967883613059": { + "serial": "_tooltip_59e9b565ac967883613059", + "qtiClass": "_tooltip", + "attributes": { + "data-role": "tooltip-target", + "aria-describedby": "tooltip_4" + }, + "body": { + "serial": "container_containertooltip_59e9b565ac971551326912", + "body": "tooltip", + "elements": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "content": "Some say that the word \"tooltip\" does not really exist." + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p2\/imsqti_v2p2.xsd" + }, + "stylesheets": { + "stylesheet_59e9b565aa589364778248": { + "serial": "stylesheet_59e9b565aa589364778248", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + } + } + }, + "outcomes": { + "outcomedeclaration_59e9b565aae8d113142771": { + "identifier": "SCORE", + "serial": "outcomedeclaration_59e9b565aae8d113142771", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float", + "normalMaximum": 0 + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "defaultValue": null + }, + "outcomedeclaration_59e9b565ab1b8932355858": { + "identifier": "MAXSCORE", + "serial": "outcomedeclaration_59e9b565ab1b8932355858", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "MAXSCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "defaultValue": "0" + } + }, + "responses": { + "responsedeclaration_59e9b565aab5a997370917": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_59e9b565aab5a997370917", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "identifier" + }, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_59e9b565acda3440073090", + "qtiClass": "responseProcessing", + "attributes": {}, + "debug": { + "relatedItem": "item_59e9b565a9b14814497792" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} diff --git a/test/samples/json/tao-item.json b/test/samples/json/tao-item.json new file mode 100644 index 00000000..f43477d2 --- /dev/null +++ b/test/samples/json/tao-item.json @@ -0,0 +1,411 @@ +{ + "identifier": "i13806271719128107", + "serial": "item_547dd4d24b648093442045", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i13806271719128107", + "title": "Create Item", + "label": "", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_547dd4d24b630267595713", + "body": "

    {{interaction_gapmatchinteraction_547dd4d24d2d0146858817}}\n\n
    \n
    \n
    ", + "elements": { + "interaction_gapmatchinteraction_547dd4d24d2d0146858817": { + "serial": "interaction_gapmatchinteraction_547dd4d24d2d0146858817", + "qtiClass": "gapMatchInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "shuffle": false + }, + "body": { + "serial": "container_containergap_547dd4d24d7f9926277347", + "body": "

    Log into tao. Go to the \n{{choice_gap_547dd4d24e894241731542}}\nCreate an item and select QTI item type.Go into the \n{{choice_gap_547dd4d24eb11566679391}}\n to start\nediting your item.
    Write some text in your item body editor. You can insert image,\nmedia and even \n{{choice_gap_547dd4d24eb9e015921385}}\n elements in\nyour item bodyInsert an interaction at some point and customized it. Let's\nstart with the simplest one the Choice Interaction which is\nbasically a \n{{choice_gap_547dd4d24ec1f329908418}}\n .Save it and preview it either in the\n\n{{choice_gap_547dd4d24ecb4936665567}}\n , or the\n\n{{choice_gap_547dd4d24ed33748444834}}\n . The result is the same, but\ngoing to the first one will have you leave the authoring tool so\nyou gonna need to reload the authoring tool to resume working on.\nFor quick review when authoring you item, prefer the second\none.

    ", + "elements": { + "choice_gap_547dd4d24e894241731542": { + "identifier": "Gap_6", + "serial": "choice_gap_547dd4d24e894241731542", + "qtiClass": "gap", + "attributes": { + "identifier": "Gap_6", + "fixed": false, + "required": false + } + }, + "choice_gap_547dd4d24eb11566679391": { + "identifier": "Gap_1", + "serial": "choice_gap_547dd4d24eb11566679391", + "qtiClass": "gap", + "attributes": { + "identifier": "Gap_1", + "fixed": false, + "required": false + } + }, + "choice_gap_547dd4d24eb9e015921385": { + "identifier": "Gap_2", + "serial": "choice_gap_547dd4d24eb9e015921385", + "qtiClass": "gap", + "attributes": { + "identifier": "Gap_2", + "fixed": false, + "required": false + } + }, + "choice_gap_547dd4d24ec1f329908418": { + "identifier": "Gap_3", + "serial": "choice_gap_547dd4d24ec1f329908418", + "qtiClass": "gap", + "attributes": { + "identifier": "Gap_3", + "fixed": false, + "required": false + } + }, + "choice_gap_547dd4d24ecb4936665567": { + "identifier": "Gap_4", + "serial": "choice_gap_547dd4d24ecb4936665567", + "qtiClass": "gap", + "attributes": { + "identifier": "Gap_4", + "fixed": false, + "required": false + } + }, + "choice_gap_547dd4d24ed33748444834": { + "identifier": "Gap_5", + "serial": "choice_gap_547dd4d24ed33748444834", + "qtiClass": "gap", + "attributes": { + "identifier": "Gap_5", + "fixed": false, + "required": false + } + } + }, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + }, + "choices": { + "choice_gaptext_547dd4d24dd4e318884097": { + "identifier": "Text_1", + "serial": "choice_gaptext_547dd4d24dd4e318884097", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_1", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_1", + "body": "authoring tool", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24dfb9192086011": { + "identifier": "Text_2", + "serial": "choice_gaptext_547dd4d24dfb9192086011", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_2", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_2", + "body": "math", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e0b0165472547": { + "identifier": "Text_3", + "serial": "choice_gaptext_547dd4d24e0b0165472547", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_3", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_3", + "body": "MCQ", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e179383165127": { + "identifier": "Text_4", + "serial": "choice_gaptext_547dd4d24e179383165127", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_4", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_4", + "body": "preview tab", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e238974723564": { + "identifier": "Text_5", + "serial": "choice_gaptext_547dd4d24e238974723564", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_5", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_5", + "body": "popup preview", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e2f2383454538": { + "identifier": "Text_6", + "serial": "choice_gaptext_547dd4d24e2f2383454538", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_6", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_6", + "body": "items extensions", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e3a9171342821": { + "identifier": "Text_7", + "serial": "choice_gaptext_547dd4d24e3a9171342821", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_7", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_7", + "body": "tests extensions", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e45c636073250": { + "identifier": "Text_8", + "serial": "choice_gaptext_547dd4d24e45c636073250", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_8", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_8", + "body": "settings", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e50e054901745": { + "identifier": "Text_9", + "serial": "choice_gaptext_547dd4d24e50e054901745", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_9", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_9", + "body": "word", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + }, + "choice_gaptext_547dd4d24e5d0796786352": { + "identifier": "Text_10", + "serial": "choice_gaptext_547dd4d24e5d0796786352", + "qtiClass": "gapText", + "attributes": { + "identifier": "Text_10", + "fixed": false, + "matchMax": 0, + "matchMin": 0 + }, + "body": { + "serial": "_container_text_10", + "body": "select box", + "elements": {}, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + } + }, + "prompt": { + "serial": "container_containerstatic_547dd4d24d575410930491", + "body": "You are a seasoned TAO user, Sam is new user and needs you help to\nguide him through the process of his first online assessment\ncreation.", + "elements": [], + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + } + } + }, + "debug": { + "relatedItem": "item_547dd4d24b648093442045" + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + }, + "stylesheets": [], + "outcomes": { + "outcomedeclaration_547dd4d24ba2f739533775": { + "identifier": "SCORE", + "serial": "outcomedeclaration_547dd4d24ba2f739533775", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_547dd4d24b8dd690436656": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_547dd4d24b8dd690436656", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "multiple", + "baseType": "directedPair" + }, + "correctResponses": [ + "Gap_1 Text_1", + "Gap_2 Text_2", + "Gap_3 Text_3", + "Gap_4 Text_4", + "Gap_5 Text_5", + "Gap_6 Text_6" + ], + "mapping": { + "Gap_1 Text_1": "0.5", + "Gap_2 Text_2": "0.5", + "Gap_3 Text_3": "0.5", + "Gap_4 Text_4": "0.5", + "Gap_5 Text_5": "0.5", + "Gap_6 Text_6": "0.5" + }, + "areaMapping": [], + "howMatch": "http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response", + "mappingAttributes": { + "defaultValue": -1, + "lowerBound": "0", + "upperBound": "3" + }, + "feedbackRules": [] + } + }, + "feedbacks": [], + "responseProcessing": { + "serial": "response_templatesdriven_547dd4d24f44f149286285", + "qtiClass": "responseProcessing", + "attributes": [], + "responseProcessing": { + "serial": "response_templatesdriven_54787e6dade83075046789", + "qtiClass": "responseProcessing", + "attributes": [], + "processingType": "templateDriven", + "responseRules": [{ + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "isNull", + "expressions": [{ + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }] + }, + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0.0" + } + }] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [{ + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "mapResponse", + "attributes": { + "identifier": "RESPONSE" + } + } + }] + } + }] + } + } +} diff --git a/test/samples/json/text-entry-length.json b/test/samples/json/text-entry-length.json new file mode 100644 index 00000000..9c02d3e9 --- /dev/null +++ b/test/samples/json/text-entry-length.json @@ -0,0 +1,175 @@ +{ + "identifier": "i1480079448133120", + "serial": "item_583d7e701e5a8766808923", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1480079448133120", + "title": "Item 12", + "label": "text interactions", + "xml:lang": "it-IT", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint39", + "class": "" + }, + "body": { + "serial": "container_containeritembody_583d7e701e589102600642", + "body": "\n
    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\u00a0\n\n {{interaction_textentryinteraction_583d7e702b765605308755}} qui street art .\n\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_583d7e702b765605308755": { + "serial": "interaction_textentryinteraction_583d7e702b765605308755", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 6, + "patternMask": "^[\\s\\S]{0,5}$", + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + } + }, + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p2\/imsqti_v2p2p1.xsd" + }, + "stylesheets": { + "stylesheet_583d7e7023a50695608434": { + "serial": "stylesheet_583d7e7023a50695608434", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + } + } + }, + "outcomes": { + "outcomedeclaration_583d7e702845b442064760": { + "identifier": "SCORE", + "serial": "outcomedeclaration_583d7e702845b442064760", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_583d7e7026d22927547154": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_583d7e7026d22927547154", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_583d7e70344ad046859860", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_583d7e701e5a8766808923" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/samples/json/text-entry-noconstraint.json b/test/samples/json/text-entry-noconstraint.json new file mode 100644 index 00000000..e094a359 --- /dev/null +++ b/test/samples/json/text-entry-noconstraint.json @@ -0,0 +1,175 @@ +{ + "identifier": "i1480079448133120", + "serial": "item_583d87875dd60279540203", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1480079448133120", + "title": "Item 12", + "label": "text interactions English", + "xml:lang": "en-US", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint39", + "class": "" + }, + "body": { + "serial": "container_containeritembody_583d87875dd30741016733", + "body": "\n

    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\u00a0\n\n {{interaction_textentryinteraction_583d878768930126427596}} qui street\n\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_583d878768930126427596": { + "serial": "interaction_textentryinteraction_583d878768930126427596", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 15, + "patternMask": "", + "placeholderText": "type in" + }, + "debug": { + "relatedItem": "item_583d87875dd60279540203" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_583d87875dd60279540203" + } + }, + "debug": { + "relatedItem": "item_583d87875dd60279540203" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p2\/imsqti_v2p2p1.xsd" + }, + "stylesheets": { + "stylesheet_583d87876213a339072041": { + "serial": "stylesheet_583d87876213a339072041", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_583d87875dd60279540203" + } + } + }, + "outcomes": { + "outcomedeclaration_583d878765b2b325066929": { + "identifier": "SCORE", + "serial": "outcomedeclaration_583d878765b2b325066929", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_583d87875dd60279540203" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_583d878764953704649964": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_583d878764953704649964", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_583d87875dd60279540203" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_583d87876d775937023581", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_583d87875dd60279540203" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/samples/json/text-entry-pattern.json b/test/samples/json/text-entry-pattern.json new file mode 100644 index 00000000..a7a1dce4 --- /dev/null +++ b/test/samples/json/text-entry-pattern.json @@ -0,0 +1,175 @@ +{ + "identifier": "i1480079448133120", + "serial": "item_583d7ef92da77287593082", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "i1480079448133120", + "title": "Item 12", + "label": "text interactions", + "xml:lang": "it-IT", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.2.0-sprint39", + "class": "" + }, + "body": { + "serial": "container_containeritembody_583d7ef92da59253696663", + "body": "\n

    \n
    \n

    Lorem ipsum dolor sit amet, consectetur adipisicing ...\u00a0\n\n {{interaction_textentryinteraction_583d7ef9340df566552260}} qui street art .\n\n <\/p>\n <\/div>\n <\/div>\n ", + "elements": { + "interaction_textentryinteraction_583d7ef9340df566552260": { + "serial": "interaction_textentryinteraction_583d7ef9340df566552260", + "qtiClass": "textEntryInteraction", + "attributes": { + "responseIdentifier": "RESPONSE", + "base": 10, + "expectedLength": 8, + "patternMask": "PARIS", + "placeholderText": "" + }, + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + }, + "choices": {} + } + }, + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + } + }, + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + }, + "namespaces": { + "": "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2", + "m": "http:\/\/www.w3.org\/1998\/Math\/MathML", + "xsi": "http:\/\/www.w3.org\/2001\/XMLSchema-instance" + }, + "schemaLocations": { + "http:\/\/www.imsglobal.org\/xsd\/imsqti_v2p2": "http:\/\/www.imsglobal.org\/xsd\/qti\/qtiv2p2\/imsqti_v2p2p1.xsd" + }, + "stylesheets": { + "stylesheet_583d7ef93055a662867673": { + "serial": "stylesheet_583d7ef93055a662867673", + "qtiClass": "stylesheet", + "attributes": { + "href": "style\/custom\/tao-user-styles.css", + "type": "text\/css", + "media": "all", + "title": "" + }, + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + } + } + }, + "outcomes": { + "outcomedeclaration_583d7ef932533850568122": { + "identifier": "SCORE", + "serial": "outcomedeclaration_583d7ef932533850568122", + "qtiClass": "outcomeDeclaration", + "attributes": { + "identifier": "SCORE", + "cardinality": "single", + "baseType": "float" + }, + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + }, + "defaultValue": null + } + }, + "responses": { + "responsedeclaration_583d7ef93187a607546486": { + "identifier": "RESPONSE", + "serial": "responsedeclaration_583d7ef93187a607546486", + "qtiClass": "responseDeclaration", + "attributes": { + "identifier": "RESPONSE", + "cardinality": "single", + "baseType": "string" + }, + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + }, + "defaultValue": [], + "mapping": [], + "areaMapping": [], + "howMatch": "http:\/\/www.imsglobal.org\/question\/qti_v2p1\/rptemplates\/match_correct", + "correctResponses": [], + "mappingAttributes": { + "defaultValue": 0 + }, + "feedbackRules": {} + } + }, + "feedbacks": {}, + "responseProcessing": { + "serial": "response_templatesdriven_583d7ef9372b1321065587", + "qtiClass": "responseProcessing", + "attributes": [], + "debug": { + "relatedItem": "item_583d7ef92da77287593082" + }, + "processingType": "templateDriven", + "responseRules": [ + { + "qtiClass": "responseCondition", + "responseIf": { + "qtiClass": "responseIf", + "expression": { + "qtiClass": "match", + "expressions": [ + { + "qtiClass": "variable", + "attributes": { + "identifier": "RESPONSE" + } + }, + { + "qtiClass": "correct", + "attributes": { + "identifier": "RESPONSE" + } + } + ] + }, + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "1" + } + } + ] + }, + "responseElse": { + "qtiClass": "responseElse", + "responseRules": [ + { + "qtiClass": "setOutcomeValue", + "attributes": { + "identifier": "SCORE" + }, + "expression": { + "qtiClass": "baseValue", + "attributes": { + "baseType": "float" + }, + "value": "0" + } + } + ] + } + } + ] + }, + "apipAccessibility": "" +} \ No newline at end of file diff --git a/test/samples/json/with-stimulus.json b/test/samples/json/with-stimulus.json new file mode 100644 index 00000000..23394ae3 --- /dev/null +++ b/test/samples/json/with-stimulus.json @@ -0,0 +1,36 @@ +{ + "identifier": "item-with-stimulus", + "serial": "item_546cb89e037d2926817182", + "qtiClass": "assessmentItem", + "attributes": { + "identifier": "item-with-stimulus", + "title": "Item with Stimulus", + "label": "", + "adaptive": false, + "timeDependent": false, + "toolName": "TAO", + "toolVersion": "3.0" + }, + "body": { + "serial": "container_containeritembody_546cb89e037ba814681360", + "body": "

    Hello included part: {{xinclude_5c7171fdcf8dc701870747}}

    ", + "elements": { + "xinclude_5c7171fdcf8dc701870747": { + "serial": "xinclude_5c7171fdcf8dc701870747", + "qtiClass": "include", + "attributes": { + "href": "taomedia://mediamanager/http_2_tao12_0_local_1_first_0_rdf_3_i1550672688604730" + }, + "bdy": { + "serial": "_container_gmubfwfv01v6xfw5e90khi", + "bdy": "
    Unthrifty loveliness, why dost thou speak
    " + } + } + } + }, + "namespaces": { + "xml": "http://www.w3.org/XML/1998/namespace", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "": "http://www.imsglobal.org/xsd/imsqti_v2p1" + } +} diff --git a/test/samples/qtiv2p1/associate_astronomy/img/earth.png b/test/samples/qtiv2p1/associate_astronomy/img/earth.png new file mode 100755 index 00000000..b5f99803 Binary files /dev/null and b/test/samples/qtiv2p1/associate_astronomy/img/earth.png differ diff --git a/test/samples/qtiv2p1/associate_astronomy/img/ganymede.png b/test/samples/qtiv2p1/associate_astronomy/img/ganymede.png new file mode 100755 index 00000000..bba45bf0 Binary files /dev/null and b/test/samples/qtiv2p1/associate_astronomy/img/ganymede.png differ diff --git a/test/samples/qtiv2p1/associate_astronomy/img/jupiter.png b/test/samples/qtiv2p1/associate_astronomy/img/jupiter.png new file mode 100755 index 00000000..243bbc6b Binary files /dev/null and b/test/samples/qtiv2p1/associate_astronomy/img/jupiter.png differ diff --git a/test/samples/qtiv2p1/associate_astronomy/img/moon.png b/test/samples/qtiv2p1/associate_astronomy/img/moon.png new file mode 100755 index 00000000..0e2588c9 Binary files /dev/null and b/test/samples/qtiv2p1/associate_astronomy/img/moon.png differ diff --git a/test/samples/qtiv2p1/associate_astronomy/img/neptune.png b/test/samples/qtiv2p1/associate_astronomy/img/neptune.png new file mode 100755 index 00000000..7c2e24b3 Binary files /dev/null and b/test/samples/qtiv2p1/associate_astronomy/img/neptune.png differ diff --git a/test/samples/qtiv2p1/associate_astronomy/img/triton.png b/test/samples/qtiv2p1/associate_astronomy/img/triton.png new file mode 100755 index 00000000..c74029a5 Binary files /dev/null and b/test/samples/qtiv2p1/associate_astronomy/img/triton.png differ diff --git a/test/samples/qtiv2p1/associate_astronomy/qti.xml b/test/samples/qtiv2p1/associate_astronomy/qti.xml new file mode 100644 index 00000000..162384cc --- /dev/null +++ b/test/samples/qtiv2p1/associate_astronomy/qti.xml @@ -0,0 +1,90 @@ + + + + + + + Ea Mo + Ju Ga + Ne Tr + + + + + + + + + + + + +
    +
    +
    this is a sample to test the grid system
    +
    +
    +
    +
    +

    What do you know about planet and moons of solar system?

    +
    +
    + + + Make pairs. +
    Each pair is composed of a planet of the Solar System and one of it's moon.
    +
    +
    + + + Earth +
    + Earth +
    + + Moon +
    + Moon +
    + + Jupiter +
    + Jupiter +
    + + Ganymede +
    + Ganymede +
    + + Neptune +
    + Neptune +
    + + triton +
    + Triton +
    +
    +
    +
    + +

    Guidelines

    +
    +

    + Earth + Moon + How to create a pair: +

    +
      +
    • Select and element from the top list, it will become highlighted.
    • +
    • Click onto one empty box (the order does not matter).
    • +
    • Repeat the operation for the second one.
    • +
    +
    +
    +
    + + +
    \ No newline at end of file diff --git a/test/samples/qtiv2p1/associate_include/qti.xml b/test/samples/qtiv2p1/associate_include/qti.xml new file mode 100755 index 00000000..422fe2c4 --- /dev/null +++ b/test/samples/qtiv2p1/associate_include/qti.xml @@ -0,0 +1,35 @@ + + + + + A P + C M + D L + + + + + + + + + +
    + + Hidden in this list of characters from famous Shakespeare plays are three pairs + of rivals. Can you match each character to his adversary? + Antonio + Capulet + Demetrius + Lysander + Montague + Prospero + +
    + +
    diff --git a/test/samples/qtiv2p1/associate_include/stimulus.xml b/test/samples/qtiv2p1/associate_include/stimulus.xml new file mode 100644 index 00000000..44f0f577 --- /dev/null +++ b/test/samples/qtiv2p1/associate_include/stimulus.xml @@ -0,0 +1,19 @@ + +
    +

    + TAO logo +

    +
    + Which famous scientist is popularly associated with the equation + + E + = + m + + c + 2 + + + +
    +
    \ No newline at end of file diff --git a/test/samples/qtiv2p1/associate_include/stimulus0.xml b/test/samples/qtiv2p1/associate_include/stimulus0.xml new file mode 100644 index 00000000..a49e13ea --- /dev/null +++ b/test/samples/qtiv2p1/associate_include/stimulus0.xml @@ -0,0 +1,6 @@ + +
    +

    + World Map +

    +
    \ No newline at end of file diff --git a/test/samples/qtiv2p1/associate_include/stimulus1.xml b/test/samples/qtiv2p1/associate_include/stimulus1.xml new file mode 100644 index 00000000..7859648a --- /dev/null +++ b/test/samples/qtiv2p1/associate_include/stimulus1.xml @@ -0,0 +1,92 @@ + +
    +

    + World Map + World Map +

    +
    + Which famous scientist is popularly associated with the equation + + + E + = + m + + c + 2 + + + + And this + + + + + + + x + + + 2 + + + + + 2 + + + + 5.12 + · + + + 10 + + + 3 + + + + + c + + + + + 12 + + j + + + + + n + + 1 + + + 2 + + + + + + + + y + + + 4 + + + - + 1 + + + + + + h + + + + 0 + + +
    +
    \ No newline at end of file diff --git a/test/samples/qtiv2p1/choice_custom/qti.xml b/test/samples/qtiv2p1/choice_custom/qti.xml new file mode 100644 index 00000000..229a75bc --- /dev/null +++ b/test/samples/qtiv2p1/choice_custom/qti.xml @@ -0,0 +1,120 @@ + + + + + B + + + + + + + + + + + D2 + + + + + + + + + + + 0 + + + +
    +
    +

    Question

    +
    +
    +

    + Sugar plum gummies lemon +

    +
    +
    +

    Pie donut sweet jelly. Powder dessert cotton candy pie candy canes gummies gingerbread marshmallow pie.

    +
    + + +

    Wafer tart oat cake tart ice cream marzipan.

    +
    + +

    (correct : +1) Topping tootsie roll halvah jelly liquorice.

    +
    + +

    Tart oat cake jelly chocolate bar cheesecake candy bonbon.

    +
    + +

    Ice cream wafer candy pie chocolate bar toffee.

    +
    +
    +
    +

    Fruitcake tiramisu sesame snaps apple pie apple pie tootsie roll tart tart toffee ? +

    +
    + + +

    “Croissant oat cake candy canes chocolate bar.” Gummi bears +

    +
    + +

    “Pudding gingerbread gummies. It apple pie jelly-o sesame (apple pie) +

    +
    + +

    “Jelly beans dessert chocolate cake carrot cake pudding chupa chups cotton candy halvah lollipop. .” ( chupa chups) +

    +
    + +

    (correct : +1) “Donut muffin gummies gingerbread bonbon. .” (sugar plum) +

    +
    +
    +
    +
    +
    +
    + + + + + + + 1 + + + + 0.0 + + + + + + + 1.0 + + + + + + + 1 + + + + + 1.0 + + + + + + + +
    diff --git a/test/samples/qtiv2p1/choice_feedback/qti.xml b/test/samples/qtiv2p1/choice_feedback/qti.xml new file mode 100644 index 00000000..5ff79c5a --- /dev/null +++ b/test/samples/qtiv2p1/choice_feedback/qti.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + +
    +
    + + Question ? + choice #1 + choice #2 + choice #3 + +
    +
    +
    + + + + + + + + + + + 1 + + + + + + + + + + + + + + feedbackModal_1 + + + + + + + + 0 + + + feedbackModal_2 + + + + + Wrong + Good +
    \ No newline at end of file diff --git a/test/samples/qtiv2p1/choice_multiple_chocolade/qti.xml b/test/samples/qtiv2p1/choice_multiple_chocolade/qti.xml new file mode 100644 index 00000000..00766462 --- /dev/null +++ b/test/samples/qtiv2p1/choice_multiple_chocolade/qti.xml @@ -0,0 +1,55 @@ + + + + + + + How to make chocolate milk. Select the combination of steps that lead to a nice + glass of hot and steamy chocolate milk. + Take a lighter + Open the gas on the stove + Light the gas + Poor the milk in the pan + Add 2 tea spoons of cocoa into the mug + Add 2 tea spoons of sugar into the mug + Add 2 spoons of water into the mug + Stir the water, cocoa and sugar until the + mixture is smooth + Put the pan with milk on the stove + Poor the boiling milk into the mug + Put the mug with the mixture and milk into + the microwave + Add milk to the mug with the smooth mixture + Add cold milk from the fridge into the mug + with smooth mixture + Set the microwave on 700 Watt and set the + timer to 2 minutes + + + + + + + + C01 C02 C03 C04 C05 C06 C07 C08 C09 + C10 + + + 1 + + + + + + C11 C05 C06 C07 C08 C12 C13 C14 + + + 1 + + + + + diff --git a/test/samples/qtiv2p1/choice_single_astronomy/qti.xml b/test/samples/qtiv2p1/choice_single_astronomy/qti.xml new file mode 100755 index 00000000..77591b12 --- /dev/null +++ b/test/samples/qtiv2p1/choice_single_astronomy/qti.xml @@ -0,0 +1,33 @@ + + + + + Atlantis + + + + + 0 + + + + +

    + During more than 30 years, the American Space Shuttle transported 355 astronauts in space over 135 + orbital launchings from Cap Canaveral, Florida. This 2046-ton Behemoth traveled 870 million kilometers + around the Earth from 12th of April 1981 to 21st of July 2011. The National Aeronautics and Space + Administration (NASA) built 5 Space Shuttles: Columbia, Challenger, Discovery, Atlantis and Endeavour. +

    + + Which was the last Space Shuttle going into space during the STS-135 mission in July 2011? + Discovery + Challenger + Pathfinder + Atlantis + Endeavour + +
    + +
    + diff --git a/test/samples/qtiv2p1/endAttempt_systemItem/qti.xml b/test/samples/qtiv2p1/endAttempt_systemItem/qti.xml new file mode 100644 index 00000000..3cd6d254 --- /dev/null +++ b/test/samples/qtiv2p1/endAttempt_systemItem/qti.xml @@ -0,0 +1,38 @@ + + + + + Y + + + + + + + +

    Identify the missing word in this famous quote from Shakespeare's Richard III.

    +
    +

    Now is the winter of our discontent
    Made glorious summer by this sun of + + Gloucester + Lancaster + York + ;
    And all the clouds that lour'd upon our house
    + In the deep bosom of the ocean buried.

    +
    +
    +

    If you don't know the answer, you can :

    +

    + + OR + + OR + +

    +
    +
    + +
    \ No newline at end of file diff --git a/test/samples/qtiv2p1/extended_text_plain/qti.xml b/test/samples/qtiv2p1/extended_text_plain/qti.xml new file mode 100644 index 00000000..c7fa95a4 --- /dev/null +++ b/test/samples/qtiv2p1/extended_text_plain/qti.xml @@ -0,0 +1,25 @@ + + + + + + +

    Plain text version

    +

    Read this postcard from your English pen-friend, Sam.

    +
    + +
    +

    Here is a postcard of my town. Please send me
    a postcard from your town. + What size is your
    town? What is the nicest part of your town?
    + Where do you go in the evenings?
    Sam.

    +
    +
    +
    + + Write Sam a postcard. Answer the questions. Write 25-35 words. + +
    +
    diff --git a/test/samples/qtiv2p1/extended_text_pre/qti.xml b/test/samples/qtiv2p1/extended_text_pre/qti.xml new file mode 100644 index 00000000..1923708b --- /dev/null +++ b/test/samples/qtiv2p1/extended_text_pre/qti.xml @@ -0,0 +1,25 @@ + + + + + + +

    preformated version

    +

    Read this postcard from your English pen-friend, Sam.

    +
    + +
    +

    Here is a postcard of my town. Please send me
    a postcard from your town. + What size is your
    town? What is the nicest part of your town?
    + Where do you go in the evenings?
    Sam.

    +
    +
    +
    + + Write Sam a postcard. Answer the questions. Write 25-35 words. + +
    +
    diff --git a/test/samples/qtiv2p1/extended_text_rubric/qti.xml b/test/samples/qtiv2p1/extended_text_rubric/qti.xml new file mode 100644 index 00000000..e9199c47 --- /dev/null +++ b/test/samples/qtiv2p1/extended_text_rubric/qti.xml @@ -0,0 +1,157 @@ + + + + + + +

    Read this postcard from your English pen-friend, Sam.

    +
    + +
    +

    Here is a postcard of my town. Please send me
    a postcard from your town. + What size is your
    town? What is the nicest part of your town?
    + Where do you go in the evenings?
    Sam.

    +
    +
    +
    + + Write Sam a postcard. Answer the questions. Write 25-35 words. + + +

    Scoring Guidelinestao logo

    +
    +

    + Max Score: 3.0 points

    +

    + Scoring: +

    +
      +
    • When not all 3 questions are answered in the response: -1 for each missing.
    • +
    • Check for gramatical errors: -0.1 per error.
    • +
    • Possibly add in .1 increments extra bonus points for extra good answers.
    • +
    +

    + At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum + deleniti atque corrupti quos tao logo + dolores et quas molestias excepturi sint occaecati cupiditate non provident, + similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. + + + + + x + = + + + + + b + ± + + + b + 2 + + + 4 + a + c + + + + 2 + a + + + + + + x = {-b \pm \sqrt{b^2-4ac} \over 2a} + + + Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est + eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas + assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut + + + E + = + m + + c + 2 + + + officiis debitis aut rerum + necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. + Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias + consequatur aut perferendis doloribus asperiores repellat. +

    +
    +
    +

    + At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum + deleniti atque corrupti quos tao logo + dolores et quas molestias excepturi sint occaecati cupiditate non provident, + similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. + + + + + x + = + + + + + b + ± + + + b + 2 + + + 4 + a + c + + + + 2 + a + + + + + + x = {-b \pm \sqrt{b^2-4ac} \over 2a} + + + Et harum quidem rerum facilis est et expedita distinctio. + + + E + = + m + + c + 2 + + + + Nam libero tempore, cum soluta nobis est + eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas + assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut + officiis debitis aut rerum + + necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. + Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias + consequatur aut perferendis doloribus asperiores repellat. +

    + + \ No newline at end of file diff --git a/test/samples/qtiv2p1/extended_text_xhtml/qti.xml b/test/samples/qtiv2p1/extended_text_xhtml/qti.xml new file mode 100644 index 00000000..ac1bacbd --- /dev/null +++ b/test/samples/qtiv2p1/extended_text_xhtml/qti.xml @@ -0,0 +1,25 @@ + + + + + + +

    xhtml version

    +

    Read this postcard from your English pen-friend, Sam.

    +
    + +
    +

    Here is a postcard of my town. Please send me
    a postcard from your town. + What size is your
    town? What is the nicest part of your town?
    + Where do you go in the evenings?
    Sam.

    +
    +
    +
    + + Write Sam a postcard. Answer the questions. Write 25-35 words. + +
    +
    diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/CBG.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/CBG.png new file mode 100755 index 00000000..144b2929 Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/CBG.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/EBG.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/EBG.png new file mode 100755 index 00000000..38af8170 Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/EBG.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/EDI.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/EDI.png new file mode 100755 index 00000000..557365c9 Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/EDI.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/GLA.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/GLA.png new file mode 100755 index 00000000..49eec0f2 Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/GLA.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/MAN.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/MAN.png new file mode 100755 index 00000000..c7f957f2 Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/MAN.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/MCH.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/MCH.png new file mode 100755 index 00000000..b72dc0f5 Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/MCH.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/images/ukairtags.png b/test/samples/qtiv2p1/graphicGapMatch_airport/images/ukairtags.png new file mode 100755 index 00000000..a01ddc1b Binary files /dev/null and b/test/samples/qtiv2p1/graphicGapMatch_airport/images/ukairtags.png differ diff --git a/test/samples/qtiv2p1/graphicGapMatch_airport/qti.xml b/test/samples/qtiv2p1/graphicGapMatch_airport/qti.xml new file mode 100755 index 00000000..a9187bf3 --- /dev/null +++ b/test/samples/qtiv2p1/graphicGapMatch_airport/qti.xml @@ -0,0 +1,54 @@ + + + + + GLA A + EDI B + MAN C + + + + + + + + + +

    The International Air Transport Association assigns three-letter codes to identify + airports worldwide. For example, London Heathrow has code LHR.

    + + Some of the labels on the following diagram are missing: can you identify the + correct three-letter codes for the unlabelled airports? + + + CBG + + + EBG + + + EDI + + + GLA + + + MAN + + + MCH + + + + + + + + + diff --git a/test/samples/qtiv2p1/hotspot_glasgow/images/ukair.png b/test/samples/qtiv2p1/hotspot_glasgow/images/ukair.png new file mode 100755 index 00000000..421480f1 Binary files /dev/null and b/test/samples/qtiv2p1/hotspot_glasgow/images/ukair.png differ diff --git a/test/samples/qtiv2p1/hotspot_glasgow/qti.xml b/test/samples/qtiv2p1/hotspot_glasgow/qti.xml new file mode 100755 index 00000000..7af90de6 --- /dev/null +++ b/test/samples/qtiv2p1/hotspot_glasgow/qti.xml @@ -0,0 +1,26 @@ + + + + + A + + + + +

    The picture illustrates four of the most popular destinations for air travellers arriving + in the United Kingdom: London, Manchester, Edinburgh and Glasgow.

    + + Which one is Glasgow? + UK Map + + + + + +
    + +
    diff --git a/test/samples/qtiv2p1/media_test/qti.xml b/test/samples/qtiv2p1/media_test/qti.xml new file mode 100644 index 00000000..be1ec159 --- /dev/null +++ b/test/samples/qtiv2p1/media_test/qti.xml @@ -0,0 +1,22 @@ + + + + + + + + + Play it ! (mp4) + + + + Play it ! (ogv) + + + + Play it ! (webm) + + + + + \ No newline at end of file diff --git a/test/samples/qtiv2p1/media_youtube/qti.xml b/test/samples/qtiv2p1/media_youtube/qti.xml new file mode 100644 index 00000000..a7bdfe3d --- /dev/null +++ b/test/samples/qtiv2p1/media_youtube/qti.xml @@ -0,0 +1,23 @@ + + + + + +
    +
    + + + + +
    +

    + tao_logo_big +

    +

    Be free

    +

    Be creative

    +

    TAO is an Open Source e-Testing platform that empowers you to build, deliver, and share innovative and engaging assessments online – in any language or subject matter.

    +
    + + + + \ No newline at end of file diff --git a/test/samples/qtiv2p1/media_youtube/tao_logo_big.png b/test/samples/qtiv2p1/media_youtube/tao_logo_big.png new file mode 100644 index 00000000..aa4b7acf Binary files /dev/null and b/test/samples/qtiv2p1/media_youtube/tao_logo_big.png differ diff --git a/test/samples/qtiv2p1/pci_likert_triple/css/likert1.css b/test/samples/qtiv2p1/pci_likert_triple/css/likert1.css new file mode 100644 index 00000000..604f80a6 --- /dev/null +++ b/test/samples/qtiv2p1/pci_likert_triple/css/likert1.css @@ -0,0 +1,2 @@ +.prompt img {height:100px; width:100px; position:absolute; top:-25px; right:-20px;} +.qti-item {width:640px;} \ No newline at end of file diff --git a/test/samples/qtiv2p1/pci_likert_triple/qti.xml b/test/samples/qtiv2p1/pci_likert_triple/qti.xml new file mode 100644 index 00000000..0d722f55 --- /dev/null +++ b/test/samples/qtiv2p1/pci_likert_triple/qti.xml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + +

    This is a sample PCI.

    + + + + + + + + + + + + + + + 5 + Not at all + Very much + + + + + + + Do you like movies ? + + + + + + + + + +

    Here is another one.

    + + + + + + + + + + + + + + + 7 + Can't stand it :( + Absolutely ! :) + + + + + + + What about video games ? + + + + + + + + + +

    Here is yet another one.

    + + + + + + + + + + + + + + + 9 + Hate it + Love it + + + + + + + And reading ? + + + + + + + + + +
    + +
    \ No newline at end of file diff --git a/test/samples/qtiv2p2/xml_namespaces/with-ns.xml b/test/samples/qtiv2p2/xml_namespaces/with-ns.xml new file mode 100644 index 00000000..06e0b7df --- /dev/null +++ b/test/samples/qtiv2p2/xml_namespaces/with-ns.xml @@ -0,0 +1,16 @@ + + + + + + + + + +
    +
    +

    村田まことの出身地はどこですか

    +
    +
    +
    +
    diff --git a/test/samples/qtiv2p2/xml_namespaces/without-ns.xml b/test/samples/qtiv2p2/xml_namespaces/without-ns.xml new file mode 100644 index 00000000..49cc60c7 --- /dev/null +++ b/test/samples/qtiv2p2/xml_namespaces/without-ns.xml @@ -0,0 +1,36 @@ + + + + + + + + + +
    +
    +

    村田__PLACEHOLDER__の出身地はどこですか

    +
    +
    +
    +
    + + 選びなさい + + __PLACEHOLDER__ + + +
    +
    +
    +
    diff --git a/test/scoring/processor/expressions/baseValue/test.html b/test/scoring/processor/expressions/baseValue/test.html new file mode 100644 index 00000000..0eb62401 --- /dev/null +++ b/test/scoring/processor/expressions/baseValue/test.html @@ -0,0 +1,20 @@ + + + + + BaseValue Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/baseValue/test.js b/test/scoring/processor/expressions/baseValue/test.js new file mode 100644 index 00000000..22a19264 --- /dev/null +++ b/test/scoring/processor/expressions/baseValue/test.js @@ -0,0 +1,58 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/baseValue' +], function(_, preProcessorFactory, baseValueProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(baseValueProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(baseValueProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integer', + expression: { + attributes: {baseType: 'integer'}, + value: 5 + }, + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 5 + } + }, { + title: 'null identifier', + expression: { + attributes: {baseType: 'indentifier'}, + value: null + }, + expectedResult: { + cardinality: 'single', + baseType: 'indentifier', + value: null + } + }, { + title: 'float', + expression: { + attributes: {baseType: 'float'}, + value: 0.75 + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.75 + } + }]; + + QUnit + .cases.init(dataProvider) + .test('baseValue ', function(data, assert) { + baseValueProcessor.expression = data.expression; + baseValueProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(baseValueProcessor.process(), data.expectedResult, 'The baseValue is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/correct/test.html b/test/scoring/processor/expressions/correct/test.html new file mode 100644 index 00000000..e672e6f9 --- /dev/null +++ b/test/scoring/processor/expressions/correct/test.html @@ -0,0 +1,20 @@ + + + + + Correct Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/correct/test.js b/test/scoring/processor/expressions/correct/test.js new file mode 100644 index 00000000..44629063 --- /dev/null +++ b/test/scoring/processor/expressions/correct/test.js @@ -0,0 +1,94 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/correct' +], function(_, preProcessorFactory, correctProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(correctProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(correctProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'single identifier', + response: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-2', + correctResponse: 'choice-1' + }, + expectedResult: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-1' + } + }, { + title: 'multiple integers', + response: { + cardinality: 'multiple', + baseType: 'integer', + value: [4, 5], + correctResponse: ['1', '2'] + }, + expectedResult: { + cardinality: 'multiple', + baseType: 'integer', + value: [1, 2] + } + }, { + title: 'no variable', + response: undefined, + expectedResult: null + }, { + title: 'null', + response: { + cardinality: 'single', + baseType: 'identifier', + value: 'zhoice-2' + }, + expectedResult: null + }, { + title: 'multiple directedPairs', + response: { + cardinality: 'multiple', + baseType: 'directedPair', + value: [['C', 'R'], ['D', 'M']], + correctResponse: [ + 'C R', + 'D M', + 'L M', + 'P T' + ] + }, + expectedResult: { + cardinality: 'multiple', + baseType: 'directedPair', + value: [ + ['C', 'R'], + ['D', 'M'], + ['L', 'M'], + ['P', 'T'] + ] + } + }]; + + QUnit + .cases.init(dataProvider) + .test('correct ', function(data, assert) { + var state = { + RESPONSE: data.response + }; + correctProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + correctProcessor.state = state; + correctProcessor.preProcessor = preProcessorFactory(state); + assert.deepEqual(correctProcessor.process(), data.expectedResult, 'The results match correct'); + }); + +}); diff --git a/test/scoring/processor/expressions/default/test.html b/test/scoring/processor/expressions/default/test.html new file mode 100644 index 00000000..ebd23cc7 --- /dev/null +++ b/test/scoring/processor/expressions/default/test.html @@ -0,0 +1,20 @@ + + + + + Default Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/default/test.js b/test/scoring/processor/expressions/default/test.js new file mode 100644 index 00000000..4d721e39 --- /dev/null +++ b/test/scoring/processor/expressions/default/test.js @@ -0,0 +1,71 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/default', +], function(_, defaultProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(defaultProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(defaultProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('Get the default value', function(assert) { + defaultProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + defaultProcessor.state = { + RESPONSE: { + cardinality: 'single', + baseType: 'integer', + correctResponse: 11, + mapping: [], + areaMapping: [], + value: 2, + defaultValue: -1 + + } + }; + + var expectedResult = { + cardinality: 'single', + baseType: 'integer', + value: -1 + }; + assert.deepEqual(defaultProcessor.process(), expectedResult, 'returns the default response'); + }); + + QUnit.test('Get the default value even null', function(assert) { + defaultProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + defaultProcessor.state = { + RESPONSE: null + }; + + assert.equal(defaultProcessor.process(), null, 'returns null'); + }); + + QUnit.test('Return null if no variable is found', function(assert) { + assert.expect(1); + defaultProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + defaultProcessor.state = { + RESPONSE_1: { + cardinality: 'single', + baseType: 'identifier', + defaultResponse: 'choice-1', + mapping: [], + areaMapping: [], + value: 'choice-2' + } + }; + + assert.equal(defaultProcessor.process(), null, 'returns null'); + }); + +}); diff --git a/test/scoring/processor/expressions/engine/test.html b/test/scoring/processor/expressions/engine/test.html new file mode 100644 index 00000000..081b7995 --- /dev/null +++ b/test/scoring/processor/expressions/engine/test.html @@ -0,0 +1,25 @@ + + + + + Scoring Processor Engine Test + + + + +
    +
    +
    +
    + +
    + + diff --git a/test/scoring/processor/expressions/engine/test.js b/test/scoring/processor/expressions/engine/test.js new file mode 100644 index 00000000..70092c58 --- /dev/null +++ b/test/scoring/processor/expressions/engine/test.js @@ -0,0 +1,120 @@ +define(['taoQtiItem/scoring/processor/expressions/engine'], function(expressionEngineFactory) { + + QUnit.module('API'); + + QUnit.test('factory', function(assert) { + var ready = assert.async(); + assert.expect(1); + + assert.ok(typeof expressionEngineFactory === 'function', 'the engine expose a factory'); + + ready(); + }); + + QUnit.test('engine', function(assert) { + var ready = assert.async(); + assert.expect(2); + + var engine = expressionEngineFactory(); + + assert.ok(typeof engine === 'object', 'the engine is an object'); + assert.ok(typeof engine.execute === 'function', 'the engine exposes a execute function'); + + ready(); + }); + + QUnit.module('Parse 1 level tree'); + + QUnit.test('2 operands sum expression', function(assert) { + var ready = assert.async(); + assert.expect(1); + + var expression = { + qtiClass: 'sum', + expressions: [{ + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '3' + }, { + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '7' + }] + }; + + var expectedResult = { + cardinality: 'single', + baseType: 'integer', + value: 10 + }; + + var engine = expressionEngineFactory(); + + assert.deepEqual(engine.execute(expression), expectedResult, 'the engine compute the right result'); + + ready(); + }); + + QUnit.module('Parse 2 levels tree'); + + QUnit.test('2 operands sum expression', function(assert) { + var ready = assert.async(); + assert.expect(1); + + var expression = { + qtiClass: 'subtract', + expressions: [{ + qtiClass: 'sum', + expressions: [{ + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '3' + }, { + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '7' + }, { + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '5' + }] + }, { + qtiClass: 'product', + expressions: [{ + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '2' + }, { + qtiClass: 'baseValue', + attributes: { + baseType: 'integer' + }, + value: '5' + }] + }] + }; + + var expectedResult = { + cardinality: 'single', + baseType: 'integer', + value: 5 + }; + var engine = expressionEngineFactory(); + assert.deepEqual(engine.execute(expression), expectedResult, 'the engine compute the right result'); + + ready(); + }); +}); + diff --git a/test/scoring/processor/expressions/mapResponse/test.html b/test/scoring/processor/expressions/mapResponse/test.html new file mode 100644 index 00000000..c8b86137 --- /dev/null +++ b/test/scoring/processor/expressions/mapResponse/test.html @@ -0,0 +1,20 @@ + + + + + MapResponse Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/mapResponse/test.js b/test/scoring/processor/expressions/mapResponse/test.js new file mode 100644 index 00000000..5f8ee378 --- /dev/null +++ b/test/scoring/processor/expressions/mapResponse/test.js @@ -0,0 +1,333 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/mapResponse', + 'taoQtiItem/scoring/processor/errorHandler' +], function(_, preProcessorFactory, mapResponseProcessor, errorHandler) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(mapResponseProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(mapResponseProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('Fails if variable has no mapping', function(assert) { + var ready = assert.async(); + assert.expect(1); + mapResponseProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + mapResponseProcessor.state = { + RESPONSE: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-1', + correctResponse: 'choice-2' + } + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Without the variable in the state it throws and error'); + ready(); + }); + + mapResponseProcessor.process(); + }); + + var dataProvider = [{ + title: 'no variable', + response: undefined, + expectedResult: null + }, { + title: 'single identifier', + response: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-1', + correctResponse: 'choice-2', + mapping: { + qtiClass: 'mapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'choice-1', + mapValue: '15', + attributes: { + caseSensitive: false + } + }, { + qtiClass: 'mapEntry', + mapKey: 'choice-2', + mapValue: '30', + attributes: { + caseSensitive: false + } + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 15 + } + }, { + title: 'single string not case sensitive', + response: { + cardinality: 'single', + baseType: 'string', + value: 'a', + correctResponse: 'A', + mapping: { + qtiClass: 'mapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'A', + mapValue: '1', + attributes: { + caseSensitive: false + } + }, { + qtiClass: 'mapEntry', + mapKey: 'B', + mapValue: '0', + attributes: { + caseSensitive: false + } + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'single string case sensitive', + response: { + cardinality: 'single', + baseType: 'string', + value: 'a', + correctResponse: 'A', + mapping: { + qtiClass: 'mapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'A', + mapValue: '1', + attributes: { + caseSensitive: true + } + }, { + qtiClass: 'mapEntry', + mapKey: 'B', + mapValue: '0', + attributes: { + caseSensitive: true + } + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'single identifier defaultValue', + response: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-3', + correctResponse: 'choice-2', + mapping: { + qtiClass: 'mapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'choice-1', + mapValue: '15', + attributes: { + caseSensitive: false + } + }, { + qtiClass: 'mapEntry', + mapKey: 'choice-2', + mapValue: '30', + attributes: { + caseSensitive: false + } + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'single identifier lowerBound', + response: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-3', + correctResponse: 'choice-2', + mapping: { + qtiClass: 'mapping', + attributes: { + lowerBound: 50 + }, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'choice-1', + mapValue: '15', + attributes: { + caseSensitive: false + } + }, { + qtiClass: 'mapEntry', + mapKey: 'choice-2', + mapValue: '30', + attributes: { + caseSensitive: false + } + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 50 + } + }, { + title: 'single identifier upperBound', + response: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-2', + correctResponse: 'choice-2', + mapping: { + qtiClass: 'mapping', + attributes: { + upperBound: 5 + }, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'choice-1', + mapValue: '15', + attributes: { + caseSensitive: false + } + }, { + qtiClass: 'mapEntry', + mapKey: 'choice-2', + mapValue: '30', + attributes: { + caseSensitive: false + } + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 5 + } + }, { + title: 'multiple directedPairs', + response: { + cardinality: 'multiple', + baseType: 'directedPair', + value: [['C', 'R'], ['D', 'M']], + correctResponse: ['C R', 'D M', 'L M', 'P T'], + mapping: { + qtiClass: 'mapping', + attributes: {defaultValue: 0}, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'C R', + mapValue: '1', + attributes: {caseSensitive: false} + }, { + qtiClass: 'mapEntry', + mapKey: 'D M', + mapValue: '0.5', + attributes: {caseSensitive: false} + }, { + qtiClass: 'mapEntry', + mapKey: 'L M', + mapValue: '0.5', + attributes: {caseSensitive: false} + }, { + qtiClass: 'mapEntry', + mapKey: 'P T', + mapValue: '1', + attributes: {caseSensitive: false} + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.5 + } + }, { + title: 'multiple strings multiple response', + response: { + cardinality: 'multiple', + baseType: 'string', + value: ['B', 'B', 'C'], + correctResponse: ['B', 'C'], + mapping: { + qtiClass: 'mapping', + attributes: {defaultValue: 0}, + mapEntries: [{ + qtiClass: 'mapEntry', + mapKey: 'A', + mapValue: '0', + attributes: {caseSensitive: false} + }, { + qtiClass: 'mapEntry', + mapKey: 'B', + mapValue: '1', + attributes: {caseSensitive: true} + }, { + qtiClass: 'mapEntry', + mapKey: 'C', + mapValue: '0.5', + attributes: {caseSensitive: false} + }, { + qtiClass: 'mapEntry', + mapKey: 'D', + mapValue: '0', + attributes: {caseSensitive: false} + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.5 + } + + }]; + + QUnit + .cases.init(dataProvider) + .test('mapResponse ', function(data, assert) { + var state = { + RESPONSE: data.response + }; + + mapResponseProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + mapResponseProcessor.state = state; + mapResponseProcessor.preProcessor = preProcessorFactory(state); + assert.deepEqual(mapResponseProcessor.process(), data.expectedResult, 'The map response is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/mapResponsePoint/test.html b/test/scoring/processor/expressions/mapResponsePoint/test.html new file mode 100644 index 00000000..b8073261 --- /dev/null +++ b/test/scoring/processor/expressions/mapResponsePoint/test.html @@ -0,0 +1,20 @@ + + + + + MapResponsePoint Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/mapResponsePoint/test.js b/test/scoring/processor/expressions/mapResponsePoint/test.js new file mode 100644 index 00000000..aae33a87 --- /dev/null +++ b/test/scoring/processor/expressions/mapResponsePoint/test.js @@ -0,0 +1,431 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/mapResponsePoint', + 'taoQtiItem/scoring/processor/errorHandler' +], function( + _, + preProcessorFactory, + mapResponsePointProcessor, + errorHandler +) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(mapResponsePointProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(mapResponsePointProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('Fails if variable has no mapping', function(assert) { + var ready = assert.async(); + assert.expect(1); + mapResponsePointProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + mapResponsePointProcessor.state = { + RESPONSE: { + cardinality: 'single', + baseType: 'point', + value: '12 12' + } + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Without a mapping in the variable variable in the state it throws and error'); + ready(); + }); + + mapResponsePointProcessor.process(); + }); + + QUnit.test('Fails if the variable is not a point', function(assert) { + var ready = assert.async(); + assert.expect(1); + mapResponsePointProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + mapResponsePointProcessor.state = { + RESPONSE: { + cardinality: 'single', + baseType: 'float', + value: '12.5', + mapping: { + qtiClass: 'areaMapping' + } + } + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The variable must be of type point'); + ready(); + }); + + mapResponsePointProcessor.process(); + }); + + var dataProvider = [{ + title: 'no variable', + response: undefined, + expectedResult: null + }, { + title: 'in a rectangle', + response: { + cardinality: 'single', + baseType: 'point', + value: '15 15', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '100' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 100 + } + }, { + title: 'out a rectangle', + response: { + cardinality: 'single', + baseType: 'point', + value: '30 30', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '100' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'in a circle', + response: { + cardinality: 'single', + baseType: 'point', + value: '20 20', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'circle', + coords: '10,10,20', + mappedValue: '2.5' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2.5 + } + }, { + title: 'out a circle', + response: { + cardinality: 'single', + baseType: 'point', + value: '20 20', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'circle', + coords: '10,10,5', + mappedValue: '2.5' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'in a simple poly', + response: { + cardinality: 'single', + baseType: 'point', + value: '134 70', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'poly', + coords: '75,10,146,79,52,132,9,51', + mappedValue: '11.75' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 11.75 + } + }, { + title: 'out a simple poly', + response: { + cardinality: 'single', + baseType: 'point', + value: '134 65', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'poly', + coords: '75,10,146,79,52,132,9,51', + mappedValue: '12' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'in a complex poly', + response: { + cardinality: 'single', + baseType: 'point', + value: '255 411', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'poly', + coords: '291,173,249,414,629,427,557,174,423,569,126,280,431,260', + mappedValue: '0.75' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.75 + } + }, { + title: 'out a complex poly', + response: { + cardinality: 'single', + baseType: 'point', + value: '380 331', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'poly', + coords: '291,173,249,414,629,427,557,174,423,569,126,280,431,260', + mappedValue: '0.25' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'in an ellipse', + response: { + cardinality: 'single', + baseType: 'point', + value: '9 12', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'ellipse', + coords: '57,18,55,14', + mappedValue: '0.25' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.25 + } + }, { + title: 'out an ellipse', + response: { + cardinality: 'single', + baseType: 'point', + value: '10 8', + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'ellipse', + coords: '57,18,55,14', + mappedValue: '0.75' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + + }, { + title: 'multiple points in a rectangle', + response: { + cardinality: 'multiple', + baseType: 'point', + value: ['15 15', '16 16'], + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '2' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2 + } + }, { + title: 'multiple points in multiple rectangles', + response: { + cardinality: 'multiple', + baseType: 'point', + value: ['15 15', '75 75'], + mapping: { + qtiClass: 'areaMapping', + attributes: {}, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '11' + }, { + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '60,60,90,90', + mappedValue: '13' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 24 + } + }, { + title: 'lowerBound', + response: { + cardinality: 'single', + baseType: 'point', + value: '15 15', + mapping: { + qtiClass: 'areaMapping', + attributes: { + lowerBound: '0.75' + }, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '0.25' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.75 + } + }, { + title: 'upperBound', + response: { + cardinality: 'single', + baseType: 'point', + value: '15 15', + mapping: { + qtiClass: 'areaMapping', + attributes: { + upperBound: '3' + }, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '3.25' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 3 + } + }, { + title: 'defaultValue', + response: { + cardinality: 'single', + baseType: 'point', + value: '1 1', + mapping: { + qtiClass: 'areaMapping', + attributes: { + defaultValue: '12' + }, + mapEntries: [{ + qtiClass: 'areaMapEntry', + shape: 'rect', + coords: '10,10,20,20', + mappedValue: '54' + }] + } + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 12 + } + }]; + + QUnit + .cases.init(dataProvider) + .test('mapResponsePoint ', function(data, assert) { + var state = { + RESPONSE: data.response + }; + + mapResponsePointProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + mapResponsePointProcessor.state = state; + mapResponsePointProcessor.preProcessor = preProcessorFactory(state); + assert.deepEqual(mapResponsePointProcessor.process(), data.expectedResult, 'The map response is correct'); + }); + +}); diff --git a/test/scoring/processor/expressions/mathConstant/test.html b/test/scoring/processor/expressions/mathConstant/test.html new file mode 100644 index 00000000..8d9e8f81 --- /dev/null +++ b/test/scoring/processor/expressions/mathConstant/test.html @@ -0,0 +1,20 @@ + + + + + MathConstant Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/mathConstant/test.js b/test/scoring/processor/expressions/mathConstant/test.js new file mode 100644 index 00000000..dd73b787 --- /dev/null +++ b/test/scoring/processor/expressions/mathConstant/test.js @@ -0,0 +1,63 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/mathConstant' +], function(_, mathConstantProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(mathConstantProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(mathConstantProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'pi is Math.PI', + expression: { + attributes: {name: 'pi'} + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI + } + }, { + title: 'pi value', + expression: { + attributes: {name: 'pi'} + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 3.141592653589793 + } + }, { + title: 'e is Math.E', + expression: { + attributes: {name: 'e'} + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.E + } + }, { + title: 'e value', + expression: { + attributes: {name: 'e'} + }, + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2.718281828459045 + } + }]; + + QUnit + .cases.init(dataProvider) + .test('math constant ', function(data, assert) { + mathConstantProcessor.expression = data.expression; + assert.deepEqual(mathConstantProcessor.process(), data.expectedResult, 'The constant value is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/null/test.html b/test/scoring/processor/expressions/null/test.html new file mode 100644 index 00000000..8b68208a --- /dev/null +++ b/test/scoring/processor/expressions/null/test.html @@ -0,0 +1,20 @@ + + + + + Null Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/null/test.js b/test/scoring/processor/expressions/null/test.js new file mode 100644 index 00000000..d41788b8 --- /dev/null +++ b/test/scoring/processor/expressions/null/test.js @@ -0,0 +1,18 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/null' +], function(_, nullProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(nullProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(nullProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('null processor', function(assert) { + assert.strictEqual(nullProcessor.process(), null, 'the processor returns null'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/and/test.html b/test/scoring/processor/expressions/operators/and/test.html new file mode 100644 index 00000000..82b86175 --- /dev/null +++ b/test/scoring/processor/expressions/operators/and/test.html @@ -0,0 +1,20 @@ + + + + + And Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/and/test.js b/test/scoring/processor/expressions/operators/and/test.js new file mode 100644 index 00000000..aa57d3e6 --- /dev/null +++ b/test/scoring/processor/expressions/operators/and/test.js @@ -0,0 +1,148 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/and' +], function(_, preProcessorFactory, andProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(andProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(andProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(andProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'false', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: 'true' + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'false', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'truth', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'truth with single', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false with single', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'truth with 3 operand', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false with 3 operand', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('and ', function(data, assert) { + andProcessor.operands = data.operands; + andProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(andProcessor.process(), data.expectedResult, 'The and is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/anyN/test.html b/test/scoring/processor/expressions/operators/anyN/test.html new file mode 100644 index 00000000..7dbff026 --- /dev/null +++ b/test/scoring/processor/expressions/operators/anyN/test.html @@ -0,0 +1,20 @@ + + + + + anyN Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/anyN/test.js b/test/scoring/processor/expressions/operators/anyN/test.js new file mode 100644 index 00000000..dfe497a0 --- /dev/null +++ b/test/scoring/processor/expressions/operators/anyN/test.js @@ -0,0 +1,190 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/anyN' +], function(_, preProcessorFactory, anyNProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(anyNProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(anyNProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(anyNProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'truth', + min: 2, + max: 4, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'truth with ref', + min: 'min', + max: 'max', + state: { + min: { + cardinality: 'single', + baseType: 'integer', + value: 2 + }, + max: { + cardinality: 'single', + baseType: 'integer', + value: 4 + } + }, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false - too much true', + min: 1, + max: 2, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'false - lack of true', + min: 2, + max: 3, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'Null', + min: 3, + max: 4, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }, null], + expectedResult: null + }, { + title: 'true with Null', + min: 3, + max: 4, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }, null], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false with Null', + min: 3, + max: 4, + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }, null], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }]; + + QUnit + .cases.init(dataProvider) + .test('anyN ', function(data, assert) { + anyNProcessor.preProcessor = preProcessorFactory(data.state ? data.state : {}); + anyNProcessor.operands = data.operands; + anyNProcessor.expression = {attributes: {min: data.min, max: data.max}}; + assert.deepEqual(anyNProcessor.process(), data.expectedResult, 'The anyN is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/constraintValidator/test.html b/test/scoring/processor/expressions/operators/constraintValidator/test.html new file mode 100644 index 00000000..31ca7c3f --- /dev/null +++ b/test/scoring/processor/expressions/operators/constraintValidator/test.html @@ -0,0 +1,20 @@ + + + + + Operator Processor's constraint validator Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/constraintValidator/test.js b/test/scoring/processor/expressions/operators/constraintValidator/test.js new file mode 100644 index 00000000..79091458 --- /dev/null +++ b/test/scoring/processor/expressions/operators/constraintValidator/test.js @@ -0,0 +1,160 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/operators/constraintValidator', + 'taoQtiItem/scoring/processor/errorHandler' +], function(_, constraintValidator, errorHandler) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.equal(typeof constraintValidator, 'function', 'the module exports a function'); + }); + + QUnit.module('Validate'); + + var dataProvider = [{ + title: 'all operands null', + constraints: { + minOperand: 1, + maxOperand: -1, + cardinality: ['single'], + baseType: ['boolean'] + }, + operands: [null, null, null], + expectedResult: true + }, { + title: 'all valide and one null', + constraints: { + minOperand: 1, + maxOperand: -1, + cardinality: ['single'], + baseType: ['boolean'] + }, + operands: [{ + baseType: 'boolean', + cardinality: 'single', + value: true + }, { + baseType: 'boolean', + cardinality: 'single', + value: false + }, null], + expectedResult: true + }, { + title: 'all valide but invalid type', + constraints: { + minOperand: 1, + maxOperand: -1, + cardinality: ['single', 'multiple'], + baseType: ['integer'] + }, + operands: [{ + baseType: 'integer', + cardinality: 'single', + value: 12 + }, { + baseType: 'integer', + cardinality: 'multiple', + value: [4, 7, 13] + }, { + baseType: 'boolean', + cardinality: 'multiple', + value: false + }], + error: new TypeError('An operand given to processor foo has an unexpected baseType') + }, { + title: 'all valide but one', + constraints: { + minOperand: 1, + maxOperand: -1, + cardinality: ['single'], + baseType: ['boolean'] + }, + operands: [{ + baseType: 'boolean', + cardinality: 'single', + value: true + }, { + baseType: 'boolean', + cardinality: 'single', + value: false + }, { + baseType: 'boolean', + cardinality: 'multiple', + value: false + }], + error: new TypeError('An operand given to processor foo has an unexpected cardinality') + }, { + title: 'wrong operands type', + constraints: { + minOperand: 1, + maxOperand: -1, + cardinality: ['single'], + baseType: ['boolean'] + }, + operands: 'a,b', + error: new TypeError('Processor foo requires operands to be an array : string given') + }, { + title: 'wrong operands minimum size', + constraints: { + minOperand: 2, + maxOperand: 3, + cardinality: ['single'], + baseType: ['boolean'] + }, + operands: [{ + baseType: 'boolean', + cardinality: 'single', + value: true + }], + error: new TypeError('Processor foo requires at least 2 operands, 1 given') + }, { + title: 'wrong operands maximum size', + constraints: { + minOperand: 1, + maxOperand: 2, + cardinality: ['single'], + baseType: ['boolean'] + }, + operands: [{ + baseType: 'boolean', + cardinality: 'single', + value: true + }, { + baseType: 'boolean', + cardinality: 'single', + value: false + }, { + baseType: 'boolean', + cardinality: 'multiple', + value: false + }], + error: new TypeError('Processor foo requires maximum 2 operands, 3 given') + }]; + + QUnit + .cases.init(dataProvider) + .test('constraintValidator.validate', function(data, assert) { + var ready = assert.async(); + + var processor = { + name: 'foo', + constraints: data.constraints + }; + + if (data.error) { + assert.expect(2); + errorHandler.listen('scoring', function(err) { + assert.ok(err instanceof Error, 'The given error is an error'); + assert.equal(data.error.message, err.message, 'The error message is the same'); + ready(); + }); + constraintValidator(processor, data.operands); + } else { + assert.expect(1); + assert.equal(constraintValidator(processor, data.operands), data.expectedResult, 'The validation returns what is expected'); + ready(); + } + }); +}); diff --git a/test/scoring/processor/expressions/operators/containerSize/test.html b/test/scoring/processor/expressions/operators/containerSize/test.html new file mode 100644 index 00000000..65ec4f04 --- /dev/null +++ b/test/scoring/processor/expressions/operators/containerSize/test.html @@ -0,0 +1,20 @@ + + + + + containerSize Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/containerSize/test.js b/test/scoring/processor/expressions/operators/containerSize/test.js new file mode 100644 index 00000000..c734cae7 --- /dev/null +++ b/test/scoring/processor/expressions/operators/containerSize/test.js @@ -0,0 +1,59 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/containerSize' +], function(_, preProcessorFactory, containerSizeProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(containerSizeProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(containerSizeProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(containerSizeProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'multiple', + operands: [{ + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 3 + } + }, { + title: 'ordered', + operands: [{ + cardinality: 'multiple', + baseType: 'float', + value: [2.5, 3.8, 7] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 3 + } + }, { + title: 'null operand', + operands: [null], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 0 + } + }]; + + QUnit + .cases.init(dataProvider) + .test('containerSize ', function(data, assert) { + containerSizeProcessor.operands = data.operands; + containerSizeProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(containerSizeProcessor.process(), data.expectedResult, 'The containerSize is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/contains/test.html b/test/scoring/processor/expressions/operators/contains/test.html new file mode 100644 index 00000000..1f892e39 --- /dev/null +++ b/test/scoring/processor/expressions/operators/contains/test.html @@ -0,0 +1,20 @@ + + + + + contains Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/contains/test.js b/test/scoring/processor/expressions/operators/contains/test.js new file mode 100644 index 00000000..839659e5 --- /dev/null +++ b/test/scoring/processor/expressions/operators/contains/test.js @@ -0,0 +1,167 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/contains' +], function(_, preProcessorFactory, containsProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(containsProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(containsProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(containsProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'multiple truth', + operands: [{ + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 3] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'multiple false', + operands: [{ + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [4, 2] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'ordered truth', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 5, 7] + }, { + cardinality: 'ordered', + baseType: 'integer', + value: [5, 7] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'different basetypes', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 5, 7] + }, { + cardinality: 'ordered', + baseType: 'string', + value: [5, 7] + }], + expectedResult: null + }, { + title: 'different cardinality', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 5, 7] + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7] + }], + expectedResult: null + }, { + title: 'ordered truth directedPair', + operands: [{ + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [7, 10], [2, 3], [4, 7]] + }, { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7]] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'multiply truth directedPair', + operands: [{ + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7]] + }, { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3]] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'ordered false directedPair', + operands: [{ + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7]] + }, { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[3, 2]] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'ordered false', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 5, 7] + }, { + cardinality: 'ordered', + baseType: 'integer', + value: [7, 5] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'null operand', + operands: [null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('contains ', function(data, assert) { + containsProcessor.operands = data.operands; + containsProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(containsProcessor.process(), data.expectedResult, 'The contains is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/delete/test.html b/test/scoring/processor/expressions/operators/delete/test.html new file mode 100644 index 00000000..12c2ce6e --- /dev/null +++ b/test/scoring/processor/expressions/operators/delete/test.html @@ -0,0 +1,20 @@ + + + + + delete Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/delete/test.js b/test/scoring/processor/expressions/operators/delete/test.js new file mode 100644 index 00000000..a6eef955 --- /dev/null +++ b/test/scoring/processor/expressions/operators/delete/test.js @@ -0,0 +1,134 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/errorHandler', + 'taoQtiItem/scoring/processor/expressions/operators/delete' +], function(_, preProcessorFactory, errorHandler, deleteProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(deleteProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(deleteProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(deleteProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process', { + afterEach: function(assert) { + errorHandler.reset('scoring'); + } + }); + + QUnit.test('Fails if the 1st operand is not single', function(assert) { + var ready = assert.async(); + assert.expect(1); + deleteProcessor.operands = [{ + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3] + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 2, 3, 2] + }]; + + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The first operand must have a single cardinality'); + ready(); + }); + deleteProcessor.preProcessor = preProcessorFactory({}); + deleteProcessor.process(); + }); + + QUnit.test('Fails if operands are not of the same type', function(assert) { + var ready = assert.async(); + assert.expect(1); + deleteProcessor.operands = [{ + cardinality: 'single', + baseType: 'pairs', + value: [2, 3] + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 2, 3, 2] + }]; + + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Operands must have the same baseType'); + ready(); + }); + deleteProcessor.preProcessor = preProcessorFactory({}); + deleteProcessor.process(); + }); + + var dataProvider = [{ + title: 'multiple', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 2 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 2, 3, 2] + }], + expectedResult: { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 3].sort() + } + }, { + title: 'ordered', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 2 + }, { + cardinality: 'ordered', + baseType: 'integer', + value: [7, 2, 3, 2] + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [7, 3] + } + }, { + title: 'incorrect baseType', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 2 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 2, 3, 2] + }], + expectedResult: null + }, { + title: 'incorrect cardinality', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 2 + }, { + cardinality: 'single', + baseType: 'integer', + value: [7, 2, 3, 2] + }], + expectedResult: null + }, { + title: 'null operand', + operands: [null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('delete ', function(data, assert) { + deleteProcessor.operands = data.operands; + deleteProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(deleteProcessor.process(), data.expectedResult, 'The delete is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/divide/test.html b/test/scoring/processor/expressions/operators/divide/test.html new file mode 100644 index 00000000..92306169 --- /dev/null +++ b/test/scoring/processor/expressions/operators/divide/test.html @@ -0,0 +1,20 @@ + + + + + Divide Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/divide/test.js b/test/scoring/processor/expressions/operators/divide/test.js new file mode 100644 index 00000000..d6d94b72 --- /dev/null +++ b/test/scoring/processor/expressions/operators/divide/test.js @@ -0,0 +1,108 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/divide' +], function(_, preProcessorFactory, divideProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(divideProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(divideProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(divideProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '6' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 3 + } + }, { + title: 'integer and float', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '6.5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 3.25 + } + }, { + title: 'zero test', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'zero test 2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: null + }, { + title: 'overflow', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Number.MIN_VALUE + }, { + cardinality: 'single', + baseType: 'float', + value: 10 + }], + expectedResult: null + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('divide ', function(data, assert) { + divideProcessor.operands = data.operands; + divideProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(divideProcessor.process(), data.expectedResult, 'The divide is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/durationGTE/test.html b/test/scoring/processor/expressions/operators/durationGTE/test.html new file mode 100644 index 00000000..e7e2a9db --- /dev/null +++ b/test/scoring/processor/expressions/operators/durationGTE/test.html @@ -0,0 +1,20 @@ + + + + + durationGTE Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/durationGTE/test.js b/test/scoring/processor/expressions/operators/durationGTE/test.js new file mode 100644 index 00000000..7a65d8d2 --- /dev/null +++ b/test/scoring/processor/expressions/operators/durationGTE/test.js @@ -0,0 +1,84 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/durationGTE' +], function(_, preProcessorFactory, durationGTEProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(durationGTEProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(durationGTEProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(durationGTEProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'greater', + operands: [{ + cardinality: 'single', + baseType: 'duration', + value: '100001' + }, { + cardinality: 'single', + baseType: 'duration', + value: '100000' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'equal', + operands: [{ + cardinality: 'single', + baseType: 'duration', + value: '100000' + }, { + cardinality: 'single', + baseType: 'duration', + value: '100000' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'greater', + operands: [{ + cardinality: 'single', + baseType: 'duration', + value: '100000' + }, { + cardinality: 'single', + baseType: 'duration', + value: '100000.1' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('durationGTE ', function(data, assert) { + durationGTEProcessor.operands = data.operands; + durationGTEProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(durationGTEProcessor.process(), data.expectedResult, 'The durationGTE is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/durationLT/test.html b/test/scoring/processor/expressions/operators/durationLT/test.html new file mode 100644 index 00000000..4ed3fdae --- /dev/null +++ b/test/scoring/processor/expressions/operators/durationLT/test.html @@ -0,0 +1,20 @@ + + + + + durationLT Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/durationLT/test.js b/test/scoring/processor/expressions/operators/durationLT/test.js new file mode 100644 index 00000000..0dcde57a --- /dev/null +++ b/test/scoring/processor/expressions/operators/durationLT/test.js @@ -0,0 +1,84 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/durationLT' +], function(_, preProcessorFactory, durationLTProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(durationLTProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(durationLTProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(durationLTProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'less', + operands: [{ + cardinality: 'single', + baseType: 'duration', + value: '100000' + }, { + cardinality: 'single', + baseType: 'duration', + value: '100001' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'equal', + operands: [{ + cardinality: 'single', + baseType: 'duration', + value: '100000' + }, { + cardinality: 'single', + baseType: 'duration', + value: '100000' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'less', + operands: [{ + cardinality: 'single', + baseType: 'duration', + value: '100000.1' + }, { + cardinality: 'single', + baseType: 'duration', + value: '100000' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('durationLT ', function(data, assert) { + durationLTProcessor.operands = data.operands; + durationLTProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(durationLTProcessor.process(), data.expectedResult, 'The durationLT is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/equal/test.html b/test/scoring/processor/expressions/operators/equal/test.html new file mode 100644 index 00000000..316ba42b --- /dev/null +++ b/test/scoring/processor/expressions/operators/equal/test.html @@ -0,0 +1,20 @@ + + + + + equal Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/equal/test.js b/test/scoring/processor/expressions/operators/equal/test.js new file mode 100644 index 00000000..56cf09ea --- /dev/null +++ b/test/scoring/processor/expressions/operators/equal/test.js @@ -0,0 +1,277 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/errorHandler', + 'taoQtiItem/scoring/processor/expressions/operators/equal' +], function(_, preProcessorFactory, errorHandler, equalProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(equalProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(equalProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(equalProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process', { + afterEach: function(assert) { + errorHandler.reset('scoring'); + } + }); + + QUnit.test('Default values', function(assert) { + assert.expect(1); + + var result = { + cardinality: 'single', + baseType: 'boolean', + value: true + }; + equalProcessor.expression = {}; + equalProcessor.operands = [{ + cardinality: 'single', + baseType: 'float', + value: '1' + }, { + cardinality: 'single', + baseType: 'float', + value: '1' + }]; + + equalProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(equalProcessor.process(), result, 'The equal is correct'); + }); + + QUnit.test('Fails if no tolerance is given when mode is relative', function(assert) { + var ready = assert.async(); + assert.expect(1); + + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Tolerance attribute is not defined'); + ready(); + }); + + equalProcessor.expression = { + attributes: { + includeLowerBound: false, + includeUpperBound: false, + toleranceMode: 'relative' + } + }; + equalProcessor.operands = [{ + cardinality: 'single', + baseType: 'float', + value: '1' + }, { + cardinality: 'single', + baseType: 'float', + value: '1.1' + }]; + equalProcessor.preProcessor = preProcessorFactory({}); + equalProcessor.process(); + }); + + var dataProvider = [{ + title: 'integers exact', + tolerance: '', + toleranceMode: 'exact', + includeLowerBound: 'true', + includeUpperBound: 'true', + + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'float absolute 2 bounds', + tolerance: '0.2 0.8', + toleranceMode: 'absolute', + includeLowerBound: true, + includeUpperBound: true, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.2' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.7' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'float absolute 1 bound', + tolerance: '0.2', + toleranceMode: 'absolute', + includeLowerBound: true, + includeUpperBound: true, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.2' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.7' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'float absolute 2 bound, not include upper', + tolerance: '0.1 0.5', + toleranceMode: 'absolute', + includeLowerBound: true, + includeUpperBound: false, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.3' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.8' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'float absolute 2 bound, not include lower', + tolerance: '0.1 0.5', + toleranceMode: 'absolute', + includeLowerBound: false, + includeUpperBound: true, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.3' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'float relative 2 bound, not include lower', + tolerance: '50 10', + toleranceMode: 'relative', + includeLowerBound: false, + includeUpperBound: true, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '10' + }, { + cardinality: 'single', + baseType: 'float', + value: '15' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'float relative 2 bound, not include lower, with ref', + tolerance: 'lowBound upBound', + state: { + lowBound: { + cardinality: 'single', + baseType: 'float', + value: 50 + }, + upBound: { + cardinality: 'single', + baseType: 'float', + value: 10 + } + }, + toleranceMode: 'relative', + includeLowerBound: false, + includeUpperBound: true, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '10' + }, { + cardinality: 'single', + baseType: 'float', + value: '15' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'float relative 1 bound, not include both', + tolerance: '50', + toleranceMode: 'relative', + includeLowerBound: false, + includeUpperBound: false, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '1' + }, { + cardinality: 'single', + baseType: 'float', + value: '1.1' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('equal ', function(data, assert) { + equalProcessor.preProcessor = preProcessorFactory(data.state ? data.state : {}); + + equalProcessor.operands = data.operands; + + equalProcessor.expression = { + attributes: { + includeLowerBound: data.includeLowerBound, + includeUpperBound: data.includeUpperBound, + toleranceMode: data.toleranceMode, + tolerance: data.tolerance + } + }; + + assert.deepEqual(equalProcessor.process(), data.expectedResult, 'The equal is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/equalRounded/test.html b/test/scoring/processor/expressions/operators/equalRounded/test.html new file mode 100644 index 00000000..1b4efa5a --- /dev/null +++ b/test/scoring/processor/expressions/operators/equalRounded/test.html @@ -0,0 +1,20 @@ + + + + + equalRounded Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/equalRounded/test.js b/test/scoring/processor/expressions/operators/equalRounded/test.js new file mode 100644 index 00000000..8eaed11e --- /dev/null +++ b/test/scoring/processor/expressions/operators/equalRounded/test.js @@ -0,0 +1,214 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/equalRounded' +], function(_, preProcessorFactory, equalRoundedProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(equalRoundedProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(equalRoundedProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(equalRoundedProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'figures as integers', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1147' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'figures as negative', + roundingMode: 'significantFigures', + figures: -10, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'figures as zero with significantFigures', + roundingMode: 'significantFigures', + figures: 0, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'figures as incorrect string ', + roundingMode: 'significantFigures', + figures: 'xxx', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'figure as reference', + roundingMode: 'significantFigures', + figures: 'ref1', + state: { + ref1: { + cardinality: 'single', + baseType: 'integer', + value: '3' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1143' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'figure as missing reference', + roundingMode: 'significantFigures', + figures: 'ref1', + state: { + ref2: { + cardinality: 'single', + baseType: 'integer', + value: '3' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'incorrect settings', + roundingMode: 'significantFigures', + figures: 0, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 12.111 + }], + expectedResult: null + }, { + title: 'incorrect settings', + roundingMode: 'significantFigures', + figures: 'string', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 12.111 + }, { + cardinality: 'single', + baseType: 'float', + value: 12.111 + }], + expectedResult: null + }, { + title: 'decimalPlaces', + roundingMode: 'decimalPlaces', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1144' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1135' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'decimalPlaces with 0 figures', + roundingMode: 'decimalPlaces', + figures: 0, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }, { + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one null', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('equalRounded ', function(data, assert) { + var state = data.state || {}; + equalRoundedProcessor.operands = data.operands; + + equalRoundedProcessor.state = state; + equalRoundedProcessor.preProcessor = preProcessorFactory(state); + + equalRoundedProcessor.expression = { + attributes: { + figures: data.figures, + roundingMode: data.roundingMode + } + }; + + assert.deepEqual(equalRoundedProcessor.process(), data.expectedResult, 'The equalRounded is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/fieldValue/test.html b/test/scoring/processor/expressions/operators/fieldValue/test.html new file mode 100644 index 00000000..11daa5ed --- /dev/null +++ b/test/scoring/processor/expressions/operators/fieldValue/test.html @@ -0,0 +1,20 @@ + + + + + fieldValue Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/fieldValue/test.js b/test/scoring/processor/expressions/operators/fieldValue/test.js new file mode 100644 index 00000000..e1c6f4ac --- /dev/null +++ b/test/scoring/processor/expressions/operators/fieldValue/test.js @@ -0,0 +1,90 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/fieldValue' +], function(_, preProcessorFactory, fieldValueProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(fieldValueProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(fieldValueProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(fieldValueProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'found field', + fieldIdentifier: 'paper', + operands: [ + { + cardinality: 'record', + value: { + rock: { + cardinality: 'single', + baseType: 'integer', + value: 10.222 + }, + paper: { + cardinality: 'multiple', + baseType: 'string', + value: ['p', 'a', 'p', 'e', 'r'] + }, + scissors: { + cardinality: 'multiple', + baseType: 'integer', + value: [1, 2, 3, 4] + } + } + } + ], + expectedResult: { + cardinality: 'multiple', + baseType: 'string', + value: ['p', 'a', 'p', 'e', 'r'].sort() + } + }, { + title: 'missing field', + fieldIdentifier: 'meal', + operands: [ + { + cardinality: 'record', + value: { + rock: { + cardinality: 'single', + baseType: 'integer', + value: 10.222 + }, + paper: { + cardinality: 'multiple', + baseType: 'string', + value: ['p', 'a', 'p', 'e', 'r'] + }, + scissors: { + cardinality: 'multiple', + baseType: 'integer', + value: [1, 2, 3, 4] + } + } + } + ], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('fieldValue ', function(data, assert) { + fieldValueProcessor.operands = data.operands; + fieldValueProcessor.preProcessor = preProcessorFactory({}); + + fieldValueProcessor.expression = { + attributes: { + fieldIdentifier: data.fieldIdentifier + } + }; + assert.deepEqual(fieldValueProcessor.process(), data.expectedResult, 'The fieldValue is correct'); + }); +}) +; diff --git a/test/scoring/processor/expressions/operators/gcd/test.html b/test/scoring/processor/expressions/operators/gcd/test.html new file mode 100644 index 00000000..88c395b9 --- /dev/null +++ b/test/scoring/processor/expressions/operators/gcd/test.html @@ -0,0 +1,20 @@ + + + + + gcd Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/gcd/test.js b/test/scoring/processor/expressions/operators/gcd/test.js new file mode 100644 index 00000000..9b432544 --- /dev/null +++ b/test/scoring/processor/expressions/operators/gcd/test.js @@ -0,0 +1,131 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/gcd' +], function(_, preProcessorFactory, gcdProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(gcdProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(gcdProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(gcdProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '16' + }, { + cardinality: 'single', + baseType: 'integer', + value: '32' + }, { + cardinality: 'single', + baseType: 'integer', + value: '8' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 8 + } + }, { + title: 'multiply integers', + operands: [{ + cardinality: 'multiply', + baseType: 'integer', + value: [10, 20, 30, 200] + }, { + cardinality: 'single', + baseType: 'integer', + value: '900' + }, { + cardinality: 'single', + baseType: 'integer', + value: '70' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 10 + } + }, { + title: 'all zeros', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '0' + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 0 + } + }, { + title: 'not all zeros', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '0' + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 2 + } + }, { + title: 'Is null', + operands: [null, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'null on wrong values with multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, Infinity] + }], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('gcd ', function(data, assert) { + gcdProcessor.operands = data.operands; + gcdProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(gcdProcessor.process(), data.expectedResult, 'The gcd is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/gt/test.html b/test/scoring/processor/expressions/operators/gt/test.html new file mode 100644 index 00000000..24f30d8d --- /dev/null +++ b/test/scoring/processor/expressions/operators/gt/test.html @@ -0,0 +1,20 @@ + + + + + Gt Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/gt/test.js b/test/scoring/processor/expressions/operators/gt/test.js new file mode 100644 index 00000000..f517a6a7 --- /dev/null +++ b/test/scoring/processor/expressions/operators/gt/test.js @@ -0,0 +1,131 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/gt' +], function(_, preProcessorFactory, gteProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(gteProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(gteProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(gteProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'integers equality', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 15 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('gt ', function(data, assert) { + gteProcessor.operands = data.operands; + gteProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(gteProcessor.process(), data.expectedResult, 'The gt is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/gte/test.html b/test/scoring/processor/expressions/operators/gte/test.html new file mode 100644 index 00000000..5793dc45 --- /dev/null +++ b/test/scoring/processor/expressions/operators/gte/test.html @@ -0,0 +1,20 @@ + + + + + Gte Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/gte/test.js b/test/scoring/processor/expressions/operators/gte/test.js new file mode 100644 index 00000000..fc74c3d4 --- /dev/null +++ b/test/scoring/processor/expressions/operators/gte/test.js @@ -0,0 +1,116 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/gte' +], function(_, preProcessorFactory, gteProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(gteProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(gteProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(gteProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'integers equality', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 15 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('gte ', function(data, assert) { + gteProcessor.operands = data.operands; + gteProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(gteProcessor.process(), data.expectedResult, 'The gte is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/index/test.html b/test/scoring/processor/expressions/operators/index/test.html new file mode 100644 index 00000000..2ae3a84f --- /dev/null +++ b/test/scoring/processor/expressions/operators/index/test.html @@ -0,0 +1,20 @@ + + + + + index Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/index/test.js b/test/scoring/processor/expressions/operators/index/test.js new file mode 100644 index 00000000..4a3924a8 --- /dev/null +++ b/test/scoring/processor/expressions/operators/index/test.js @@ -0,0 +1,109 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/errorHandler', + 'taoQtiItem/scoring/processor/expressions/operators/index' +], function(_, preProcessorFactory, errorHandler, indexProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(indexProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(indexProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(indexProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process', { + afterEach: function(assert) { + errorHandler.reset('scoring'); + } + }); + + QUnit.test('Fails if n, the index is 0', function(assert) { + var ready = assert.async(); + assert.expect(1); + indexProcessor.operands = [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 6, 9, 10] + }]; + + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The index is one based'); + ready(); + }); + + indexProcessor.expression = {attributes: {n: 0}}; + indexProcessor.preProcessor = preProcessorFactory({}); + indexProcessor.process(); + }); + + var dataProvider = [{ + title: 'exists', + n: 3, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 6, 9, 10] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 9 + } + }, { + title: 'exists - n is reference', + n: 'ref1', + state: { + ref1: { + cardinality: 'single', + baseType: 'integer', + value: '3' + } + }, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 6, 9, 10] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 9 + } + }, { + title: 'incorrect n', + n: -1, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 6, 9, 10] + }], + expectedResult: null + }, { + title: 'n - out of the range ', + n: 10, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 6, 9, 10] + }], + expectedResult: null + }, { + title: 'null operand', + n: 2, + operands: [null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('index ', function(data, assert) { + indexProcessor.operands = data.operands; + indexProcessor.state = data.state || {}; + indexProcessor.preProcessor = preProcessorFactory(data.state || {}); + indexProcessor.expression = {attributes: {n: data.n}}; + assert.deepEqual(indexProcessor.process(), data.expectedResult, 'The index is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/inside/test.html b/test/scoring/processor/expressions/operators/inside/test.html new file mode 100644 index 00000000..98c8e788 --- /dev/null +++ b/test/scoring/processor/expressions/operators/inside/test.html @@ -0,0 +1,20 @@ + + + + + inside Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/inside/test.js b/test/scoring/processor/expressions/operators/inside/test.js new file mode 100644 index 00000000..8854b1d5 --- /dev/null +++ b/test/scoring/processor/expressions/operators/inside/test.js @@ -0,0 +1,177 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/inside' +], function(_, preProcessorFactory, insideProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(insideProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(insideProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(insideProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'rect inside', + coords: '0,0,10,20', + shape: 'rect', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '1 1' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'rect outside', + coords: '0,0,10,20', + shape: 'rect', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '-21 1' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'poly inside', + coords: '291,173,249,414,629,427,557,174,423,569,126,280,431,260', + shape: 'poly', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '255 411' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'poly outside', + coords: '291,173,249,414,629,427,557,174,423,569,126,280,431,260', + shape: 'poly', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '1 1' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'default', + coords: '', + shape: 'default', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '0 8' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'circle inside', + coords: '5,5,5', + shape: 'circle', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '3 3' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'circle outside', + coords: '5,5,5', + shape: 'circle', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '31 3' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'circle', + coords: '57,18,55,14', + shape: 'ellipse', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '9 12' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'wrong type', + coords: '57,18,55,14,57,18,55,14', + shape: 'cube', + + operands: [{ + cardinality: 'single', + baseType: 'point', + value: '9 12' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + coords: '0,0,10,20', + shape: 'rect', + operands: [null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('inside ', function(data, assert) { + insideProcessor.preProcessor = preProcessorFactory({}); + + insideProcessor.operands = data.operands; + + insideProcessor.expression = { + attributes: { + coords: data.coords, + shape: data.shape + } + }; + + assert.deepEqual(insideProcessor.process(), data.expectedResult, 'The inside is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/integerDivide/test.html b/test/scoring/processor/expressions/operators/integerDivide/test.html new file mode 100644 index 00000000..4a004976 --- /dev/null +++ b/test/scoring/processor/expressions/operators/integerDivide/test.html @@ -0,0 +1,20 @@ + + + + + integerDivide Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/integerDivide/test.js b/test/scoring/processor/expressions/operators/integerDivide/test.js new file mode 100644 index 00000000..782d8851 --- /dev/null +++ b/test/scoring/processor/expressions/operators/integerDivide/test.js @@ -0,0 +1,80 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/integerDivide' +], function(_, preProcessorFactory, integerModulusProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(integerModulusProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(integerModulusProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(integerModulusProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 2 + } + }, { + title: 'zero test', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 0 + } + }, { + title: 'zero test 2', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }], + expectedResult: null + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('integerModulus ', function(data, assert) { + integerModulusProcessor.operands = data.operands; + integerModulusProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(integerModulusProcessor.process(), data.expectedResult, 'The integerModulus is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/integerModulus/test.html b/test/scoring/processor/expressions/operators/integerModulus/test.html new file mode 100644 index 00000000..45fb6136 --- /dev/null +++ b/test/scoring/processor/expressions/operators/integerModulus/test.html @@ -0,0 +1,20 @@ + + + + + integerModulus Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/integerModulus/test.js b/test/scoring/processor/expressions/operators/integerModulus/test.js new file mode 100644 index 00000000..1350f0db --- /dev/null +++ b/test/scoring/processor/expressions/operators/integerModulus/test.js @@ -0,0 +1,80 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/integerModulus' +], function(_, preProcessorFactory, integerModulusProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(integerModulusProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(integerModulusProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(integerModulusProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 1 + } + }, { + title: 'zero test', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 0 + } + }, { + title: 'zero test 2', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }], + expectedResult: null + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('integerModulus ', function(data, assert) { + integerModulusProcessor.operands = data.operands; + integerModulusProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(integerModulusProcessor.process(), data.expectedResult, 'The integerModulus is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/integerToFloat/test.html b/test/scoring/processor/expressions/operators/integerToFloat/test.html new file mode 100644 index 00000000..39092649 --- /dev/null +++ b/test/scoring/processor/expressions/operators/integerToFloat/test.html @@ -0,0 +1,20 @@ + + + + + integerToFloat Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/integerToFloat/test.js b/test/scoring/processor/expressions/operators/integerToFloat/test.js new file mode 100644 index 00000000..dc86bf88 --- /dev/null +++ b/test/scoring/processor/expressions/operators/integerToFloat/test.js @@ -0,0 +1,60 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/integerToFloat' +], function(_, preProcessorFactory, integerToFloatProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(integerToFloatProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(integerToFloatProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(integerToFloatProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integer', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '10' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 10 + } + }, { + title: 'integer', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 10 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 10 + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('integerToFloat ', function(data, assert) { + integerToFloatProcessor.operands = data.operands; + integerToFloatProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(integerToFloatProcessor.process(), data.expectedResult, 'The integerToFloat is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/isNull/test.html b/test/scoring/processor/expressions/operators/isNull/test.html new file mode 100644 index 00000000..cc8c83c1 --- /dev/null +++ b/test/scoring/processor/expressions/operators/isNull/test.html @@ -0,0 +1,20 @@ + + + + + IsNull Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/isNull/test.js b/test/scoring/processor/expressions/operators/isNull/test.js new file mode 100644 index 00000000..0cc2698c --- /dev/null +++ b/test/scoring/processor/expressions/operators/isNull/test.js @@ -0,0 +1,70 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/isNull' +], function(_, preProcessorFactory, isNullProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(isNullProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(isNullProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(isNullProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'not null integer', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'not null falsy', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'null value', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: null + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'null operand', + operands: [null], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }]; + + QUnit + .cases.init(dataProvider) + .test('isNull ', function(data, assert) { + isNullProcessor.operands = data.operands; + isNullProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(isNullProcessor.process(), data.expectedResult, 'The isNull is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/lcm/test.html b/test/scoring/processor/expressions/operators/lcm/test.html new file mode 100644 index 00000000..666c5dd6 --- /dev/null +++ b/test/scoring/processor/expressions/operators/lcm/test.html @@ -0,0 +1,20 @@ + + + + + lcm Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/lcm/test.js b/test/scoring/processor/expressions/operators/lcm/test.js new file mode 100644 index 00000000..f52040f9 --- /dev/null +++ b/test/scoring/processor/expressions/operators/lcm/test.js @@ -0,0 +1,131 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/lcm' +], function(_, preProcessorFactory, lcmProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(lcmProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(lcmProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(lcmProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '16' + }, { + cardinality: 'single', + baseType: 'integer', + value: '32' + }, { + cardinality: 'single', + baseType: 'integer', + value: '8' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 32 + } + }, { + title: 'multiply integers', + operands: [{ + cardinality: 'multiply', + baseType: 'integer', + value: [10, 20, 30] + }, { + cardinality: 'single', + baseType: 'integer', + value: '900' + }, { + cardinality: 'single', + baseType: 'integer', + value: '70' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 6300 + } + }, { + title: 'all zeros', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '0' + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 0 + } + }, { + title: 'not all zeros', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '0' + }, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 0 + } + }, { + title: 'Is null', + operands: [null, { + cardinality: 'single', + baseType: 'integer', + value: 0 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'null on wrong values with multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, Infinity] + }], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('lcm ', function(data, assert) { + lcmProcessor.operands = data.operands; + lcmProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(lcmProcessor.process(), data.expectedResult, 'The lcm is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/lt/test.html b/test/scoring/processor/expressions/operators/lt/test.html new file mode 100644 index 00000000..7ef8e973 --- /dev/null +++ b/test/scoring/processor/expressions/operators/lt/test.html @@ -0,0 +1,20 @@ + + + + + Lt Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/lt/test.js b/test/scoring/processor/expressions/operators/lt/test.js new file mode 100644 index 00000000..013fcf2f --- /dev/null +++ b/test/scoring/processor/expressions/operators/lt/test.js @@ -0,0 +1,100 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/lt' +], function(_, preProcessorFactory, ltProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(ltProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(ltProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(ltProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 15 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('lt ', function(data, assert) { + ltProcessor.operands = data.operands; + ltProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(ltProcessor.process(), data.expectedResult, 'The lt is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/lte/test.html b/test/scoring/processor/expressions/operators/lte/test.html new file mode 100644 index 00000000..de8c16bb --- /dev/null +++ b/test/scoring/processor/expressions/operators/lte/test.html @@ -0,0 +1,20 @@ + + + + + Lte Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/lte/test.js b/test/scoring/processor/expressions/operators/lte/test.js new file mode 100644 index 00000000..202a3ee7 --- /dev/null +++ b/test/scoring/processor/expressions/operators/lte/test.js @@ -0,0 +1,131 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/lte' +], function(_, preProcessorFactory, ltProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(ltProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(ltProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(ltProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'integers equality', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 15 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }, { + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('lt ', function(data, assert) { + ltProcessor.operands = data.operands; + ltProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(ltProcessor.process(), data.expectedResult, 'The lt is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/match/test.html b/test/scoring/processor/expressions/operators/match/test.html new file mode 100644 index 00000000..b283279f --- /dev/null +++ b/test/scoring/processor/expressions/operators/match/test.html @@ -0,0 +1,20 @@ + + + + + match Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/match/test.js b/test/scoring/processor/expressions/operators/match/test.js new file mode 100644 index 00000000..66d2d129 --- /dev/null +++ b/test/scoring/processor/expressions/operators/match/test.js @@ -0,0 +1,249 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/match' +], function(_, preProcessorFactory, matchProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(matchProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(matchProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(matchProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integer', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '2' + }, { + cardinality: 'single', + baseType: 'integer', + value: '3' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'integer', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 3 + }, { + cardinality: 'single', + baseType: 'integer', + value: '3' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'identifier', + operands: [{ + cardinality: 'single', + baseType: 'identifier', + value: 'over' + }, { + cardinality: 'single', + baseType: 'identifier', + value: 'over' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'identifier', + operands: [{ + cardinality: 'single', + baseType: 'identifier', + value: 'overfalse' + }, { + cardinality: 'single', + baseType: 'identifier', + value: 'over' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'boolean', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'boolean', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: 'true' + }, { + cardinality: 'single', + baseType: 'boolean', + value: 'false' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'boolean', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'pair', + operands: [{ + cardinality: 'single', + baseType: 'pair', + value: ['id1', 'id2'] + }, { + cardinality: 'single', + baseType: 'pair', + value: ['id2', 'id1'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'pair', + operands: [{ + cardinality: 'single', + baseType: 'pair', + value: ['id1', 'id2'] + }, { + cardinality: 'single', + baseType: 'pair', + value: ['id1', 'id2'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'pair', + operands: [{ + cardinality: 'single', + baseType: 'pair', + value: ['id1', 'id2'] + }, { + cardinality: 'single', + baseType: 'pair', + value: ['id1', 'id3'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'pair multiple', + operands: [{ + cardinality: 'multiple', + baseType: 'pair', + value: [['id1', 'id2'], ['id2', 'id3']] + }, { + cardinality: 'multiple', + baseType: 'pair', + value: [['id1', 'id2'], ['id2', 'id5']] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'directedPair', + operands: [{ + cardinality: 'single', + baseType: 'directedPair', + value: ['id1', 'id2'] + }, { + cardinality: 'single', + baseType: 'directedPair', + value: ['id1', 'id2'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'directedPair', + operands: [{ + cardinality: 'single', + baseType: 'directedPair', + value: ['id2', 'id1'] + }, { + cardinality: 'single', + baseType: 'directedPair', + value: ['id1', 'id2'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, + null, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + } + ]; + + QUnit + .cases.init(dataProvider) + .test('match ', function(data, assert) { + matchProcessor.operands = data.operands; + matchProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(matchProcessor.process(), data.expectedResult, 'The match is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/mathOperator/test.html b/test/scoring/processor/expressions/operators/mathOperator/test.html new file mode 100644 index 00000000..619b1d12 --- /dev/null +++ b/test/scoring/processor/expressions/operators/mathOperator/test.html @@ -0,0 +1,21 @@ + + + + + mathOperator Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/mathOperator/test.js b/test/scoring/processor/expressions/operators/mathOperator/test.js new file mode 100644 index 00000000..617ac8eb --- /dev/null +++ b/test/scoring/processor/expressions/operators/mathOperator/test.js @@ -0,0 +1,1056 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/mathOperator' +], function(_, preProcessorFactory, mathOperatorProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(mathOperatorProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(mathOperatorProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(mathOperatorProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'sin', + name: 'sin', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.PI / 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'cos', + name: 'cos', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'tan', + name: 'tan', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'tan', + name: 'tan', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.PI / 4 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'sec1', + name: 'sec', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.PI + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -1 + } + }, { + title: 'sec', + name: 'sec', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: 'sec', + name: 'sec', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.PI / 2 + }], + expectedResult: null + }, { + title: 'sec', + name: 'sec', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.PI / 3 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2 + } + }, { + title: 'asin0', + name: 'asin', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'asin', + name: 'asin', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI / 2 + } + }, { + title: 'asin overflow', + name: 'asin', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1.4 + }], + expectedResult: null + }, { + title: 'acos overflow', + name: 'acos', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1.4 + }], + expectedResult: null + }, { + title: 'acos', + name: 'acos', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'asec < 1', + name: 'asec', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.2 + }], + expectedResult: null + }, { + title: 'asec', + name: 'asec', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.7721542475852274 + } + }, { + title: 'acsc < 1', + name: 'acsc', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.2 + }], + expectedResult: null + }, { + title: 'acsc ', + name: 'acsc', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -0.2013579207903308 + } + }, { + title: 'acot ', + name: 'acot', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -0.19739555984988078 + } + }, { + title: 'acot ', + name: 'acot', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0.1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.4711276743037345 + } + }, { + title: 'atan', + name: 'atan', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI / 4 + } + }, { + title: 'atan', + name: 'atan', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: +0 + }, { + cardinality: 'single', + baseType: 'float', + value: 10 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -0 + }, { + cardinality: 'single', + baseType: 'float', + value: 10 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 10 + }, { + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -10 + }, { + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 10 + }, { + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 20 + }, { + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI / 2 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -20 + }, { + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Math.PI / 2 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }, { + cardinality: 'single', + baseType: 'float', + value: 20 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Math.PI / 2 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }, { + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI / 4 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }, { + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 3 * Math.PI / 4 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }, { + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Math.PI / 4 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }, { + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -3 * Math.PI / 4 + } + }, { + title: 'atan2', + name: 'atan2', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }, { + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: null + }, { + title: 'sinh', + name: 'sinh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'sinh', + name: 'sinh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.1752011936438014 + } + }, { + title: 'cosh', + name: 'cosh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.5430806348152437 + } + }, { + title: 'cosh', + name: 'cosh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'cosh', + name: 'cosh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'tanh', + name: 'tanh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'tanh', + name: 'tanh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -1 + } + }, { + title: 'tanh', + name: 'tanh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'tanh', + name: 'tanh', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.7615941559557649 + } + }, { + title: 'sech', + name: 'sech', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.6480542736638855 + } + }, { + title: 'csch', + name: 'csch', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.8509181282393216 + } + }, { + title: 'coth', + name: 'coth', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1.3130352854993312 + } + }, { + title: 'log', + name: 'log', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'log', + name: 'log', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + }, { + title: 'log', + name: 'log', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 100 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2 + } + }, { + title: 'ln', + name: 'ln', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.E + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'log', + name: 'log', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -1 + }], + expectedResult: null + }, { + title: 'exp', + name: 'exp', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: 'exp', + name: 'exp', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'exp', + name: 'exp', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'exp', + name: 'exp', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.E + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 15.154262241479264 + } + }, { + title: 'abs', + name: 'abs', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Math.E + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.E + } + }, { + title: 'abs', + name: 'abs', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.E + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.E + } + }, { + title: 'abs', + name: 'abs', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'abs', + name: 'abs', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: 'signum', + name: 'signum', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: 'signum', + name: 'signum', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 0 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0 + } + }, { + title: 'signum', + name: 'signum', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 100 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 1 + } + }, { + title: 'signum', + name: 'signum', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -100 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -1 + } + }, { + title: 'floor', + name: 'floor', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 100.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 100 + } + }, { + title: 'floor', + name: 'floor', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'floor', + name: 'floor', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + }, { + title: 'ceil', + name: 'ceil', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 100.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 101 + } + }, { + title: 'ceil', + name: 'ceil', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'ceil', + name: 'ceil', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + }, { + title: 'toDegrees', + name: 'toDegrees', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Math.PI + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 180 + } + }, { + title: 'toDegrees', + name: 'toDegrees', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: 'toDegrees', + name: 'toDegrees', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'toDegrees', + name: 'toDegrees', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + }, { + title: 'toRadians', + name: 'toRadians', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'toRadians', + name: 'toRadians', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 180 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Math.PI + } + }, { + title: 'toRadians', + name: 'toRadians', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + }, { + title: 'wrong function', + name: 'jump', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'one null', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, null], + expectedResult: null + } + ]; + + var accuracy = mathOperatorProcessor.accuracy; + QUnit + .cases.init(dataProvider) + .test('mathOperator ', function(data, assert) { + mathOperatorProcessor.operands = data.operands; + + mathOperatorProcessor.preProcessor = preProcessorFactory(data.state ? data.state : {}); + + mathOperatorProcessor.expression = { + attributes: { + name: data.name + } + }; + + var results = mathOperatorProcessor.process(); + if (_.isNull(results) || _.isNull(data.expectedResult)) { + assert.equal(data.expectedResult, results, 'The mathOperator is correct'); + } else { + assert.equal(data.expectedResult.cardinality, results.cardinality, 'The mathOperator - cardinality is correct'); + assert.equal(data.expectedResult.baseType, results.baseType, ' The mathOperator is correct'); + assert.close(results.value, data.expectedResult.value, accuracy, 'The mathOperator value is correct with accuracy ' + accuracy); + } + + }); +}); diff --git a/test/scoring/processor/expressions/operators/max/test.html b/test/scoring/processor/expressions/operators/max/test.html new file mode 100644 index 00000000..eb371db1 --- /dev/null +++ b/test/scoring/processor/expressions/operators/max/test.html @@ -0,0 +1,20 @@ + + + + + Max Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/max/test.js b/test/scoring/processor/expressions/operators/max/test.js new file mode 100644 index 00000000..fb9195eb --- /dev/null +++ b/test/scoring/processor/expressions/operators/max/test.js @@ -0,0 +1,165 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/max' +], function(_, preProcessorFactory, maxProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(maxProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(maxProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(maxProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 5 + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 5 + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.333323' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.666677' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 5.666677 + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 10.25 + } + }, { + title: 'null on wrong values', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: NaN + }, { + cardinality: 'single', + baseType: 'integer', + value: Infinity + }], + expectedResult: null + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null, + { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 3 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, 11] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 11 + } + }, { + title: 'null on wrong values with multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, 11] + }, { + cardinality: 'single', + baseType: 'integer', + value: undefined + }], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('max ', function(data, assert) { + maxProcessor.operands = data.operands; + maxProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(maxProcessor.process(), data.expectedResult, 'The max is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/member/test.html b/test/scoring/processor/expressions/operators/member/test.html new file mode 100644 index 00000000..9a32f69d --- /dev/null +++ b/test/scoring/processor/expressions/operators/member/test.html @@ -0,0 +1,20 @@ + + + + + member Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/member/test.js b/test/scoring/processor/expressions/operators/member/test.js new file mode 100644 index 00000000..73e853f6 --- /dev/null +++ b/test/scoring/processor/expressions/operators/member/test.js @@ -0,0 +1,135 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/member' +], function(_, preProcessorFactory, memberProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(memberProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(memberProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(memberProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'multiple truth', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 7 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [7, 3] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'string false', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'xx,' + }, { + cardinality: 'multiple', + baseType: 'string', + value: ['xx', 'yy'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'different basetypes', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 7 + }, { + cardinality: 'ordered', + baseType: 'string', + value: [5, 7] + }], + expectedResult: null + }, { + title: 'multiple false', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 22 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [4, 2] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'incorrect cardinality', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 5, 7] + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7] + }], + expectedResult: null + }, { + title: 'ordered truth directedPair', + operands: [{ + cardinality: 'single', + baseType: 'directedPair', + value: [2, 3] + }, { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[5, 8], [2, 3], [4, 7]] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'ordered false directedPair', + operands: [{ + cardinality: 'single', + baseType: 'directedPair', + value: [2, 3] + }, { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[3, 2], [4, 22]] + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'null operand', + operands: [null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('member ', function(data, assert) { + memberProcessor.operands = data.operands; + memberProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(memberProcessor.process(), data.expectedResult, 'The member is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/min/test.html b/test/scoring/processor/expressions/operators/min/test.html new file mode 100644 index 00000000..d2decf78 --- /dev/null +++ b/test/scoring/processor/expressions/operators/min/test.html @@ -0,0 +1,20 @@ + + + + + Min Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/min/test.js b/test/scoring/processor/expressions/operators/min/test.js new file mode 100644 index 00000000..1ace93ba --- /dev/null +++ b/test/scoring/processor/expressions/operators/min/test.js @@ -0,0 +1,164 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/min' +], function(_, preProcessorFactory, minProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(minProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(minProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(minProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 2 + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 2 + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.333323' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.666677' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 5.333323 + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2 + } + }, { + title: 'null on wrong values', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: NaN + }, { + cardinality: 'single', + baseType: 'integer', + value: Infinity + }], + expectedResult: null + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null, + { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 3 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, 11] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 3 + } + }, { + title: 'null on wrong values with multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, 11] + }, { + cardinality: 'single', + baseType: 'integer', + value: undefined + }], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('min ', function(data, assert) { + minProcessor.operands = data.operands; + minProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(minProcessor.process(), data.expectedResult, 'The min is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/multiple/test.html b/test/scoring/processor/expressions/operators/multiple/test.html new file mode 100644 index 00000000..f6b161c6 --- /dev/null +++ b/test/scoring/processor/expressions/operators/multiple/test.html @@ -0,0 +1,20 @@ + + + + + multiple Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/multiple/test.js b/test/scoring/processor/expressions/operators/multiple/test.js new file mode 100644 index 00000000..f91e482f --- /dev/null +++ b/test/scoring/processor/expressions/operators/multiple/test.js @@ -0,0 +1,99 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/multiple' +], function(_, preProcessorFactory, multipleProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(multipleProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(multipleProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(multipleProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'multiple integer', + operands: [{ + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7, 5] + } + }, { + title: 'multiple directedPair', + operands: [{ + cardinality: 'multiple', + baseType: 'directedPair', + value: [[2, 3], [4, 7]] + }, { + cardinality: 'single', + baseType: 'directedPair', + value: [5, 10] + }], + expectedResult: { + cardinality: 'multiple', + baseType: 'directedPair', + value: [[2, 3], [4, 7], [5, 10]] + } + }, { + title: 'multiple integer with nulls', + operands: [{ + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7] + }, null, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'multiple', + baseType: 'integer', + value: [2, 3, 7, 5, 5] + } + }, { + title: 'different baeTypes', + operands: [{ + cardinality: 'multiple', + baseType: 'float', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: [5] + }], + expectedResult: null + }, { + title: 'null operand', + operands: [null, null], + expectedResult: null + }, { + title: 'no operands', + operands: [], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('multiple ', function(data, assert) { + multipleProcessor.preProcessor = preProcessorFactory({}); + multipleProcessor.operands = data.operands; + assert.deepEqual(multipleProcessor.process(), data.expectedResult, 'The multiple is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/not/test.html b/test/scoring/processor/expressions/operators/not/test.html new file mode 100644 index 00000000..11169357 --- /dev/null +++ b/test/scoring/processor/expressions/operators/not/test.html @@ -0,0 +1,20 @@ + + + + + Not Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/not/test.js b/test/scoring/processor/expressions/operators/not/test.js new file mode 100644 index 00000000..2e0cf5e8 --- /dev/null +++ b/test/scoring/processor/expressions/operators/not/test.js @@ -0,0 +1,72 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/not' +], function(_, preProcessorFactory, notProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(notProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(notProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(notProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'boolean string', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: 'true' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'boolean', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'boolean number', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: '1' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('not ', function(data, assert) { + notProcessor.operands = data.operands; + notProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(notProcessor.process(), data.expectedResult, 'The not is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/or/test.html b/test/scoring/processor/expressions/operators/or/test.html new file mode 100644 index 00000000..4dce0591 --- /dev/null +++ b/test/scoring/processor/expressions/operators/or/test.html @@ -0,0 +1,20 @@ + + + + + OR Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/or/test.js b/test/scoring/processor/expressions/operators/or/test.js new file mode 100644 index 00000000..494fc57e --- /dev/null +++ b/test/scoring/processor/expressions/operators/or/test.js @@ -0,0 +1,148 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/or' +], function(_, preProcessorFactory, orProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(orProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(orProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(orProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'truth strings', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: 'true' + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'truth', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'truth with single', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false with single', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'truth with 3 operands', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: true + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: true + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'false with 3 operands', + operands: [{ + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }, { + cardinality: 'single', + baseType: 'boolean', + value: false + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('or ', function(data, assert) { + orProcessor.operands = data.operands; + orProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(orProcessor.process(), data.expectedResult, 'The or is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/ordered/test.html b/test/scoring/processor/expressions/operators/ordered/test.html new file mode 100644 index 00000000..cd5e8a4e --- /dev/null +++ b/test/scoring/processor/expressions/operators/ordered/test.html @@ -0,0 +1,20 @@ + + + + + ordered Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/ordered/test.js b/test/scoring/processor/expressions/operators/ordered/test.js new file mode 100644 index 00000000..b76c8bc4 --- /dev/null +++ b/test/scoring/processor/expressions/operators/ordered/test.js @@ -0,0 +1,109 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/errorHandler', + 'taoQtiItem/scoring/processor/expressions/operators/ordered' +], function(_, preProcessorFactory, errorHandler, orderedProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(orderedProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(orderedProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(orderedProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + QUnit.test('Fails if operands are not of the same baseType', function(assert) { + var ready = assert.async(); + assert.expect(1); + orderedProcessor.operands = [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'float', + value: 5.5 + }]; + + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Operands must be of the same type'); + ready(); + }); + orderedProcessor.preProcessor = preProcessorFactory({}); + orderedProcessor.process(); + }); + + var dataProvider = [{ + title: 'ordered integer', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7, 5] + } + }, { + title: 'ordered directedPair', + operands: [{ + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7]] + }, { + cardinality: 'single', + baseType: 'directedPair', + value: [5, 10] + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7], [5, 10]] + } + }, { + title: 'ordered integer with nulls', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, null, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7, 5, 5] + } + }, { + title: 'null operand', + operands: [null, null], + expectedResult: null + }, { + title: 'no operands', + operands: [], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('ordered ', function(data, assert) { + orderedProcessor.operands = data.operands; + orderedProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(orderedProcessor.process(), data.expectedResult, 'The ordered is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/patternMatch/test.html b/test/scoring/processor/expressions/operators/patternMatch/test.html new file mode 100644 index 00000000..918ce31b --- /dev/null +++ b/test/scoring/processor/expressions/operators/patternMatch/test.html @@ -0,0 +1,20 @@ + + + + + patternMatch Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/patternMatch/test.js b/test/scoring/processor/expressions/operators/patternMatch/test.js new file mode 100644 index 00000000..a599fdcd --- /dev/null +++ b/test/scoring/processor/expressions/operators/patternMatch/test.js @@ -0,0 +1,224 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/patternMatch' +], function(_, preProcessorFactory, patternMatchProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(patternMatchProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(patternMatchProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(patternMatchProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'don\'t match', + pattern: 'rain', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'The rain in' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: ' match with dot', + pattern: 'ra(.*)in', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'raalksjaslkdjin' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'don\'t match', + pattern: '^rain$', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'rain' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'match - escaping for ^', + pattern: 'ra^in', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'ra^in' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: ' match ', + pattern: '.*rain.*', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'the rain was' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: ' match ', + pattern: '\\d{1,2}', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 99 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: ' don\'t match ', + pattern: '.*rain.*', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'the Rain was' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: ' match ', + pattern: '.*ra/in.*', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'the ra/in was' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'match', + pattern: 'rain', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'rain' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'match - ref', + pattern: 'ref1', + state: { + ref1: { + cardinality: 'single', + baseType: 'string', + value: 'rain' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'rain' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'don\'t - match - ref(exists)', + pattern: 'rain', + state: { + rain: { + cardinality: 'single', + baseType: 'string', + value: 'hidden' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'rain' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'don\'t - match - ref(missing)', + pattern: 'rain', + state: { + draw: { + cardinality: 'single', + baseType: 'string', + value: 'hidden' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'rain' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'don\'t match', + pattern: 'car', + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'The rain in' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + pattern: /car/, + operands: [null], + expectedResult: null + } + ]; + + QUnit + .cases.init(dataProvider) + .test('patternMatch ', function(data, assert) { + patternMatchProcessor.preProcessor = preProcessorFactory(data.state ? data.state : {}); + patternMatchProcessor.operands = data.operands; + patternMatchProcessor.expression = {attributes: {pattern: data.pattern}}; + assert.deepEqual(patternMatchProcessor.process(), data.expectedResult, 'The patternMatch is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/power/test.html b/test/scoring/processor/expressions/operators/power/test.html new file mode 100644 index 00000000..1e64f43f --- /dev/null +++ b/test/scoring/processor/expressions/operators/power/test.html @@ -0,0 +1,20 @@ + + + + + Power Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/power/test.js b/test/scoring/processor/expressions/operators/power/test.js new file mode 100644 index 00000000..0d34f96d --- /dev/null +++ b/test/scoring/processor/expressions/operators/power/test.js @@ -0,0 +1,124 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/power' +], function(_, preProcessorFactory, powerProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(powerProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(powerProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(powerProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '2' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 4 + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 3 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 9 + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '2.1' + }, { + cardinality: 'single', + baseType: 'float', + value: '3.2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 10.74241047739471 + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 4 + }, { + cardinality: 'single', + baseType: 'float', + value: 0.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 2 + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, null], + expectedResult: null + }, { + title: 'Overflow max range', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Number.MAX_VALUE + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'Overflow min range', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Number.MIN_VALUE + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + } + ]; + + QUnit + .cases.init(dataProvider) + .test('power ', function(data, assert) { + powerProcessor.operands = data.operands; + powerProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(powerProcessor.process(), data.expectedResult, 'The power is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/product/test.html b/test/scoring/processor/expressions/operators/product/test.html new file mode 100644 index 00000000..8beef5fa --- /dev/null +++ b/test/scoring/processor/expressions/operators/product/test.html @@ -0,0 +1,20 @@ + + + + + Product Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/product/test.js b/test/scoring/processor/expressions/operators/product/test.js new file mode 100644 index 00000000..6974f733 --- /dev/null +++ b/test/scoring/processor/expressions/operators/product/test.js @@ -0,0 +1,151 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/product' +], function(_, preProcessorFactory, productProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(productProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(productProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(productProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 50 + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 2 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 20 + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '0.13' + }, { + cardinality: 'single', + baseType: 'float', + value: '0.16' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.020800000000000003 + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 8 + }, { + cardinality: 'single', + baseType: 'float', + value: 0.25 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 4 + } + }, { + title: 'ignore wrong values', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: NaN + }, { + cardinality: 'single', + baseType: 'integer', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 5 + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 2 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [2, 2, 2] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 16 + } + }]; + + QUnit + .cases.init(dataProvider) + .test('product ', function(data, assert) { + productProcessor.operands = data.operands; + productProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(productProcessor.process(), data.expectedResult, 'The product is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/random/test.html b/test/scoring/processor/expressions/operators/random/test.html new file mode 100644 index 00000000..c49a10b3 --- /dev/null +++ b/test/scoring/processor/expressions/operators/random/test.html @@ -0,0 +1,20 @@ + + + + + random Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/random/test.js b/test/scoring/processor/expressions/operators/random/test.js new file mode 100644 index 00000000..48830810 --- /dev/null +++ b/test/scoring/processor/expressions/operators/random/test.js @@ -0,0 +1,77 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/random' +], function(_, preProcessorFactory, randomProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(randomProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(randomProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(randomProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'string', + operands: [{ + cardinality: 'multiple', + baseType: 'string', + value: ['xx', 'yy', 'zz'] + }], + expectedResult: { + cardinality: 'single', + baseType: 'string' + } + }, { + title: 'integer', + operands: [{ + cardinality: 'multiple', + baseType: 'integer', + value: ['2', '3', 5] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer' + } + }, { + title: 'pair', + operands: [{ + cardinality: 'multiple', + baseType: 'pair', + value: [[2, 3], [5, 7], [10, 20]] + }], + expectedResult: { + cardinality: 'single', + baseType: 'pair' + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('random ', function(data, assert) { + randomProcessor.operands = data.operands; + randomProcessor.preProcessor = preProcessorFactory({}); + + var result = randomProcessor.process(); + if (_.isNull(result)) { + assert.equal(result, data.expectedResult, 'The null check'); + } else { + assert.equal(result.baseType, data.expectedResult.baseType, 'The random baseType is correct'); + assert.equal(result.cardinality, data.expectedResult.cardinality, 'The random cardinality is correct'); + assert.notEqual(data.operands[0].value.indexOf(result.value), -1, 'The random value is correct'); + } + }); +}); diff --git a/test/scoring/processor/expressions/operators/repeat/test.html b/test/scoring/processor/expressions/operators/repeat/test.html new file mode 100644 index 00000000..52d940fc --- /dev/null +++ b/test/scoring/processor/expressions/operators/repeat/test.html @@ -0,0 +1,20 @@ + + + + + repeat Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/repeat/test.js b/test/scoring/processor/expressions/operators/repeat/test.js new file mode 100644 index 00000000..475af9da --- /dev/null +++ b/test/scoring/processor/expressions/operators/repeat/test.js @@ -0,0 +1,161 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/repeat' +], function(_, preProcessorFactory, repeatProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(repeatProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(repeatProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(repeatProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'repeat integer', + numberRepeats: 2, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7, 5, 2, 3, 7, 5] + } + }, { + title: 'repeat-1 integer', + numberRepeats: 1, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7, 5] + } + }, { + title: 'repeat integer with ref', + numberRepeats: 'ref1', + state: { + ref1: { + cardinality: 'single', + baseType: 'integer', + value: '2' + } + }, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7, 5, 2, 3, 7, 5] + } + }, { + title: 'repeat integer with nulls', + numberRepeats: 3, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2] + }, null, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'integer', + value: [2, 5, 5, 2, 5, 5, 2, 5, 5] + } + }, { + title: 'ordered directedPair', + numberRepeats: 2, + operands: [{ + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7]] + }, { + cardinality: 'single', + baseType: 'directedPair', + value: [5, 10] + }], + expectedResult: { + cardinality: 'ordered', + baseType: 'directedPair', + value: [[2, 3], [4, 7], [5, 10], [2, 3], [4, 7], [5, 10]] + } + }, { + title: 'different baseTypes', + numberRepeats: 3, + operands: [{ + cardinality: 'ordered', + baseType: 'float', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: [5] + }], + expectedResult: null + }, { + title: 'null operand', + numberRepeats: 3, + operands: [null, null], + expectedResult: null + }, { + title: 'no operands', + numberRepeats: 3, + operands: [], + expectedResult: null + }, { + title: 'incorrect numberRepeats', + numberRepeats: -1, + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }, { + cardinality: 'single', + baseType: 'integer', + value: 5 + }], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('repeat ', function(data, assert) { + repeatProcessor.operands = data.operands; + repeatProcessor.expression = {attributes: {numberRepeats: data.numberRepeats}}; + repeatProcessor.state = data.state ? data.state : {}; + repeatProcessor.preProcessor = preProcessorFactory(data.state ? data.state : {}); + assert.deepEqual(repeatProcessor.process(), data.expectedResult, 'The repeat is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/round/test.html b/test/scoring/processor/expressions/operators/round/test.html new file mode 100644 index 00000000..ce9435ed --- /dev/null +++ b/test/scoring/processor/expressions/operators/round/test.html @@ -0,0 +1,20 @@ + + + + + Round Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/round/test.js b/test/scoring/processor/expressions/operators/round/test.js new file mode 100644 index 00000000..9043ab33 --- /dev/null +++ b/test/scoring/processor/expressions/operators/round/test.js @@ -0,0 +1,92 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/round' +], function(_, preProcessorFactory, roundProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(roundProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(roundProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(roundProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'float up', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.5145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 21 + } + }, { + title: 'float down', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20 + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, null], + expectedResult: null + }, { + title: '+Inf', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: 'Nan', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: '-Inf', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + } + ]; + + QUnit + .cases.init(dataProvider) + .test('round ', function(data, assert) { + roundProcessor.operands = data.operands; + roundProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(roundProcessor.process(), data.expectedResult, 'The round is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/roundTo/test.html b/test/scoring/processor/expressions/operators/roundTo/test.html new file mode 100644 index 00000000..b3df6ca1 --- /dev/null +++ b/test/scoring/processor/expressions/operators/roundTo/test.html @@ -0,0 +1,20 @@ + + + + + RoundTo Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/roundTo/test.js b/test/scoring/processor/expressions/operators/roundTo/test.js new file mode 100644 index 00000000..e5205487 --- /dev/null +++ b/test/scoring/processor/expressions/operators/roundTo/test.js @@ -0,0 +1,220 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/roundTo' +], function(_, preProcessorFactory, roundToProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(roundToProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(roundToProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(roundToProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'figures as integers', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20.115 + } + }, { + title: 'figures as negative', + roundingMode: 'significantFigures', + figures: -10, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'figures as zero with significantFigures', + roundingMode: 'significantFigures', + figures: 0, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'figures as string ', + roundingMode: 'significantFigures', + figures: '3', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20.115 + } + }, { + title: 'figures as incorrect string ', + roundingMode: 'significantFigures', + figures: 'xxx', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'figure as reference', + roundingMode: 'significantFigures', + figures: 'ref1', + state: { + ref1: { + cardinality: 'single', + baseType: 'integer', + value: '3' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20.115 + } + }, { + title: 'figure as missing reference', + roundingMode: 'significantFigures', + figures: 'ref1', + state: { + ref2: { + cardinality: 'single', + baseType: 'integer', + value: '3' + } + }, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: null + }, { + title: 'incorrect settings', + roundingMode: 'significantFigures', + figures: 0, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 12.111 + }], + expectedResult: null + }, { + title: 'incorrect settings', + roundingMode: 'significantFigures', + figures: 'string', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 12.111 + }], + expectedResult: null + }, { + title: 'decimalPlaces', + roundingMode: 'decimalPlaces', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20.114 + } + }, { + title: 'decimalPlaces with 0 figures', + roundingMode: 'decimalPlaces', + figures: 0, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.1145' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20 + } + }, { + title: 'one null', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, null], + expectedResult: null + }, { + title: '+Inf', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: '-Inf', + roundingMode: 'significantFigures', + figures: 3, + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + } + ]; + + QUnit + .cases.init(dataProvider) + .test('roundTo ', function(data, assert) { + roundToProcessor.operands = data.operands; + + roundToProcessor.state = data.state ? data.state : {}; + roundToProcessor.preProcessor = preProcessorFactory(data.state ? data.state : {}); + + roundToProcessor.expression = { + attributes: { + figures: data.figures, + roundingMode: data.roundingMode + } + }; + + assert.deepEqual(roundToProcessor.process(), data.expectedResult, 'The roundTo is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/statsOperator/test.html b/test/scoring/processor/expressions/operators/statsOperator/test.html new file mode 100644 index 00000000..978154cd --- /dev/null +++ b/test/scoring/processor/expressions/operators/statsOperator/test.html @@ -0,0 +1,20 @@ + + + + + statsOperator Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/statsOperator/test.js b/test/scoring/processor/expressions/operators/statsOperator/test.js new file mode 100644 index 00000000..f2b08c5a --- /dev/null +++ b/test/scoring/processor/expressions/operators/statsOperator/test.js @@ -0,0 +1,137 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/errorHandler', + 'taoQtiItem/scoring/processor/expressions/operators/statsOperator' +], function(_, preProcessorFactory, errorHandler, statsProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(statsProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(statsProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(statsProcessor.operands), 'the processor has operands'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'mean', + name: 'mean', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 4 + } + }, { + title: 'incorrect stat operation', + name: 'magic', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, 3, 7] + }], + expectedResult: null + }, { + title: 'sampleVariance', + name: 'sampleVariance', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [600, 470, 170, 430, 300] + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 27130 + } + }, { + title: 'sampleVariance', + name: 'sampleVariance', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [20] + }], + expectedResult: null + }, { + title: 'sampleSD', + name: 'sampleSD', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [20] + }], + expectedResult: null + }, { + title: 'sampleSD', + name: 'sampleSD', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [600, 470, 170, 430, 300] + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 164.7118696390761 + } + }, { + title: 'popVariance', + name: 'popVariance', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [600, 470, 170, 430, 300] + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 21704 + } + }, { + title: 'popSD', + name: 'popSD', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [600, 470, 170, 430, 300] + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 147.32277488562318 + } + }, { + title: 'null operand', + operands: [{ + cardinality: 'ordered', + baseType: 'integer', + value: [2, NaN, 7] + }], + expectedResult: null + }, { + title: 'null operand', + operands: [null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('ordered ', function(data, assert) { + statsProcessor.operands = data.operands; + statsProcessor.expression = { + attributes: { + name: data.name + } + }; + statsProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(statsProcessor.process(), data.expectedResult, 'The statsOperator is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/stringMatch/test.html b/test/scoring/processor/expressions/operators/stringMatch/test.html new file mode 100644 index 00000000..cd3c8cef --- /dev/null +++ b/test/scoring/processor/expressions/operators/stringMatch/test.html @@ -0,0 +1,20 @@ + + + + + stringMatch Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/stringMatch/test.js b/test/scoring/processor/expressions/operators/stringMatch/test.js new file mode 100644 index 00000000..6a5c877b --- /dev/null +++ b/test/scoring/processor/expressions/operators/stringMatch/test.js @@ -0,0 +1,89 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/stringMatch' +], function(_, preProcessorFactory, stringMatchProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(stringMatchProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(stringMatchProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(stringMatchProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'match truth caseSensitive', + caseSensitive: true, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'The Rain in' + }, { + cardinality: 'single', + baseType: 'string', + value: 'The Rain in' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'match false caseSensitive', + caseSensitive: true, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'The Rain in' + }, { + cardinality: 'single', + baseType: 'string', + value: 'The rain in' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'match true caseInSensitive', + caseSensitive: false, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'The Rain in' + }, { + cardinality: 'single', + baseType: 'string', + value: 'The rain in' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'one null', + caseSensitive: true, + operands: [null, { + cardinality: 'single', + baseType: 'string', + value: 'The rain in' + }], + expectedResult: null + } + ]; + + QUnit + .cases.init(dataProvider) + .test('stringMatch ', function(data, assert) { + stringMatchProcessor.operands = data.operands; + stringMatchProcessor.expression = {attributes: {caseSensitive: data.caseSensitive}}; + stringMatchProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(stringMatchProcessor.process(), data.expectedResult, 'The stringMatch is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/substring/test.html b/test/scoring/processor/expressions/operators/substring/test.html new file mode 100644 index 00000000..3c4d9dbc --- /dev/null +++ b/test/scoring/processor/expressions/operators/substring/test.html @@ -0,0 +1,20 @@ + + + + + Substring Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/substring/test.js b/test/scoring/processor/expressions/operators/substring/test.js new file mode 100644 index 00000000..fdfd7c48 --- /dev/null +++ b/test/scoring/processor/expressions/operators/substring/test.js @@ -0,0 +1,106 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/substring' +], function(_, preProcessorFactory, substringProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(substringProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(substringProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(substringProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'numbers', + caseSensitive: true, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 7788 + }, { + cardinality: 'single', + baseType: 'string', + value: 78 + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'contain substring case insensitive', + caseSensitive: false, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'ovERwhelming' + }, { + cardinality: 'single', + baseType: 'string', + value: 'over' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: true + } + }, { + title: 'contain substring', + caseSensitive: true, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'ovERwhelming' + }, { + cardinality: 'single', + baseType: 'string', + value: 'over' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'don\'t contain', + caseSensitive: true, + operands: [{ + cardinality: 'single', + baseType: 'string', + value: 'overwhelming' + }, { + cardinality: 'single', + baseType: 'string', + value: 'sticker' + }], + expectedResult: { + cardinality: 'single', + baseType: 'boolean', + value: false + } + }, { + title: 'one null', + caseSensitive: true, + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('substring ', function(data, assert) { + substringProcessor.operands = data.operands; + substringProcessor.expression = {attributes: {caseSensitive: data.caseSensitive}}; + substringProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(substringProcessor.process(), data.expectedResult, 'The substring is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/subtract/test.html b/test/scoring/processor/expressions/operators/subtract/test.html new file mode 100644 index 00000000..25226002 --- /dev/null +++ b/test/scoring/processor/expressions/operators/subtract/test.html @@ -0,0 +1,20 @@ + + + + + Subtract Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/subtract/test.js b/test/scoring/processor/expressions/operators/subtract/test.js new file mode 100644 index 00000000..353f4adf --- /dev/null +++ b/test/scoring/processor/expressions/operators/subtract/test.js @@ -0,0 +1,116 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/subtract' +], function(_, preProcessorFactory, subtractProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(subtractProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(subtractProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(subtractProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 3 + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 15 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 10 + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: 1.333323 + }, { + cardinality: 'single', + baseType: 'float', + value: 0.666677 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 0.6666460000000001 + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -5.25 + } + }, { + title: 'ignore wrong values', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 5 + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null], + expectedResult: null + }]; + + QUnit + .cases.init(dataProvider) + .test('subtract ', function(data, assert) { + subtractProcessor.operands = data.operands; + subtractProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(subtractProcessor.process(), data.expectedResult, 'The subtract is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/sum/test.html b/test/scoring/processor/expressions/operators/sum/test.html new file mode 100644 index 00000000..0e4f9a18 --- /dev/null +++ b/test/scoring/processor/expressions/operators/sum/test.html @@ -0,0 +1,20 @@ + + + + + Sum Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/sum/test.js b/test/scoring/processor/expressions/operators/sum/test.js new file mode 100644 index 00000000..c49f6fc4 --- /dev/null +++ b/test/scoring/processor/expressions/operators/sum/test.js @@ -0,0 +1,151 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/sum' +], function(_, preProcessorFactory, sumProcessor) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(sumProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(sumProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(sumProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '5' + }, { + cardinality: 'single', + baseType: 'integer', + value: '2' + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 12 + } + }, { + title: 'integers from numbers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 5.5 + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 12 + } + }, { + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '5.333323' + }, { + cardinality: 'single', + baseType: 'float', + value: '5.666677' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 11.0 + } + }, { + title: 'one float', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: '10.25' + }, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 17.25 + } + }, { + title: 'ignore wrong values', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, { + cardinality: 'single', + baseType: 'float', + value: NaN + }, { + cardinality: 'single', + baseType: 'integer', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 5 + } + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, + null, { + cardinality: 'single', + baseType: 'integer', + value: 2 + }], + expectedResult: null + }, { + title: 'multiple cardinality operand', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 3 + }, { + cardinality: 'multiple', + baseType: 'integer', + value: [5, 7, 11] + }], + expectedResult: { + cardinality: 'single', + baseType: 'integer', + value: 26 + } + }]; + + QUnit + .cases.init(dataProvider) + .test('sum ', function(data, assert) { + sumProcessor.operands = data.operands; + sumProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(sumProcessor.process(), data.expectedResult, 'The sum is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/operators/truncate/test.html b/test/scoring/processor/expressions/operators/truncate/test.html new file mode 100644 index 00000000..b19b1d4d --- /dev/null +++ b/test/scoring/processor/expressions/operators/truncate/test.html @@ -0,0 +1,20 @@ + + + + + Truncate.js Operator Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/operators/truncate/test.js b/test/scoring/processor/expressions/operators/truncate/test.js new file mode 100644 index 00000000..7f1d8fbd --- /dev/null +++ b/test/scoring/processor/expressions/operators/truncate/test.js @@ -0,0 +1,92 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/operators/truncate' +], function(_, preProcessorFactory, truncateProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(truncateProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(truncateProcessor.process), 'the processor has a process function'); + assert.ok(_.isArray(truncateProcessor.operands), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + var dataProvider = [{ + title: 'floats', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: '20.123' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20 + } + }, { + title: 'integers', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: '20' + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: 20 + } + }, { + title: 'Infinity', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: Infinity + } + }, { + title: '-Infinity', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: -Infinity + }], + expectedResult: { + cardinality: 'single', + baseType: 'float', + value: -Infinity + } + }, { + title: 'NaN', + operands: [{ + cardinality: 'single', + baseType: 'float', + value: NaN + }], + expectedResult: null + }, { + title: 'one null', + operands: [{ + cardinality: 'single', + baseType: 'integer', + value: 5 + }, null], + expectedResult: null + } + ]; + + QUnit + .cases.init(dataProvider) + .test('truncate ', function(data, assert) { + truncateProcessor.operands = data.operands; + truncateProcessor.preProcessor = preProcessorFactory({}); + assert.deepEqual(truncateProcessor.process(), data.expectedResult, 'The truncate is correct'); + }); +}); diff --git a/test/scoring/processor/expressions/randomFloat/test.html b/test/scoring/processor/expressions/randomFloat/test.html new file mode 100644 index 00000000..fbcdb6d6 --- /dev/null +++ b/test/scoring/processor/expressions/randomFloat/test.html @@ -0,0 +1,20 @@ + + + + + RandomFloat Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/randomFloat/test.js b/test/scoring/processor/expressions/randomFloat/test.js new file mode 100644 index 00000000..e0c1d82b --- /dev/null +++ b/test/scoring/processor/expressions/randomFloat/test.js @@ -0,0 +1,108 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/randomFloat', + 'taoQtiItem/scoring/processor/errorHandler' +], function(_, preProcessorFactory, randomFloatProcessor, errorHandler) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(randomFloatProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(randomFloatProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('The processor returns a single integer', function(assert) { + assert.expect(4); + + randomFloatProcessor.expression = { + attributes: {min: 2, max: 2} + }; + randomFloatProcessor.preProcessor = preProcessorFactory({}); + var result = randomFloatProcessor.process(); + + assert.ok(_.isPlainObject(result), 'The processor result is a plain object'); + assert.equal(result.cardinality, 'single', 'The processor result has a single cardinality'); + assert.equal(result.baseType, 'float', 'The processor result has a float baseType'); + assert.ok(_.isNumber(result.value), 'The processor result has a numeric value'); + }); + + QUnit.test('Fails if there aren\'t any attributes', function(assert) { + var ready = assert.async(); + assert.expect(1); + randomFloatProcessor.expression = { + attributes: { } + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Without the attributes the processor throws and error'); + ready(); + }); + + randomFloatProcessor.process(); + }); + + QUnit.test('Fails if max is not valid', function(assert) { + var ready = assert.async(); + assert.expect(1); + randomFloatProcessor.expression = { + attributes: {max: 'foo'} + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The max attribute must have a value'); + ready(); + }); + + randomFloatProcessor.process(); + }); + + QUnit.test('Fails if min is greater than max', function(assert) { + var ready = assert.async(); + assert.expect(1); + randomFloatProcessor.expression = { + attributes: {min: 10, max: 5} + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The max attribute must be greater than the min'); + ready(); + }); + + randomFloatProcessor.process(); + }); + + var dataProvider = [{ + title: '0.25 to 0.50', + min: 0.25, + max: 0.50 + }, { + title: '0.15 to 0.16', + min: 0.15, + max: 0.16 + }, { + title: '5 to 6', + min: 5, + max: 6 + }, { + title: '5 to 6 with strings', + min: '5', + max: '6' + }]; + + QUnit + .cases.init(dataProvider) + .test('randomFloat ', function(data, assert) { + randomFloatProcessor.expression = { + attributes: { + min: data.min, + max: data.max + } + }; + randomFloatProcessor.preProcessor = preProcessorFactory({}); + var result = randomFloatProcessor.process(); + + assert.ok(result.value >= data.min, 'The value ' + result.value + ' is GTE ' + data.min); + assert.ok(result.value <= data.max, 'The value ' + result.value + ' is LTE ' + data.max); + }); + +}); diff --git a/test/scoring/processor/expressions/randomInteger/test.html b/test/scoring/processor/expressions/randomInteger/test.html new file mode 100644 index 00000000..188c70cb --- /dev/null +++ b/test/scoring/processor/expressions/randomInteger/test.html @@ -0,0 +1,20 @@ + + + + + RandomInteger Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/randomInteger/test.js b/test/scoring/processor/expressions/randomInteger/test.js new file mode 100644 index 00000000..64c3541a --- /dev/null +++ b/test/scoring/processor/expressions/randomInteger/test.js @@ -0,0 +1,119 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/randomInteger', + 'taoQtiItem/scoring/processor/errorHandler' +], function(_, preProcessorFactory, randomIntegerProcessor, errorHandler) { + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(randomIntegerProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(randomIntegerProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('The processor returns a single integer', function(assert) { + assert.expect(1); + + var expectedResult = { + cardinality: 'single', + baseType: 'integer', + value: 2 + }; + randomIntegerProcessor.preProcessor = preProcessorFactory({}); + randomIntegerProcessor.expression = { + attributes: {min: 2, max: 2, step: 1} + }; + + assert.deepEqual(randomIntegerProcessor.process(), expectedResult, 'The processor result is a single integer'); + }); + + QUnit.test('Fails if there aren\'t any attributes', function(assert) { + var ready = assert.async(); + assert.expect(1); + randomIntegerProcessor.expression = { + attributes: { } + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'Without the attributes the processor throws and error'); + ready(); + }); + + randomIntegerProcessor.process(); + }); + + QUnit.test('Fails if max is not valid', function(assert) { + var ready = assert.async(); + assert.expect(1); + randomIntegerProcessor.expression = { + attributes: {max: 'foo'} + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The max attribute must have a value'); + ready(); + }); + + randomIntegerProcessor.process(); + }); + + QUnit.test('Fails if min is greater than max', function(assert) { + var ready = assert.async(); + assert.expect(1); + randomIntegerProcessor.expression = { + attributes: {min: 10, max: 5} + }; + errorHandler.listen('scoring', function(err) { + assert.equal(err.name, 'Error', 'The max attribute must be greater than the min'); + ready(); + }); + + randomIntegerProcessor.process(); + }); + + var dataProvider = [{ + title: '1 to 10', + attributes: { + min: 1, + max: 10, + step: 1 + }, + expectedRange: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + }, { + title: '0 to 9 with default value', + attributes: { + min: -Infinity, + max: 9, + step: NaN + }, + expectedRange: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + }, { + title: '2 to 11 with a 3 step', + attributes: { + min: 2, + max: 11, + step: 3 + }, + expectedRange: [2, 5, 8, 11] + }, { + title: '15 to 20 from strings', + attributes: { + min: '17', + max: '20' + }, + expectedRange: [17, 18, 19, 20] + }]; + + QUnit + .cases.init(dataProvider) + .test('randomInteger ', function(data, assert) { + randomIntegerProcessor.expression = { + attributes: data.attributes + }; + randomIntegerProcessor.preProcessor = preProcessorFactory({}); + var result = randomIntegerProcessor.process(); + assert.ok(_.contains(data.expectedRange, result.value), 'The value ' + result.value + ' is in the range'); + }); + +}); diff --git a/test/scoring/processor/expressions/variable/test.html b/test/scoring/processor/expressions/variable/test.html new file mode 100644 index 00000000..cc5535da --- /dev/null +++ b/test/scoring/processor/expressions/variable/test.html @@ -0,0 +1,20 @@ + + + + + Variable Processor Test + + + + +
    + + diff --git a/test/scoring/processor/expressions/variable/test.js b/test/scoring/processor/expressions/variable/test.js new file mode 100644 index 00000000..d7385822 --- /dev/null +++ b/test/scoring/processor/expressions/variable/test.js @@ -0,0 +1,88 @@ +define([ + 'lodash', + 'taoQtiItem/scoring/processor/expressions/preprocessor', + 'taoQtiItem/scoring/processor/expressions/variable' +], function(_, preProcessorFactory, variableProcessor) { + 'use strict'; + + QUnit.module('API'); + + QUnit.test('structure', function(assert) { + assert.ok(_.isPlainObject(variableProcessor), 'the processor expose an object'); + assert.ok(_.isFunction(variableProcessor.process), 'the processor has a process function'); + }); + + QUnit.module('Process'); + + QUnit.test('Get the variable', function(assert) { + var state = { + RESPONSE: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-2' + } + }; + variableProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + variableProcessor.state = state; + variableProcessor.preProcessor = preProcessorFactory(state); + + var expectedResult = { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-2' + }; + assert.deepEqual(variableProcessor.process(), expectedResult, 'returns the variable response'); + }); + + QUnit.test('Get the variable value even null', function(assert) { + var state = { + }; + variableProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + variableProcessor.state = state; + variableProcessor.preProcessor = preProcessorFactory(state); + + assert.equal(variableProcessor.process(), null, 'returns null'); + }); + + QUnit.test('Get the variable value even with a null value', function(assert) { + var state = { + RESPONSE: { + cardinality: 'single', + baseType: 'identifier', + value: null + } + }; + variableProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + variableProcessor.state = state; + variableProcessor.preProcessor = preProcessorFactory(state); + + var expectedResult = { + cardinality: 'single', + baseType: 'identifier', + value: null + }; + assert.deepEqual(variableProcessor.process(), expectedResult, 'returns null'); + }); + + QUnit.test('Get null if no variable is found', function(assert) { + assert.expect(1); + variableProcessor.expression = { + attributes: {identifier: 'RESPONSE'} + }; + variableProcessor.state = { + RESPONSE_1: { + cardinality: 'single', + baseType: 'identifier', + value: 'choice-2' + } + }; + + assert.deepEqual(variableProcessor.process(), null, 'returns null'); + }); +}); diff --git a/test/scoring/provider/test.html b/test/scoring/provider/test.html new file mode 100644 index 00000000..aa81f778 --- /dev/null +++ b/test/scoring/provider/test.html @@ -0,0 +1,20 @@ + + + + + QTI Scoring Provider Test + + + + +
    + + diff --git a/test/scoring/provider/test.js b/test/scoring/provider/test.js new file mode 100644 index 00000000..9841fc2b --- /dev/null +++ b/test/scoring/provider/test.js @@ -0,0 +1,591 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; under version 2 + * of the License (non-upgradable). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2015-2018 (original work) Open Assessment Technlogies SA (under the project TAO-PRODUCT); + * + */ +define([ + 'lodash', + 'taoItems/scoring/api/scorer', + 'taoQtiItem/scoring/provider/qti', + 'json!taoQtiItem/test/samples/json/space-shuttle.json', + 'json!taoQtiItem/test/samples/json/space-shuttle-m.json', + 'json!taoQtiItem/test/samples/json/characters.json', + 'json!taoQtiItem/test/samples/json/edinburgh.json', + 'json!taoQtiItem/test/samples/json/customrp/Choicemultiple_2014410822.json', + 'json!taoQtiItem/test/samples/json/customrp/TextEntrynumeric_770468849.json', + 'json!taoQtiItem/test/samples/json/customrp/Choicemultiple_871212949.json', + 'json!taoQtiItem/test/samples/json/customrp/Matchsingle_143114773.json', + 'json!taoQtiItem/test/samples/json/customrp/order.json', + 'json!taoQtiItem/test/samples/json/es6.json', + 'json!taoQtiItem/test/samples/json/pluto.json', + 'json!taoQtiItem/test/samples/json/customrp/andAnd.json', + 'json!taoQtiItem/test/samples/json/customrp/custom_record.json' +], function( + _, + scorer, + qtiScoringProvider, + singleCorrectData, + multipleCorrectData, + multipleMapData, + singleMapPointData, + customChoiceMultipleData, + customTextEntryNumericData, + customChoiceMultipleData2, + customChoiceSingleData, + orderData, + multipleResponseCorrectData, + embedConditionsData, + andAndData, + customRecordData +) { + 'use strict'; + + QUnit.module('Provider API'); + + QUnit.test('module', function(assert) { + assert.ok(typeof qtiScoringProvider !== 'undefined', 'The module exports something'); + assert.ok(typeof qtiScoringProvider === 'object', 'The module exports an object'); + assert.ok(typeof qtiScoringProvider.process === 'function', 'The module exposes a process method'); + }); + + QUnit.module('Register the provider', { + afterEach: function(assert) { + + //Reset the provider + scorer.providers = undefined; + } + }); + + QUnit.test('register the qti provider', function(assert) { + assert.expect(4); + + assert.ok(typeof scorer.providers === 'undefined', 'the scorer has: no providers'); + + scorer.register('qti', qtiScoringProvider); + + assert.ok(typeof scorer.providers === 'object', 'the scorer has now providers'); + assert.ok(typeof scorer.providers.qti === 'object', 'the scorer has now the qti providers'); + assert.equal(scorer.providers.qti, qtiScoringProvider, 'the scorer has now the qti providers'); + + }); + + QUnit.module('Without processing', { + afterEach: function(assert) { + + //Reset the provides + scorer.providers = undefined; + } + }); + + QUnit.test('default outcomes', function(assert) { + var ready = assert.async(); + var responses = { + 'RESPONSE': { + 'base': { + 'identifier': 'Discovery' + } + } + }; + + var noRulesItemData = _.cloneDeep(singleCorrectData); + + assert.expect(10); + + noRulesItemData.responseProcessing.responseRules = []; + + scorer.register('qti', qtiScoringProvider); + + scorer('qti') + .on('error', function(err) { + assert.ok(false, 'Got an error : ' + err); + }) + .on('outcome', function(outcomes, state) { + + assert.ok(typeof outcomes === 'object', 'the outcomes are an object'); + assert.ok(typeof outcomes.RESPONSE === 'object', 'the outcomes contains the response'); + assert.deepEqual(outcomes.RESPONSE, responses.RESPONSE, 'the response is the same'); + assert.ok(typeof outcomes.SCORE === 'object', 'the outcomes contains the score'); + assert.deepEqual(outcomes.SCORE, {base: {integer: 0}}, 'the score has the default value'); + + assert.ok(typeof state === 'object', 'the state is an object'); + assert.ok(typeof state.RESPONSE === 'object', 'the state contains the RESPONSE variable'); + assert.deepEqual(state.RESPONSE, { + cardinality: 'single', + baseType: 'identifier', + correctResponse: ['Atlantis'], + defaultValue: undefined, + mapping: undefined, + value: 'Discovery' + }, 'the RESPONSE variable matches'); + assert.ok(typeof state.SCORE === 'object', 'the state contains the SCORE variable'); + assert.deepEqual(state.SCORE, { + cardinality: 'single', + baseType: 'integer', + defaultValue: '0', + value: 0 + }, 'the SCORE variable matches'); + + ready(); + }) + .process(responses, noRulesItemData); + }); + + QUnit.test('No responseProcessing', function(assert) { + var ready = assert.async(); + var noRPItemData = _.cloneDeep(singleCorrectData); + + assert.expect(3); + + assert.equal(noRPItemData.identifier, 'space-shuttle-30-years-of-adventure', 'The item has the expected identifier'); + delete noRPItemData.responseProcessing; + + scorer.register('qti', qtiScoringProvider); + + scorer('qti') + .on('error', function(err) { + assert.ok(err instanceof Error, 'Got an Error'); + assert.equal(err.message, 'The item space-shuttle-30-years-of-adventure has not responseProcessing', 'The error is about responseProcessing'); + ready(); + }) + .process({}, noRPItemData); + }); + + QUnit.module('Provider process correct template', { + afterEach: function(assert) { + + //Reset the provides + delete scorer.providers; + } + }); + + QUnit.cases.init([{ + title: 'match correct single identifier', + item: singleCorrectData, + outcomes: { + RESPONSE: {base: {identifier: 'Atlantis'}}, + SCORE: {base: {integer: 1}} + }, + state: { + RESPONSE: { + 'cardinality': 'single', + 'baseType': 'identifier', + 'value': 'Atlantis' + }, + SCORE: {value: 1} + } + }, { + title: 'match incorrect single identifier', + item: singleCorrectData, + outcomes: { + RESPONSE: {base: {identifier: 'Discovery'}}, + SCORE: {base: {integer: 0}} + }, + state: { + RESPONSE: { + 'cardinality': 'single', + 'baseType': 'identifier', + 'value': 'Discovery' + }, + SCORE: {value: 0} + } + }, { + title: 'match correct multiple identifier', + item: multipleCorrectData, + outcomes: { + RESPONSE: {list: {identifier: ['Pathfinder', 'Atlantis']}}, + SCORE: {base: {integer: 1}} + }, + state: { + RESPONSE: { + 'cardinality': 'multiple', + 'baseType': 'identifier', + 'value': ['Pathfinder', 'Atlantis'] + }, + SCORE: {value: 1} + } + }, { + title: 'match incorrect multiple identifier', + item: multipleCorrectData, + outcomes: { + RESPONSE: {list: {identifier: ['Atlantis', 'Discovery']}}, + SCORE: {base: {integer: 0}} + }, + state: { + RESPONSE: { + 'cardinality': 'multiple', + 'baseType': 'identifier', + 'value': ['Atlantis', 'Discovery'] + }, + SCORE: {value: 0} + } + }, { + title: 'map response multiple directedPair', + item: multipleMapData, + outcomes: { + RESPONSE: {list: {directedPair: [['C', 'R'], ['D', 'M']]}}, + SCORE: {base: {float: 1.5}} + }, + state: { + RESPONSE: { + 'cardinality': 'multiple', + 'baseType': 'directedPair', + 'value': [['C', 'R'], ['D', 'M']] + }, + SCORE: {value: 1.5} + } + }, { + title: 'incorrect map response multiple directedPair', + item: multipleMapData, + outcomes: { + RESPONSE: {list: {directedPair: [['M', 'D'], ['R', 'M']]}}, + SCORE: {base: {float: 0}} + }, + state: { + RESPONSE: { + 'cardinality': 'multiple', + 'baseType': 'directedPair', + 'value': [['M', 'D'], ['R', 'M']] + }, + SCORE: {value: 0} + } + }, { + title: 'map response point inside', + item: singleMapPointData, + outcomes: { + RESPONSE: {base: {point: [102, 113]}}, + SCORE: {base: {float: 1}} + }, + state: { + RESPONSE: { + 'cardinality': 'single', + 'baseType': 'point', + 'value': [102, 113] + }, + SCORE: {value: 1} + } + }, { + title: 'map response point outside', + item: singleMapPointData, + outcomes: { + RESPONSE: {base: {point: [145, 190]}}, + SCORE: {base: {float: 0}} + }, + state: { + RESPONSE: { + 'cardinality': 'single', + 'baseType': 'point', + 'value': [145, 190] + }, + SCORE: {value: 0} + } + }]).test('process ', function(data, assert) { + var ready = assert.async(); + + assert.expect(8); + + scorer.register('qti', qtiScoringProvider); + + scorer('qti') + .on('error', function(err) { + assert.ok(false, 'Got an error : ' + err); + }) + .on('outcome', function(outcomes, state) { + + assert.deepEqual(outcomes, data.outcomes, 'Generated outcomes matche'); + + assert.ok(typeof state === 'object', 'The generated state is an object'); + + //Check RESPONSE variable cardinality, baseType and value + assert.ok(typeof state.RESPONSE === 'object', 'The generated state contains a RESPONSE variable'); + assert.equal(state.RESPONSE.cardinality, data.state.RESPONSE.cardinality, 'The RESPONSE cardinality is correct'); + assert.equal(state.RESPONSE.baseType, data.state.RESPONSE.baseType, 'The RESPONSE baseType is correct'); + assert.deepEqual(state.RESPONSE.value, data.state.RESPONSE.value, 'The RESPONSE value is correct'); + + //Check only SCORE value + assert.ok(typeof state.SCORE === 'object', 'The generated state contains a SCORE variable'); + assert.equal(state.SCORE.value, data.state.SCORE.value, 'The score matches the expected value'); + + ready(); + }) + .process({ + RESPONSE: data.outcomes.RESPONSE + }, data.item); + }); + + QUnit.test('process multiple responses', function(assert) { + var ready = assert.async(); + + assert.expect(7); + + var responses = { + 'RESPONSE': {list: {identifier: ['choice_3']}}, + 'RESPONSE_1': {base: {identifier: 'choice_7'}} + }; + scorer.register('qti', qtiScoringProvider); + + scorer('qti') + .on('error', function(err) { + assert.ok(false, 'Got an error : ' + err); + }) + .on('outcome', function(outcomes) { + + assert.ok(typeof outcomes === 'object', 'the outcomes are an object'); + assert.ok(typeof outcomes.RESPONSE === 'object', 'the outcomes contains the response'); + assert.deepEqual(outcomes.RESPONSE, responses.RESPONSE, 'the response is the same'); + assert.ok(typeof outcomes.RESPONSE_1 === 'object', 'the outcomes contains the response'); + assert.deepEqual(outcomes.RESPONSE_1, responses.RESPONSE_1, 'the response is the same'); + assert.ok(typeof outcomes.SCORE === 'object', 'the outcomes contains the score'); + assert.deepEqual(outcomes.SCORE, {base: {float: 2}}, 'the score has the correct value'); + + ready(); + }) + .process(responses, multipleResponseCorrectData); + }); + + QUnit.test('process multiple responses one is empty', function(assert) { + var ready = assert.async(); + + assert.expect(7); + + var responses = { + 'RESPONSE': {list: {identifier: ['choice_3']}}, + 'RESPONSE_1': {base: null} + }; + scorer.register('qti', qtiScoringProvider); + + scorer('qti') + .on('error', function(err) { + assert.ok(false, 'Got an error : ' + err); + }) + .on('outcome', function(outcomes) { + + assert.ok(typeof outcomes === 'object', 'the outcomes are an object'); + assert.ok(typeof outcomes.RESPONSE === 'object', 'the outcomes contains the response'); + assert.deepEqual(outcomes.RESPONSE, responses.RESPONSE, 'the response is the same'); + assert.ok(typeof outcomes.RESPONSE_1 === 'object', 'the outcomes contains the response'); + assert.deepEqual(outcomes.RESPONSE_1, responses.RESPONSE_1, 'the response is the same'); + assert.ok(typeof outcomes.SCORE === 'object', 'the outcomes contains the score'); + assert.deepEqual(outcomes.SCORE, {base: {float: 1}}, 'the score has the correct value'); + + ready(); + }) + .process(responses, multipleResponseCorrectData); + }); + + QUnit.module('Custom template', { + afterEach: function(assert) { + + //Reset the provides + scorer.providers = undefined; + } + }); + + var customDataProvider = [{ + title: 'choice multiple correct', + item: customChoiceMultipleData, + resp: {RESPONSE_13390220: {list: {identifier: ['choice_693643701', 'choice_853818748']}}}, + outcomes: { + SCORE: {base: {'float': 1}}, + FEEDBACKBASIC: {base: {'identifier': 'correct'}} + } + }, { + title: 'choice multiple incorrect', + item: customChoiceMultipleData, + resp: {RESPONSE_13390220: {list: {identifier: ['choice_853818748']}}}, + outcomes: { + SCORE: {base: {'float': 0}}, + FEEDBACKBASIC: {base: {'identifier': 'incorrect'}} + } + }, { + title: 'single numeric text entry exact', + item: customTextEntryNumericData, + resp: {RESPONSE_1: {base: {float: 4.136}}}, + outcomes: { + SCORE: {base: {'float': 1}}, + FEEDBACKBASIC: {base: {'identifier': 'correct'}} + } + }, { + title: 'single numeric text entry pretty correct', + item: customTextEntryNumericData, + resp: {RESPONSE_1: {base: {float: 4.132}}}, + outcomes: { + SCORE: {base: {'float': 1}}, + FEEDBACKBASIC: {base: {'identifier': 'correct'}} + } + }, { + title: 'single numeric text entry incorrect', + item: customTextEntryNumericData, + resp: {RESPONSE_1: {base: {float: 5.8756}}}, + outcomes: { + SCORE: {base: {'float': 0}}, + FEEDBACKBASIC: {base: {'identifier': 'incorrect'}} + } + }, { + title: 'choice multiple correct', + item: customChoiceMultipleData2, + resp: {RESPONSE_27966883: {list: {identifier: ['choice_934383202', 'choice_2022864592', 'choice_1534527094']}}}, + outcomes: { + SCORE: {base: {'float': 3}}, + FEEDBACKBASIC: {base: {'identifier': 'correct'}} + } + }, { + title: 'choice multiple incorrect', + item: customChoiceMultipleData2, + resp: {RESPONSE_27966883: {list: {identifier: ['choice_921260236']}}}, + outcomes: { + SCORE: {base: {'float': -1}}, + FEEDBACKBASIC: {base: {'identifier': 'incorrect'}} + } + }, { + title: 'choice directed pair multiple correct', + item: customChoiceSingleData, + resp: {RESPONSE: {list: {directedPair: ['Match29886762 Match30518135', 'Match5256823 Match2607634', 'Match4430647 Match8604807', 'Match1403839 Match5570831']}}}, + outcomes: { + SCORE: {base: {'float': 1}}, + FEEDBACKBASIC: {base: {'identifier': 'correct'}} + } + }, { + title: 'choice directed pair multiple incorrect', + item: customChoiceSingleData, + resp: {RESPONSE: {list: {directedPair: ['Match29886762 Match30518135', 'Match2607634 Match5256823', 'Match4430647 Match8604807', 'Match1403839 Match5570831']}}}, + outcomes: { + SCORE: {base: {'float': 0}}, + FEEDBACKBASIC: {base: {'identifier': 'incorrect'}} + } + }, { + title: 'ordered correct', + item: orderData, + resp: {RESPONSE: {list: {identifier: ['DriverC', 'DriverA', 'DriverB']}}}, + outcomes: { + SCORE: {base: {'float': 1}} + } + }, { + title: 'ordered incorrect', + item: orderData, + resp: {RESPONSE: {list: {identifier: ['DriverC', 'DriverAS', 'DriverB']}}}, + outcomes: { + SCORE: {base: {'float': 0}} + } + }, { + title: 'embed conditions correct', + item: embedConditionsData.data, + resp: { + RESPONSE: {base: {identifier: 'choice_1'}}, + RESPONSE_1: {base: {identifier: 'choice_6'}} + }, + outcomes: { + SCORE: {base: {'float': 2}} + } + }, { + title: 'embed conditions first correct', + item: embedConditionsData.data, + resp: { + RESPONSE: {base: {identifier: 'choice_1'}}, + RESPONSE_1: {base: {identifier: 'choice_7'}} + }, + outcomes: { + SCORE: {base: {'float': 1}} + } + }, { + title: 'embed conditions 2nd correct', + item: embedConditionsData.data, + resp: { + RESPONSE: {base: {identifier: 'choice_2'}}, + RESPONSE_1: {base: {identifier: 'choice_6'}} + }, + outcomes: { + SCORE: {base: {'float': 0}} + } + }, { + title: 'embed conditions 2nd null', + item: embedConditionsData.data, + resp: { + RESPONSE: {base: {identifier: 'choice_1'}}, + RESPONSE_1: {base: null} + }, + outcomes: { + SCORE: {base: {'float': 1}} + } + }, { + title: 'embed conditions null', + item: embedConditionsData.data, + resp: { + RESPONSE: {base: null}, + RESPONSE_1: {base: null} + }, + outcomes: { + SCORE: {base: {'float': 0}} + } + }, { + title: 'nested and incorrect', + item: andAndData.data, + resp: { + RESPONSE: {base: {float: 1.234}}, + RESPONSE_2: {base: {float: 42}} + }, + outcomes: { + SCORE: {base: {'float': 0}} + } + }, { + title: 'nested and correct', + item: andAndData.data, + resp: { + RESPONSE: {base: {float: 1234}}, + RESPONSE_2: {base: {float: 42}} + }, + outcomes: { + SCORE: {base: {'float': 1}} + } + }, { + title: 'custom record', + item: customRecordData.data, + resp: { + RESPONSE: {record: [{ + name: 'fieldA', + base: {string: 'yes'} + }]} + }, + outcomes: { + SCORE: {base: {'float': 2}} + } + }]; + + QUnit + .cases.init(customDataProvider) + .test('process ', function(data, assert) { + var ready = assert.async(); + + scorer.register('qti', qtiScoringProvider); + + scorer('qti') + .on('error', function(err) { + assert.ok(false, 'Got an error : ' + err); + }) + .on('outcome', function(outcomes) { + + assert.ok(typeof outcomes === 'object', 'the outcomes are an object'); + + _.forEach(data.outcomes, function(outcome, name) { + assert.deepEqual(outcomes[name], outcome, 'the outcome ' + name + ' is correct'); + }); + + ready(); + }) + .process(data.resp, data.item); + }); + +}); +