Browse Source

Merge pull request #48 from PQClean/ds-check-makefile-dependencies

Add test to check that every .c / .h file triggers a library rebuild
tags/v0.0.1
Thom Wiggers 5 years ago
committed by GitHub
parent
commit
b81652e9e4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 1 deletions
  1. +2
    -1
      test/helpers.py
  2. +3
    -0
      test/pqclean.py
  3. +67
    -0
      test/test_makefile_dependencies.py

+ 2
- 1
test/helpers.py View File

@@ -1,7 +1,7 @@
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
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,
cwd=working_dir
)
print(working_dir + " > " + " ".join(command))
print(result.stdout.decode('utf-8'))
assert(result.returncode == expected_returncode)
return result.stdout.decode('utf-8')

+ 3
- 0
test/pqclean.py View File

@@ -69,6 +69,9 @@ class Implementation:
def path(self, base='..') -> str:
return os.path.join(self.scheme.path(), self.name)

def libname(self) -> str:
return "lib{}_{}.a".format(self.scheme.name, self.name)

@staticmethod
def by_name(scheme_name, implementation_name):
scheme = Scheme.by_name(scheme_name)


+ 67
- 0
test/test_makefile_dependencies.py View 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…
Cancel
Save