-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
yaml_io_test.cc
202 lines (179 loc) · 7.22 KB
/
yaml_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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "drake/common/yaml/yaml_io.h"
#include <fstream>
#include <gtest/gtest.h>
#include "drake/common/find_resource.h"
#include "drake/common/temp_directory.h"
#include "drake/common/test_utilities/expect_throws_message.h"
#include "drake/common/yaml/test/example_structs.h"
// This unit test only covers the basics of the helper functions in yaml_io,
// as well as (indirectly) the helper functions on YamlReadArchive related
// to file document loading (LoadFileAsNode, LoadStringAsNode).
//
// The exact details of YAML/C++ parsing, matching, and error messages are
// tested in more focused unit tests of the Archive classes.
namespace drake {
namespace yaml {
namespace test {
namespace {
GTEST_TEST(YamlIoTest, LoadString) {
const std::string data = R"""(
value:
some_value
)""";
const auto result = LoadYamlString<StringStruct>(data);
EXPECT_EQ(result.value, "some_value");
}
GTEST_TEST(YamlIoTest, LoadStringChildName) {
const std::string data = R"""(
some_child_name:
value:
some_value
)""";
const std::string child_name = "some_child_name";
const auto result = LoadYamlString<StringStruct>(data, child_name);
EXPECT_EQ(result.value, "some_value");
// When the requested child_name does not exist, that's an error.
DRAKE_EXPECT_THROWS_MESSAGE(
LoadYamlString<StringStruct>(data, "wrong_child_name"),
".* no such .* map entry .*wrong_child_name.*");
}
GTEST_TEST(YamlIoTest, LoadStringDefaults) {
const std::string data = R"""(
value:
some_key: 1.0
)""";
const std::optional<std::string> no_child_name;
const MapStruct defaults; // The defaults contains kNominalDouble already.
const auto result = LoadYamlString<MapStruct>(data, no_child_name, defaults);
EXPECT_EQ(result.value.at("some_key"), 1.0);
EXPECT_EQ(result.value.at("kNominalDouble"), test::kNominalDouble);
EXPECT_EQ(result.value.size(), 2);
}
GTEST_TEST(YamlIoTest, LoadStringOptions) {
const std::string data = R"""(
value: some_value
extra_junk: will_be_ignored
)""";
const std::optional<std::string> no_child_name;
const std::optional<StringStruct> no_defaults;
LoadYamlOptions options;
options.allow_yaml_with_no_cpp = true;
const auto result =
LoadYamlString<StringStruct>(data, no_child_name, no_defaults, options);
EXPECT_EQ(result.value, "some_value");
// Cross-check that the options actually were important.
DRAKE_EXPECT_THROWS_MESSAGE(
LoadYamlString<StringStruct>(data, no_child_name, no_defaults,
{/* no options */}),
".*extra_junk.*");
}
GTEST_TEST(YamlIoTest, LoadStringDefaultsAndOptions) {
const std::string data = R"""(
value:
some_key: 1.0
extra_junk:
will_be_ignored: 2.0
)""";
const std::optional<std::string> no_child_name;
const MapStruct defaults; // The defaults contains kNominalDouble already.
LoadYamlOptions options;
options.allow_yaml_with_no_cpp = true;
const auto result =
LoadYamlString<MapStruct>(data, no_child_name, defaults, options);
// When user options are provided, the implicit options that would otherwise
// be used for defaults parsing are not in effect; thus, retain_map_defaults
// will be false and kNominalDouble is not present in the result.
EXPECT_EQ(result.value.at("some_key"), 1.0);
EXPECT_EQ(result.value.size(), 1);
}
GTEST_TEST(YamlIoTest, LoadFile) {
const std::string filename =
FindResourceOrThrow("drake/common/yaml/test/yaml_io_test_input_1.yaml");
const auto result = LoadYamlFile<StringStruct>(filename);
EXPECT_EQ(result.value, "some_value_1");
}
GTEST_TEST(YamlIoTest, LoadFileChildName) {
const std::string filename =
FindResourceOrThrow("drake/common/yaml/test/yaml_io_test_input_2.yaml");
const std::string child_name = "some_string_struct";
const auto result = LoadYamlFile<StringStruct>(filename, child_name);
EXPECT_EQ(result.value, "some_value_2");
}
GTEST_TEST(YamlIoTest, LoadFileChildNameBad) {
const std::string filename =
FindResourceOrThrow("drake/common/yaml/test/yaml_io_test_input_2.yaml");
const std::string child_name = "wrong_child_name";
DRAKE_EXPECT_THROWS_MESSAGE(
LoadYamlFile<StringStruct>(filename, child_name),
".*yaml_io_test_input_2.yaml.* no such .*wrong_child_name.*");
}
GTEST_TEST(YamlIoTest, LoadFileSchemaBad) {
const std::string filename =
FindResourceOrThrow("drake/common/yaml/test/yaml_io_test_input_2.yaml");
using WrongSchema = std::map<std::string, DoubleStruct>;
DRAKE_EXPECT_THROWS_MESSAGE(
LoadYamlFile<WrongSchema>(filename),
".*/test/yaml_io_test_input_2.yaml:2:3:"
" YAML node of type Mapping .*"
" could not parse double value entry for double value.*");
}
// Because we know that the LoadFile and LoadString implementations share a
// helper function that implements handling of defaults and options, these
// specific variations of File-based test cases are not needed because the
// LoadString cases already covered them:
//
// - LoadFileDefaults
// - LoadFileOptions
// - LoadFileDefaultsAndOptions
GTEST_TEST(YamlIoTest, SaveString) {
const StringStruct data{.value = "save_string"};
const auto result = SaveYamlString(data);
EXPECT_EQ(result, "value: save_string\n");
}
GTEST_TEST(YamlIoTest, SaveStringChild) {
const std::string child_name = "some_child";
const StringStruct data{.value = "save_string_child"};
const auto result = SaveYamlString(data, child_name);
EXPECT_EQ(result, "some_child:\n value: save_string_child\n");
}
GTEST_TEST(YamlIoTest, SaveStringDefaults) {
const std::optional<std::string> no_child_name;
const MapStruct defaults;
MapStruct data; // The data.value contains kNominalDouble already.
data.value.insert({"save_string_defaults", 1.0});
ASSERT_EQ(data.value.size(), 2);
const auto result = SaveYamlString(data, no_child_name, {defaults});
// Only the non-default map entry is saved.
EXPECT_EQ(result, "value:\n save_string_defaults: 1.0\n");
}
// The implementation of SaveYamlFile calls SaveYamlString, so we only need
// to lightly test it (specifically the file-writing function). We'll do
// one test case with minimal arguments (just the filename) and one test
// case with all arguments (to confirm that they are all forwarded).
GTEST_TEST(YamlIoTest, SaveFile) {
const std::string filename = temp_directory() + "/SaveFile1.yaml";
const StringStruct data{.value = "save_file_1"};
SaveYamlFile(filename, data);
const auto result = ReadFileOrThrow(filename);
EXPECT_EQ(result, "value: save_file_1\n");
}
GTEST_TEST(YamlIoTest, SaveFileAllArgs) {
const std::string filename = temp_directory() + "/SaveFile4.yaml";
const std::string child_name = "some_child";
const MapStruct defaults;
MapStruct data; // The data.value contains kNominalDouble already.
data.value.insert({"save_file_4", 1.0});
ASSERT_EQ(data.value.size(), 2);
SaveYamlFile(filename, data, child_name, {defaults});
const auto result = ReadFileOrThrow(filename);
EXPECT_EQ(result, "some_child:\n value:\n save_file_4: 1.0\n");
}
GTEST_TEST(YamlIoTest, SaveFileBad) {
const std::string filename = temp_directory() + "/no_such_dir/file.yaml";
DRAKE_EXPECT_THROWS_MESSAGE(SaveYamlFile(filename, StringStruct{}),
".* could not open .*/no_such_dir/.*");
}
} // namespace
} // namespace test
} // namespace yaml
} // namespace drake