-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathpgm_io_test.cc
182 lines (155 loc) · 6.28 KB
/
pgm_io_test.cc
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
// Copyright(C) 2018 Tommy Hinks <tommy.hinks@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.
#include <cstdint>
#include <exception>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "catch2/catch.hpp"
#include "catch_utils.h"
#include "thinks/pnm_io/pnm_io.h"
namespace {
void WriteInvalidPgmImage(std::ostream& os, std::string const& magic_number,
std::uint32_t const max_value,
std::size_t const width, std::size_t const height,
std::vector<std::uint8_t> const& pixel_data) {
// Write header.
os << magic_number << "\n"
<< width << "\n"
<< height << "\n"
<< max_value << "\n"; // Marks beginning of pixel data.
// Write pixel data.
os.write(reinterpret_cast<char const*>(pixel_data.data()), pixel_data.size());
}
std::vector<std::uint8_t> ValidPixelData(std::size_t const width,
std::size_t const height) {
return std::vector<std::uint8_t>(width * height);
}
} // namespace
TEST_CASE("PGM - Write invalid filename throws") {
auto constexpr width = std::size_t{10};
auto constexpr height = std::size_t{10};
auto const pixel_data = std::vector<std::uint8_t>(width * height);
auto const filename = std::string{}; // Invalid.
// Not checking error message since it is OS dependent.
REQUIRE_THROWS_AS(
thinks::WritePgmImage(filename, width, height, pixel_data.data()),
std::runtime_error);
}
TEST_CASE("PGM - Write invalid width throws") {
auto constexpr width = std::size_t{0}; // Invalid.
auto constexpr height = std::size_t{10};
auto const pixel_data = ValidPixelData(width, height);
auto oss = std::ostringstream{};
REQUIRE_THROWS_MATCHES(
thinks::WritePgmImage(oss, width, height, pixel_data.data()),
std::invalid_argument,
ExceptionContentMatcher("width must be non-zero"));
}
TEST_CASE("PGM - Write invalid height throws") {
auto constexpr width = std::size_t{10};
auto constexpr height = std::size_t{0}; // Invalid.
auto const pixel_data = ValidPixelData(width, height);
auto oss = std::ostringstream{};
REQUIRE_THROWS_MATCHES(
thinks::WritePgmImage(oss, width, height, pixel_data.data()),
std::invalid_argument,
ExceptionContentMatcher("height must be non-zero"));
}
TEST_CASE("PGM - Read invalid filename throws") {
auto width = std::size_t{0};
auto height = std::size_t{0};
auto pixel_data = ValidPixelData(width, height);
auto const filename = std::string{}; // Invalid.
// Not checking error message since it is OS dependent.
REQUIRE_THROWS_AS(
thinks::ReadPgmImage(filename, &width, &height, &pixel_data),
std::runtime_error);
}
TEST_CASE("PGM - Read invalid magic number throws") {
auto ss = std::stringstream{};
WriteInvalidPgmImage(ss,
"P4", // Invalid.
255, 10, 10, ValidPixelData(10, 10));
auto width = std::size_t{0};
auto height = std::size_t{0};
auto pixel_data = std::vector<std::uint8_t>{};
REQUIRE_THROWS_MATCHES(
thinks::ReadPgmImage(ss, &width, &height, &pixel_data),
std::runtime_error,
ExceptionContentMatcher("magic number must be 'P5', was 'P4'"));
}
TEST_CASE("PGM - Read invalid width throws") {
auto ss = std::stringstream{};
WriteInvalidPgmImage(ss, "P5", 255,
0, // Invalid.
10, ValidPixelData(0, 10));
auto width = std::size_t{0};
auto height = std::size_t{0};
auto pixel_data = std::vector<std::uint8_t>{};
REQUIRE_THROWS_MATCHES(
thinks::ReadPgmImage(ss, &width, &height, &pixel_data),
std::runtime_error,
ExceptionContentMatcher("width must be non-zero"));
}
TEST_CASE("PGM - Read invalid height throws") {
auto ss = std::stringstream{};
WriteInvalidPgmImage(ss, "P5", 255, 10,
0, // Invalid.
ValidPixelData(10, 0));
auto width = std::size_t{0};
auto height = std::size_t{0};
auto pixel_data = std::vector<std::uint8_t>{};
REQUIRE_THROWS_MATCHES(
thinks::ReadPgmImage(ss, &width, &height, &pixel_data),
std::runtime_error,
ExceptionContentMatcher("height must be non-zero"));
}
TEST_CASE("PGM - Read invalid max value throws") {
auto ss = std::stringstream{};
WriteInvalidPgmImage(ss, "P5",
254, // Invalid.
10, 10, ValidPixelData(10, 10));
auto width = std::size_t{0};
auto height = std::size_t{0};
auto pixel_data = std::vector<std::uint8_t>{};
REQUIRE_THROWS_MATCHES(
thinks::ReadPgmImage(ss, &width, &height, &pixel_data),
std::runtime_error,
ExceptionContentMatcher("max value must be 255, was 254"));
}
TEST_CASE("PGM - Read invalid file size throws") {
auto ss = std::stringstream{};
WriteInvalidPgmImage(ss, "P5", 255, 10, 10,
ValidPixelData(10, 10 - 1)); // Invalid.
auto width = std::size_t{0};
auto height = std::size_t{0};
auto pixel_data = std::vector<std::uint8_t>{};
REQUIRE_THROWS_MATCHES(
thinks::ReadPgmImage(ss, &width, &height, &pixel_data),
std::runtime_error,
ExceptionContentMatcher("failed reading 100 bytes"));
}
TEST_CASE("PGM - Round-trip") {
auto constexpr write_width = std::size_t{16};
auto constexpr write_height = std::size_t{16};
auto constexpr write_pixel_count = write_width * write_height;
auto write_pixels = std::vector<std::uint8_t>(write_pixel_count);
for (auto i = std::size_t{0}; i < write_pixel_count; ++i) {
write_pixels[i] = static_cast<std::uint8_t>(i);
}
// Write image to IO stream.
auto ss = std::stringstream{};
thinks::WritePgmImage(ss, write_width, write_height, write_pixels.data());
// Read image from IO stream.
auto read_width = std::size_t{0};
auto read_height = std::size_t{0};
auto read_pixels = std::vector<std::uint8_t>{};
thinks::ReadPgmImage(ss, &read_width, &read_height, &read_pixels);
// Check that values were preserved.
REQUIRE(read_width == write_width);
REQUIRE(read_height == write_height);
REQUIRE(read_pixels == write_pixels);
}