summaryrefslogtreecommitdiff
path: root/tools/boostbook/test/more/run-tests.py
blob: 2a56795426c081e9ac8c4f41d7adafad254945e1 (plain)
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
#!/usr/bin/env python

# Copyright 2010 Daniel James.
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

"""Boostbook tests

Usage: python build_docs.py [--generate-gold]
"""

import difflib, getopt, os, re, sys
import lxml.ElementInclude
from lxml import etree

# Globals

def usage_and_exit():
    print __doc__
    sys.exit(2)

def main(argv):
    script_directory = os.path.dirname(sys.argv[0])
    boostbook_directory = os.path.join(script_directory, "../../xsl")

    try:
        opts, args = getopt.getopt(argv, "",
            ["generate-gold"])
        if(len(args)): usage_and_exit()
    except getopt.GetoptError:
        usage_and_exit()

    generate_gold = False

    for opt, arg in opts:
        if opt == '--generate-gold':
            generate_gold = True

    # Walk the test directory

    parser = etree.XMLParser()
    
    try:
        boostbook_xsl = etree.XSLT(
            etree.parse(os.path.join(boostbook_directory, "docbook.xsl"), parser)
        )
    except lxml.etree.XMLSyntaxError, error:
        print "Error parsing boostbook xsl:"
        print error
        sys.exit(1)
    
    for root, dirs, files in os.walk(os.path.join(script_directory, 'tests')):
        for filename in files:
            (base, ext) = os.path.splitext(filename)
            if (ext == '.xml'):
                src_path = os.path.join(root, filename)
                gold_path = os.path.join(root, base + '.gold')
                try:
                    doc_text = run_boostbook(parser, boostbook_xsl, src_path)
                except:
                    # TODO: Need better error reporting here:
                    print "Error running boostbook for " + src_path
                    continue

                if (generate_gold):
                    file = open(gold_path, 'w')
                    try:
                        file.write(doc_text)
                    finally: file.close()
                else:
                    file = open(gold_path, 'r')
                    try:
                        gold_text = file.read()
                    finally:
                        file.close()
                    compare_xml(filename, doc_text, gold_text)

def run_boostbook(parser, boostbook_xsl, file):
    doc = boostbook_xsl(etree.parse(file, parser))
    normalize_boostbook_ids(doc)
    return etree.tostring(doc)

def normalize_boostbook_ids(doc):
    ids = {}
    id_bases = {}

    for node in doc.xpath("//*[starts-with(@id, 'id') or contains(@id, '_id')]"):
        id = node.get('id')
        
        if(id in ids):
            print 'Duplicate id: ' + id
        
        match = re.match("(id|.+_id)(\d+)((?:-bb)?)", id)
        if(match):
            count = 1
            if(match.group(1) in id_bases):
                count = id_bases[match.group(1)] + 1
            id_bases[match.group(1)] = count
            ids[id] = match.group(1) + str(count) + match.group(3)

    for node in doc.xpath("//*[@linkend or @id]"):
        x = node.get('linkend')
        if(x in ids): node.set('linkend', ids[x])
        x = node.get('id')
        if(x in ids): node.set('id', ids[x])

def compare_xml(file, doc_text, gold_text):
    # Had hoped to use xmldiff but it turned out to be a pain to install.
    # So instead just do a text diff.
    
    if (doc_text != gold_text):
        print "Error: " + file
        print
        sys.stdout.writelines(
            difflib.unified_diff(
                gold_text.splitlines(True),
                doc_text.splitlines(True)
            )
        )

if __name__ == "__main__":
    main(sys.argv[1:])