File: make-tests

package info (click to toggle)
gjs 1.32.0-5
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 4,436 kB
  • sloc: ansic: 27,721; sh: 11,157; makefile: 203; python: 120; cpp: 49
file content (168 lines) | stat: -rwxr-xr-x 5,918 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#! /usr/bin/env python

import os
import sys
import stat
import re
import errno

FILE_NOT_THERE=1
FILE_REGULAR=2
FILE_DIRECTORY=3
FILE_SYMLINK=4

## return tuple of (kind, mtime, size), or (FILE_NOT_THERE,0,0) if file not found
def stat_file(filename):
    try:
        s = os.stat(filename)
        kind = 0
        if stat.S_ISDIR(s.st_mode):
            kind = FILE_DIRECTORY
        elif stat.S_ISLNK(s.st_mode):
            kind = FILE_SYMLINK
        elif stat.S_ISREG(s.st_mode):
            kind = FILE_REGULAR
        else:
            raise Exception("Unknown file type (not a directory, regular, or link) %s" % filename)

        return (kind, s.st_mtime, s.st_size)
    except OSError, e:
        if e.errno == errno.ENOENT:
            return (FILE_NOT_THERE, 0, 0)
        else:
            raise

test_func_re = re.compile('gjstest_test_func_([a-zA-Z0-9_]+)')

def find_tests(base_filename, full_filename):
    f = open(full_filename)
    test_funcs = [] ## list of (path, funcname)

    found_expected_test_func = False
    in_tests = False
    for l in f.readlines():
        if 'GJS_BUILD_TESTS' in l:
            if '#if' in l:
                if in_tests:
                    raise Exception('GJS_BUILD_TESTS nested inside itself? ' + base_filename)
                else:
                    in_tests = True
            elif '#endif' in l:
                # GJS_BUILD_TESTS should have been in a comment post-endif
                if not in_tests:
                    raise Exception('#endif /* GJS_BUILD_TESTS */ found but no #if in ' + base_filename)
                else:
                    in_tests = False

        ## do the substring check before re match so we can plow
        ## through the file quickly and only do the more expensive
        ## match on relevant lines
        elif 'gjstest_test_func_' in l:
            match = test_func_re.search(l)
            if not match:
                raise Exception('line does not match test_func_re in ' + base_filename + ': ' + l)
            subname = match.group(1)
            funcname = 'gjstest_test_func_' + subname

            if not in_tests:
                raise Exception("Test func %s in %s not inside GJS_BUILD_TESTS" % (funcname, base_filename))

            ## check namespacing
            expected_subname = ''
            rest = base_filename
            while rest != '':
                (rest, last) = os.path.split(rest)
                if last != '':
                    last = last.replace('-', '_')
                    if expected_subname != '':
                        expected_subname = last + '_' + expected_subname
                    else:
                        (last, ext) = os.path.splitext(last)
                        expected_subname = last

            if not subname.startswith(expected_subname):
                raise Exception("Test funcs in '%s' should start with gjstest_test_func_%s" % (base_filename, expected_subname))

            test_path = '/' + subname.replace('_', '/')

            test_funcs.append((test_path, funcname))

    if in_tests:
        raise Exception('no #endif /* GJS_BUILD_TESTS */ found - comment with GJS_BUILD_TESTS in it is mandatory')

    ## return a tuple, so we can add other kinds of stuff to find later
    return (test_funcs)

output_dir = sys.argv[1]
input_files = sys.argv[2:]
top_srcdir = os.getenv('TOP_SRCDIR')

out_header_name = os.path.join(output_dir, "gjstest.h")
out_impl_name = os.path.join(output_dir, "gjstest.c")

(out_header_kind, out_header_mtime, out_header_size) = stat_file(out_header_name)
(out_impl_kind, out_impl_mtime, out_impl_size) = stat_file(out_impl_name)

out_header_tmp_name = out_header_name + ".stamp"
out_impl_tmp_name = out_impl_name + ".stamp"

all_test_funcs = []

for filename in input_files:
    (test_funcs) = find_tests(filename, os.path.join(top_srcdir, filename))
    all_test_funcs = all_test_funcs + test_funcs

header_out = open(out_header_tmp_name, 'w')
impl_out = open(out_impl_tmp_name, 'w')

def write_generic_c_boilerplate(f):
    f.write('/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */\n')
    f.write('/* FILE AUTOGENERATED DO NOT EDIT */\n')
    f.write('\n')

write_generic_c_boilerplate(header_out)
write_generic_c_boilerplate(impl_out)

header_out.write('#ifndef __GJS_GJSTEST_GENERATED_H__\n')
header_out.write('#define __GJS_GJSTEST_GENERATED_H__\n\n')
header_out.write('#include <glib.h>\n\n')
header_out.write('G_BEGIN_DECLS\n\n')

header_out.write('void gjstest_add_all_tests(void);\n\n')

impl_out.write('#include <gjstest.h>\n\n')

impl_out.write('void\n')
impl_out.write('gjstest_add_all_tests(void)\n')
impl_out.write('{\n')

for (path, func) in all_test_funcs:
    impl_out.write('    g_test_add_func("%s", %s);\n' % (path, func))

    header_out.write('void %s(void);\n' % (func))

impl_out.write('}\n')

header_out.write('\n')
header_out.write('G_END_DECLS\n\n')
header_out.write('#endif  /* __GJS_GJSTEST_GENERATED_H__ */\n')

## close so we can stat and rename
impl_out.close()
header_out.close()

## rename only if changed, to avoid needless rebuilds.
## we use the size to decide if it changed... not really
## quite kosher, but will fail infrequently enough to
## not be annoying
(new_header_kind, new_header_mtime, new_header_size) = stat_file(out_header_tmp_name)
(new_impl_kind, new_impl_mtime, new_impl_size) = stat_file(out_impl_tmp_name)

if new_header_size != out_header_size or new_impl_size != out_impl_size:
    print "Replacing old %s and %s" % (out_header_name, out_impl_name)
    print "   %s  was %d bytes now %d" % (out_header_name, out_header_size, new_header_size)
    print "   %s  was %d bytes now %d" % (out_impl_name, out_impl_size, new_impl_size)
    os.rename(out_header_tmp_name, out_header_name)
    os.rename(out_impl_tmp_name, out_impl_name)
else:
    print "%s and %s appear to be unchanged, not updating" % (out_header_name, out_impl_name)