<file_sep>from flask import Flask
from src.api.blueprint import app_blueprint


class InitFlaskApp(object):
    def __init__(self, host='localhost', port=5000, debug=False):
        self.host = host
        self.port = port
        self.debug = debug

    def create_app(self):
        # Define a Flask application
        app = Flask(__name__, instance_relative_config=False)
        app.config.from_pyfile(filename='flask_config_test.py')

        # Register the blueprint
        app.register_blueprint(app_blueprint)

        return app
<file_sep>import json
import pytest


def _get_formatted_response(response):
    result_dict={}
    result_dict['data'] = json.loads(response.data.decode('utf-8'))
    result_dict['status_code'] = response.status_code

    return result_dict


def test_flask_up_and_running(init_flask_app):
    response = _get_formatted_response(init_flask_app.get('/up_and_running'))
    assert(response['data']['text'] == 'OK')
    assert(response['status_code'] == 200)


def test_create_user_correctly(init_users_db_table, init_flask_app):
    data = {'name': 'Edoardo', 'surname': 'Casiraghi', 'birth_place': 'Merate',
            'birth_date': '25/04/1993', 'instruction_level': 'University'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.post('/add_user', data=json.dumps(data), headers=headers))
    assert(response['data']['text'] == 'The user has been added to SQLite database with ID auto-generated equal to "1".')
    assert(response['status_code'] == 201)


def test_create_user_with_one_field_none(init_users_db_table, init_flask_app):
    data = {'name': 'Edoardo', 'surname': None, 'birth_place': 'Merate',
            'birth_date': '25/04/1993', 'instruction_level': 'University'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    with pytest.raises(ValueError):
        _ = init_flask_app.post('/add_user', data=json.dumps(data), headers=headers)


def test_create_user_without_data(init_users_db_table, init_flask_app):
    data = {}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    with pytest.raises(ValueError):
        _ = init_flask_app.post('/add_user', data=json.dumps(data), headers=headers)


def test_create_user_with_many_fields_none(init_users_db_table, init_flask_app):
    data = {'name': 'Edoardo', 'surname': None, 'birth_place': 'Merate',
            'birth_date': None, 'instruction_level': None}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    with pytest.raises(ValueError):
        _ = init_flask_app.post('/add_user', data=json.dumps(data), headers=headers)


def test_delete_user_without_passing_id(examples_users_db_table, init_flask_app):
    with pytest.raises(json.decoder.JSONDecodeError):
        response = _get_formatted_response(init_flask_app.delete('/delete_user/'))
        assert(response['status_code'] == 404)


def test_delete_user_by_not_existing_id(examples_users_db_table, init_flask_app):
    with pytest.raises(ValueError):
        response = _get_formatted_response(init_flask_app.delete('/delete_user/10'))
        assert(response['data']['text'] == 'There is no user with ID equal to "10" into the SQLite database.')
        assert(response['status_code'] == 200)


def test_delete_user_by_existing_id(examples_users_db_table, init_flask_app):
    response = _get_formatted_response(init_flask_app.delete('/delete_user/1'))
    assert(response['data']['text'] == 'The user with ID equal to "1" has been removed from the SQLite database correctly.')
    assert(response['status_code'] == 200)


def test_get_user_by_existing_id(examples_users_db_table, init_flask_app):
    response = _get_formatted_response(init_flask_app.get('/get_user/1'))
    assert(response['data']['text'] == 'The user with ID equal to 1 is <NAME>,' +
           ' born in 25/04/1993 at Merate and him/her instruction level is University.')
    assert(response['status_code'] == 200)

def test_get_user_without_passing_id(examples_users_db_table, init_flask_app):
    with pytest.raises(json.decoder.JSONDecodeError):
        response = _get_formatted_response(init_flask_app.get('/get_user/'))
        assert(response['status_code'] == 404)


def test_get_user_by_not_existing_id(examples_users_db_table, init_flask_app):
    with pytest.raises(ValueError):
        response = _get_formatted_response(init_flask_app.get('/get_user/10'))
        assert(response['data']['text'] == 'There is no user with ID equal to "10" into the SQLite database.')
        assert(response['status_code'] == 200)


def test_update_one_field_user_by_existing_id(examples_users_db_table, init_flask_app):
    data = {'name': 'Edward'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.put('/update_user/1', headers=headers, data=json.dumps(data)))
    assert(response['data']['text'] == 'The user with ID equal to "1" has been updated in the SQLite database correctly.')
    assert(response['status_code'] == 200)


def test_update_many_fields_user_by_existing_id(examples_users_db_table, init_flask_app):
    data = {'name': 'Edward', 'birth_place': 'Milan', 'instruction_level': 'High School'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.put('/update_user/1', headers=headers, data=json.dumps(data)))
    assert (response['data']['text'] == 'The user with ID equal to "1" has been updated in the SQLite database correctly.')
    assert (response['status_code'] == 200)

def test_update_zero_fields_user_by_existing_id(examples_users_db_table, init_flask_app):
    with pytest.raises(ValueError):
        data = {}
        headers = {'Content-Type': 'application/json', 'Accept': 'text/plain'}
        response = _get_formatted_response(init_flask_app.put('/update_user/1', headers=headers, data=json.dumps(data)))
        assert(response['data']['text'] == 'No fields to update for user with ID equal to "1" has been received by the server.')
        assert(response['status_code'] == 200)


###########

@pytest.mark.courses
def test_create_course_correctly(init_courses_db_table, init_flask_app):
    data = {'name': 'Programming Languages 1', 'professor': '<NAME>', 'tutor': '<NAME>',
            'academic_year': '2020/2021', 'academic_semester': 1, 'credits_number': 8,
            'description': 'Python, Java and OOP.'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.post('/create_course', data=json.dumps(data), headers=headers))
    assert(response['data']['text'] == 'The course has been created to SQLite database with ID auto-generated equal to "1".')
    assert(response['status_code'] == 201)


@pytest.mark.courses
def test_create_course_with_one_field_none_error(init_courses_db_table, init_flask_app):
    data = {'name': None, 'professor': '<NAME>', 'tutor': '<NAME>',
            'academic_year': '2020/2021', 'academic_semester': 1, 'credits_number': 8,
            'description': 'Python, Java and OOP.'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    with pytest.raises(ValueError):
        _ = init_flask_app.post('/create_course', data=json.dumps(data), headers=headers)


@pytest.mark.courses
def test_create_course_with_one_field_none_correctly(init_courses_db_table, init_flask_app):
    data = {'name': 'Programming Languages 1', 'professor': '<NAME>', 'tutor': None,
            'academic_year': '2020/2021', 'academic_semester': 1, 'credits_number': 8,
            'description': 'Python, Java and OOP.'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.post('/create_course', data=json.dumps(data), headers=headers))
    assert (response['data']['text'] == 'The course has been created to SQLite database with ID auto-generated equal to "1".')
    assert (response['status_code'] == 201)


@pytest.mark.courses
def test_create_course_without_data(init_courses_db_table, init_flask_app):
    data = {}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    with pytest.raises(ValueError):
        _ = init_flask_app.post('/create_course', data=json.dumps(data), headers=headers)


@pytest.mark.courses
def test_create_course_with_many_fields_none_correctly(init_courses_db_table, init_flask_app):
    data = {'name': 'Programming Languages 1', 'professor': '<NAME>', 'tutor': None,
            'academic_year': '2020/2021', 'academic_semester': 1, 'credits_number': 8,
            'description': None}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    response = _get_formatted_response(init_flask_app.post('/create_course', data=json.dumps(data), headers=headers))
    assert (response['data']['text'] == 'The course has been created to SQLite database with ID auto-generated equal to "1".')
    assert (response['status_code'] == 201)


@pytest.mark.courses
def test_create_course_with_many_fields_none_error(init_courses_db_table, init_flask_app):
    data = {'name': None, 'professor': None, 'tutor': '<NAME>',
            'academic_year': '2020/2021', 'academic_semester': 1, 'credits_number': 8,
            'description': 'Python, Java and OOP.'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

    with pytest.raises(ValueError):
        _ = init_flask_app.post('/create_course', data=json.dumps(data), headers=headers)

def test_delete_course_without_passing_id(examples_courses_db_table, init_flask_app):
    with pytest.raises(json.decoder.JSONDecodeError):
        response = _get_formatted_response(init_flask_app.delete('/delete_course/'))
        assert(response['status_code'] == 404)


def test_delete_course_by_not_existing_id(examples_courses_db_table, init_flask_app):
    with pytest.raises(ValueError):
        response = _get_formatted_response(init_flask_app.delete('/delete_course/10'))
        assert(response['data']['text'] == 'There is no course with ID equal to "10" into the SQLite database.')
        assert(response['status_code'] == 200)


def test_delete_course_by_existing_id(examples_courses_db_table, init_flask_app):
    response = _get_formatted_response(init_flask_app.delete('/delete_course/1'))
    assert(response['data']['text'] == 'The course with ID equal to "1" has been removed from the SQLite database correctly.')
    assert(response['status_code'] == 200)


def test_get_course_by_existing_id(examples_courses_db_table, init_flask_app):
    response = _get_formatted_response(init_flask_app.get('/get_course/1'))
    assert(response['data']['text'] == 'The course with ID equal to "1" is Programming Languages 1, held by' +
           ' <NAME> during the academic year 2018/2019 in the 2° semester and it is 10 credits.')
    assert(response['status_code'] == 200)


def test_get_course_without_passing_id(examples_courses_db_table, init_flask_app):
    with pytest.raises(json.decoder.JSONDecodeError):
        response = _get_formatted_response(init_flask_app.get('/get_course/'))
        assert(response['status_code'] == 404)


def test_get_course_by_not_existing_id(examples_courses_db_table, init_flask_app):
    with pytest.raises(ValueError):
        response = _get_formatted_response(init_flask_app.get('/get_course/10'))
        assert(response['data']['text'] == 'There is no course with ID equal to "10" into the SQLite database.')
        assert(response['status_code'] == 200)

'''
def test_update_one_field_user_by_existing_id(examples_users_db_table, init_flask_app):
    data = {'name': 'Edward'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.put('/update_user/1', headers=headers, data=json.dumps(data)))
    assert(response['data']['text'] == 'The user with ID equal to "1" has been updated in the SQLite database correctly.')
    assert(response['status_code'] == 200)


def test_update_many_fields_user_by_existing_id(examples_users_db_table, init_flask_app):
    data = {'name': 'Edward', 'birth_place': 'Milan', 'instruction_level': 'High School'}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    response = _get_formatted_response(init_flask_app.put('/update_user/1', headers=headers, data=json.dumps(data)))
    assert (response['data']['text'] == 'The user with ID equal to "1" has been updated in the SQLite database correctly.')
    assert (response['status_code'] == 200)

def test_update_zero_fields_user_by_existing_id(examples_users_db_table, init_flask_app):
    with pytest.raises(ValueError):
        data = {}
        headers = {'Content-Type': 'application/json', 'Accept': 'text/plain'}
        response = _get_formatted_response(init_flask_app.put('/update_user/1', headers=headers, data=json.dumps(data)))
        assert(response['data']['text'] == 'No fields to update for user with ID equal to "1" has been received by the server.')
        assert(response['status_code'] == 200)
'''
<file_sep>antiorm==1.2.1
appdirs==1.4.4
atomicwrites==1.4.0
attrs==20.3.0
certifi==2020.11.8
chardet==3.0.4
click==7.1.2
colorama==0.4.4
coverage==5.3
db==0.1.1
db-sqlite3==0.0.1
distlib==0.3.1
et-xmlfile==1.0.1
filelock==3.0.12
flake8==3.8.4
Flask==1.1.2
idna==2.10
importlib-metadata==2.1.1
iniconfig==1.1.1
itsdangerous==1.1.0
jdcal==1.4.1
Jinja2==2.11.2
MarkupSafe==1.1.1
mccabe==0.6.1
numpy==1.19.4
openpyxl==3.0.5
packaging==20.7
Pillow==8.0.1
pluggy==0.13.1
py==1.9.0
pycodestyle==2.6.0
pyflakes==2.2.0
pyparsing==2.4.7
pytesseract==0.3.6
pytest==6.1.2
pytest-cov==2.10.1
pytest-flake8==1.0.6
python-dateutil==2.8.1
pytz==2020.4
requests==2.25.0
six==1.15.0
src==0.0.1
toml==0.10.2
tox==3.20.1
tox-interpreters==0.1.0
urllib3==1.26.2
virtualenv==20.2.1
Werkzeug==1.0.1
wincertstore==0.2
zipp==3.4.0
<file_sep>import os
import sqlite3

class DAO(object):
    def __init__(self, path_to_db):
        # Define the path where to save the SQLite3 database data
        self._path_to_db = path_to_db

        # Retrieve the connection to the (already created) database
        self._connection = sqlite3.connect(database=self._path_to_db)
        self._connection.row_factory = sqlite3.Row
        self._cursor = self._connection.cursor()

    def destroy(self):
        self._cursor.close()
        self._connection.close()

    def _create_table(self, table_name):
        sql_statement=None
        if table_name == 'users':
            sql_statement = """ CREATE TABLE users (
                id INTEGER PRIMARY KEY,
                name varchar NOT NULL,
                surname varchar NOT NULL,
                birth_place varchar NOT NULL,
                birth_date varchar NOT NULL,
                instruction_level varchar NOT NULL,
                age INTEGER NOT NULL
            ); """
        elif table_name == 'courses':
            sql_statement = """ CREATE TABLE courses (
                id INTEGER PRIMARY KEY,
                name varchar NOT NULL,
                professor varchar NOT NULL,
                tutor varchar NULL,
                academic_year varchar NOT NULL,
                academic_semester varchar NOT NULL,
                credits_number INT NOT NULL,
                description varchar NULL
            ); """
        try:
            self._cursor.execute(sql_statement)
            self._connection.commit()
        except Exception as e:
            print(e)

    def _truncate_table(self, table_name):
        sql_statement = """ DELETE FROM {}; """.format(table_name)

        try:
            self._cursor.execute(sql_statement)
            self._connection.commit()
        except Exception as e:
            print(e)

    def create_table(self, table_name):
        # Check whether the table already exists or not
        result = self._cursor.execute("SELECT name FROM sqlite_master WHERE type='table';").fetchall()

        # Get the already existing tables in the SQLite database
        already_existing_table_names = [table_name[0] for table_name in result]
        if len(result) == 0 or table_name not in already_existing_table_names:
            # empty database or the database exists but the table does not exist
            self._create_table(table_name=table_name)
        else:
            # truncate table
            self._truncate_table(table_name=table_name)

    def add_row_into_table(self, object, table_name):
        if table_name == 'users':
            return self._add_user_into_users_table(user=object)
        elif table_name == 'courses':
            return self._add_course_into_courses_table(course=object)

    def _add_course_into_courses_table(self, course):
        # Define the SQL statement to use for adding a new course in the "courses" database table
        sql_statement = 'INSERT INTO courses(name, professor, tutor, academic_year, academic_semester, credits_number, description)' + \
                        'VALUES (?, ?, ?, ?, ?, ?, ?);'
        self._cursor.execute(sql_statement, (course.name, course.professor, course.tutor, course.academic_year,
                                             course.academic_semester, course.credits_number, course.description))
        self._connection.commit()

        # Retrieve the ID automatically assigned by SQLite database
        course_id = self._cursor.lastrowid

        return course_id

    def _add_user_into_users_table(self, user):
        # Define the SQL statement to use for adding a new user in the "users" database table
        sql_statement = 'INSERT INTO users(name, surname, birth_date, age, birth_place, instruction_level)' + \
                        'VALUES (?, ?, ?, ?, ?, ?);'
        self._cursor.execute(sql_statement, (user.name, user.surname, user.birth_date, user.age,
                                             user.birth_place, user.instruction_level))
        self._connection.commit()

        # Retrieve the ID automatically assigned by SQLite database
        user_id = self._cursor.lastrowid

        return user_id

    def delete_row_from_table(self, object, table_name):
        # Get the ID of the object to remove from a specific table in the SQLite database
        if 'id' in object:
            object_id = object['id']

        # Define the SQL statement to use for removing a specific user with ID equal to the one received
        sql_statement = """SELECT * FROM {};""".format(table_name)
        result = self._cursor.execute(sql_statement).fetchall()
        if object_id not in [element['id'] for element in result]:
            # The particular row from a table name has not been removed correctly
            raise ValueError('There is no {} with ID equal to "{}" into the SQLite database.'.format(
                table_name[:-1], object_id))

        sql_statement = """DELETE FROM {} WHERE id = {};""".format(table_name, object_id)
        self._cursor.execute(sql_statement)
        self._connection.commit()

        sql_statement = """SELECT * FROM {};""".format(table_name)
        result = self._cursor.execute(sql_statement).fetchall()

        if object_id in [element['id'] for element in result]:
            raise ValueError('The {} with ID equal to "{}"'.format(table_name[:-1], object_id) +\
                             ' has not been removed correctly from the SQLite database.')

    def get_row_from_table(self, object, table_name):
        # Get the ID of the object to remove from a specific table in the SQLite database
        if 'id' in object:
            object_id = object['id']

        # Define the SQL statement to use for removing a specific user with ID equal to the one received
        try:
            sql_statement = """SELECT * FROM {} WHERE id = {};""".format(table_name, object_id)
            result = self._cursor.execute(sql_statement).fetchone()

            # If a specific user with ID does not exist in the SQLite database, raise a KeyError Exception
            if object_id == result['id']:
                # The particular row from a table name has been removed correctly
                # Return the description of a specific user by ID
                return {field: result[field] for field in list(result.keys()) if field != 'id'}
            else:
                # The particular row from a table name has not been removed correctly
                raise KeyError('ERROR: there is no {} with ID equal to "{}"'.format(table_name[:-1], object_id) + \
                               ' in the "{}" table of the SQLite database.'.format(table_name))

        except Exception as e:
            raise ValueError

    def update_row_in_table(self, table_name, object):
        def _prepare_sql_update_statement(new_data_dict):
            update_values_stmt = ''
            for k, v in new_data_dict.items():
                update_values_stmt += '{} = "{}", '.format(k, v)
            update_values_stmt = update_values_stmt.rstrip(', ')

            return update_values_stmt

        # Get the ID of the object to remove from a specific table in the SQLite database
        if 'id' in object:
            object_id = object['id']

        # Define the SQL statement to use for removing a specific user with ID equal to the one received
        sql_statement = """SELECT * FROM {};""".format(table_name)
        result = self._cursor.execute(sql_statement).fetchall()

        if object_id not in [element['id'] for element in result]:
            # The particular row from a table name has not been removed correctly
            raise ValueError('There is no {} with ID equal to "{}" into the SQLite database.'.format(table_name[:-1], object_id))

        # Remove the 'id' of the user
        new_data_dict = {k: v for k, v in object.items() if k != 'id'}
        if len(new_data_dict) == 0:
            raise ValueError('No fields to update for {} with ID equal to "{}"'.format(table_name[:-1], object_id) +\
                             ' has been received by the server.')

        # Define the portion of the SQL DML statement for updating the user field(s)
        update_values_stmt = _prepare_sql_update_statement(new_data_dict=new_data_dict)

        # Update the found user with new data values
        sql_statement = """UPDATE {} SET {} WHERE id = {};""".format(table_name, update_values_stmt, object_id)
        self._cursor.execute(sql_statement)
        self._connection.commit()

        # Check the update operation has been done successfully
        sql_statement = """SELECT * FROM {} WHERE id = {};""".format(table_name, object_id)
        result = self._cursor.execute(sql_statement).fetchone()

        for field, new_value in new_data_dict.items():
            if result[field] != new_value:
                raise AttributeError
<file_sep>from setuptools import setup

setup(
   name='src',
   version='0.0.1',
   description='TestingApplication description',
   author='<NAME>',
   author_email='<EMAIL>',
   packages=['src']
)<file_sep>from datetime import datetime
import math


class User(object):

    def __init__(self, name, surname, birth_date, birth_place, instruction_level):
        self.name = name
        self.surname = surname
        self.birth_date = birth_date
        self.birth_place = birth_place
        self.instruction_level = instruction_level

        self.age = self.compute_age_from_birth_date(self.convert_date_to_standard_format(self.birth_date))

    ### GETTER methods ###
    @property
    def name(self):
        return self._name

    @property
    def surname(self):
        return self._surname

    @property
    def birth_date(self):
        return self._birth_date

    @property
    def birth_place(self):
        return self._birth_place

    @property
    def instruction_level(self):
        return self._instruction_level

    @property
    def age(self):
        return self._age

    ### SETTER methods ###
    @name.setter
    def name(self, name):
        if name is None:
            raise ValueError('ERROR: the name of a user can not be empty.')
        self._name = name

    @surname.setter
    def surname(self, surname):
        if surname is None:
            raise ValueError('ERROR: the surname of a user can not be empty.')
        self._surname = surname

    @birth_date.setter
    def birth_date(self, birth_date):
        if birth_date is None:
            raise ValueError('ERROR: the birth date of a user can not be empty.')
        self._birth_date = birth_date

    @birth_place.setter
    def birth_place(self, birth_place):
        if birth_place is None:
            raise ValueError('ERROR: the birth place of a user can not be empty.')
        self._birth_place = birth_place

    @instruction_level.setter
    def instruction_level(self, instruction_level):
        if instruction_level not in ['Middle School', 'High School', 'University']:
            raise ValueError('ERROR: the instruction level of a user can be only "Middle School",'
                                 '"High School or "University".')
        self._instruction_level = instruction_level

    @age.setter
    def age(self, age):
        self._age = age

    def compute_age_from_birth_date(self, birth_date):
        # Retrieve the current date
        current_date = datetime.now()
        # Convert the birth date from string type to datetime type
        birth_date = datetime.strptime(birth_date, '%d/%m/%Y')

        # Derive the age of a user as the difference between the current date and the birth date of the user
        age = math.floor( float( (current_date - birth_date).days / 365 ) )
        # If the difference between them is negative, then it is a error to capture
        if age < 0:
            raise ValueError('ERROR: The birth date can not be after the current date.')

        return age

    def convert_date_to_standard_format(self, birth_date):
        # If there are both "-" and "/" characters that split day, month and year, it is a not understandable format
        if '-' in birth_date and '/' in birth_date:
            raise ValueError('ERROR: in a date can not be both "-" and "/" characters.')

        # Convert "-" to "/" if necessary
        if '-' in birth_date:
            birth_date = birth_date.replace('-', '/')

        # Split the date to its component i.e. day, month, year
        day, month, year = birth_date.split('/')

        # If the year is between day and month, it is a not understandable format
        if len(month) == 4:
            raise ValueError('ERROR: date format not understandable.')

        # If the day is at the end of the date and the year is at the beginning of the date, switch them
        if len(day) == 4 and len(year) == 2:
            day, year = year, day

        return '{}/{}/{}'.format(day, month, year)
<file_sep>from flask import Blueprint, request, jsonify
import json

from src.model.user import User
from src.model.course import Course
from src.dao.dao import DAO

app_blueprint = Blueprint('main', __name__)

def _get_dao_handler():
    # Read a temporary file called "tmp.txt" which contains the path to the test SQLite database
    with open('tmp.txt', 'r') as input_file:
        path_to_tmp_db_directory = input_file.readline().rstrip('\n')

    # Create a connection to the test SQLite database
    dao_handler = DAO(path_to_db=path_to_tmp_db_directory)

    return dao_handler


@app_blueprint.route('/up_and_running', methods=['GET'])
def up_and_running():
    return jsonify({'text': 'OK'}), 200


@app_blueprint.route('/add_user', methods=['POST'])
def add_user():
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Get the data received by HTTP POST request
    request_data = json.loads(request.data)
    if len(request_data) == 0:
        raise ValueError('ERROR: no data have been received.')

    # Create a User object with the information about him/her passed by HTTP request
    u = User(name=request_data['name'], surname=request_data['surname'], birth_date=request_data['birth_date'],
             birth_place=request_data['birth_place'], instruction_level=request_data['instruction_level'])

    # Add the user to the SQLite database and retrieve the ID automatically assigned to him/her
    user_id = dao_handler.add_row_into_table(object=u, table_name='users')

    return jsonify({'text': 'The user has been added to SQLite database with ID auto-generated' +\
                            ' equal to "{}".'.format(user_id)}), 201


@app_blueprint.route('/delete_user/<int:user_id>', methods=['DELETE'])
def delete_user_by_id(user_id):
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Delete the specific user by him/her ID
    dao_handler.delete_row_from_table(table_name='users', object={'id': user_id})

    return jsonify({'text': 'The user with ID equal to "{}" has been removed'.format(user_id) +\
                            ' from the SQLite database correctly.'}), 200


@app_blueprint.route('/get_user/<int:user_id>', methods=['GET'])
def get_user_by_id(user_id):
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Get the specific user by him/her ID
    user_description = dao_handler.get_row_from_table(table_name='users', object={'id': user_id})

    # If the specific user does not exist in the SQLite database
    if user_description is None:
        return jsonify({'text': 'The user with ID equal to {} does not exist into the SQLite database.'.format(user_id)}, 200)

    # Prepare the output string
    return jsonify({'text': 'The user with ID equal to {} is {} {}'.format(user_id, user_description['name'], user_description['surname']) +\
                       ', born in {} at {} and him/her instruction'.format(user_description['birth_date'], user_description['birth_place']) +\
                        ' level is {}.'.format(user_description['instruction_level'])}), 200


@app_blueprint.route('/update_user/<int:user_id>', methods=['PUT'])
def update_user_by_id(user_id):
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Get the data received by HTTP POST request
    request_data = json.loads(request.data)

    # Update the user with the new values received as input
    object = {**{'id': user_id}, **request_data}
    dao_handler.update_row_in_table(table_name='users', object=object)

    return jsonify({'text': 'The user with ID equal to "{}" has been updated'.format(user_id) +\
                    ' in the SQLite database correctly.'}), 200


@app_blueprint.route('/create_course', methods=['POST'])
def create_user():
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Get the data received by HTTP POST request
    request_data = json.loads(request.data)
    if len(request_data) == 0:
        raise ValueError('ERROR: no data have been received.')

    # Create a Course object with the information about him/her passed by HTTP request
    c = Course(name=request_data['name'], professor=request_data['professor'], tutor=request_data['tutor'],
               academic_year=request_data['academic_year'], academic_semester=request_data['academic_semester'],
               credits_number=request_data['credits_number'], description=request_data['description'])

    # Add the course to the SQLite database and retrieve the ID automatically assigned to it
    course_id = dao_handler.add_row_into_table(object=c, table_name='courses')

    return jsonify({'text': 'The course has been created to SQLite database with ID auto-generated' + \
                            ' equal to "{}".'.format(course_id)}), 201

@app_blueprint.route('/delete_course/<int:course_id>', methods=['DELETE'])
def delete_course_by_id(course_id):
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Delete the specific course by its ID
    dao_handler.delete_row_from_table(table_name='courses', object={'id': course_id})

    return jsonify({'text': 'The course with ID equal to "{}" has been removed'.format(course_id) +\
                            ' from the SQLite database correctly.'}), 200


@app_blueprint.route('/get_course/<int:course_id>', methods=['GET'])
def get_course_by_id(course_id):
    # Get a connection to the test SQLite database
    dao_handler = _get_dao_handler()

    # Get the specific course by him/her ID
    course_description = dao_handler.get_row_from_table(table_name='courses', object={'id': course_id})

    # If the specific user does not exist in the SQLite database
    if course_description is None:
        return jsonify({'text': 'The course with ID equal to "{}" does not exist into the SQLite database.'.format(course_id)}, 200)

    # Prepare the output string
    return jsonify({'text': 'The course with ID equal to "{}" is {},'.format(course_id, course_description['name']) +\
                            ' held by {} during the academic year {}'.format(course_description['professor'],
                                                                             course_description['academic_year']) +\
                            ' in the {}° semester and it is'.format(course_description['academic_semester']) +\
                            ' {} credits.'.format(course_description['credits_number'])}), 200
<file_sep>class Course(object):

    def __init__(self, name, professor, tutor, academic_year, academic_semester, credits_number, description):
        self.name = name
        self.professor = professor
        self.tutor = tutor
        self.academic_year = academic_year
        self.academic_semester = academic_semester
        self.credits_number = credits_number
        self.description = description

    @property
    def name(self):
        return self._name

    @property
    def professor(self):
        return self._professor

    @property
    def tutor(self):
        return self._tutor

    @property
    def academic_year(self):
        return self._academic_year

    @property
    def academic_semester(self):
        return self._academic_semester

    @property
    def credits_number(self):
        return self._credits_number

    @property
    def description(self):
        return self._description

    @name.setter
    def name(self, name):
        if name is None:
            raise ValueError('ERROR: the name of the course is mandatory.')
        self._name = name

    @professor.setter
    def professor(self, professor):
        if professor is None:
            raise ValueError('ERROR: the professor name and surname of the course is mandatory.')
        self._professor = professor

    @tutor.setter
    def tutor(self, tutor):
        self._tutor = tutor

    @academic_year.setter
    def academic_year(self, academic_year):
        if academic_year is None:
            raise ValueError('ERROR: the academic year of the course is mandatory.')
        self._academic_year = academic_year

    @academic_semester.setter
    def academic_semester(self, academic_semester):
        if academic_semester is None:
            raise ValueError('ERROR: the academic semester of the course is mandatory.')
        self._academic_semester = academic_semester

    @credits_number.setter
    def credits_number(self, credits_number):
        if credits_number is None:
            raise ValueError('ERROR: the number of credits of the course is mandatory.')
        self._credits_number = credits_number

    @description.setter
    def description(self, description):
        self._description = description
<file_sep>##########################################################
#
# flask_test.cfg is intended to be used for testing a Flask application
#
##########################################################


# Update later by using a random number generator and moving
# the actual key outside of the source code under version control
DEBUG = True

# Enable the TESTING flag to disable the error catching during request handling
# so that you get better error reports when performing test requests against the application.
TESTING = True
<file_sep>import pytest

from src.model.course import Course

@pytest.mark.courses
@pytest.mark.parametrize('course', [('Programming Languages 1', '<NAME>', '<NAME>',
                                     '2020/2021', 1, 8, 'Learning Python, Java and OOP.')])
def test_init_course_correctly(course):
    name, professor, tutor, academic_year, academic_semester, credits_number, description = course
    c = Course(name=name, professor=professor, tutor=tutor, academic_year=academic_year,
               academic_semester=academic_semester, credits_number=credits_number, description=description)
    assert(c.name == name)
    assert(c.professor == professor)
    assert(c.tutor == tutor)
    assert(c.academic_year == academic_year)
    assert(c.academic_semester == academic_semester)
    assert(c.credits_number == credits_number)
    assert(c.description == description)

@pytest.mark.courses
@pytest.mark.parametrize('course_description,expected_output', [
    ( (None, '<NAME>', '<NAME>', '2020/2021', 1, 8, 'Learning Python, Java and OOP.'), ValueError),
    ( ('Programming Languages 1', None, '<NAME>', '2020/2021', 1, 8, 'Learning Python, Java and OOP.'), ValueError),
    ( ('Programming Languages 1', '<NAME>', None, '2020/2021', 1, 8, 'Learning Python, Java and OOP.'), 'OK'),
    ( ('Programming Languages 1', '<NAME>', '<NAME>', None, 1, 8, 'Learning Python, Java and OOP.'), ValueError),
    ( ('Programming Languages 1', '<NAME>', '<NAME>', '2020/2021', None, 8, 'Learning Python, Java and OOP.'), ValueError),
    ( ('Programming Languages 1', '<NAME>', '<NAME>', '2020/2021', 1, None, 'Learning Python, Java and OOP.'), ValueError),
    ( ('Programming Languages 1', '<NAME>', '<NAME>', '2020/2021', 1, 8, None), 'OK')])
def test_init_user_empty_attributes_error(course_description, expected_output):
    name, professor, tutor, academic_year, academic_semester, credits_number, description = course_description

    if expected_output == 'OK':
        c = Course(name=name, professor=professor, tutor=tutor, academic_year=academic_year,
                   academic_semester=academic_semester, credits_number=credits_number, description=description)
        assert (c.name == name)
        assert (c.professor == professor)
        assert (c.tutor == tutor)
        assert (c.academic_year == academic_year)
        assert (c.academic_semester == academic_semester)
        assert (c.credits_number == credits_number)
        assert (c.description == description)

    elif isinstance(expected_output, Exception):
        with pytest.raises(ValueError):
            _ = Course(name=name, professor=professor, tutor=tutor, academic_year=academic_year,
                       academic_semester=academic_semester, credits_number=credits_number, description=description)
<file_sep>[tox]
envlist = py37

[testenv]
# run the tests
# ... or run any other command line tool you need to run here
commands = pytest<file_sep>import pytest
from src.model.user import User


@pytest.mark.parametrize('user', [('Edoardo', 'Casiraghi', '25/04/1993',
                                   'Merate', 'University')])
def test_init_user_correctly(user):
    name, surname, birth_date, birth_place, instruction_level = user
    u = User(name=name, surname=surname, birth_date=birth_date,
             birth_place=birth_place, instruction_level=instruction_level)
    assert(u.name == name)
    assert(u.surname == surname)
    assert(u.birth_place == birth_place)
    assert(u.birth_date == birth_date)
    assert(u.instruction_level == instruction_level)
    assert(u.age == 27)


@pytest.mark.parametrize('user_description', [(None, 'Casiraghi', '25/04/1993',
                                               'Merate', 'University'),
                                              ('Edoardo', None, '25/04/1993',
                                               'Merate', 'University'),
                                              ('Edoardo', 'Casiraghi', None,
                                               'Merate', 'University'),
                                              ('Edoardo', 'Casiraghi', '25/04/1993',
                                               None, 'University'),
                                              ('Edoardo', 'Casiraghi', '25/04/1993',
                                               'Merate', None)])
def test_init_user_empty_attributes_error(user_description):
    name, surname, birth_date, birth_place, instruction_level = user_description
    with pytest.raises(expected_exception=ValueError):
        _ = User(name=name, surname=surname, birth_date=birth_date, birth_place=birth_place,
                 instruction_level=instruction_level)


@pytest.mark.parametrize('input_birth_date,expected_age',
                         [('01/01/2020', 0),
                          ('25/04/1993', 27),
                          ('25/04/2002', 18)])
def test_compute_age_from_birth_date(input_birth_date, expected_age):
    user = User(name='Edoardo', surname='Casiraghi', birth_date=input_birth_date,
                birth_place='Merate', instruction_level='University')

    if isinstance(expected_age, int):
        # Compute the age given the birth date of a user
        computed_age = user.compute_age_from_birth_date(birth_date=input_birth_date)
        assert( computed_age == expected_age )
    elif isinstance(expected_age, Exception):
        with pytest.raises(ValueError):
            # Compute the age given the birth date of a user
            user.compute_age_from_birth_date(birth_date=input_birth_date)


@pytest.mark.parametrize('input_birth_date, expected_birth_date',
                         [('01/01/2020', '01/01/2020'),
                          ('2020-11-01', '01/11/2020'),
                          ('2020/11-01', ValueError),
                          ('2020-11/01', ValueError),
                          ('1999/11/01', '01/11/1999'),
                          ('1999-11-01', '01/11/1999'),
                          ('11-1999-01', ValueError)])
def test_convert_date_to_standard_format(input_birth_date, expected_birth_date):
    user = User(name='Edoardo', surname='Casiraghi', birth_date='25/04/1993',
                birth_place='Merate', instruction_level='University')

    if isinstance(expected_birth_date, str):
        # Compute the age given the birth date of a user
        computed_birth_date = user.convert_date_to_standard_format(birth_date=input_birth_date)
        assert(computed_birth_date == expected_birth_date)
    else:
        with pytest.raises(ValueError):
            # Compute the age given the birth date of a user
            _ = user.convert_date_to_standard_format(birth_date=input_birth_date)
<file_sep># TestingApplication
Experiments with Python testing framework (pytest), CI/CD with Jenkins and TDD.
<file_sep>import sqlite3
import os


class DataBaseHandler(object):
    def __init__(self, db_name):
        # Define the path where to save the SQLite3 database data
        self._path_to_db = db_name

        # Create the SQLite database
        print('INFO: creating the SQLite database...')
        self._connection = sqlite3.connect(database=self._path_to_db)

        print('SQLite Database created correctly to "{}".'.format(self._path_to_db))

    def destroy(self):
        print('INFO: destroying the SQLite database...')
        self._connection.close()
        #os.remove(self._path_to_db)
<file_sep>import configparser


class ConfigurationsUtils(object):
    def __init__(self, config_file='./utils/init_config_test.cfg'):
        config = configparser.ConfigParser()
        config.read(config_file)

        # Read the path to the SQLite database
        self._path_to_sqlite_database = config.get('DATABASE', 'PathToDatabase')
        self._database_name = config.get('DATABASE', 'DatabaseName')
<file_sep>import pytest
import os

from src.model.user import User
from src.model.course import Course
from src.dao.dao import DAO
from src.dao.database import DataBaseHandler
from src.api.app import InitFlaskApp
from utils.configuration_utils import ConfigurationsUtils

@pytest.fixture(scope='session', name='init_sqlite3_db')
def init_sqlite3_db(tmpdir_factory):
    ### SET-UP ###
    # Read the init_config_test.cfg file which contains the path to the SQLite database
    cfg_handler = ConfigurationsUtils()

    # Split the path to the SQLite database used for test purposes to its directories and sub-directories
    main_dir, sub_dir = cfg_handler._path_to_sqlite_database.split('/')[1:]

    # Add a sub-directory whose name is read from "init_config_test.cfg" file where to save the SQLite database
    path_to_tmp_db_directory = tmpdir_factory.mktemp(basename=main_dir, numbered=False).mkdir(sub_dir)\
        .join(cfg_handler._database_name)

    # Save in a temporary file called "tmp.txt" the path to the test SQLite database (removed at the end of tests)
    with open('tmp.txt', 'w') as output_file:
        output_file.write(str(path_to_tmp_db_directory)+'\n')

    # Create a SQLite3 database one-shot
    database_handler = DataBaseHandler(db_name=path_to_tmp_db_directory)

    yield database_handler

    ### TEAR-DOWN ###
    database_handler.destroy()
    os.remove('tmp.txt') # file where to save the path to the SQLite database


@pytest.fixture(scope='session', name='init_sqlite3_db_connection')
def init_sqlite3_db_connection(init_sqlite3_db):
    ### SET-UP ###

    dao_handler = DAO(path_to_db=init_sqlite3_db._path_to_db)

    yield dao_handler

    ### TEAR-DOWN ###
    dao_handler.destroy()


@pytest.fixture(scope='function', name='init_users_db_table')
def create_users_table_in_db(init_sqlite3_db, init_sqlite3_db_connection):
    ### SET-UP ###
    dao_handler = init_sqlite3_db_connection
    dao_handler.create_table(table_name='users')

    yield

    ### TEAR-DOWN ###
    #@TODO: drop "users" table in the SQLite database


@pytest.fixture(scope='function', name='init_courses_db_table')
def create_courses_table_in_db(init_sqlite3_db, init_sqlite3_db_connection):
    ### SET-UP ###
    dao_handler = init_sqlite3_db_connection
    dao_handler.create_table(table_name='courses')

    yield

    ### TEAR-DOWN ###
    #@TODO: drop "courses" table in the SQLite database

###################################################################


@pytest.fixture(scope='module', name='return_new_users_correctly')
def return_new_users_correctly():
    new_users_correct = [User(name='Edoardo', surname='Casiraghi', birth_date='25/04/1993', birth_place='Merate',
                              instruction_level='University'),
                         User(name='Veronica', surname='Lanzi', birth_date='01/05/1994', birth_place='Lecco',
                              instruction_level='University'),
                         User(name='Danilo', surname='Casiraghi', birth_date='11/10/1961', birth_place='Vimercate',
                              instruction_level='High School'),
                         User(name='Daniela', surname='Bonalume', birth_date='18/02/1963', birth_place='Merate',
                              instruction_level='Middle School')]

    return new_users_correct


@pytest.fixture(scope='module', name='init_flask_app')
def init_flask_app(init_sqlite3_db):
    flask_handler = InitFlaskApp()
    flask_app = flask_handler.create_app()

    # Create a test client using the Flask application configured for testing
    with flask_app.test_client() as testing_client:
        # Establish an application context
        with flask_app.app_context():
            yield testing_client # this is where the testing happens!


@pytest.fixture(scope='function', name='examples_users_db_table')
def create_users_table_in_db_with_test_users_already_added(init_sqlite3_db, init_sqlite3_db_connection,
                                                           return_new_users_correctly):
    ### SET-UP ###
    dao_handler = init_sqlite3_db_connection
    ### STEP 1: create an empty "users" table ###
    dao_handler.create_table(table_name='users')

    ### STEP 2: # add some test users in the "users" table ###
    for index, user in enumerate(return_new_users_correctly):
        # Add a user and retrieve him/her ID
        user_id = dao_handler.add_row_into_table(object=user, table_name='users')
        assert (user_id == index + 1)

    yield

    ### TEAR-DOWN ###
    print('teardown init_users_db_table')
    #@TODO: drop table in the database


@pytest.fixture(scope='module', name='return_new_courses_correctly')
def return_new_courses_correctly():
    new_courses_correct = [Course(name='Programming Languages 1', professor='<NAME>', tutor=None,
                                  academic_year='2018/2019', academic_semester=2, credits_number=10, description=None),
                           Course(name='Linear Algebra 1', professor='<NAME>', tutor='<NAME>',
                                  academic_year='2015/2016', academic_semester=1, credits_number=5, description='Mathematics.'),
                           Course(name='Database 1', professor='<NAME>', tutor='<NAME>',
                                  academic_year='2018/2019', academic_semester=1, credits_number=8, description='SQL.')]

    return new_courses_correct


@pytest.fixture(scope='function', name='examples_courses_db_table')
def create_courses_table_in_db_with_test_courses_already_added(
        init_sqlite3_db, init_sqlite3_db_connection, return_new_courses_correctly):
    ### SET-UP ###
    dao_handler = init_sqlite3_db_connection
    ### STEP 1: create an empty "courses" table ###
    dao_handler.create_table(table_name='courses')

    ### STEP 2: # add some test courses in the "courses" table ###
    for index, course in enumerate(return_new_courses_correctly):
        # Add a user and retrieve him/her ID
        course_id = dao_handler.add_row_into_table(object=course, table_name='courses')
        assert (course_id == index + 1)

    yield

    ### TEAR-DOWN ###
    print('teardown init_courses_db_table')
    #@TODO: drop table in the database
