def test_twofaced_field_access(): # Check that a field with different to_json and from_json representations # persists and saves correctly. class TwoFacedField(Field): """A field that emits different 'json' than it parses.""" def from_json(self, thestr): """Store an int, the length of the string parsed.""" return len(thestr) def to_json(self, value): """Emit some number of X's.""" return "X" * value class FieldTester(XBlock): """Test block for TwoFacedField.""" how_many = TwoFacedField(scope=Scope.settings) original_json = "YYY" runtime = TestRuntime( services={'field-data': DictFieldData({'how_many': original_json})}) field_tester = FieldTester(runtime, scope_ids=Mock(spec=ScopeIds)) # Test that the native value isn't equal to the original json we specified. assert_not_equals(field_tester.how_many, original_json) # Test that the native -> json value isn't equal to the original json we specified. assert_not_equals(TwoFacedField().to_json(field_tester.how_many), original_json) # The previous accesses will mark the field as dirty (via __get__) assert_equals(len(field_tester._dirty_fields), 1) # However, the field should not ACTUALLY be marked as a field that is needing to be saved. assert_not_in('how_many', field_tester._get_fields_to_save()) # pylint: disable=W0212
def test_cached_parent(): class HasParent(XBlock): pass runtime = Mock() block = HasParent(runtime, DictFieldData({}), Mock()) # block has no parent yet, and we don't need to call the runtime to find # that out. assert_equals(block.get_parent(), None) assert not runtime.get_block.called # Set a parent id for the block. Get the parent. Now we have one, and we # used runtime.get_block to get it. block.parent = "some_parent_id" parent = block.get_parent() assert_not_equals(parent, None) assert runtime.get_block.called_with("some_parent_id") # Get the parent again. It will be the same parent, and we didn't call the # runtime. runtime.reset_mock() parent2 = block.get_parent() assert parent2 is parent assert not runtime.get_block.called
def test_cached_parent(): class HasParent(XBlock): """ Dummy empty class """ pass runtime = TestRuntime(services={'field-data': DictFieldData({})}) runtime.get_block = Mock() block = HasParent(runtime, scope_ids=Mock(spec=ScopeIds)) # block has no parent yet, and we don't need to call the runtime to find # that out. assert_equals(block.get_parent(), None) assert not runtime.get_block.called # Set a parent id for the block. Get the parent. Now we have one, and we # used runtime.get_block to get it. block.parent = "some_parent_id" parent = block.get_parent() assert_not_equals(parent, None) assert runtime.get_block.called_with("some_parent_id") # Get the parent again. It will be the same parent, and we didn't call the # runtime. runtime.get_block.reset_mock() parent2 = block.get_parent() assert parent2 is parent assert not runtime.get_block.called
def test_caching_is_per_instance(): # Test that values cached for one instance do not appear on another class FieldTester(object): """Toy class for ModelMetaclass and field access testing""" __metaclass__ = ModelMetaclass field_a = List(scope=Scope.settings) def __init__(self, field_data): self._field_data = field_data self._dirty_fields = {} field_data = MagicMock(spec=FieldData) field_data.get = lambda block, name, default=None: [name] # pylint: disable=C0322 # Same field_data used in different objects should result # in separately-cached values, so that changing a value # in one instance doesn't affect values stored in others. field_tester_a = FieldTester(field_data) field_tester_b = FieldTester(field_data) value = field_tester_a.field_a assert_equals(value, field_tester_a.field_a) field_tester_a.field_a.append(1) assert_equals(value, field_tester_a.field_a) assert_not_equals(value, field_tester_b.field_a)
def test_caching_is_per_instance(): # Test that values cached for one instance do not appear on another class FieldTester(ScopedStorageMixin): """Toy class for ModelMetaclass and field access testing""" field_a = List(scope=Scope.settings) field_data = MagicMock(spec=FieldData) field_data.get = lambda block, name, default=None: [name] # pylint: disable=C0322 # Same field_data used in different objects should result # in separately-cached values, so that changing a value # in one instance doesn't affect values stored in others. field_tester_a = FieldTester( runtime=TestRuntime(services={'field-data': field_data}), scope_ids=MagicMock(spec=ScopeIds) ) field_tester_b = FieldTester( runtime=TestRuntime(services={'field-data': field_data}), scope_ids=MagicMock(spec=ScopeIds) ) value = field_tester_a.field_a assert_equals(value, field_tester_a.field_a) field_tester_a.field_a.append(1) assert_equals(value, field_tester_a.field_a) assert_not_equals(value, field_tester_b.field_a)
def test_twofaced_field_access(): # Check that a field with different to_json and from_json representations # persists and saves correctly. class TwoFacedField(Field): """A field that emits different 'json' than it parses.""" def from_json(self, thestr): """Store an int, the length of the string parsed.""" return len(thestr) def to_json(self, value): """Emit some number of X's.""" return "X" * value class FieldTester(XBlock): """Test block for TwoFacedField.""" how_many = TwoFacedField(scope=Scope.settings) original_json = "YYY" runtime = TestRuntime(services={'field-data': DictFieldData({'how_many': original_json})}) field_tester = FieldTester(runtime, scope_ids=Mock(spec=ScopeIds)) # Test that the native value isn't equal to the original json we specified. assert_not_equals(field_tester.how_many, original_json) # Test that the native -> json value isn't equal to the original json we specified. assert_not_equals(TwoFacedField().to_json(field_tester.how_many), original_json) # The previous accesses will mark the field as dirty (via __get__) assert_equals(len(field_tester._dirty_fields), 1) # However, the field should not ACTUALLY be marked as a field that is needing to be saved. assert_not_in('how_many', field_tester._get_fields_to_save()) # pylint: disable=W0212
def test_mutation_without_save_doesnt_write(self): initial_value = self.field_data.get(self.block, 'field') reference_copy = copy.deepcopy(initial_value) mutable = self.get() self.mutate(mutable) # Verify that the test isn't vacuously true assert_not_equals(reference_copy, mutable) final_value = self.field_data.get(self.block, 'field') assert_equals(reference_copy, final_value) assert_equals(initial_value, final_value)
def test_set_save_get_mutate_save(self): reference_value = copy.deepcopy(self.new_value) self.mutate(reference_value) # Verify that the test isn't vacuously true assert_not_equals(self.new_value, reference_value) self.set(copy.deepcopy(self.new_value)) self.block.save() self.mutate(self.get()) self.block.save() final_value = self.field_data.get(self.block, 'field') assert_equals(reference_value, final_value)
def test_mutation_with_save_writes(self): assert_false(self.field_data.has(self.block, 'field')) mutable = self.get() reference_copy = copy.deepcopy(mutable) self.mutate(reference_copy) # Verify that the test isn't vacuously true assert_not_equals(mutable, reference_copy) self.mutate(mutable) self.block.save() final_value = self.field_data.get(self.block, 'field') assert_equals(reference_copy, final_value)
def test_twofaced_field_access(): # Check that a field with different to_json and from_json representations # persists and saves correctly. class FieldTester(XBlock): """Test block for TwoFacedField.""" how_many = TwoFacedField(scope=Scope.settings) original_json = "YYY" field_tester = FieldTester(MagicMock(), DictFieldData({'how_many': original_json}), Mock()) # Test that the native value isn't equal to the original json we specified. assert_not_equals(field_tester.how_many, original_json) # Test that the native -> json value isn't equal to the original json we specified. assert_not_equals(TwoFacedField().to_json(field_tester.how_many), original_json) # The previous accesses will mark the field as dirty (via __get__) assert_equals(len(field_tester._dirty_fields), 1) # However, the field should not ACTUALLY be marked as a field that is needing to be saved. assert_not_in('how_many', field_tester._get_fields_to_save()) # pylint: disable=W0212
def test_unique_id_default(): class TestBlock(XBlock): """ Block for testing """ field_a = String(default=UNIQUE_ID, scope=Scope.settings) field_b = String(default=UNIQUE_ID, scope=Scope.user_state) sids = ScopeIds(user_id="bob", block_type="bobs-type", def_id="definition-id", usage_id="usage-id") runtime = TestRuntime(services={'field-data': DictFieldData({})}) block = TestBlock(runtime, DictFieldData({}), sids) unique_a = block.field_a unique_b = block.field_b # Create another instance of the same block. Unique ID defaults should not change. runtime = TestRuntime(services={'field-data': DictFieldData({})}) block = TestBlock(runtime, DictFieldData({}), sids) assert_equals(unique_a, block.field_a) assert_equals(unique_b, block.field_b) # Change the user id. Unique ID default should change for field_b with # user_state scope, but not for field_a with scope=settings. runtime = TestRuntime(services={'field-data': DictFieldData({})}) block = TestBlock(runtime, DictFieldData({}), sids._replace(user_id='alice')) assert_equals(unique_a, block.field_a) assert_not_equals(unique_b, block.field_b) # Change the usage id. Unique ID default for both fields should change. runtime = TestRuntime(services={'field-data': DictFieldData({})}) block = TestBlock(runtime, DictFieldData({}), sids._replace(usage_id='usage-2')) assert_not_equals(unique_a, block.field_a) assert_not_equals(unique_b, block.field_b)
def test_caching_is_per_instance(): # Test that values cached for one instance do not appear on another class FieldTester(ScopedStorageMixin): """Toy class for ModelMetaclass and field access testing""" field_a = List(scope=Scope.settings) field_data = MagicMock(spec=FieldData) field_data.get = lambda block, name, default=None: [name] # pylint: disable=C0322 # Same field_data used in different objects should result # in separately-cached values, so that changing a value # in one instance doesn't affect values stored in others. field_tester_a = FieldTester( runtime=TestRuntime(services={'field-data': field_data}), scope_ids=MagicMock(spec=ScopeIds)) field_tester_b = FieldTester( runtime=TestRuntime(services={'field-data': field_data}), scope_ids=MagicMock(spec=ScopeIds)) value = field_tester_a.field_a assert_equals(value, field_tester_a.field_a) field_tester_a.field_a.append(1) assert_equals(value, field_tester_a.field_a) assert_not_equals(value, field_tester_b.field_a)