diff --git a/js/MasteryCriteria.js b/js/MasteryCriteria.js index 5553722..e51c336 100644 --- a/js/MasteryCriteria.js +++ b/js/MasteryCriteria.js @@ -9,6 +9,7 @@ export default { NUM_CORRECT_IN_A_ROW_2: "num_correct_in_a_row_2", NUM_CORRECT_IN_A_ROW_3: "num_correct_in_a_row_3", NUM_CORRECT_IN_A_ROW_5: "num_correct_in_a_row_5", + PRE_POST_TEST: "pre_post_test", }; export const SCHEMA = { @@ -28,7 +29,47 @@ export const SCHEMA = { "num_correct_in_a_row_2", "num_correct_in_a_row_3", "num_correct_in_a_row_5", - "num_correct_in_a_row_10" + "num_correct_in_a_row_10", + "pre_post_test" + ] + }, + "pre_post_test": { + "type": "object", + "description": "Definition for pre/post test", + "additionalProperties": false, + "properties": { + "assessment_item_ids": { + "type": "array", + "minItems": 2, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "description": "List of assessment item UUIDs for version A and B of the pre/post test" + }, + "version_a_item_ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "description": "List of assessment item UUIDs for version A of the pre/post test" + }, + "version_b_item_ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "description": "List of assessment item UUIDs for version B of the pre/post test" + } + }, + "required": [ + "assessment_item_ids", + "version_a_item_ids", + "version_b_item_ids" ] } }, @@ -37,6 +78,9 @@ export const SCHEMA = { "n": true, "mastery_model": { "$ref": "#/definitions/mastery_model" + }, + "pre_post_test": { + "$ref": "#/definitions/pre_post_test" } }, "anyOf": [ @@ -66,6 +110,14 @@ export const SCHEMA = { "type": "null" } } + }, + { + "properties": { + "mastery_model": { + "const": "pre_post_test" + } + }, + "required": ["pre_post_test"] } ] }; diff --git a/le_utils/constants/exercises.py b/le_utils/constants/exercises.py index 1591f3c..3be2f11 100644 --- a/le_utils/constants/exercises.py +++ b/le_utils/constants/exercises.py @@ -8,6 +8,7 @@ SKILL_CHECK = "skill_check" M_OF_N = "m_of_n" QUIZ = "quiz" +PRE_POST_TEST = "pre_post_test" MASTERY_MODELS = ( (DO_ALL, "Do all"), @@ -18,6 +19,7 @@ (SKILL_CHECK, "Skill check"), (M_OF_N, "M out of N"), (QUIZ, "Quiz"), + (PRE_POST_TEST, "Pre/Post Test"), ) IMG_PLACEHOLDER = "{☣ LOCALPATH}" diff --git a/le_utils/constants/mastery_criteria.py b/le_utils/constants/mastery_criteria.py index 353e1fc..79ba4b1 100644 --- a/le_utils/constants/mastery_criteria.py +++ b/le_utils/constants/mastery_criteria.py @@ -10,6 +10,7 @@ NUM_CORRECT_IN_A_ROW_2 = "num_correct_in_a_row_2" NUM_CORRECT_IN_A_ROW_3 = "num_correct_in_a_row_3" NUM_CORRECT_IN_A_ROW_5 = "num_correct_in_a_row_5" +PRE_POST_TEST = "pre_post_test" choices = ( (DO_ALL, "Do All"), @@ -18,6 +19,7 @@ (NUM_CORRECT_IN_A_ROW_2, "Num Correct In A Row 2"), (NUM_CORRECT_IN_A_ROW_3, "Num Correct In A Row 3"), (NUM_CORRECT_IN_A_ROW_5, "Num Correct In A Row 5"), + (PRE_POST_TEST, "Pre Post Test"), ) MASTERYCRITERIALIST = [ @@ -27,6 +29,7 @@ NUM_CORRECT_IN_A_ROW_2, NUM_CORRECT_IN_A_ROW_3, NUM_CORRECT_IN_A_ROW_5, + PRE_POST_TEST, ] SCHEMA = { @@ -47,13 +50,54 @@ "num_correct_in_a_row_3", "num_correct_in_a_row_5", "num_correct_in_a_row_10", + "pre_post_test", ], - } + }, + "pre_post_test": { + "type": "object", + "description": "Definition for pre/post test", + "additionalProperties": False, + "properties": { + "assessment_item_ids": { + "type": "array", + "minItems": 2, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", + }, + "description": "List of assessment item UUIDs for version A and B of the pre/post test", + }, + "version_a_item_ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", + }, + "description": "List of assessment item UUIDs for version A of the pre/post test", + }, + "version_b_item_ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", + }, + "description": "List of assessment item UUIDs for version B of the pre/post test", + }, + }, + "required": [ + "assessment_item_ids", + "version_a_item_ids", + "version_b_item_ids", + ], + }, }, "properties": { "m": True, "n": True, "mastery_model": {"$ref": "#/definitions/mastery_model"}, + "pre_post_test": {"$ref": "#/definitions/pre_post_test"}, }, "anyOf": [ {"properties": {"mastery_model": {"const": "m_of_n"}}, "required": ["m", "n"]}, @@ -72,5 +116,9 @@ "n": {"type": "null"}, } }, + { + "properties": {"mastery_model": {"const": "pre_post_test"}}, + "required": ["pre_post_test"], + }, ], } diff --git a/spec/schema-mastery_criteria.json b/spec/schema-mastery_criteria.json index ef6d459..b67529e 100644 --- a/spec/schema-mastery_criteria.json +++ b/spec/schema-mastery_criteria.json @@ -15,7 +15,47 @@ "num_correct_in_a_row_2", "num_correct_in_a_row_3", "num_correct_in_a_row_5", - "num_correct_in_a_row_10" + "num_correct_in_a_row_10", + "pre_post_test" + ] + }, + "pre_post_test": { + "type": "object", + "description": "Definition for pre/post test", + "additionalProperties": false, + "properties": { + "assessment_item_ids": { + "type": "array", + "minItems": 2, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "description": "List of assessment item UUIDs for version A and B of the pre/post test" + }, + "version_a_item_ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "description": "List of assessment item UUIDs for version A of the pre/post test" + }, + "version_b_item_ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[45][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "description": "List of assessment item UUIDs for version B of the pre/post test" + } + }, + "required": [ + "assessment_item_ids", + "version_a_item_ids", + "version_b_item_ids" ] } }, @@ -24,6 +64,9 @@ "n": true, "mastery_model": { "$ref": "#/definitions/mastery_model" + }, + "pre_post_test": { + "$ref": "#/definitions/pre_post_test" } }, "anyOf": [ @@ -53,6 +96,14 @@ "type": "null" } } + }, + { + "properties": { + "mastery_model": { + "const": "pre_post_test" + } + }, + "required": ["pre_post_test"] } ] } \ No newline at end of file diff --git a/tests/test_schemas.py b/tests/test_schemas.py index de5e37c..79cbfaf 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -223,6 +223,24 @@ def test_completion_criteria__mastery_model__valid(): "threshold": {"mastery_model": "m_of_n", "m": 1, "n": 2}, } ) + _validate_completion_criteria( + { + "model": "mastery", + "threshold": { + "mastery_model": "pre_post_test", + "pre_post_test": { + "assessment_item_ids": [ + str(uuid.uuid4()), + str(uuid.uuid4()), + ], # v4 UUID + "version_a_item_ids": [str(uuid.uuid4())], # v4 UUID + "version_b_item_ids": [ + str(uuid.uuid5(uuid.NAMESPACE_DNS, "test")) + ], # v5 UUID + }, + }, + } + ) @skip_if_jsonschema_unavailable @@ -258,6 +276,37 @@ def test_completion_criteria__mastery_model__invalid(): "threshold": -1, } ) + # Missing version_b_item_ids + with pytest.raises(jsonschema.ValidationError): + _validate_completion_criteria( + { + "model": "mastery", + "threshold": { + "mastery_model": "pre_post_test", + "pre_post_test": { + "assessment_item_ids": [str(uuid.uuid4())], # v4 UUID + "version_a_item_ids": [str(uuid.uuid4())], # v4 UUID + }, + }, + "learner_managed": False, + } + ) + # Invalid UUIDs + with pytest.raises(jsonschema.ValidationError): + _validate_completion_criteria( + { + "model": "mastery", + "threshold": { + "mastery_model": "pre_post_test", + "pre_post_test": { + "assessment_item_ids": ["not-a-uuid"], + "version_a_item_ids": ["not-a-uuid"], + "version_b_item_ids": ["not-a-uuid"], + }, + }, + "learner_managed": False, + } + ) @skip_if_jsonschema_unavailable