Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
parse_utils_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38#include <gtest/gtest.h>
39#include <fstream>
40#include <sstream>
41#include <cstdio>
42#include <filesystem>
43#include <string>
44#if defined(_WIN32)
45# include <process.h>
46#else
47# include <unistd.h>
48#endif
49#include <parse_utils.H>
50
51using namespace std;
52using namespace testing;
53using namespace Aleph;
54
55// ============================================================================
56// Test Fixture
57// ============================================================================
58
59class ParseUtilsTest : public Test
60{
61protected:
63
64 static long long process_id() noexcept
65 {
66#if defined(_WIN32)
67 return static_cast<long long>(_getpid());
68#else
69 return static_cast<long long>(getpid());
70#endif
71 }
72
73 void SetUp() override
74 {
75 // Create a unique temp file name for this test and process.
76 const auto *test_info = UnitTest::GetInstance()->current_test_info();
77 string base = string("parse_utils_test_") + test_info->test_suite_name() + "_" +
78 test_info->name() + "_" + to_string(process_id()) + ".txt";
79
80 for (auto &ch : base)
81 if (ch == '/' or ch == '\\' or ch == ' ')
82 ch = '_';
83
84 temp_filename = (std::filesystem::temp_directory_path() / base).string();
86 }
87
88 void TearDown() override
89 {
90 // Remove temp file if it exists
91 remove(temp_filename.c_str());
92 }
93
94 // Helper to create temp file with content
95 void create_temp_file(const string& content)
96 {
97 ofstream out(temp_filename);
98 out << content;
99 out.close();
100 }
101};
102
103// ============================================================================
104// put_char_in_buffer Tests
105// ============================================================================
106
108{
109 char buffer[10];
110 char* ptr = buffer;
111 char* end = buffer + 10;
112
113 put_char_in_buffer(ptr, end, 'H');
114 put_char_in_buffer(ptr, end, 'i');
115 put_char_in_buffer(ptr, end, '\0');
116
117 EXPECT_STREQ(buffer, "Hi");
118}
119
121{
122 char buffer[10];
123 char* ptr = buffer;
124 char* end = buffer + 10;
125
126 EXPECT_EQ(ptr, buffer);
127 put_char_in_buffer(ptr, end, 'A');
128 EXPECT_EQ(ptr, buffer + 1);
129 put_char_in_buffer(ptr, end, 'B');
130 EXPECT_EQ(ptr, buffer + 2);
131}
132
134{
135 char buffer[5];
136 char* ptr = buffer;
137 char* end = buffer + 5;
138
139 for (int i = 0; i < 5; ++i)
140 put_char_in_buffer(ptr, end, 'X');
141
142 EXPECT_EQ(ptr, end);
143}
144
145// Note: Buffer overflow causes AH_ERROR which terminates - can't easily test
146
147// ============================================================================
148// init_token_scanning / close_token_scanning Tests
149// ============================================================================
150
161
163{
164 char buffer[20] = "hello";
165 char* ptr = buffer + 5;
166 char* end = buffer + 20;
167
168 close_token_scanning(buffer, ptr, end);
169
171}
172
174{
175 char buffer[20] = "test";
176 char* ptr = buffer + 4;
177 char* end = buffer + 20;
178
179 // Overwrite the implicit null
180 buffer[4] = 'X';
181 buffer[5] = 'Y';
182
183 close_token_scanning(buffer, ptr, end);
184
185 // Should have added null terminator at position 4
186 EXPECT_EQ(buffer[4], '\0');
188}
189
190// ============================================================================
191// read_char_from_stream Tests
192// ============================================================================
193
195{
196 create_temp_file("ABC");
197 ifstream input(temp_filename);
198
202}
203
215
217{
218 create_temp_file("A\nB");
219 ifstream input(temp_filename);
220
226 EXPECT_EQ(Aleph::current_col_number, 0); // Reset on newline
227}
228
230{
231 create_temp_file("");
232 ifstream input(temp_filename);
233
234 // Force EOF
235 input.get(); // This will set EOF flag
236
238}
239
240// ============================================================================
241// skip_white_spaces Tests
242// ============================================================================
243
245{
246 create_temp_file(" hello");
247 ifstream input(temp_filename);
248
250
251 EXPECT_EQ(input.peek(), 'h');
252}
253
255{
256 create_temp_file("\t\thello");
257 ifstream input(temp_filename);
258
260
261 EXPECT_EQ(input.peek(), 'h');
262}
263
265{
266 create_temp_file("\n\nhello");
267 ifstream input(temp_filename);
268
270
271 EXPECT_EQ(input.peek(), 'h');
272}
273
275{
276 create_temp_file(" \t\n \t\nhello");
277 ifstream input(temp_filename);
278
280
281 EXPECT_EQ(input.peek(), 'h');
282}
283
285{
286 create_temp_file("hello");
287 ifstream input(temp_filename);
288
290
291 EXPECT_EQ(input.peek(), 'h');
292}
293
294// ============================================================================
295// load_number Tests
296// ============================================================================
297
299{
300 create_temp_file("42 ");
301 ifstream input(temp_filename);
302
304}
305
307{
308 create_temp_file("-123 ");
309 ifstream input(temp_filename);
310
312}
313
315{
316 create_temp_file("0 ");
317 ifstream input(temp_filename);
318
320}
321
323{
324 create_temp_file(" 100 ");
325 ifstream input(temp_filename);
326
328}
329
331{
332 create_temp_file("10 20 30 ");
333 ifstream input(temp_filename);
334
338}
339
341{
342 // Number without trailing whitespace at EOF throws exception
343 // because the parser expects whitespace to terminate numbers
344 create_temp_file("42");
345 ifstream input(temp_filename);
346
347 // The implementation throws when number doesn't end in whitespace
348 EXPECT_THROW(load_number(input), std::domain_error);
349}
350
352{
353 // Number with trailing newline works fine
354 create_temp_file("42\n");
355 ifstream input(temp_filename);
356
358}
359
361{
362 create_temp_file("1234567890 ");
363 ifstream input(temp_filename);
364
365 EXPECT_EQ(load_number(input), 1234567890L);
366}
367
369{
370 create_temp_file("-987654321 ");
371 ifstream input(temp_filename);
372
373 EXPECT_EQ(load_number(input), -987654321L);
374}
375
377{
378 create_temp_file("999 ");
379 ifstream input(temp_filename);
380
382
384}
385
386// ============================================================================
387// load_string Tests
388// ============================================================================
389
391{
392 create_temp_file("hello ");
393 ifstream input(temp_filename);
394
395 EXPECT_EQ(load_string(input), "hello");
396}
397
399{
400 create_temp_file("\"hello world\" ");
401 ifstream input(temp_filename);
402
403 EXPECT_EQ(load_string(input), "hello world");
404}
405
407{
408 create_temp_file("\"hello world\" ");
409 ifstream input(temp_filename);
410
411 EXPECT_EQ(load_string(input), "hello world");
412}
413
415{
416 create_temp_file(" hello ");
417 ifstream input(temp_filename);
418
419 EXPECT_EQ(load_string(input), "hello");
420}
421
423{
424 create_temp_file("hello world test ");
425 ifstream input(temp_filename);
426
427 EXPECT_EQ(load_string(input), "hello");
428 EXPECT_EQ(load_string(input), "world");
429 EXPECT_EQ(load_string(input), "test");
430}
431
433{
434 create_temp_file("hello \"world test\" foo ");
435 ifstream input(temp_filename);
436
437 EXPECT_EQ(load_string(input), "hello");
438 EXPECT_EQ(load_string(input), "world test");
439 EXPECT_EQ(load_string(input), "foo");
440}
441
443{
444 create_temp_file("\"\" ");
445 ifstream input(temp_filename);
446
448}
449
451{
452 create_temp_file("test ");
453 ifstream input(temp_filename);
454
456
458}
459
461{
462 create_temp_file("abc123 ");
463 ifstream input(temp_filename);
464
465 EXPECT_EQ(load_string(input), "abc123");
466}
467
469{
470 create_temp_file("\"line1\nline2\" ");
471 ifstream input(temp_filename);
472
473 string result = load_string(input);
474 EXPECT_EQ(result, "line1\nline2");
475}
476
477// ============================================================================
478// command_line_to_string Tests
479// ============================================================================
480
482{
483 const char* argv[] = {"program"};
484 string result = command_line_to_string(1, const_cast<char**>(argv));
485
486 EXPECT_EQ(result, " program");
487}
488
490{
491 const char* argv[] = {"program", "--input", "file.txt", "-v"};
492 string result = command_line_to_string(4, const_cast<char**>(argv));
493
494 EXPECT_EQ(result, " program --input file.txt -v");
495}
496
498{
499 string result = command_line_to_string(0, nullptr);
500
501 EXPECT_EQ(result, "");
502}
503
504// ============================================================================
505// reset_parse_state Tests
506// ============================================================================
507
522
531
532// ============================================================================
533// Integration Tests
534// ============================================================================
535
537{
538 // Simulate a simple config file format:
539 // name value
540 // ...
541 create_temp_file("count 10\nname \"test file\"\nsize 42\n");
542 ifstream input(temp_filename);
543
544 string key1 = load_string(input);
545 long val1 = load_number(input);
546 EXPECT_EQ(key1, "count");
547 EXPECT_EQ(val1, 10);
548
549 string key2 = load_string(input);
550 string val2 = load_string(input);
551 EXPECT_EQ(key2, "name");
552 EXPECT_EQ(val2, "test file");
553
554 string key3 = load_string(input);
555 long val3 = load_number(input);
556 EXPECT_EQ(key3, "size");
557 EXPECT_EQ(val3, 42);
558}
559
561{
562 create_temp_file(" 123 \"hello world\" -456 test ");
563 ifstream input(temp_filename);
564
566 EXPECT_EQ(load_string(input), "hello world");
568 EXPECT_EQ(load_string(input), "test");
569}
570
572{
573 create_temp_file("line1\nline2\nline3\n");
574 ifstream input(temp_filename);
575
576 // Note: current_line_number updates AFTER reading newline,
577 // so after reading "line1\n", we're at line 2
578 EXPECT_EQ(load_string(input), "line1");
579 EXPECT_EQ(Aleph::current_line_number, 2); // After reading newline
580
581 EXPECT_EQ(load_string(input), "line2");
583
584 EXPECT_EQ(load_string(input), "line3");
586}
587
588// ============================================================================
589// Position Tracking Tests
590// ============================================================================
591
593{
594 create_temp_file("abc def\nghi jkl\n");
595 ifstream input(temp_filename);
596
597 // Read first token
599
600 // Previous position is recorded by init_token_scanning() inside load_string()
601 // It records position BEFORE skipping whitespace, which happens after token
604
605 // Read second token - previous_col is where skip_white_spaces left off
607
609 // Column 6 because: skip reads space (col 5), then init captures col 6
611
612 // Read third token (on new line)
614
616}
617
618// ============================================================================
619// Edge Cases
620// ============================================================================
621
623{
624 create_temp_file("- 5 ");
625 ifstream input(temp_filename);
626
627 // A lone minus followed by space should return 0 (atol(""))
628 long result = load_number(input);
629 EXPECT_EQ(result, 0); // atol("-") or empty
630}
631
633{
634 create_temp_file("\"hello@world#test!\" ");
635 ifstream input(temp_filename);
636
637 EXPECT_EQ(load_string(input), "hello@world#test!");
638}
639
641{
642 create_temp_file("\"path\\to\\file\" ");
643 ifstream input(temp_filename);
644
645 // Backslashes are preserved (no escape processing)
646 EXPECT_EQ(load_string(input), "path\\to\\file");
647}
648
650{
651 string longstr(400, 'X'); // 400 X's, within Buffer_Size
652 create_temp_file("\"" + longstr + "\" ");
653 ifstream input(temp_filename);
654
656}
657
658// ============================================================================
659// Buffer Size Constant Test
660// ============================================================================
661
667
668// ============================================================================
669// SourceLocation Tests
670// ============================================================================
671
673{
675 EXPECT_TRUE(loc.filename.empty());
676 EXPECT_EQ(loc.line, 1);
677 EXPECT_EQ(loc.column, 1);
678}
679
681{
682 SourceLocation loc("test.cpp", 42, 15);
683 EXPECT_EQ(loc.filename, "test.cpp");
684 EXPECT_EQ(loc.line, 42);
685 EXPECT_EQ(loc.column, 15);
686}
687
689{
690 SourceLocation loc("test.cpp", 10, 5);
691 EXPECT_EQ(loc.to_string(), "test.cpp:10:5");
692}
693
695{
696 SourceLocation loc("", 10, 5);
697 EXPECT_EQ(loc.to_string(), "10:5");
698}
699
701{
704
705 auto loc = SourceLocation::current("file.txt");
706
707 EXPECT_EQ(loc.filename, "file.txt");
708 EXPECT_EQ(loc.line, 100);
709 EXPECT_EQ(loc.column, 50);
710
712}
713
714// ============================================================================
715// ParseError Tests
716// ============================================================================
717
719{
720 SourceLocation loc("test.cpp", 5, 10);
721 ParseError err("unexpected token", loc);
722
723 string msg = err.what();
724 EXPECT_NE(msg.find("test.cpp"), string::npos);
725 EXPECT_NE(msg.find("5"), string::npos);
726 EXPECT_NE(msg.find("unexpected token"), string::npos);
727}
728
730{
731 SourceLocation loc("file.c", 20, 30);
732 ParseError err("error", loc);
733
734 EXPECT_EQ(err.location().line, 20);
735 EXPECT_EQ(err.location().column, 30);
736}
737
738// ============================================================================
739// Lookahead and Backtracking Tests
740// ============================================================================
741
743{
744 create_temp_file("ABC");
745 ifstream input(temp_filename);
746
748 EXPECT_EQ(peek_char(input), 'A'); // Still 'A'
749 EXPECT_EQ(input.get(), 'A'); // Now consumed
751}
752
754{
755 create_temp_file("hello world");
756 ifstream input(temp_filename);
757
758 // Read "hello"
759 for (int i = 0; i < 5; ++i)
761
763
764 // Read " world"
765 for (int i = 0; i < 6; ++i)
767
768 // Restore
770
771 EXPECT_EQ(input.get(), ' ');
772 EXPECT_EQ(input.get(), 'w');
773}
774
775// ============================================================================
776// Comment Handling Tests
777// ============================================================================
778
780{
781 create_temp_file("// this is a comment\nhello");
782 ifstream input(temp_filename);
783
784 input.get(); // '/'
785 input.get(); // '/'
787
789
790 EXPECT_EQ(input.peek(), 'h');
792}
793
795{
796 create_temp_file("/* comment */hello");
797 ifstream input(temp_filename);
798
799 input.get(); // '/'
800 input.get(); // '*'
802
804
805 EXPECT_EQ(input.peek(), 'h');
806}
807
809{
810 create_temp_file("/* line 1\n line 2\n line 3 */hello");
811 ifstream input(temp_filename);
812
813 input.get(); // '/'
814 input.get(); // '*'
816
818
819 EXPECT_EQ(input.peek(), 'h');
821}
822
824{
825 create_temp_file(" // comment\n /* block */ hello");
826 ifstream input(temp_filename);
827
829
830 EXPECT_EQ(input.peek(), 'h');
831}
832
834{
835 create_temp_file(" # python style comment\nhello");
836 ifstream input(temp_filename);
837
839
840 EXPECT_EQ(input.peek(), 'h');
841}
842
843// ============================================================================
844// Extended Numeric Parsing Tests
845// ============================================================================
846
848{
849 create_temp_file("3.14159 ");
850 ifstream input(temp_filename);
851
852 EXPECT_NEAR(load_double(input), 3.14159, 0.00001);
853}
854
856{
857 create_temp_file("-2.5 ");
858 ifstream input(temp_filename);
859
860 EXPECT_NEAR(load_double(input), -2.5, 0.001);
861}
862
864{
865 create_temp_file("1.5e10 ");
866 ifstream input(temp_filename);
867
868 EXPECT_NEAR(load_double(input), 1.5e10, 1e5);
869}
870
872{
873 create_temp_file("2.5e-3 ");
874 ifstream input(temp_filename);
875
876 EXPECT_NEAR(load_double(input), 0.0025, 0.00001);
877}
878
880{
881 create_temp_file(".5 ");
882 ifstream input(temp_filename);
883
884 EXPECT_NEAR(load_double(input), 0.5, 0.001);
885}
886
888{
889 create_temp_file("5. ");
890 ifstream input(temp_filename);
891
892 EXPECT_NEAR(load_double(input), 5.0, 0.001);
893}
894
896{
897 create_temp_file("0xFF ");
898 ifstream input(temp_filename);
899
901}
902
904{
905 create_temp_file("0x1a2b ");
906 ifstream input(temp_filename);
907
909}
910
912{
913 create_temp_file("0755 ");
914 ifstream input(temp_filename);
915
917}
918
920{
921 create_temp_file("0 ");
922 ifstream input(temp_filename);
923
925}
926
928{
929 create_temp_file("0b1010 ");
930 ifstream input(temp_filename);
931
933}
934
936{
937 create_temp_file("0B11110000 ");
938 ifstream input(temp_filename);
939
941}
942
943// ============================================================================
944// Identifier Tests
945// ============================================================================
946
948{
949 create_temp_file("myVariable ");
950 ifstream input(temp_filename);
951
952 EXPECT_EQ(load_identifier(input), "myVariable");
953}
954
956{
957 create_temp_file("_private_var ");
958 ifstream input(temp_filename);
959
960 EXPECT_EQ(load_identifier(input), "_private_var");
961}
962
964{
965 create_temp_file("var123 ");
966 ifstream input(temp_filename);
967
968 EXPECT_EQ(load_identifier(input), "var123");
969}
970
972{
973 create_temp_file("camelCaseIdentifier ");
974 ifstream input(temp_filename);
975
976 EXPECT_EQ(load_identifier(input), "camelCaseIdentifier");
977}
978
980{
981 create_temp_file("123invalid ");
982 ifstream input(temp_filename);
983
985}
986
987// ============================================================================
988// Keyword Tests
989// ============================================================================
990
992{
993 vector<string> keywords = {"if", "while", "for", "return"};
994
997 EXPECT_TRUE(is_keyword("return", keywords));
998}
999
1001{
1002 vector<string> keywords = {"if", "while", "for", "return"};
1003
1004 EXPECT_FALSE(is_keyword("IF", keywords)); // Case sensitive
1005 EXPECT_FALSE(is_keyword("unless", keywords));
1007}
1008
1009// ============================================================================
1010// Expectation Tests
1011// ============================================================================
1012
1014{
1015 create_temp_file(" ( hello");
1016 ifstream input(temp_filename);
1017
1019}
1020
1022{
1023 create_temp_file(" [ hello");
1024 ifstream input(temp_filename);
1025
1027}
1028
1030{
1031 create_temp_file(" function foo");
1032 ifstream input(temp_filename);
1033
1034 EXPECT_NO_THROW(expect(input, "function"));
1035}
1036
1038{
1039 create_temp_file(" procedure foo");
1040 ifstream input(temp_filename);
1041
1042 EXPECT_THROW(expect(input, "function"), ParseError);
1043}
1044
1046{
1047 create_temp_file(" ; next");
1048 ifstream input(temp_filename);
1049
1050 EXPECT_TRUE(try_char(input, ';'));
1051 // Should have consumed the ';'
1053 EXPECT_EQ(input.peek(), 'n');
1054}
1055
1057{
1058 create_temp_file(" , next");
1059 ifstream input(temp_filename);
1060
1062 // Should NOT have consumed anything
1064 EXPECT_EQ(input.peek(), ',');
1065}
1066
1067// ============================================================================
1068// Escape Processing Tests
1069// ============================================================================
1070
1072{
1073 EXPECT_EQ(process_escape('n'), '\n');
1074 EXPECT_EQ(process_escape('t'), '\t');
1075 EXPECT_EQ(process_escape('r'), '\r');
1076 EXPECT_EQ(process_escape('\\'), '\\');
1077 EXPECT_EQ(process_escape('"'), '"');
1078 EXPECT_EQ(process_escape('\''), '\'');
1079 EXPECT_EQ(process_escape('0'), '\0');
1080}
1081
1083{
1084 // Unknown escapes return the character as-is
1085 EXPECT_EQ(process_escape('x'), 'x');
1086 EXPECT_EQ(process_escape('q'), 'q');
1087}
1088
1089// ============================================================================
1090// Escaped String Tests
1091// ============================================================================
1092
1094{
1095 create_temp_file("\"hello\\nworld\" ");
1096 ifstream input(temp_filename);
1097
1098 string result = load_escaped_string(input);
1099 EXPECT_EQ(result, "hello\nworld");
1100}
1101
1103{
1104 create_temp_file("\"line1\\tline2\\r\\nline3\" ");
1105 ifstream input(temp_filename);
1106
1107 string result = load_escaped_string(input);
1108 EXPECT_EQ(result, "line1\tline2\r\nline3");
1109}
1110
1112{
1113 create_temp_file("\"he said \\\"hello\\\"\" ");
1114 ifstream input(temp_filename);
1115
1116 string result = load_escaped_string(input);
1117 EXPECT_EQ(result, "he said \"hello\"");
1118}
1119
1121{
1122 create_temp_file("\"path\\\\to\\\\file\" ");
1123 ifstream input(temp_filename);
1124
1125 string result = load_escaped_string(input);
1126 EXPECT_EQ(result, "path\\to\\file");
1127}
1128
1130{
1131 create_temp_file("\"no closing quote");
1132 ifstream input(temp_filename);
1133
1135}
1136
1137// ============================================================================
1138// Character Literal Tests
1139// ============================================================================
1140
1142{
1143 create_temp_file("'a' ");
1144 ifstream input(temp_filename);
1145
1147}
1148
1150{
1151 create_temp_file("'\\n' ");
1152 ifstream input(temp_filename);
1153
1155}
1156
1158{
1159 create_temp_file("'\\t' ");
1160 ifstream input(temp_filename);
1161
1163}
1164
1166{
1167 create_temp_file("'\\'' ");
1168 ifstream input(temp_filename);
1169
1171}
1172
1173// ============================================================================
1174// Token Type Tests
1175// ============================================================================
1176
1178{
1179 EXPECT_EQ(token_type_to_string(TokenType::END_OF_FILE), "EOF");
1180 EXPECT_EQ(token_type_to_string(TokenType::IDENTIFIER), "IDENTIFIER");
1181 EXPECT_EQ(token_type_to_string(TokenType::INTEGER), "INTEGER");
1182 EXPECT_EQ(token_type_to_string(TokenType::STRING), "STRING");
1183}
1184
1186{
1187 SourceLocation loc("file.c", 10, 5);
1188 Token tok(TokenType::IDENTIFIER, "myVar", loc);
1189
1190 EXPECT_EQ(tok.type, TokenType::IDENTIFIER);
1191 EXPECT_EQ(tok.value, "myVar");
1192 EXPECT_EQ(tok.location.line, 10);
1193}
1194
1196{
1197 Token eof(TokenType::END_OF_FILE, "", SourceLocation());
1198 Token id(TokenType::IDENTIFIER, "x", SourceLocation());
1199
1200 EXPECT_TRUE(eof.is_eof());
1201 EXPECT_FALSE(id.is_eof());
1202}
1203
1204// ============================================================================
1205// File Utility Tests
1206// ============================================================================
1207
1209{
1210 create_temp_file("line1\nline2\nline3");
1211
1212 string contents = load_file_contents(temp_filename);
1213 EXPECT_EQ(contents, "line1\nline2\nline3");
1214}
1215
1217{
1218 create_temp_file("line1\nline2\nline3");
1219
1220 DynList<string> lines = load_file_lines(temp_filename);
1221 ASSERT_EQ(lines.size(), 3u);
1223 EXPECT_EQ(it.get_curr(), "line1"); it.next();
1224 EXPECT_EQ(it.get_curr(), "line2"); it.next();
1225 EXPECT_EQ(it.get_curr(), "line3");
1226}
1227
1229{
1230 EXPECT_THROW(load_file_contents("/nonexistent/file.txt"), runtime_error);
1231}
1232
1233// ============================================================================
1234// String Utility Tests
1235// ============================================================================
1236
1238{
1239 DynList<string> parts = split_string("a,b,c,d", ',');
1240 ASSERT_EQ(parts.size(), 4u);
1242 EXPECT_EQ(it.get_curr(), "a"); it.next();
1243 EXPECT_EQ(it.get_curr(), "b"); it.next();
1244 EXPECT_EQ(it.get_curr(), "c"); it.next();
1245 EXPECT_EQ(it.get_curr(), "d");
1246}
1247
1249{
1250 // std::getline produces no tokens for empty string
1252 EXPECT_EQ(parts.size(), 0u);
1253}
1254
1256{
1257 EXPECT_EQ(trim(" hello "), "hello");
1258 EXPECT_EQ(trim("hello"), "hello");
1259 EXPECT_EQ(trim(" hello"), "hello");
1260 EXPECT_EQ(trim("hello "), "hello");
1261}
1262
1264{
1265 EXPECT_EQ(trim("\t\thello\t\t"), "hello");
1266}
1267
1269{
1270 EXPECT_EQ(trim(""), "");
1271 EXPECT_EQ(trim(" "), "");
1272}
1273
1274// ============================================================================
1275// Integration Test: Simple Expression Parser
1276// ============================================================================
1277
1279{
1280 // Parse: x = 42 + 3.14;
1281 create_temp_file("x = 42 + 3.14;");
1282 ifstream input(temp_filename);
1283
1284 string id = load_identifier(input);
1285 EXPECT_EQ(id, "x");
1286
1287 expect_char(input, '=');
1288
1289 long intVal = load_number(input);
1290 EXPECT_EQ(intVal, 42);
1291
1292 expect_char(input, '+');
1293
1294 double dblVal = load_double(input);
1295 EXPECT_NEAR(dblVal, 3.14, 0.01);
1296
1297 expect_char(input, ';');
1298}
1299
1301{
1302 // Note: load_number expects whitespace after number, so use spaces before ';'
1303 create_temp_file("// comment\nx = 10 ; /* another */ y = 20 ;");
1304 ifstream input(temp_filename);
1305
1309 expect_char(input, '=');
1311 expect_char(input, ';');
1312
1316 expect_char(input, '=');
1318}
1319// satisfy CI policy
size_t size_t int32_t * out
Definition ca-c-api.h:120
Iterator on the items of list.
Definition htlist.H:1420
T & get_curr() const
Return the current item.
Definition htlist.H:1446
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
Exception class for parsing errors with location information.
void SetUp() override
static long long process_id() noexcept
void create_temp_file(const string &content)
void TearDown() override
#define TEST(name)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void restore_position(std::ifstream &input_stream, const StreamPosition &pos)
Restore a previously marked position.
int current_line_number
Current line number in the input stream.
char load_char_literal(std::ifstream &input_stream)
Load a character literal.
bool is_keyword(const std::string &s, const std::vector< std::string > &keywords)
Check if a string is in a list of keywords.
void skip_block_comment(std::ifstream &input_stream, const std::string &open="/" "*", const std::string &close="*" "/")
Skip a block comment (C-style)
std::string load_file_contents(const std::string &filename)
Load entire file contents into a string.
void init_token_scanning()
Initialize token scanning by recording current position.
void close_token_scanning(const char *buffer, char *&start_addr, const char *end_addr)
Finalize token scanning by null-terminating and saving the token.
Container< std::string > split_string(const std::string &s, const std::string &delim)
Split a std::string by a set of delimiter characters.
int read_char_from_stream(std::ifstream &input_stream)
Read a single character from an input stream with position tracking.
void expect_char(std::ifstream &input_stream, char expected)
Expect and consume a specific character.
void expect(std::ifstream &input_stream, const std::string &expected)
Expect and consume a specific string/keyword.
StreamPosition mark_position(std::ifstream &input_stream)
Mark the current position for potential backtracking.
double load_double(std::ifstream &input_stream)
Load a floating-point number from the input stream.
int current_col_number
Current column number in the input stream.
int previous_col_number
Column number at the start of the current token.
std::string trim(const std::string &s)
Return a trimmed copy of a std::string (leading + trailing whitespace removed).
std::string token_instance
The most recently scanned token.
void put_char_in_buffer(char *&start_addr, const char *end_addr, int c)
Append a character to a buffer with bounds checking.
Fw_Itor remove(Fw_Itor __first, const Fw_Itor &__last, const T &__value)
Remove elements equal to a value.
Definition ahAlgo.H:962
bool try_char(std::ifstream &input_stream, char ch)
Try to match a character without throwing.
char process_escape(const int c)
Process an escape sequence.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
long load_binary_number(std::ifstream &input_stream)
Load a binary number from the input stream.
std::string command_line_to_string(int argc, char *argv[])
Convert command line arguments to a single string.
std::string load_identifier(std::ifstream &input_stream)
Load an identifier from the input stream.
void reset_parse_state()
Reset the parsing state to initial values.
int previous_line_number
Line number at the start of the current token.
void skip_white_spaces(std::ifstream &input_stream)
Skip whitespace characters in the input stream.
std::string token_type_to_string(TokenType type)
Convert TokenType to string for debugging.
DynList< std::string > load_file_lines(const std::string &filename)
Load file as a list of lines.
long load_octal_number(std::ifstream &input_stream)
Load an octal number from the input stream.
std::string load_escaped_string(std::ifstream &input_stream)
Load a string with escape sequence processing.
constexpr size_t Buffer_Size
Default buffer size for token parsing.
std::string load_string(std::ifstream &input_stream)
Load a string from the input stream.
void skip_whitespace_and_comments(std::ifstream &input_stream)
Skip whitespace and comments (C/C++ style)
int peek_char(std::ifstream &input_stream)
Peek at the next character without consuming it.
long load_hex_number(std::ifstream &input_stream)
Load a hexadecimal number from the input stream.
void skip_line_comment(std::ifstream &input_stream)
Skip a line comment (// style or # style)
long load_number(std::ifstream &input_stream)
Load an integer number from the input stream.
STL namespace.
Comprehensive parsing utilities for text processing and compiler construction.
TEST_F(ParseUtilsTest, ReadCharBasic)
Represents a location in source code.
static SourceLocation current(const std::string &file="")
Construct from the current global parsing state.
Structure to save stream position for backtracking.
Structure representing a lexical token.
bool is_eof() const
Check if this is an end-of-file token.
Dnode< int > Test
Definition testDnode.C:42