1 /*****************************************************************************
2 * Copyright (c) 2014-2018 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #include "openrct2/config/IniWriter.hpp"
11
12 #include "openrct2/config/ConfigEnum.hpp"
13 #include "openrct2/core/MemoryStream.h"
14 #include "openrct2/platform/platform.h"
15
16 #include <gtest/gtest.h>
17 #include <limits>
18
19 class IniWriterTest : public testing::Test
20 {
21 };
22
23 static auto Enum_Currency = ConfigEnum<int32_t>({
24 ConfigEnumEntry<int32_t>("GBP", 1),
25 });
26
TEST_F(IniWriterTest,create_empty)27 TEST_F(IniWriterTest, create_empty)
28 {
29 OpenRCT2::MemoryStream ms(0);
30 ASSERT_EQ(ms.CanRead(), true);
31 ASSERT_EQ(ms.CanWrite(), true);
32 auto iw = CreateIniWriter(&ms);
33 ASSERT_NE(iw, nullptr);
34 }
35
TEST_F(IniWriterTest,create_one_section)36 TEST_F(IniWriterTest, create_one_section)
37 {
38 OpenRCT2::MemoryStream ms(1000);
39 auto iw = CreateIniWriter(&ms);
40 ASSERT_NE(iw, nullptr);
41 iw->WriteSection("OpenRCT2");
42 uint8_t null_terminator = 0;
43 ms.Write(&null_terminator, 1);
44 ASSERT_GE(ms.GetPosition(), 12);
45 ASSERT_LE(ms.GetPosition(), 13); // Accommodate for varying-sized newline (Windows)
46 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
47 ms.SetPosition(0);
48 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
49 ASSERT_STREQ(ini, "[OpenRCT2]" PLATFORM_NEWLINE);
50 Memory::Free(ini);
51 }
52
TEST_F(IniWriterTest,create_multiple_sections)53 TEST_F(IniWriterTest, create_multiple_sections)
54 {
55 OpenRCT2::MemoryStream ms(1000);
56 auto iw = CreateIniWriter(&ms);
57 ASSERT_NE(iw, nullptr);
58 iw->WriteSection("OpenRCT1");
59 iw->WriteSection("OpenRCT2");
60 iw->WriteSection("OpenRCT3");
61 iw->WriteSection("OpenRCT4");
62 uint8_t null_terminator = 0;
63 ms.Write(&null_terminator, 1);
64 ASSERT_GE(ms.GetPosition(), 48);
65 ASSERT_LE(ms.GetPosition(), 55); // Accommodate for varying-sized newline (Windows)
66 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
67 ms.SetPosition(0);
68 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
69 ASSERT_STREQ(
70 ini,
71 "[OpenRCT1]" PLATFORM_NEWLINE PLATFORM_NEWLINE "[OpenRCT2]" PLATFORM_NEWLINE PLATFORM_NEWLINE
72 "[OpenRCT3]" PLATFORM_NEWLINE PLATFORM_NEWLINE "[OpenRCT4]" PLATFORM_NEWLINE);
73 Memory::Free(ini);
74 }
75
TEST_F(IniWriterTest,create_loose_bool_entry)76 TEST_F(IniWriterTest, create_loose_bool_entry)
77 {
78 OpenRCT2::MemoryStream ms(1000);
79 auto iw = CreateIniWriter(&ms);
80 ASSERT_NE(iw, nullptr);
81 iw->WriteBoolean("boolval", true);
82 uint8_t null_terminator = 0;
83 ms.Write(&null_terminator, 1);
84 ASSERT_GE(ms.GetPosition(), 16);
85 ASSERT_LE(ms.GetPosition(), 17); // Accommodate for varying-sized newline (Windows)
86 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
87 ms.SetPosition(0);
88 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
89 ASSERT_STREQ(ini, "boolval = true" PLATFORM_NEWLINE);
90 Memory::Free(ini);
91 }
92
TEST_F(IniWriterTest,create_loose_enum_entry)93 TEST_F(IniWriterTest, create_loose_enum_entry)
94 {
95 OpenRCT2::MemoryStream ms(1000);
96 auto iw = CreateIniWriter(&ms);
97 ASSERT_NE(iw, nullptr);
98 iw->WriteEnum("by_string", "stringval");
99 iw->WriteEnum<int32_t>("int32_t", 0, Enum_Currency);
100 uint8_t null_terminator = 0;
101 ms.Write(&null_terminator, 1);
102 ASSERT_GE(ms.GetPosition(), 34);
103 ASSERT_LE(ms.GetPosition(), 37); // Accommodate for varying-sized newline (Windows)
104 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
105 ms.SetPosition(0);
106 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
107 ASSERT_STREQ(ini, "by_string = stringval" PLATFORM_NEWLINE "int32_t = 0" PLATFORM_NEWLINE);
108 Memory::Free(ini);
109 }
110
TEST_F(IniWriterTest,create_loose_float_entry)111 TEST_F(IniWriterTest, create_loose_float_entry)
112 {
113 OpenRCT2::MemoryStream ms(1000);
114 auto iw = CreateIniWriter(&ms);
115 ASSERT_NE(iw, nullptr);
116 iw->WriteFloat("one", 1.);
117 uint8_t null_terminator = 0;
118 ms.Write(&null_terminator, 1);
119 ASSERT_GE(ms.GetPosition(), 16);
120 ASSERT_LE(ms.GetPosition(), 17); // Accommodate for varying-sized newline (Windows)
121 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
122 ms.SetPosition(0);
123 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
124 // This will be non-fatal due to float.
125 EXPECT_STREQ(ini, "one = 1.000000" PLATFORM_NEWLINE);
126 Memory::Free(ini);
127 }
128
TEST_F(IniWriterTest,create_loose_int32_t_entry)129 TEST_F(IniWriterTest, create_loose_int32_t_entry)
130 {
131 OpenRCT2::MemoryStream ms(1000);
132 auto iw = CreateIniWriter(&ms);
133 ASSERT_NE(iw, nullptr);
134 iw->WriteInt32("one", 1);
135 iw->WriteInt32("zero", 0);
136 iw->WriteInt32("minusone", -1);
137 iw->WriteInt32("intmin", (std::numeric_limits<int32_t>::min)());
138 iw->WriteInt32("intmax", (std::numeric_limits<int32_t>::max)());
139 uint8_t null_terminator = 0;
140 ms.Write(&null_terminator, 1);
141 ASSERT_GE(ms.GetPosition(), 73);
142 ASSERT_LE(ms.GetPosition(), 78); // Accommodate for varying-sized newline (Windows)
143 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
144 ms.SetPosition(0);
145 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
146 ASSERT_STREQ(
147 ini,
148 "one = 1" PLATFORM_NEWLINE "zero = 0" PLATFORM_NEWLINE "minusone = -1" PLATFORM_NEWLINE
149 "intmin = -2147483648" PLATFORM_NEWLINE "intmax = 2147483647" PLATFORM_NEWLINE);
150 Memory::Free(ini);
151 }
152
TEST_F(IniWriterTest,create_loose_string_entry)153 TEST_F(IniWriterTest, create_loose_string_entry)
154 {
155 OpenRCT2::MemoryStream ms(1000);
156 auto iw = CreateIniWriter(&ms);
157 ASSERT_NE(iw, nullptr);
158 iw->WriteString("path", u8"C:'\\some/dir\\here/神鷹暢遊");
159 uint8_t null_terminator = 0;
160 ms.Write(&null_terminator, 1);
161 ASSERT_GE(ms.GetPosition(), 43);
162 ASSERT_LE(ms.GetPosition(), 44); // Accommodate for varying-sized newline (Windows)
163 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
164 ms.SetPosition(0);
165 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
166 ASSERT_STREQ(ini, "path = \"C:'\\\\some/dir\\\\here/\xE7\xA5\x9E\xE9\xB7\xB9\xE6\x9A\xA2\xE9\x81\x8A\"" PLATFORM_NEWLINE);
167 Memory::Free(ini);
168 }
169
TEST_F(IniWriterTest,create_multiple_section_with_values)170 TEST_F(IniWriterTest, create_multiple_section_with_values)
171 {
172 OpenRCT2::MemoryStream ms(1000);
173 auto iw = CreateIniWriter(&ms);
174 ASSERT_NE(iw, nullptr);
175 iw->WriteSection("bool");
176 iw->WriteBoolean("boolval", true);
177 iw->WriteSection("int");
178 iw->WriteInt32("one", 1);
179 iw->WriteInt32("zero", 0);
180 iw->WriteSection("string");
181 iw->WriteString("path", u8"C:'\\some/dir\\here/神鷹暢遊");
182 uint8_t null_terminator = 0;
183 ms.Write(&null_terminator, 1);
184 ASSERT_GE(ms.GetPosition(), 99);
185 ASSERT_LE(ms.GetPosition(), 108); // Accommodate for varying-sized newline (Windows)
186 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
187 ms.SetPosition(0);
188 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
189 ASSERT_STREQ(
190 ini,
191 "[bool]" PLATFORM_NEWLINE "boolval = true" PLATFORM_NEWLINE PLATFORM_NEWLINE "[int]" PLATFORM_NEWLINE
192 "one = 1" PLATFORM_NEWLINE "zero = 0" PLATFORM_NEWLINE PLATFORM_NEWLINE "[string]" PLATFORM_NEWLINE "path = "
193 "\"C:'\\\\some/dir\\\\here/\xE7\xA5\x9E\xE9\xB7\xB9\xE6\x9A\xA2\xE9\x81\x8A\"" PLATFORM_NEWLINE);
194 Memory::Free(ini);
195 }
196
TEST_F(IniWriterTest,create_duplicate_sections)197 TEST_F(IniWriterTest, create_duplicate_sections)
198 {
199 OpenRCT2::MemoryStream ms(1000);
200 auto iw = CreateIniWriter(&ms);
201 ASSERT_NE(iw, nullptr);
202 iw->WriteSection("section");
203 iw->WriteSection("section");
204 iw->WriteSection("section");
205 uint8_t null_terminator = 0;
206 ms.Write(&null_terminator, 1);
207 ASSERT_GE(ms.GetPosition(), 33);
208 ASSERT_LE(ms.GetPosition(), 43); // Accommodate for varying-sized newline (Windows)
209 ASSERT_EQ(ms.GetLength(), ms.GetPosition());
210 ms.SetPosition(0);
211 const char* ini = reinterpret_cast<const char*>(ms.ReadString());
212 ASSERT_STREQ(
213 ini,
214 "[section]" PLATFORM_NEWLINE PLATFORM_NEWLINE "[section]" PLATFORM_NEWLINE PLATFORM_NEWLINE
215 "[section]" PLATFORM_NEWLINE);
216 Memory::Free(ini);
217 }
218