initialize programmatic tests (with pytest)

An Emacs .org file is the source in to (re)create a Python script
to perform a few tests on date2name's functions to prepend a date/
time stamp.  The .org file equally is source for the Makefile to
automate the testing even further.

Set up for and tested in Linux Debian 12/bookworm (branch testing)
with Python 3.9.2, pytest 6.2.4 (for Python 3); GNU Make 4.3;
GNU Emacs 27.1 backed by elpa org 9.4.0.
This commit is contained in:
Norwid Behrnd 2021-09-02 14:52:09 +00:00
parent 6c8f37277e
commit 2af0ee87df
3 changed files with 528 additions and 0 deletions

20
Makefile Normal file
View file

@ -0,0 +1,20 @@
# GNU Make file for the automation of pytest for date2name.
#
# While the test script is written for Python 3.9.2, you might need to
# adjust the following instruction once in case your OS includes pyest
# for legacy Python 2 side by side to Python 3, or only hosts pytest
# for Python 3. The tests in script test_date2name.py are set up to
# work with pytest for Python 3; dependent on your installation, which
# may be named pytest-3, or (again) pytest.
#
# Put this file like test_date2name.py in the root folder of date2name
# fetched from PyPi or GitHub. Then run
#
# chmod +x *
# make ./Makefile
#
# to run the tests. The test sequence either stops at the first test
# failing, or after completion.
# pytest -xv test_date2name.py # only pytest for Python 3 is present
pytest-3 -xv test_date2name.py # pytest if Python 2 and Python 3 coexist

192
test_date2name.py Normal file
View file

@ -0,0 +1,192 @@
#!/bin/usr/env python3
# name: test_date2name.py
# author: nbehrnd@yahoo.com
# license: GPL v3, 2021.
# date: 2021-08-30 (YYYY-MM-DD)
# edit: 2021-09-02 (YYYY-MM-DD)
#
"""Test pad for functions by date2name with pytest.
Written for Python 3.9.2 and pytest 6.2.4 for Python 3 as provided by
Linux Debian 12/bookworm, branch testing, this is a programmatic check
of functions offered by date2name. Deposit this script in the root of
the folder fetched and unzipped from PyPi or GitHub. If your system
includes both legacy Python 2 and Python 3, pytest for Python 3 likely
is named pytest-3; otherwise only pytest. Thus, adjust your input on
the CLI accordingly when running either one of
pytest -xv test_date2name.py
pytest-3 -xv test_date2name.py
The script either stops when one of the tests fail, or after completion
of the test sequence. In both cases, the progress of the ongoing tests
is reported to the CLI."""
import os
import time
from datetime import datetime
from subprocess import getstatusoutput, getoutput
import pytest
PROGRAM = str("./date2name/__init__.py")
TFILE = str("test_file.txt") # the intermediate test file written
def prepare_testfile():
"""The creation of the test file."""
with open (TFILE, mode="w") as newfile:
newfile.write("This is the test file for test_date2name.py.")
# adjust modification time stamp, based on
# https://stackoverflow.com/questions/53111614/how-to-modify-the-file-modification-date-with-python-on-mac
result = os.stat(TFILE)
os.utime(TFILE, (result.st_atime, result.st_mtime + 10.0))
def query_file_creation():
"""Determine the time of creation of the file."""
created = os.stat(TFILE).st_ctime
created = str(datetime.fromtimestamp(created))
return created
def query_file_modification():
"""Determine the time when the file was modified."""
modified = os.stat(TFILE).st_mtime
modified = str(datetime.fromtimestamp(modified))
return modified
def test_create_remove_testfile():
"""Merely check if the test file may be written and removed."""
prepare_testfile()
os.remove(TFILE)
def test_script_existance():
"""Merely check for the script's presence."""
assert os.path.isfile(PROGRAM)
def test_script_version():
"""Check for the correct output of the version.
CLI equivalence: date2name --version """
out = getoutput(f"python3 {PROGRAM} --version")
assert out.strip() == "__init__.py 2018-05-09"
@pytest.mark.parametrize("arg1", [" ", "-f", "--files",
"-m", "--mtime",
"-c", "--ctime"])
def test_default_pattern_YYYY_MM_DD(arg1):
"""Prepend YYYY-MM-DD to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in [" ", "-f", "--files", "-m", "--mtime"]:
day = query_file_modification().split()[0]
elif arg1 in ["-c", "--ctime"]:
day = query_file_creation().split()[0]
new = "_".join([day, TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
@pytest.mark.parametrize("arg1", ["-C", "--compact",
"-C -f", "--compact -f",
"-C --files", "--compact --files",
"-C -m", "--compact -m",
"-C --mtime", "--compact --mtime",
"-C -c", "--compact -c",
"-C --ctime", "--compact --ctime"])
def test_compact_pattern_YYYYMMDD(arg1):
"""Prepend YYYYMMDD to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in ["-C", "--compact",
"-C -f", "--compact -f",
"-C --files", "--compact --files",
"-C -m", "--compact -m",
"-C --mtime", "--compact --mtime"]:
day = query_file_modification().split()[0]
elif arg1 in ["-C -c", "--compact -c",
"-C --ctime", "--compact --ctime"]:
day = query_file_creation().split()[0]
# drop the hyphens in the date stamp:
day = day.replace("-", "")
new = "_".join([day, TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
@pytest.mark.parametrize("arg1", ["-M", "--month",
"-M -f", "--month -f",
"-M --files", "--month --files",
"-M -m", "--month -m",
"-M --mtime", "--month --mtime",
"-M -c", "--month -c",
"-M --ctime", "--month --ctime"])
def test_compact_monthn_YYYY_MM(arg1):
"""Prepend YYYY-MM to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in ["-M", "--month",
"-M -f", "--month -f",
"-M --files", "--month --files",
"-M -m", "--month -m",
"-M --mtime", "--month --mtime"]:
day = query_file_modification().split()[0]
elif arg1 in ["-M -c", "--month -c",
"-M --ctime", "--month --ctime"]:
day = query_file_creation().split()[0]
# trim off the last three characters in the date stamp:
day = day[:-3]
new = "_".join([day, TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
@pytest.mark.parametrize("arg1", ["-w -f", "-w --files",
"--withtime -f", "--withtime --files",
"-w -m", "-w --mtime",
"--withtime -m", "--withtime --mtime",
"-w -c", "-w --ctime",
"--withtime -c", "--withtime --ctime"])
def test_default_pattern_YYYY_MM_DDThh_mm_ss(arg1):
"""Prepend YYYY-MM-DDThh.mm.ss to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in ["-w -f", "-w --files",
"--withtime -f", "--withtime --files",
"-w -m", "-w --mtime",
"--withtime -m", "--withtime --mtime"]:
day = query_file_modification().split()[0]
second = query_file_modification().split()[1]
elif arg1 in ["-w -c", "-w --ctime",
"--withtime -c", "--withtime --ctime"]:
day = query_file_creation().split()[0]
second = query_file_creation().split()[1]
second = second.split(".")[0] # use integer seconds only
second = second.replace(":", ".") # adjust represetation
new = "".join([day, "T", second, "_", TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)

316
test_generator.org Executable file
View file

@ -0,0 +1,316 @@
#+NAME: test_generator.org
#+AUTHOR: nbehrnd@yahoo.com
#+DATE: 2021-09-02 (YYYY-MM-DD)
# License: GPL3, 2021.
#+PROPERTY: header-args :tangle yes
# Export the tangled files with C-c C-v t
* Intent
The application =date2name= by Karl Voit /et al./ ([[https://github.com/novoid/date2name][source)]] prepepends date
stamps to files and folders (YYYY-MM-DD, YYYYMMDD, YYYY-MM, and
YYYY-MM-DDThh.mm.ss). This Emacs .org file is used to prepare the automatic
testing of the file processing by [[https://docs.pytest.org/en/latest/][pytest]].
By the command =C-c C-v t=, this =.org= file may (re)generate the tangled test
script, file =test_date2name.py= as well as a dedicated =Makefile= to ease the
automated testing even further. =pytest= is not part of the Python standard
library, but may be obtained easily e.g., from [[https://pypi.org/project/pytest/][PyPi]].
It is advantageous to retain the options to run =pytest= in a =Makefile=,
which equally is inlcuded in this development e.g. to retain if an
instruction like =pytest -xv= or =pytest-3 -xv= is necessary (/vide infra/).
* Dependencies
The testing script is set up with Python 3.9.2 in mind. Thus, to run the
tests successfully, you need a working installation of Python 3 with pytest
for Python 3.
* Deployment
On a computer with Python 3 only, the recommended call on the CLI to run the
tests is either one of the following instructions (you might need to add the
executable bit):
python pytest -xv test_date2name.py
./Makefile
In case the computer you use equally includes an installation of legacy
Python 2 side-by-side to Python 3, you must explicitly call for the later
branch of the two. Depending on your OS, this requires an adjustment of the
command issue. In Linux Debian 12/bookworm, branch testing, for example,
python3 pytest-3 -xv test_date2name.py
or, after adjustment of the =Makefile= and provision of the executable bit
./Makefile
* Building the tests
** Building of the Makefile
Set up for GNU Make 4.3, as provided from the repositories of Linux Debian 12
(bookworm), branch testing.
#+BEGIN_SRC makefile :tangle Makefile
# GNU Make file for the automation of pytest for date2name.
#
# While the test script is written for Python 3.9.2, you might need to
# adjust the following instruction once in case your OS includes pyest
# for legacy Python 2 side by side to Python 3, or only hosts pytest
# for Python 3. The tests in script test_date2name.py are set up to
# work with pytest for Python 3; dependent on your installation, which
# may be named pytest-3, or (again) pytest.
#
# Put this file like test_date2name.py in the root folder of date2name
# fetched from PyPi or GitHub. Then run
#
# chmod +x *
# make ./Makefile
#
# to run the tests. The test sequence either stops at the first test
# failing, or after completion.
# pytest -xv test_date2name.py # only pytest for Python 3 is present
pytest-3 -xv test_date2name.py # pytest if Python 2 and Python 3 coexist
#+end_src
** Building the test script
*** header section
#+BEGIN_SRC python :tangle test_date2name.py
#!/bin/usr/env python3
# name: test_date2name.py
# author: nbehrnd@yahoo.com
# license: GPL v3, 2021.
# date: 2021-08-30 (YYYY-MM-DD)
# edit: 2021-09-02 (YYYY-MM-DD)
#
"""Test pad for functions by date2name with pytest.
Written for Python 3.9.2 and pytest 6.2.4 for Python 3 as provided by
Linux Debian 12/bookworm, branch testing, this is a programmatic check
of functions offered by date2name. Deposit this script in the root of
the folder fetched and unzipped from PyPi or GitHub. If your system
includes both legacy Python 2 and Python 3, pytest for Python 3 likely
is named pytest-3; otherwise only pytest. Thus, adjust your input on
the CLI accordingly when running either one of
pytest -xv test_date2name.py
pytest-3 -xv test_date2name.py
The script either stops when one of the tests fail, or after completion
of the test sequence. In both cases, the progress of the ongoing tests
is reported to the CLI."""
import os
import time
from datetime import datetime
from subprocess import getstatusoutput, getoutput
import pytest
PROGRAM = str("./date2name/__init__.py")
TFILE = str("test_file.txt") # the intermediate test file written
#+end_src
*** prepare recurrently used functions
Define actions which are going to be used multiple times.
#+begin_src python :tangle test_date2name.py
def prepare_testfile():
"""The creation of the test file."""
with open (TFILE, mode="w") as newfile:
newfile.write("This is the test file for test_date2name.py.")
# adjust modification time stamp, based on
# https://stackoverflow.com/questions/53111614/how-to-modify-the-file-modification-date-with-python-on-mac
result = os.stat(TFILE)
os.utime(TFILE, (result.st_atime, result.st_mtime + 10.0))
def query_file_creation():
"""Determine the time of creation of the file."""
created = os.stat(TFILE).st_ctime
created = str(datetime.fromtimestamp(created))
return created
def query_file_modification():
"""Determine the time when the file was modified."""
modified = os.stat(TFILE).st_mtime
modified = str(datetime.fromtimestamp(modified))
return modified
#+end_src
*** set up very elementary tests
These tests do not modify a file, nor folder by =date2time=.
#+begin_src python :tangle test_date2name.py
def test_create_remove_testfile():
"""Merely check if the test file may be written and removed."""
prepare_testfile()
os.remove(TFILE)
def test_script_existance():
"""Merely check for the script's presence."""
assert os.path.isfile(PROGRAM)
def test_script_version():
"""Check for the correct output of the version.
CLI equivalence: date2name --version """
out = getoutput(f"python3 {PROGRAM} --version")
assert out.strip() == "__init__.py 2018-05-09"
#+end_src
*** perform the tests on files [4/4]
These are tests for prepending the time stamp to a file name without
explicit call to query for the time of modification.
+ [X] default pattern, i.e. prepend YYYY-MM-DD_ to file test.txt
#+begin_src python :tangle test_date2name.py
@pytest.mark.parametrize("arg1", [" ", "-f", "--files",
"-m", "--mtime",
"-c", "--ctime"])
def test_default_pattern_YYYY_MM_DD(arg1):
"""Prepend YYYY-MM-DD to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in [" ", "-f", "--files", "-m", "--mtime"]:
day = query_file_modification().split()[0]
elif arg1 in ["-c", "--ctime"]:
day = query_file_creation().split()[0]
new = "_".join([day, TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
#+end_src
+ [X] prepend the day in the compact format YYYYMMDD_ to file test.txt
This may re-use much of the instructions used for the default pattern
and only needs to drop the hyphens.
#+begin_src python :tangle test_date2name.py
@pytest.mark.parametrize("arg1", ["-C", "--compact",
"-C -f", "--compact -f",
"-C --files", "--compact --files",
"-C -m", "--compact -m",
"-C --mtime", "--compact --mtime",
"-C -c", "--compact -c",
"-C --ctime", "--compact --ctime"])
def test_compact_pattern_YYYYMMDD(arg1):
"""Prepend YYYYMMDD to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in ["-C", "--compact",
"-C -f", "--compact -f",
"-C --files", "--compact --files",
"-C -m", "--compact -m",
"-C --mtime", "--compact --mtime"]:
day = query_file_modification().split()[0]
elif arg1 in ["-C -c", "--compact -c",
"-C --ctime", "--compact --ctime"]:
day = query_file_creation().split()[0]
# drop the hyphens in the date stamp:
day = day.replace("-", "")
new = "_".join([day, TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
#+end_src
+ [X] Prepend year and month in the format YYYY-MM_ to file test.txt.
Departing from the standard format YYYY-MM-DD, it suffices to trim
off the last three characters.
#+begin_src python :tangle test_date2name.py
@pytest.mark.parametrize("arg1", ["-M", "--month",
"-M -f", "--month -f",
"-M --files", "--month --files",
"-M -m", "--month -m",
"-M --mtime", "--month --mtime",
"-M -c", "--month -c",
"-M --ctime", "--month --ctime"])
def test_compact_monthn_YYYY_MM(arg1):
"""Prepend YYYY-MM to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in ["-M", "--month",
"-M -f", "--month -f",
"-M --files", "--month --files",
"-M -m", "--month -m",
"-M --mtime", "--month --mtime"]:
day = query_file_modification().split()[0]
elif arg1 in ["-M -c", "--month -c",
"-M --ctime", "--month --ctime"]:
day = query_file_creation().split()[0]
# trim off the last three characters in the date stamp:
day = day[:-3]
new = "_".join([day, TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
#+end_src
+ [X] To prepend date and time to file test.txt in a pattern of
YYYY-MM-DDThh.mm.ss, the default pattern YYYY-MM-DD is extended.
#+begin_src python :tangle test_date2name.py
@pytest.mark.parametrize("arg1", ["-w -f", "-w --files",
"--withtime -f", "--withtime --files",
"-w -m", "-w --mtime",
"--withtime -m", "--withtime --mtime",
"-w -c", "-w --ctime",
"--withtime -c", "--withtime --ctime"])
def test_default_pattern_YYYY_MM_DDThh_mm_ss(arg1):
"""Prepend YYYY-MM-DDThh.mm.ss to the file."""
prepare_testfile()
day = str("")
new = str("")
if arg1 in ["-w -f", "-w --files",
"--withtime -f", "--withtime --files",
"-w -m", "-w --mtime",
"--withtime -m", "--withtime --mtime"]:
day = query_file_modification().split()[0]
second = query_file_modification().split()[1]
elif arg1 in ["-w -c", "-w --ctime",
"--withtime -c", "--withtime --ctime"]:
day = query_file_creation().split()[0]
second = query_file_creation().split()[1]
second = second.split(".")[0] # use integer seconds only
second = second.replace(":", ".") # adjust represetation
new = "".join([day, "T", second, "_", TFILE])
test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
assert os.path.isfile(new)
os.remove(new)
#+end_src