fossasia/knittingpattern

View on GitHub
knittingpattern/convert/test/test_save_as_svg.py

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
from test_convert import fixture
from knittingpattern import load_from_relative_file
import untangle
from itertools import chain
import re

INKSCAPE_MESSAGE = "row is usable by inkscape"
TRANSFORM_REGEX = "^translate\(\s*(\S+?)\s*,\s*(\S+?)\s*\)\s*,"\
                  "\s*scale\(\s*(\S+?)\s*\)$"
ZOOM_MESSAGE = "zoom is computed from height"
DEFAULT_ZOOM = 25


def is_close_to(v1, v2, relative_epsilon=0.01):
    return v2 * (1 - relative_epsilon) < v1 < v2 * (1 + relative_epsilon)


@fixture(scope="module")
def patterns_svg():
    return load_from_relative_file(__name__, "test_patterns/block4x4.json")


@fixture(scope="module")
def path(patterns_svg):
    return patterns_svg.to_svg(zoom=DEFAULT_ZOOM).temporary_path(".svg")


@fixture(scope="module")
def svg(path):
    return untangle.parse(path).svg


@fixture
def rows(svg):
    return [("row-{}".format(i), row) for i, row in enumerate(svg.g, 1)]


@fixture
def instructions(rows):
    return chain(*(row.g for _, row in rows))


def rows_test(function):
    def test(rows):
        for row_id, row in rows:
            function(row_id, row)
    return test


def instructions_test(function):
    def test(instructions):
        for instruction in instructions:
            function(instruction)
    return test


def instructions_svg_test(function):
    def test(instructions):
        for instruction in instructions:
            function(instruction, svg, path, patterns_svg)
    return test


def test_svg_contains_four_rows(svg):
    assert len(svg.g) == 4


@rows_test
def test_rows_contain_four_instructions(row_id, row):
    assert len(row.g) == 4


@rows_test
def test_rows_are_labeled_for_inkscape(row_id, row):
    assert row["inkscape:label"] == row_id


@rows_test
def test_row_is_inkscape_layer(row_id, row):
    assert row["inkscape:groupmode"] == "layer"


@rows_test
def test_rows_have_class_for_styling(row_id, row):
    assert row["class"] == "row"


@rows_test
def test_rows_have_id_for_styling(row_id, row):
    assert row["id"] == row_id


@instructions_test
def test_instructions_have_class(instruction):
    assert instruction["class"] == "instruction"


@instructions_test
def test_instructions_have_id(instruction):
    # TODO all ids should be made up from the real ids
    assert instruction["id"].startswith("instruction-")


@instructions_test
def test_instructions_content_is_knit_svg_file(instruction):
    assert instruction.use["xlink:href"].startswith("#knit")


@instructions_svg_test
def test_instructions_have_transform(instruction, svg, path, patterns_svg):
    transform = instruction["transform"]
    x, y, zoom = map(float, re.match(TRANSFORM_REGEX, transform).groups())
    bbox = list(map(float, svg(path(patterns_svg()))["viewBox"].split()))
    assert is_close_to(DEFAULT_ZOOM / (bbox[3] - bbox[1]), zoom), ZOOM_MESSAGE