1import logging
2import os
3import re
4import subprocess
5
6import dune.common.module
7
8from dune.common.utility import buffer_to_str
9from dune.generator import builder, ConfigurationError
10
11logger = logging.getLogger(__name__)
12
13def assertHave(identifier):
14    '''check if an identifier is defined equal to 1 in the dune-py config.h file.
15       use this to check if for example #define HAVE_DUNE_COMMON 1 is
16       provided the config file by calling
17       assertHave("HAVE_DUNE_COMMON")
18    '''
19    config = os.path.join(dune.common.module.get_dune_py_dir(), "config.h")
20
21    matches = [match for match in [re.match('^[ ]*#define[ ]+' + identifier.strip() + '[ ]+1$', line) for line in open(config)] if match is not None]
22    if not matches:
23        matches = [match for match in [re.match('^[ ]*#define[ ]+' + identifier.strip() + '[ ]+ENABLE', line) for line in open(config)] if match is not None]
24
25    if not matches:
26        raise ConfigurationError(identifier + " is not set in dune-py's config.h")
27    elif matches.__len__() > 1:
28        raise ConfigurationError(identifier + " found multiple times in dune-py's config.h")
29
30def assertCMakeVariable(identifier,value,defaultFails):
31    '''check if a variable in CMakeCache.txt in dune-py is defined and equal to 'value'
32    '''
33    cache = os.path.join(dune.common.module.get_dune_py_dir(), "CMakeCache.txt")
34
35    identifier = identifier.lower().strip()
36    matches = [line.lower() for line in open(cache) if re.match('^[ ]*'+identifier+':+', line.lower()) is not None]
37    if not matches and defaultFails:
38        raise ConfigurationError(identifier + " default behavior is used in dune-py and that is not allowed")
39    elif len(matches) > 1:
40        raise ConfigurationError(identifier + " found multiple times in dune-py's config.h")
41    elif matches:
42        # check for bool on/off type variables:
43        bools = {True:["on","true","1"], False:["off","false","0"]}
44        if not [x for x in bools[value] if x in matches[0]]:
45            raise ConfigurationError(identifier + " dune-py wrongly configured wrt "+identifier)
46
47def preprocessorAssert(tests):
48    '''perform preprocessore checks.
49       A list of checks can be provided each should contain a pair, the
50       first being the preprocessor check to perform (e.g. #if or #ifdef)
51       and the second being the message to print if the check fails. The
52       generated code is of the form:
53          tests[i][0]
54          #else
55          test failed
56          #endif
57       so the first argument of each test has to make this piece of code
58       valid C++ code assuming config.h is included.
59    '''
60    source = "#include <config.h>\nint main() {\n"
61    i = 0
62    for t in tests:
63        source = source + t[0]+"\n#else\nreturn "+str(i+1)+";\n#endif\n"
64        i += 1
65    source = source + "return 0;\n}\n"
66
67    with open(os.path.join(builder.generated_dir, "generated_module.hh"), 'w') as out:
68        out.write(source)
69    builder.compile("generated_test")
70
71    test_args = ["./generated_test"]
72    test = subprocess.Popen(test_args, cwd=builder.generated_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
73    stdout, stderr = test.communicate()
74    logger.debug(buffer_to_str(stdout))
75    returncode = test.returncode
76
77    if returncode > 0:
78        logger.debug("failed testing:\n"+source)
79        logger.critical("checking "+tests[returncode-1][0]+" failed: "+tests[returncode-1][1])
80        raise ConfigurationError(tests[returncode-1][1])
81