1+ <?php
2+ /**
3+ * Class HelpersLoopbackTest
4+ *
5+ * @package Accessibility_Checker
6+ */
7+
8+ use EDAC \Admin \Helpers ;
9+
10+ /**
11+ * Test cases for EDAC\Admin\Helpers::is_domain_loopback() method.
12+ */
13+ class HelpersLoopbackTest extends WP_UnitTestCase {
14+
15+ /**
16+ * Tests the is_domain_loopback method with various inputs.
17+ *
18+ * @dataProvider domain_loopback_data
19+ *
20+ * @param string $domain The domain to test.
21+ * @param bool $expected The expected result.
22+ */
23+ public function test_is_domain_loopback ( $ domain , $ expected ) {
24+ $ result = Helpers::is_domain_loopback ( $ domain );
25+
26+ // The result should always be a boolean.
27+ $ this ->assertIsBool ( $ result );
28+ $ this ->assertSame ( $ expected , $ result );
29+ }
30+
31+ /**
32+ * Data provider for test_is_domain_loopback.
33+ */
34+ public function domain_loopback_data () {
35+ return [
36+ 'localhost ' => [
37+ 'domain ' => 'localhost ' ,
38+ 'expected ' => true ,
39+ ],
40+ '127.0.0.1 direct IP ' => [
41+ 'domain ' => '127.0.0.1 ' ,
42+ 'expected ' => true ,
43+ ],
44+ '127.0.0.2 loopback range ' => [
45+ 'domain ' => '127.0.0.2 ' ,
46+ 'expected ' => true ,
47+ ],
48+ '127.255.255.255 loopback range end ' => [
49+ 'domain ' => '127.255.255.255 ' ,
50+ 'expected ' => true ,
51+ ],
52+ '127.100.50.25 mid loopback range ' => [
53+ 'domain ' => '127.100.50.25 ' ,
54+ 'expected ' => true ,
55+ ],
56+ 'google.com external domain ' => [
57+ 'domain ' => 'google.com ' ,
58+ 'expected ' => false ,
59+ ],
60+ 'example.com external domain ' => [
61+ 'domain ' => 'example.com ' ,
62+ 'expected ' => false ,
63+ ],
64+ '192.168.1.1 private IP (not loopback) ' => [
65+ 'domain ' => '192.168.1.1 ' ,
66+ 'expected ' => false ,
67+ ],
68+ '10.0.0.1 private IP (not loopback) ' => [
69+ 'domain ' => '10.0.0.1 ' ,
70+ 'expected ' => false ,
71+ ],
72+ '8.8.8.8 public IP ' => [
73+ 'domain ' => '8.8.8.8 ' ,
74+ 'expected ' => false ,
75+ ],
76+ ];
77+ }
78+
79+ /**
80+ * Test IPv4 loopback range boundaries.
81+ */
82+ public function test_ipv4_loopback_boundaries () {
83+ // Test the exact start of loopback range.
84+ $ this ->assertTrue ( Helpers::is_domain_loopback ( '127.0.0.0 ' ) );
85+
86+ // Test just before loopback range.
87+ $ this ->assertFalse ( Helpers::is_domain_loopback ( '126.255.255.255 ' ) );
88+
89+ // Test just after loopback range.
90+ $ this ->assertFalse ( Helpers::is_domain_loopback ( '128.0.0.0 ' ) );
91+ }
92+
93+ /**
94+ * Test edge cases and invalid inputs.
95+ */
96+ public function test_edge_cases () {
97+ // Empty string.
98+ $ result = Helpers::is_domain_loopback ( '' );
99+ $ this ->assertIsBool ( $ result );
100+ $ this ->assertFalse ( $ result );
101+
102+ // Invalid domain format.
103+ $ result = Helpers::is_domain_loopback ( 'not-a-domain ' );
104+ $ this ->assertIsBool ( $ result );
105+
106+ // Malformed IP.
107+ $ result = Helpers::is_domain_loopback ( '999.999.999.999 ' );
108+ $ this ->assertIsBool ( $ result );
109+ $ this ->assertFalse ( $ result );
110+
111+ // Domain with protocol.
112+ $ result = Helpers::is_domain_loopback ( 'http://localhost ' );
113+ $ this ->assertIsBool ( $ result );
114+ }
115+
116+ /**
117+ * Test special localhost variations.
118+ */
119+ public function test_localhost_variations () {
120+ // Standard localhost should resolve to loopback.
121+ $ this ->assertTrue ( Helpers::is_domain_loopback ( 'localhost ' ) );
122+
123+ // Test case sensitivity (if applicable).
124+ $ result = Helpers::is_domain_loopback ( 'LOCALHOST ' );
125+ $ this ->assertIsBool ( $ result );
126+
127+ // Test with port (should still work since we're testing the domain part).
128+ $ result = Helpers::is_domain_loopback ( 'localhost:8080 ' );
129+ $ this ->assertIsBool ( $ result );
130+ }
131+
132+ /**
133+ * Test that the method handles DNS resolution errors gracefully.
134+ */
135+ public function test_dns_resolution_error_handling () {
136+ // Test with a clearly non-existent domain.
137+ $ fake_domain = 'definitely-not-a-real-domain- ' . uniqid () . '.invalid ' ;
138+ $ result = Helpers::is_domain_loopback ( $ fake_domain );
139+
140+ // Should return a boolean and not throw an exception.
141+ $ this ->assertIsBool ( $ result );
142+ $ this ->assertFalse ( $ result );
143+ }
144+
145+ /**
146+ * Test IPv6 loopback detection (if supported).
147+ */
148+ public function test_ipv6_loopback_detection () {
149+ // The method checks for IPv6 AAAA records.
150+ // This test may be limited by the test environment's DNS capabilities.
151+
152+ // Test direct IPv6 loopback address (may not work in all environments).
153+ $ result = Helpers::is_domain_loopback ( '::1 ' );
154+ $ this ->assertIsBool ( $ result );
155+
156+ // If IPv6 is supported, ::1 should be detected as loopback.
157+ // However, we can't guarantee this in all test environments.
158+ }
159+
160+ /**
161+ * Test that the method properly validates IP address formats.
162+ */
163+ public function test_ip_address_validation () {
164+ // Valid IPv4 addresses in loopback range.
165+ $ valid_loopback_ips = [
166+ '127.0.0.1 ' ,
167+ '127.1.2.3 ' ,
168+ '127.254.255.254 ' ,
169+ ];
170+
171+ foreach ( $ valid_loopback_ips as $ ip ) {
172+ $ result = Helpers::is_domain_loopback ( $ ip );
173+ $ this ->assertTrue ( $ result , "Failed to detect loopback for IP: $ ip " );
174+ }
175+
176+ // Valid IPv4 addresses outside loopback range.
177+ $ non_loopback_ips = [
178+ '1.1.1.1 ' ,
179+ '8.8.8.8 ' ,
180+ '192.168.1.1 ' ,
181+ '172.16.0.1 ' ,
182+ '203.0.113.1 ' ,
183+ ];
184+
185+ foreach ( $ non_loopback_ips as $ ip ) {
186+ $ result = Helpers::is_domain_loopback ( $ ip );
187+ $ this ->assertFalse ( $ result , "Incorrectly detected loopback for IP: $ ip " );
188+ }
189+ }
190+
191+ /**
192+ * Test behavior with domains that might have multiple A records.
193+ */
194+ public function test_multiple_a_records () {
195+ // Some domains may have multiple A records.
196+ // The method should handle this correctly by checking the resolved IP.
197+
198+ // Test a well-known domain that should resolve to non-loopback.
199+ $ result = Helpers::is_domain_loopback ( 'github.com ' );
200+ $ this ->assertIsBool ( $ result );
201+ $ this ->assertFalse ( $ result );
202+ }
203+
204+ /**
205+ * Test the method's handling of the gethostbyname function.
206+ */
207+ public function test_gethostbyname_behavior () {
208+ // gethostbyname returns the hostname unchanged if resolution fails.
209+ // The method should handle this case.
210+
211+ $ non_resolvable = 'non-resolvable-domain- ' . uniqid () . '.invalid ' ;
212+ $ result = Helpers::is_domain_loopback ( $ non_resolvable );
213+
214+ // Should return false for non-resolvable domains.
215+ $ this ->assertIsBool ( $ result );
216+ $ this ->assertFalse ( $ result );
217+ }
218+
219+ /**
220+ * Test performance with multiple calls.
221+ */
222+ public function test_performance_multiple_calls () {
223+ // Test that the method performs reasonably with multiple calls.
224+ $ domains = [
225+ 'localhost ' ,
226+ '127.0.0.1 ' ,
227+ 'google.com ' ,
228+ 'example.com ' ,
229+ '127.0.0.2 ' ,
230+ ];
231+
232+ $ start_time = microtime ( true );
233+
234+ foreach ( $ domains as $ domain ) {
235+ $ result = Helpers::is_domain_loopback ( $ domain );
236+ $ this ->assertIsBool ( $ result );
237+ }
238+
239+ $ end_time = microtime ( true );
240+ $ execution_time = $ end_time - $ start_time ;
241+
242+ // Should complete within a reasonable time (5 seconds).
243+ $ this ->assertLessThan ( 5.0 , $ execution_time , 'Method took too long to execute multiple calls ' );
244+ }
245+ }
0 commit comments