appendfilename/test_generator.org
Norwid Behrnd 052ca37939 style: lint tests against flake8
Tests were linted with flake8 (7.1.1 (mccabe: 0.7.0, pycodestyle:
2.12.1, pyflakes: 3.2.0) CPython 3.12.7).

Signed-off-by: Norwid Behrnd <nbehrnd@yahoo.com>
2024-11-21 21:11:31 +01:00

491 lines
16 KiB
Org Mode
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# name: test_generator.org
# author: nbehrnd@yahoo.com
# date: 2022-01-05 (YYYY-MM-DD)
# edit: [2024-11-21 Thu]
# license: GPL3, 2022-2024
# Export the tangled files with C-c C-v t
#+PROPERTY: header-args :tangle yes
* Intent
The application =appendfilename= by Karl Voit /et al./ ([[https://github.com/novoid/appendfilename][source]])
allows the programmatic addition of user defined strings to one or
multiple already existing file names (e.g., add =travel= to file
=example.jpg= to yield =example_travel.jpg=). This file
=test_generator.org= provides the files for a programmatic test
of =appendfilename= by means of /code tangle/ from Emacs orgmode.
* Deployment
The tests presume a working installation of Python 3. After the
activation of a virtual environment, one suitable approach is to
resolve the dependencies by
#+begin_src shell :tangle no
python -m pip install -r requirements.txt
#+end_src
with data by PyPI. Subsequently, the tests can be launched by
#+begin_src shell :tangle no
python -m pytest
#+end_src
where each period (=.=) indicates a passing, and each =E= a failing
test. An optional flag
- =-v= allows a more verbose output to the CLI
- =-x= stops the sequence after the first failing test
- =-s= occasionally provides information e.g., about the tests' criteria
The tests are organized in sets =default=, =prepend=, and =smart=.
This allows to selectively run only checks which are about the
results by =appendfilename= in the /default/ mode, /prepend/ mode,
or /smart prepend/ mode alone, e.g.
#+begin_src shell :tangle no
python -m pytest -m "prepend"
#+end_src
The tests were revised to work equally well in Linux Debian 13/trixie
(e.g., Python 3.12.6 and pytest 8.3.3) as well as Windows 10.
* Setup of Emacs
The edit of this =.org= file in Emacs and the subsequent export
(tangle) of the files are affected by Emacs' own parameters (e.g.,
the indentation in Python). It is recommended to access this file
with Emacs in a session started by =emacs -q test_generator.org &=
and to evaluate the following block by =C-c C-c=; this explicitly
adjusts a few basic settings, but does not permanently overwrite an
already existing personalized Emacs configuration.
Most of these instructions are elements of Hendrik Suenkler's
annotated Emacs configuration ([[https://www.suenkler.info/notes/emacs-config/][blog post]]) which are reused with his
permission.
#+begin_src emacs-lisp :tangle no
;; support these languages at all:
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(org . t)
(shell . t)
(python . t)))
;; enable syntax highlighting:
(setq org-src-fontify-natively t)
;; adjust indentations, set tabs as explicit 4 spaces:
(setq-default indent-tabs-mode nil)
(setq default-tab-width 4)
(setq custom-tab-width 4)
(setq-default python-indent-offset custom-tab-width)
(setq org-edit-src-content-indentation 0)
(setq org-src-tab-acts-natively t)
(setq org-src-preserve-indentation t)
;; some comfort functions Suenkler mentions:
(delete-selection-mode 1)
(defalias 'yes-or-no-p 'y-or-n-p)
(show-paren-mode 1)
(setq show-paren-style 'parenthesis)
(column-number-mode nil)
(setq org-src-fontify-natively t)
#+end_src
#+RESULTS:
: t
If the previous block was evaluated as .TRUE. (=t=), test script and
Makefile may be tangled right now by =C-c C-v t=. After closing
this =.org= file, deploy them as indicated earlier.
* Building the tests
** Building file =pytest.ini=
Markers file =pytest.ini= defines and which are used in file
=test_appendfilename.py= allows to constrain the run of
=pytest=. Rather than to launch a check on all tests, a call
like e.g.,
#+begin_src bash :tangle no
python -m pytest -m "prepend"
#+end_src
only checks those of set =prepend=. At present, tests are
grouped as
+ =default= appendfilename's default string insertions
+ =prepend= corresponding to either appendfilename's optional =-p=
or =--prepend= flag, and
+ =smart= corresponding to appendfilename's optional
=--smart-prepend= flag
It is possible to run one, two, or all three groups in one run of
pytest, for instance
#+begin_src bash :tangle no
pytest-3 test_appendfilename.py -m "default and prepend" -v
#+end_src
The content of =pytest.ini=:
#+begin_src shell :tangle pytest.ini
[pytest]
markers =
default: appendfilename's default string insertions
prepend: appendfilename's optional -p/--prepend flag
smart: appendfilename's optional --smart-prepend flag
#+end_src
** Building the test script
*** header section
#+BEGIN_SRC python :tangle test_appendfilename.py
#!/bin/usr/env python3
# name: test_appendfilename.py
# author: nbehrnd@yahoo.com
# license: GPL v3, 2022.
# date: 2022-01-05 (YYYY-MM-DD)
# edit: [2024-11-05 Tue]
#
"""Test pad for functions by appendfilename with pytest.
Initially written for Python 3.9.9 and pytest 6.2.4 and recently update
for Python 3.12.6/pytest 8.3.3, this script provides a programmatic check
of functions offered by appendfilename. Deposit this script in the root
of the folder fetched and unzipped from PyPi or GitHub. Create a virtual
environment for Python, e.g. by
```shell
python -m venv sup
```
In the activated virtual environment, ensure the dependencies are met -
either by `pip install pyreadline3 pytest`, or `pip install -r requirements.txt`
- and launch the tests by
```shell
python -m pytest
```
As a reminder, the following optional pytest flags may be useful to obtain
a report tailored to your needs:
- `-x` exit after the first failing test (reported by `E` instead of `.`)
- `-v` provide a more verbose output
- `-s` equally report the test criterion, e.g. the queried file name
"""
import re
import os
import shlex
import subprocess
from itertools import product
import pytest
PROGRAM = os.path.join("appendfilename", "__init__.py") # Cross-platform path
#+end_src
*** appendfilename, default position
Departing with file =test.txt=, appendfile's addition of =example= should
yield =test example.txt=.
#+begin_src python :tangle test_appendfilename.py
# The following section tests the applications default pattern where a
# string is added to the file name, just prior to the file's file
# extension. The permutations of the arguments define 120 tests.
arg1_values = [
"test.txt", "2021-12-31_test.txt", "2021-12-31T18.48.22_test.txt"
]
arg2_values = [
"-t book", "-t book_shelf", "--text book", "--text book_shelf"
]
arg3_values = [
"", # i.e. fall back to default single space
"--separator '!'",
"--separator '@'",
"--separator '#'",
"--separator '$'",
"--separator '%'",
"--separator '_'",
"--separator '+'",
"--separator '='",
"--separator '-'"
]
# Note: The check with pytest and `*` as separator in Windows 10 fails.
# create the permutations:
test_cases = list(product(arg1_values, arg2_values, arg3_values))
@pytest.mark.default
@pytest.mark.parametrize("arg1, arg2, arg3", test_cases)
def test_append(arg1, arg2, arg3):
"""Test default which appends a string just prior file extension
arg1 the test file to process, partly inspired by `date2name`
arg2 the text string to be added
arg3 the separator (at least in Windows 10, do not use `*`)"""
# create a test file:
with open(arg1, mode="w", encoding="utf-8") as newfile:
newfile.write("This is a place holder.\n")
# run the test to be tested:
full_command = ["python", PROGRAM, arg1
] + shlex.split(arg2) + shlex.split(arg3)
subprocess.run(full_command, text=True, check=True)
# construct the new file name to be tested:
if len(shlex.split(arg3)) == 0:
separator = " "
else:
separator = shlex.split(arg3)[1]
new_filename = "".join(
[arg1[:-4], separator, shlex.split(arg2)[1], ".txt"])
print(f"test criterion: {new_filename}") # for an optional `pytest -s`
# is the new file present?
assert os.path.isfile(new_filename)
# check if the OS can process the new file / space cleaning
os.remove(new_filename)
assert os.path.isfile(new_filename) is False
#+end_src
*** appendfilename, prepend position
Departing with file =test.txt=, appendfile's addition of =example=
should yield =example test.txt=. The 240 tests equally consider the
separator between the string added, and the original file name.
#+begin_src python :tangle test_appendfilename.py
# The following section is about tests to prepend a user defined string
# and an adjustable separator to the original file name of the submitted
# file. The permutation of the parameters defines 240 tests.
arg1_values = [
"test.txt", "2021-12-31_test.txt", "2021-12-31T18.48.22_test.txt"
]
arg2_values = [
"-t book", "-t book_shelf", "--text book", "--text book_shelf"
]
arg3_values = [
"", # i.e. fall back to default single space
"--separator '!'",
"--separator '@'",
"--separator '#'",
"--separator '$'",
"--separator '%'",
"--separator '_'",
"--separator '+'",
"--separator '='",
"--separator '-'"
]
# Note: The check with pytest and `*` as separator in Windows 10 fails.
arg4_values = [
"-p", "--prepend"
]
# create the permutations:
test_cases = list(product(arg1_values, arg2_values, arg3_values, arg4_values))
@pytest.mark.prepend
@pytest.mark.parametrize("arg1, arg2, arg3, arg4", test_cases)
def test_prepend(arg1, arg2, arg3, arg4):
"""test to prepend a string to the original file name
arg1 the test file to process, partly inspired by `date2name`
arg2 the text string to be added
arg3 the separator (at least in Windows 10, do not use `*`)
arg4 either short of long form to introduce the string as leading """
# create a test file:
with open(arg1, mode="w", encoding="utf-8") as newfile:
newfile.write("This is a place holder.\n")
# run the test to be tested:
full_command = [
"python", PROGRAM, arg1
] + shlex.split(arg2) + shlex.split(arg3) + shlex.split(arg4)
subprocess.run(full_command, text=True, check=True)
# construct the new file name to be tested:
if len(shlex.split(arg3)) == 0:
separator = " "
else:
separator = shlex.split(arg3)[1]
new_filename = "".join([shlex.split(arg2)[1], separator, arg1])
print(f"test criterion: {new_filename}") # visible by optional `pytest -s`
# is the new file present?
assert os.path.isfile(new_filename)
# check if the OS can process the new file / space cleaning
os.remove(new_filename)
assert os.path.isfile(new_filename) is False
#+end_src
*** appendfilename, smart prepend position
Here, the additional string follows the time stamp, and leads
the rest of the file's file name. Of five patterns provided by
=date2name=, only =--withtime= and the default YYYY-MM-DD are
checked. The other three (=--compact=, =--month=, and =--short=)
are muted for their pattern still different to the other two.
Equally see [[https://github.com/novoid/appendfilename/issues/15]]
and [[https://github.com/novoid/appendfilename/issues/16]].
The permutation of the parameter's active levels define 8 tests.
#+begin_src python :tangle test_appendfilename.py
# This section tests the insertion of a string into the file's file name
# just after the file's time or date stamp as provided `date2name`.
arg1_values = [
"2021-12-31T18.48.22_test.txt",
"2021-12-31_test.txt",
# "20211231_test.txt", # by now `20211231_test.txt` -> 20211231_test ping.txt
# "2021-12_test.txt", # by now `2021-12_test.txt` -> `2021-12_test ping.txt`
# "211231_test.txt" # by now `211231_test.txt` -> `211231_test ping.txt`
]
arg2_values = [
"-t book",
"-t book_shelf",
"--text book",
"--text book_shelf"
]
arg3_values = [
"", # i.e. fall back to default single space
# "--separator '!'",
# "--separator '@'",
# "--separator '#'",
# "--separator '$'",
# "--separator '%'",
# "--separator '_'",
# "--separator '+'",
# "--separator '='",
# "--separator '-'"
]
# Note: The check with pytest and `*` as separator in Windows 10 fails.
# Contrasting to Linux Debian 13, a `pytest` in Windows 10 revealed every
# of these special characters can not safely used as an additional separator.
# create the permutations:
test_cases = list(product(arg1_values, arg2_values, arg3_values))
@pytest.mark.smart
@pytest.mark.parametrize("arg1, arg2, arg3", test_cases)
def test_smart_prepend(arg1, arg2, arg3):
"""test the insertion of a new string just past the time stamp
arg1 the test file to process, partly inspired by `date2name`
arg2 the text string to be added
arg3 the separator (at least in Windows 10, do not use `*`
"""
time_stamp = ""
# time_stamp_separator = ""
old_filename_no_timestamp = ""
# create a test file:
with open(arg1, mode="w", encoding="utf-8") as newfile:
newfile.write("this is a placeholder\n")
# run `appendfilename` on this test file
run_appendfilename = " ".join(
["python", PROGRAM, arg1, arg2, arg3, " --smart-prepend"])
subprocess.run(run_appendfilename, shell=True, check=True)
# construct the new file name to be testedt:
old_filename = arg1
# account for the implicit separator, i.e. the single space:
if len(shlex.split(arg3)) == 0:
separator = " "
else:
separator = shlex.split(arg3)[1]
# Time stamps `date2name` provides can be either one of five formats
#
# YYYY-MM-DDTHH.MM.SS `--withtime`
# YYYY-MM-DD default
# YYYYMMDD `--compact`
# YYYY-MM `--month`
# YYMMDD `--short`
# Currently, one observes two patterns by `appendfilename`: one which
# substitutes the separator by `date2name`, the other which retains it.
# Note patterns `compact`, `month`, and `short`, currently append the
# additional string rather than smartly prepend after the date stamp --
# for now, these three are not tested. Equally see discussions 15 and 16,
# https://github.com/novoid/appendfilename/issues/15
# https://github.com/novoid/appendfilename/issues/16
# pattern `--with-time`
if re.search(r"^\d{4}-[012]\d-[0-3]\dT[012]\d\.[0-5]\d\.[0-5]\d", old_filename):
time_stamp = old_filename[:19]
time_stamp_separator = old_filename[19]
old_filename_no_timestamp = old_filename[20:]
# default pattern
elif re.search(r"^\d{4}-[012]\d-[0-3]\d", old_filename):
time_stamp = old_filename[:10]
time_stamp_separator = old_filename[10]
old_filename_no_timestamp = old_filename[11:]
# pattern `--compact` # currently fails
elif re.search(r"^\d{4}[012]\d[0-3]\d", old_filename):
time_stamp = old_filename[:8]
time_stamp_separator = old_filename[8]
old_filename_no_timestamp = old_filename[9:]
# pattern `--month` # currently fails
elif re.search(r"^\d{4}-[012]\d", old_filename):
time_stamp = old_filename[:7]
time_stamp_separator = old_filename[7]
old_filename_no_timestamp = old_filename[8:]
# pattern `--short` # currently fails
elif re.search(r"^\d{4}[012]\d[0-3]\d", old_filename):
time_stamp = old_filename[:6]
time_stamp_separator = old_filename[6]
old_filename_no_timestamp = old_filename[7:]
new_filename = "".join([time_stamp, # time_stamp_separator,
separator, shlex.split(arg2)[1], separator,
old_filename_no_timestamp])
# is the new file present?
print("\nnew_filename") # optional check for `pytest -s`
print(new_filename)
assert os.path.isfile(new_filename)
# check if the IS can process the new file / space cleaning
os.remove(new_filename)
assert os.path.isfile(new_filename) is False
#+end_src