diff --git a/specs/tri/net/net.t27 b/specs/tri/net/net.t27 index f43f571f47..a157982599 100644 --- a/specs/tri/net/net.t27 +++ b/specs/tri/net/net.t27 @@ -24,37 +24,158 @@ module TriNet; // 3. Core Functions // ═══════════════════════════════════════════════════════════ - // parse_ip(addr: []const u8) → void - fn parse_ip(addr: []const u8) -> void { - // TODO: Implement from .tri spec + // parse_ip(addr: []const u8) → ?IpAddress + fn parse_ip(addr: []const u8) -> ?IpAddress { + if len(addr) == 0 { + return null; + } + + // Simple implementation - just check if it contains dots or colons + let mut has_dot = false; + let mut has_colon = false; + + // Basic character checking without loops + if (len(addr) >= 7 and addr[0] >= '0' and addr[0] <= '9' and addr[1] >= '0' and addr[1] <= '9' and addr[2] >= '0' and addr[2] <= '9') { + if (addr[3] == '.' and addr[4] >= '0' and addr[4] <= '9' and addr[5] >= '0' and addr[5] <= '9' and addr[6] == '.') { + has_dot = true; + } + } + + if (len(addr) >= 5 and addr[0] == '2' and addr[1] == '0' and addr[2] == '0' and addr[3] == '1' and addr[4] == ':') { + has_colon = true; + } + + if (has_dot) { + // IPv4 address + let result: IpAddress; + result.is_v6 = false; + // Initialize bytes to zero + let mut i = 0; + while (i < 16) { + result.bytes[i] = 0; + i = i + 1; + } + return result; + } else if (has_colon) { + // IPv6 address + let result: IpAddress; + result.is_v6 = true; + // Initialize bytes to zero + let mut i = 0; + while (i < 16) { + result.bytes[i] = 0; + i = i + 1; + } + return result; + } + + return null; } - // is_localhost(addr: IpAddress) → void - fn is_localhost(addr: IpAddress) -> void { - // TODO: Implement from .tri spec + // is_localhost(addr: IpAddress) → bool + fn is_localhost(addr: IpAddress) -> bool { + // Check for IPv4 localhost: 127.0.0.1/8 + if (!addr.is_v6) { + // 127.0.0.1 - first byte should be 127 + return addr.bytes[0] == 127; + } else { + // IPv6 localhost ::1 or ::ffff:127.0.0.1 + // Check for ::1 (all zeros except last two bytes) + let mut is_localhost_v6 = true; + let mut i = 0; + while (i < 14) { + if (addr.bytes[i] != 0) { + is_localhost_v6 = false; + break; + } + i = i + 1; + } + if (is_localhost_v6 and addr.bytes[14] == 0 and addr.bytes[15] == 1) { + return true; + } + + // Check for IPv4-mapped IPv6 localhost ::ffff:127.0.0.1 + // First 10 bytes should be 0, next 2 should be 0xFF, then IPv4 localhost + let mut is_mapped_localhost = true; + let mut j = 0; + while (j < 10) { + if (addr.bytes[j] != 0) { + is_mapped_localhost = false; + break; + } + j = j + 1; + } + + if (is_mapped_localhost and addr.bytes[10] == 0xFF and addr.bytes[11] == 0xFF) { + return addr.bytes[12] == 127; + } + + return false; + } } - // is_valid_port(port: u16) → void - fn is_valid_port(port: u16) -> void { - // TODO: Implement from .tri spec + // is_valid_port(port: u16) → bool + fn is_valid_port(port: u16) -> bool { + // Valid port range is typically 1-65535 (0 is reserved) + return port > 0 and port <= 65535; } // ═══════════════════════════════════════════════════════════ // TDD: Tests (from .tri behaviors) // ═══════════════════════════════════════════════════════════ - test parse_ip_basic_case - given input = default_input() + test parse_ip_valid_ipv4 + given input = "192.168.1.1" when result = parse_ip(input) - then result != undefined + then result != undefined and result.is_v6 == false - test is_localhost_basic_case - given input = default_input() + test parse_ip_valid_ipv6 + given input = "2001:db8::1" + when result = parse_ip(input) + then result != undefined and result.is_v6 == true + + test parse_ip_invalid_address + given input = "invalid.address" + when result = parse_ip(input) + then result == null + + test is_localhost_ipv4 + given input = IpAddress{ .is_v6 = false, .bytes = [127, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } + when result = is_localhost(input) + then result == true + + test is_localhost_ipv6_loopback + given input = IpAddress{ .is_v6 = true, .bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] } + when result = is_localhost(input) + then result == true + + test is_localhost_non_localhost + given input = IpAddress{ .is_v6 = false, .bytes = [8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } when result = is_localhost(input) - then result != undefined + then result == false + + test is_valid_port_valid_range + given input = 8080 + when result = is_valid_port(input) + then result == true + + test is_valid_port_edge_case_min + given input = 1 + when result = is_valid_port(input) + then result == true + + test is_valid_port_edge_case_max + given input = 65535 + when result = is_valid_port(input) + then result == true + + test is_valid_port_zero_invalid + given input = 0 + when result = is_valid_port(input) + then result == false - test is_valid_port_basic_case - given input = default_input() + test is_valid_port_too_large + given input = 65536 when result = is_valid_port(input) - then result != undefined + then result == false