return (byte[])_address.Clone();
}
- public static PhysicalAddress Parse(string address)
+ public static PhysicalAddress Parse(string address) => address != null ? Parse(address.AsSpan()) : None;
+
+ public static PhysicalAddress Parse(ReadOnlySpan<char> address)
{
- int validSegmentLength;
- char? delimiter = null;
- byte[] buffer;
+ if (!TryParse(address, out PhysicalAddress value))
+ throw new FormatException(SR.Format(SR.net_bad_mac_address, new string(address)));
+ return value;
+ }
+
+ public static bool TryParse(string address, out PhysicalAddress value)
+ {
if (address == null)
{
- return None;
+ value = None;
+ return true;
}
+ return TryParse(address, out value);
+ }
+
+ public static bool TryParse(ReadOnlySpan<char> address, out PhysicalAddress value)
+ {
+ int validSegmentLength;
+ char? delimiter = null;
+ byte[] buffer;
+ value = null;
+
if (address.Contains('-'))
{
if ((address.Length + 1) % 3 != 0)
{
- ThrowBadAddressException(address);
+ return false;
}
delimiter = '-';
else if (address.Contains(':'))
{
delimiter = ':';
- validSegmentLength = GetValidSegmentLength(address, ':');
+
+ if (!TryGetValidSegmentLength(address, ':', out validSegmentLength))
+ {
+ return false;
+ }
+
if (validSegmentLength != 2 && validSegmentLength != 4)
{
- ThrowBadAddressException(address);
+ return false;
}
buffer = new byte[6];
}
else if (address.Contains('.'))
{
delimiter = '.';
- validSegmentLength = GetValidSegmentLength(address, '.');
+
+ if (!TryGetValidSegmentLength(address, '.', out validSegmentLength))
+ {
+ return false;
+ }
+
if (validSegmentLength != 4)
{
- ThrowBadAddressException(address);
+ return false;
}
buffer = new byte[6];
}
{
if (address.Length % 2 > 0)
{
- ThrowBadAddressException(address);
+ return false;
}
validSegmentLength = address.Length;
int j = 0;
for (int i = 0; i < address.Length; i++)
{
- int value = address[i];
+ int character = address[i];
- if (value >= '0' && value <= '9')
+ if (character >= '0' && character <= '9')
{
- value -= '0';
+ character -= '0';
}
- else if (value >= 'A' && value <= 'F')
+ else if (character >= 'A' && character <= 'F')
{
- value -= ('A' - 10);
+ character -= ('A' - 10);
}
- else if (value >= 'a' && value <= 'f')
+ else if (character >= 'a' && character <= 'f')
{
- value -= ('a' - 10);
+ character -= ('a' - 10);
}
else
{
- if (delimiter == value && validCount == validSegmentLength)
+ if (delimiter == character && validCount == validSegmentLength)
{
validCount = 0;
continue;
}
- ThrowBadAddressException(address);
+ return false;
}
// we had too many characters after the last delimiter
if (validCount >= validSegmentLength)
{
- ThrowBadAddressException(address);
+ return false;
}
if (validCount % 2 == 0)
{
- buffer[j] = (byte)(value << 4);
+ buffer[j] = (byte)(character << 4);
}
else
{
- buffer[j++] |= (byte)value;
+ buffer[j++] |= (byte)character;
}
validCount++;
// we had too few characters after the last delimiter
if (validCount < validSegmentLength)
{
- ThrowBadAddressException(address);
+ return false;
}
- return new PhysicalAddress(buffer);
-
- static void ThrowBadAddressException(string address) =>
- throw new FormatException(SR.Format(SR.net_bad_mac_address, address));
+ value = new PhysicalAddress(buffer);
+ return true;
}
- private static int GetValidSegmentLength(string address, char delimiter)
+ private static bool TryGetValidSegmentLength(ReadOnlySpan<char> address, char delimiter, out int value)
{
+ value = -1;
int segments = 1;
int validSegmentLength = 0;
for (int i = 0; i < address.Length; i++)
}
else if ((i - (segments - 1)) % validSegmentLength != 0)
{
- // segments - 1 = num of delimeters. Throw if new segment isn't the validSegmentLength
- throw new FormatException(SR.Format(SR.net_bad_mac_address, address));
+ // segments - 1 = num of delimeters. Return false if new segment isn't the validSegmentLength
+ return false;
}
segments++;
if (segments * validSegmentLength != 12)
{
- throw new FormatException(SR.Format(SR.net_bad_mac_address, address));
+ return false;
}
- return validSegmentLength;
+ value = validSegmentLength;
+ return true;
}
}
}
};
}
+ public static IEnumerable<object[]> InvalidAddressStrings()
+ {
+ yield return new object[] { "F" };
+ yield return new object[] { "M0" };
+ yield return new object[] { "33-3" };
+ yield return new object[] { "D2-C3-" };
+ yield return new object[] { "D2-A33" };
+ yield return new object[] { "B4-A5-F01" };
+ yield return new object[] { "00:111:22:33:44:55" };
+ yield return new object[] { "0:1:22:33:44:55" };
+ yield return new object[] { "0:0:1:1:22:33:44:55" };
+ yield return new object[] { ":::00112233444" };
+ yield return new object[] { "0011:2233" };
+ yield return new object[] { "0011:2233:4455:6677" };
+ yield return new object[] { "0011:2233:4455:6677:8899:0011" };
+ yield return new object[] { "001:12233:4455" };
+ yield return new object[] { "0011:2233:" };
+ yield return new object[] { "0011:2233:44555" };
+ yield return new object[] { "001.12233.4455" };
+ yield return new object[] { "0011.2233." };
+ yield return new object[] { "0011.2233.44555" };
+ yield return new object[] { "00.111.22.33.44.55" };
+ yield return new object[] { "001.122.334.455" };
+ }
+
[Theory]
[MemberData(nameof(RoundtripParseToString_String_Bytes))]
- public void Parse_Valid_Success(string address, byte[] expectedBytes)
+ public void ParseString_Valid_Success(string address, byte[] expectedBytes)
{
PhysicalAddress parsedAddress = PhysicalAddress.Parse(address);
byte[] addressBytes = parsedAddress.GetAddressBytes();
- Assert.Equal(addressBytes, expectedBytes);
+ Assert.Equal(expectedBytes, addressBytes);
+ }
+
+ [Fact]
+ public void ParseString_Null_Success()
+ {
+ PhysicalAddress parsedAddress = PhysicalAddress.Parse(null);
+ Assert.Equal(PhysicalAddress.None, parsedAddress);
+ }
+
+ [Fact]
+ public void ParseString_Empty_Success()
+ {
+ PhysicalAddress parsedAddress = PhysicalAddress.Parse(string.Empty);
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Empty(addressBytes);
+ }
+
+ [Theory]
+ [MemberData(nameof(RoundtripParseToString_String_Bytes))]
+ public void TryParseString_Valid_Success(string address, byte[] expectedBytes)
+ {
+ Assert.True(PhysicalAddress.TryParse(address, out PhysicalAddress parsedAddress));
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Equal(expectedBytes, addressBytes);
+ }
+
+ [Fact]
+ public void TryParseString_Null_Success()
+ {
+ Assert.True(PhysicalAddress.TryParse(null, out PhysicalAddress parsedAddress));
+ Assert.Equal(PhysicalAddress.None, parsedAddress);
+ }
+
+ [Fact]
+ public void TryParseString_Empty_Success()
+ {
+ Assert.True(PhysicalAddress.TryParse(string.Empty, out PhysicalAddress parsedAddress));
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Empty(addressBytes);
+ }
+
+ [Theory]
+ [MemberData(nameof(RoundtripParseToString_String_Bytes))]
+ public void ParseSpan_Valid_Success(string address, byte[] expectedBytes)
+ {
+ PhysicalAddress parsedAddress = PhysicalAddress.Parse(address.AsSpan());
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Equal(expectedBytes, addressBytes);
+ }
+
+ [Fact]
+ public void ParseSpan_Empty_Success()
+ {
+ PhysicalAddress parsedAddress = PhysicalAddress.Parse(new ReadOnlySpan<char>());
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Empty(addressBytes);
}
[Theory]
- [InlineData("F")]
- [InlineData("M0")]
- [InlineData("33-3")]
- [InlineData("D2-C3-")]
- [InlineData("D2-A33")]
- [InlineData("B4-A5-F01")]
- [InlineData("00:111:22:33:44:55")]
- [InlineData("0:1:22:33:44:55")]
- [InlineData("0:0:1:1:22:33:44:55")]
- [InlineData(":::00112233444")]
- [InlineData("0011:2233")]
- [InlineData("0011:2233:4455:6677")]
- [InlineData("0011:2233:4455:6677:8899:0011")]
- [InlineData("001:12233:4455")]
- [InlineData("0011:2233:")]
- [InlineData("0011:2233:44555")]
- [InlineData("001.12233.4455")]
- [InlineData("0011.2233.")]
- [InlineData("0011.2233.44555")]
- [InlineData("00.111.22.33.44.55")]
- [InlineData("001.122.334.455")]
-
- public void Parse_Invalid_ThrowsFormatException(string address)
+ [MemberData(nameof(RoundtripParseToString_String_Bytes))]
+ public void TryParseSpan_Valid_Success(string address, byte[] expectedBytes)
+ {
+ Assert.True(PhysicalAddress.TryParse(address.AsSpan(), out PhysicalAddress parsedAddress));
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Equal(expectedBytes, addressBytes);
+ }
+
+ [Fact]
+ public void TryParseSpan_Empty_Success()
+ {
+ Assert.True(PhysicalAddress.TryParse(new ReadOnlySpan<char>(), out PhysicalAddress parsedAddress));
+ byte[] addressBytes = parsedAddress.GetAddressBytes();
+ Assert.Empty(addressBytes);
+ }
+
+ [Theory]
+ [MemberData(nameof(InvalidAddressStrings))]
+ public void ParseString_Invalid_ThrowsFormatException(string address)
{
FormatException ex = Assert.Throws<FormatException>(() => PhysicalAddress.Parse(address));
Assert.Contains(address, ex.Message);
}
+ [Theory]
+ [MemberData(nameof(InvalidAddressStrings))]
+ public void TryParseString_Invalid_ReturnsFalse(string address)
+ {
+ Assert.False(PhysicalAddress.TryParse(address, out PhysicalAddress value));
+ Assert.Null(value);
+ }
+
+ [Theory]
+ [MemberData(nameof(InvalidAddressStrings))]
+ public void ParseSpan_Invalid_ThrowsFormatException(string address)
+ {
+ FormatException ex = Assert.Throws<FormatException>(() => PhysicalAddress.Parse(address.AsSpan()));
+ Assert.Contains(address, ex.Message);
+ }
+
+ [Theory]
+ [MemberData(nameof(InvalidAddressStrings))]
+ public void TryParseSpan_Invalid_ReturnsFalse(string address)
+ {
+ Assert.False(PhysicalAddress.TryParse(address.AsSpan(), out PhysicalAddress value));
+ Assert.Null(value);
+ }
+
[Fact]
public void ToString_NullAddress_NullReferenceException()
{