diff --git a/CLAUDE.md b/CLAUDE.md
index 3b531e8d..9a6cac5f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -96,6 +96,14 @@ is mirrored into `~/utils/file_length/_tables.py`, `[tool.ruff] exclude` and
- `ruff` runs with `select = ["ALL"]` and mypy with `strict = true`.
- No `# noqa`, no `# type: ignore`. A pre-commit hook rejects both outright.
+- **No per-file-ignores either, including for tests.** `pyproject.toml` has no
+ `[tool.ruff.lint.per-file-ignores]` table at all, which is stricter than the
+ rest of the fleet. So a test asserts by raising:
+ `if x != y: msg = ...; raise AssertionError(msg)` -- never a bare `assert`,
+ which is `S101`. Test functions carry docstrings and full annotations like
+ any other code, `pytest.raises` always takes `match=`, and an expected value
+ gets a named constant rather than being a magic number. Decided by kuhy on
+ 2026-08-28 against the alternative of mirroring testsAndMisc's test block.
- Notebooks: `ruff` reads and formats `.ipynb` natively (cell-aware, so an
import used two cells later is not reported unused), which is why there is
no `nbqa` layer. It rewrites `source` only — outputs are left byte-identical.
diff --git a/Programming/ECOTE/program/translator/__init__.py b/Programming/ECOTE/program/translator/__init__.py
index e69de29b..fb364d91 100644
--- a/Programming/ECOTE/program/translator/__init__.py
+++ b/Programming/ECOTE/program/translator/__init__.py
@@ -0,0 +1 @@
+"""LaTeX-subset to HTML translator: the ECOTE project deliverable."""
diff --git a/Programming/ECOTE/program/translator/main.py b/Programming/ECOTE/program/translator/main.py
index 1f8686b2..eeb59cdd 100644
--- a/Programming/ECOTE/program/translator/main.py
+++ b/Programming/ECOTE/program/translator/main.py
@@ -1,68 +1,74 @@
"""Program for converting Latex files into html files."""
import argparse
+import logging
+from pathlib import Path
+
+logger = logging.getLogger(__name__)
-def command_name_check(latex_string, command_name):
- """Checks if command name given from latex was spelled correctly."""
+def command_name_check(latex_string: str, command_name: str) -> str:
+ """Check if command name given from latex was spelled correctly."""
if latex_string[1 : (len(command_name) + 1)] != command_name:
- print(latex_string + "Error! command misspeled!")
+ logger.error("%sError! command misspeled!", latex_string)
return "Error!"
return ""
-def generic_checks(latex_string):
- """Checks if string is given and whether latex parameters
- ends with curly bracket.
+def generic_checks(latex_string: str) -> str:
+ """Check that a string was given and that its parameters close.
+
+ "Close" means the latex parameter list ends with a curly bracket.
"""
if latex_string == "":
- print(latex_string + "Error! No input given to function")
+ logger.error("%sError! No input given to function", latex_string)
return "Error!"
if "}" not in latex_string:
- print(latex_string + "Error! curly bracket not closed!")
+ logger.error("%sError! curly bracket not closed!", latex_string)
return "Error!"
return ""
-def generic_checks_command(latex_string):
- """In additon to generic checks it also checks if command starts with \
- """
+def generic_checks_command(latex_string: str) -> str:
+ r"""Run the generic checks, and also require a leading backslash."""
if generic_checks(latex_string) == "Error!":
return "Error!"
if latex_string[0] != "\\":
- print(latex_string + "Error! has no slash at begining")
+ logger.error("%sError! has no slash at begining", latex_string)
return "Error!"
return ""
-def document_class_only_checks(latex_string):
- """Checks only errors connected to document class."""
+def document_class_only_checks(latex_string: str) -> str:
+ """Check only errors connected to document class."""
if len(latex_string) < len("\\documentclass{"):
- print(latex_string + "Error! latex string to short to be document class!")
+ logger.error(
+ "%sError! latex string to short to be document class!", latex_string
+ )
return "Error!"
if latex_string[len("\\documentclass{") - 1] != "{":
- print(latex_string + "Error! curly bracket not opened!")
+ logger.error("%sError! curly bracket not opened!", latex_string)
return "Error!"
if command_name_check(latex_string, "documentclass") == "Error!":
return "Error!"
return ""
-def document_class(latex_string):
- r"""Converts LaTeX documentclass method to html
+def document_class(latex_string: str) -> str:
+ r"""Convert LaTeX documentclass method to html.
+
\documentclass{article}.
"""
if generic_checks_command(latex_string) == "Error!":
return "Error!"
if document_class_only_checks(latex_string) == "Error!":
return "Error!"
- # document_type = latex_string[len(
- # "\\documentclass{"): (len(latex_string) - 1)]
return ""
-def begin_document(latex_string):
- r"""Converts LaTeX begin document method to html
+def begin_document(latex_string: str) -> str:
+ r"""Convert LaTeX begin document method to html.
+
\begin{document}.
"""
if generic_checks_command(latex_string) == "Error!":
@@ -72,8 +78,8 @@ def begin_document(latex_string):
return ""
-def begin_tabular(latex_string):
- r"""Checks if LaTeX begin tabular method is correct."""
+def begin_tabular(latex_string: str) -> str:
+ r"""Check if LaTeX begin tabular method is correct."""
if generic_checks_command(latex_string) == "Error!":
return "Error!"
if command_name_check(latex_string, "begin") == "Error!":
@@ -81,8 +87,8 @@ def begin_tabular(latex_string):
return "
"
-def tabular_parameters(latex_string):
- r"""Checks if LaTeX tabular environment has any parameters."""
+def tabular_parameters(latex_string: str) -> str:
+ r"""Check if LaTeX tabular environment has any parameters."""
if latex_string == "":
return ""
if latex_string == "[]":
@@ -90,15 +96,18 @@ def tabular_parameters(latex_string):
return "Error!"
-def only_pipes_and_space(latex_string):
- """Checks if latex string only contains | or " "
+def only_pipes_and_space(latex_string: str) -> bool:
+ """Check if latex string only contains | or " ".
+
if yes returns True, if no returns false.
"""
return all(char in ("|", " ", "{", "}") for char in latex_string)
-def handle_complicated_parameter(latex_string, return_array, i):
- """Handles single complicated parameter from loop."""
+def handle_complicated_parameter(
+ latex_string: str, return_array: list[str], i: int
+) -> tuple[list[str], int, str]:
+ """Handle single complicated parameter from loop."""
closing_bracket = latex_string.find("}", i + 1)
columns_string = latex_string[i : closing_bracket + 1]
result = tabular_columns_parameters(columns_string)
@@ -110,9 +119,12 @@ def handle_complicated_parameter(latex_string, return_array, i):
def main_tabular_parameters_loop_inside(
- latex_string, i, simple_parameters_dictionary, return_array
-):
- """Handles single tabular parameter character."""
+ latex_string: str,
+ i: int,
+ simple_parameters_dictionary: dict[str, str],
+ return_array: list[str],
+) -> tuple[list[str], int, str]:
+ """Handle single tabular parameter character."""
character = latex_string[i]
if character in ["l", "c", "r", "|"]:
return_array.append(simple_parameters_dictionary.get(latex_string[i]))
@@ -124,8 +136,10 @@ def main_tabular_parameters_loop_inside(
return return_array, i, ""
-def main_tabular_parameters_loop(latex_string, simple_parameters_dictionary):
- """Converts simple and paragraph table parameters into html style code."""
+def main_tabular_parameters_loop(
+ latex_string: str, simple_parameters_dictionary: dict[str, str]
+) -> list[str] | str:
+ """Convert simple and paragraph table parameters into html style code."""
return_array = []
i = 0
latex_string_length = len(latex_string)
@@ -138,50 +152,48 @@ def main_tabular_parameters_loop(latex_string, simple_parameters_dictionary):
return return_array
-def tabular_required_errors(latex_string):
- """Runs generic checks and
+def tabular_required_errors(latex_string: str) -> str:
+ """Run the generic checks and.
+
checks if there are any parameters put to latex table.
"""
if generic_checks(latex_string) == "Error!":
return "Error!"
if latex_string == "{}":
- print(
- """tabular_required_parameters
- required table parameters are empty!:""",
+ logger.error(
+ "tabular_required_parameters: required table parameters are empty: %s",
latex_string,
)
return "Error!"
return ""
-def simple_parameters_dictionary_return():
- """Defines html styles for simple tabular parameters."""
- simple_parameters_dictionary = {
+def simple_parameters_dictionary_return() -> dict[str, str]:
+ """Return the html styles for the simple tabular parameters."""
+ return {
"l": "align='left'",
"c": "align='center'",
"r": "align='right'",
"|": "style='border-left: 1px solid black'",
}
- return simple_parameters_dictionary
-def tabular_required_parameters(latex_string):
- """Converts simple tabular parameters to html style commands."""
+def tabular_required_parameters(latex_string: str) -> list[str] | str:
+ """Convert simple tabular parameters to html style commands."""
if tabular_required_errors(latex_string) == "Error!":
return "Error!"
simple_parameters_dictionary = simple_parameters_dictionary_return()
if only_pipes_and_space(latex_string):
- print(
- """tabular_required_parameters,
- required table parameters are only pipes and spaces!:""",
+ logger.error(
+ "tabular_required_parameters: parameters are only pipes and spaces: %s",
latex_string,
)
return "Error!"
return main_tabular_parameters_loop(latex_string, simple_parameters_dictionary)
-def length_conversions(latex_length):
- """Converts latex lengths to html lengths."""
+def length_conversions(latex_length: str) -> float | None:
+ """Convert latex lengths to html lengths."""
length_dictionary = {
"pt": [1.3, "px"],
"mm": [1, "mm"],
@@ -193,9 +205,11 @@ def length_conversions(latex_length):
return length_dictionary.get(latex_length, "Error!")
-def construct_return_string(vertical_align_type, final_length, conversed_unit):
+def construct_return_string(
+ vertical_align_type: str, final_length: float, conversed_unit: str
+) -> str:
"""Construsts entire html style of parameters."""
- return_string = (
+ return (
"style='"
+ vertical_align_type
+ " width: "
@@ -203,38 +217,40 @@ def construct_return_string(vertical_align_type, final_length, conversed_unit):
+ conversed_unit[1]
+ ";'"
)
- return return_string
-def return_parameter_dictionary():
- """Returns html styles for each complicated latex parameter."""
- parameter_dictionary = {
+def return_parameter_dictionary() -> dict[str, str]:
+ """Return html styles for each complicated latex parameter."""
+ return {
"p": "vertical-align: top;",
"m": "vertical-align: middle;",
"b": "vertical-align: bottom;",
}
- return parameter_dictionary
-def tabular_columns_parameters_errors(latex_string, vertical_align_type):
- """Checks for intermediate errors
+def tabular_columns_parameters_errors(
+ latex_string: str, vertical_align_type: str
+) -> str:
+ """Check for intermediate errors.
+
Checks if parameter length starts with curly bracket.
"""
if vertical_align_type == "Error!":
- print("tabular_columns_parameters, unknown parameter: ", latex_string[0])
+ logger.error(
+ "tabular_columns_parameters: unknown parameter: %s", latex_string[0]
+ )
return "Error!"
if latex_string[1] != "{":
- print(
- """tabular_columns_parameters
- parameter length does not start with {""",
+ logger.error(
+ "tabular_columns_parameters: parameter length does not start with {: %s",
latex_string,
)
return "Error!"
return ""
-def string_length_no_whitespace(length_parameter):
- """Calculates string width without whitespace."""
+def string_length_no_whitespace(length_parameter: str) -> tuple[int, str]:
+ """Measure the string width, ignoring whitespace."""
i = 0
length_value = ""
for character in length_parameter:
@@ -245,8 +261,8 @@ def string_length_no_whitespace(length_parameter):
return i, length_value
-def tabular_columns_parameters(latex_string):
- """Handles tabular paragraph parameters and translates them to html style."""
+def tabular_columns_parameters(latex_string: str) -> str:
+ """Handle tabular paragraph parameters and translates them to html style."""
if generic_checks(latex_string) == "Error!":
return "Error!"
parameter_dictionary = return_parameter_dictionary()
@@ -259,44 +275,44 @@ def tabular_columns_parameters(latex_string):
length_unit = length_parameter[i:]
conversed_unit = length_conversions(length_unit)
if conversed_unit == "Error!":
- print(
- """tabular_columns_parameters,
- Unit could not be conversed!""",
- latex_string,
+ logger.error(
+ "tabular_columns_parameters: unit could not be converted: %s", latex_string
)
return "Error!"
final_length = round(float(length_value) * conversed_unit[0], 2)
return construct_return_string(vertical_align_type, final_length, conversed_unit)
-def split_rows(latex_string):
- """Splits table row string into separate strings and puts them in array."""
+def split_rows(latex_string: str) -> list[str]:
+ """Split table row string into separate strings and puts them in array."""
double_backslash = "\\"
- rows = latex_string.split(double_backslash)
- return rows
+ return latex_string.split(double_backslash)
-def split_columns(table_row, column_count):
- """Splits table row columns into separate strings and puts them in array."""
+def split_columns(table_row: str, column_count: int) -> list[str] | str:
+ """Split table row columns into separate strings and puts them in array."""
columns = table_row.split("&")
if len(columns) != column_count and columns != [""]:
- print(
- f"Error! extracted columns length: {columns} and columns_count: {column_count} is different!"
+ logger.error(
+ "Error! extracted columns length: %s and columns_count: %s is different!",
+ columns,
+ column_count,
)
return "Error!"
return columns
-def translate_column(latex_column):
+def translate_column(latex_column: str) -> str:
"""Translate insides of a single latex tabular column to html."""
hline_string_literal = "\\hline"
replaced_hline = latex_column.replace(hline_string_literal, "
")
- replaced_newline = replaced_hline.replace("\newline", "
")
- return replaced_newline
+ return replaced_hline.replace("\newline", "
")
-def handle_line_strings(line_string, column_style, column_number, return_string):
- """Converts lines untill there are no more lines."""
+def handle_line_strings(
+ line_string: str, column_style: list[str], column_number: int, return_string: str
+) -> tuple[str, int]:
+ """Convert lines untill there are no more lines."""
current_style = column_style[column_number]
if current_style == line_string:
while current_style == line_string:
@@ -307,14 +323,19 @@ def handle_line_strings(line_string, column_style, column_number, return_string)
def handle_single_column(
- column, column_style, column_number, line_string, return_string
-):
- """Handles single column from columns loop."""
+ column: str,
+ column_style: list[str],
+ column_number: int,
+ line_string: str,
+ return_string: str,
+) -> tuple[str, int]:
+ """Handle single column from columns loop."""
return_string += "= len(column_style):
- print(
- f"""Error! column_number index: {column_number}
- is out of length of column_style: {column_style}"""
+ logger.error(
+ "Error! column_number index %s is past the end of column_style %s",
+ column_number,
+ column_style,
)
return "Error!", column_number
return_string, column_number = handle_line_strings(
@@ -329,9 +350,13 @@ def handle_single_column(
def handle_latex_columns(
- columns, column_style, column_number, line_string, return_string
-):
- """Goes through every column in a row and translates it to html."""
+ columns: list[str],
+ column_style: list[str],
+ column_number: int,
+ line_string: str,
+ return_string: str,
+) -> tuple[str, int]:
+ """Go through every column in a row and translates it to html."""
if columns != "Error!":
for column in columns:
return_string, column_number = handle_single_column(
@@ -341,9 +366,13 @@ def handle_latex_columns(
def go_through_latex_rows(
- rows, return_string, column_amount, column_style, line_string
-):
- """Goes through latex table insides row by row."""
+ rows: list[str],
+ return_string: str,
+ column_amount: int,
+ column_style: list[str],
+ line_string: str,
+) -> str:
+ """Go through latex table insides row by row."""
for row in rows:
return_string += " | "
columns = split_columns(row, column_amount)
@@ -356,8 +385,8 @@ def go_through_latex_rows(
return return_string
-def translate_inside_to_html(latex_table_inside, column_style):
- """Translates entire table insides to html."""
+def translate_inside_to_html(latex_table_inside: str, column_style: list[str]) -> str:
+ """Translate entire table insides to html."""
return_string = ""
column_amount = 0
line_string = "style='border-left: 1px solid black'"
@@ -372,21 +401,17 @@ def translate_inside_to_html(latex_table_inside, column_style):
return return_string
-def read_file(tex_filename):
- """opens, reads and saves latex file
- content into python string, then closes file.
- """
- with open(tex_filename, encoding="UTF-8") as tex_file:
- data = tex_file.read().replace("\n", "")
- tex_file.close()
- return data
+def read_file(tex_filename: str) -> str:
+ """Read a latex file into one string, with newlines stripped."""
+ with Path(tex_filename).open(encoding="UTF-8") as tex_file:
+ return tex_file.read().replace("\n", "")
-def read_document_class(latex_full_string):
- """Finds documentclass in latex file and checks function correctness."""
+def read_document_class(latex_full_string: str) -> tuple[str, str] | str:
+ """Find documentclass in latex file and checks function correctness."""
document_class_index = latex_full_string.find("\\documentclass")
if document_class_index == -1:
- print("Main function error! documentclass not found")
+ logger.error("Main function error! documentclass not found")
return "Error!"
document_class_close_bracket = latex_full_string.find("}", document_class_index)
document_class_string = latex_full_string[
@@ -398,11 +423,11 @@ def read_document_class(latex_full_string):
return document_class(document_class_string), latex_full_string
-def read_begin_document(latex_full_string):
- """Finds LaTeX \begin{document} command and returns html counterpart to it."""
+def read_begin_document(latex_full_string: str) -> tuple[str, str]:
+ r"""Find the LaTeX \begin{document} command and return its html counterpart."""
begin_document_index = latex_full_string.find(r"\begin{document}")
if begin_document_index == -1:
- print("read_begin_document error! begin{document not found")
+ logger.error("read_begin_document error! begin{document not found")
return "Error!", latex_full_string
begin_document_close_bracket = latex_full_string.find("}", begin_document_index)
begin_document_string = latex_full_string[
@@ -415,8 +440,9 @@ def read_begin_document(latex_full_string):
return return_string, latex_full_string
-def read_start(html_string, data):
- """Finds, reads latex document class
+def read_start(html_string: str, data: str) -> tuple[str, str]:
+ """Find and read the latex document class.
+
and begin document and translates them to html.
"""
document_class_result, data = read_document_class(data)
@@ -431,8 +457,11 @@ def read_start(html_string, data):
return html_string, data
-def handle_table_whole(html_string, data, table_start, table_end):
- """Reads entire table, handles its parameters
+def handle_table_whole(
+ html_string: str, data: str, table_start: int, table_end: int
+) -> tuple[str, str] | str:
+ """Read entire table, handles its parameters.
+
and insides and translates to html.
"""
if table_start == -1 or table_end == -1:
@@ -448,8 +477,8 @@ def handle_table_whole(html_string, data, table_start, table_end):
return html_string
-def handle_insides(html_string, data):
- """Finds inside of table and translates them to html."""
+def handle_insides(html_string: str, data: str) -> tuple[str, str]:
+ """Find inside of table and translates them to html."""
tabular_index = 0
tabular_end_string = r"\end{tabular}"
while tabular_index != -1:
@@ -467,23 +496,25 @@ def handle_insides(html_string, data):
return html_string, data
-def main_function(tex_filename):
- """Ran by default by program,
+def main_function(tex_filename: str) -> str:
+ """Ran by default by program,.
+
gets latex file and translates to html.
"""
data = read_file(tex_filename)
html_string = ""
html_string, data = read_start(html_string, data)
if html_string == "Error!":
- print("""main_function error!
- when reading documentclass or begin document""")
+ logger.error(
+ "main_function error!\n when reading documentclass or begin document"
+ )
return "Error"
html_string, data = handle_insides(html_string, data)
- html_string = html_string.replace("}", "")
- return html_string
+ return html_string.replace("}", "")
-def handle_arguments():
+def handle_arguments() -> str:
+ """Parse the command line and return the .tex filename to translate."""
parser = argparse.ArgumentParser(description="Specify tex filename and path")
parser.add_argument(
"--filename",
@@ -499,5 +530,4 @@ def handle_arguments():
if __name__ == "__main__":
TEX_FILENAME = handle_arguments()
FINAL_HTML = main_function(TEX_FILENAME)
- with open(TEX_FILENAME + ".html", "w", encoding="UTF-8") as f:
- f.write(FINAL_HTML)
+ Path(TEX_FILENAME + ".html").write_text(FINAL_HTML, encoding="UTF-8")
diff --git a/Programming/ECOTE/program/unit_tests/__init__.py b/Programming/ECOTE/program/unit_tests/__init__.py
index e69de29b..4fed924d 100644
--- a/Programming/ECOTE/program/unit_tests/__init__.py
+++ b/Programming/ECOTE/program/unit_tests/__init__.py
@@ -0,0 +1 @@
+"""Unit tests for the ECOTE LaTeX-to-HTML translator."""
diff --git a/Programming/ECOTE/program/unit_tests/expect.py b/Programming/ECOTE/program/unit_tests/expect.py
new file mode 100644
index 00000000..757994dd
--- /dev/null
+++ b/Programming/ECOTE/program/unit_tests/expect.py
@@ -0,0 +1,40 @@
+"""Assertion helpers for the ECOTE test suite.
+
+This repo runs ruff with ``select = ["ALL"]`` and no per-file-ignores, so a
+bare ``assert`` is an ``S101`` violation even inside a test. These raise
+``AssertionError`` explicitly and, unlike a bare assert, always report both
+values -- pytest's assertion rewriting does not apply to a helper, so the
+message has to carry the detail itself.
+"""
+
+
+def expect_equal(actual: object, expected: object) -> None:
+ """Raise unless *actual* equals *expected*."""
+ if actual != expected:
+ msg = f"expected {expected!r}, got {actual!r}"
+ raise AssertionError(msg)
+
+
+def expect_in(member: str, container: str) -> None:
+ """Raise unless *member* is contained in *container*."""
+ if member not in container:
+ msg = f"expected {member!r} to be in {container!r}"
+ raise AssertionError(msg)
+
+
+def expect_true(actual: object) -> None:
+ """Raise unless *actual* equals ``True``.
+
+ Separate from expect_equal so that a caller never has to pass a bare
+ boolean positionally, which is FBT003.
+ """
+ if actual is not True:
+ msg = f"expected True, got {actual!r}"
+ raise AssertionError(msg)
+
+
+def expect_false(actual: object) -> None:
+ """Raise unless *actual* equals ``False``."""
+ if actual is not False:
+ msg = f"expected False, got {actual!r}"
+ raise AssertionError(msg)
diff --git a/Programming/ECOTE/program/unit_tests/test_code/__init__.py b/Programming/ECOTE/program/unit_tests/test_code/__init__.py
index e69de29b..0050609c 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/__init__.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/__init__.py
@@ -0,0 +1 @@
+"""One module per translator function under test."""
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py b/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py
index a952b438..26688dbc 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_begin_document.py
@@ -2,57 +2,72 @@
from translator.main import begin_document
+from unit_tests.expect import expect_equal
+
# Write python tests for a function translating LaTeX documentclass to html
-def given_empty_then_error():
- """Given: ""
+def given_empty_then_error() -> None:
+ """Given empty, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert begin_document("") == "Error!"
+ expect_equal(begin_document(""), "Error!")
-def given_not_closed_then_error():
- r"""Given: "\\begin\{document"
+def given_not_closed_then_error() -> None:
+ r"""Given not closed, then error.
+
+ Given: "\\begin\{document"
When: N/A
Then: Error message.
"""
- assert begin_document(r"\\begin{document") == "Error!"
+ expect_equal(begin_document(r"\\begin{document"), "Error!")
-def given_no_opening_then_error():
- """Given: No opening curly bracket
+def given_no_opening_then_error() -> None:
+ """Given no opening, then error.
+
+ Given: No opening curly bracket
When: N/A
Then: Error message.
"""
- assert begin_document(r"\\begindocument}") == "Error!"
+ expect_equal(begin_document(r"\\begindocument}"), "Error!")
-def given_misspeled_then_error():
- """Given: misspelled begin document
+def given_misspeled_then_error() -> None:
+ """Given misspeled, then error.
+
+ Given: misspelled begin document
When: N/A
Then: Error message.
"""
- assert begin_document(r"\\begim{document}") == "Error!"
+ expect_equal(begin_document(r"\\begim{document}"), "Error!")
-def given_no_slash_then_error():
- """Given: no backslash at start
+def given_no_slash_then_error() -> None:
+ """Given no slash, then error.
+
+ Given: no backslash at start
When: N/A
Then: Error message.
"""
- assert begin_document(r"begin{document}") == "Error!"
+ expect_equal(begin_document(r"begin{document}"), "Error!")
-def given_correct_then_html():
- """Given: \\documentclass{article}
+def given_correct_then_html() -> None:
+ r"""Given correct, then html.
+
+ Given: \\documentclass{article}
When: N/A
Then: .
"""
- assert begin_document(r"\begin{document}") == ""
+ expect_equal(begin_document(r"\begin{document}"), "")
-def test_begin_document():
+def test_begin_document() -> None:
+ """Exercise begin document."""
given_correct_then_html()
given_empty_then_error()
given_misspeled_then_error()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py b/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py
index f798e75d..845b452e 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_begin_tabular.py
@@ -2,65 +2,82 @@
from translator.main import begin_tabular
+from unit_tests.expect import expect_equal
+
# Write python tests for a function translating LaTeX documentclass to html
-def given_empty_then_error():
- """Given: ""
+def given_empty_then_error() -> None:
+ """Given empty, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert begin_tabular("") == "Error!"
+ expect_equal(begin_tabular(""), "Error!")
-def given_not_closed_then_error():
- r"""Given: command not closed
+def given_not_closed_then_error() -> None:
+ r"""Given not closed, then error.
+
+ Given: command not closed
When: N/A
Then: Error message.
"""
- assert begin_tabular(r"\\begin{tabular") == "Error!"
+ expect_equal(begin_tabular(r"\\begin{tabular"), "Error!")
-def given_no_opening_then_error():
- """Given: No opening curly bracket
+def given_no_opening_then_error() -> None:
+ """Given no opening, then error.
+
+ Given: No opening curly bracket
When: N/A
Then: Error message.
"""
- assert begin_tabular(r"\\begintabular}") == "Error!"
+ expect_equal(begin_tabular(r"\\begintabular}"), "Error!")
-def given_misspeled_then_error():
- """Given: misspelled begin tabular
+def given_misspeled_then_error() -> None:
+ """Given misspeled, then error.
+
+ Given: misspelled begin tabular
When: N/A
Then: Error message.
"""
- assert begin_tabular(r"\\begim{tabular}") == "Error!"
+ expect_equal(begin_tabular(r"\\begim{tabular}"), "Error!")
-def given_no_slash_then_error():
- """Given: no backslash at start
+def given_no_slash_then_error() -> None:
+ """Given no slash, then error.
+
+ Given: no backslash at start
When: N/A
Then: Error message.
"""
- assert begin_tabular(r"begin{tabular}") == "Error!"
+ expect_equal(begin_tabular(r"begin{tabular}"), "Error!")
-def given_tabular_star_then_error():
- """Given: no backslash at start
+def given_tabular_star_then_error() -> None:
+ """Given tabular star, then error.
+
+ Given: no backslash at start
When: N/A
Then: Error message.
"""
- assert begin_tabular(r"begin{tabular*}") == "Error!"
+ expect_equal(begin_tabular(r"begin{tabular*}"), "Error!")
-def given_correct_then_html():
- """Given: \begin{tabular}
+def given_correct_then_html() -> None:
+ r"""Given correct, then html.
+
+ Given: \begin{tabular}
When: N/A
Then: .
"""
- assert begin_tabular(r"\begin{tabular}") == ""
+ expect_equal(begin_tabular(r"\begin{tabular}"), "")
-def test_begin_tabular():
+def test_begin_tabular() -> None:
+ """Exercise begin tabular."""
given_correct_then_html()
given_empty_then_error()
given_misspeled_then_error()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py b/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py
index 57d72abd..5fd1b590 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_command_name_check.py
@@ -1,23 +1,32 @@
+"""Tests the command name check."""
+
from translator.main import command_name_check
-
-def given_valid_then_empty():
- assert command_name_check("{documentclass}", "documentclass") == ""
+from unit_tests.expect import expect_equal
-def given_valid_begin_then_empty():
- assert command_name_check("{begin}", "begin") == ""
+def given_valid_then_empty() -> None:
+ """Given valid, then empty."""
+ expect_equal(command_name_check("{documentclass}", "documentclass"), "")
-def given_invalid_then_error():
- assert command_name_check("{documentclasS}", "documentclass") == "Error!"
+def given_valid_begin_then_empty() -> None:
+ """Given valid begin, then empty."""
+ expect_equal(command_name_check("{begin}", "begin"), "")
-def given_invalid_begin_then_error():
- assert command_name_check("{begIn}", "begin") == "Error!"
+def given_invalid_then_error() -> None:
+ """Given invalid, then error."""
+ expect_equal(command_name_check("{documentclasS}", "documentclass"), "Error!")
-def test_command_name_check():
+def given_invalid_begin_then_error() -> None:
+ """Given invalid begin, then error."""
+ expect_equal(command_name_check("{begIn}", "begin"), "Error!")
+
+
+def test_command_name_check() -> None:
+ """Exercise command name check."""
given_valid_then_empty()
given_valid_begin_then_empty()
given_invalid_then_error()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py b/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py
index bf8df2dc..4bef0a88 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_document_class.py
@@ -2,74 +2,93 @@
from translator.main import document_class
+from unit_tests.expect import expect_equal
+
# Write python tests for a function translating LaTeX documentclass to html
-def given_empty_then_error():
- """Given: ""
+def given_empty_then_error() -> None:
+ """Given empty, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert document_class("") == "Error!"
+ expect_equal(document_class(""), "Error!")
-def given_not_closed_then_error():
- """Given: "\\documentclass{article"
+def given_not_closed_then_error() -> None:
+ r"""Given not closed, then error.
+
+ Given: "\\documentclass{article"
When: N/A
Then: Error message.
"""
- assert document_class("\\documentclass{article") == "Error!"
+ expect_equal(document_class("\\documentclass{article"), "Error!")
-def given_parameters_then_error():
- """Given: class parameters
+def given_parameters_then_error() -> None:
+ """Given parameters, then error.
+
+ Given: class parameters
When: N/A
Then: Error message.
"""
- assert document_class("\\documentclass[12pt]{article}") == "Error!"
+ expect_equal(document_class("\\documentclass[12pt]{article}"), "Error!")
-def given_no_opening_then_error():
- """Given: No opening curly bracket
+def given_no_opening_then_error() -> None:
+ """Given no opening, then error.
+
+ Given: No opening curly bracket
When: N/A
Then: Error message.
"""
- assert document_class("\\documentclassarticle}") == "Error!"
+ expect_equal(document_class("\\documentclassarticle}"), "Error!")
-def given_misspeled_then_error():
- """Given: misspelled document class
+def given_misspeled_then_error() -> None:
+ """Given misspeled, then error.
+
+ Given: misspelled document class
When: N/A
Then: Error message.
"""
- assert document_class("\\documentclasZ{article}") == "Error!"
+ expect_equal(document_class("\\documentclasZ{article}"), "Error!")
-def given_class_not_recognized_then_error():
- """Given: class not recognized
+def given_class_not_recognized_then_error() -> None:
+ """Given class not recognized, then error.
+
+ Given: class not recognized
When: N/A
Then: Error message.
"""
- assert document_class("\\documentclass{idonotexist}") == ""
+ expect_equal(document_class("\\documentclass{idonotexist}"), "")
-def given_no_slash_then_error():
- """Given: no backslash at start
+def given_no_slash_then_error() -> None:
+ """Given no slash, then error.
+
+ Given: no backslash at start
When: N/A
Then: Error message.
"""
- assert document_class("documentclass{article}") == "Error!"
+ expect_equal(document_class("documentclass{article}"), "Error!")
-def given_correct_then_html():
- """Given: \\documentclass{article}
+def given_correct_then_html() -> None:
+ r"""Given correct, then html.
+
+ Given: \\documentclass{article}
When: N/A
Then: .
"""
- assert document_class("\\documentclass{article}") == ""
+ expect_equal(document_class("\\documentclass{article}"), "")
-def test_document_class():
+def test_document_class() -> None:
+ """Exercise document class."""
given_correct_then_html()
given_class_not_recognized_then_error()
given_empty_then_error()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py b/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py
index b85f22ea..9f85a322 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_document_class_only_checks.py
@@ -1,19 +1,27 @@
+"""Tests the documentclass-only checks."""
+
from translator.main import document_class_only_checks
-
-def test_missing_curly_bracket():
- assert document_class_only_checks("\\documentclass") == "Error!"
+from unit_tests.expect import expect_equal
-def test_missing_command_name():
- assert document_class_only_checks("\\otherclass{}") == "Error!"
+def test_missing_curly_bracket() -> None:
+ """Exercise missing curly bracket."""
+ expect_equal(document_class_only_checks("\\documentclass"), "Error!")
-def test_correct_input():
- assert document_class_only_checks("\\documentclass{}") == ""
+def test_missing_command_name() -> None:
+ """Exercise missing command name."""
+ expect_equal(document_class_only_checks("\\otherclass{}"), "Error!")
-def test_document_class_only_checks():
+def test_correct_input() -> None:
+ """Exercise correct input."""
+ expect_equal(document_class_only_checks("\\documentclass{}"), "")
+
+
+def test_document_class_only_checks() -> None:
+ """Exercise document class only checks."""
test_missing_curly_bracket()
test_missing_command_name()
test_correct_input()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py
index eb0006a0..ae7802cd 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks.py
@@ -1,19 +1,27 @@
+"""Tests the generic command checks."""
+
from translator.main import generic_checks
-
-def test_empty_string():
- assert generic_checks("") == "Error!"
+from unit_tests.expect import expect_equal
-def test_no_curly_bracket():
- assert generic_checks("latex_string_without_curly_bracket") == "Error!"
+def test_empty_string() -> None:
+ """Exercise empty string."""
+ expect_equal(generic_checks(""), "Error!")
-def test_with_curly_bracket_at_end():
- assert generic_checks("latex_string_with_curly_bracket}") == ""
+def test_no_curly_bracket() -> None:
+ """Exercise no curly bracket."""
+ expect_equal(generic_checks("latex_string_without_curly_bracket"), "Error!")
-def test_generic_checks():
+def test_with_curly_bracket_at_end() -> None:
+ """Exercise with curly bracket at end."""
+ expect_equal(generic_checks("latex_string_with_curly_bracket}"), "")
+
+
+def test_generic_checks() -> None:
+ """Exercise generic checks."""
test_empty_string()
test_no_curly_bracket()
test_with_curly_bracket_at_end()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py
index 9cccc3de..bc6a7f7d 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_generic_checks_command.py
@@ -1,27 +1,36 @@
+"""Tests the generic checks for a command."""
+
from translator.main import generic_checks_command
-
-def test_empty_string():
- assert (generic_checks_command("")) == "Error!"
+from unit_tests.expect import expect_equal
-def test_no_curly_bracket():
- assert (generic_checks_command("latex_string_without_curly_bracket")) == "Error!"
+def test_empty_string() -> None:
+ """Exercise empty string."""
+ expect_equal(generic_checks_command(""), "Error!")
-def test_no_slash_at_beginning():
- assert (
- generic_checks_command("latex_string_without_slash_at_beginning}")
- ) == "Error!"
+def test_no_curly_bracket() -> None:
+ """Exercise no curly bracket."""
+ expect_equal(generic_checks_command("latex_string_without_curly_bracket"), "Error!")
-def test_with_slash_and_curly_bracket():
- assert (
- generic_checks_command("\\latex_string_with_slash_and_curly_bracket}")
- ) == ""
+def test_no_slash_at_beginning() -> None:
+ """Exercise no slash at beginning."""
+ expect_equal(
+ generic_checks_command("latex_string_without_slash_at_beginning}"), "Error!"
+ )
-def test_generic_checks_command():
+def test_with_slash_and_curly_bracket() -> None:
+ """Exercise with slash and curly bracket."""
+ expect_equal(
+ generic_checks_command("\\latex_string_with_slash_and_curly_bracket}"), ""
+ )
+
+
+def test_generic_checks_command() -> None:
+ """Exercise generic checks command."""
test_empty_string()
test_no_curly_bracket()
test_no_slash_at_beginning()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py b/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py
index 7cfcd521..32d1d565 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_length_conversions.py
@@ -2,90 +2,113 @@
from translator.main import length_conversions
+from unit_tests.expect import expect_equal
+
# Write python tests for a function translating LaTeX documentclass to html
-def given_empty_then_error():
- """Given: ""
+def given_empty_then_error() -> None:
+ """Given empty, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("") == "Error!"
+ expect_equal(length_conversions(""), "Error!")
-def given_pt_then_px():
- """Given: ""
+def given_pt_then_px() -> None:
+ """Given pt, then px.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("pt") == [1.3, "px"]
+ expect_equal(length_conversions("pt"), [1.3, "px"])
-def given_mm_then_mm():
- """Given: ""
+def given_mm_then_mm() -> None:
+ """Given mm, then mm.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("mm") == [1, "mm"]
+ expect_equal(length_conversions("mm"), [1, "mm"])
-def given_cm_then_cm():
- """Given: ""
+def given_cm_then_cm() -> None:
+ """Given cm, then cm.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("cm") == [1, "cm"]
+ expect_equal(length_conversions("cm"), [1, "cm"])
-def given_in_then_in():
- """Given: ""
+def given_in_then_in() -> None:
+ """Given in, then in.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("in") == [1, "in"]
+ expect_equal(length_conversions("in"), [1, "in"])
-def given_ex_then_ex():
- """Given: ""
+def given_ex_then_ex() -> None:
+ """Given ex, then ex.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("ex") == [1, "ex"]
+ expect_equal(length_conversions("ex"), [1, "ex"])
-def given_em_then_em():
- """Given: ""
+def given_em_then_em() -> None:
+ """Given em, then em.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("em") == [1, "em"]
+ expect_equal(length_conversions("em"), [1, "em"])
-def given_mu_then_error():
- """Given: ""
+def given_mu_then_error() -> None:
+ """Given mu, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("mu") == "Error!"
+ expect_equal(length_conversions("mu"), "Error!")
-def given_sp_then_error():
- """Given: ""
+def given_sp_then_error() -> None:
+ """Given sp, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("sp") == "Error!"
+ expect_equal(length_conversions("sp"), "Error!")
-def given_unknown_then_error():
- """Given: ""
+def given_unknown_then_error() -> None:
+ """Given unknown, then error.
+
+ Given: ""
When: N/A
Then: Error message.
"""
- assert length_conversions("unknown") == "Error!"
+ expect_equal(length_conversions("unknown"), "Error!")
-def test_begin_tabular():
+def test_begin_tabular() -> None:
+ """Exercise begin tabular."""
given_empty_then_error()
given_pt_then_px()
given_mm_then_mm()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py b/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py
index d6d7024f..7d7f1818 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_only_pipes_and_space.py
@@ -1,27 +1,37 @@
+"""Tests the only-pipes-and-space predicate."""
+
from translator.main import only_pipes_and_space
-
-def given_empty_then_true():
- assert only_pipes_and_space("") == True
+from unit_tests.expect import expect_false, expect_true
-def given_only_pipes_then_true():
- assert only_pipes_and_space("|||||") == True
+def given_empty_then_true() -> None:
+ """Given empty, then true."""
+ expect_true(only_pipes_and_space(""))
-def given_only_space_then_true():
- assert only_pipes_and_space(" ") == True
+def given_only_pipes_then_true() -> None:
+ """Given only pipes, then true."""
+ expect_true(only_pipes_and_space("|||||"))
-def given_space_and_pipes_then_true():
- assert only_pipes_and_space("| | ||| |") == True
+def given_only_space_then_true() -> None:
+ """Given only space, then true."""
+ expect_true(only_pipes_and_space(" "))
-def given_not_space_nor_pipes_then_false():
- assert only_pipes_and_space(" || || a") == False
+def given_space_and_pipes_then_true() -> None:
+ """Given space and pipes, then true."""
+ expect_true(only_pipes_and_space("| | ||| |"))
-def test_only_pipes_and_space():
+def given_not_space_nor_pipes_then_false() -> None:
+ """Given not space nor pipes, then false."""
+ expect_false(only_pipes_and_space(" || || a"))
+
+
+def test_only_pipes_and_space() -> None:
+ """Exercise only pipes and space."""
given_empty_then_true()
given_only_pipes_then_true()
given_only_space_then_true()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py b/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py
index fe734d06..f07e1b36 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_split_columns.py
@@ -1,27 +1,37 @@
+"""Tests splitting a tabular row into columns."""
+
from translator.main import split_columns
-
-def given_empty_then_correct():
- assert split_columns("", 0) == [""]
+from unit_tests.expect import expect_equal
-def given_no_and_then_correct():
- assert split_columns("estsegsegtswegseg", 1) == ["estsegsegtswegseg"]
+def given_empty_then_correct() -> None:
+ """Given empty, then correct."""
+ expect_equal(split_columns("", 0), [""])
-def given_single_and_then_correct():
- assert split_columns("&", 2) == ["", ""]
+def given_no_and_then_correct() -> None:
+ """Given no and, then correct."""
+ expect_equal(split_columns("estsegsegtswegseg", 1), ["estsegsegtswegseg"])
-def given_too_much_columns_then_error():
- assert split_columns("test & 2 & test", 1) == "Error!"
+def given_single_and_then_correct() -> None:
+ """Given single and, then correct."""
+ expect_equal(split_columns("&", 2), ["", ""])
-def given_default_then_correct():
- assert split_columns("test & 2 & test", 3) == ["test ", " 2 ", " test"]
+def given_too_much_columns_then_error() -> None:
+ """Given too much columns, then error."""
+ expect_equal(split_columns("test & 2 & test", 1), "Error!")
-def test_split_columns():
+def given_default_then_correct() -> None:
+ """Given default, then correct."""
+ expect_equal(split_columns("test & 2 & test", 3), ["test ", " 2 ", " test"])
+
+
+def test_split_columns() -> None:
+ """Exercise split columns."""
given_empty_then_correct()
given_no_and_then_correct()
given_single_and_then_correct()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py b/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py
index 8cf12c1f..6e1cf391 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_split_rows.py
@@ -1,24 +1,33 @@
+"""Tests splitting a tabular body into rows."""
+
from translator.main import split_rows
-
-def given_empty_then_correct():
- assert split_rows("") == [""]
+from unit_tests.expect import expect_equal
-def given_no_slash_then_correct():
- assert split_rows("estsegsegtswegseg") == ["estsegsegtswegseg"]
+def given_empty_then_correct() -> None:
+ """Given empty, then correct."""
+ expect_equal(split_rows(""), [""])
-def given_double_slash_then_correct():
- assert split_rows("\\") == ["", ""]
+def given_no_slash_then_correct() -> None:
+ """Given no slash, then correct."""
+ expect_equal(split_rows("estsegsegtswegseg"), ["estsegsegtswegseg"])
-def given_actual_string_then_correct():
+def given_double_slash_then_correct() -> None:
+ """Given double slash, then correct."""
+ expect_equal(split_rows("\\"), ["", ""])
+
+
+def given_actual_string_then_correct() -> None:
+ """Given actual string, then correct."""
actual_string = "test & 2 & test \\ 4 & 5 & 6"
- assert split_rows(actual_string) == ["test & 2 & test ", " 4 & 5 & 6"]
+ expect_equal(split_rows(actual_string), ["test & 2 & test ", " 4 & 5 & 6"])
-def test_split_rows():
+def test_split_rows() -> None:
+ """Exercise split rows."""
given_empty_then_correct()
given_no_slash_then_correct()
given_double_slash_then_correct()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py
index cc01ea1d..971185bc 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_columns_parameters.py
@@ -1,56 +1,71 @@
+"""Tests the tabular column parameters."""
+
from translator.main import tabular_columns_parameters
+from unit_tests.expect import expect_equal
-def given_empty_then_error():
- """Given:
+
+def given_empty_then_error() -> None:
+ """Given empty, then error.
+
+ Given:
When: N/A
Then: .
"""
- assert tabular_columns_parameters("") == "Error!"
+ expect_equal(tabular_columns_parameters(""), "Error!")
-def given_unknown_then_error():
- """Given:
+def given_unknown_then_error() -> None:
+ """Given unknown, then error.
+
+ Given:
When: N/A
Then: .
"""
- assert tabular_columns_parameters("l{1.3cm}") == "Error!"
+ expect_equal(tabular_columns_parameters("l{1.3cm}"), "Error!")
-def given_p_then_array():
- """Given:
+def given_p_then_array() -> None:
+ """Given p, then array.
+
+ Given:
When: N/A
Then: .
"""
- assert (
- tabular_columns_parameters("p{1.3pt}")
- == "style='vertical-align: top; width: 1.69px;'"
+ expect_equal(
+ tabular_columns_parameters("p{1.3pt}"),
+ "style='vertical-align: top; width: 1.69px;'",
)
-def given_m_then_array():
- """Given:
+def given_m_then_array() -> None:
+ """Given m, then array.
+
+ Given:
When: N/A
Then: .
"""
- assert (
- tabular_columns_parameters("m{1.3pt}")
- == "style='vertical-align: middle; width: 1.69px;'"
+ expect_equal(
+ tabular_columns_parameters("m{1.3pt}"),
+ "style='vertical-align: middle; width: 1.69px;'",
)
-def given_b_then_array():
- """Given:
+def given_b_then_array() -> None:
+ """Given b, then array.
+
+ Given:
When: N/A
Then: .
"""
- assert (
- tabular_columns_parameters("b{1.3pt}")
- == "style='vertical-align: bottom; width: 1.69px;'"
+ expect_equal(
+ tabular_columns_parameters("b{1.3pt}"),
+ "style='vertical-align: bottom; width: 1.69px;'",
)
-def test_tabular_columns_parameters():
+def test_tabular_columns_parameters() -> None:
+ """Exercise tabular columns parameters."""
given_empty_then_error()
given_unknown_then_error()
given_p_then_array()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py
index 68d81d04..80a11022 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_parameters.py
@@ -2,32 +2,41 @@
from translator.main import tabular_parameters
+from unit_tests.expect import expect_equal
-def given_empty_then_empty():
- """Given:
+
+def given_empty_then_empty() -> None:
+ """Given empty, then empty.
+
+ Given:
When: N/A
Then: .
"""
- assert tabular_parameters("") == ""
+ expect_equal(tabular_parameters(""), "")
-def given_empty_brackets_then_empty():
- """Given: []
+def given_empty_brackets_then_empty() -> None:
+ """Given empty brackets, then empty.
+
+ Given: []
When: N/A
Then: .
"""
- assert tabular_parameters("[]") == ""
+ expect_equal(tabular_parameters("[]"), "")
-def given_non_empty_then_error():
- """Given: [c]
+def given_non_empty_then_error() -> None:
+ """Given non empty, then error.
+
+ Given: [c]
When: N/A
Then: .
"""
- assert tabular_parameters("[c]") == "Error!"
+ expect_equal(tabular_parameters("[c]"), "Error!")
-def test_tabular_parameters():
+def test_tabular_parameters() -> None:
+ """Exercise tabular parameters."""
given_empty_then_empty()
given_empty_brackets_then_empty()
given_non_empty_then_error()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py
index 17d717a4..5e987202 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_tabular_required_parameters.py
@@ -2,134 +2,170 @@
from translator.main import tabular_required_parameters
+from unit_tests.expect import expect_equal
-def given_empty_then_error():
- """Given:
+
+def given_empty_then_error() -> None:
+ """Given empty, then error.
+
+ Given:
When: N/A
Then: .
"""
- assert tabular_required_parameters("") == "Error!"
+ expect_equal(tabular_required_parameters(""), "Error!")
-def given_empty_brackets_then_error():
- """Given: {}
+def given_empty_brackets_then_error() -> None:
+ """Given empty brackets, then error.
+
+ Given: {}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{}") == "Error!"
+ expect_equal(tabular_required_parameters("{}"), "Error!")
-def given_just_line_then_error():
- """Given: {}
+def given_just_line_then_error() -> None:
+ """Given just line, then error.
+
+ Given: {}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{|}") == "Error!"
+ expect_equal(tabular_required_parameters("{|}"), "Error!")
-def given_just_lines_then_error():
- """Given: {}
+def given_just_lines_then_error() -> None:
+ """Given just lines, then error.
+
+ Given: {}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{|||||||}") == "Error!"
+ expect_equal(tabular_required_parameters("{|||||||}"), "Error!")
-def given_single_left_then_correct():
- """Given: {l}
+def given_single_left_then_correct() -> None:
+ """Given single left, then correct.
+
+ Given: {l}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{l}") == ["align='left'"]
+ expect_equal(tabular_required_parameters("{l}"), ["align='left'"])
-def given_single_center_then_correct():
- """Given: {c}
+def given_single_center_then_correct() -> None:
+ """Given single center, then correct.
+
+ Given: {c}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{c}") == ["align='center'"]
+ expect_equal(tabular_required_parameters("{c}"), ["align='center'"])
-def given_single_right_then_correct():
- """Given: {r}
+def given_single_right_then_correct() -> None:
+ """Given single right, then correct.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{r}") == ["align='right'"]
+ expect_equal(tabular_required_parameters("{r}"), ["align='right'"])
-def given_empty_wrap_p_then_error():
- """Given: {r}
+def given_empty_wrap_p_then_error() -> None:
+ """Given empty wrap p, then error.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{p}") == "Error!"
+ expect_equal(tabular_required_parameters("{p}"), "Error!")
-def given_empty_wrap_m_then_error():
- """Given: {r}
+def given_empty_wrap_m_then_error() -> None:
+ """Given empty wrap m, then error.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{m}") == "Error!"
+ expect_equal(tabular_required_parameters("{m}"), "Error!")
-def given_empty_wrap_b_then_error():
- """Given: {r}
+def given_empty_wrap_b_then_error() -> None:
+ """Given empty wrap b, then error.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{b}") == "Error!"
+ expect_equal(tabular_required_parameters("{b}"), "Error!")
-def given_empty_wrap_p_brackets_then_error():
- """Given: {r}
+def given_empty_wrap_p_brackets_then_error() -> None:
+ """Given empty wrap p brackets, then error.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{p{}}") == "Error!"
+ expect_equal(tabular_required_parameters("{p{}}"), "Error!")
-def given_empty_wrap_m_brackets_then_error():
- """Given: {r}
+def given_empty_wrap_m_brackets_then_error() -> None:
+ """Given empty wrap m brackets, then error.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{m{}}") == "Error!"
+ expect_equal(tabular_required_parameters("{m{}}"), "Error!")
-def given_empty_wrap_b_brackets_then_error():
- """Given: {r}
+def given_empty_wrap_b_brackets_then_error() -> None:
+ """Given empty wrap b brackets, then error.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{b{}}") == "Error!"
+ expect_equal(tabular_required_parameters("{b{}}"), "Error!")
-def given_filled_p_brackets_then_correct():
- """Given: {r}
+def given_filled_p_brackets_then_correct() -> None:
+ """Given filled p brackets, then correct.
+
+ Given: {r}
When: N/A
Then: .
"""
- assert tabular_required_parameters("{p{1.3pt}}") == [
- "style='vertical-align: top; width: 1.69px;'"
- ]
+ expect_equal(
+ tabular_required_parameters("{p{1.3pt}}"),
+ ["style='vertical-align: top; width: 1.69px;'"],
+ )
-def given_complicated_then_correct():
- assert tabular_required_parameters("{|lp{1.3pt}c|r|}") == [
- "style='border-left: 1px solid black'",
- "align='left'",
- "style='vertical-align: top; width: 1.69px;'",
- "align='center'",
- "style='border-left: 1px solid black'",
- "align='right'",
- "style='border-left: 1px solid black'",
- ]
+def given_complicated_then_correct() -> None:
+ """Given complicated, then correct."""
+ expect_equal(
+ tabular_required_parameters("{|lp{1.3pt}c|r|}"),
+ [
+ "style='border-left: 1px solid black'",
+ "align='left'",
+ "style='vertical-align: top; width: 1.69px;'",
+ "align='center'",
+ "style='border-left: 1px solid black'",
+ "align='right'",
+ "style='border-left: 1px solid black'",
+ ],
+ )
-def test_tabular_required_parameters():
+def test_tabular_required_parameters() -> None:
+ """Exercise tabular required parameters."""
given_empty_then_error()
given_empty_brackets_then_error()
given_just_line_then_error()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py b/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py
index 897f31c0..9438a3d6 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_translate_column.py
@@ -1,30 +1,40 @@
+"""Tests translating one tabular column to HTML."""
+
from translator.main import translate_column
-
-def given_empty_then_correct():
- assert translate_column("") == ""
+from unit_tests.expect import expect_equal
-def given_plain_text_then_correct():
- assert translate_column("plain text") == "plain text"
+def given_empty_then_correct() -> None:
+ """Given empty, then correct."""
+ expect_equal(translate_column(""), "")
-def given_just_hline_then_correct():
- assert translate_column(r"\hline") == "
"
+def given_plain_text_then_correct() -> None:
+ """Given plain text, then correct."""
+ expect_equal(translate_column("plain text"), "plain text")
-def given_just_newline_then_correct():
- assert translate_column("\newline") == "
"
+def given_just_hline_then_correct() -> None:
+ """Given just hline, then correct."""
+ expect_equal(translate_column(r"\hline"), "
")
-def given_all_then_correct():
- assert (
- translate_column("\\hline \newline hline newline test")
- == "
hline newline test"
+def given_just_newline_then_correct() -> None:
+ """Given just newline, then correct."""
+ expect_equal(translate_column("\newline"), "
")
+
+
+def given_all_then_correct() -> None:
+ """Given all, then correct."""
+ expect_equal(
+ translate_column("\\hline \newline hline newline test"),
+ "
hline newline test",
)
-def test_translate_column():
+def test_translate_column() -> None:
+ """Exercise translate column."""
given_empty_then_correct()
given_plain_text_then_correct()
given_just_hline_then_correct()
diff --git a/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py b/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py
index 7b98d8f6..68962c73 100644
--- a/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py
+++ b/Programming/ECOTE/program/unit_tests/test_code/test_translate_inside_to_html.py
@@ -1,15 +1,26 @@
+"""Tests translating a tabular body to HTML."""
+
from translator.main import tabular_required_parameters, translate_inside_to_html
+from unit_tests.expect import expect_equal
-def given_correct_then_correct():
+
+def given_correct_then_correct() -> None:
+ """Given correct, then correct."""
latex_string = "test & 2 & test \\ 4 & 5 & 6 \\"
parameters_string = "{ l | c | r }"
column_styles = tabular_required_parameters(parameters_string)
- assert (
- translate_inside_to_html(latex_string, column_styles)
- == ""
+ expect_equal(
+ translate_inside_to_html(latex_string, column_styles),
+ "",
)
-def test_translate_inside_to_html():
+def test_translate_inside_to_html() -> None:
+ """Exercise translate inside to html."""
given_correct_then_correct()
diff --git a/Programming/ECRYPT_PROJECT/__init__.py b/Programming/ECRYPT_PROJECT/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/Programming/ECRYPT_PROJECT/sieve/__init__.py b/Programming/ECRYPT_PROJECT/sieve/__init__.py
index e69de29b..8ab38c77 100644
--- a/Programming/ECRYPT_PROJECT/sieve/__init__.py
+++ b/Programming/ECRYPT_PROJECT/sieve/__init__.py
@@ -0,0 +1,6 @@
+"""Sieve of Eratosthenes, and the pytest suite that checks it against a table.
+
+The lab's point is not the sieve itself but the verification: every prime and
+every composite below a bound, read from the reference CSVs in this directory,
+becomes its own parametrised test case.
+"""
diff --git a/Programming/ECRYPT_PROJECT/sieve/conftest.py b/Programming/ECRYPT_PROJECT/sieve/conftest.py
index e6d18854..191f4da8 100644
--- a/Programming/ECRYPT_PROJECT/sieve/conftest.py
+++ b/Programming/ECRYPT_PROJECT/sieve/conftest.py
@@ -1,51 +1,61 @@
+"""Turn the reference CSVs into one test case per prime and per composite.
+
+``P-100000.csv`` and ``C-100000.csv`` sit beside this file and are read with a
+relative path, which is why the suite has to be run from this directory (see
+``../run.sh``). ``--primes`` and ``--composites`` cap how far up each table the
+run goes; the defaults keep a plain ``pytest`` fast.
+"""
+
import pandas as pd
import pytest
from .project import sieve_of_eratosthenes
+DEFAULT_BOUND = "100"
-def pytest_addoption(parser):
+
+def pytest_addoption(parser: pytest.Parser) -> None:
+ """Register the two bounds that decide how much of each table is used."""
parser.addoption(
"--primes",
action="store",
- default="100",
+ default=DEFAULT_BOUND,
help="Upper bound for primes to test.",
)
parser.addoption(
"--composites",
action="store",
- default="100",
+ default=DEFAULT_BOUND,
help="Upper bound for composites to test.",
)
-def pytest_configure(config):
+def pytest_configure(config: pytest.Config) -> None:
+ """Stash the parsed bounds where pytest_generate_tests can reach them."""
pytest.primes = int(config.getoption("--primes"))
pytest.composites = int(config.getoption("--composites"))
-def pytest_generate_tests(metafunc):
+def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
+ """Parametrise each test over its half of the reference tables."""
df_prime = pd.read_csv("P-100000.csv", header=None)
df_prime = df_prime[df_prime.iloc[:, 1] < pytest.primes]
primes = set(df_prime.iloc[:, 1])
+ # C-100000.csv is "n=factorisation", so the number is the first column.
df_composite = pd.read_csv("C-100000.csv", header=None, delimiter="=")
- # interpret first oclumns as numbers
df_composite = df_composite[df_composite.iloc[:, 0] < pytest.composites]
composites = set(df_composite.iloc[:, 0])
+
if metafunc.function.__name__ == "test_positives":
metafunc.parametrize("prime", primes)
metafunc.parametrize(
"primes_obtained",
- [
- sieve_of_eratosthenes(max(primes) + 1),
- ],
+ [sieve_of_eratosthenes(max(primes) + 1)],
)
if metafunc.function.__name__ == "test_composites":
metafunc.parametrize("composite", composites)
metafunc.parametrize(
"primes_obtained",
- [
- sieve_of_eratosthenes(max(composites) + 1),
- ],
+ [sieve_of_eratosthenes(max(composites) + 1)],
)
diff --git a/Programming/ECRYPT_PROJECT/sieve/project.py b/Programming/ECRYPT_PROJECT/sieve/project.py
index ac3ec671..a29c7b5b 100644
--- a/Programming/ECRYPT_PROJECT/sieve/project.py
+++ b/Programming/ECRYPT_PROJECT/sieve/project.py
@@ -1,10 +1,11 @@
-"""Python program to print all Primes Smaller than or equal to N using Sieve of Eratosthenes."""
+"""Sieve of Eratosthenes: every prime up to and including N."""
import math
+import sys
def sieve_of_eratosthenes(num: int) -> list[int]:
- """Finds all prime number from 1 to num.
+ """Return every prime from 1 to num.
Args:
num (int): Number up to which the prime numbers should be printed
@@ -14,12 +15,13 @@ def sieve_of_eratosthenes(num: int) -> list[int]:
"""
if num <= 0:
- raise ValueError("Number should not be negative.")
+ msg = "Number should not be negative."
+ raise ValueError(msg)
# boolean list to store if a number is prime or not
prime = [True] * (num + 1)
p = 2 # starting prime number
- # we will iterate till square root of num because
- # if a number is not prime then it will have a factor less than or equal to square root of that number
+ # Stop at sqrt(num): a composite always has a factor at or below its
+ # square root, so anything still marked prime past that point stays prime.
while p <= math.sqrt(num):
# If prime[p] is not
# changed, then it is a prime
@@ -34,18 +36,20 @@ def sieve_of_eratosthenes(num: int) -> list[int]:
def print_sieve(num: int) -> None:
- """Prints all prime number from 1 to num.
+ """Print every prime from 1 to num, space separated.
Args:
num (int): Number up to which the prime numbers should be printed
"""
- for number in sieve_of_eratosthenes(num):
- print(number, end=" ")
+ sys.stdout.write(" ".join(str(n) for n in sieve_of_eratosthenes(num)))
+ sys.stdout.write("\n")
# Driver code
if __name__ == "__main__":
- num = int(input("Enter a number: "))
- print(f"Following are the prime numbers smaller than or equal to {num}")
- print_sieve(num)
+ bound = int(input("Enter a number: "))
+ sys.stdout.write(
+ f"Following are the prime numbers smaller than or equal to {bound}\n"
+ )
+ print_sieve(bound)
diff --git a/Programming/ECRYPT_PROJECT/sieve/test_main.py b/Programming/ECRYPT_PROJECT/sieve/test_main.py
index 25f456b7..37fafeae 100644
--- a/Programming/ECRYPT_PROJECT/sieve/test_main.py
+++ b/Programming/ECRYPT_PROJECT/sieve/test_main.py
@@ -1,16 +1,33 @@
+"""Check the sieve against the reference prime and composite tables.
+
+Both parametrised fixtures come from ``conftest.py``, which reads the CSVs in
+this directory -- so "a prime" here means a number this course was given as
+prime, not one this code decided was prime.
+
+The assertions raise instead of using ``assert``: this repo runs ruff with
+``select = ["ALL"]`` and no per-file-ignores, and a bare assert is ``S101``.
+"""
+
import pytest
from .project import sieve_of_eratosthenes
-def test_positives(prime, primes_obtained):
- assert prime in primes_obtained
+def test_positives(prime: int, primes_obtained: list[int]) -> None:
+ """Every number the reference table calls prime is found by the sieve."""
+ if prime not in primes_obtained:
+ msg = f"{prime} is prime but the sieve did not report it"
+ raise AssertionError(msg)
-def test_composites(composite, primes_obtained):
- assert composite not in primes_obtained
+def test_composites(composite: int, primes_obtained: list[int]) -> None:
+ """No number the reference table calls composite is reported as prime."""
+ if composite in primes_obtained:
+ msg = f"{composite} is composite but the sieve reported it as prime"
+ raise AssertionError(msg)
-def test_negatives():
- with pytest.raises(ValueError):
+def test_negatives() -> None:
+ """A non-positive bound is rejected rather than silently returning []."""
+ with pytest.raises(ValueError, match="should not be negative"):
sieve_of_eratosthenes(-1)