class ModuleEngagementSummaryDataTaskMapTest(MapperTestMixin, TestCase):
    """Base class for test analysis of student engagement summaries"""

    task_class = ModuleEngagementSummaryDataTask

    input_record = ModuleEngagementRecord(course_id='foo/bar/baz',
                                          username='******',
                                          date=datetime.date(2015, 11, 1),
                                          entity_type='problem',
                                          entity_id='problem-id',
                                          event='attempted',
                                          count=1)

    def test_invalid_input_types(self):
        input_as_strings = list(self.input_record.to_string_tuple())
        input_as_strings[-1] = 'foo'
        with self.assertRaises(ValueError):
            tuple(self.task.mapper('\t'.join(input_as_strings) + '\n'))

    def test_not_enough_input_columns(self):
        input_as_strings = list(self.input_record.to_string_tuple())[:-1]
        with self.assertRaises(ValueError):
            tuple(self.task.mapper('\t'.join(input_as_strings) + '\n'))

    def test_single_output(self):
        tsv_line = self.input_record.to_separated_values()
        self.assert_single_map_output(tsv_line, ('foo/bar/baz', 'foouser'),
                                      tsv_line)
class ModuleEngagementSummaryDataTaskReducerTest(ReducerTestMixin, TestCase):
    """Base class for test analysis of student engagement summaries"""

    task_class = ModuleEngagementSummaryDataTask
    output_record_type = ModuleEngagementSummaryRecord

    input_record = ModuleEngagementRecord(course_id='foo/bar/baz',
                                          username='******',
                                          date=datetime.date(2014, 03, 26),
                                          entity_type='problem',
                                          entity_id='problem-id',
                                          event='attempted',
                                          count=1)

    def setUp(self):
        super(ModuleEngagementSummaryDataTaskReducerTest, self).setUp()

        self.reduce_key = (self.COURSE_ID, 'test_user')

        self.video_play_record = self.input_record.replace(
            entity_type='video',
            entity_id='foox-video1',
            event='viewed',
        )
        self.forum_record = self.input_record.replace(entity_type='discussion',
                                                      entity_id='forum0',
                                                      event='contributed')

    def test_output_format(self):
        self._check_output_complete_tuple(
            [self.input_record.to_separated_values()], ((
                'foo/bar/baz',
                'test_user',
                '2014-03-25',
                '2014-04-01',
                '1',
                '1',
                '0',
                'inf',
                '0',
                '0',
                '1',
            ), ))

    def test_multiple_problem_attempts_same_problem(self):
        self._check_output_by_record_field(
            [
                self.input_record.to_separated_values(),
                self.input_record.replace(
                    date=datetime.date(2014, 03, 27)).to_separated_values()
            ], {
                'problem_attempts': '2',
                'problems_attempted': '1',
                'problem_attempts_per_completed': 'inf',
                'days_active': '2'
            })

    def test_multiple_problem_attempts_different_problem(self):
        self._check_output_by_record_field(
            [
                self.input_record.to_separated_values(),
                self.input_record.replace(
                    entity_id='problem-id-2').to_separated_values()
            ], {
                'problem_attempts': '2',
                'problems_attempted': '2',
                'problem_attempts_per_completed': 'inf',
                'days_active': '1'
            })

    def test_correct_problem_attempt(self):
        self._check_output_by_record_field(
            [
                self.input_record.to_separated_values(),
                self.input_record.replace(
                    event='completed').to_separated_values()
            ], {
                'problem_attempts': '1',
                'problems_attempted': '1',
                'problems_completed': '1',
                'problem_attempts_per_completed': str(1.0),
                'days_active': '1'
            })

    def test_correct_problem_multiple_attempts(self):
        self._check_output_by_record_field(
            [
                self.input_record.replace(count=4).to_separated_values(),
                self.input_record.replace(
                    event='completed').to_separated_values()
            ], {
                'problem_attempts': '4',
                'problems_attempted': '1',
                'problems_completed': '1',
                'problem_attempts_per_completed': str(4.0),
                'days_active': '1'
            })

    def test_multiple_correct_problems(self):
        self._check_output_by_record_field(
            [
                self.input_record.replace(count=4).to_separated_values(),
                self.input_record.replace(
                    event='completed').to_separated_values(),
                self.input_record.replace(
                    date=datetime.date(
                        2014, 03, 27), entity_id='p2').to_separated_values(),
                self.input_record.replace(
                    date=datetime.date(2014, 03, 27),
                    entity_id='p2',
                    event='completed',
                ).to_separated_values(),
            ], {
                'problem_attempts': '5',
                'problems_attempted': '2',
                'problems_completed': '2',
                'problem_attempts_per_completed': str(2.5),
                'days_active': '2'
            })

    def test_video_viewed(self):
        self._check_output_by_record_field(
            [
                self.video_play_record.to_separated_values(),
            ], {
                'problem_attempts': '0',
                'problems_attempted': '0',
                'problems_completed': '0',
                'problem_attempts_per_completed': 'inf',
                'videos_viewed': '1',
                'days_active': '1'
            })

    def test_multiple_videos_viewed(self):
        self._check_output_by_record_field([
            self.video_play_record.to_separated_values(),
            self.video_play_record.replace(
                entity_id='1').to_separated_values(),
        ], {'videos_viewed': '2'})

    def test_multiple_forum_contributions(self):
        self._check_output_by_record_field([
            self.forum_record.to_separated_values(),
            self.forum_record.replace(entity_id='1',
                                      count=2).to_separated_values(),
        ], {'discussion_contributions': '3'})