unittest_util.cc 5.69 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// $Id$

17
#include <config.h>
18

19
20
21
22
23
24
25
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <vector>
#include <string>

26
27
#include <gtest/gtest.h>

28
#include <dns/name.h>
29
30
#include "unittest_util.h"

31
32
using namespace std;

33
using isc::UnitTestUtil;
34
using isc::dns::NameComparisonResult;
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
namespace {
class UnitTestUtilConfig {
private:
    // This is a singleton object and cannot be constructed explicitly.
    UnitTestUtilConfig() {}
    UnitTestUtilConfig(const UnitTestUtilConfig& source);
    ~UnitTestUtilConfig() {}
public:
    /// Return a singleton unit test configuration object.  On first invocation
    /// one will be constructed.
    static UnitTestUtilConfig& getConfig();

    /// A list of paths to wire data files.
    /// \c UnitTestUtil::readWireData() (first version)
    /// will search the directories in this list for the specified data file.
    std::vector<string> data_paths_;
};

UnitTestUtilConfig&
UnitTestUtilConfig::getConfig() {
    static UnitTestUtilConfig config;
    return (config);
}
}

61
void
62
UnitTestUtil::readWireData(const char* datafile, vector<unsigned char>& data) {
63
    ifstream ifs;
64
65
66
67
68

    const UnitTestUtilConfig& config = UnitTestUtilConfig::getConfig();
    vector<string>::const_iterator it = config.data_paths_.begin();
    for (; it != config.data_paths_.end(); ++it) {
        string data_path = *it;
69
        if (data_path.empty() || *data_path.rbegin() != '/') {
70
71
72
73
74
75
76
77
78
79
80
            data_path.push_back('/');
        }
        ifs.open((data_path + datafile).c_str(), ios_base::in);
        if ((ifs.rdstate() & istream::failbit) == 0) {
            break;
        }
    }

    if (it == config.data_paths_.end()) {
        throw runtime_error("failed to open data file in data paths: " +
                            string(datafile));
81
82
83
84
    }

    data.clear();

85
    string s;
86
87
    while (getline(ifs, s), !ifs.eof()) {
        if (ifs.bad() || ifs.fail()) {
88
            throw runtime_error("unexpected data line");
89
90
91
92
93
94
95
96
97
        }
        if (s.empty() || s[0] == '#') {
            continue;
        }

        readWireData(s, data);
    }
}

98
99
100
101
102
void
UnitTestUtil::addDataPath(const string& directory) {
    UnitTestUtilConfig::getConfig().data_paths_.push_back(directory);
}

103
void
104
105
UnitTestUtil::readWireData(const string& datastr,
                           vector<unsigned char>& data)
106
{
107
    istringstream iss(datastr);
108
109

    do {
110
        string bytes;
111
112
        iss >> bytes;
        if (iss.bad() || iss.fail() || (bytes.size() % 2) != 0) {
113
114
115
116
            ostringstream err_oss;
            err_oss << "unexpected input or I/O error in reading " <<
                datastr;
            throw runtime_error(err_oss.str());
117
118
119
        }

        for (int pos = 0; pos < bytes.size(); pos += 2) {
120
            istringstream iss_byte(bytes.substr(pos, 2));
121
            unsigned int ch;
122
123
124
125
126
127
128

            iss_byte >> hex >> ch;
            if (iss_byte.rdstate() != istream::eofbit) {
                ostringstream err_oss;
                err_oss << "invalid byte representation: " << iss_byte.str();
                throw runtime_error(err_oss.str());
            }
129
130
131
132
            data.push_back(static_cast<unsigned char>(ch));
        }
    } while (!iss.eof());
}
133
134

::testing::AssertionResult
135
136
137
138
UnitTestUtil::matchWireData(const char* dataexp1 UNUSED_PARAM,
                            const char* lenexp1 UNUSED_PARAM,
                            const char* dataexp2 UNUSED_PARAM,
                            const char* lenexp2 UNUSED_PARAM,
139
140
141
142
                            const void* data1, size_t len1,
                            const void* data2, size_t len2)
{
    ::testing::Message msg;
143
    size_t cmplen = min(len1, len2);
144
145

    for (int i = 0; i < cmplen; i++) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
146
147
        int ch1 = static_cast<const uint8_t*>(data1)[i];
        int ch2 = static_cast<const uint8_t*>(data2)[i];
148
149
        if (ch1 != ch2) {
            msg << "Wire data mismatch at " << i << "th byte\n"
JINMEI Tatuya's avatar
JINMEI Tatuya committed
150
151
                << "  Actual: " << ch1 << "\n"
                << "Expected: " << ch2 << "\n";
152
153
154
155
156
157
158
159
160
161
162
            return (::testing::AssertionFailure(msg));
        }
    }
    if (len1 != len2) {
        msg << "Wire data mismatch in length:\n"
            << "  Actual: " << len1 << "\n"
            << "Expected: " << len2 << "\n";
        return (::testing::AssertionFailure(msg));
    }
    return ::testing::AssertionSuccess();
}
163
164

::testing::AssertionResult
165
166
UnitTestUtil::matchName(const char* nameexp1 UNUSED_PARAM,
                        const char* nameexp2 UNUSED_PARAM,
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
                        const isc::dns::Name& name1,
                        const isc::dns::Name& name2)
{
    ::testing::Message msg;

    NameComparisonResult cmpresult = name1.compare(name2);
    if (cmpresult.getOrder() != 0 ||
        cmpresult.getRelation() != NameComparisonResult::EQUAL) {
        msg << "Two names are expected to be equal but not:\n"
            << "  One: " << name1 << "\n"
            << "Other: " << name2 << "\n";
        return (::testing::AssertionFailure(msg));
    }
    return ::testing::AssertionSuccess();
}