Fortran · 7827 bytes Raw Blame History
1 ! ==============================================================================
2 ! Simplified test program for Phase 6 - Parser with memory pooling
3 ! ==============================================================================
4 program test_parser_simple
5 use string_pool
6 use memory_dashboard
7 use pooled_types
8 use shell_types
9 use iso_fortran_env, only: output_unit
10 implicit none
11
12 type(pooled_command_t) :: cmd
13 integer :: i
14 character(:), pointer :: token_ptr, str_ptr
15 logical :: test_passed
16 integer :: total_allocs, total_deallocs, current_strings, peak_strings
17 real :: hit_rate
18
19 test_passed = .true.
20
21 print *, "=== Phase 6 Parser Memory Pooling Test (Simplified) ==="
22 print *, "Testing pooled command types with memory dashboard"
23 print *
24
25 ! Initialize the pool and dashboard
26 call pool_init()
27 call dashboard_init(verbose=.false.)
28
29 ! Test 1: Create and populate a pooled command
30 print *, "Test 1: Creating pooled command with tokens..."
31 call init_pooled_command(cmd)
32
33 ! Allocate tokens
34 call allocate_pooled_tokens(cmd, 4, MAX_TOKEN_LEN)
35 call set_pooled_token(cmd, 1, "ls")
36 call set_pooled_token(cmd, 2, "-la")
37 call set_pooled_token(cmd, 3, "/tmp")
38 call set_pooled_token(cmd, 4, "testdir")
39
40 ! Verify tokens
41 print *, " Tokens allocated:", cmd%num_tokens
42 do i = 1, cmd%num_tokens
43 token_ptr => get_pooled_token(cmd, i)
44 if (associated(token_ptr)) then
45 print *, " Token", i, ":", trim(token_ptr)
46 else
47 print *, " Token", i, ": NULL"
48 test_passed = .false.
49 end if
50 end do
51
52 ! Test 2: Set string fields
53 print *, ""
54 print *, "Test 2: Setting string fields..."
55 call set_pooled_string(cmd%input_file, "input.txt", MOD_PARSER)
56 call set_pooled_string(cmd%output_file, "output.txt", MOD_PARSER)
57 call set_pooled_string(cmd%error_file, "error.log", MOD_PARSER)
58 call set_pooled_string(cmd%heredoc_delimiter, "EOF", MOD_PARSER)
59 call set_pooled_string(cmd%heredoc_content, "This is heredoc content"//new_line('a')//"Multiple lines", MOD_PARSER)
60
61 ! Verify string fields
62 str_ptr => get_pooled_string(cmd%input_file)
63 if (associated(str_ptr)) then
64 print *, " Input file:", trim(str_ptr)
65 if (trim(str_ptr) /= "input.txt") test_passed = .false.
66 else
67 print *, " Input file: NULL"
68 test_passed = .false.
69 end if
70
71 str_ptr => get_pooled_string(cmd%output_file)
72 if (associated(str_ptr)) then
73 print *, " Output file:", trim(str_ptr)
74 if (trim(str_ptr) /= "output.txt") test_passed = .false.
75 else
76 print *, " Output file: NULL"
77 test_passed = .false.
78 end if
79
80 str_ptr => get_pooled_string(cmd%error_file)
81 if (associated(str_ptr)) then
82 print *, " Error file:", trim(str_ptr)
83 if (trim(str_ptr) /= "error.log") test_passed = .false.
84 else
85 print *, " Error file: NULL"
86 test_passed = .false.
87 end if
88
89 ! Test 3: Memory statistics before release
90 print *, ""
91 print *, "Test 3: Checking memory statistics before release..."
92 call pool_statistics(total_allocs, total_deallocs, current_strings, peak_strings, hit_rate)
93 print *, " Current strings in pool:", current_strings
94 print *, " Peak strings:", peak_strings
95 print *, " Cache hit rate:", int(hit_rate * 100), "%"
96
97 if (current_strings > 0) then
98 print *, " PASSED: Strings are allocated in pool"
99 else
100 print *, " FAILED: No strings in pool"
101 test_passed = .false.
102 end if
103
104 ! Test 4: Release the command
105 print *, ""
106 print *, "Test 4: Releasing pooled command..."
107 call release_pooled_command(cmd)
108
109 ! Check that everything was released
110 call pool_statistics(total_allocs, total_deallocs, current_strings, peak_strings, hit_rate)
111 print *, " Current strings after release:", current_strings
112
113 if (current_strings == 0) then
114 print *, " PASSED: All strings released (no memory leak)"
115 else
116 print *, " FAILED: Memory leak -", current_strings, "strings still allocated"
117 test_passed = .false.
118 end if
119
120 ! Test 5: Stress test - rapid allocations and deallocations
121 print *, ""
122 print *, "Test 5: Stress testing with 1000 allocate/release cycles..."
123 do i = 1, 1000
124 call init_pooled_command(cmd)
125 call allocate_pooled_tokens(cmd, 3, 64)
126 call set_pooled_token(cmd, 1, "test")
127 call set_pooled_token(cmd, 2, "command")
128 call set_pooled_token(cmd, 3, "tokens")
129 call set_pooled_string(cmd%output_file, "test_output.txt", MOD_PARSER)
130 call release_pooled_command(cmd)
131 end do
132
133 call pool_statistics(total_allocs, total_deallocs, current_strings, peak_strings, hit_rate)
134 print *, " Total allocations:", total_allocs
135 print *, " Total deallocations:", total_deallocs
136 print *, " Current strings:", current_strings
137 print *, " Cache hit rate:", int(hit_rate * 100), "%"
138
139 if (current_strings == 0 .and. hit_rate > 0.95) then
140 print *, " PASSED: No leaks and excellent cache hit rate"
141 else if (current_strings == 0) then
142 print *, " PASSED: No memory leaks"
143 else
144 print *, " FAILED: Memory leak detected"
145 test_passed = .false.
146 end if
147
148 ! Test 6: Test conversion from legacy command
149 print *, ""
150 print *, "Test 6: Testing conversion from legacy command_t..."
151 block
152 type(command_t) :: legacy_cmd
153 type(pooled_command_t) :: pooled_cmd
154
155 ! Create a legacy command
156 allocate(character(len=MAX_TOKEN_LEN) :: legacy_cmd%tokens(3))
157 legacy_cmd%tokens(1) = "echo"
158 legacy_cmd%tokens(2) = "Hello"
159 legacy_cmd%tokens(3) = "World"
160 legacy_cmd%num_tokens = 3
161 allocate(character(len=10) :: legacy_cmd%input_file)
162 legacy_cmd%input_file = "input.txt"
163 allocate(character(len=11) :: legacy_cmd%output_file)
164 legacy_cmd%output_file = "output.txt"
165
166 ! Convert to pooled
167 call convert_to_pooled_command(legacy_cmd, pooled_cmd)
168
169 ! Verify conversion
170 token_ptr => get_pooled_token(pooled_cmd, 1)
171 if (associated(token_ptr) .and. trim(token_ptr) == "echo") then
172 print *, " Token conversion: PASSED"
173 else
174 print *, " Token conversion: FAILED"
175 test_passed = .false.
176 end if
177
178 str_ptr => get_pooled_string(pooled_cmd%input_file)
179 if (associated(str_ptr) .and. trim(str_ptr) == "input.txt") then
180 print *, " String field conversion: PASSED"
181 else
182 print *, " String field conversion: FAILED"
183 test_passed = .false.
184 end if
185
186 ! Clean up
187 call release_pooled_command(pooled_cmd)
188 if (allocated(legacy_cmd%tokens)) deallocate(legacy_cmd%tokens)
189 if (allocated(legacy_cmd%input_file)) deallocate(legacy_cmd%input_file)
190 if (allocated(legacy_cmd%output_file)) deallocate(legacy_cmd%output_file)
191 end block
192
193 ! Display dashboard
194 print *, ""
195 print *, "=== Memory Dashboard Display ==="
196 call dashboard_display(detailed=.false.)
197
198 ! Final check
199 call pool_statistics(total_allocs, total_deallocs, current_strings, peak_strings, hit_rate)
200
201 ! Export statistics
202 call dashboard_export_csv("parser_pooling_test.csv")
203 print *, ""
204 print *, "Statistics exported to parser_pooling_test.csv"
205
206 ! Clean up
207 call dashboard_cleanup()
208 call pool_cleanup()
209
210 ! Summary
211 print *, ""
212 print *, "=== Test Summary ==="
213 if (test_passed .and. current_strings == 0) then
214 print *, "✅ ALL TESTS PASSED"
215 print *, ""
216 print *, "Parser pooling integration verified:"
217 print *, " • Pooled tokens working correctly"
218 print *, " • Pooled string fields working correctly"
219 print *, " • No memory leaks detected"
220 print *, " • Dashboard integration successful"
221 print *, " • Cache hit rate:", int(hit_rate * 100), "%"
222 print *, ""
223 print *, "Ready to integrate into production parser!"
224 else
225 print *, "❌ SOME TESTS FAILED"
226 if (current_strings > 0) then
227 print *, " Memory leak:", current_strings, "strings not released"
228 end if
229 end if
230
231 end program test_parser_simple