class TestMentoringBlockOptions(unittest.TestCase):
    def setUp(self):
        self.service_mock = Mock()
        self.runtime_mock = Mock()
        self.runtime_mock.service = Mock(return_value=self.service_mock)
        self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())

    def test_get_options_returns_default_if_settings_service_is_not_available(self):
        self.runtime_mock.service = Mock(return_value=None)
        self.assertEqual(self.block.get_options(), _default_options_config)

    def test_get_options_returns_default_if_xblock_settings_not_customized(self):
        self.block.get_xblock_settings = Mock(return_value=None)
        self.assertEqual(self.block.get_options(), _default_options_config)
        self.block.get_xblock_settings.assert_called_once_with(default={})

    @ddt.data(
        {}, {'mass': 123}, {'spin': {}}, {'parity': "1"}
    )
    def test_get_options_returns_default_if_options_not_customized(self, xblock_settings):
        self.block.get_xblock_settings = Mock(return_value=xblock_settings)
        self.assertEqual(self.block.get_options(), _default_options_config)
        self.block.get_xblock_settings.assert_called_once_with(default={})

    @ddt.data(
        {MentoringBlock.options_key: 123},
        {MentoringBlock.options_key: [1, 2, 3]},
        {MentoringBlock.options_key: {'pb_mcq_hide_previous_answer': False}},
     )
    def test_get_options_correctly_returns_customized_options(self, xblock_settings):
        self.block.get_xblock_settings = Mock(return_value=xblock_settings)
        self.assertEqual(self.block.get_options(), xblock_settings[MentoringBlock.options_key])
        self.block.get_xblock_settings.assert_called_once_with(default={})

    def test_get_option(self):
        random_key, random_value = random(), random()
        with patch.object(self.block, 'get_options') as patched_get_options:
            # Happy path: Customizations contain expected key
            patched_get_options.return_value = {random_key: random_value}
            option = self.block.get_option(random_key)
            patched_get_options.assert_called_once_with()
            self.assertEqual(option, random_value)
        with patch.object(self.block, 'get_options') as patched_get_options:
            # Sad path: Customizations do not contain expected key
            patched_get_options.return_value = {}
            option = self.block.get_option(random_key)
            patched_get_options.assert_called_once_with()
            self.assertEqual(option, None)

    def test_student_view_calls_get_option(self):
        self.block.get_xblock_settings = Mock(return_value={})
        with patch.object(self.block, 'get_option') as patched_get_option:
            self.block.student_view({})
            patched_get_option.assert_any_call('pb_mcq_hide_previous_answer')
            patched_get_option.assert_any_call('pb_hide_feedback_if_attempts_remain')

    def test_get_standard_results_calls_get_option(self):
        with patch.object(self.block, 'get_option') as patched_get_option:
            self.block._get_standard_results()
            patched_get_option.assert_called_with('pb_hide_feedback_if_attempts_remain')
class TestMentoringBlockOptions(unittest.TestCase):
    def setUp(self):
        self.service_mock = Mock()
        self.runtime_mock = Mock()
        self.runtime_mock.service = Mock(return_value=self.service_mock)
        self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())

    def test_get_options_returns_default_if_settings_service_is_not_available(self):
        self.runtime_mock.service = Mock(return_value=None)
        self.assertEqual(self.block.get_options(), _default_options_config)

    def test_get_options_returns_default_if_xblock_settings_not_customized(self):
        self.block.get_xblock_settings = Mock(return_value=None)
        self.assertEqual(self.block.get_options(), _default_options_config)
        self.block.get_xblock_settings.assert_called_once_with(default={})

    @ddt.data(
        {}, {'mass': 123}, {'spin': {}}, {'parity': "1"}
    )
    def test_get_options_returns_default_if_options_not_customized(self, xblock_settings):
        self.block.get_xblock_settings = Mock(return_value=xblock_settings)
        self.assertEqual(self.block.get_options(), _default_options_config)
        self.block.get_xblock_settings.assert_called_once_with(default={})

    @ddt.data(
        {MentoringBlock.options_key: 123},
        {MentoringBlock.options_key: [1, 2, 3]},
        {MentoringBlock.options_key: {'pb_mcq_hide_previous_answer': False}},
     )
    def test_get_options_correctly_returns_customized_options(self, xblock_settings):
        self.block.get_xblock_settings = Mock(return_value=xblock_settings)
        self.assertEqual(self.block.get_options(), xblock_settings[MentoringBlock.options_key])
        self.block.get_xblock_settings.assert_called_once_with(default={})

    def test_get_option(self):
        random_key, random_value = random(), random()
        with patch.object(self.block, 'get_options') as patched_get_options:
            # Happy path: Customizations contain expected key
            patched_get_options.return_value = {random_key: random_value}
            option = self.block.get_option(random_key)
            patched_get_options.assert_called_once_with()
            self.assertEqual(option, random_value)
        with patch.object(self.block, 'get_options') as patched_get_options:
            # Sad path: Customizations do not contain expected key
            patched_get_options.return_value = {}
            option = self.block.get_option(random_key)
            patched_get_options.assert_called_once_with()
            self.assertEqual(option, None)

    def test_student_view_calls_get_option(self):
        self.block.get_xblock_settings = Mock(return_value={})
        with patch.object(self.block, 'get_option') as patched_get_option:
            self.block.student_view({})
            patched_get_option.assert_any_call('pb_mcq_hide_previous_answer')
            patched_get_option.assert_any_call('pb_hide_feedback_if_attempts_remain')

    def test_get_standard_results_calls_get_option(self):
        with patch.object(self.block, 'get_option') as patched_get_option:
            self.block._get_standard_results()
            patched_get_option.assert_called_with('pb_hide_feedback_if_attempts_remain')
 def test_correctly_decides_to_show_or_hide_feedback_message(
         self, pb_hide_feedback_if_attempts_remain, max_attempts_reached, expected_show_message
 ):
     block = MentoringBlock(Mock(), DictFieldData({
         'student_results': ['must', 'be', 'non-empty'],
     }), Mock())
     block.get_option = Mock(return_value=pb_hide_feedback_if_attempts_remain)
     with patch(
             'problem_builder.mentoring.MentoringBlock.max_attempts_reached', new_callable=PropertyMock
     ) as patched_max_attempts_reached:
         patched_max_attempts_reached.return_value = max_attempts_reached
         _, _, show_message = block._get_standard_results()
         self.assertEqual(show_message, expected_show_message)
 def test_correctly_decides_to_show_or_hide_feedback_message(
         self, pb_hide_feedback_if_attempts_remain, max_attempts_reached, expected_show_message
 ):
     block = MentoringBlock(Mock(), DictFieldData({
         'student_results': ['must', 'be', 'non-empty'],
     }), Mock())
     block.get_option = Mock(return_value=pb_hide_feedback_if_attempts_remain)
     with patch(
             'problem_builder.mentoring.MentoringBlock.max_attempts_reached', new_callable=PropertyMock
     ) as patched_max_attempts_reached:
         patched_max_attempts_reached.return_value = max_attempts_reached
         _, _, show_message = block._get_standard_results()
         self.assertEqual(show_message, expected_show_message)