From 01b15786a8ae02d364ff79011473bde90eb42e76 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sun, 4 Aug 2019 11:54:08 +0200 Subject: Add some tests --- resumejson_converter/example/resume.json | 95 ++++++++++ resumejson_converter/example/template.html | 266 ++++++++++++++++++++++++++++ resumejson_converter/generators/html.py | 28 +-- resumejson_converter/generators/pdf.py | 10 +- resumejson_converter/utils/json.py | 25 ++- tests/filters/test_birthday.py | 17 ++ tests/filters/test_clean.py | 12 ++ tests/filters/test_datediff.py | 84 +++++++++ tests/filters/test_dateedit.py | 30 ++++ tests/generators/html/test_generate_html.py | 72 ++++++++ tests/generators/pdf/test_generate_pdf.py | 55 ++++++ tests/utils/json/test_load.py | 52 ++++++ tests/utils/templates/test_templates.py | 33 ++++ 13 files changed, 753 insertions(+), 26 deletions(-) create mode 100644 resumejson_converter/example/resume.json create mode 100644 resumejson_converter/example/template.html create mode 100644 tests/filters/test_birthday.py create mode 100644 tests/filters/test_clean.py create mode 100644 tests/filters/test_datediff.py create mode 100644 tests/filters/test_dateedit.py create mode 100644 tests/generators/html/test_generate_html.py create mode 100644 tests/generators/pdf/test_generate_pdf.py create mode 100644 tests/utils/json/test_load.py create mode 100644 tests/utils/templates/test_templates.py diff --git a/resumejson_converter/example/resume.json b/resumejson_converter/example/resume.json new file mode 100644 index 0000000..91d713e --- /dev/null +++ b/resumejson_converter/example/resume.json @@ -0,0 +1,95 @@ +{ + + "basics": { + "name": "John Doe", + "label": "Programmer", + "picture": "", + "email": "john@gmail.com", + "phone": "(912) 555-4321", + "website": "http://johndoe.com", + "summary": "A summary of John Doe...", + "location": { + "address": "2712 Broadway St", + "postalCode": "CA 94115", + "city": "San Francisco", + "countryCode": "US", + "region": "California" + }, + "profiles": [{ + "network": "Twitter", + "username": "john", + "url": "http://twitter.com/john" + }] + }, + "work": [{ + "company": "Company", + "position": "President", + "website": "http://company.com", + "startDate": "2013-01-01", + "endDate": "2014-01-01", + "summary": "Description...", + "highlights": [ + "Started the company" + ] + }], + "volunteer": [{ + "organization": "Organization", + "position": "Volunteer", + "website": "http://organization.com/", + "startDate": "2012-01-01", + "endDate": "2013-01-01", + "summary": "Description...", + "highlights": [ + "Awarded 'Volunteer of the Month'" + ] + }], + "education": [{ + "institution": "University", + "area": "Software Development", + "studyType": "Bachelor", + "startDate": "2011-01-01", + "endDate": "2013-01-01", + "gpa": "4.0", + "courses": [ + "DB1101 - Basic SQL" + ] + }], + "awards": [{ + "title": "Award", + "date": "2014-11-01", + "awarder": "Company", + "summary": "There is no spoon." + }], + "publications": [{ + "name": "Publication", + "publisher": "Company", + "releaseDate": "2014-10-01", + "website": "http://publication.com", + "summary": "Description..." + }], + "skills": [{ + "name": "Web Development", + "level": "Master", + "keywords": [ + "HTML", + "CSS", + "Javascript" + ] + }], + "languages": [{ + "language": "English", + "fluency": "Native speaker" + }], + "interests": [{ + "name": "Wildlife", + "keywords": [ + "Ferrets", + "Unicorns" + ] + }], + "references": [{ + "name": "Jane Doe", + "reference": "Reference..." + }] + +} diff --git a/resumejson_converter/example/template.html b/resumejson_converter/example/template.html new file mode 100644 index 0000000..d57be01 --- /dev/null +++ b/resumejson_converter/example/template.html @@ -0,0 +1,266 @@ + + + + Neodarz's CV + + + + + +
+
+
+
+
{{ resume.basics.name }}
+
{{ resume.basics.label }}
+
+
+
{{ resume.basics.birthdate }}
+
+ {{ resume.basics.location.address }}
+ {{ resume.basics.location.postalCode }} {{ resume.basics.location.city }} +
+
{{ resume.basics.phone|clean }}
+
{{ resume.basics.website }}
+
{{ resume.basics.git }}
+
{{ resume.basics.email }}
+
+
+ A propos +
+

{{ resume.basics.summary }}

+
+
+

{{ resume.basics.title }}

+

Expériences

+ {% for work in resume.work %} +
+
+
{{ work.startDate }}
+
{{ work.company|datediff(work.startDate, work.endDate) }}
+
{{ work.location }}
+
+
+

{{ work.summary }}

+
    + {% for highlight in work.highlights %} +
  • {{ highlight }}
  • + {% endfor %} +
+
+
+ {% endfor %} +

Formations

+ {% for education in resume.education %} +
+
+
{{ education.startDate }}
+
{{ education.studyType}} - {{ education.area }} - {{ education.institution }}
+
{{ education.location }}
+
+
+
    + {% for course in education.courses %} +
  • {{ course }}
  • + {% endfor %} +
+
+
+ {% endfor %} +

Compétences

+ + {% for skill in resume.skills %} + + + + + {% endfor %} +
{{ skill.name }} + {% for keyword in skill.keywords %} + {{ keyword }} + {% if not loop.last %}/{% endif %} + {% endfor %} +
+

Volontériat

+ {% for volunteer in resume.volunteer %} +
+
+
{{ volunteer.startDate }}
+
{{ volunteer.organization }}
+
+
+

{{ volunteer.summary }}

+
    + {% for highlight in volunteer.highlights %} +
  • {{ highlight }}
  • + {% endfor %} +
+
+
+ {% endfor %} +

Intérets

+ + {% for interest in resume.interests %} + + + {% for keyword in interest.keywords %} + + {% endfor %} + + {% endfor %} +
{{ interest.name }}{{ keyword }}
+
+
+ + + diff --git a/resumejson_converter/generators/html.py b/resumejson_converter/generators/html.py index 1b34e91..b1d2802 100644 --- a/resumejson_converter/generators/html.py +++ b/resumejson_converter/generators/html.py @@ -1,14 +1,14 @@ import os.path as path -import sys import codecs import logging import jinja2 +from jinja2.exceptions import TemplateSyntaxError import resumejson_converter.filters as filters -def generate(resume, template, out_path): +def generate(resume, template, out_path=None): """ Return html version of a JSON resume based on a template. @@ -32,18 +32,22 @@ def generate(resume, template, out_path): try: template = env.get_template(template_name) except jinja2.exceptions.TemplateNotFound: - logging.exception("File not found: '{}'!" - .format(template)) - sys.exit(1) + logging.error("File not found: '{}'!" + .format(template)) + raise html = template.render(dict(resume=resume)) - except jinja2.exceptions.TemplateSyntaxError as e: - logging.exception("Syntax error in template file '{}' line {}: {}" - .format(e.name, e.lineno, e.message)) - sys.exit(1) + except TemplateSyntaxError as e: + logging.error("Syntax error in template file '{}' line {}: {}" + .format(e.name, e.lineno, e.message)) + raise else: logging.info("HTML generation done.") if out_path: - file = codecs.open(out_path, "w", "utf-8-sig") - file.write(html) - file.close + try: + file = codecs.open(out_path, "w", "utf-8-sig") + file.write(html) + file.close + except IOError: + logging.error("Permission error when writing html file!") + raise return html diff --git a/resumejson_converter/generators/pdf.py b/resumejson_converter/generators/pdf.py index b8c2905..ed772a8 100644 --- a/resumejson_converter/generators/pdf.py +++ b/resumejson_converter/generators/pdf.py @@ -1,18 +1,17 @@ -import sys import logging import pdfkit -def generate(html): +def generate(html, pdf_output_path="out/out.pdf"): """ Generate a pdf file in out/out.pdf in current folder where main script is executed. + + Use pdf_out_path to select final pdf generated destination. """ logging.info("PDF generation...") - pdf_output_path = "out/out.pdf" - import os if not os.path.exists("out"): os.makedirs("out", exist_ok=True) @@ -34,6 +33,7 @@ def generate(html): configuration=config, options=options) except (IOError, OSError) as e: - logging.exception("Something append: {}".format(e)) + logging.error("Something append: {}".format(e)) + raise else: logging.info("PDF generated at {}".format(pdf_output_path)) diff --git a/resumejson_converter/utils/json.py b/resumejson_converter/utils/json.py index 77e1312..fb44899 100644 --- a/resumejson_converter/utils/json.py +++ b/resumejson_converter/utils/json.py @@ -1,4 +1,3 @@ -import sys import logging import json @@ -34,17 +33,25 @@ def load(json_filepath): """ try: logging.info("JSON parsing...") - with open(json_filepath, 'r') as f: - resume_json = json.load(f) + if type(json_filepath) is str: + with open(json_filepath, 'r') as f: + resume_json = json.load(f) + elif type(json_filepath) is dict: + resume_json = json_filepath + else: + msg = "{} is not a valid type, type accepted are \n\ + or .".format(type(json_filepath)) + logging.error(msg) + raise TypeError except IOError: msg = "Json file could not be loaded. Perhaps file path: \n\ [{}] is incorrect".format(json_filepath) - logging.exception(msg) - sys.exit(1) + logging.error(msg) + raise except ValueError: - logging.exception( + logging.error( "Json file could not be loaded. The syntax is not valid.") - sys.exit(1) + raise else: resume = Resume(resume_json) try: @@ -52,8 +59,8 @@ def load(json_filepath): except InvalidResumeError: msg = "The json resume don't respect standard. Check: \n\ https://jsonresume.org/schema/." - logging.exception(msg) - sys.exit(1) + logging.error(msg) + raise else: logging.info("JSON parsing done.") return JsonObject(resume_json) diff --git a/tests/filters/test_birthday.py b/tests/filters/test_birthday.py new file mode 100644 index 0000000..257f8c4 --- /dev/null +++ b/tests/filters/test_birthday.py @@ -0,0 +1,17 @@ +import pytest + +import resumejson_converter.filters as filters + + +def test_birthday_no_parameter(): + with pytest.raises(TypeError): + filters.birthday() + + +def test_birthday_false_date(): + with pytest.raises(ValueError): + filters.birthday("1990-10-25a") + + +def test_birthday(): + assert filters.birthday("1990-10-25") == "25 octobre 1990" diff --git a/tests/filters/test_clean.py b/tests/filters/test_clean.py new file mode 100644 index 0000000..32553b4 --- /dev/null +++ b/tests/filters/test_clean.py @@ -0,0 +1,12 @@ +import pytest + +import resumejson_converter.filters as filters + + +def test_clean_no_parameter(): + with pytest.raises(TypeError): + filters.clean() + + +def test_clean(): + assert filters.clean("0011223344") == "00 11 22 33 44" diff --git a/tests/filters/test_datediff.py b/tests/filters/test_datediff.py new file mode 100644 index 0000000..845330b --- /dev/null +++ b/tests/filters/test_datediff.py @@ -0,0 +1,84 @@ +import pytest + +import resumejson_converter.filters as filters + + +def test_datediff_only_one_parameter(): + with pytest.raises(TypeError): + filters.datediff() + + +def test_datediff_only_one_parameter(): + with pytest.raises(TypeError): + filters.datediff("Hello World") + + +def test_datediff_only_two_parameter(): + with pytest.raises(TypeError): + filters.datediff("Hello World", "2019-01-02") + + +def test_datediff_false_end_date(): + with pytest.raises(ValueError): + filters.datediff("Hello", "2019-01-02", "2019-01-02d") + + +def test_datediff_false_start_date(): + with pytest.raises(ValueError): + filters.datediff("Hello", "2019-01-02a", "2019-01-02") + + +def test_datediff_one_year(): + assert filters.datediff( + "Hello World!", + "2018-01-02", + "2019-01-03" + ) == "Hello World! - 1 an" + + +def test_datediff_two_year(): + assert filters.datediff( + "Hello World!", + "2017-01-02", + "2019-01-03" + ) == "Hello World! - 2 ans" + + +def test_datediff_two_years(): + assert filters.datediff( + "Hello World!", + "2017-01-02", + "2019-01-03" + ) == "Hello World! - 2 ans" + + +def test_datediff_one_month(): + assert filters.datediff( + "Hello World!", + "2019-01-02", + "2019-02-03" + ) == "Hello World! - 1 mois" + + +def test_datediff_one_week(): + assert filters.datediff( + "Hello World!", + "2019-01-01", + "2019-01-09" + ) == "Hello World! - 1 semaine" + + +def test_datediff_two_weeks(): + assert filters.datediff( + "Hello World!", + "2019-01-01", + "2019-01-16" + ) == "Hello World! - 2 semaines" + + +def test_datediff_two_days(): + assert filters.datediff( + "Hello World!", + "2019-01-02", + "2019-01-04" + ) == "Hello World! - 2 jours" diff --git a/tests/filters/test_dateedit.py b/tests/filters/test_dateedit.py new file mode 100644 index 0000000..5191b26 --- /dev/null +++ b/tests/filters/test_dateedit.py @@ -0,0 +1,30 @@ +import pytest + +import resumejson_converter.filters as filters + + +def test_dateedit_only_one_parameter(): + with pytest.raises(TypeError): + filters.dateedit() + + +def test_dateedit_only_one_parameter(): + with pytest.raises(TypeError): + filters.dateedit("2019-01-01") + + +def test_dateedit_false_date(): + with pytest.raises(ValueError): + filters.dateedit("2019-01-01i", "") + + +def test_dateedit_only_start_date(): + assert filters.dateedit("2019-01-01", "") == "2019 - Auj." + + +def test_dateedite_same_year(): + assert filters.dateedit("2019-01-01", "2019-02-02") == "2019" + + +def test_dateedit_start_date_and_end_date_different(): + assert filters.dateedit("2019-01-01", "2017-05-01") == "2019 - 2017" diff --git a/tests/generators/html/test_generate_html.py b/tests/generators/html/test_generate_html.py new file mode 100644 index 0000000..f1ce676 --- /dev/null +++ b/tests/generators/html/test_generate_html.py @@ -0,0 +1,72 @@ +import pytest +import os + +import resumejson_converter + +from jinja2.exceptions import TemplateSyntaxError + +from resumejson_converter.generators.html import generate as generate_html +from resumejson_converter.utils import json as ujson + + +@pytest.fixture(scope="session") +def gen_template_html(tmpdir_factory): + tmp_file = tmpdir_factory.mktemp( + "resumejson_converter_test" + ).join("template.html") + + with open(tmp_file, "w") as f: + f.write("

{{ resume.basics.name }}

") + return tmp_file + + +@pytest.fixture(scope="session") +def gen_incorrect_template_html(tmpdir_factory): + tmp_file = tmpdir_factory.mktemp( + "resumejson_converter_test" + ).join("template.html") + + with open(tmp_file, "w") as f: + f.write("

{{ resume.basics.name }

") + return tmp_file + + +def test_generate_html(): + with pytest.raises(TypeError): + generate_html() + + +def test_generate_html_one_parameters(): + with pytest.raises(TypeError): + generate_html("resume") + + +def test_generate_html(gen_template_html): + resume_path = "{}/example/resume.json".format( + os.path.dirname(resumejson_converter.__file__)) + template_path = gen_template_html + resume = ujson.load(resume_path) + assert generate_html(resume, template_path) == "

John Doe

" + + +def test_generate_html_incorect_path(): + with pytest.raises(IOError): + generate_html("resume", "/tmp/template") + + +def test_generate_html_incorrect_template(gen_incorrect_template_html): + resume_path = "{}/example/resume.json".format( + os.path.dirname(resumejson_converter.__file__)) + template_path = gen_incorrect_template_html + resume = ujson.load(resume_path) + with pytest.raises(TemplateSyntaxError): + generate_html(resume, template_path) + + +def test_generate_html_out_path_without_right(gen_template_html): + resume_path = "{}/example/resume.json".format( + os.path.dirname(resumejson_converter.__file__)) + template_path = gen_template_html + resume = ujson.load(resume_path) + with pytest.raises(IOError): + generate_html(resume, template_path, "/my_cv.html") diff --git a/tests/generators/pdf/test_generate_pdf.py b/tests/generators/pdf/test_generate_pdf.py new file mode 100644 index 0000000..738508c --- /dev/null +++ b/tests/generators/pdf/test_generate_pdf.py @@ -0,0 +1,55 @@ +import pytest +import os +from pathlib import Path + +import resumejson_converter + +from jinja2.exceptions import TemplateSyntaxError + +from resumejson_converter.generators.html import generate as generate_html +from resumejson_converter.generators.pdf import generate as generate_pdf +from resumejson_converter.utils import json as ujson + + +@pytest.fixture(scope="session") +def gen_template_html(tmpdir_factory): + tmp_file = tmpdir_factory.mktemp( + "resumejson_converter_test" + ).join("template.html") + + with open(tmp_file, "w") as f: + f.write("

{{ resume.basics.name }}

") + return tmp_file + + +@pytest.fixture(scope="session") +def gen_incorrect_template_html(tmpdir_factory): + tmp_file = tmpdir_factory.mktemp( + "resumejson_converter_test" + ).join("template.html") + + with open(tmp_file, "w") as f: + f.write("

{{ resume.basics.name }

") + return tmp_file + + +@pytest.fixture(scope="session") +def gen_dest_path(tmpdir_factory): + return tmpdir_factory.mktemp("out").join("out.pdf") + + +def test_generate_pdf(): + with pytest.raises(TypeError): + generate_html() + + +def test_generate_pdf_generated( + gen_template_html, + gen_incorrect_template_html): + resume_path = "{}/example/resume.json".format( + os.path.dirname(resumejson_converter.__file__)) + template_path = gen_template_html + resume = ujson.load(resume_path) + html = generate_html(resume, template_path) + generate_pdf(html, gen_incorrect_template_html) + assert Path(gen_incorrect_template_html).is_file diff --git a/tests/utils/json/test_load.py b/tests/utils/json/test_load.py new file mode 100644 index 0000000..d809069 --- /dev/null +++ b/tests/utils/json/test_load.py @@ -0,0 +1,52 @@ +import pytest +import os + +from jsonresume.exceptions import InvalidResumeError + +import resumejson_converter + +from resumejson_converter.utils import json as ujson + + +@pytest.fixture(scope="session") +def prepare_tmp_json(tmpdir_factory): + tmp_file = tmpdir_factory.mktemp( + "resumejson_converter_test" + ).join("resume_not_standard.json") + + with open(tmp_file, "w") as f: + f.write("{'Hello': 'World!'}") + return tmp_file + + +def test_json_load_no_parameter(): + with pytest.raises(TypeError): + ujson.load() + + +def test_json_load(): + resume_path = "{}/example/resume.json".format( + os.path.dirname(resumejson_converter.__file__)) + assert type(ujson.load(resume_path)) is ujson.JsonObject + + +def test_json_load_incorrect_path(): + with pytest.raises(IOError): + resume_json = "/tmp/sd54f5f48ds4f98ds7g48d468s4f68ds4f.json" + ujson.load(resume_json) + + +def test_json_load_resume_dont_respect_standard(): + with pytest.raises(InvalidResumeError): + resume_path = {"Hello": 'World!'} + ujson.load(resume_path) + + +def test_json_load_array(): + with pytest.raises(TypeError): + ujson.load(["o", "f"]) + + +def test_json_load_resume_dont_respect_standard_from_file(prepare_tmp_json): + with pytest.raises(ValueError): + ujson.load(str(prepare_tmp_json)) diff --git a/tests/utils/templates/test_templates.py b/tests/utils/templates/test_templates.py new file mode 100644 index 0000000..66c77f6 --- /dev/null +++ b/tests/utils/templates/test_templates.py @@ -0,0 +1,33 @@ +import pytest +import os + +from datetime import datetime + +import resumejson_converter + +from resumejson_converter.utils import templates + + +def test_td_format_no_argument(): + with pytest.raises(TypeError): + templates.td_format() + + +def test_td_format_classic(): + startDateTime = datetime.strptime( + "2015-02-20 10:15:20", + '%Y-%m-%d %H:%M:%S') + endDateTime = datetime.strptime( + "2019-03-25 11:16:25", + '%Y-%m-%d %H:%M:%S') + diffDate = endDateTime - startDateTime + + assert templates.td_format(diffDate) == "4 ans, 1 mois, 4 jours, 1 heure, 1 minute, 5 secondes" + + +def test_td_format_week(): + startDateTime = datetime.strptime("2019-02-01", '%Y-%m-%d') + endDateTime = datetime.strptime("2019-02-16", '%Y-%m-%d') + diffDate = endDateTime - startDateTime + + assert templates.td_format(diffDate) == "2 semaines, 24 heures" -- cgit v1.2.1