data-io.cpp 7.3 KB
Newer Older
1 2
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions

3
   Copyright (C) 2015, 2016, 2017 Inria
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

   This file is part of ALTA.

   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0.  If a copy of the MPL was not distributed with this
   file, You can obtain one at http://mozilla.org/MPL/2.0/.  */


/* Test whether the 'load' and 'save' methods of 'data' work as expected.  We
 * do that by bitwise comparison of the files produced by 'save', which is
 * not ideal (we may want to compare the in-memory representations
 * instead.)  */

#include <core/args.h>
#include <core/data.h>
#include <core/data_storage.h>
#include <core/vertical_segment.h>
21
#include <core/plugins_manager.h>
22 23 24 25
#include <tests.h>

#include <string>
#include <iostream>
26
#include <sstream>
27 28 29 30 31 32 33 34 35 36 37 38

#include <cstring>
#include <cstdlib>

// Get the 'unlink' declaration.
#ifdef _WIN32
# include <io.h>
# define unlink _unlink
#else
# include <unistd.h>
#endif

39 40
using namespace alta;

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
// Try loading a simple example from a text-format stream.
static void test_simple_load_from_text()
{
    static const char example[] = "\
#DIM 1 3f\n\
#VS 0\n\
#PARAM_IN COS_TH\n\
#PARAM_OUT RGB_COLOR\n\
0 1 2 3\n\
4 5 6 7\n\
8 9 10 11\n";

    std::istringstream input(example);

    auto data = dynamic_pointer_cast<vertical_segment>(
        plugins_manager::load_data("vertical_segment", input));
    TEST_ASSERT(data != NULL);

    TEST_ASSERT(data->size() == 3);
    TEST_ASSERT(data->parametrization().input_parametrization()
                == params::COS_TH);
    TEST_ASSERT(data->parametrization().output_parametrization()
                == params::RGB_COLOR);

    // Currently we always get ASYMMETRICAL_CONFIDENCE_INTERVAL for backward
    // compatibility reasons.
    TEST_ASSERT(data->confidence_interval_kind()
                == vertical_segment::ASYMMETRICAL_CONFIDENCE_INTERVAL);

    TEST_ASSERT(data->get(0) == Eigen::Vector4d(0., 1., 2., 3.));
    TEST_ASSERT(data->get(1) == Eigen::Vector4d(4., 5., 6., 7.));
    TEST_ASSERT(data->get(2) == Eigen::Vector4d(8., 9., 10., 11.));

74 75 76 77 78 79 80 81 82 83
    // Check the result of the other 'get' methods.
    vec x, y_lower, y_upper;
    data->get(1, x, y_lower, y_upper);
    TEST_ASSERT(x == Eigen::VectorXd::Constant(1, 4.));
    TEST_ASSERT(y_lower == Eigen::Vector3d(5., 6., 7.));
    TEST_ASSERT(y_lower == y_upper);
    data->get(1, y_lower, y_upper);
    TEST_ASSERT(y_lower == Eigen::Vector3d(5., 6., 7.));
    TEST_ASSERT(y_lower == y_upper);

84 85 86 87 88 89 90 91 92 93
    // The "matrix view" includes confidence interval data.
    auto view = data->matrix_view();
    TEST_ASSERT(view.cols() == 1 + 3 + 2 * 3);
    TEST_ASSERT(view.rows() == 3);
    TEST_ASSERT(view.col(0) == Eigen::Vector3d(0., 4., 8.));
    TEST_ASSERT(view.col(1) == Eigen::Vector3d(1., 5., 9.));
    TEST_ASSERT(view.col(2) == Eigen::Vector3d(2., 6., 10.));
    TEST_ASSERT(view.col(3) == Eigen::Vector3d(3., 7., 11.));
}

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
// Files that are automatically deleted upon destruction.
class temporary_file
{
public:
    temporary_file()
    {
        static std::string suffix;
        _name = "t-data-io" + suffix;
        suffix += "-";
    }

    ~temporary_file()
    {
        ::unlink(_name.c_str());
    }

    const std::string& name() { return _name; };
    operator const std::string& () { return _name; }

private:
    std::string _name;
};

// Try hard to read N bytes from INPUT into BUF.
static std::streamsize read_exactly(std::istream &input, char *buf, std::streamsize n)
{
    std::streamsize total;

    for (total = 0;
         total < n && !input.eof();
         total += input.gcount())
    {
        input.read(&buf[total], n - total);
    }

    return total;
}

// Return true if the contents of FILE1 are identical to the contents of
// FILE2.
static bool files_are_equal(const std::string &file1, const std::string &file2)
{
    std::ifstream i1, i2;

    i1.exceptions(std::ios_base::failbit);
    i1.open(file1.c_str());
    i2.open(file2.c_str());
    i1.exceptions(std::ios_base::goodbit);

    while (!i1.eof() && !i2.eof())
    {
        char buf1[16384], buf2[16384];
        std::streamsize len1 = read_exactly(i1, buf1, sizeof buf1);
        std::streamsize len2 = read_exactly(i2, buf2, sizeof buf2);
        if (len1 != len2 || memcmp(buf1, buf2, len1) != 0) {
            return false;
        }
    }

    return i1.eof() && (i1.eof() == i2.eof());
}

int main(int argc, char** argv)
{
    std::string input_file;
    temporary_file temp_file1, temp_file2, temp_file3;

    if (argc > 1)
        // Process the user-specified file.
        input_file = argv[1];
    else
    {
        // Process the default test file.
        static const std::string data_file = "Kirby2.dat";
        std::string data_dir = getenv("TEST_DATA_DIRECTORY") != NULL
            ? getenv("TEST_DATA_DIRECTORY") : ".";
        input_file = data_dir + "/" + data_file;
    }

173 174 175 176
    // Simple test first.
    test_simple_load_from_text();

    // Try a sequence of loads and saves.
177 178
    try
    {
179 180 181
        std::ifstream input;
        input.open(input_file);

182
        // Use the standard load/save methods.
183 184
        auto sample1 = plugins_manager::load_data("vertical_segment", input);
        sample1->save(temp_file1);
185

186 187 188
        std::ifstream temp1;
        temp1.open(temp_file1);

189 190
        auto sample2 = plugins_manager::load_data("vertical_segment", temp1);
        sample2->save(temp_file2);
191 192 193 194

        // Now use the binary output format.
        std::ofstream out;
        out.open(temp_file3.name().c_str(), std::ofstream::binary);
195
        save_data_as_binary(out, *sample2);
196 197 198
        out.close();

        // This should automatically load using the binary format loader.
199 200
        std::ifstream temp3;
        temp3.open(temp_file3);
201
        auto sample3 = plugins_manager::load_data("vertical_segment", temp3);
202

203 204 205
        TEST_ASSERT(sample1->equals(*sample2));
        TEST_ASSERT(files_are_equal(temp_file1, temp_file2));
        TEST_ASSERT(sample2->equals(*sample3));
206

207 208
        TEST_ASSERT(sample1->min().size() == sample1->parametrization().dimX());
        TEST_ASSERT(sample1->max().size() == sample1->parametrization().dimX());
209

210 211 212 213
        TEST_ASSERT(sample1->min() == sample2->min());
        TEST_ASSERT(sample1->max() == sample2->max());
        TEST_ASSERT(sample1->min() == sample3->min());
        TEST_ASSERT(sample1->max() == sample3->max());
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231

        // Make sure confidence interval data was preserved.
        auto vs_sample1 = dynamic_pointer_cast<vertical_segment>(sample1);
        auto vs_sample2 = dynamic_pointer_cast<vertical_segment>(sample2);
        auto vs_sample3 = dynamic_pointer_cast<vertical_segment>(sample3);
        TEST_ASSERT(vs_sample1 && vs_sample2 && vs_sample3);

        TEST_ASSERT(vs_sample1->confidence_interval_kind()
                    == vertical_segment::ASYMMETRICAL_CONFIDENCE_INTERVAL);
        TEST_ASSERT(vs_sample2->confidence_interval_kind()
                    == vertical_segment::ASYMMETRICAL_CONFIDENCE_INTERVAL);
        TEST_ASSERT(vs_sample3->confidence_interval_kind()
                    == vertical_segment::ASYMMETRICAL_CONFIDENCE_INTERVAL);

        // Compare the full "matrix views", which contains both X, Y, and the
        // confidence interval on Y.
        TEST_ASSERT(vs_sample1->matrix_view() == vs_sample2->matrix_view());
        TEST_ASSERT(vs_sample1->matrix_view() == vs_sample3->matrix_view());
232 233
    }
    CATCH_FILE_IO_ERROR(input_file);
234 235 236

    return EXIT_SUCCESS;
}