- """
- Checks that every .c and .h file in an implementation is present as a
- dependency of that scheme's Makefile.
- """
-
- import datetime
- import glob
- import os
-
- import pytest
-
- import helpers
- import pqclean
-
-
- @pytest.mark.parametrize(
- 'implementation,test_dir,impl_path, init, destr',
- [(impl,
- *helpers.isolate_test_files(impl.path(), 'test_makefile_deps_'))
- for impl in pqclean.Scheme.all_supported_implementations()],
- ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
- )
- @helpers.filtered_test
- def test_makefile_dependencies(implementation, impl_path, test_dir,
- init, destr):
- init()
- # initial build - want to have *all* files in place at beginning
- helpers.make('clean', working_dir=impl_path)
- helpers.make(working_dir=impl_path)
- # test case for each candidate file
- cfiles = glob.glob(os.path.join(impl_path, '*.c'))
- sfiles = glob.glob(os.path.join(impl_path, '*.[sS]'))
- incfiles = glob.glob(os.path.join(impl_path, '*.inc'))
- hfiles = glob.glob(os.path.join(impl_path, '*.h'))
- try:
- for file in (cfiles + hfiles + sfiles + incfiles):
- check_makefile_dependencies(implementation, impl_path, file)
- except Exception as e:
- print("Affected file: {}".format(file))
- raise e
- finally:
- destr()
-
-
- def touch(time, *files):
- for path in files:
- times = (time.timestamp(), time.timestamp())
- os.utime(path, times)
-
-
- def make_check(path, expect_error=False):
- makeflag = '-q' if os.name != 'nt' else '/Q'
- expected_returncode = 0
- if expect_error:
- expected_returncode = 1 if os.name != 'nt' else 255
- helpers.make(makeflag, working_dir=path,
- expected_returncode=expected_returncode)
-
-
- def check_makefile_dependencies(implementation, impl_path, file):
- cfiles = glob.glob(os.path.join(impl_path, '*.c'))
- sfiles = glob.glob(os.path.join(impl_path, '*.[sS]'))
- hfiles = glob.glob(os.path.join(impl_path, '*.h'))
- incfiles = glob.glob(os.path.join(impl_path, '*.inc'))
- o_ext = '*.o' if os.name != 'nt' else '*.obj'
- ofiles = glob.glob(os.path.join(impl_path, o_ext))
-
- # handle dependency files: these also need to be set correctly
- commondir = os.path.join(impl_path, '..', '..', '..', 'common')
- cfiles += glob.glob(os.path.join(commondir, '*.c'))
- cfiles += glob.glob(os.path.join(commondir, '**', '*.c'))
- hfiles += glob.glob(os.path.join(commondir, '*.h'))
- hfiles += glob.glob(os.path.join(commondir, '**', '*.h'))
- incfiles.append(os.path.join(commondir, 'keccak4x', 'KeccakP-1600-unrolling.macros'))
- ofiles += glob.glob(os.path.join(commondir, o_ext))
- ofiles += glob.glob(os.path.join(commondir, '**', o_ext))
-
- libfile = os.path.join(impl_path, implementation.libname())
-
- # modification time-based calculations is tricky on a sub-second basis
- # so we reset all the modification times to a known and "sensible" order
- now = datetime.datetime.now() - datetime.timedelta(seconds=10)
- ago15 = now - datetime.timedelta(minutes=15)
- ago10 = now - datetime.timedelta(minutes=10)
- ago5 = now - datetime.timedelta(minutes=5)
-
- touch(ago15, *cfiles, *sfiles, *hfiles, *incfiles)
- touch(ago10, *ofiles)
- touch(ago5, libfile)
-
- # Sanity check: the scheme is up to date
- make_check(impl_path)
-
- # touch the candidate .c / .h file
- touch(now, file)
-
- # check if it needs to be rebuilt using make -q
- make_check(impl_path, expect_error=True)
-
-
- if __name__ == '__main__':
- import sys
- pytest.main(sys.argv)
|