aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ext_depends/D-YAML/source/dyaml/test/common.d
blob: a6bafa98140a342ac63a852b133dffdc4566dd0a (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
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//          Copyright Ferdinand Majerech 2011.
// 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)

module dyaml.test.common;

version(unittest)
{

import dyaml.node;
import dyaml.event;

import core.exception;
import std.algorithm;
import std.array;
import std.conv;
import std.file;
import std.range;
import std.path;
import std.traits;
import std.typecons;

package:

/**
Run a test.

Params:
    testFunction = Unittest function.
    unittestExt = Extensions of data files needed for the unittest.
    skipExt = Extensions that must not be used for the unittest.
 */
void run(D)(D testFunction, string[] unittestExt, string[] skipExt = [])
{
    immutable string dataDir = __FILE_FULL_PATH__.dirName ~  "/../../../test/data";
    auto testFilenames = findTestFilenames(dataDir);

    if (unittestExt.length > 0)
    {
        outer: foreach (base, extensions; testFilenames)
        {
            string[] filenames;
            foreach (ext; unittestExt)
            {
                if (!extensions.canFind(ext))
                {
                    continue outer;
                }
                filenames ~= base ~ '.' ~ ext;
            }
            foreach (ext; skipExt)
            {
                if (extensions.canFind(ext))
                {
                    continue outer;
                }
            }

            execute(testFunction, filenames);
        }
    }
    else
    {
        execute(testFunction, string[].init);
    }
}

// TODO: remove when a @safe ubyte[] file read can be done.
/**
Reads a file as an array of bytes.

Params:
    filename = Full path to file to read.

Returns: The file's data.
*/
ubyte[] readData(string filename) @trusted
{
    import std.file : read;
    return cast(ubyte[])read(filename);
}
void assertNodesEqual(const scope Node gotNode, const scope Node expectedNode) @safe
{
    import std.format : format;
    assert(gotNode == expectedNode, format!"got %s, expected %s"(gotNode.debugString, expectedNode.debugString));
}

/**
Determine if events in events1 are equivalent to events in events2.

Params:
    events1 = A range of events to compare with.
    events2 = A second range of events to compare.

Returns: true if the events are equivalent, false otherwise.
*/
bool compareEvents(T, U)(T events1, U events2)
if (isInputRange!T && isInputRange!U && is(ElementType!T == Event) && is(ElementType!U == Event))
{
    foreach (e1, e2; zip(events1, events2))
    {
        //Different event types.
        if (e1.id != e2.id)
        {
            return false;
        }
        //Different anchor (if applicable).
        if (e1.id.among!(EventID.sequenceStart, EventID.mappingStart, EventID.alias_, EventID.scalar)
            && e1.anchor != e2.anchor)
        {
            return false;
        }
        //Different collection tag (if applicable).
        if (e1.id.among!(EventID.sequenceStart, EventID.mappingStart) && e1.tag != e2.tag)
        {
            return false;
        }
        if (e1.id == EventID.scalar)
        {
            //Different scalar tag (if applicable).
            if (!(e1.implicit || e2.implicit) && e1.tag != e2.tag)
            {
                return false;
            }
            //Different scalar value.
            if (e1.value != e2.value)
            {
                return false;
            }
        }
    }
    return true;
}
/**
Throw an Error if events in events1 aren't equivalent to events in events2.

Params:
    events1 = First event array to compare.
    events2 = Second event array to compare.
*/
void assertEventsEqual(T, U)(T events1, U events2)
if (isInputRange!T && isInputRange!U && is(ElementType!T == Event) && is(ElementType!U == Event))
{
    auto events1Copy = events1.array;
    auto events2Copy = events2.array;
    assert(compareEvents(events1Copy, events2Copy), text("Got '", events1Copy, "', expected '", events2Copy, "'"));
}

private:

/**
Find unittest input filenames.

Params:  dir = Directory to look in.

Returns: Test input base filenames and their extensions.
*/
 //@trusted due to dirEntries
string[][string] findTestFilenames(const string dir) @trusted
{
    //Groups of extensions indexed by base names.
    string[][string] names;
    foreach (string name; dirEntries(dir, SpanMode.shallow))
    {
        if (isFile(name))
        {
            string base = name.stripExtension();
            string ext = name.extension();
            if (ext is null)
            {
                ext = "";
            }
            if (ext[0] == '.')
            {
                ext = ext[1 .. $];
            }

            //If the base name doesn't exist yet, add it; otherwise add new extension.
            names[base] = ((base in names) is null) ? [ext] : names[base] ~ ext;
        }
    }
    return names;
}

/**
Recursively copy an array of strings to a tuple to use for unittest function input.

Params:
    index = Current index in the array/tuple.
    tuple = Tuple to copy to.
    strings = Strings to copy.
*/
void stringsToTuple(uint index, F ...)(ref F tuple, const string[] strings)
in(F.length == strings.length)
do
{
    tuple[index] = strings[index];
    static if (index > 0)
    {
        stringsToTuple!(index - 1, F)(tuple, strings);
    }
}

/**
Execute an unittest on specified files.

Params:
    testName = Name of the unittest.
    testFunction = Unittest function.
    filenames = Names of input files to test with.
 */
void execute(D)(D testFunction, string[] filenames)
{
    //Convert filenames to parameters tuple and call the test function.
    alias F = Parameters!D[0..$];
    F parameters;
    stringsToTuple!(F.length - 1, F)(parameters, filenames);
    testFunction(parameters);
}

} // version(unittest)