1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# 5# Copyright 2017, Data61 6# Commonwealth Scientific and Industrial Research Organisation (CSIRO) 7# ABN 41 687 119 230. 8# 9# This software may be distributed and modified according to the terms of 10# the BSD 2-Clause license. Note that NO WARRANTY is provided. 11# See "LICENSE_BSD2.txt" for details. 12# 13# @TAG(DATA61_BSD) 14# 15 16from __future__ import absolute_import, division, print_function, \ 17 unicode_literals 18 19import collections, os, shutil, subprocess, tempfile, unittest 20 21def which(command): 22 with open(os.devnull, 'wt') as f: 23 try: 24 return subprocess.check_output(['which', command], stderr=f, 25 universal_newlines=True).strip() 26 except subprocess.CalledProcessError: 27 return None 28 29_cpp_available = None 30def cpp_available(): 31 global _cpp_available 32 if _cpp_available is None: 33 _cpp_available = which('cpp') 34 return _cpp_available 35 36_spin_available = None 37def spin_available(): 38 global _spin_available 39 if _spin_available is None: 40 _spin_available = which('spin') 41 return _spin_available 42 43_plyplus_introspectible = None 44def plyplus_introspectible(): 45 ''' 46 Returns True if plyplus' internals look like we expect. 47 48 This is irrelevant except for tests that need to reach into plyplus and 49 poke at its beating heart. If this function returns False, your only option 50 to re-enable tests that depend on it is to inspect the plyplus sources and 51 figure out what needs to be updated on our side. 52 ''' 53 global _plyplus_introspectible 54 if _plyplus_introspectible is None: 55 try: 56 from plyplus.grammar_parser import parse 57 _plyplus_introspectible = True 58 except ImportError: 59 _plyplus_introspectible = False 60 return _plyplus_introspectible 61 62_c_compiler = None 63def c_compiler(): 64 ''' 65 Find a C compiler or return `None` if we don't have one. 66 ''' 67 global _c_compiler 68 if _c_compiler is None: 69 for cc in ('ccomp', # CompCert 70 'gcc', # GCC 71 'clang', # Clang 72 ): 73 _c_compiler = which(cc) 74 if _c_compiler is not None: 75 break 76 return _c_compiler 77 78_python_available = None 79def python_available(): 80 ''' 81 Test whether we can call out to the Python binary. 82 ''' 83 global _python_available 84 if _python_available is None: 85 _python_available = which('python') 86 return _python_available 87 88_sha256sum_available = None 89def sha256sum_available(): 90 ''' 91 Test whether we can call out to sha256sum. 92 ''' 93 global _sha256sum_available 94 if _sha256sum_available is None: 95 _sha256sum_available = which('sha256sum') 96 return _sha256sum_available 97 98class CAmkESTest(unittest.TestCase): 99 ''' 100 A `unittest` test case with a few more bells and whistles. 101 ''' 102 def setUp(self): 103 self.tempdirs = [] 104 self.tempfiles = [] 105 106 def mkdtemp(self): 107 tmp = tempfile.mkdtemp() 108 self.tempdirs.append(tmp) 109 return tmp 110 111 def mkstemp(self): 112 _, tmp = tempfile.mkstemp() 113 self.tempfiles.append(tmp) 114 return tmp 115 116 def execute(self, argv, cwd=os.getcwd(), env=os.environ): 117 p = subprocess.Popen(argv, stdout=subprocess.PIPE, 118 stderr=subprocess.PIPE, cwd=cwd, env=env, universal_newlines=True) 119 stdout, stderr = p.communicate() 120 return p.returncode, stdout, stderr 121 122 def tearDown(self): 123 [shutil.rmtree(t) for t in self.tempdirs] 124 [os.remove(t) for t in self.tempfiles] 125 126 def assertLen(self, container, *args): 127 ''' 128 Assert the length of a variable. 129 130 I find this is a common operation I want to do in the CAmkES test suite 131 but there seems to be no `unittest` builtin for it. 132 ''' 133 assert isinstance(container, collections.Iterable) 134 return self.assertEqual(len(container), *args) 135