Merge branch 'main' into feature/additional-stammdaten

This commit is contained in:
TrisNol
2023-09-23 10:32:09 +02:00
36 changed files with 3086 additions and 725 deletions

View File

@@ -18,7 +18,8 @@ def test_import_enrich_company_financials() -> None:
@patch(
"aki_prj23_transparenzregister.apps.enrich_company_financials.CompanyMongoService"
)
def test_work(mock_compnay_service: Mock, mock_bundesanzeiger: Mock) -> None:
def test_work(mock_company_service: Mock, mock_bundesanzeiger: Mock) -> None:
"""Tests the readout of the company financials."""
mock_bundesanzeiger.return_value = pd.DataFrame(
[
{
@@ -28,9 +29,8 @@ def test_work(mock_compnay_service: Mock, mock_bundesanzeiger: Mock) -> None:
}
]
)
# mock_compnay_service.add_yearly_resreturn_value
enrich_company_financials.work(
{"_id": "", "name": "ABC AG", "location": {"city": "Haltern am See"}},
mock_compnay_service,
mock_company_service,
)
assert enrich_company_financials

View File

@@ -1,3 +1,4 @@
"""Tests the config provers."""
import json
from unittest.mock import mock_open, patch
@@ -10,11 +11,13 @@ from aki_prj23_transparenzregister.config.config_providers import (
def test_json_provider_init_fail() -> None:
"""Tests the file not found error if an unknown filepath is given for the JsonFileConfigProvider."""
with pytest.raises(FileNotFoundError):
JsonFileConfigProvider("file-that-does-not-exist")
def test_json_provider_init_no_json() -> None:
"""Tests if a non json file throws the correct error."""
with patch("os.path.isfile") as mock_isfile, patch(
"builtins.open", mock_open(read_data="fhdaofhdoas")
):
@@ -24,6 +27,7 @@ def test_json_provider_init_no_json() -> None:
def test_json_provider_init() -> None:
"""Tests the JsonFileConfigProvider creation."""
data = {"hello": "world"}
input_data = json.dumps(data)
with patch("os.path.isfile") as mock_isfile:
@@ -34,6 +38,7 @@ def test_json_provider_init() -> None:
def test_json_provider_get_postgres() -> None:
"""Tests if the config provider can return the postgre config string."""
data = {
"postgres": {
"username": "user",
@@ -56,6 +61,7 @@ def test_json_provider_get_postgres() -> None:
def test_json_provider_get_mongo() -> None:
"""Tests the JsonConfigProvider for the mongo db."""
data = {
"mongo": {
"username": "user",

178
tests/conftest.py Normal file
View File

@@ -0,0 +1,178 @@
"""Global configurations and definitions for pytest."""
import datetime
import os
from collections.abc import Generator
from inspect import getmembers, isfunction
from typing import Any
import pytest
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session
from aki_prj23_transparenzregister.utils import data_transfer
from aki_prj23_transparenzregister.utils.sql import entities
from aki_prj23_transparenzregister.utils.sql.connector import get_session, init_db
@pytest.fixture(autouse=True)
def _clear_caches() -> Generator[None, None, None]:
"""A function that clears all caches after each test.
All the modules containing the cached functions need to be listed in the modules tuple.
"""
yield
# https://stackoverflow.com/a/139198/11003343
modules = (data_transfer,)
functions = [
function
for module in modules
for name, function in getmembers(module, isfunction)
if function.__dict__.get("cache") is not None
]
# https://cachetools.readthedocs.io/en/stable/?highlight=clear#memoizing-decorators
for function in functions:
function.cache.clear() # type: ignore
@pytest.fixture()
def empty_db() -> Generator[Session, None, None]:
"""Generates a db Session to a sql_lite db."""
if os.path.exists("test-db.db"):
os.remove("test-db.db")
db = get_session("sqlite:///test-db.db")
init_db(db)
yield db
db.close()
bind = db.bind
assert isinstance(bind, Engine)
bind.dispose()
os.remove("test-db.db")
@pytest.fixture()
def finance_statements() -> list[dict[str, Any]]:
"""Creates a list of finance statements."""
return [
{
"id": 1,
"company_id": 1,
"date": datetime.date.fromisoformat("2023-01-01"),
"total_volume": 1000.0,
"ebit": 1000.0,
"ebitda": 1000.0,
"ebit_margin": 1000.0,
"total_balance": 1000.0,
"equity": 1000.0,
"debt": 1000.0,
"return_on_equity": 1000.0,
"capital_turnover_rate": 1000.0,
"current_liabilities": 1000.0,
"dividends": float("NaN"),
"net_income": float("NaN"),
"assets": 1000.0,
"long_term_debt": 1000.0,
"short_term_debt": 1000.0,
"revenue": 1000.0,
"cash_flow": 1000.0,
"current_assets": 1000.0,
},
{
"id": 2,
"company_id": 1,
"date": datetime.date.fromisoformat("2022-01-01"),
"total_volume": 1100.0,
"ebit": 1100.0,
"ebitda": 1100.0,
"ebit_margin": 1100.0,
"total_balance": 1100.0,
"equity": 1100.0,
"debt": 1100.0,
"return_on_equity": 1100.0,
"capital_turnover_rate": 1100.0,
"current_liabilities": 1100.0,
"dividends": float("NaN"),
"net_income": float("NaN"),
"assets": 1100.0,
"long_term_debt": 1100.0,
"short_term_debt": 1100.0,
"revenue": 1100.0,
"cash_flow": 1100.0,
"current_assets": 1100.0,
},
]
@pytest.fixture()
def full_db(empty_db: Session, finance_statements: list[dict[str, Any]]) -> Session:
"""Fills a db with some test data."""
empty_db.add_all(
[
entities.DistrictCourt(name="Amtsgericht Bochum", city="Bochum"),
entities.DistrictCourt(name="Amtsgericht Dortmund", city="Dortmund"),
entities.Person(
name="Max",
surname="Mustermann",
date_of_birth=datetime.date(2023, 1, 1),
),
entities.Person(
name="Sabine",
surname="Mustermann",
date_of_birth=datetime.date(2023, 1, 1),
),
entities.Person(
name="Some Firstname",
surname="Some Surname",
date_of_birth=datetime.date(2023, 1, 1),
),
entities.Person(
name="Some Firstname",
surname="Some Surname",
date_of_birth=datetime.date(2023, 1, 2),
),
entities.Person(
name="Other Firstname",
surname="Other Surname",
date_of_birth=datetime.date(2023, 1, 2),
),
]
)
empty_db.commit()
empty_db.add_all(
[
entities.Company(
hr="HRB 123",
court_id=2,
name="Some Company GmbH",
street="Sesamstr.",
zip_code="12345",
city="TV City",
last_update=datetime.date.fromisoformat("2023-01-01"),
),
entities.Company(
hr="HRB 123",
court_id=1,
name="Other Company GmbH",
street="Sesamstr.",
zip_code="12345",
city="TV City",
last_update=datetime.date.fromisoformat("2023-01-01"),
),
entities.Company(
hr="HRB 12",
court_id=2,
name="Third Company GmbH",
last_update=datetime.date.fromisoformat("2023-01-01"),
),
]
)
empty_db.commit()
empty_db.add_all(
[
entities.AnnualFinanceStatement(**finance_statement)
for finance_statement in finance_statements
]
)
empty_db.commit()
# print(pd.read_sql_table("company", empty_db.bind).to_string())
return empty_db

View File

@@ -0,0 +1,118 @@
"""Tests for ui elements."""
import pandas as pd
from sqlalchemy.orm import Session
from aki_prj23_transparenzregister.ui import ui_elements
def test_import() -> None:
"""Checks if an import co ui_elements can be made."""
assert ui_elements is not None
def test_get_company_data(full_db: Session) -> None:
"""Checks if data from the company and district court tables can be accessed."""
company_df = ui_elements.get_company_data(full_db)
test_data = pd.DataFrame(
{
"company_id": {0: 1, 1: 2, 2: 3},
"company_hr": {0: "HRB 123", 1: "HRB 123", 2: "HRB 12"},
"company_court_id": {0: 2, 1: 1, 2: 2},
"company_name": {
0: "Some Company GmbH",
1: "Other Company GmbH",
2: "Third Company GmbH",
},
"company_street": {0: "Sesamstr.", 1: "Sesamstr.", 2: None},
"company_zip_code": {0: "12345", 1: "12345", 2: None},
"company_city": {0: "TV City", 1: "TV City", 2: None},
"company_last_update": {
0: "2023-01-01",
1: "2023-01-01",
2: "2023-01-01",
},
"company_sector": {0: None, 1: None, 2: None},
"district_court_name": {
0: "Amtsgericht Dortmund",
1: "Amtsgericht Bochum",
2: "Amtsgericht Dortmund",
},
}
)
test_data = test_data.set_index("company_id")
pd.testing.assert_frame_equal(company_df, test_data)
def test_get_finance_data(full_db: Session) -> None:
"""Checks if data from the company and finance tables can be accessed."""
finance_df = ui_elements.get_finance_data(full_db)
test_data = pd.DataFrame(
{
"annual_finance_statement_id": {0: 1, 1: 2},
"annual_finance_statement_company_id": {0: 1, 1: 1},
"annual_finance_statement_date": {0: "2023-01-01", 1: "2022-01-01"},
"annual_finance_statement_total_volume": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_ebit": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_ebitda": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_ebit_margin": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_total_balance": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_equity": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_debt": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_return_on_equity": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_capital_turnover_rate": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_current_liabilities": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_dividends": {0: None, 1: None},
"annual_finance_statement_net_income": {0: None, 1: None},
"annual_finance_statement_assets": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_long_term_debt": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_short_term_debt": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_revenue": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_cash_flow": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_current_assets": {0: 1000.0, 1: 1100.0},
"company_name": {0: "Some Company GmbH", 1: "Some Company GmbH"},
"company_id": {0: 1, 1: 1},
}
)
pd.testing.assert_frame_equal(finance_df, test_data)
def test_create_header() -> None:
"""Checks if the header can be created."""
options = {1: "a", 2: "b"}
ui_elements.create_header(options)
def test_create_company_header() -> None:
"""Checks if the company header can be created."""
selected_company = "Test GmbH"
ui_elements.create_company_header(selected_company)
def test_create_company_stats(full_db: Session) -> None:
"""Checks if the company widgets can be created."""
company_df = ui_elements.get_company_data(full_db)
value_chosen = 1
selected_company_stats = company_df.loc[value_chosen]
ui_elements.create_company_stats(selected_company_stats)
def test_create_tabs(full_db: Session) -> None:
"""Checks if the tabs of the company page can be created."""
selected_company_id = 1
finance_df = ui_elements.get_finance_data(full_db)
selected_finance_df = finance_df.loc[
finance_df["company_id"] == selected_company_id
]
ui_elements.create_tabs(selected_finance_df)
def test_kennzahlen_layout(full_db: Session) -> None:
"""Checks if the financial metric layout of the company page can be created."""
selected_company_id = 1
finance_df = ui_elements.get_finance_data(full_db)
selected_finance_df = finance_df.loc[
finance_df["company_id"] == selected_company_id
]
ui_elements.kennzahlen_layout(selected_finance_df)

View File

@@ -1,3 +1,4 @@
"""Tests if the bundesanzeiger can be accessed and read."""
from unittest.mock import Mock, patch
import pandas as pd

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
"""Tests for the enumeration types."""
import pytest
from aki_prj23_transparenzregister.utils import enum_types
def test_import() -> None:
"""Tests if enum_types can be imported."""
assert enum_types
@pytest.mark.parametrize("relation_name", ["Vorstand", "Prokurist", "Direktor"])
@pytest.mark.parametrize("changes", ["lower", "upper", None])
def test_relation_type_enum_from_string(
relation_name: str, changes: str | None
) -> None:
"""Tests the transformation of a name to an enumeration type."""
if changes == "lower":
relation_name = relation_name.lower()
elif changes == "upper":
relation_name = relation_name.upper()
assert isinstance(
enum_types.RelationTypeEnum.get_enum_from_name(relation_name),
enum_types.RelationTypeEnum,
)
@pytest.mark.parametrize("relation_name", ["does Not Exists", "Also not"])
@pytest.mark.parametrize("changes", ["lower", "upper", None])
def test_relation_type_enum_from_string_wrong(
relation_name: str, changes: str | None
) -> None:
"""Tests the transformation of a name to an enumeration type if no equivalent can be found."""
if changes == "lower":
relation_name = relation_name.lower()
elif changes == "upper":
relation_name = relation_name.upper()
with pytest.raises(ValueError, match='Relation type ".*" is not yet implemented!'):
enum_types.RelationTypeEnum.get_enum_from_name(relation_name)

View File

@@ -1,3 +1,4 @@
"""Tests for connecting to the mongodb."""
from unittest.mock import patch
from aki_prj23_transparenzregister.utils.mongo.connector import (
@@ -7,21 +8,25 @@ from aki_prj23_transparenzregister.utils.mongo.connector import (
def test_get_conn_string_no_credentials() -> None:
"""Tests the mongo connection string generation."""
conn = MongoConnection("localhost", "", 27017, None, None)
assert conn.get_conn_string() == "mongodb://localhost:27017"
def test_get_conn_string_no_port_but_credentials() -> None:
"""Tests the mongo connection string generation."""
conn = MongoConnection("localhost", "", None, "admin", "password")
assert conn.get_conn_string() == "mongodb+srv://admin:password@localhost"
def test_get_conn_simple() -> None:
"""Tests the mongo connection string generation."""
conn = MongoConnection("localhost", "", None, None, None)
assert conn.get_conn_string() == "mongodb+srv://localhost"
def test_mongo_connector() -> None:
"""Tests the MongoConnector."""
with patch("pymongo.MongoClient") as mock_mongo_client:
expected_result = 42
mock_mongo_client.return_value = {"db": expected_result}

View File

@@ -1,3 +1,4 @@
"""Tests for the mongo news service."""
from unittest.mock import Mock, patch
import pytest
@@ -50,6 +51,7 @@ def test_init(mock_mongo_connector: Mock, mock_collection: Mock) -> None:
def test_get_all(mock_mongo_connector: Mock, mock_collection: Mock) -> None:
"""Tests the get_all function from the mongo connector."""
mock_mongo_connector.database = {"news": mock_collection}
service = MongoNewsService(mock_mongo_connector)
@@ -60,6 +62,7 @@ def test_get_all(mock_mongo_connector: Mock, mock_collection: Mock) -> None:
def test_get_by_id_with_result(
mock_mongo_connector: Mock, mock_collection: Mock
) -> None:
"""Tests the get_by_id_with_result function from the mongo connector."""
mock_mongo_connector.database = {"news": mock_collection}
service = MongoNewsService(mock_mongo_connector)
@@ -72,6 +75,7 @@ def test_get_by_id_with_result(
def test_get_by_id_no_result(mock_mongo_connector: Mock, mock_collection: Mock) -> None:
"""Test if the mongo connector can get an object by id."""
mock_mongo_connector.database = {"news": mock_collection}
service = MongoNewsService(mock_mongo_connector)
@@ -80,6 +84,7 @@ def test_get_by_id_no_result(mock_mongo_connector: Mock, mock_collection: Mock)
def test_insert(mock_mongo_connector: Mock, mock_collection: Mock) -> None:
"""Tests the insert function from the mongo connector."""
mock_mongo_connector.database = {"news": mock_collection}
service = MongoNewsService(mock_mongo_connector)
@@ -92,6 +97,7 @@ def test_insert(mock_mongo_connector: Mock, mock_collection: Mock) -> None:
def test_transform_ingoing() -> None:
"""Tests the transform_ingoing function from the mongo connector."""
news = News("42", None, None, None, None) # type: ignore
result = MongoEntryTransformer.transform_ingoing(news)
assert result["_id"] == "42"
@@ -99,6 +105,7 @@ def test_transform_ingoing() -> None:
def test_transform_outgoing() -> None:
"""Tests the transform_outgoing function from the mongo connector."""
data = {
"_id": "4711",
"title": "Hello",

View File

@@ -1,21 +1,27 @@
"""Tests the sql connector."""
import os.path
from collections.abc import Generator
from typing import Any
from unittest.mock import Mock, patch
import pandas as pd
import pytest
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session
from aki_prj23_transparenzregister.config.config_providers import JsonFileConfigProvider
from aki_prj23_transparenzregister.config.config_template import PostgreConnectionString
from aki_prj23_transparenzregister.utils.sql.connector import (
Base,
get_pg_engine,
get_session,
init_db,
transfer_db,
)
def test_get_engine_pg() -> None:
"""Tests the creation of a postgre engine."""
conn_args = PostgreConnectionString("", "", "", "", 42)
with patch(
"aki_prj23_transparenzregister.utils.sql.connector.sa.create_engine"
@@ -25,6 +31,36 @@ def test_get_engine_pg() -> None:
assert get_pg_engine(conn_args) == result
@pytest.fixture()
def destination_db() -> Generator[Session, None, None]:
"""Generates a db Session to a sqlite db to copy data to."""
if os.path.exists("secondary.db"):
os.remove("secondary.db")
db = get_session("sqlite:///secondary.db")
init_db(db)
yield db
db.close()
bind = db.bind
assert isinstance(bind, Engine)
bind.dispose()
os.remove("secondary.db")
def test_transfer_db(full_db: Session, destination_db: Session) -> None:
"""Tests if the data transfer between two sql tables works."""
transfer_db(source=full_db, destination=destination_db)
sbind = full_db.bind
dbind = destination_db.bind
assert isinstance(sbind, Engine)
assert isinstance(dbind, Engine)
for table in Base.metadata.sorted_tables:
pd.testing.assert_frame_equal(
pd.read_sql_table(str(table), dbind),
pd.read_sql_table(str(table), sbind),
)
@pytest.fixture()
def delete_sqlite_table() -> Generator[str, None, None]:
"""Cleans a path before and deletes the table after a test.

View File

@@ -1,4 +1,8 @@
def test_import() -> None:
from aki_prj23_transparenzregister.utils.sql import entities
"""Tests for the sql entities."""
from aki_prj23_transparenzregister.utils.sql import entities
def test_import() -> None: #
"""Tests if the entities can be imported."""
assert entities

View File

@@ -0,0 +1,35 @@
"""Tests for the string tool module."""
from typing import Any
import pytest
from aki_prj23_transparenzregister.utils import string_tools
def test_import() -> None:
"""Tests if the import is possible."""
assert string_tools
@pytest.mark.parametrize(
("value", "expected"),
[
("None ", "None"),
(" ", None),
("", None),
("\t", None),
("\n", None),
(" Some String ", "Some String"),
("Some String", "Some String"),
],
)
def test_simplify_string(value: str | None, expected: str | None) -> None:
"""Tests the sting simplification."""
assert string_tools.simplify_string(value) == expected
@pytest.mark.parametrize("value", [0, 0.1, True, ("1",), {}, set()])
def test_simplify_string_type_error(value: Any) -> None:
"""Tests if the type error is thrown when the value is the wrong type."""
with pytest.raises(TypeError):
assert string_tools.simplify_string(value)