1import sys
2import yaml
3import hashlib
4
5DEFINE = 'YAML_GEN_TESTS'
6EVENT_COUNT = 5
7
8def encode_stream(line):
9    for c in line:
10        if c == '\n':
11            yield '\\n'
12        elif c == '"':
13            yield '\\"'
14        elif c == '\t':
15            yield '\\t'
16        elif ord(c) < 0x20:
17            yield '\\x' + hex(ord(c))
18        else:
19            yield c
20
21def encode(line):
22    return ''.join(encode_stream(line))
23
24def doc_start(implicit=False):
25    if implicit:
26        return {'emit': '', 'handle': 'OnDocumentStart(_)'}
27    else:
28        return {'emit': 'BeginDoc', 'handle': 'OnDocumentStart(_)'}
29
30def doc_end(implicit=False):
31    if implicit:
32        return {'emit': '', 'handle': 'OnDocumentEnd()'}
33    else:
34        return {'emit': 'EndDoc', 'handle': 'OnDocumentEnd()'}
35
36def scalar(value, tag='', anchor='', anchor_id=0):
37    emit = []
38    if tag:
39        emit += ['VerbatimTag("%s")' % encode(tag)]
40    if anchor:
41        emit += ['Anchor("%s")' % encode(anchor)]
42    if tag:
43        out_tag = encode(tag)
44    else:
45        if value == encode(value):
46            out_tag = '?'
47        else:
48            out_tag = '!'
49    emit += ['"%s"' % encode(value)]
50    return {'emit': emit, 'handle': 'OnScalar(_, "%s", %s, "%s")' % (out_tag, anchor_id, encode(value))}
51
52def comment(value):
53    return {'emit': 'Comment("%s")' % value, 'handle': ''}
54
55def seq_start(tag='', anchor='', anchor_id=0, style='_'):
56    emit = []
57    if tag:
58        emit += ['VerbatimTag("%s")' % encode(tag)]
59    if anchor:
60        emit += ['Anchor("%s")' % encode(anchor)]
61    if tag:
62        out_tag = encode(tag)
63    else:
64        out_tag = '?'
65    emit += ['BeginSeq']
66    return {'emit': emit, 'handle': 'OnSequenceStart(_, "%s", %s, %s)' % (out_tag, anchor_id, style)}
67
68def seq_end():
69    return {'emit': 'EndSeq', 'handle': 'OnSequenceEnd()'}
70
71def map_start(tag='', anchor='', anchor_id=0, style='_'):
72    emit = []
73    if tag:
74        emit += ['VerbatimTag("%s")' % encode(tag)]
75    if anchor:
76        emit += ['Anchor("%s")' % encode(anchor)]
77    if tag:
78        out_tag = encode(tag)
79    else:
80        out_tag = '?'
81    emit += ['BeginMap']
82    return {'emit': emit, 'handle': 'OnMapStart(_, "%s", %s, %s)' % (out_tag, anchor_id, style)}
83
84def map_end():
85    return {'emit': 'EndMap', 'handle': 'OnMapEnd()'}
86
87def gen_templates():
88    yield [[doc_start(), doc_start(True)],
89           [scalar('foo'), scalar('foo\n'), scalar('foo', 'tag'), scalar('foo', '', 'anchor', 1)],
90           [doc_end(), doc_end(True)]]
91    yield [[doc_start(), doc_start(True)],
92           [seq_start()],
93           [[], [scalar('foo')], [scalar('foo', 'tag')], [scalar('foo', '', 'anchor', 1)], [scalar('foo', 'tag', 'anchor', 1)], [scalar('foo'), scalar('bar')], [scalar('foo', 'tag', 'anchor', 1), scalar('bar', 'tag', 'other', 2)]],
94           [seq_end()],
95           [doc_end(), doc_end(True)]]
96    yield [[doc_start(), doc_start(True)],
97           [map_start()],
98           [[], [scalar('foo'), scalar('bar')], [scalar('foo', 'tag', 'anchor', 1), scalar('bar', 'tag', 'other', 2)]],
99           [map_end()],
100           [doc_end(), doc_end(True)]]
101    yield [[doc_start(True)],
102           [map_start()],
103           [[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
104           [[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
105           [map_end()],
106           [doc_end(True)]]
107    yield [[doc_start(True)],
108           [seq_start()],
109           [[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
110           [[scalar('foo')], [seq_start(), scalar('foo'), seq_end()], [map_start(), scalar('foo'), scalar('bar'), map_end()]],
111           [seq_end()],
112           [doc_end(True)]]
113
114def expand(template):
115    if len(template) == 0:
116        pass
117    elif len(template) == 1:
118        for item in template[0]:
119            if isinstance(item, list):
120                yield item
121            else:
122                yield [item]
123    else:
124        for car in expand(template[:1]):
125            for cdr in expand(template[1:]):
126                yield car + cdr
127
128
129def gen_events():
130    for template in gen_templates():
131        for events in expand(template):
132            base = list(events)
133            for i in range(0, len(base)+1):
134                cpy = list(base)
135                cpy.insert(i, comment('comment'))
136                yield cpy
137
138def gen_tests():
139    for events in gen_events():
140        name = 'test' + hashlib.sha1(''.join(yaml.dump(event) for event in events)).hexdigest()[:20]
141        yield {'name': name, 'events': events}
142
143class Writer(object):
144    def __init__(self, out):
145        self.out = out
146        self.indent = 0
147
148    def writeln(self, s):
149        self.out.write('%s%s\n' % (' ' * self.indent, s))
150
151class Scope(object):
152    def __init__(self, writer, name, indent):
153        self.writer = writer
154        self.name = name
155        self.indent = indent
156
157    def __enter__(self):
158        self.writer.writeln('%s {' % self.name)
159        self.writer.indent += self.indent
160
161    def __exit__(self, type, value, traceback):
162        self.writer.indent -= self.indent
163        self.writer.writeln('}')
164
165def create_emitter_tests(out):
166    out = Writer(out)
167
168    includes = [
169        'handler_test.h',
170        'yaml-cpp/yaml.h',
171        'gmock/gmock.h',
172        'gtest/gtest.h',
173    ]
174    for include in includes:
175        out.writeln('#include "%s"' % include)
176    out.writeln('')
177
178    usings = [
179        '::testing::_',
180    ]
181    for using in usings:
182        out.writeln('using %s;' % using)
183    out.writeln('')
184
185    with Scope(out, 'namespace YAML', 0) as _:
186        with Scope(out, 'namespace', 0) as _:
187            out.writeln('')
188            out.writeln('typedef HandlerTest GenEmitterTest;')
189            out.writeln('')
190            tests = list(gen_tests())
191
192            for test in tests:
193                with Scope(out, 'TEST_F(%s, %s)' % ('GenEmitterTest', test['name']), 2) as _:
194                    out.writeln('Emitter out;')
195                    for event in test['events']:
196                        emit = event['emit']
197                        if isinstance(emit, list):
198                            for e in emit:
199                                out.writeln('out << %s;' % e)
200                        elif emit:
201                            out.writeln('out << %s;' % emit)
202                    out.writeln('')
203                    for event in test['events']:
204                        handle = event['handle']
205                        if handle:
206                            out.writeln('EXPECT_CALL(handler, %s);' % handle)
207                    out.writeln('Parse(out.c_str());')
208                out.writeln('')
209
210if __name__ == '__main__':
211    create_emitter_tests(sys.stdout)
212