1
0
Fork 0
mirror of synced 2024-12-04 14:45:36 -05:00
yadm/test/test_unit_template_default.py
Erik Flodin 8ba9823407
Rewrite default template to handle nested ifs, != and env vars in if
The awk script now performs all processing in the BEGIN block using an
implementation that is capable of handling if statements which contain nested
if statments (fixes #436). To make nested ifs look better, if, else and endif
lines can now have optional whitespace before {%.

Includes are now handled in the same way as the main file which means that
included files can both include other files and have if statements in addition
to variables (fixes #406). Include lines can now also have optional whitespace
before {%.

All variables are handled in the same way now so it's now possible to use env
variables in if statements (fixes #488).

Also add support for != in addition to == (fixes #358). Thus it's now
e.g. possible to check if a variable is set (#477) by doing:

{% if yadm.class != ""%}
Class is set to {{ yadm.class }}
{% endif %}

A non-existing yadm or env variable is now replaced with the empty string.
2024-11-04 22:30:23 +01:00

331 lines
9.1 KiB
Python

"""Unit tests: template_default"""
import os
FILE_MODE = 0o754
# these values are also testing the handling of bizarre characters
LOCAL_CLASS = "default_Test+@-!^Class"
LOCAL_CLASS2 = "default_Test+@-|^2nd_Class withSpace"
LOCAL_ARCH = "default_Test+@-!^Arch"
LOCAL_SYSTEM = "default_Test+@-!^System"
LOCAL_HOST = "default_Test+@-!^Host"
LOCAL_USER = "default_Test+@-!^User"
LOCAL_DISTRO = "default_Test+@-!^Distro"
LOCAL_DISTRO_FAMILY = "default_Test+@-!^Family"
ENV_VAR = "default_Test+@-!^Env"
TEMPLATE = f"""
start of template
default class = >{{{{yadm.class}}}}<
default arch = >{{{{yadm.arch}}}}<
default os = >{{{{yadm.os}}}}<
default host = >{{{{yadm.hostname}}}}<
default user = >{{{{yadm.user}}}}<
default distro = >{{{{yadm.distro}}}}<
default distro_family = >{{{{yadm.distro_family}}}}<
classes = >{{{{yadm.classes}}}}<
{{% if yadm.class == "else1" %}}
wrong else 1
{{% else %}}
Included section from else
{{% endif %}}
{{% if yadm.class == "wrongclass1" %}}
wrong class 1
{{% endif %}}
{{% if yadm.class != "wronglcass" %}}
Included section from !=
{{% endif\t\t %}}
{{% if yadm.class == "{LOCAL_CLASS}" %}}
Included section for class = {{{{yadm.class}}}} ({{{{yadm.class}}}} repeated)
Multiple lines
{{% else %}}
Should not be included...
{{% endif %}}
{{% if yadm.class == "{LOCAL_CLASS2}" %}}
Included section for second class
{{% endif %}}
{{% if yadm.class == "wrongclass2" %}}
wrong class 2
{{% endif %}}
{{% if yadm.arch == "wrongarch1" %}}
wrong arch 1
{{% endif %}}
{{% if yadm.arch == "{LOCAL_ARCH}" %}}
Included section for arch = {{{{yadm.arch}}}} ({{{{yadm.arch}}}} repeated)
{{% endif %}}
{{% if yadm.arch == "wrongarch2" %}}
wrong arch 2
{{% endif %}}
{{% if yadm.os == "wrongos1" %}}
wrong os 1
{{% endif %}}
{{% if yadm.os == "{LOCAL_SYSTEM}" %}}
Included section for os = {{{{yadm.os}}}} ({{{{yadm.os}}}} repeated)
{{% endif %}}
{{% if yadm.os == "wrongos2" %}}
wrong os 2
{{% endif %}}
{{% if yadm.hostname == "wronghost1" %}}
wrong host 1
{{% endif %}}
{{% if yadm.hostname == "{LOCAL_HOST}" %}}
Included section for host = {{{{yadm.hostname}}}} ({{{{yadm.hostname}}}} again)
{{% endif %}}
{{% if yadm.hostname == "wronghost2" %}}
wrong host 2
{{% endif %}}
{{% if yadm.user == "wronguser1" %}}
wrong user 1
{{% endif %}}
{{% if yadm.user == "{LOCAL_USER}" %}}
Included section for user = {{{{yadm.user}}}} ({{{{yadm.user}}}} repeated)
{{% endif %}}
{{% if yadm.user == "wronguser2" %}}
wrong user 2
{{% endif %}}
{{% if yadm.distro == "wrongdistro1" %}}
wrong distro 1
{{% endif %}}
{{% if yadm.distro == "{LOCAL_DISTRO}" %}}
Included section for distro = {{{{yadm.distro}}}} ({{{{yadm.distro}}}} again)
{{% endif %}}
{{% if yadm.distro == "wrongdistro2" %}}
wrong distro 2
{{% endif %}}
{{% if yadm.distro_family == "wrongfamily1" %}}
wrong family 1
{{% endif %}}
{{% if yadm.distro_family == "{LOCAL_DISTRO_FAMILY}" %}}
Included section for distro_family = \
{{{{yadm.distro_family}}}} ({{{{yadm.distro_family}}}} again)
{{% endif %}}
{{% if yadm.distro_family == "wrongfamily2" %}}
wrong family 2
{{% endif %}}
{{% if env.VAR == "{ENV_VAR}" %}}
Included section for env.VAR = {{{{env.VAR}}}} ({{{{env.VAR}}}} again)
{{% endif %}}
{{% if env.VAR == "wrongenvvar" %}}
wrong env.VAR
{{% endif %}}
yadm.no_such_var="{{{{ yadm.no_such_var }}}}" and env.NO_SUCH_VAR="{{{{ env.NO_SUCH_VAR }}}}"
end of template
"""
EXPECTED = f"""
start of template
default class = >{LOCAL_CLASS}<
default arch = >{LOCAL_ARCH}<
default os = >{LOCAL_SYSTEM}<
default host = >{LOCAL_HOST}<
default user = >{LOCAL_USER}<
default distro = >{LOCAL_DISTRO}<
default distro_family = >{LOCAL_DISTRO_FAMILY}<
classes = >{LOCAL_CLASS2}
{LOCAL_CLASS}<
Included section from else
Included section from !=
Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated)
Multiple lines
Included section for second class
Included section for arch = {LOCAL_ARCH} ({LOCAL_ARCH} repeated)
Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
Included section for user = {LOCAL_USER} ({LOCAL_USER} repeated)
Included section for distro = {LOCAL_DISTRO} ({LOCAL_DISTRO} again)
Included section for distro_family = \
{LOCAL_DISTRO_FAMILY} ({LOCAL_DISTRO_FAMILY} again)
Included section for env.VAR = {ENV_VAR} ({ENV_VAR} again)
yadm.no_such_var="" and env.NO_SUCH_VAR=""
end of template
"""
INCLUDE_BASIC = "basic\n"
INCLUDE_VARIABLES = """\
included <{{ yadm.class }}> file
empty line above
"""
INCLUDE_NESTED = "no newline at the end"
TEMPLATE_INCLUDE = """\
The first line
{% include empty %}
An empty file removes the line above
{%include basic%}
{% include "./variables.{{ yadm.os }}" %}
{% include dir/nested %}
Include basic again:
{% include basic %}
"""
EXPECTED_INCLUDE = f"""\
The first line
An empty file removes the line above
basic
included <{LOCAL_CLASS}> file
empty line above
no newline at the end
Include basic again:
basic
"""
TEMPLATE_NESTED_IFS = """\
{% if yadm.user == "me" %}
print1
{% if yadm.user == "me" %}
print2
{% else %}
no print1
{% endif %}
{% else %}
{% if yadm.user == "me" %}
no print2
{% else %}
no print3
{% endif %}
{% endif %}
{% if yadm.user != "me" %}
no print4
{% if yadm.user == "me" %}
no print5
{% else %}
no print6
{% endif %}
{% else %}
{% if yadm.user == "me" %}
print3
{% else %}
no print7
{% endif %}
{% endif %}
"""
EXPECTED_NESTED_IFS = """\
print1
print2
print3
"""
def test_template_default(runner, yadm, tmpdir):
"""Test template_default"""
input_file = tmpdir.join("input")
input_file.write(TEMPLATE, ensure=True)
input_file.chmod(FILE_MODE)
output_file = tmpdir.join("output")
# ensure overwrite works when file exists as read-only (there is some
# special processing when this is encountered because some environments do
# not properly overwrite read-only files)
output_file.write("existing")
output_file.chmod(0o400)
script = f"""
YADM_TEST=1 source {yadm}
set_awk
local_class="{LOCAL_CLASS}"
local_classes=("{LOCAL_CLASS2}" "{LOCAL_CLASS}")
local_arch="{LOCAL_ARCH}"
local_system="{LOCAL_SYSTEM}"
local_host="{LOCAL_HOST}"
local_user="{LOCAL_USER}"
local_distro="{LOCAL_DISTRO}"
local_distro_family="{LOCAL_DISTRO_FAMILY}"
template_default "{input_file}" "{output_file}"
"""
run = runner(command=["bash"], inp=script, env={"VAR": ENV_VAR})
assert run.success
assert run.err == ""
assert output_file.read() == EXPECTED
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
def test_source(runner, yadm, tmpdir):
"""Test yadm.source"""
input_file = tmpdir.join("input")
input_file.write("{{yadm.source}}", ensure=True)
input_file.chmod(FILE_MODE)
output_file = tmpdir.join("output")
script = f"""
YADM_TEST=1 source {yadm}
set_awk
template_default "{input_file}" "{output_file}"
"""
run = runner(command=["bash"], inp=script)
assert run.success
assert run.err == ""
assert output_file.read().strip() == str(input_file)
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
def test_include(runner, yadm, tmpdir):
"""Test include"""
empty_file = tmpdir.join("empty")
empty_file.write("", ensure=True)
basic_file = tmpdir.join("basic")
basic_file.write(INCLUDE_BASIC)
variables_file = tmpdir.join(f"variables.{LOCAL_SYSTEM}")
variables_file.write(INCLUDE_VARIABLES)
nested_file = tmpdir.join("dir").join("nested")
nested_file.write(INCLUDE_NESTED, ensure=True)
input_file = tmpdir.join("input")
input_file.write(TEMPLATE_INCLUDE)
input_file.chmod(FILE_MODE)
output_file = tmpdir.join("output")
script = f"""
YADM_TEST=1 source {yadm}
set_awk
local_class="{LOCAL_CLASS}"
local_system="{LOCAL_SYSTEM}"
template_default "{input_file}" "{output_file}"
"""
run = runner(command=["bash"], inp=script)
assert run.success
assert run.err == ""
assert output_file.read() == EXPECTED_INCLUDE
assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
def test_nested_ifs(runner, yadm, tmpdir):
"""Test nested if statements"""
input_file = tmpdir.join("input")
input_file.write(TEMPLATE_NESTED_IFS, ensure=True)
output_file = tmpdir.join("output")
script = f"""
YADM_TEST=1 source {yadm}
set_awk
local_user="me"
template_default "{input_file}" "{output_file}"
"""
run = runner(command=["bash"], inp=script)
assert run.success
assert run.err == ""
assert output_file.read() == EXPECTED_NESTED_IFS
def test_env(runner, yadm, tmpdir):
"""Test env"""
input_file = tmpdir.join("input")
input_file.write("{{env.PWD}}", ensure=True)
output_file = tmpdir.join("output")
script = f"""
YADM_TEST=1 source {yadm}
set_awk
template_default "{input_file}" "{output_file}"
"""
run = runner(command=["bash"], inp=script)
assert run.success
assert run.err == ""
assert output_file.read().strip() == os.environ["PWD"]