mirror of
https://github.com/kuhyx/WUT_Computer_Science.git
synced 2026-11-10 19:07:11 +01:00
ECOTE and ECRYPT_PROJECT: zero findings, tests still green
kuhy chose the strict branch: no per-file-ignores at all, not even the S101 block that ruff's own docs and the rest of this fleet carry for test code. So 125 test assertions were rewritten to raise instead of assert. Rather than 125 copies of `if x != y: raise AssertionError(...)`, each course grows a small expect module -- expect_equal / expect_in / expect_true / expect_false. That is also strictly better output than a bare assert here: pytest's assertion rewriting does not reach into a helper, so the helper has to print both values, and it does. The rewrite itself went through ast, not a regex, because seven of ECOTE's asserts were wrapped over several lines. Everything else in the two courses is gone as well: - 66 argument and 37 return annotations on the translator, worked out from what each function actually returns rather than stamped on as Any -- `list[str] | str` where a function returns "Error!" or the parsed columns. - 16 prints became logger.error with %-style arguments. The messages still reach stderr with no basicConfig, via logging's last-resort handler, so the translator behaves exactly as before. - Two `open()` calls became Path.open / Path.write_text, six RET504 assign-then-return pairs collapsed, one 380-character expected-HTML literal split into implicitly concatenated pieces (it cannot be wrapped any other way, which is what ISC001 being off is for), and one block of commented-out code deleted. - ECRYPT_PROJECT/__init__.py removed. It made the COURSE directory a package, which nothing imports, and it was the sole cause of `N999 Invalid module name: 'ECRYPT_PROJECT'`; with it gone, sieve is the top-level package and its name is fine. Verified by running both, not by reading: ECOTE 26 tests pass and `python -m translator.main --filename examples/complicated/table1.tex` still writes the same HTML with the same three column-count warnings on stderr; ECRYPT_PROJECT 99 tests pass. Repo-wide: 3,686 findings -> 3,159. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
This commit is contained in:
parent
bd24dd57ea
commit
a8a2710ebd
@ -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.
|
||||
|
||||
@ -0,0 +1 @@
|
||||
"""LaTeX-subset to HTML translator: the ECOTE project deliverable."""
|
||||
@ -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 "<!DOCTYPE html>"
|
||||
|
||||
|
||||
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 "<html>"
|
||||
|
||||
|
||||
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 "<table>"
|
||||
|
||||
|
||||
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, "<hr>")
|
||||
replaced_newline = replaced_hline.replace("\newline", "<br>")
|
||||
return replaced_newline
|
||||
return replaced_hline.replace("\newline", "<br>")
|
||||
|
||||
|
||||
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 += "<td "
|
||||
if column_number >= 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 += "<tr>"
|
||||
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 = "<table>"
|
||||
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")
|
||||
|
||||
@ -0,0 +1 @@
|
||||
"""Unit tests for the ECOTE LaTeX-to-HTML translator."""
|
||||
40
Programming/ECOTE/program/unit_tests/expect.py
Normal file
40
Programming/ECOTE/program/unit_tests/expect.py
Normal file
@ -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)
|
||||
@ -0,0 +1 @@
|
||||
"""One module per translator function under test."""
|
||||
@ -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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
assert begin_document(r"\begin{document}") == "<html>"
|
||||
expect_equal(begin_document(r"\begin{document}"), "<html>")
|
||||
|
||||
|
||||
def test_begin_document():
|
||||
def test_begin_document() -> None:
|
||||
"""Exercise begin document."""
|
||||
given_correct_then_html()
|
||||
given_empty_then_error()
|
||||
given_misspeled_then_error()
|
||||
|
||||
@ -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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
assert begin_tabular(r"\begin{tabular}") == "<table>"
|
||||
expect_equal(begin_tabular(r"\begin{tabular}"), "<table>")
|
||||
|
||||
|
||||
def test_begin_tabular():
|
||||
def test_begin_tabular() -> None:
|
||||
"""Exercise begin tabular."""
|
||||
given_correct_then_html()
|
||||
given_empty_then_error()
|
||||
given_misspeled_then_error()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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}") == "<!DOCTYPE html>"
|
||||
expect_equal(document_class("\\documentclass{idonotexist}"), "<!DOCTYPE html>")
|
||||
|
||||
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
assert document_class("\\documentclass{article}") == "<!DOCTYPE html>"
|
||||
expect_equal(document_class("\\documentclass{article}"), "<!DOCTYPE html>")
|
||||
|
||||
|
||||
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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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()
|
||||
|
||||
@ -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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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()
|
||||
|
||||
@ -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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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: <!DOCTYPE html><html>.
|
||||
"""
|
||||
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()
|
||||
|
||||
@ -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") == "<hr>"
|
||||
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") == "<br>"
|
||||
def given_just_hline_then_correct() -> None:
|
||||
"""Given just hline, then correct."""
|
||||
expect_equal(translate_column(r"\hline"), "<hr>")
|
||||
|
||||
|
||||
def given_all_then_correct():
|
||||
assert (
|
||||
translate_column("\\hline \newline hline newline test")
|
||||
== "<hr> <br> hline newline test"
|
||||
def given_just_newline_then_correct() -> None:
|
||||
"""Given just newline, then correct."""
|
||||
expect_equal(translate_column("\newline"), "<br>")
|
||||
|
||||
|
||||
def given_all_then_correct() -> None:
|
||||
"""Given all, then correct."""
|
||||
expect_equal(
|
||||
translate_column("\\hline \newline hline newline test"),
|
||||
"<hr> <br> 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()
|
||||
|
||||
@ -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)
|
||||
== "<table><tr><td align='left'>test </td><td style='border-left: 1px solid black'align='center'> 2 </td><td style='border-left: 1px solid black'align='right'> test </td></tr><tr><td align='left'> 4 </td><td style='border-left: 1px solid black'align='center'> 5 </td><td style='border-left: 1px solid black'align='right'> 6 </td></tr><tr><td align='left'></td></tr></table>"
|
||||
expect_equal(
|
||||
translate_inside_to_html(latex_string, column_styles),
|
||||
"<table><tr><td align='left'>test </td><td style='border-left: 1px so"
|
||||
"lid black'align='center'> 2 </td><td style='border-left: 1px solid b"
|
||||
"lack'align='right'> test </td></tr><tr><td align='left'> 4 </td><td "
|
||||
"style='border-left: 1px solid black'align='center'> 5 </td><td style"
|
||||
"='border-left: 1px solid black'align='right'> 6 </td></tr><tr><td al"
|
||||
"ign='left'></td></tr></table>",
|
||||
)
|
||||
|
||||
|
||||
def test_translate_inside_to_html():
|
||||
def test_translate_inside_to_html() -> None:
|
||||
"""Exercise translate inside to html."""
|
||||
given_correct_then_correct()
|
||||
|
||||
@ -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.
|
||||
"""
|
||||
@ -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)],
|
||||
)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user