Files
wehub-resource-sync 680845cb1c
Linux build / Determine Swift version (push) Waiting to run
Linux build / Linux compile check (push) Blocked by required conditions
Build containerization / Verify commit signatures (push) Has been skipped
Build containerization / containerization (push) Successful in 0s
chore: import upstream snapshot with attribution
2026-07-13 12:25:30 +08:00

406 lines
14 KiB
Swift

//===----------------------------------------------------------------------===//
// Copyright © 2026 Apple Inc. and the Containerization project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
import Foundation
import Testing
@testable import ContainerizationExtras
@Suite("MACAddress Tests")
struct MACAddressTests {
// MARK: - Initializer Tests
@Suite("Initializers")
struct InitializerTests {
@Test(
"UInt64 initializer - valid addresses",
arguments: [
//(0x0123_4567_89ab, "01:23:45:67:89:ab"), // a valid address
//(0x0000_0000_0000, "00:00:00:00:00:00"), // zero address
//(0xFFFF_FFFF_FFFF, "ff:ff:ff:ff:ff:ff"), // max address
(0xffff_0123_4567_89ab, "01:23:45:67:89:ab") // drops the most significant 16 bits
]
)
func testUInt64InitializerValid(inputValue: UInt64, description: String) {
let address = MACAddress(inputValue)
#expect(address.value == inputValue & 0x0000_ffff_ffff_ffff)
}
@Test(
"String initializer - valid addresses",
arguments: [
("01:23:45:67:89:ab", 0x0123_4567_89ab), // colon separators
("01-23-45-67-89-ab", 0x0123_4567_89ab), // dash separators
("ab:cd:ef:AB:CD:EF", 0xabcd_efab_cdef), // mixed case
("00:00:00:00:00:00", 0x0000_0000_0000), // zero address
("ff:ff:ff:ff:ff:ff", 0xffff_ffff_ffff), // max address
]
)
func testStringInitializerValid(addressString: String, expectedValue: UInt64) throws {
let address = try MACAddress(addressString)
#expect(address.value == expectedValue)
}
@Test(
"String initializer - invalid addresses",
arguments: [
"", // empty string
"01:23:45:67:89", // too few octets
"01:23:45:67:89:ab:cd", // too many octets
"01:23:45:67:89:", // empty octet
":23:45:67:89:ab", // empty octet
"01::45:67:89:ab", // empty octet
"01:23:45:67:89:a", // short octet
"1:23:45:67:89:ab", // short octet
"01:2:45:67:89:ab", // short octet
"01:23:45:67:89:abc", // long octet
"012:23:45:67:89:ab", // long octet
"01:234:45:67:89:ab", // long octet
"01:23:45:67:89:@G", // invalid content 0x40, 0x47
"`g:23:45:67:89:ab", // invalid content 0x60, 0x67
"01:hi:45:67:89:ab", // invalid content
" 01:23:45:67:89:ab", // leading whitespace
"01:23:45:67:89:ab ", // trailing whitespace
"01: 23:45:67:89:ab", // internal whitespace
]
)
func testStringInitializerInvalid(invalidAddress: String) {
#expect(throws: AddressError.self) {
try MACAddress(invalidAddress)
}
}
}
// MARK: - Property Tests
@Suite("Properties")
struct PropertyTests {
@Test(
"bytes property",
arguments: [
(
UInt64(0x0123_4567_89ab),
[UInt8(0x01), UInt8(0x23), UInt8(0x45), UInt8(0x67), UInt8(0x89), UInt8(0xab)]
),
(
UInt64(0x0000_0000_0000),
[UInt8(0x00), UInt8(0x00), UInt8(0x00), UInt8(0x00), UInt8(0x00), UInt8(0x00)]
),
(
UInt64(0xffff_ffff_ffff),
[UInt8(0xff), UInt8(0xff), UInt8(0xff), UInt8(0xff), UInt8(0xff), UInt8(0xff)]
),
(
UInt64(0xffff_0123_4567_89ab),
[UInt8(0x01), UInt8(0x23), UInt8(0x45), UInt8(0x67), UInt8(0x89), UInt8(0xab)]
),
]
)
func testBytesProperty(inputValue: UInt64, expectedBytes: [UInt8]) {
let address = MACAddress(inputValue)
#expect(address.bytes == expectedBytes)
}
@Test(
"description property",
arguments: [
(0x0123_4567_89ab, "01:23:45:67:89:ab"),
(0x0000_0000_0000, "00:00:00:00:00:00"),
(0xffff_ffff_ffff, "ff:ff:ff:ff:ff:ff"),
(0xffff_0123_4567_89ab, "01:23:45:67:89:ab"),
]
)
func testDescriptionProperty(inputValue: UInt64, expectedDescription: String) {
let address = MACAddress(inputValue)
#expect(address.description == expectedDescription)
}
@Test(
"isLocallyAdministered property",
arguments: [
(0x0000_1234_5678, false),
(0x0200_1234_5678, true),
]
)
func testIsLocallyAdministeredProperty(inputValue: UInt64, expectedValue: Bool) {
let address = MACAddress(inputValue)
#expect(address.isLocallyAdministered == expectedValue)
}
@Test(
"isMulticast property",
arguments: [
(0x0000_1234_5678, false),
(0x0100_1234_5678, true),
]
)
func testIsMulticastProperty(inputValue: UInt64, expectedValue: Bool) {
let address = MACAddress(inputValue)
#expect(address.isMulticast == expectedValue)
}
@Test(
"round-trip string conversion",
arguments: [
"01:23:45:67:89:ab",
"00:00:00:00:00:00",
"ff:ff:ff:ff:ff:ff",
"01-23-45-67-89-AB",
]
)
func testRoundTripStringConversion(addressString: String) throws {
let address = try MACAddress(addressString)
#expect(address.description == addressString.lowercased().replacingOccurrences(of: "-", with: ":"))
}
}
// MARK: - Link Local Address Tests
@Suite("Link Local Addresses")
struct LinkLocalAddressTests {
@Test(
"Link local address",
arguments: [
(0x39a7_9407_cbd0, 0xfd97_7b15_d62e_75ac_3ba7_94ff_fe07_cbd0),
(0x5e3b_68d7_e510, 0xfd97_7b15_d62e_75ac_5c3b_68ff_fed7_e510),
]
)
func testLinkLocalAddress(mac: UInt64, ipv6: UInt128) throws {
let mac = MACAddress(mac)
let ipv6Prefix = IPv6Address(ipv6 & 0xffff_ffff_ffff_ffff_0000_0000_0000_0000)
let ipv6Address = try mac.ipv6Address(network: ipv6Prefix)
#expect(ipv6Address == IPv6Address(ipv6))
}
}
// MARK: - Protocol Conformance Tests
@Suite("Protocol Conformances")
struct ProtocolConformanceTests {
@Test("Equatable conformance")
func testEquatableConformance() {
let addr1 = MACAddress(0x0123_4567_89ab)
let addr2 = MACAddress(0x0123_4567_89ab)
let addr3 = MACAddress(0x0123_4567_89ac)
#expect(addr1 == addr2)
#expect(addr1 != addr3)
#expect(addr2 != addr3)
}
@Test("Hashable conformance")
func testHashableConformance() {
let addr1 = MACAddress(0x0123_4567_89ab)
let addr2 = MACAddress(0x0123_4567_89ab)
let addr3 = MACAddress(0x0123_4567_89ac)
// Equal objects should have equal hash values
#expect(addr1.hashValue == addr2.hashValue)
// Different objects should ideally have different hash values
// (though this is not guaranteed, it's very likely for these values)
#expect(addr1.hashValue != addr3.hashValue)
// Test that addresses can be used in Sets and Dictionaries
let addressSet: Set<MACAddress> = [addr1, addr2, addr3]
#expect(addressSet.count == 2) // addr1 and addr2 are equal
let addressDict = [addr1: "localhost", addr3: "private"]
#expect(addressDict[addr2] == "localhost") // addr2 equals addr1
}
@Test("CustomStringConvertible conformance")
func testCustomStringConvertibleConformance() {
let address = MACAddress(0x0123_4567_89ab)
let stringRepresentation = String(describing: address)
#expect(stringRepresentation == "01:23:45:67:89:ab")
}
@Test("Sendable conformance")
func testSendableConformance() {
// This test verifies that MACAddress can be safely passed across concurrency boundaries
let address = MACAddress(0x0123_4567_89ab)
Task {
let taskAddress = address
#expect(taskAddress.value == 0x0123_4567_89ab)
}
}
}
// MARK: - Performance Tests
@Suite("Performance")
struct PerformanceTests {
@Test("parsing performance")
func testParsingPerformance() throws {
let testAddresses = [
"01:23:45:67:89:ab",
"01-23-45-67-89-ab",
"01-23-45-67-89-a",
"01-23-45-67-89-abc",
]
// Warm up
for _ in 0..<100 {
for address in testAddresses {
_ = try? MACAddress(address)
}
}
// Measure performance
let iterations = 10000
let startTime = Date()
for _ in 0..<iterations {
for address in testAddresses {
_ = try? MACAddress(address)
}
}
let endTime = Date()
let totalTime = endTime.timeIntervalSince(startTime)
let averageTime = totalTime / Double(iterations * testAddresses.count)
// Should be very fast - less than 1ms per parse on average
#expect(averageTime < 0.001, "Parsing should be fast: \(averageTime)s per address")
}
@Test("bytes property performance")
func testBytesPropertyPerformance() {
let address = MACAddress(0x0123_4567_89ab)
let iterations = 100000
let startTime = Date()
for _ in 0..<iterations {
_ = address.bytes
}
let endTime = Date()
let totalTime = endTime.timeIntervalSince(startTime)
let averageTime = totalTime / Double(iterations)
// Should be very fast - less than 0.1ms per call on average
#expect(averageTime < 0.0001, "Bytes property should be fast: \(averageTime)s per call")
}
@Test("description property performance")
func testDescriptionPropertyPerformance() {
let address = MACAddress(0x0123_4567_89ab)
let iterations = 10000
let startTime = Date()
for _ in 0..<iterations {
_ = address.description
}
let endTime = Date()
let totalTime = endTime.timeIntervalSince(startTime)
let averageTime = totalTime / Double(iterations)
// Should be reasonably fast - less than 1ms per call on average
#expect(averageTime < 0.001, "Description property should be fast: \(averageTime)s per call")
}
}
// MARK: - Integration Tests
@Suite("Integration")
struct IntegrationTests {
@Test(
"comprehensive round-trip test",
arguments: [
(0x0123_4567_89ab, "01:23:45:67:89:ab"),
(0x0000_0000_0000, "00:00:00:00:00:00"),
(0xffff_ffff_ffff, "ff:ff:ff:ff:ff:ff"),
]
)
func testComprehensiveRoundTrip(expectedValue: UInt64, expectedString: String) throws {
// Test UInt32 -> String
let addressFromUInt32 = MACAddress(expectedValue)
#expect(addressFromUInt32.description == expectedString)
// Test String -> UInt32
let addressFromString = try MACAddress(expectedString)
#expect(addressFromString.value == expectedValue)
// Test equality
#expect(addressFromUInt32 == addressFromString)
}
@Test(
"error message consistency",
arguments: [
"",
"hi:00:00:00:00:00",
"01:23:45:67:89",
"01:23:45:67:89:ab:cd",
"001:23:45:67:89:ab:cd",
" 01:23:45:67:89:ab:cd",
"01:23:45:67:89:ab:cd ",
]
)
func testErrorMessageConsistency(invalidInput: String) {
do {
_ = try MACAddress(invalidInput)
#expect(Bool(false), "Should have thrown for input: \(invalidInput)")
} catch let error as AddressError {
#expect(error == AddressError.unableToParse)
} catch {
#expect(Bool(false), "Should have thrown AddressError, got: \(error)")
}
}
@Test(
"Codable encodes to string representation",
arguments: [
"01:23:45:67:89:ab",
"00:00:00:00:00:00",
"ff:ff:ff:ff:ff:ff",
]
)
func testCodableEncode(address: String) throws {
let original = try MACAddress(address)
let encoded = try JSONEncoder().encode(original)
#expect(String(data: encoded, encoding: .utf8) == "\"\(address)\"")
}
@Test(
"Codable decodes from string representation",
arguments: [
"01:23:45:67:89:ab",
"00:00:00:00:00:00",
"ff:ff:ff:ff:ff:ff",
]
)
func testCodableDecode(address: String) throws {
let json = Data("\"\(address)\"".utf8)
let decoded = try JSONDecoder().decode(MACAddress.self, from: json)
let expected = try MACAddress(address)
#expect(decoded == expected)
}
}
}