2024-03-17 19:10:43 +00:00
|
|
|
"""This module contains fixtures and other helpful functions for the tests."""
|
|
|
|
|
2024-02-06 20:18:46 +00:00
|
|
|
import pathlib
|
2024-02-27 19:46:24 +00:00
|
|
|
import copy
|
2024-03-11 19:30:02 +00:00
|
|
|
import typing
|
|
|
|
import itertools
|
2024-03-12 18:02:06 +00:00
|
|
|
import filecmp
|
2024-03-17 19:10:43 +00:00
|
|
|
from typing import Optional
|
|
|
|
import os
|
|
|
|
import shutil
|
2024-02-06 20:18:46 +00:00
|
|
|
|
2024-03-17 19:10:43 +00:00
|
|
|
import pypdf
|
2024-02-09 19:14:46 +00:00
|
|
|
import jinja2
|
2024-02-06 20:18:46 +00:00
|
|
|
import pytest
|
2024-03-11 19:30:02 +00:00
|
|
|
import pydantic
|
|
|
|
import pydantic_extra_types.phone_numbers as pydantic_phone_numbers
|
2024-02-06 20:18:46 +00:00
|
|
|
|
2024-02-09 19:14:46 +00:00
|
|
|
from rendercv import data_models as dm
|
|
|
|
import rendercv.renderer as r
|
|
|
|
|
2024-03-17 19:10:43 +00:00
|
|
|
# RenderCV is being tested by comparing the output to reference files. Therefore,
|
|
|
|
# reference files should be updated when RenderCV is updated in a way that changes
|
|
|
|
# the output. Setting update_testdata to True will update the reference files with
|
|
|
|
# the latest RenderCV. This should be done with caution, as it will overwrite the
|
|
|
|
# reference files with the latest output.
|
2024-04-28 19:19:47 +00:00
|
|
|
update_testdata = False
|
2024-02-23 18:10:25 +00:00
|
|
|
|
2024-04-07 23:44:02 +00:00
|
|
|
# copy sample entries from docs/update_rendercv_files.py:
|
2024-02-27 19:46:24 +00:00
|
|
|
education_entry_dictionary = {
|
2024-02-27 19:05:06 +00:00
|
|
|
"institution": "Boğaziçi University",
|
|
|
|
"location": "Istanbul, Turkey",
|
|
|
|
"degree": "BS",
|
|
|
|
"area": "Mechanical Engineering",
|
|
|
|
"start_date": "2015-09",
|
|
|
|
"end_date": "2020-06",
|
|
|
|
"highlights": [
|
|
|
|
"GPA: 3.24/4.00 ([Transcript](https://example.com))",
|
|
|
|
"Awards: Dean's Honor List, Sportsperson of the Year",
|
|
|
|
],
|
|
|
|
}
|
2024-02-27 17:56:52 +00:00
|
|
|
|
2024-02-27 19:46:24 +00:00
|
|
|
experience_entry_dictionary = {
|
2024-02-27 19:05:06 +00:00
|
|
|
"company": "Some Company",
|
|
|
|
"location": "TX, USA",
|
|
|
|
"position": "Software Engineer",
|
|
|
|
"start_date": "2020-07",
|
|
|
|
"end_date": "2021-08-12",
|
|
|
|
"highlights": [
|
|
|
|
(
|
|
|
|
"Developed an [IOS application](https://example.com) that has received"
|
|
|
|
" more than **100,000 downloads**."
|
|
|
|
),
|
|
|
|
"Managed a team of **5** engineers.",
|
|
|
|
],
|
2024-02-23 18:10:25 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 19:46:24 +00:00
|
|
|
normal_entry_dictionary = {
|
2024-02-27 19:05:06 +00:00
|
|
|
"name": "Some Project",
|
|
|
|
"location": "Remote",
|
|
|
|
"date": "2021-09",
|
|
|
|
"highlights": [
|
|
|
|
"Developed a web application with **React** and **Django**.",
|
|
|
|
"Implemented a **RESTful API**",
|
|
|
|
],
|
|
|
|
}
|
|
|
|
|
2024-02-27 19:46:24 +00:00
|
|
|
publication_entry_dictionary = {
|
2024-02-27 19:05:06 +00:00
|
|
|
"title": (
|
|
|
|
"Magneto-Thermal Thin Shell Approximation for 3D Finite Element Analysis of"
|
|
|
|
" No-Insulation Coils"
|
|
|
|
),
|
2024-03-09 17:04:21 +00:00
|
|
|
"authors": ["J. Doe", "***H. Tom***", "S. Doe", "A. Andsurname"],
|
2024-02-27 19:05:06 +00:00
|
|
|
"date": "2021-12-08",
|
|
|
|
"journal": "IEEE Transactions on Applied Superconductivity",
|
|
|
|
"doi": "10.1109/TASC.2023.3340648",
|
|
|
|
}
|
|
|
|
|
2024-02-27 19:46:24 +00:00
|
|
|
one_line_entry_dictionary = {
|
2024-03-10 17:13:32 +00:00
|
|
|
"label": "Programming",
|
2024-02-27 19:05:06 +00:00
|
|
|
"details": "Python, C++, JavaScript, MATLAB",
|
|
|
|
}
|
|
|
|
|
2024-03-10 18:08:18 +00:00
|
|
|
bullet_entry_dictionary = {
|
2024-04-07 23:44:02 +00:00
|
|
|
"bullet": "This is a bullet entry.",
|
2024-03-10 18:08:18 +00:00
|
|
|
}
|
|
|
|
|
2024-02-07 18:18:49 +00:00
|
|
|
|
2024-02-06 20:18:46 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def publication_entry() -> dict[str, str | list[str]]:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample publication entry."""
|
2024-02-27 19:46:24 +00:00
|
|
|
return copy.deepcopy(publication_entry_dictionary)
|
2024-02-06 20:18:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def experience_entry() -> dict[str, str]:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample experience entry."""
|
2024-02-27 19:46:24 +00:00
|
|
|
return copy.deepcopy(experience_entry_dictionary)
|
2024-02-06 20:18:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def education_entry() -> dict[str, str]:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample education entry."""
|
2024-02-27 19:46:24 +00:00
|
|
|
return copy.deepcopy(education_entry_dictionary)
|
2024-02-06 20:18:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def normal_entry() -> dict[str, str]:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample normal entry."""
|
2024-02-27 19:46:24 +00:00
|
|
|
return copy.deepcopy(normal_entry_dictionary)
|
2024-02-06 20:18:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def one_line_entry() -> dict[str, str]:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample one line entry."""
|
2024-02-27 19:46:24 +00:00
|
|
|
return copy.deepcopy(one_line_entry_dictionary)
|
2024-02-06 20:18:46 +00:00
|
|
|
|
|
|
|
|
2024-03-10 18:08:18 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def bullet_entry() -> dict[str, str]:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample bullet entry."""
|
2024-03-10 18:08:18 +00:00
|
|
|
return copy.deepcopy(bullet_entry_dictionary)
|
|
|
|
|
|
|
|
|
2024-02-06 20:18:46 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def text_entry() -> str:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample text entry."""
|
2024-04-07 23:44:02 +00:00
|
|
|
return (
|
|
|
|
"This is a *TextEntry*. It is only a text and can be useful for sections like"
|
|
|
|
" **Summary**. To showcase the TextEntry completely, this sentence is added,"
|
|
|
|
" but it doesn't contain any information."
|
|
|
|
)
|
2024-03-12 18:02:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def rendercv_data_model() -> dm.RenderCVDataModel:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a sample RenderCV data model."""
|
2024-03-12 18:02:06 +00:00
|
|
|
return dm.get_a_sample_data_model()
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def rendercv_empty_curriculum_vitae_data_model() -> dm.CurriculumVitae:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return an empty CurriculumVitae data model."""
|
2024-03-12 18:02:06 +00:00
|
|
|
return dm.CurriculumVitae(sections={"test": ["test"]})
|
2024-02-06 20:18:46 +00:00
|
|
|
|
|
|
|
|
2024-03-11 19:30:02 +00:00
|
|
|
def return_a_value_for_a_field_type(
|
|
|
|
field: str,
|
|
|
|
field_type: typing.Any,
|
|
|
|
) -> str:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a value for a given field and field type.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
```python
|
|
|
|
return_a_value_for_a_field_type("institution", str)
|
|
|
|
```
|
|
|
|
will return:
|
|
|
|
`#!python "Boğaziçi University"`
|
2024-03-11 19:30:02 +00:00
|
|
|
|
|
|
|
Args:
|
|
|
|
field_type (typing.Any): _description_
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
str: _description_
|
|
|
|
"""
|
|
|
|
field_dictionary = {
|
|
|
|
"institution": "Boğaziçi University",
|
|
|
|
"location": "Istanbul, Turkey",
|
|
|
|
"degree": "BS",
|
|
|
|
"area": "Mechanical Engineering",
|
|
|
|
"start_date": "2015-09",
|
|
|
|
"end_date": "2020-06",
|
|
|
|
"date": "2021-09",
|
|
|
|
"highlights": [
|
2024-04-28 18:59:11 +00:00
|
|
|
(
|
|
|
|
"Did *this* and this is a **bold** [link](https://example.com). But I"
|
|
|
|
" must explain to you how all this mistaken idea of denouncing pleasure"
|
|
|
|
" and praising pain was born and I will give you a complete account of"
|
|
|
|
" the system, and expound the actual teachings of the great explorer of"
|
|
|
|
" the truth, the master-builder of human happiness. No one rejects,"
|
|
|
|
" dislikes, or avoids pleasure itself, because it is pleasure, but"
|
|
|
|
" because those who do not know how to pursue pleasure rationally"
|
|
|
|
" encounter consequences that are extremely painful."
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"Did that. Nor again is there anyone who loves or pursues or desires to"
|
|
|
|
" obtain pain of itself, because it is pain, but because occasionally"
|
|
|
|
" circumstances occur in which toil and pain can procure him some great"
|
|
|
|
" pleasure."
|
|
|
|
),
|
2024-03-11 19:30:02 +00:00
|
|
|
],
|
2024-03-21 18:01:26 +00:00
|
|
|
"company": "Some **Company**",
|
2024-03-11 19:30:02 +00:00
|
|
|
"position": "Software Engineer",
|
|
|
|
"name": "My Project",
|
2024-03-21 18:01:26 +00:00
|
|
|
"label": "Pro**gram**ming",
|
2024-03-11 19:30:02 +00:00
|
|
|
"details": "Python, C++, JavaScript, MATLAB",
|
|
|
|
"authors": ["J. Doe", "**H. Tom**", "S. Doe", "A. Andsurname"],
|
|
|
|
"title": (
|
|
|
|
"Magneto-Thermal Thin Shell Approximation for 3D Finite Element Analysis of"
|
|
|
|
" No-Insulation Coils"
|
|
|
|
),
|
|
|
|
"journal": "IEEE Transactions on Applied Superconductivity",
|
|
|
|
"doi": "10.1109/TASC.2023.3340648",
|
|
|
|
}
|
|
|
|
|
|
|
|
field_type_dictionary = {
|
|
|
|
pydantic.HttpUrl: "https://example.com",
|
|
|
|
pydantic_phone_numbers.PhoneNumber: "+905419999999",
|
|
|
|
str: "A string",
|
|
|
|
list[str]: ["A string", "Another string"],
|
|
|
|
int: 1,
|
|
|
|
float: 1.0,
|
|
|
|
bool: True,
|
|
|
|
}
|
|
|
|
|
2024-04-14 22:57:09 +00:00
|
|
|
if field in field_dictionary:
|
|
|
|
return field_dictionary[field]
|
|
|
|
elif type(None) in typing.get_args(field_type):
|
2024-03-11 19:30:02 +00:00
|
|
|
return return_a_value_for_a_field_type(field, field_type.__args__[0])
|
|
|
|
elif typing.get_origin(field_type) == typing.Literal:
|
|
|
|
return field_type.__args__[0]
|
|
|
|
elif typing.get_origin(field_type) == typing.Union:
|
|
|
|
return return_a_value_for_a_field_type(field, field_type.__args__[0])
|
|
|
|
elif field_type in field_type_dictionary:
|
|
|
|
return field_type_dictionary[field_type]
|
|
|
|
|
|
|
|
return "A string"
|
|
|
|
|
|
|
|
|
|
|
|
def create_combinations_of_a_model(
|
|
|
|
model: pydantic.BaseModel,
|
|
|
|
) -> list[pydantic.BaseModel]:
|
|
|
|
"""Look at the required fields and optional fields of a model and create all
|
|
|
|
possible combinations of them.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
model (pydantic.BaseModel): The data model class to create combinations of.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
list[pydantic.BaseModel]: All possible instances of the model.
|
|
|
|
"""
|
|
|
|
fields = typing.get_type_hints(model)
|
|
|
|
|
|
|
|
required_fields = dict()
|
|
|
|
optional_fields = dict()
|
|
|
|
|
|
|
|
for field, field_type in fields.items():
|
|
|
|
value = return_a_value_for_a_field_type(field, field_type)
|
|
|
|
if type(None) in typing.get_args(field_type): # check if a field is optional
|
|
|
|
optional_fields[field] = value
|
|
|
|
else:
|
|
|
|
required_fields[field] = value
|
|
|
|
|
|
|
|
model_with_only_required_fields = model(**required_fields)
|
|
|
|
|
|
|
|
# create all possible combinations of optional fields
|
|
|
|
all_combinations = [model_with_only_required_fields]
|
|
|
|
for i in range(1, len(optional_fields) + 1):
|
|
|
|
for combination in itertools.combinations(optional_fields, i):
|
|
|
|
kwargs = {k: optional_fields[k] for k in combination}
|
|
|
|
model = copy.deepcopy(model_with_only_required_fields)
|
|
|
|
model.__dict__.update(kwargs)
|
|
|
|
all_combinations.append(model)
|
|
|
|
|
|
|
|
return all_combinations
|
|
|
|
|
|
|
|
|
2024-02-18 16:19:59 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def rendercv_filled_curriculum_vitae_data_model(
|
2024-03-12 17:26:52 +00:00
|
|
|
text_entry, bullet_entry
|
2024-02-18 16:19:59 +00:00
|
|
|
) -> dm.CurriculumVitae:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a filled CurriculumVitae data model, where each section has all possible
|
|
|
|
combinations of entry types.
|
|
|
|
"""
|
2024-02-18 16:19:59 +00:00
|
|
|
return dm.CurriculumVitae(
|
|
|
|
name="John Doe",
|
|
|
|
label="Mechanical Engineer",
|
|
|
|
location="Istanbul, Turkey",
|
2024-05-12 13:45:14 +00:00
|
|
|
email="john_doe@example.com",
|
2024-02-18 16:19:59 +00:00
|
|
|
phone="+905419999999", # type: ignore
|
|
|
|
website="https://example.com", # type: ignore
|
|
|
|
social_networks=[
|
|
|
|
dm.SocialNetwork(network="LinkedIn", username="johndoe"),
|
|
|
|
dm.SocialNetwork(network="GitHub", username="johndoe"),
|
|
|
|
dm.SocialNetwork(network="Instagram", username="johndoe"),
|
|
|
|
dm.SocialNetwork(network="Orcid", username="0000-0000-0000-0000"),
|
|
|
|
dm.SocialNetwork(network="Mastodon", username="@johndoe@example"),
|
|
|
|
dm.SocialNetwork(network="Twitter", username="johndoe"),
|
|
|
|
],
|
|
|
|
sections={
|
2024-03-12 17:26:52 +00:00
|
|
|
"Text Entries": [text_entry, text_entry, text_entry],
|
|
|
|
"Bullet Entries": [bullet_entry, bullet_entry],
|
|
|
|
"Publication Entries": create_combinations_of_a_model(dm.PublicationEntry),
|
|
|
|
"Experience Entries": create_combinations_of_a_model(dm.ExperienceEntry),
|
|
|
|
"Education Entries": create_combinations_of_a_model(dm.EducationEntry),
|
|
|
|
"Normal Entries": create_combinations_of_a_model(dm.NormalEntry),
|
|
|
|
"One Line Entries": create_combinations_of_a_model(dm.OneLineEntry),
|
2024-02-18 16:19:59 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-02-09 19:14:46 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def jinja2_environment() -> jinja2.Environment:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return a Jinja2 environment."""
|
2024-02-09 19:14:46 +00:00
|
|
|
return r.setup_jinja2_environment()
|
|
|
|
|
|
|
|
|
2024-02-06 20:18:46 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def tests_directory_path() -> pathlib.Path:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return the path to the tests directory."""
|
2024-02-06 20:18:46 +00:00
|
|
|
return pathlib.Path(__file__).parent
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def root_directory_path(tests_directory_path) -> pathlib.Path:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return the path to the repository's root directory."""
|
2024-02-06 20:18:46 +00:00
|
|
|
return tests_directory_path.parent
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2024-03-12 17:19:14 +00:00
|
|
|
def testdata_directory_path(tests_directory_path) -> pathlib.Path:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return the path to the testdata directory."""
|
2024-03-12 17:19:14 +00:00
|
|
|
return tests_directory_path / "testdata"
|
2024-02-07 18:18:49 +00:00
|
|
|
|
|
|
|
|
2024-03-12 18:02:06 +00:00
|
|
|
@pytest.fixture
|
2024-03-17 19:10:43 +00:00
|
|
|
def specific_testdata_directory_path(testdata_directory_path, request) -> pathlib.Path:
|
|
|
|
"""Return the path to a specific testdata directory.
|
|
|
|
|
|
|
|
For example, if the test function is named `test_rendercv`, this will return the
|
|
|
|
path to the `testdata/test_rendercv` directory.
|
|
|
|
"""
|
|
|
|
return testdata_directory_path / request.node.originalname
|
|
|
|
|
|
|
|
|
|
|
|
def are_these_two_directories_the_same(
|
|
|
|
directory1: pathlib.Path, directory2: pathlib.Path
|
|
|
|
) -> None:
|
|
|
|
"""Check if two directories are the same.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
directory1 (pathlib.Path): The first directory to compare.
|
|
|
|
directory2 (pathlib.Path): The second directory to compare.
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
AssertionError: If the two directories are not the same.
|
|
|
|
"""
|
|
|
|
for file1 in directory1.iterdir():
|
2024-03-31 19:48:54 +00:00
|
|
|
if file1.name == "__pycache__":
|
|
|
|
continue
|
|
|
|
|
2024-03-17 19:10:43 +00:00
|
|
|
file2 = directory2 / file1.name
|
|
|
|
if file1.is_dir():
|
|
|
|
if not file2.is_dir():
|
|
|
|
return False
|
|
|
|
are_these_two_directories_the_same(file1, file2)
|
|
|
|
else:
|
|
|
|
if are_these_two_files_the_same(file1, file2) is False:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def are_these_two_files_the_same(file1: pathlib.Path, file2: pathlib.Path) -> None:
|
|
|
|
"""Check if two files are the same.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
file1 (pathlib.Path): The first file to compare.
|
|
|
|
file2 (pathlib.Path): The second file to compare.
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
AssertionError: If the two files are not the same.
|
|
|
|
"""
|
|
|
|
extension1 = file1.suffix
|
|
|
|
extension2 = file2.suffix
|
|
|
|
|
|
|
|
if extension1 != extension2:
|
|
|
|
return False
|
|
|
|
|
|
|
|
if extension1 == ".pdf":
|
|
|
|
pages1 = pypdf.PdfReader(file1).pages
|
|
|
|
pages2 = pypdf.PdfReader(file2).pages
|
|
|
|
if len(pages1) != len(pages2):
|
|
|
|
return False
|
|
|
|
|
|
|
|
for i in range(len(pages1)):
|
|
|
|
if pages1[i].extract_text() != pages2[i].extract_text():
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return filecmp.cmp(file1, file2)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def run_a_function_and_check_if_output_is_the_same_as_reference(
|
2024-03-12 18:02:06 +00:00
|
|
|
tmp_path: pathlib.Path,
|
2024-03-17 19:10:43 +00:00
|
|
|
specific_testdata_directory_path: pathlib.Path,
|
2024-03-12 18:02:06 +00:00
|
|
|
) -> typing.Callable:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Run a function and check if the output is the same as the reference."""
|
|
|
|
|
2024-03-12 18:02:06 +00:00
|
|
|
def function(
|
|
|
|
function: typing.Callable,
|
2024-03-17 19:10:43 +00:00
|
|
|
reference_file_or_directory_name: str,
|
|
|
|
output_file_name: Optional[str] = None,
|
|
|
|
generate_reference_files_function: Optional[typing.Callable] = None,
|
2024-03-12 18:02:06 +00:00
|
|
|
**kwargs,
|
|
|
|
):
|
2024-03-17 19:10:43 +00:00
|
|
|
output_is_a_single_file = output_file_name is not None
|
|
|
|
if output_is_a_single_file:
|
|
|
|
output_file_path = tmp_path / output_file_name
|
2024-03-12 18:02:06 +00:00
|
|
|
|
2024-03-17 19:10:43 +00:00
|
|
|
reference_directory_path: pathlib.Path = specific_testdata_directory_path
|
|
|
|
reference_file_or_directory_path = (
|
|
|
|
reference_directory_path / reference_file_or_directory_name
|
|
|
|
)
|
2024-03-12 18:02:06 +00:00
|
|
|
|
2024-03-17 19:10:43 +00:00
|
|
|
# Update the testdata if update_testdata is True
|
2024-03-12 18:02:06 +00:00
|
|
|
if update_testdata:
|
|
|
|
# create the reference directory if it does not exist
|
|
|
|
reference_directory_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
2024-03-17 19:10:43 +00:00
|
|
|
# remove the reference file or directory if it exists
|
|
|
|
if reference_file_or_directory_path.is_dir():
|
|
|
|
shutil.rmtree(reference_file_or_directory_path)
|
|
|
|
elif reference_file_or_directory_path.exists():
|
|
|
|
reference_file_or_directory_path.unlink()
|
|
|
|
|
|
|
|
if generate_reference_files_function:
|
|
|
|
generate_reference_files_function(
|
|
|
|
reference_file_or_directory_path, **kwargs
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
# copy the output file or directory to the reference directory
|
|
|
|
function(tmp_path, reference_file_or_directory_path, **kwargs)
|
|
|
|
if output_is_a_single_file:
|
|
|
|
shutil.move(output_file_path, reference_file_or_directory_path)
|
|
|
|
else:
|
|
|
|
shutil.move(tmp_path, reference_file_or_directory_path)
|
|
|
|
os.mkdir(tmp_path)
|
|
|
|
|
|
|
|
function(tmp_path, reference_file_or_directory_path, **kwargs)
|
|
|
|
|
|
|
|
if output_is_a_single_file:
|
|
|
|
return are_these_two_files_the_same(
|
|
|
|
output_file_path, reference_file_or_directory_path
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return are_these_two_directories_the_same(
|
|
|
|
tmp_path, reference_file_or_directory_path
|
|
|
|
)
|
2024-03-12 18:02:06 +00:00
|
|
|
|
|
|
|
return function
|
|
|
|
|
|
|
|
|
2024-02-07 18:18:49 +00:00
|
|
|
@pytest.fixture
|
2024-03-12 17:19:14 +00:00
|
|
|
def input_file_path(testdata_directory_path) -> pathlib.Path:
|
2024-03-17 19:10:43 +00:00
|
|
|
"""Return the path to the input file."""
|
2024-03-12 17:19:14 +00:00
|
|
|
return testdata_directory_path / "John_Doe_CV.yaml"
|