From fa1dfd716a6e58719ed0fd997e87c11cd6649710 Mon Sep 17 00:00:00 2001 From: cahrens Date: Wed, 15 May 2013 15:25:36 -0400 Subject: [PATCH] Update unit test for editable_metadata_fields. --- .../xmodule/xmodule/tests/test_xml_module.py | 86 +++++++++++++++---- common/lib/xmodule/xmodule/x_module.py | 10 +-- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/common/lib/xmodule/xmodule/tests/test_xml_module.py b/common/lib/xmodule/xmodule/tests/test_xml_module.py index e41bcdd73a..341d0e591b 100644 --- a/common/lib/xmodule/xmodule/tests/test_xml_module.py +++ b/common/lib/xmodule/xmodule/tests/test_xml_module.py @@ -1,21 +1,39 @@ from xmodule.x_module import XModuleFields -from xblock.core import Scope, String, Object -from xmodule.fields import Date, StringyInteger +from xblock.core import Scope, String, Object, Boolean +from xmodule.fields import Date, StringyInteger, StringyFloat from xmodule.xml_module import XmlDescriptor import unittest from . import test_system from mock import Mock +class CrazyJsonString(String): + + def to_json(self, value): + return value + " JSON" + + class TestFields(object): # Will be returned by editable_metadata_fields. - max_attempts = StringyInteger(scope=Scope.settings, default=1000) + max_attempts = StringyInteger(scope=Scope.settings, default=1000, values={'min': 1 , 'max' : 10}) # Will not be returned by editable_metadata_fields because filtered out by non_editable_metadata_fields. due = Date(scope=Scope.settings) # Will not be returned by editable_metadata_fields because is not Scope.settings. student_answers = Object(scope=Scope.user_state) # Will be returned, and can override the inherited value from XModule. - display_name = String(scope=Scope.settings, default='local default') + display_name = String(scope=Scope.settings, default='local default', display_name = 'Local Display Name', + help='local help') + # Used for testing select type, effect of to_json method + string_select = CrazyJsonString(scope=Scope.settings, default='default value', + values=[{'display_name' : 'first', 'value' : 'value a'}, + {'display_name' : 'second','value' : 'value b'}]) + # Used for testing select type + float_select = StringyFloat(scope=Scope.settings, default=.999, values=[1.23, 0.98]) + # Used for testing float type + float_non_select = StringyFloat(scope=Scope.settings, default=.999, values={'min': 0 , 'step' : .3}) + # Used for testing that Booleans get mapped to select type + # TODO: move default value into xblock! + boolean_select = Boolean(scope=Scope.settings, values=[{'display_name': "True", "value": True}, {'display_name': "False", "value": False}]) class EditableMetadataFieldsTest(unittest.TestCase): @@ -34,18 +52,20 @@ class EditableMetadataFieldsTest(unittest.TestCase): self.assert_field_values(editable_fields, 'display_name', XModuleFields.display_name, explicitly_set=True, inheritable=False, value='foo', default_value=None) - def test_additional_field(self): + def test_integer_field(self): descriptor = self.get_descriptor({'max_attempts' : '7'}) editable_fields = descriptor.editable_metadata_fields - self.assertEqual(2, len(editable_fields)) + self.assertEqual(6, len(editable_fields)) self.assert_field_values(editable_fields, 'max_attempts', TestFields.max_attempts, - explicitly_set=True, inheritable=False, value=7, default_value=1000) - self.assert_field_values(editable_fields, 'display_name', XModuleFields.display_name, + explicitly_set=True, inheritable=False, value=7, default_value=1000, type='Integer', + options=TestFields.max_attempts.values) + self.assert_field_values(editable_fields, 'display_name', TestFields.display_name, explicitly_set=False, inheritable=False, value='local default', default_value='local default') editable_fields = self.get_descriptor({}).editable_metadata_fields self.assert_field_values(editable_fields, 'max_attempts', TestFields.max_attempts, - explicitly_set=False, inheritable=False, value=1000, default_value=1000) + explicitly_set=False, inheritable=False, value=1000, default_value=1000, type='Integer', + options=TestFields.max_attempts.values) def test_inherited_field(self): model_val = {'display_name' : 'inherited'} @@ -54,7 +74,7 @@ class EditableMetadataFieldsTest(unittest.TestCase): descriptor._inherited_metadata = model_val descriptor._inheritable_metadata = model_val editable_fields = descriptor.editable_metadata_fields - self.assert_field_values(editable_fields, 'display_name', XModuleFields.display_name, + self.assert_field_values(editable_fields, 'display_name', TestFields.display_name, explicitly_set=False, inheritable=True, value='inherited', default_value='inherited') descriptor = self.get_descriptor({'display_name' : 'explicit'}) @@ -62,9 +82,36 @@ class EditableMetadataFieldsTest(unittest.TestCase): descriptor._inheritable_metadata = {'display_name' : 'inheritable value'} descriptor._inherited_metadata = {} editable_fields = descriptor.editable_metadata_fields - self.assert_field_values(editable_fields, 'display_name', XModuleFields.display_name, + self.assert_field_values(editable_fields, 'display_name', TestFields.display_name, explicitly_set=True, inheritable=True, value='explicit', default_value='inheritable value') + def test_type_and_options(self): + # test_display_name_field verifies that a String field is of type "Generic". + # test_integer_field verifies that a StringyInteger field is of type "Integer". + + descriptor = self.get_descriptor({}) + editable_fields = descriptor.editable_metadata_fields + + # Tests for select + self.assert_field_values(editable_fields, 'string_select', TestFields.string_select, + explicitly_set=False, inheritable=False, value='default value', default_value='default value', + type='Select', options=[{'display_name' : 'first', 'value' : 'value a JSON'}, + {'display_name' : 'second','value' : 'value b JSON'}]) + + self.assert_field_values(editable_fields, 'float_select', TestFields.float_select, + explicitly_set=False, inheritable=False, value=.999, default_value=.999, + type='Select', options=[1.23, 0.98]) + + self.assert_field_values(editable_fields, 'boolean_select', TestFields.boolean_select, + explicitly_set=False, inheritable=False, value=None, default_value=None, + type='Select', options=[{'display_name': "True", "value": True}, {'display_name': "False", "value": False}]) + + # Test for float + self.assert_field_values(editable_fields, 'float_non_select', TestFields.float_non_select, + explicitly_set=False, inheritable=False, value=.999, default_value=.999, + type='Float', options={'min': 0 , 'step' : .3}) + + # Start of helper methods def get_xml_editable_fields(self, model_data): system = test_system() @@ -84,10 +131,19 @@ class EditableMetadataFieldsTest(unittest.TestCase): system.render_template = Mock(return_value="
Test Template HTML
") return TestModuleDescriptor(system=system, location=None, model_data=model_data) - def assert_field_values(self, editable_fields, name, field, explicitly_set, inheritable, value, default_value): + def assert_field_values(self, editable_fields, name, field, explicitly_set, inheritable, value, default_value, + type='Generic', options=[]): test_field = editable_fields[name] - self.assertEqual(field, test_field['field']) + + self.assertEqual(field.name, test_field['field_name']) + self.assertEqual(field.display_name, test_field['display_name']) + self.assertEqual(field.help, test_field['help']) + + self.assertEqual(field.to_json(value), test_field['value']) + self.assertEqual(field.to_json(default_value), test_field['default_value']) + + self.assertEqual(options, test_field['options']) + self.assertEqual(type, test_field['type']) + self.assertEqual(explicitly_set, test_field['explicitly_set']) self.assertEqual(inheritable, test_field['inheritable']) - self.assertEqual(value, test_field['value']) - self.assertEqual(default_value, test_field['default_value']) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 11b0efecf8..bc4dac028e 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1,4 +1,5 @@ import logging +import copy import yaml import os @@ -644,17 +645,16 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock): # We support the following editors: # 1. A select editor for fields with a list of possible values (includes Booleans). - # 2. Number editor for integers and floats. + # 2. Number editors for integers and floats. # 3. A generic string editor for anything else (editing JSON representation of the value). type = "Generic" - # TODO: test all this logic - values = [] if field.values is None else field.values + values = [] if field.values is None else copy.deepcopy(field.values) if isinstance(values, list): if len(values) > 0: type = "Select" for index, choice in enumerate(values): - json_choice = choice - if hasattr(json_choice, 'value'): + json_choice = copy.deepcopy(choice) + if isinstance(json_choice, dict) and 'value' in json_choice: json_choice['value'] = field.to_json(json_choice['value']) else: json_choice = field.to_json(json_choice)