1+ program test_symlog_axes_implementation
2+ ! ! Test symlog tick generation implementation in fortplot_axes module
3+ ! ! Tests edge cases and proper region handling for symmetric logarithmic scale
4+ use , intrinsic :: iso_fortran_env, only: wp = > real64
5+ use fortplot_axes, only: compute_scale_ticks, MAX_TICKS
6+ implicit none
7+
8+ call test_symlog_all_positive()
9+ call test_symlog_all_negative()
10+ call test_symlog_spanning_zero()
11+ call test_symlog_small_threshold()
12+ call test_symlog_large_threshold()
13+ call test_symlog_edge_boundaries()
14+ call test_symlog_single_region_cases()
15+
16+ print * , " All symlog axes implementation tests passed!"
17+
18+ contains
19+
20+ subroutine test_symlog_all_positive ()
21+ ! ! Test symlog with all positive values
22+ real (wp) :: tick_positions(MAX_TICKS)
23+ integer :: num_ticks
24+ real (wp), parameter :: threshold = 10.0_wp
25+
26+ call compute_scale_ticks(' symlog' , 1.0_wp , 1000.0_wp , threshold, tick_positions, num_ticks)
27+
28+ if (num_ticks < 2 ) then
29+ print * , " FAIL: symlog all positive should generate multiple ticks"
30+ print * , " Got" , num_ticks, " ticks for range 1 to 1000 with threshold" , threshold
31+ stop 1
32+ end if
33+
34+ ! Should have ticks in positive log region only
35+ if (any (tick_positions(1 :num_ticks) <= 0.0_wp )) then
36+ print * , " FAIL: symlog all positive should not have negative ticks"
37+ stop 1
38+ end if
39+
40+ ! Should include values > threshold in log region
41+ if (.not. any (tick_positions(1 :num_ticks) > threshold)) then
42+ print * , " FAIL: symlog all positive should have ticks in log region"
43+ stop 1
44+ end if
45+ end subroutine test_symlog_all_positive
46+
47+ subroutine test_symlog_all_negative ()
48+ ! ! Test symlog with all negative values
49+ real (wp) :: tick_positions(MAX_TICKS)
50+ integer :: num_ticks, i
51+ real (wp), parameter :: threshold = 5.0_wp
52+
53+ call compute_scale_ticks(' symlog' , - 500.0_wp , - 1.0_wp , threshold, tick_positions, num_ticks)
54+
55+ if (num_ticks < 2 ) then
56+ print * , " FAIL: symlog all negative should generate multiple ticks"
57+ print * , " Got" , num_ticks, " ticks for range -500 to -1 with threshold" , threshold
58+ stop 1
59+ end if
60+
61+ ! Should have only negative ticks
62+ if (any (tick_positions(1 :num_ticks) >= 0.0_wp )) then
63+ print * , " FAIL: symlog all negative should not have positive ticks"
64+ stop 1
65+ end if
66+
67+ ! Should include values < -threshold in negative log region
68+ if (.not. any (tick_positions(1 :num_ticks) < - threshold)) then
69+ print * , " FAIL: symlog all negative should have ticks in negative log region"
70+ print * , " No ticks found < -threshold (" , - threshold, " )"
71+ stop 1
72+ end if
73+ end subroutine test_symlog_all_negative
74+
75+ subroutine test_symlog_spanning_zero ()
76+ ! ! Test symlog spanning zero (most common case)
77+ real (wp) :: tick_positions(MAX_TICKS)
78+ integer :: num_ticks
79+ real (wp), parameter :: threshold = 1.0_wp
80+
81+ call compute_scale_ticks(' symlog' , - 100.0_wp , 100.0_wp , threshold, tick_positions, num_ticks)
82+
83+ if (num_ticks < 3 ) then
84+ print * , " FAIL: symlog spanning zero should generate many ticks"
85+ print * , " Got" , num_ticks, " ticks for range -100 to 100 with threshold" , threshold
86+ stop 1
87+ end if
88+
89+ ! Should have ticks in all three regions
90+ if (.not. any (tick_positions(1 :num_ticks) < - threshold)) then
91+ print * , " FAIL: symlog spanning zero should have negative log region ticks"
92+ stop 1
93+ end if
94+
95+ if (.not. any (abs (tick_positions(1 :num_ticks)) <= threshold)) then
96+ print * , " FAIL: symlog spanning zero should have linear region ticks"
97+ stop 1
98+ end if
99+
100+ if (.not. any (tick_positions(1 :num_ticks) > threshold)) then
101+ print * , " FAIL: symlog spanning zero should have positive log region ticks"
102+ stop 1
103+ end if
104+ end subroutine test_symlog_spanning_zero
105+
106+ subroutine test_symlog_small_threshold ()
107+ ! ! Test symlog with very small threshold
108+ real (wp) :: tick_positions(MAX_TICKS)
109+ integer :: num_ticks
110+ real (wp), parameter :: threshold = 0.1_wp
111+
112+ call compute_scale_ticks(' symlog' , - 10.0_wp , 10.0_wp , threshold, tick_positions, num_ticks)
113+
114+ if (num_ticks < 2 ) then
115+ print * , " FAIL: symlog small threshold should generate ticks"
116+ print * , " Got" , num_ticks, " ticks for range -10 to 10 with threshold" , threshold
117+ stop 1
118+ end if
119+
120+ ! With small threshold, most data should be in log regions
121+ if (.not. any (tick_positions(1 :num_ticks) < - threshold)) then
122+ print * , " FAIL: symlog small threshold should have negative log ticks"
123+ stop 1
124+ end if
125+
126+ if (.not. any (tick_positions(1 :num_ticks) > threshold)) then
127+ print * , " FAIL: symlog small threshold should have positive log ticks"
128+ stop 1
129+ end if
130+ end subroutine test_symlog_small_threshold
131+
132+ subroutine test_symlog_large_threshold ()
133+ ! ! Test symlog with large threshold
134+ real (wp) :: tick_positions(MAX_TICKS)
135+ integer :: num_ticks
136+ real (wp), parameter :: threshold = 50.0_wp
137+
138+ call compute_scale_ticks(' symlog' , - 10.0_wp , 10.0_wp , threshold, tick_positions, num_ticks)
139+
140+ if (num_ticks < 2 ) then
141+ print * , " FAIL: symlog large threshold should generate ticks"
142+ print * , " Got" , num_ticks, " ticks for range -10 to 10 with threshold" , threshold
143+ stop 1
144+ end if
145+
146+ ! With large threshold, all data should be in linear region
147+ if (any (abs (tick_positions(1 :num_ticks)) > threshold)) then
148+ print * , " FAIL: symlog large threshold should only have linear region ticks"
149+ print * , " Found tick outside threshold:" , maxval (abs (tick_positions(1 :num_ticks)))
150+ stop 1
151+ end if
152+ end subroutine test_symlog_large_threshold
153+
154+ subroutine test_symlog_edge_boundaries ()
155+ ! ! Test symlog at exact threshold boundaries
156+ real (wp) :: tick_positions(MAX_TICKS)
157+ integer :: num_ticks
158+ real (wp), parameter :: threshold = 10.0_wp
159+
160+ ! Data range exactly at boundaries
161+ call compute_scale_ticks(' symlog' , - threshold, threshold, threshold, tick_positions, num_ticks)
162+
163+ if (num_ticks < 1 ) then
164+ print * , " FAIL: symlog at boundaries should generate ticks"
165+ print * , " Got" , num_ticks, " ticks for boundary case"
166+ stop 1
167+ end if
168+
169+ ! All ticks should be within or at threshold boundaries
170+ if (any (tick_positions(1 :num_ticks) < - threshold - 1.0e-10_wp ) .or. &
171+ any (tick_positions(1 :num_ticks) > threshold + 1.0e-10_wp )) then
172+ print * , " FAIL: symlog boundary ticks should be within threshold"
173+ stop 1
174+ end if
175+ end subroutine test_symlog_edge_boundaries
176+
177+ subroutine test_symlog_single_region_cases ()
178+ ! ! Test symlog cases that only touch single regions
179+ real (wp) :: tick_positions(MAX_TICKS)
180+ integer :: num_ticks, i
181+ real (wp), parameter :: threshold = 1.0_wp
182+
183+ ! Test only linear region
184+ call compute_scale_ticks(' symlog' , - 0.5_wp , 0.5_wp , threshold, tick_positions, num_ticks)
185+
186+ if (num_ticks < 1 ) then
187+ print * , " FAIL: symlog linear-only should generate ticks"
188+ stop 1
189+ end if
190+
191+ ! All ticks should be in linear region
192+ if (any (abs (tick_positions(1 :num_ticks)) > threshold)) then
193+ print * , " FAIL: symlog linear-only should only have linear ticks"
194+ stop 1
195+ end if
196+
197+ ! Test only positive log region
198+ call compute_scale_ticks(' symlog' , 10.0_wp , 1000.0_wp , threshold, tick_positions, num_ticks)
199+
200+ if (num_ticks < 1 ) then
201+ print * , " FAIL: symlog positive-log-only should generate ticks"
202+ stop 1
203+ end if
204+
205+ ! All ticks should be positive and > threshold
206+ if (any (tick_positions(1 :num_ticks) <= threshold)) then
207+ print * , " FAIL: symlog positive-log-only should only have positive log ticks"
208+ stop 1
209+ end if
210+
211+ ! Test only negative log region
212+ call compute_scale_ticks(' symlog' , - 1000.0_wp , - 10.0_wp , threshold, tick_positions, num_ticks)
213+
214+ if (num_ticks < 1 ) then
215+ print * , " FAIL: symlog negative-log-only should generate ticks"
216+ stop 1
217+ end if
218+
219+ ! All ticks should be negative and < -threshold
220+ if (any (tick_positions(1 :num_ticks) >= - threshold)) then
221+ print * , " FAIL: symlog negative-log-only should only have negative log ticks"
222+ stop 1
223+ end if
224+ end subroutine test_symlog_single_region_cases
225+
226+ end program test_symlog_axes_implementation
0 commit comments