File: test_edge_cases.c

package info (click to toggle)
pacparser 1.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,276 kB
  • sloc: ansic: 72,713; python: 299; sh: 169; makefile: 144
file content (175 lines) | stat: -rw-r--r-- 4,863 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Comprehensive edge case testing
// Tests unusual scenarios and boundary conditions

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifndef _WIN32
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#define MAX_IP_RESULTS 10

static int
resolve_host(const char *hostname, char *ipaddr_list, int max_results,
             int req_ai_family)
{
  struct addrinfo hints;
  struct addrinfo *result;
  char ipaddr[INET6_ADDRSTRLEN];
  int error;

  // Truncate ipaddr_list to an empty string.
  ipaddr_list[0] = '\0';

  memset(&hints, 0, sizeof(struct addrinfo));

  hints.ai_family = req_ai_family;
  hints.ai_socktype = SOCK_STREAM;

  error = getaddrinfo(hostname, NULL, &hints, &result);
  if (error) return error;
  int i = 0;
  size_t offset = 0;
  for(struct addrinfo *ai = result; ai != NULL && i < max_results; ai = ai->ai_next, i++) {
    getnameinfo(ai->ai_addr, ai->ai_addrlen, ipaddr, sizeof(ipaddr), NULL, 0,
                NI_NUMERICHOST);
    if (offset > 0) {
      ipaddr_list[offset++] = ';';
    }
    size_t len = strlen(ipaddr);
    strcpy(ipaddr_list + offset, ipaddr);
    offset += len;
  }
  freeaddrinfo(result);
  return 0;
}

void test_case(const char *name, const char *hostname, int max_results, int family) {
  char ipaddr_list[INET6_ADDRSTRLEN * MAX_IP_RESULTS + MAX_IP_RESULTS];
  memset(ipaddr_list, 0xFF, sizeof(ipaddr_list));  // Fill with 0xFF

  printf("\n--- %s ---\n", name);
  printf("Hostname: '%s', max_results: %d\n", hostname, max_results);

  int result = resolve_host(hostname, ipaddr_list, max_results, family);

  if (result != 0) {
    printf("Failed: %s\n", gai_strerror(result));
    // Verify buffer was initialized to empty string
    if (ipaddr_list[0] != '\0') {
      printf("✗ ERROR: Buffer not initialized to empty string on failure\n");
    } else {
      printf("✓ Buffer properly initialized to empty string on failure\n");
    }
    return;
  }

  size_t len = strlen(ipaddr_list);
  printf("Success: '%s' (length: %zu)\n", ipaddr_list, len);

  // Count IPs
  int ip_count = (len > 0) ? 1 : 0;
  int semicolon_count = 0;
  for (size_t i = 0; i < len; i++) {
    if (ipaddr_list[i] == ';') {
      semicolon_count++;
      ip_count++;
    }
  }
  printf("IPs: %d, Semicolons: %d\n", ip_count, semicolon_count);

  // Validation checks
  int errors = 0;

  // Check null termination
  if (ipaddr_list[len] != '\0') {
    printf("✗ ERROR: String not null-terminated\n");
    errors++;
  }

  // Check no writes beyond null terminator
  int found_non_ff = 0;
  for (size_t i = len + 1; i < sizeof(ipaddr_list); i++) {
    if ((unsigned char)ipaddr_list[i] != 0xFF) {
      found_non_ff = 1;
      break;
    }
  }
  if (found_non_ff) {
    printf("✗ ERROR: Wrote beyond null terminator\n");
    errors++;
  }

  // Check semicolon placement
  if (len > 0) {
    if (ipaddr_list[0] == ';') {
      printf("✗ ERROR: Starts with semicolon\n");
      errors++;
    }
  }
  if (len > 0 && ipaddr_list[len-1] == ';') {
    printf("✗ ERROR: Ends with semicolon\n");
    errors++;
  }

  // Check for double semicolons
  if (len > 1) {
    for (size_t i = 0; i < len - 1; i++) {
      if (ipaddr_list[i] == ';' && ipaddr_list[i+1] == ';') {
        printf("✗ ERROR: Contains ';;'\n");
        errors++;
        break;
      }
    }
  }

  // Check IP count matches semicolons
  if (ip_count != semicolon_count + 1 && len > 0) {
    printf("✗ ERROR: IP count mismatch (expected %d, got %d)\n",
           semicolon_count + 1, ip_count);
    errors++;
  }

  if (errors == 0) {
    printf("✓ All validations passed\n");
  }
}

int main() {
  printf("=== Comprehensive Edge Case Testing ===\n");

  // Edge case: max_results boundaries
  test_case("Max results = 0", "localhost", 0, AF_INET);
  test_case("Max results = 1", "localhost", 1, AF_INET);
  test_case("Max results = MAX_IP_RESULTS", "google.com", MAX_IP_RESULTS, AF_UNSPEC);

  // Edge case: Different IP types
  test_case("IPv4 only", "google.com", 10, AF_INET);
  test_case("IPv6 only", "google.com", 10, AF_INET6);
  test_case("Both IPv4 and IPv6", "google.com", 10, AF_UNSPEC);

  // Edge case: Numeric IPs (should not fail)
  test_case("Numeric IPv4", "8.8.8.8", 10, AF_INET);
  test_case("Numeric IPv6 full", "2001:4860:4860::8888", 10, AF_INET6);
  test_case("Numeric IPv6 compressed", "::1", 10, AF_INET6);
  test_case("Numeric IPv4 mapped IPv6", "::ffff:8.8.8.8", 10, AF_INET6);

  // Edge case: Special hostnames
  test_case("Localhost", "localhost", 10, AF_INET);
  test_case("Localhost IPv6", "localhost", 10, AF_INET6);

  // Edge case: Non-existent hostnames
  test_case("Invalid hostname", "this-definitely-does-not-exist.invalid", 10, AF_INET);

  printf("\n=== All Edge Case Tests Complete ===\n");

  return 0;
}