diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index c197b8f..e6588ff --- a/Makefile +++ b/Makefile @@ -13,8 +13,10 @@ # chmod +x * # make ./Makefile # -# to run the tests. The test sequence either stops at the first test -# failing, or after completion. +# 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 -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 +# 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 diff --git a/date2name/__init__.py b/date2name/__init__.py index 978cbfe..d404a11 100755 --- a/date2name/__init__.py +++ b/date2name/__init__.py @@ -71,15 +71,15 @@ parser.add_option("-d", "--directories", dest="onlydirectories", parser.add_option("-f", "--files", dest="onlyfiles", action="store_true", help="modify only file names") -parser.add_option("-S", "--short", dest="short", - action="store_true", - help="use short datestamp (YYMMDD)") parser.add_option("-C", "--compact", dest="compact", action="store_true", help="use compact datestamp (YYYYMMDD)") parser.add_option("-M", "--month", dest="month", action="store_true", help="use datestamp with year and month (YYYY-MM)") +parser.add_option("-S", "--short", dest="short", + action="store_true", + help="use short datestamp (YYMMDD)") parser.add_option("-w", "--withtime", dest="withtime", action="store_true", help="use datestamp including seconds (YYYY-MM-DDThh.mm.ss)") diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..0f7d5b7 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,12 @@ +[pytest] +markers = + elementary: elementary tests ahead of action on files/folders by date2name + files: tests about affect by date2name on files + folders: tests about affect by date2name on folders + + default: stamp pattern default, YYYY-MM-DD + compact: stamp pattern compact, YYYYMMDD + month: stamp pattern month, YYYY-MM + short: stamp pattern short, YYMMDD + withtime: stamp pattern withtime, YYYY-MM-DDThh.mm.ss + remove: stamp retraction diff --git a/test_date2name.py b/test_date2name.py index 267c472..4dd8c8a 100644 --- a/test_date2name.py +++ b/test_date2name.py @@ -4,7 +4,7 @@ # author: nbehrnd@yahoo.com # license: GPL v3, 2021. # date: 2021-08-30 (YYYY-MM-DD) -# edit: 2021-09-17 (YYYY-MM-DD) +# edit: 2021-09-29 (YYYY-MM-DD) # """Test pad for functions by date2name with pytest. @@ -32,41 +32,63 @@ import pytest PROGRAM = str("./date2name/__init__.py") TFILE = str("test_file.txt") # the intermediate test file written +TFOLDER = str("test_folder") # for complementary check on folders -def prepare_testfile(): +def prepare_testfile(name=TFILE): """The creation of the test file.""" - with open (TFILE, mode="w") as newfile: + with open (name, 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)) + result = os.stat(name) + os.utime(name, (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 +def prepare_testfolder(name=TFOLDER): + """Create a test folder.""" + os.mkdir(name) + result = os.stat(name) + os.utime(name, (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_file_modification(): - """Determine the time when the file was modified.""" - modified = os.stat(TFILE).st_mtime +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 -def test_create_remove_testfile(): +@pytest.mark.elementary +def test_create_remove_testfile(name=TFILE): """Merely check if the test file may be written and removed.""" - prepare_testfile() - os.remove(TFILE) + prepare_testfile(name=TFILE) + assert os.path.isfile(name) + os.remove(name) + assert os.path.isfile(name) is False +@pytest.mark.elementary +def test_create_remove_testfolder(name=TFOLDER): + """Probe the generation/removal of a test folder.""" + prepare_testfolder(name=TFOLDER) + assert os.path.isdir(name) + os.rmdir(name) + assert os.path.isdir(name) is False + + +@pytest.mark.elementary def test_script_existence(): """Merely check for the script's presence.""" assert os.path.isfile(PROGRAM) +@pytest.mark.elementary def test_script_version(): """Check for the correct output of the version. @@ -74,26 +96,30 @@ def test_script_version(): out = getoutput(f"python3 {PROGRAM} --version") assert out.strip() == "__init__.py 2018-05-09" +@pytest.mark.files +@pytest.mark.default @pytest.mark.parametrize("arg1", [" ", "-f", "--files", "-m", "--mtime", "-c", "--ctime"]) -def test_default_pattern_YYYY_MM_DD(arg1): +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_file_modification().split()[0] + day = query_modification_time().split()[0] elif arg1 in ["-c", "--ctime"]: - day = query_file_creation().split()[0] + 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) +@pytest.mark.files +@pytest.mark.compact @pytest.mark.parametrize("arg1", ["-C", "--compact", "-C -f", "--compact -f", "-C --files", "--compact --files", @@ -101,7 +127,7 @@ def test_default_pattern_YYYY_MM_DD(arg1): "-C --mtime", "--compact --mtime", "-C -c", "--compact -c", "-C --ctime", "--compact --ctime"]) -def test_compact_pattern_YYYYMMDD(arg1): +def test_file_pattern_compact(arg1): """Prepend 'YYYYMMDD_' to the file name.""" prepare_testfile() day = str("") @@ -112,13 +138,13 @@ def test_compact_pattern_YYYYMMDD(arg1): "-C --files", "--compact --files", "-C -m", "--compact -m", "-C --mtime", "--compact --mtime"]: - day = query_file_modification().split()[0] + day = query_modification_time().split()[0] elif arg1 in ["-C -c", "--compact -c", "-C --ctime", "--compact --ctime"]: - day = query_file_creation().split()[0] + day = query_creation_time().split()[0] - # drop the hyphens in the datestamp: + # drop the hyphens in the date stamp: day = day.replace("-", "") new = "_".join([day, TFILE]) @@ -126,6 +152,8 @@ def test_compact_pattern_YYYYMMDD(arg1): assert os.path.isfile(new) os.remove(new) +@pytest.mark.files +@pytest.mark.month @pytest.mark.parametrize("arg1", ["-M", "--month", "-M -f", "--month -f", "-M --files", "--month --files", @@ -133,7 +161,7 @@ def test_compact_pattern_YYYYMMDD(arg1): "-M --mtime", "--month --mtime", "-M -c", "--month -c", "-M --ctime", "--month --ctime"]) -def test_compact_month_YYYY_MM(arg1): +def test_file_pattern_month(arg1): """Prepend 'YYYY-MM_' to the file name.""" prepare_testfile() day = str("") @@ -144,13 +172,13 @@ def test_compact_month_YYYY_MM(arg1): "-M --files", "--month --files", "-M -m", "--month -m", "-M --mtime", "--month --mtime"]: - day = query_file_modification().split()[0] + day = query_modification_time().split()[0] elif arg1 in ["-M -c", "--month -c", "-M --ctime", "--month --ctime"]: - day = query_file_creation().split()[0] + day = query_creation_time().split()[0] - # trim off the last three characters in the datestamp: + # trim off the last three characters in the date stamp: day = day[:-3] new = "_".join([day, TFILE]) @@ -158,39 +186,8 @@ def test_compact_month_YYYY_MM(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 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_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 representation - - new = "".join([day, "T", second, "_", TFILE]) - - test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}") - assert os.path.isfile(new) - os.remove(new) - +@pytest.mark.files +@pytest.mark.short @pytest.mark.parametrize("arg1", ["-S", "--short", "-S -f", "--short -f", "-S --files", "--short --files", @@ -198,7 +195,7 @@ def test_default_pattern_YYYY_MM_DDThh_mm_ss(arg1): "-S --mtime", "--short --mtime", "-S -c", "--short -c", "-S --ctime", "--short --ctime"]) -def test_short_pattern_YYMMDD(arg1): +def test_file_pattern_short(arg1): """Prepend 'YYMMDD_' to the file name.""" prepare_testfile() day = str("") @@ -209,13 +206,13 @@ def test_short_pattern_YYMMDD(arg1): "-S --files", "--short --files", "-S -m", "--short -m", "-S --mtime", "--short --mtime"]: - day = query_file_modification().split()[0] + day = query_modification_time().split()[0] elif arg1 in ["-S -c", "--short -c", "-S --ctime", "--short --ctime"]: - day = query_file_creation().split()[0] + day = query_creation_time().split()[0] - # drop the hyphens in the datestamp: + # drop the hyphens in the date stamp: day = day.replace("-", "") # drop the first two characters about the year (e.g., 1789 -> 89) day = day[2:] @@ -224,3 +221,271 @@ def test_short_pattern_YYMMDD(arg1): test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}") assert os.path.isfile(new) os.remove(new) + +@pytest.mark.files +@pytest.mark.withtime +@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) + +@pytest.mark.files +@pytest.mark.remove +@pytest.mark.parametrize("arg1", ["default", + "compact", "month", "short", + "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", + "compact" : "20210921", + "month" : "2021-09", + "short" : "210921", + "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") # successful space cleaning for next test + assert os.path.isfile("test.txt") is False + +@pytest.mark.folders +@pytest.mark.default +@pytest.mark.parametrize("arg1", [" ", "-d", "--directories", + "-m", "--mtime", + "-c", "--ctime"]) +def test_folder_pattern_default(arg1, name=TFOLDER): + """Prepend 'YYYY-MM-DD_' to the folder name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in [" ", "-d", "--directories", "-m", "--mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-c", "--ctime"]: + day = query_creation_time(name).split()[0] + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + +@pytest.mark.folders +@pytest.mark.compact +@pytest.mark.parametrize("arg1", ["-C", "--compact", + "-C -d", "--compact -d", + "-C --directories", "--compact --directories", + "-C -m", "--compact -m", + "-C --mtime", "--compact --mtime", + "-C -c", "--compact -c", + "-C --ctime", "--compact --ctime"]) +def test_folder_pattern_compact(arg1, name=TFOLDER): + """Prepend 'YYYYMMDD_' to the folder name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-C", "--compact", + "-C -d", "--compact -d", + "-C --directories", "--compact --directories", + "-C -m", "--compact -m", + "-C --mtime", "--compact --mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-C -c", "--compact -c", + "-C --ctime", "--compact --ctime"]: + day = query_creation_time(name).split()[0] + + # drop the hyphens in the date stamp: + day = day.replace("-", "") + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + +@pytest.mark.folders +@pytest.mark.month +@pytest.mark.parametrize("arg1", ["-M", "--month", + "-M -d", "--month -d", + "-M --directories", "--month --directories", + "-M -m", "--month -m", + "-M --mtime", "--month --mtime", + "-M -c", "--month -c", + "-M --ctime", "--month --ctime"]) +def test_file_pattern_month(arg1, name=TFOLDER): + """Prepend 'YYYY-MM_' to the file name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-M", "--month", + "-M -d", "--month -d", + "-M --directories", "--month --directories", + "-M -m", "--month -m", + "-M --mtime", "--month --mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-M -c", "--month -c", + "-M --ctime", "--month --ctime"]: + day = query_creation_time(name).split()[0] + + # trim off the last three characters in the date stamp: + day = day[:-3] + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + +@pytest.mark.folders +@pytest.mark.short +@pytest.mark.parametrize("arg1", ["-S", "--short", + "-S -d", "--short -d", + "-S --directories", "--short --directories", + "-S -m", "--short -m", + "-S --mtime", "--short --mtime", + "-S -c", "--short -c", + "-S --ctime", "--short --ctime"]) +def test_folder_pattern_short(arg1, name=TFOLDER): + """Prepend 'YYMMDD_' to the file name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-S", "--short", + "-S -d", "--short -d", + "-S --directories", "--short --directories", + "-S -m", "--short -m", + "-S --mtime", "--short --mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-S -c", "--short -c", + "-S --ctime", "--short --ctime"]: + day = query_creation_time(name).split()[0] + + # drop the hyphens in the date stamp: + day = day.replace("-", "") + # drop the first two characters about the year (e.g., 1789 -> 89) + day = day[2:] + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + +@pytest.mark.folders +@pytest.mark.withtime +@pytest.mark.parametrize("arg1", ["-w -d", "-w --directories", + "--withtime -d", "--withtime --directories", + "-w -m", "-w --mtime", + "--withtime -m", "--withtime --mtime", + "-w -c", "-w --ctime", + "--withtime -c", "--withtime --ctime"]) +def test_file_pattern_withtime(arg1, name=TFOLDER): + """Prepend 'YYYY-MM-DDThh.mm.ss_' to the folder name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-w -d", "-w --directories", + "--withtime -d", "--withtime --directories", + "-w -m", "-w --mtime", + "--withtime -m", "--withtime --mtime"]: + day = query_modification_time(name).split()[0] + second = query_modification_time(name).split()[1] + + elif arg1 in ["-w -c", "-w --ctime", + "--withtime -c", "--withtime --ctime"]: + day = query_creation_time(name).split()[0] + second = query_creation_time(name).split()[1] + + second = second.split(".")[0] # use integer seconds only + second = second.replace(":", ".") # adjust representation + + new = "".join([day, "T", second, "_", name]) + + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + +@pytest.mark.folders +@pytest.mark.remove +@pytest.mark.parametrize("arg1", ["default", + "compact", "month", "short", + "withtime"]) +@pytest.mark.parametrize("arg2", ["-r", "--remove"]) +def test_folder_remove_stamp(arg1, arg2, name=TFOLDER): + """Check the retraction of the leading time stamp.""" + substitution = {"default" : "2021-09-21", + "compact" : "20210921", + "month" : "2021-09", + "short" : "210921", + "withtime": "2021-09-21T13.59.59"} + prepend = substitution.get(arg1) + + # os.mkdir(name) + BASIS = str(name) + stamped_folder = "" + stamped_folder = "_".join([prepend, BASIS]) + os.mkdir(stamped_folder) + assert os.path.isdir(stamped_folder) # presence stamped folder + + test = getoutput(f"python3 {PROGRAM} {stamped_folder} {arg2}") + + assert os.path.isdir(stamped_folder) is False + assert os.path.isdir(name) # presence unstamped folder + os.rmdir(name) + assert os.path.isdir(name) is False # space cleaning diff --git a/test_generator.org b/test_generator.org index c125923..4e2f519 100755 --- a/test_generator.org +++ b/test_generator.org @@ -1,6 +1,6 @@ #+NAME: test_generator.org #+AUTHOR: nbehrnd@yahoo.com -#+DATE: 2021-09-17 (YYYY-MM-DD) +#+DATE: 2021-09-29 (YYYY-MM-DD) # License: GPL3, 2021. #+PROPERTY: header-args :tangle yes @@ -8,7 +8,7 @@ * Intent - The application =date2name= by Karl Voit /et al./ ([[https://github.com/novoid/date2name][source)]] prepends datestamps + The application =date2name= by Karl Voit /et al./ ([[https://github.com/novoid/date2name][source)]] prepends 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]]. @@ -24,7 +24,7 @@ * Dependencies - The testing script is set up with Python 3.9.2 in mind. Thus, to run the + The testing script is set up with Python 3.9.7 in mind. Thus, to run the tests successfully, you need a working installation of Python 3 with pytest for Python 3. @@ -34,7 +34,7 @@ tests is either one of the following instructions (you might need to add the executable bit): - python pytest -xv test_date2name.py + python pytest -v test_date2name.py ./Makefile In case the computer you use equally includes an installation of legacy @@ -42,12 +42,14 @@ 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 + python3 pytest-3 -v test_date2name.py or, after adjustment of the =Makefile= and provision of the executable bit ./Makefile + See section about building a =pytest.ini= for additional options prepared. + * Building the tests @@ -72,13 +74,56 @@ # 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 + # 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 #+end_src +** Building a pytest.ini + + This file defines markers which groups the tests into groups. Subsequently, + tests with pytest may focus on them rather than performing all tests (which + is set up as the default). In presence of =pytest.ini=, the typical call + then is + #+begin_src bash :tangle no + pytest-3 test_date2name.py -v -m "elementary" + #+end_src + to constrain the tester's action to all tests labeled as "elementary". At + present, tests are grouped as + + elementary; ahead of checking date2name's action on files or folders + + files; checking date2name's action on files, and + + folders; checking date2name's action on folders. + in a first layer. Orthogonal to this, the five fixed pattern (keyword + =default=, =compact=, =month=, =withtime=, or =short=) and the stamps' + retraction (keyword =remove=) may be used as mutually exclusive levels, + either alone, or in combination with the keyword =files= or =folders=, e.g. + + #+begin_src bash :tangle no + pytest-3 test_date2name.py -m "files and default" -v + #+end_src + + This became necessary since a reliable approach to stack the levels "files" + and "folders" in this testing suite was not yet identified. + + + #+begin_src python :tangle pytest.ini + [pytest] + markers = + elementary: elementary tests ahead of action on files/folders by date2name + files: tests about affect by date2name on files + folders: tests about affect by date2name on folders + + default: stamp pattern default, YYYY-MM-DD + compact: stamp pattern compact, YYYYMMDD + month: stamp pattern month, YYYY-MM + short: stamp pattern short, YYMMDD + withtime: stamp pattern withtime, YYYY-MM-DDThh.mm.ss + remove: stamp retraction + #+end_src ** Building the test script @@ -90,7 +135,7 @@ # author: nbehrnd@yahoo.com # license: GPL v3, 2021. # date: 2021-08-30 (YYYY-MM-DD) - # edit: 2021-09-17 (YYYY-MM-DD) + # edit: 2021-09-29 (YYYY-MM-DD) # """Test pad for functions by date2name with pytest. @@ -118,6 +163,7 @@ PROGRAM = str("./date2name/__init__.py") TFILE = str("test_file.txt") # the intermediate test file written + TFOLDER = str("test_folder") # for complementary check on folders #+end_src @@ -126,26 +172,33 @@ Define actions which are going to be used multiple times. #+begin_src python :tangle test_date2name.py - def prepare_testfile(): + def prepare_testfile(name=TFILE): """The creation of the test file.""" - with open (TFILE, mode="w") as newfile: + with open (name, 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 + result = os.stat(name) + os.utime(name, (result.st_atime, result.st_mtime + 10.0)) + + + def prepare_testfolder(name=TFOLDER): + """Create a test folder.""" + os.mkdir(name) + result = os.stat(name) + os.utime(name, (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_file_modification(): - """Determine the time when the file was modified.""" - modified = os.stat(TFILE).st_mtime + + + 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 #+end_src @@ -156,57 +209,75 @@ These tests do not modify a file, nor folder by =date2time=. #+begin_src python :tangle test_date2name.py - def test_create_remove_testfile(): + @pytest.mark.elementary + def test_create_remove_testfile(name=TFILE): """Merely check if the test file may be written and removed.""" - prepare_testfile() - os.remove(TFILE) - - + prepare_testfile(name=TFILE) + assert os.path.isfile(name) + os.remove(name) + assert os.path.isfile(name) is False + + + @pytest.mark.elementary + def test_create_remove_testfolder(name=TFOLDER): + """Probe the generation/removal of a test folder.""" + prepare_testfolder(name=TFOLDER) + assert os.path.isdir(name) + os.rmdir(name) + assert os.path.isdir(name) is False + + + @pytest.mark.elementary def test_script_existence(): """Merely check for the script's presence.""" assert os.path.isfile(PROGRAM) - - + + + @pytest.mark.elementary 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 [5/5] +*** perform the tests on files [6/6] These tests check the addition of a time stamp ahead of the file name. + [X] default pattern, i.e. prepend YYYY-MM-DD_ to file test.txt #+begin_src python :tangle test_date2name.py + @pytest.mark.files + @pytest.mark.default @pytest.mark.parametrize("arg1", [" ", "-f", "--files", "-m", "--mtime", "-c", "--ctime"]) - def test_default_pattern_YYYY_MM_DD(arg1): + 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_file_modification().split()[0] - + day = query_modification_time().split()[0] + elif arg1 in ["-c", "--ctime"]: - day = query_file_creation().split()[0] - + 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) #+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. + + [X] compact pattern, i.e. prepend 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.files + @pytest.mark.compact @pytest.mark.parametrize("arg1", ["-C", "--compact", "-C -f", "--compact -f", "-C --files", "--compact --files", @@ -214,36 +285,38 @@ "-C --mtime", "--compact --mtime", "-C -c", "--compact -c", "-C --ctime", "--compact --ctime"]) - def test_compact_pattern_YYYYMMDD(arg1): + 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_file_modification().split()[0] - + day = query_modification_time().split()[0] + elif arg1 in ["-C -c", "--compact -c", "-C --ctime", "--compact --ctime"]: - day = query_file_creation().split()[0] - - # drop the hyphens in the datestamp: + day = query_creation_time().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. + + [X] month pattern, i.e. prepend 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.files + @pytest.mark.month @pytest.mark.parametrize("arg1", ["-M", "--month", "-M -f", "--month -f", "-M --files", "--month --files", @@ -251,73 +324,38 @@ "-M --mtime", "--month --mtime", "-M -c", "--month -c", "-M --ctime", "--month --ctime"]) - def test_compact_month_YYYY_MM(arg1): + 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_file_modification().split()[0] - + day = query_modification_time().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 datestamp: + day = query_creation_time().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 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_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 representation - - new = "".join([day, "T", second, "_", TFILE]) - - test = getoutput(f"python3 {PROGRAM} {TFILE} {arg1}") - assert os.path.isfile(new) - os.remove(new) - #+end_src - - + [X] Preprend the short datestamp (YYMMDD, feature by Reiner Rottmann) - Related to the basic pattern, except truncating of the first two - characters. + + [X] short pattern, i.e. prepend YYMMDD_ to file test.txt. A feature by + Reiner Rottmann. Related to the basic pattern, except the two first + characters are truncated. #+begin_src python :tangle test_date2name.py + @pytest.mark.files + @pytest.mark.short @pytest.mark.parametrize("arg1", ["-S", "--short", "-S -f", "--short -f", "-S --files", "--short --files", @@ -325,7 +363,7 @@ "-S --mtime", "--short --mtime", "-S -c", "--short -c", "-S --ctime", "--short --ctime"]) - def test_short_pattern_YYMMDD(arg1): + def test_file_pattern_short(arg1): """Prepend 'YYMMDD_' to the file name.""" prepare_testfile() day = str("") @@ -336,13 +374,13 @@ "-S --files", "--short --files", "-S -m", "--short -m", "-S --mtime", "--short --mtime"]: - day = query_file_modification().split()[0] + day = query_modification_time().split()[0] elif arg1 in ["-S -c", "--short -c", "-S --ctime", "--short --ctime"]: - day = query_file_creation().split()[0] + day = query_creation_time().split()[0] - # drop the hyphens in the datestamp: + # drop the hyphens in the date stamp: day = day.replace("-", "") # drop the first two characters about the year (e.g., 1789 -> 89) day = day[2:] @@ -352,3 +390,320 @@ assert os.path.isfile(new) os.remove(new) #+end_src + + + [X] withtime pattern, i.e. prepend YYYY-MM-DDThh.mm.ss_ to file test.txt. + This extends the default pattern YYYY-MM-DD. + #+begin_src python :tangle test_date2name.py + @pytest.mark.files + @pytest.mark.withtime + @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) + #+end_src + + + [X] Check the retraction of the date/time stamp on files. + + Based on a pattern comparison, a file like =20210921_test.txt= is renamed + =test.txt=. At present (Linux Debian 12/bookworm, branch testing), + date2name is known to struggle for files with the tag date2time prepended + by parameter =--withtime= (or =-w=). This is why the two corresponding + tests fail. + + #+begin_src python :tangle test_date2name.py + @pytest.mark.files + @pytest.mark.remove + @pytest.mark.parametrize("arg1", ["default", + "compact", "month", "short", + "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", + "compact" : "20210921", + "month" : "2021-09", + "short" : "210921", + "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") # successful space cleaning for next test + assert os.path.isfile("test.txt") is False + #+end_src + +*** perform the tests on folders [6/6] + + At present, most of the instructions already defined and used in section + "test on files" is repeated with small adjustments for checking date2name's + action on folders. While this approach isn't dry, given current experience, + it however is more reliable in eventual code execution running pytest, than + stacking the files/folders levels as an additional parameter. + + + [X] default pattern, YYYY-MM-DD_ prepended + #+begin_src python :tangle test_date2name.py + @pytest.mark.folders + @pytest.mark.default + @pytest.mark.parametrize("arg1", [" ", "-d", "--directories", + "-m", "--mtime", + "-c", "--ctime"]) + def test_folder_pattern_default(arg1, name=TFOLDER): + """Prepend 'YYYY-MM-DD_' to the folder name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in [" ", "-d", "--directories", "-m", "--mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-c", "--ctime"]: + day = query_creation_time(name).split()[0] + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + #+end_src + + + [X] compact pattern, YYYYMMDD_ prepended + #+begin_src python :tangle test_date2name.py + @pytest.mark.folders + @pytest.mark.compact + @pytest.mark.parametrize("arg1", ["-C", "--compact", + "-C -d", "--compact -d", + "-C --directories", "--compact --directories", + "-C -m", "--compact -m", + "-C --mtime", "--compact --mtime", + "-C -c", "--compact -c", + "-C --ctime", "--compact --ctime"]) + def test_folder_pattern_compact(arg1, name=TFOLDER): + """Prepend 'YYYYMMDD_' to the folder name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-C", "--compact", + "-C -d", "--compact -d", + "-C --directories", "--compact --directories", + "-C -m", "--compact -m", + "-C --mtime", "--compact --mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-C -c", "--compact -c", + "-C --ctime", "--compact --ctime"]: + day = query_creation_time(name).split()[0] + + # drop the hyphens in the date stamp: + day = day.replace("-", "") + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + #+end_src + + + [X] month pattern, YYYY-MM_ prepended + #+begin_src python :tangle test_date2name.py + @pytest.mark.folders + @pytest.mark.month + @pytest.mark.parametrize("arg1", ["-M", "--month", + "-M -d", "--month -d", + "-M --directories", "--month --directories", + "-M -m", "--month -m", + "-M --mtime", "--month --mtime", + "-M -c", "--month -c", + "-M --ctime", "--month --ctime"]) + def test_file_pattern_month(arg1, name=TFOLDER): + """Prepend 'YYYY-MM_' to the file name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-M", "--month", + "-M -d", "--month -d", + "-M --directories", "--month --directories", + "-M -m", "--month -m", + "-M --mtime", "--month --mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-M -c", "--month -c", + "-M --ctime", "--month --ctime"]: + day = query_creation_time(name).split()[0] + + # trim off the last three characters in the date stamp: + day = day[:-3] + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + #+end_src + + + [X] short pattern, YYMMDD_ prepended + #+begin_src python :tangle test_date2name.py + @pytest.mark.folders + @pytest.mark.short + @pytest.mark.parametrize("arg1", ["-S", "--short", + "-S -d", "--short -d", + "-S --directories", "--short --directories", + "-S -m", "--short -m", + "-S --mtime", "--short --mtime", + "-S -c", "--short -c", + "-S --ctime", "--short --ctime"]) + def test_folder_pattern_short(arg1, name=TFOLDER): + """Prepend 'YYMMDD_' to the file name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-S", "--short", + "-S -d", "--short -d", + "-S --directories", "--short --directories", + "-S -m", "--short -m", + "-S --mtime", "--short --mtime"]: + day = query_modification_time(name).split()[0] + + elif arg1 in ["-S -c", "--short -c", + "-S --ctime", "--short --ctime"]: + day = query_creation_time(name).split()[0] + + # drop the hyphens in the date stamp: + day = day.replace("-", "") + # drop the first two characters about the year (e.g., 1789 -> 89) + day = day[2:] + + new = "_".join([day, name]) + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + #+end_src + + + [X] withtime pattern, YYYY-MM-DDThh.mm.ss_ prepended + #+begin_src python :tangle test_date2name.py + @pytest.mark.folders + @pytest.mark.withtime + @pytest.mark.parametrize("arg1", ["-w -d", "-w --directories", + "--withtime -d", "--withtime --directories", + "-w -m", "-w --mtime", + "--withtime -m", "--withtime --mtime", + "-w -c", "-w --ctime", + "--withtime -c", "--withtime --ctime"]) + def test_file_pattern_withtime(arg1, name=TFOLDER): + """Prepend 'YYYY-MM-DDThh.mm.ss_' to the folder name.""" + prepare_testfolder(name) + day = str("") + new = str("") + + if arg1 in ["-w -d", "-w --directories", + "--withtime -d", "--withtime --directories", + "-w -m", "-w --mtime", + "--withtime -m", "--withtime --mtime"]: + day = query_modification_time(name).split()[0] + second = query_modification_time(name).split()[1] + + elif arg1 in ["-w -c", "-w --ctime", + "--withtime -c", "--withtime --ctime"]: + day = query_creation_time(name).split()[0] + second = query_creation_time(name).split()[1] + + second = second.split(".")[0] # use integer seconds only + second = second.replace(":", ".") # adjust representation + + new = "".join([day, "T", second, "_", name]) + + test = getoutput(f"python3 {PROGRAM} {name} {arg1}") + + assert os.path.isdir(name) is False # absence unstamped folder + assert os.path.isdir(new) # presence stamped folder + os.rmdir(new) + assert os.path.isdir(new) is False # space cleaning + #+end_src + + + [X] retraction of the date/time stamp + + Similar to the retraction of a prepended time stamp on files, the two + checks to remove a time stamp added by =--withtime= or =-w= currently fail + when running =pytest-3= on Linux Debian 12/bookworm, branch testing. + + #+begin_src python :tangle test_date2name.py + @pytest.mark.folders + @pytest.mark.remove + @pytest.mark.parametrize("arg1", ["default", + "compact", "month", "short", + "withtime"]) + @pytest.mark.parametrize("arg2", ["-r", "--remove"]) + def test_folder_remove_stamp(arg1, arg2, name=TFOLDER): + """Check the retraction of the leading time stamp.""" + substitution = {"default" : "2021-09-21", + "compact" : "20210921", + "month" : "2021-09", + "short" : "210921", + "withtime": "2021-09-21T13.59.59"} + prepend = substitution.get(arg1) + + # os.mkdir(name) + BASIS = str(name) + stamped_folder = "" + stamped_folder = "_".join([prepend, BASIS]) + os.mkdir(stamped_folder) + assert os.path.isdir(stamped_folder) # presence stamped folder + + test = getoutput(f"python3 {PROGRAM} {stamped_folder} {arg2}") + + assert os.path.isdir(stamped_folder) is False + assert os.path.isdir(name) # presence unstamped folder + os.rmdir(name) + assert os.path.isdir(name) is False # space cleaning + #+end_src + + + +