Esempio n. 1
0
    def test_update_class(self, empty_json_database, test_full_class):
        test_json_database = empty_json_database
        test_class = Class(test_full_class.name, test_full_class.students)
        # create_class takes a NewClass object due to avatar moving machinery.
        test_class_new_class = NewClass(test_full_class.name,
                                        test_full_class.students)
        assert test_class.json_dict() == test_class_new_class.json_dict(
        )  # Ensure classes are the same.

        # Create class in database.
        test_json_database.create_class(
            NewClass(test_full_class.name, test_full_class.students))
        # Ensure test_class in database
        test_class.id = test_class.name

        # Loaded class will have ids:
        test_loaded_class = test_full_class.json_dict()
        for student in test_loaded_class['students']:
            student['id'] = student['name']
        assert test_json_database.load_class(
            test_class.name).json_dict() == test_loaded_class

        # Change class by adding student, update database:
        new_student = Student(name='new student')
        assert new_student not in test_class and new_student.name not in test_class  # Confirm student not in class.
        test_class.add_student(new_student)

        assert test_json_database.update_class(test_class) is None
        # Look up name because new_student object itself is not in the loaded class object.
        assert new_student.name in test_json_database.load_class(
            test_class.name)
Esempio n. 2
0
def test_new_class_name_only():
    """Returns empty NewClass instantiated with name only."""
    test_new_class_name_only = NewClass(
        test_class_name_only_data_set['json_dict_rep']['name'])

    # Add attributes to test expected output.
    test_new_class_name_only.json_str_rep = test_class_name_only_data_set[
        'json_str_rep']
    test_new_class_name_only.json_dict_rep = test_class_name_only_data_set[
        'json_dict_rep']

    return test_new_class_name_only
Esempio n. 3
0
def take_class_data_input(class_name: str) -> NewClass:
    """
    Take student names, avatars, return Class object.

    :param class_name: str
    :return: Class
    """
    new_class = NewClass(name=class_name)
    while True:
        student_name = take_student_name_input(new_class)
        if student_name.upper() == 'END':
            break
        avatar_filename = take_student_avatar(new_class, student_name)
        new_class.add_student(name=student_name, avatar_id=avatar_filename)
    return new_class
Esempio n. 4
0
    def test_get_classes(self, empty_sqlite_database, existing_class_names,
                         returned_value):
        test_sqlite_database = empty_sqlite_database
        for class_name in existing_class_names:
            empty_sqlite_database.create_class(NewClass(name=class_name))

        assert test_sqlite_database.get_classes() == returned_value
Esempio n. 5
0
    def test_get_avatar_path(self, tmpdir, request, database_backend,
                             avatar_provided):
        """"""
        test_database = request.getfixturevalue(database_backend)

        # Create avatar:
        test_avatar_data = b'some binary data'
        test_avatar_path = Path(tmpdir, 'test_avatar.png')
        test_avatar_path.write_bytes(test_avatar_data)
        # Add avatar to db:
        test_class = NewClass(
            name='test class',
            students=[
                Student(
                    name='test_student',
                    avatar_id=(test_avatar_path if avatar_provided else None),
                )
            ])
        test_database.create_class(test_class)

        # Find avatar_id, load class to verify:
        classes = test_database.get_classes()
        test_class_id = classes[0].id  # As the only class will be first item.
        loaded_test_class = test_database.load_class(test_class_id)
        test_avatar_id = loaded_test_class.students[0].avatar_id

        # Path may be different/random - test data:
        assert test_database.get_avatar_path(test_avatar_id).read_bytes() == (
            test_avatar_data if avatar_provided else
            test_database.default_avatar_path.read_bytes())
    def test_take_student_avatar_pre_clean_name(self, monkeypatch):
        test_class = NewClass('some_class')
        test_student_name = 'clean name'
        test_avatar_filepath = Path('avatar file name')
        cleaned_student_name = 'file name was already clean'
        returned_filename = f'{cleaned_student_name}.png'

        def mocked_select_avatar_file_dialogue():
            return test_avatar_filepath

        def mocked_clean_for_filename(student_name):
            if student_name != test_student_name:
                raise ValueError  # Ensure called with correct arg.
            return cleaned_student_name

        def mocked_copy_file(avatar_filepath, destination_filepath):
            if (avatar_filepath, destination_filepath) != (
                    test_avatar_filepath,
                    test_class.temp_avatars_dir.joinpath(returned_filename)):
                raise ValueError  # Ensure called with correct args.
            return None

        monkeypatch.setattr(class_functions, 'select_avatar_file_dialogue',
                            mocked_select_avatar_file_dialogue)
        monkeypatch.setattr(class_functions, 'clean_for_filename',
                            mocked_clean_for_filename)
        monkeypatch.setattr(class_functions, 'copy_file', mocked_copy_file)

        assert take_student_avatar(test_class,
                                   test_student_name) == returned_filename
Esempio n. 7
0
    def test_create_chart(self, request, database_backend):
        """
        Verify API works.

        NB No verification in API test, as API for verifying does not exist.
        TODO: Verify saved chart contents when load/edit features added.
        """
        test_database = request.getfixturevalue(database_backend)
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                              ])
        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1]],
                100: [test_class.students[2]],
            }
        }

        assert test_database.create_chart(test_chart_data_dict) is None
Esempio n. 8
0
    def test_load_class(self, request, database_backend, class_data):
        """Class loaded has same data as that saved in db, with class/student ids."""
        test_database = request.getfixturevalue(database_backend)
        preexisting_class = request.getfixturevalue(class_data)
        # Create test NewClass object, mocking avatar_files.
        preexisting_class = NewClass.from_dict(preexisting_class.json_dict())
        for student in preexisting_class:
            if student.avatar_id:
                Path(preexisting_class.temp_avatars_dir,
                     student.avatar_id).write_text(student.avatar_id)
        # Create class in db:
        test_database.create_class(preexisting_class)

        # Find class id, load class to verify:
        classes = test_database.get_classes()
        test_full_class_id = classes[
            0].id  # As the only class will be first item.

        # Loaded class will have ids:
        test_loaded_class_with_student_ids = Class.from_dict(
            preexisting_class.json_dict())
        if isinstance(test_database, JSONDatabase):
            for student in test_loaded_class_with_student_ids.students:
                student.id = student.name
        if not isinstance(test_database, JSONDatabase):
            # This should be accurate for most sql databases.
            for test_id, student in enumerate(
                    test_loaded_class_with_student_ids.students, start=1):
                student.id = test_id

        assert test_database.load_class(test_full_class_id).json_dict(
        ) == test_loaded_class_with_student_ids.json_dict()
Esempio n. 9
0
class TestAssembleChartData:
    @pytest.mark.parametrize('class_from_create_class',
                             [Class.from_dict(test_full_class_data_set['json_dict_rep']),  # Pass in test_class
                              NewClass.from_dict(test_full_class_data_set['json_dict_rep'])  # NewClass obj
                              ])
    def test_assemble_chart_data(self, monkeypatch, class_from_create_class):
        test_chart_name = 'my_chart'
        test_chart_filename = test_chart_name
        mock_score_avatar_dict = {'scores': 'list of avatars'}
        mock_chart_params = {'some': 'chart_params'}

        def mocked_take_score_data(class_obj):
            assert class_obj is class_from_create_class
            return mock_score_avatar_dict

        def mocked_take_chart_name():
            return test_chart_name

        def mocked_clean_for_filename(chart_name):
            assert chart_name == test_chart_name
            return test_chart_name

        def mocked_set_chart_params():
            return mock_chart_params

        monkeypatch.setattr(create_chart, 'take_score_data', mocked_take_score_data)
        monkeypatch.setattr(create_chart, 'take_chart_name', mocked_take_chart_name)
        monkeypatch.setattr(create_chart, 'clean_for_filename', mocked_clean_for_filename)
        monkeypatch.setattr(create_chart, 'set_chart_params', mocked_set_chart_params)

        assert assemble_chart_data(class_from_create_class) == (
            test_chart_name, test_chart_filename, mock_score_avatar_dict, mock_chart_params)
Esempio n. 10
0
    def test_create_class(self, request, empty_sqlite_database, class_data):
        test_database = empty_sqlite_database
        test_class_data = request.getfixturevalue(class_data)
        # Create test NewClass object, mocking avatar_files.
        test_class = NewClass.from_dict(test_class_data.json_dict())
        for student in test_class:
            if student.avatar_id:
                Path(test_class.temp_avatars_dir,
                     student.avatar_id).write_text(student.avatar_id)

        # no students or class in empty db:
        assert not test_database._connection().cursor().execute(
            """SELECT * FROM class""").fetchall()
        assert not test_database._connection().cursor().execute(
            """SELECT * FROM student""").fetchall()

        # Create class in db:
        assert test_database.create_class(test_class) is None

        # Find class id, load class to verify:
        classes = test_database.get_classes()
        test_class_id = classes[0].id

        # Class will have ids:
        test_loaded_class_with_student_ids = Class.from_dict(
            test_class.json_dict()).json_dict()
        for test_id, student in enumerate(
                test_loaded_class_with_student_ids['students'], start=1):
            student['id'] = test_id

        assert test_database.load_class(  # NB Returned object will be Class, not NewClass:
            test_class_id).json_dict() == test_loaded_class_with_student_ids
Esempio n. 11
0
    def test_class_name_exists(self, request, database_backend,
                               test_class_name, existing_class_names,
                               returned_value):
        test_database = request.getfixturevalue(database_backend)
        for class_name in existing_class_names:
            test_database.create_class(NewClass(name=class_name))

        assert test_database.class_name_exists(
            test_class_name) == returned_value
Esempio n. 12
0
    def test_new_class_uses_path_safe_name(self):
        # Ensure class name has disallowed characters - validate test.
        test_new_class = NewClass("S|r Røbin's ß@boon$")
        assert test_new_class.name != test_new_class.path_safe_name

        # Ensure class_name_with_disallowed chars in temp dir path.
        assert test_new_class.name not in str(test_new_class.temp_dir)
        # Ensure path_safe_name is in temp dir path.
        assert test_new_class.path_safe_name in str(test_new_class.temp_dir)
Esempio n. 13
0
    def test_move_avatar_to_class_data(self, monkeypatch, empty_json_database):
        """Avatar moved from original location to class data."""
        test_class = NewClass('test_class')
        test_class.id = test_class.name  # Set NewClass id to save in db.
        test_filename = 'test avatar filename'
        test_json_database = empty_json_database

        def mock_move_file(origin_path: Path, destination_path: Path):
            if origin_path != test_class.temp_dir.joinpath(
                    'avatars', test_filename):
                raise ValueError("Origin path incorrect.")
            if destination_path != test_json_database.class_data_path.joinpath(
                    test_class.name, 'avatars', test_filename):
                raise ValueError("Destination path incorrect")

        monkeypatch.setattr(json, 'move_file', mock_move_file)

        assert test_json_database._move_avatar_to_class_data(
            test_class, test_filename) is None
Esempio n. 14
0
    def test_get_classes(self, request, database_backend, existing_class_names,
                         returned_id_names):
        test_database = request.getfixturevalue(database_backend)
        for class_name in existing_class_names:
            test_database.create_class(NewClass(name=class_name))

        retrieved_class_identifiers = test_database.get_classes()
        # class_identifier.id will be different for each backend, but the names will be the same.
        assert [class_id.name for class_id in retrieved_class_identifiers
                ] == returned_id_names
Esempio n. 15
0
    def test_move_avatar_to_class_data_avatar_preexisting(
            self, monkeypatch, empty_json_database):
        """No attempt to move avatar that already exists in class_data."""
        test_class = NewClass('test_class')
        test_class.id = test_class.name  # Set NewClass id to save in db.
        test_json_database = empty_json_database
        # Make existing avatar in tmpdir test_class class data:
        destination_avatar_path = test_json_database.class_data_path.joinpath(
            test_class.name, 'avatars', 'test_avatar_filename')
        Path.mkdir(destination_avatar_path.parent, parents=True)
        with open(destination_avatar_path, 'w'):
            pass

        def mock_move_file(origin_path: Path, destination_path: Path):
            raise ValueError("Move file should not be called.")

        monkeypatch.setattr(json, 'move_file', mock_move_file)

        assert test_json_database._move_avatar_to_class_data(
            test_class, destination_avatar_path.name) is None
Esempio n. 16
0
    def test_new_class_temp_dir_deleted_on_deletion(self, monkeypatch, tmpdir):
        test_temp_dir = Path(tmpdir, 'temp_dir')
        test_temp_dir.mkdir(parents=True)  # Make temp_dir.
        assert not os.listdir(test_temp_dir)  # Nothing in test_temp_dir.

        monkeypatch.setattr(class_, 'TEMP_DIR', test_temp_dir)

        test_class = NewClass("Sir Robin's baboons")
        assert test_class.temp_dir.exists() and os.listdir(
            test_temp_dir)  # Class temp dir in test_temp_dir.
        del test_class  # NB May throw an (ignored) Exception because the class is garbage collected before this line.
        # No class temp dir in test_temp_dir:
        assert not os.listdir(test_temp_dir)
Esempio n. 17
0
    def test_score_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50.0: [test_class.students[1], test_class.students[3]],
                100: [test_class.students[2]],
            }
        }
        test_database.create_chart(test_chart_data_dict)

        scores_data = []
        score_id = 1  # initiate score id
        for score, students in test_chart_data_dict[
                'score-students_dict'].items():
            # NB One chart in db -> chart.id = 1]
            for student in students:
                scores_data += [(score_id, test_chart_data_dict['chart_id'],
                                 student.id, score)]
                score_id += 1

        # Verify reprs of scores in db:
        score_strings = [
            (
                f"<Score("
                f"id={score[0]}, "
                f"chart_id={score[1]}, "
                f"student_id={score[2]}, "
                f"value={float(score[3])}"  # Value is stored as a float.
                f")>") for score in scores_data
        ]
        with test_database.session_scope() as test_session:
            assert repr(test_session.query(
                test_database.Score).all()) == f"[{', '.join(score_strings)}]"
Esempio n. 18
0
    def test_create_chart(self, empty_sqlite_sqlalchemy_database):
        """
        Verify API works.

        NB No verification in API test, as API for verifying does not exist.
        TODO: Verify saved chart contents when load/edit features added.
        """
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])
        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1], test_class.students[3]],
                100: [test_class.students[2]],
            }
        }

        assert test_database.create_chart(test_chart_data_dict) is None

        # Verify chart data in db:
        # A load_chart method might go here.
        with test_database.session_scope() as test_session:
            assert test_session.execute(
                """SELECT chart.name FROM chart""").fetchone(
                )[0] == test_chart_data_dict['chart_name']

            scores_data = []
            for score, students in test_chart_data_dict[
                    'score-students_dict'].items():
                # NB One chart in db -> chart.id = 1
                scores_data += [(1, student.id, score) for student in students]
            assert test_session.execute(
                """SELECT chart_id, student_id, value FROM score""").fetchall(
                ) == scores_data
            # Ensure chart id added to chart_data_dict:
            assert test_chart_data_dict['chart_id'] == 1
Esempio n. 19
0
    def create_class(self, new_class: NewClass) -> None:
        """
        Take a Class object and create/write the class in the database.

        Creates class data in persistence.
        Calls setup_class to create any needed files, then writes data to file.

        :param new_class: Class object
        :return: None
        """
        new_class.id = new_class.name
        self._setup_class(new_class.id)
        self._write_classlist_to_file(new_class)
        self._move_avatars_to_class_data(new_class)
    def test_take_student_avatar_no_avatar(self, monkeypatch):
        test_class = NewClass('some_class')

        def mocked_select_avatar_file_dialogue():
            return None  # No file selected

        monkeypatch.setattr(class_functions, 'select_avatar_file_dialogue',
                            mocked_select_avatar_file_dialogue)

        # Ensure calls to other funcs will cause error.
        monkeypatch.delattr(class_functions, 'clean_for_filename')
        monkeypatch.delattr(class_functions, 'copy_file')

        assert take_student_avatar(test_class, 'some student') is None
Esempio n. 21
0
    def test_new_class_temp_dir_created(self, monkeypatch, tmpdir):
        test_temp_dir = Path(tmpdir, 'temp_dir')
        test_temp_dir.mkdir(parents=True)  # Make temp_dir.
        assert not os.listdir(test_temp_dir)  # Nothing in test_temp_dir.

        monkeypatch.setattr(class_, 'TEMP_DIR', test_temp_dir)

        test_class = NewClass("Sir Robin's baboons")

        assert test_class.temp_dir.exists()
        assert test_class.temp_dir.name in os.listdir(test_temp_dir)
        # Check temp_avatars_dir
        assert test_class.temp_avatars_dir.exists()
        # noinspection PyTypeChecker
        assert test_class.temp_avatars_dir.name in os.listdir(
            test_class.temp_dir)
Esempio n. 22
0
    def test_class_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)

        # Verify repr of (only) class in db:
        with test_database.session_scope() as test_session:
            assert repr(test_session.query(test_database.Class).one(
            )) == f"<Class(id={test_class.id}, name={test_class.name})>"
Esempio n. 23
0
    def test_avatar_table_repr(self, tmpdir, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database

        dummy_avatar_bytes = b'1a2b3c4d'
        avatar_path = Path(tmpdir, 'avatar_path.jpg')
        avatar_path.write_bytes(dummy_avatar_bytes)
        test_class = NewClass(
            name='test_class',
            students=[Student(name='bad student', avatar_id=avatar_path)])

        test_database.create_class(test_class)

        # Verify reprs of avatar in db:
        with test_database.session_scope() as test_session:
            assert repr(
                test_session.query(test_database.Avatar).one()
            ) == f"<Avatar(id={test_class.students[0].id}, image={dummy_avatar_bytes})>"
Esempio n. 24
0
def test_full_new_class():
    """Returns empty NewClass instantiated with students."""
    test_full_new_class = NewClass(
        test_full_class_data_set['json_dict_rep']['name'])
    for student in test_full_class_data_set['json_dict_rep']['students']:
        test_full_new_class.add_student(Student(**student))

    test_full_new_class.json_str_rep = test_full_class_data_set['json_str_rep']
    test_full_new_class.json_dict_rep = test_full_class_data_set[
        'json_dict_rep']

    return test_full_new_class
Esempio n. 25
0
    def test_chart_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1], test_class.students[3]],
                100: [test_class.students[2]],
            }
        }
        test_database.create_chart(test_chart_data_dict)

        # Create fake plot/image
        mock_plt = plt.figure(figsize=(19.20, 10.80))
        test_image = io.BytesIO()
        mock_plt.savefig(test_image, format='png', dpi=300)
        test_image.seek(0)  # Return pointer to start of binary stream.

        test_database.save_chart_image(test_chart_data_dict, mock_plt)

        # Verify repr of (only) chart in db:
        with test_database.session_scope() as test_session:
            assert repr(test_session.query(test_database.Chart).one()) == (
                f"<Chart("
                f"id={test_chart_data_dict['chart_id']}, "
                f"name={test_chart_data_dict['chart_name']}, "
                f"image={test_image.read1()}, "
                f"date=None"  # Not implemented yet.
                f")>")
Esempio n. 26
0
    def create_class(self, new_class: NewClass) -> None:
        """
        Create class data in database.

        Moves avatars for each student to db, changes student.avatar_id
        to id of avatar image in db. If no avatar, this remains None/null,
        and that is stored as student's avatar_id in db.

        :param new_class:
        :return: None
        """
        with self._connection() as conn:
            cursor = conn.cursor()
            # insert class into class
            cursor.execute(
                """
                INSERT INTO class(name)
                VALUES(?);
                """, (new_class.name, ))
            # Add id to class:
            new_class.id = cursor.lastrowid
            for student in new_class:
                # insert student
                if student.avatar_id:
                    # Move avatar from temp to db:
                    avatar_blob = new_class.temp_avatars_dir.joinpath(
                        student.avatar_id).read_bytes()
                    cursor.execute(
                        """
                        INSERT INTO avatar(image)
                        VALUES(?);
                        """, (avatar_blob, ))
                    # Change avatar_id to id of avatar in db.
                    student.avatar_id = cursor.lastrowid
                cursor.execute(
                    """
                    INSERT INTO student(name, class_id, avatar_id)
                    VALUES(?,?,?);
                    """, (student.name, new_class.id, student.avatar_id))

                # Add id to student:
                student.id = cursor.lastrowid
            conn.commit()
        conn.close()
Esempio n. 27
0
    def test_store_students_as_student_names(self, empty_json_database):
        test_json_database = empty_json_database
        test_json_database.default_avatar_path = Path('default/path')

        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                              ])

        test_data_dict = {
            'class_name': "test_class_name",
            'chart_name': "test_chart_name",
            'chart_default_filename': "test_chart_default_filename",
            'chart_params': {
                "some": "chart",
                "default": "params"
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1]],
                100: [test_class.students[2]],
            },
        }
        test_returned_sanitised_data_dict = {
            'class_name': "test_class_name",
            'chart_name': "test_chart_name",
            'chart_default_filename': "test_chart_default_filename",
            'chart_params': {
                "some": "chart",
                "default": "params"
            },
            'score-students_dict': {
                0: [test_class.students[0].name],
                50: [test_class.students[1].name],
                100: [test_class.students[2].name],
            },
        }

        assert test_json_database._store_students_as_student_names(
            test_data_dict) == test_returned_sanitised_data_dict
Esempio n. 28
0
    def test_student_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)
        # Verify reprs of students in db:
        student_strings = [(f"<Student("
                            f"id={student.id}, "
                            f"name={student.name}, "
                            f"class_id={test_class.id}, "
                            f"avatar_id={student.avatar_id}"
                            f")>") for student in test_class.students]

        with test_database.session_scope() as test_session:
            assert repr(test_session.query(test_database.Student).all()
                        ) == f"[{', '.join(student_strings)}]"
Esempio n. 29
0
    def create_class(self, new_class: NewClass) -> None:
        """
        Create class data in database.

        Moves avatars for each student to db, changes student.avatar_id
        to id of avatar image in db. If no avatar, this remains None/null,
        and that is stored as student's avatar_id in db.

        :param new_class:
        :return: None
        """
        with self.session_scope() as session:
            added_class = self.Class(name=new_class.name)
            session.add(added_class)
            session.flush()  # Commit to get a class id
            new_class.id = added_class.id

            # Add students:
            for student in new_class:
                if student.avatar_id:
                    # Move avatar from temp to db:
                    avatar_blob = new_class.temp_avatars_dir.joinpath(
                        student.avatar_id).read_bytes()
                    added_avatar = self.Avatar(image=avatar_blob)
                    session.add(added_avatar)
                    session.flush(
                    )  # Must flush after each avatar to get the avatar id.
                    student.avatar_id = added_avatar.id

                added_student = self.Student(
                    name=student.name,
                    class_id=new_class.id,
                    avatar_id=student.avatar_id,
                )
                session.add(added_student)
                session.flush(
                )  # Must flush after each student to get the avatar id.
                # Add id to student:
                student.id = added_student.id
    def test_take_student_avatar_dirty_name(self, monkeypatch):
        test_class = NewClass('some_class')
        test_student_name = r'very unsafe */^@ :$ name'
        test_avatar_filepath = Path('avatar file name')

        returned_filename = f'{clean_for_filename(test_student_name)}.png'

        def mocked_select_avatar_file_dialogue():
            return test_avatar_filepath

        def mocked_copy_file(avatar_filepath, destination_filepath):
            if (avatar_filepath, destination_filepath) != (
                    test_avatar_filepath,
                    test_class.temp_avatars_dir.joinpath(returned_filename)):
                raise ValueError  # Ensure called with correct args.
            return None

        monkeypatch.setattr(class_functions, 'select_avatar_file_dialogue',
                            mocked_select_avatar_file_dialogue)
        monkeypatch.setattr(class_functions, 'copy_file', mocked_copy_file)

        assert take_student_avatar(test_class,
                                   test_student_name) == returned_filename