chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user