date2name/test_generator.org
Norwid Behrnd d1f5672db0 Adjust present test functions to file.
The present test functions act on files only.  Early tests to stack
folders on top of the present functions do not work reliably yet.
Thus, better to name the functions (uniformly) about what they test
which are actions on files only.  This change equally prevents some
line breaks on the CLI, too.
2021-09-28 15:06:33 +00:00

16 KiB
Executable file
Raw Blame History

Intent

The application date2name by Karl Voit et al. (source) prepends datestamps 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 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 PyPi.

It is advantageous to retain the options to run pytest in a Makefile, which equally is included 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.

  # 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 pytest
  # 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 will explicitly report if a test
  # was passed successfully, or failed.  If you want to script to stop on
  # the first encounter of a test failed, add option -x on the commands
  # set below
  
  # pytest -v test_date2name.py     # only pytest for Python 3 is present
  pytest-3 -v test_date2name.py   # pytest if Python 2 and Python 3 coexist

Building the test script

header section

  #!/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-28 (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

prepare recurrently used functions

Define actions which are going to be used multiple times.

  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_creation_time(name=TFILE):
      """Determine the time of creation of the file/folder."""
      created = os.stat(name).st_ctime
      created = str(datetime.fromtimestamp(created))
      return created
  
  
  def query_modification_time(name=TFILE):
      """Determine the time when the file/folder was modified."""
      modified = os.stat(name).st_mtime
      modified = str(datetime.fromtimestamp(modified))
      return modified

set up very elementary tests

These tests do not modify a file, nor folder by date2time.

  def test_create_remove_testfile():
      """Merely check if the test file may be written and removed."""
      prepare_testfile()
      os.remove(TFILE)


  def test_script_existence():
      """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"

perform the tests on files [5/6]

These tests check the addition of a time stamp ahead of the file name.

  • default pattern, i.e. prepend YYYY-MM-DD_ to file test.txt

      @pytest.mark.parametrize("arg1", [" ", "-f", "--files",
                                        "-m", "--mtime",
                                        "-c", "--ctime"])
      def test_file_pattern_default(arg1):
          """Prepend 'YYYY-MM-DD_' to the file name."""
          prepare_testfile()
          day = str("")
          new = str("")
      
          if arg1 in [" ", "-f", "--files", "-m", "--mtime"]:
              day = query_modification_time().split()[0]
      
          elif arg1 in ["-c", "--ctime"]:
              day = query_creation_time().split()[0]
      
          new = "_".join([day, TFILE])
          test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
          assert os.path.isfile(new)
          os.remove(new)
  • 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.

      @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_file_pattern_compact(arg1):
          """Prepend 'YYYYMMDD_' to the file name."""
          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_modification_time().split()[0]
      
          elif arg1 in ["-C -c", "--compact -c",
                        "-C --ctime", "--compact --ctime"]:
              day = query_creation_time().split()[0]
      
          # drop the hyphens in the datestamp:
          day = day.replace("-", "")
      
          new = "_".join([day, TFILE])
          test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
          assert os.path.isfile(new)
          os.remove(new)
  • 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.

      @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_file_pattern_month(arg1):
          """Prepend 'YYYY-MM_' to the file name."""
          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_modification_time().split()[0]
      
          elif arg1 in ["-M -c", "--month -c",
                        "-M --ctime", "--month --ctime"]:
              day = query_creation_time().split()[0]
      
          # trim off the last three characters in the datestamp:
          day = day[:-3]
      
          new = "_".join([day, TFILE])
          test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
          assert os.path.isfile(new)
          os.remove(new)
  • 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.

      @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_file_pattern_withtime(arg1):
          """Prepend 'YYYY-MM-DDThh.mm.ss_' to the file name."""
          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_modification_time().split()[0]
              second = query_modification_time().split()[1]
      
          elif arg1 in ["-w -c", "-w --ctime",
                        "--withtime -c", "--withtime --ctime"]:
              day = query_creation_time().split()[0]
              second = query_creation_time().split()[1]
      
          second = second.split(".")[0]  # use integer seconds only
          second = second.replace(":", ".")  # adjust representation
      
          new = "".join([day, "T", second, "_", TFILE])
      
          test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
          assert os.path.isfile(new)
          os.remove(new)
  • Preprend the short datestamp (YYMMDD, feature by Reiner Rottmann) Related to the basic pattern, except truncating of the first two characters.

      @pytest.mark.parametrize("arg1", ["-S", "--short",
                                        "-S -f", "--short -f",
                                        "-S --files", "--short --files",
                                        "-S -m", "--short -m",
                                        "-S --mtime", "--short --mtime",
                                        "-S -c", "--short -c",
                                        "-S --ctime", "--short --ctime"])
      def test_file_pattern_short(arg1):
          """Prepend 'YYMMDD_' to the file name."""
          prepare_testfile()
          day = str("")
          new = str("")
      
          if arg1 in ["-S", "--short",
                      "-S -f", "--short -f",
                      "-S --files", "--short --files",
                      "-S -m", "--short -m",
                      "-S --mtime", "--short --mtime"]:
              day = query_modification_time().split()[0]
      
          elif arg1 in ["-S -c", "--short -c",
                        "-S --ctime", "--short --ctime"]:
              day = query_creation_time().split()[0]
      
          # drop the hyphens in the datestamp:
          day = day.replace("-", "")
          # drop the first two characters about the year (e.g., 1789 -> 89)
          day = day[2:]
      
          new = "_".join([day, TFILE])
          test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}")
          assert os.path.isfile(new)
          os.remove(new)
  • Check the retraction of the date/time stamp

    The test is constrained to the five fix formats prepending the file name.

    Not ready for inclusion into the main branch To trace the advancement of pytest's processing, long delays are set. A manual check of date2time on the CLI confirms that date2name writes the withtime format, but is not successful to retract this stamp.

      @pytest.mark.parametrize("arg1", ["default", "short", "compact",
                                        "month", "withtime"])
      @pytest.mark.parametrize("arg2", ["-r", "--remove"])
      def test_file_remove_stamp(arg1, arg2):
          """Check the retraction of the leading time stamp."""
          substitution = {"default" : "2021-09-21",
                          "short"   : "210921",
                          "compact" : "20210921",
                          "month"   : "2021-09",
                          "withtime": "2021-09-21T13.59.59"}
          prepend = substitution.get(arg1)
      
          BASIS = "test.txt"
          TFILE = ""
          TFILE = "_".join([prepend, BASIS])
          with open(TFILE, mode = "w") as newfile:
              newfile.write("This is a test file.")
      
          test = getoutput(f"python3 {PROGRAM} {TFILE} {arg2}")
      
          assert os.path.isfile(TFILE) is False  # absence of stamped file
          assert os.path.isfile(BASIS)           # presence unstamped file
      
          os.remove("test.txt")  # succesful space cleaning for next test
          assert os.path.isfile("test.txt") is False