Merge pull request #48 from PQClean/ds-check-makefile-dependencies
Add test to check that every .c / .h file triggers a library rebuild
This commit is contained in:
commit
b81652e9e4
@ -1,7 +1,7 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
def run_subprocess(command, working_dir, expected_returncode=0):
|
def run_subprocess(command, working_dir='.', expected_returncode=0):
|
||||||
"""
|
"""
|
||||||
Helper function to run a shell command and report success/failure
|
Helper function to run a shell command and report success/failure
|
||||||
depending on the exit status of the shell command.
|
depending on the exit status of the shell command.
|
||||||
@ -15,6 +15,7 @@ def run_subprocess(command, working_dir, expected_returncode=0):
|
|||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
cwd=working_dir
|
cwd=working_dir
|
||||||
)
|
)
|
||||||
|
print(working_dir + " > " + " ".join(command))
|
||||||
print(result.stdout.decode('utf-8'))
|
print(result.stdout.decode('utf-8'))
|
||||||
assert(result.returncode == expected_returncode)
|
assert(result.returncode == expected_returncode)
|
||||||
return result.stdout.decode('utf-8')
|
return result.stdout.decode('utf-8')
|
||||||
|
@ -69,6 +69,9 @@ class Implementation:
|
|||||||
def path(self, base='..') -> str:
|
def path(self, base='..') -> str:
|
||||||
return os.path.join(self.scheme.path(), self.name)
|
return os.path.join(self.scheme.path(), self.name)
|
||||||
|
|
||||||
|
def libname(self) -> str:
|
||||||
|
return "lib{}_{}.a".format(self.scheme.name, self.name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def by_name(scheme_name, implementation_name):
|
def by_name(scheme_name, implementation_name):
|
||||||
scheme = Scheme.by_name(scheme_name)
|
scheme = Scheme.by_name(scheme_name)
|
||||||
|
67
test/test_makefile_dependencies.py
Normal file
67
test/test_makefile_dependencies.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
Checks that every .c and .h file in an implementation is present as a
|
||||||
|
dependency of that scheme's Makefile.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import pqclean
|
||||||
|
import helpers
|
||||||
|
import subprocess
|
||||||
|
import glob
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def test_makefile_dependencies():
|
||||||
|
for scheme in pqclean.Scheme.all_schemes():
|
||||||
|
for implementation in scheme.implementations:
|
||||||
|
# initial build - want to have all files in place at beginning
|
||||||
|
helpers.run_subprocess(['make', 'clean'], implementation.path())
|
||||||
|
helpers.run_subprocess(['make'], implementation.path())
|
||||||
|
# test case for each candidate file
|
||||||
|
cfiles = glob.glob(os.path.join(implementation.path(), '*.c'))
|
||||||
|
hfiles = glob.glob(os.path.join(implementation.path(), '*.h'))
|
||||||
|
for file in cfiles + hfiles:
|
||||||
|
yield check_makefile_dependencies, scheme.name, implementation.name, file
|
||||||
|
|
||||||
|
def check_makefile_dependencies(scheme_name, implementation_name, file):
|
||||||
|
scheme = pqclean.Scheme.by_name(scheme_name)
|
||||||
|
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
|
||||||
|
|
||||||
|
cfiles = glob.glob(os.path.join(implementation.path(), '*.c'))
|
||||||
|
hfiles = glob.glob(os.path.join(implementation.path(), '*.h'))
|
||||||
|
ofiles = glob.glob(os.path.join(implementation.path(), '*.o'))
|
||||||
|
|
||||||
|
libfile = os.path.join(implementation.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()
|
||||||
|
ago15 = now - datetime.timedelta(seconds=15)
|
||||||
|
ago10 = now - datetime.timedelta(seconds=10)
|
||||||
|
ago5 = now - datetime.timedelta(seconds=5)
|
||||||
|
formatstring = "%Y%m%d%H%M.%S"
|
||||||
|
helpers.run_subprocess(['touch', '-t', ago15.strftime(formatstring)] + cfiles + hfiles)
|
||||||
|
helpers.run_subprocess(['touch', '-t', ago10.strftime(formatstring)] + ofiles)
|
||||||
|
helpers.run_subprocess(['touch', '-t', ago5.strftime(formatstring), libfile])
|
||||||
|
mtime_lib_orig = os.stat(libfile).st_mtime_ns
|
||||||
|
|
||||||
|
# touch the candidate .c / .h file
|
||||||
|
helpers.run_subprocess(['touch', '-t', now.strftime(formatstring), file])
|
||||||
|
|
||||||
|
# rebuild
|
||||||
|
helpers.run_subprocess(['make'], implementation.path())
|
||||||
|
|
||||||
|
# make sure the libfile's modification time changed
|
||||||
|
mtime_lib_upd = os.stat(libfile).st_mtime_ns
|
||||||
|
if (mtime_lib_orig == mtime_lib_upd):
|
||||||
|
print("ERROR: Library was not updated after touching {}".format(file))
|
||||||
|
assert(mtime_lib_orig != mtime_lib_upd)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
import nose2
|
||||||
|
nose2.main()
|
||||||
|
except ImportError:
|
||||||
|
import nose
|
||||||
|
nose.runmodule()
|
Loading…
Reference in New Issue
Block a user