Skip to content

Commit 09cb671

Browse files
committed
Add more unit tests to discover edge cases
1 parent 8a888e6 commit 09cb671

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

ini_parser.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ static ini_linetype_t parseLine(const char *line, char *section, char *key, char
155155
memcpy(section, start, len);
156156
section[len] = '\0';
157157
trimWhitespace(section);
158+
159+
if(section[0] == '\0')
160+
{
161+
return INI_LINE_INVALID;
162+
}
163+
158164
return INI_LINE_SECTION;
159165
}
160166

@@ -245,20 +251,19 @@ bool ini_initialize(ini_context_t *ctx, const char *content, size_t length)
245251
while(*ptr)
246252
{
247253
const char *start = ptr;
254+
size_t len = 0;
248255

249-
while(*ptr && *ptr != '\n')
256+
while(*ptr && *ptr != '\n' && *ptr != '\r' && len < INI_MAX_LINE_LENGTH)
250257
{
251258
ptr++;
259+
len++;
252260
}
253261

254-
size_t len = ptr - start;
255-
256262
if(len > 0 && start[len - 1] == '\r')
257263
{
258264
len--;
259265
}
260266

261-
len = (len < INI_MAX_LINE_LENGTH - 1) ? len : INI_MAX_LINE_LENGTH - 1;
262267
memcpy(line, start, len);
263268
line[len] = '\0';
264269
char section[INI_MAX_LINE_LENGTH] = {0};
@@ -338,6 +343,11 @@ bool ini_initialize(ini_context_t *ctx, const char *content, size_t length)
338343
{
339344
ptr++;
340345
}
346+
347+
while(*ptr == '\r' || *ptr == '\n')
348+
{
349+
ptr++;
350+
}
341351
}
342352

343353
if(!has_valid_entries)

ini_parser_tests.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,88 @@ TEST_F(IniParserTest, HandlesCRLFFiles)
235235
EXPECT_STREQ(value, "value");
236236
}
237237

238+
TEST_F(IniParserTest, HandlesCRLineEndings)
239+
{
240+
const char *content = "[section]\rkey=value\r";
241+
ASSERT_TRUE(LoadIniContent(content));
242+
char value[INI_MAX_LINE_LENGTH];
243+
EXPECT_TRUE(ini_getValue(&ctx, "section", "key", value, sizeof(value)));
244+
EXPECT_STREQ(value, "value");
245+
}
246+
247+
TEST_F(IniParserTest, HandlesMixedLineEndings)
248+
{
249+
const char *content =
250+
"[crlf]\r\n"
251+
"key1=value1\r\n"
252+
"[lf]\n"
253+
"key2=value2\n"
254+
"[cr]\r"
255+
"key3=value3\r";
256+
ASSERT_TRUE(LoadIniContent(content));
257+
char value[INI_MAX_LINE_LENGTH];
258+
EXPECT_TRUE(ini_getValue(&ctx, "crlf", "key1", value, sizeof(value)));
259+
EXPECT_STREQ(value, "value1");
260+
EXPECT_TRUE(ini_getValue(&ctx, "lf", "key2", value, sizeof(value)));
261+
EXPECT_STREQ(value, "value2");
262+
EXPECT_TRUE(ini_getValue(&ctx, "cr", "key3", value, sizeof(value)));
263+
EXPECT_STREQ(value, "value3");
264+
}
265+
266+
TEST_F(IniParserTest, HandlesMaxLengthLines)
267+
{
268+
// Section: [aaaaa...] (INI_MAX_LINE_LENGTH - 3 chars)
269+
const size_t section_len = INI_MAX_LINE_LENGTH - 3;
270+
std::string section_name(section_len, 'a');
271+
// Key & value: "key=value" within line limit
272+
const size_t kv_len = (INI_MAX_LINE_LENGTH - 1) / 2 - 1; // Half for key, half for value
273+
std::string key(kv_len, 'b');
274+
std::string value(kv_len, 'c');
275+
std::string content =
276+
"[" + section_name + "]\n" +
277+
key + "=" + value;
278+
ASSERT_TRUE(ini_initialize(&ctx, content.c_str(), content.size()));
279+
char result[INI_MAX_LINE_LENGTH];
280+
EXPECT_TRUE(ini_getValue(&ctx, section_name.c_str(), key.c_str(), result, sizeof(result)));
281+
EXPECT_STREQ(result, value.c_str());
282+
}
283+
238284
TEST_F(IniParserTest, MaxLineLengthHandling)
239285
{
240286
std::string long_line(INI_MAX_LINE_LENGTH * 2, 'a');
241287
std::string content = "[section]\n" + long_line + "\n";
242288
ASSERT_TRUE(ini_initialize(&ctx, content.c_str(), content.size()));
243289
}
244290

291+
TEST_F(IniParserTest, HandlesWhitespaceOnlySections)
292+
{
293+
const char *content =
294+
"[ ]\n" // Invalid empty section
295+
"[ valid ]\n" // Valid section
296+
"key=value\n";
297+
ASSERT_TRUE(LoadIniContent(content));
298+
EXPECT_FALSE(ini_hasSection(&ctx, ""));
299+
EXPECT_TRUE(ini_hasSection(&ctx, "valid"));
300+
}
301+
302+
TEST_F(IniParserTest, HandlesCaseSensitivityWhenEnabled)
303+
{
304+
#ifdef INI_ENABLE_CASE_SENSITIVITY
305+
const char *content = "[Section]\nKey=Value\n";
306+
ASSERT_TRUE(LoadIniContent(content));
307+
char value[INI_MAX_LINE_LENGTH];
308+
EXPECT_FALSE(ini_getValue(&ctx, "section", "key", value, sizeof(value)));
309+
EXPECT_TRUE(ini_getValue(&ctx, "Section", "Key", value, sizeof(value)));
310+
EXPECT_STREQ(value, "Value");
311+
#endif
312+
}
313+
314+
TEST_F(IniParserTest, DetectsUnclosedSectionHeaders)
315+
{
316+
const char *content = "[section\nkey=value";
317+
ASSERT_FALSE(LoadIniContent(content));
318+
}
319+
245320
TEST_F(IniParserTest, MemorySafetyOnInvalidInput)
246321
{
247322
const char *content = "[section\nkey=value"; // Missing ] and unterminated quote

0 commit comments

Comments
 (0)