handlermacros.h 6.38 KB
Newer Older
1
#include "teststruct.h"
2
3
4
5
6
7
8
9
#pragma once

#include "yaml-cpp/yaml.h"
#include "yaml-cpp/eventhandler.h"
#include <string>
#include <cassert>

namespace Test {
10
    inline std::string Quote(const std::string& text) {
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
        YAML::Emitter out;
        out << YAML::DoubleQuoted << text;
        return out.c_str();
    }
    
    struct Event {
        enum Type { DocStart, DocEnd, Null, Alias, Scalar, SeqStart, SeqEnd, MapStart, MapEnd };
        
        typedef YAML::Mark Mark;
        typedef YAML::anchor_t anchor_t;
        
        Event(Type type_, const std::string& tag_, anchor_t anchor_, const std::string& scalar_): type(type_), tag(tag_), anchor(anchor_), scalar(scalar_) {}
        
        Type type;
        std::string tag;
        anchor_t anchor;
        std::string scalar;
        
        std::ostream& write(std::ostream& out) const {
            switch(type) {
                case DocStart:
                    return out << "DocStart";
                case DocEnd:
                    return out << "DocEnd";
                case Null:
                    return out << "Null(" << anchor << ")";
                case Alias:
                    return out << "Alias(" << anchor << ")";
                case Scalar:
                    return out << "Scalar(" << Quote(tag) << ", " << anchor << ", " << Quote(scalar) << ")";
                case SeqStart:
                    return out << "SeqStart(" << Quote(tag) << ", " << anchor << ")";
                case SeqEnd:
                    return out << "SeqEnd";
                case MapStart:
                    return out << "MapStart(" << Quote(tag) << ", " << anchor << ")";
                case MapEnd:
                    return out << "MapEnd";
            }
            assert(false);
            return out;
        }
    };
    
55
    inline std::ostream& operator << (std::ostream& out, const Event& event) {
56
57
58
        return event.write(out);
    }
    
59
    inline bool operator == (const Event& a, const Event& b) {
60
61
62
        return a.type == b.type && a.tag == b.tag && a.anchor == b.anchor && a.scalar == b.scalar;
    }
    
63
    inline bool operator != (const Event& a, const Event& b) {
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
        return !(a == b);
    }
    
	class MockEventHandler: public YAML::EventHandler
	{
	public:
        typedef YAML::Mark Mark;
        typedef YAML::anchor_t anchor_t;
        
        MockEventHandler() {}
        
		virtual void OnDocumentStart(const Mark&) {
            m_actualEvents.push_back(Event(Event::DocStart, "", 0, ""));
        }
        
		virtual void OnDocumentEnd() {
            m_actualEvents.push_back(Event(Event::DocEnd, "", 0, ""));
        }
		
		virtual void OnNull(const Mark&, anchor_t anchor) {
            m_actualEvents.push_back(Event(Event::Null, "", anchor, ""));
        }
        
		virtual void OnAlias(const Mark&, anchor_t anchor) {
            m_actualEvents.push_back(Event(Event::Alias, "", anchor, ""));
        }
        
		virtual void OnScalar(const Mark&, const std::string& tag, anchor_t anchor, const std::string& value) {
            m_actualEvents.push_back(Event(Event::Scalar, tag, anchor, value));
        }
        
		virtual void OnSequenceStart(const Mark&, const std::string& tag, anchor_t anchor) {
            m_actualEvents.push_back(Event(Event::SeqStart, tag, anchor, ""));
        }
        
		virtual void OnSequenceEnd() {
            m_actualEvents.push_back(Event(Event::SeqEnd, "", 0, ""));
        }
        
		virtual void OnMapStart(const Mark&, const std::string& tag, anchor_t anchor) {
            m_actualEvents.push_back(Event(Event::MapStart, tag, anchor, ""));
        }
        
		virtual void OnMapEnd() {
            m_actualEvents.push_back(Event(Event::MapEnd, "", 0, ""));
        }
        
        void Expect(const Event& event) { m_expectedEvents.push_back(event); }
        
        Test::TEST Check() const {
            std::size_t N = std::max(m_expectedEvents.size(), m_actualEvents.size());
            for(std::size_t i=0;i<N;i++) {
                if(i >= m_expectedEvents.size()) {
                    std::stringstream out;
                    for(std::size_t j=0;j<i;j++) {
                        out << "  " << m_expectedEvents[j] << "\n";
                    }
                    out << "  EXPECTED: (no event expected)\n";
                    out << "  ACTUAL  : " << m_actualEvents[i] << "\n";
                    return out.str().c_str();
                }
                
                if(i >= m_actualEvents.size()) {
                    std::stringstream out;
                    for(std::size_t j=0;j<i;j++) {
                        out << "  " << m_expectedEvents[j] << "\n";
                    }
                    out << "  EXPECTED: " << m_expectedEvents[i] << "\n";
                    out << "  ACTUAL  : (no event recorded)\n";
                    return out.str().c_str();
                }
                
                if(m_expectedEvents[i] != m_actualEvents[i]) {
                    std::stringstream out;
                    for(std::size_t j=0;j<i;j++) {
                        out << "  " <<  m_expectedEvents[j] << "\n";
                    }
                    out << "  EXPECTED: " << m_expectedEvents[i] << "\n";
                    out << "  ACTUAL  : " << m_actualEvents[i] << "\n";
                    return out.str().c_str();
                }
            }
            
            return true;
        }
        
        std::vector<Event> m_expectedEvents;
        std::vector<Event> m_actualEvents;
	};
    
#define HANDLE(ex)\
MockEventHandler handler;\
std::stringstream stream(ex);\
YAML::Parser parser(stream);\
158
while(parser.HandleNextDocument(handler)) {}
159
160

#define EXPECT_DOC_START()\
161
handler.Expect(Event(Event::DocStart, "", 0, ""))
162
163
    
#define EXPECT_DOC_END()\
164
handler.Expect(Event(Event::DocEnd, "", 0, ""))
165
166
    
#define EXPECT_NULL(anchor)\
167
handler.Expect(Event(Event::Null, "", anchor, ""))
168
169
    
#define EXPECT_ALIAS(anchor)\
170
handler.Expect(Event(Event::Alias, "", anchor, ""))
171
172
    
#define EXPECT_SCALAR(tag, anchor, value)\
173
handler.Expect(Event(Event::Scalar, tag, anchor, value))
174
175
    
#define EXPECT_SEQ_START(tag, anchor)\
176
handler.Expect(Event(Event::SeqStart, tag, anchor, ""))
177
178
    
#define EXPECT_SEQ_END()\
179
handler.Expect(Event(Event::SeqEnd, "", 0, ""))
180
181
    
#define EXPECT_MAP_START(tag, anchor)\
182
handler.Expect(Event(Event::MapStart, tag, anchor, ""))
183
184
    
#define EXPECT_MAP_END()\
185
handler.Expect(Event(Event::MapEnd, "", 0, ""))
186
187
    
#define DONE()\
188
return handler.Check()
189
190
    
}