mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-11 19:44:55 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0de417b665 | ||
|
|
da57fcb988 | ||
|
|
c6b6711eb2 | ||
|
|
138a6f3470 | ||
|
|
e84bc721ee | ||
|
|
2988912d44 | ||
|
|
be94503e6a | ||
|
|
6877b5c800 | ||
|
|
569066edc4 | ||
|
|
73a716f9b9 | ||
|
|
4e430731cc | ||
|
|
2b8f2a125a | ||
|
|
cc25c41805 | ||
|
|
2487a70891 | ||
|
|
5c5a25775b | ||
|
|
27f6267f54 | ||
|
|
430eac8cb6 | ||
|
|
b47e305d9f | ||
|
|
0c8f8242e8 | ||
|
|
a52e77c1e7 | ||
|
|
2aa05f3ee8 | ||
|
|
2700f5018a | ||
|
|
b09b22266b | ||
|
|
1c206c5539 | ||
|
|
56a48175c6 | ||
|
|
0acd0ae5d4 | ||
|
|
d2856c1983 | ||
|
|
fa65a9de65 | ||
|
|
e4b292f145 | ||
|
|
11a5533fcd | ||
|
|
e0d0763306 | ||
|
|
7d42158bc7 | ||
|
|
92a28813e0 | ||
|
|
3b313a442c | ||
|
|
16fb3683dd | ||
|
|
bb9bcf6cdf |
38
CHANGELOG.md
38
CHANGELOG.md
@@ -6,6 +6,44 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [17.2.0] - 2023-06-18
|
||||
### Added
|
||||
- Added BigEndianBitConverter
|
||||
- Added EnumUtils.GetInverseFlags
|
||||
- Added ReverseLookupDictionary collection
|
||||
- Added NotifyFlagsChanged type
|
||||
|
||||
### Changed
|
||||
- SafeMutex now implements IDisposable
|
||||
|
||||
## [17.1.0] - 2023-03-22
|
||||
### Changed
|
||||
- Improved methods for human formatted timespan, including without milliseconds.
|
||||
- Removed Obfuscation
|
||||
|
||||
## [17.0.0] 2022-12-02
|
||||
### Changed
|
||||
- IcdEnvironment - Added CrestronDevicePlatform, removed from CrestronRuntimeEnvironment, to support SimplWindows on VC-4
|
||||
- Fixed IcdEnvironment CrestronRuntimeEnvironment uses in IcdConsole, PathUtils, and ProgramUtils
|
||||
- Fixed preprocessors in IcdDirectory
|
||||
- Added exception handling to ThreadedWorkerQueue
|
||||
|
||||
## [16.0.5] 2022-07-11
|
||||
### Changed
|
||||
- Fixed console command responses in Simpl+ Runtime Environment
|
||||
- Changed Crestron apps to not report as an interactive console
|
||||
- Fixed NETSTANDARD vs SIMPLSHARP preprocessors in various files
|
||||
- Fixed package reference conditions for NetStandard pakcages
|
||||
|
||||
## [16.0.4] 2022-07-01
|
||||
### Changed
|
||||
- Fixed PreProcessors for NETSTANDARD vs SIMPLSHARP for 4-series builds
|
||||
- Updated Crestron SDK to 2.18.96
|
||||
|
||||
## [16.0.3] 2022-06-23
|
||||
### Changed
|
||||
- Throwing better exception when trying to get unknown timezones
|
||||
|
||||
## [16.0.2] 2022-05-23
|
||||
### Changed
|
||||
- Fixed an issue in IcdUriBuilder where relative pathes were not being built into a valid URI.
|
||||
|
||||
332
ICD.Common.Utils.Tests/BigEndianBitConverterTest.cs
Normal file
332
ICD.Common.Utils.Tests/BigEndianBitConverterTest.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
// ReSharper disable AssignNullToNotNullAttribute
|
||||
|
||||
namespace ICD.Common.Utils.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class BigEndianBitConverterTest
|
||||
{
|
||||
[TestCase(ushort.MaxValue, new byte[] { 0xFF, 0xFF }, 0)]
|
||||
[TestCase(ushort.MinValue, new byte[] { 0x00, 0x00 }, 0)]
|
||||
[TestCase((ushort)255, new byte[] { 0x00, 0xFF }, 0)]
|
||||
[TestCase((ushort)65280, new byte[] { 0xFF, 0x00 }, 0)]
|
||||
[TestCase(ushort.MaxValue, new byte[] { 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 }, 2)]
|
||||
[TestCase(ushort.MinValue, new byte[] { 0xFF, 0x00, 0x00, 0xFF, 0xFF }, 1)]
|
||||
[TestCase((ushort)255, new byte[] { 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00 }, 3)]
|
||||
[TestCase((ushort)65280, new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF }, 4)]
|
||||
[TestCase((ushort)240, new byte[] { 0x00, 0xFF, 0x00, 0xF0, 0xFF }, 2)]
|
||||
[TestCase((ushort)15, new byte[] { 0x00, 0x0F }, 0)]
|
||||
public void ToUshortTest(ushort expectedResult, byte[] value, int startIndex)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
|
||||
Assert.AreEqual(expectedResult, BigEndianBitConverter.ToUshort(value, startIndex));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToUshortExceptionTest()
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F };
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => BigEndianBitConverter.ToUshort(null, 0));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToUshort(values, -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToUshort(values, 9));
|
||||
Assert.Throws<ArgumentException>(() => BigEndianBitConverter.ToUshort(values, 8));
|
||||
}
|
||||
|
||||
[TestCase(short.MaxValue, new byte[] { 0x7F, 0xFF }, 0)]
|
||||
[TestCase(short.MinValue, new byte[] { 0x80, 0x00 }, 0)]
|
||||
[TestCase(0, new byte[] { 0x00, 0x00 }, 0)]
|
||||
[TestCase(-1, new byte[] { 0xFF, 0xFF }, 0)]
|
||||
[TestCase((short)255, new byte[] { 0x00, 0xFF }, 0)]
|
||||
[TestCase((short)-256, new byte[] { 0xFF, 0x00 }, 0)]
|
||||
[TestCase(short.MaxValue, new byte[] { 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00 }, 2)]
|
||||
[TestCase(short.MinValue, new byte[] { 0xFF, 0x80, 0x00, 0xFF, 0xFF }, 1)]
|
||||
[TestCase((short)255, new byte[] { 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00 }, 3)]
|
||||
[TestCase((short)-256, new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF }, 4)]
|
||||
[TestCase((short)240, new byte[] { 0x00, 0xFF, 0x00, 0xF0, 0xFF }, 2)]
|
||||
[TestCase((short)15, new byte[] { 0x00, 0x0F }, 0)]
|
||||
public void ToShortTest(short expectedResult, byte[] value, int startIndex)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
|
||||
Assert.AreEqual(expectedResult, BigEndianBitConverter.ToShort(value, startIndex));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToShortExceptionTest()
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F };
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => BigEndianBitConverter.ToShort(null, 0));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToShort(values, -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToShort(values, 9));
|
||||
Assert.Throws<ArgumentException>(() => BigEndianBitConverter.ToShort(values, 8));
|
||||
}
|
||||
|
||||
[TestCase(uint.MaxValue, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0)]
|
||||
[TestCase(uint.MinValue, new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase((uint)255, new byte[] { 0x00, 0x00, 0x00, 0xFF }, 0)]
|
||||
[TestCase(4278190080, new byte[] { 0xFF, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(uint.MaxValue, new byte[] { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 }, 2)]
|
||||
[TestCase(uint.MinValue, new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 1)]
|
||||
[TestCase((uint)255, new byte[] { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 }, 3)]
|
||||
[TestCase(4278190080, new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 4)]
|
||||
[TestCase((uint)15728895, new byte[] { 0x00, 0xFF, 0x00, 0xF0, 0x00, 0xFF, 0xFF }, 2)]
|
||||
[TestCase((uint)1044735, new byte[] { 0x00, 0x0F, 0xF0, 0xFF }, 0)]
|
||||
public void ToUintTest(uint expectedResult, byte[] value, int startIndex)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
|
||||
Assert.AreEqual(expectedResult, BigEndianBitConverter.ToUint(value, startIndex));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToUintExceptionTest()
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F };
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => BigEndianBitConverter.ToUint(null, 0));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToUint(values, -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToUint(values, 9));
|
||||
Assert.Throws<ArgumentException>(() => BigEndianBitConverter.ToUint(values, 6));
|
||||
}
|
||||
|
||||
[TestCase(int.MaxValue, new byte[] { 0x7F, 0xFF, 0xFF, 0xFF }, 0)]
|
||||
[TestCase(int.MinValue, new byte[] { 0x80, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(0, new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(255, new byte[] { 0x00, 0x00, 0x00, 0xFF }, 0)]
|
||||
[TestCase(-1, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0)]
|
||||
[TestCase(-16777216, new byte[] { 0xFF, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(int.MaxValue, new byte[] { 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00 }, 2)]
|
||||
[TestCase(int.MinValue, new byte[] { 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 1)]
|
||||
[TestCase(255, new byte[] { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 }, 3)]
|
||||
[TestCase(-16777216, new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 4)]
|
||||
[TestCase(15728895, new byte[] { 0x00, 0xFF, 0x00, 0xF0, 0x00, 0xFF, 0xFF }, 2)]
|
||||
[TestCase(1044735, new byte[] { 0x00, 0x0F, 0xF0, 0xFF }, 0)]
|
||||
public void ToIntTest(int expectedResult, byte[] value, int startIndex)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
|
||||
Assert.AreEqual(expectedResult, BigEndianBitConverter.ToInt(value, startIndex));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToIntExceptionTest()
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F };
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => BigEndianBitConverter.ToInt(null, 0));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToInt(values, -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToInt(values, 9));
|
||||
Assert.Throws<ArgumentException>(() => BigEndianBitConverter.ToInt(values, 6));
|
||||
}
|
||||
|
||||
[TestCase(ulong.MaxValue, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 0)]
|
||||
[TestCase(ulong.MinValue, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase((ulong)255, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, 0)]
|
||||
[TestCase(18374686479671623680, new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(ulong.MaxValue, new byte[] { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 },
|
||||
2)]
|
||||
[TestCase(ulong.MinValue, new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 1)]
|
||||
[TestCase((ulong)255,
|
||||
new byte[] { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 }, 3)]
|
||||
[TestCase(18374686479671623680,
|
||||
new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 4)]
|
||||
[TestCase((ulong)67555089642946815,
|
||||
new byte[] { 0x00, 0xFF, 0x00, 0xF0, 0x00, 0xFF, 0x00, 0xF0, 0x00, 0xFF, 0xFF }, 2)]
|
||||
[TestCase((ulong)4487102673719295, new byte[] { 0x00, 0x0F, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0xFF }, 0)]
|
||||
public void ToUlongTest(ulong expectedResult, byte[] value, int startIndex)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
|
||||
Assert.AreEqual(expectedResult, BigEndianBitConverter.ToUlong(value, startIndex));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToUlongExceptionTest()
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F };
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => BigEndianBitConverter.ToUlong(null, 0));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToUlong(values, -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToUlong(values, 9));
|
||||
Assert.Throws<ArgumentException>(() => BigEndianBitConverter.ToUlong(values, 2));
|
||||
}
|
||||
|
||||
[TestCase(long.MaxValue, new byte[] { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 0)]
|
||||
[TestCase(long.MinValue, new byte[] { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(255, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, 0)]
|
||||
[TestCase(-1, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 0)]
|
||||
[TestCase(-72057594037927936, new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(long.MaxValue, new byte[] { 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 },
|
||||
2)]
|
||||
[TestCase(long.MinValue, new byte[] { 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 1)]
|
||||
[TestCase(255,
|
||||
new byte[] { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 }, 3)]
|
||||
[TestCase(-72057594037927936,
|
||||
new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }, 4)]
|
||||
[TestCase(67555093906456320, new byte[] { 0x00, 0xFF, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0x0F, 0xFF, 0x00, 0xF0 },
|
||||
2)]
|
||||
[TestCase(4487102659035120, new byte[] { 0x00, 0x0F, 0xF0, 0xFF, 0x00, 0x0F, 0xFF, 0xF0 }, 0)]
|
||||
public void ToLongTest(long expectedResult, byte[] value, int startIndex)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
|
||||
Assert.AreEqual(expectedResult, BigEndianBitConverter.ToLong(value, startIndex));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToLongExceptionTest()
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F };
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => BigEndianBitConverter.ToLong(null, 0));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToLong(values, -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BigEndianBitConverter.ToLong(values, 9));
|
||||
Assert.Throws<ArgumentException>(() => BigEndianBitConverter.ToLong(values, 2));
|
||||
}
|
||||
|
||||
[TestCase(new byte[] { 0x7F, 0xFF, 0xFF, 0xFF }, int.MaxValue)]
|
||||
[TestCase(new byte[] { 0x80, 0x00, 0x00, 0x00 }, int.MinValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0xFF }, 255)]
|
||||
[TestCase(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, -1)]
|
||||
[TestCase(new byte[] { 0xFF, 0x00, 0x00, 0x00 }, -16777216)]
|
||||
[TestCase(new byte[] { 0x00, 0xF0, 0x00, 0xFF }, 15728895)]
|
||||
[TestCase(new byte[] { 0x00, 0x0F, 0xF0, 0xFF }, 1044735)]
|
||||
public void GetBytesIntTest(byte[] expectedResult, int value)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
CollectionAssert.AreEqual(expectedResult, BigEndianBitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
[TestCase(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, uint.MaxValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0x00 }, uint.MinValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0xFF }, (uint)255)]
|
||||
[TestCase(new byte[] { 0xFF, 0x00, 0x00, 0x00 }, 4278190080)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0xFF }, (uint)255)]
|
||||
[TestCase(new byte[] { 0x00, 0xF0, 0x00, 0xFF }, (uint)15728895)]
|
||||
[TestCase(new byte[] { 0x00, 0x0F, 0xF0, 0xFF }, (uint)1044735)]
|
||||
public void GetBytesUintTest(byte[] expectedResult, uint value)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
CollectionAssert.AreEqual(expectedResult, BigEndianBitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
[TestCase(new byte[] { 0x7F, 0xFF }, short.MaxValue)]
|
||||
[TestCase(new byte[] { 0x80, 0x00 }, short.MinValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00 }, (short)0)]
|
||||
[TestCase(new byte[] { 0xFF, 0xFF }, (short)-1)]
|
||||
[TestCase(new byte[] { 0x00, 0xFF }, (short)255)]
|
||||
[TestCase(new byte[] { 0xFF, 0x00 }, (short)-256)]
|
||||
[TestCase(new byte[] { 0x00, 0xF0 }, (short)240)]
|
||||
[TestCase(new byte[] { 0x00, 0x0F }, (short)15)]
|
||||
public void GetBytesShortTest(byte[] expectedResult, short value)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
CollectionAssert.AreEqual(expectedResult, BigEndianBitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
[TestCase(new byte[] { 0xFF, 0xFF }, ushort.MaxValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00 }, ushort.MinValue)]
|
||||
[TestCase(new byte[] { 0x00, 0xFF }, (ushort)255)]
|
||||
[TestCase(new byte[] { 0xFF, 0x00 }, (ushort)65280)]
|
||||
[TestCase(new byte[] { 0x00, 0xF0 }, (ushort)240)]
|
||||
[TestCase(new byte[] { 0x00, 0x0F }, (ushort)15)]
|
||||
public void GetBytesUshortTest(byte[] expectedResult, ushort value)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
CollectionAssert.AreEqual(expectedResult, BigEndianBitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
[TestCase(new byte[] { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, long.MaxValue)]
|
||||
[TestCase(new byte[] { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },long.MinValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, (long)0)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, (long)255)]
|
||||
[TestCase(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, (long)-1)]
|
||||
[TestCase(new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, -72057594037927936)]
|
||||
[TestCase(new byte[] { 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0x0F, 0xFF, 0x00 }, 67555093906456320)]
|
||||
[TestCase(new byte[] { 0x00, 0x0F, 0xF0, 0xFF, 0x00, 0x0F, 0xFF, 0xF0 }, 4487102659035120)]
|
||||
public void GetBytesLongTest(byte[] expectedResult, long value)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
CollectionAssert.AreEqual(expectedResult, BigEndianBitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
[TestCase(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ulong.MaxValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ulong.MinValue)]
|
||||
[TestCase(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, (ulong)255)]
|
||||
[TestCase(new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 18374686479671623680)]
|
||||
[TestCase(new byte[] { 0x00, 0xF0, 0x00, 0xFF, 0x00, 0xF0, 0x00, 0xFF }, (ulong)67555089642946815)]
|
||||
[TestCase(new byte[] { 0x00, 0x0F, 0xF0, 0xFF, 0x00, 0xF0, 0x0F, 0xFF }, (ulong)4487102673719295)]
|
||||
public void GetBytesUlongTest(byte[] expectedResult, ulong value)
|
||||
{
|
||||
// We use system BitConverter for systems that are already big-endian
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Assert.Inconclusive();
|
||||
|
||||
CollectionAssert.AreEqual(expectedResult, BigEndianBitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Collections
|
||||
{
|
||||
[TestFixture]
|
||||
public class ReverseLookupDictionaryTest
|
||||
{
|
||||
|
||||
//todo: Finish!
|
||||
#region Properties
|
||||
|
||||
[Test]
|
||||
public void CountTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(2, "10");
|
||||
dict.Set(3, "30");
|
||||
|
||||
Assert.AreEqual(2, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void KeysTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(2, "10");
|
||||
dict.Set(3, "30");
|
||||
|
||||
Assert.AreEqual(2, dict.Keys.Count);
|
||||
|
||||
Assert.IsTrue(dict.Keys.Contains(2));
|
||||
Assert.IsTrue(dict.Keys.Contains(3));
|
||||
Assert.IsFalse(dict.Keys.Contains(4));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ValuesTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(1, "20");
|
||||
dict.Set(3, "30");
|
||||
|
||||
Assert.AreEqual(2, dict.Values.Count);
|
||||
|
||||
Assert.IsTrue(dict.Values.Contains("20"));
|
||||
Assert.IsTrue(dict.Values.Contains("30"));
|
||||
Assert.IsFalse(dict.Values.Contains("40"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
[Test]
|
||||
public void ClearTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(1, "20");
|
||||
dict.Set(3, "30");
|
||||
|
||||
Assert.AreEqual(2, dict.Count);
|
||||
|
||||
dict.Clear();
|
||||
|
||||
Assert.AreEqual(0, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContainsKeyTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
Assert.IsFalse(dict.ContainsKey(1));
|
||||
|
||||
dict.Set(1, "10");
|
||||
|
||||
Assert.IsTrue(dict.ContainsKey(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContainsValueTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
Assert.IsFalse(dict.ContainsValue("10"));
|
||||
|
||||
dict.Set(1, "10");
|
||||
|
||||
Assert.IsTrue(dict.ContainsValue("10"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Add(1, "10");
|
||||
|
||||
Assert.AreEqual(1, dict.Count);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => dict.Add(1, "10"));
|
||||
Assert.Throws<ArgumentException>(() => dict.Add(1, "20"));
|
||||
|
||||
Assert.DoesNotThrow(() => dict.Add(2, "10"));
|
||||
Assert.DoesNotThrow(() => dict.Add(3, "20"));
|
||||
|
||||
Assert.AreEqual(3, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(1, "20");
|
||||
dict.Set(3, "30");
|
||||
dict.Set(4, "20");
|
||||
|
||||
Assert.AreEqual("20", dict.GetValue(1));
|
||||
Assert.AreEqual("30", dict.GetValue(3));
|
||||
Assert.AreEqual("40", dict.GetValue(4));
|
||||
|
||||
CollectionAssert.AreEquivalent(new[]{1,4}, dict.GetKeys("20"));
|
||||
CollectionAssert.AreEquivalent(new[]{3}, dict.GetKeys("30"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetKeysTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(1, "Odd");
|
||||
dict.Add(2, "Even");
|
||||
dict.Set(3, "Odd");
|
||||
dict.Add(4, "Value");
|
||||
dict.Set(4, "Even");
|
||||
dict.Add(5, "Odd");
|
||||
dict.Add(6, "Even");
|
||||
|
||||
CollectionAssert.AreEquivalent(new[]{1,3,5}, dict.GetKeys("Odd"));
|
||||
CollectionAssert.AreEquivalent(new[]{2,4,6}, dict.GetKeys("Even"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValueTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Set(1, "10");
|
||||
dict.Set(1, "20");
|
||||
dict.Set(3, "30");
|
||||
dict.Set(2, "20");
|
||||
|
||||
Assert.AreEqual("20", dict.GetValue(1));
|
||||
Assert.AreEqual("30", dict.GetValue(3));
|
||||
Assert.AreEqual("20", dict.GetValue(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveKeyTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Add(1, "10");
|
||||
|
||||
Assert.AreEqual(1, dict.Count);
|
||||
|
||||
dict.RemoveKey(1);
|
||||
|
||||
Assert.AreEqual(0, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveValueSingleTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Add(1, "10");
|
||||
|
||||
Assert.AreEqual(1, dict.Count);
|
||||
|
||||
dict.RemoveValue("10");
|
||||
|
||||
Assert.AreEqual(0, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveValueMultipleTest1()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Add(1, "10");
|
||||
dict.Add(2, "10");
|
||||
dict.Add(3, "10");
|
||||
|
||||
Assert.AreEqual(3, dict.Count);
|
||||
|
||||
dict.RemoveValue("10");
|
||||
|
||||
Assert.AreEqual(0, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveValueWithOthersTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
dict.Add(1, "10");
|
||||
dict.Add(2, "10");
|
||||
dict.Add(3, "10");
|
||||
dict.Add(4, "20");
|
||||
dict.Add(5, "20");
|
||||
dict.Add(6, "some other string");
|
||||
|
||||
Assert.AreEqual(6, dict.Count);
|
||||
|
||||
dict.RemoveValue("10");
|
||||
|
||||
Assert.AreEqual(3, dict.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetValueTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
string value;
|
||||
Assert.IsFalse(dict.TryGetValue(1, out value));
|
||||
// ReSharper disable once ExpressionIsAlwaysNull
|
||||
Assert.AreEqual(null, value);
|
||||
|
||||
dict.Add(1, "10");
|
||||
|
||||
Assert.IsTrue(dict.TryGetValue(1, out value));
|
||||
Assert.AreEqual("10", value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetKeysMultipleTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
IEnumerable<int> value;
|
||||
Assert.IsFalse(dict.TryGetKeys("10", out value));
|
||||
|
||||
dict.Add(1, "10");
|
||||
dict.Add(11, "100");
|
||||
|
||||
Assert.IsTrue(dict.TryGetKeys("10", out value));
|
||||
CollectionAssert.AreEquivalent(new[]{1}, value);
|
||||
Assert.IsTrue(dict.TryGetKeys("100", out value));
|
||||
CollectionAssert.AreEquivalent(new[]{11}, value);
|
||||
|
||||
|
||||
dict.Add(2, "10");
|
||||
dict.Add(3, "10");
|
||||
dict.Add(12, "100");
|
||||
dict.Add(13, "100");
|
||||
|
||||
Assert.IsTrue(dict.TryGetKeys("10", out value));
|
||||
CollectionAssert.AreEquivalent(new[]{1,2,3}, value);
|
||||
|
||||
Assert.IsTrue(dict.TryGetKeys("100", out value));
|
||||
CollectionAssert.AreEquivalent(new[]{11,12,13}, value);
|
||||
|
||||
Assert.IsFalse(dict.TryGetKeys("string", out value));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetKeysSingleTest()
|
||||
{
|
||||
ReverseLookupDictionary<int, string> dict = new ReverseLookupDictionary<int, string>();
|
||||
|
||||
IEnumerable<int> value;
|
||||
Assert.IsFalse(dict.TryGetKeys("10", out value));
|
||||
|
||||
dict.Add(1, "10");
|
||||
|
||||
Assert.IsTrue(dict.TryGetKeys("10", out value));
|
||||
CollectionAssert.AreEquivalent(new[]{1}, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,16 @@ namespace ICD.Common.Utils.Tests
|
||||
value);
|
||||
}
|
||||
|
||||
[TestCase(eTestFlagsEnum.A, eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D)]
|
||||
[TestCase(eTestFlagsEnum.BandC, eTestFlagsEnum.A | eTestFlagsEnum.D)]
|
||||
[TestCase(eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D, eTestFlagsEnum.None)]
|
||||
[TestCase(eTestFlagsEnum.None, eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D)]
|
||||
[TestCase(eTestFlagsEnum.D, eTestFlagsEnum.A | eTestFlagsEnum.BandC)]
|
||||
public void GetInverseFlagsTest(eTestFlagsEnum expected, eTestFlagsEnum value)
|
||||
{
|
||||
Assert.AreEqual(expected, EnumUtils.GetInverseFlags(value));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasFlagGenericTest()
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="Newtonsoft.Json" Version="13.0.1" Aliases="RealNewtonsoft"/>
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="Newtonsoft.Json" Version="13.0.1" Aliases="RealNewtonsoft" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
|
||||
131
ICD.Common.Utils.Tests/Types/GenericNotifyFlagsChangedTest.cs
Normal file
131
ICD.Common.Utils.Tests/Types/GenericNotifyFlagsChangedTest.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Types
|
||||
{
|
||||
[TestFixture]
|
||||
public class GenericNotifyFlagsChangedTest
|
||||
{
|
||||
[Flags]
|
||||
private enum eTestFlagsEnum
|
||||
{
|
||||
None = 0,
|
||||
A = 1,
|
||||
B = 2,
|
||||
C = 4,
|
||||
D = 32,
|
||||
BandC = B | C
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleFlags()
|
||||
{
|
||||
List<GenericEventArgs<eTestFlagsEnum>> addedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
List<GenericEventArgs<eTestFlagsEnum>> removedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
|
||||
GenericNotifyFlagsChanged<eTestFlagsEnum> genericNotify = new GenericNotifyFlagsChanged<eTestFlagsEnum>();
|
||||
|
||||
genericNotify.OnFlagsSet += (sender, args) => addedFlags.Add(args);
|
||||
genericNotify.OnFlagsUnset += (sender, args) => removedFlags.Add(args);
|
||||
|
||||
// Initial State
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add No flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add Flag
|
||||
genericNotify.Data = eTestFlagsEnum.B;
|
||||
Assert.AreEqual(1, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B, addedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B, genericNotify.Data);
|
||||
|
||||
// Add Another Flag
|
||||
genericNotify.Data |= eTestFlagsEnum.C;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, addedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.C, genericNotify.Data);
|
||||
|
||||
// Remove a Flag
|
||||
genericNotify.Data = genericNotify.Data & ~ eTestFlagsEnum.B;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B, removedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, genericNotify.Data);
|
||||
|
||||
// Add Already Existing Flags
|
||||
genericNotify.Data |= eTestFlagsEnum.C;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
|
||||
// Clear Flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(2, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, removedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.None, genericNotify.Data);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleFlags()
|
||||
{
|
||||
List<GenericEventArgs<eTestFlagsEnum>> addedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
List<GenericEventArgs<eTestFlagsEnum>> removedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
|
||||
GenericNotifyFlagsChanged<eTestFlagsEnum> genericNotify = new GenericNotifyFlagsChanged<eTestFlagsEnum>();
|
||||
|
||||
genericNotify.OnFlagsSet += (sender, args) => addedFlags.Add(args);
|
||||
genericNotify.OnFlagsUnset += (sender, args) => removedFlags.Add(args);
|
||||
|
||||
// Initial State
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add No flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add Flag
|
||||
genericNotify.Data = eTestFlagsEnum.B | eTestFlagsEnum.D;
|
||||
Assert.AreEqual(1, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.D, addedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.D, genericNotify.Data);
|
||||
|
||||
// Add Another Flag
|
||||
genericNotify.Data |= eTestFlagsEnum.C;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, addedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D, genericNotify.Data);
|
||||
|
||||
// Remove a Flag
|
||||
genericNotify.Data = eTestFlagsEnum.D;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.C, removedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.D, genericNotify.Data);
|
||||
|
||||
// Add Already Existing Flags
|
||||
genericNotify.Data |= eTestFlagsEnum.D;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
|
||||
// Clear Flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(2, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.D, removedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.None, genericNotify.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
public static IDictionary<string, string> PuttyColors { get { return s_PuttyColors; } }
|
||||
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
/// <summary>
|
||||
/// Enables ANSI color in the console.
|
||||
/// </summary>
|
||||
|
||||
153
ICD.Common.Utils/BigEndianBitConverter.cs
Normal file
153
ICD.Common.Utils/BigEndianBitConverter.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
public static class BigEndianBitConverter
|
||||
{
|
||||
private const byte FULL_BYTE = 0xFF;
|
||||
|
||||
public static ushort ToUshort([NotNull] byte[] value, int startIndex)
|
||||
{
|
||||
return unchecked((ushort)ToShort(value, startIndex));
|
||||
}
|
||||
|
||||
public static short ToShort([NotNull] byte[] value, int startIndex)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return BitConverter.ToInt16(value, startIndex);
|
||||
|
||||
const int bytes = sizeof(short);
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
if (startIndex < 0 || startIndex >= value.Length)
|
||||
throw new ArgumentOutOfRangeException("startIndex");
|
||||
if (startIndex > value.Length - bytes)
|
||||
throw new ArgumentException("Array plus start index too small");
|
||||
|
||||
short result = 0;
|
||||
for (int i = 0; i < bytes; i++)
|
||||
result |= (short)(value[i + startIndex] << GetBitShift(i, bytes));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static uint ToUint([NotNull] byte[] value, int startIndex)
|
||||
{
|
||||
return unchecked((uint)ToInt(value, startIndex));
|
||||
}
|
||||
|
||||
public static int ToInt([NotNull] byte[] value, int startIndex)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return BitConverter.ToInt32(value, startIndex);
|
||||
|
||||
const int bytes = sizeof(int);
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
if (startIndex < 0 || startIndex >= value.Length)
|
||||
throw new ArgumentOutOfRangeException("startIndex");
|
||||
if (startIndex > value.Length - bytes)
|
||||
throw new ArgumentException("Array plus start index too small");
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < bytes; i++)
|
||||
result |= value[i + startIndex] << GetBitShift(i, bytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ulong ToUlong([NotNull] byte[] value, int startIndex)
|
||||
{
|
||||
return unchecked((ulong)ToLong(value, startIndex));
|
||||
}
|
||||
|
||||
public static long ToLong([NotNull] byte[] value, int startIndex)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return BitConverter.ToInt64(value, startIndex);
|
||||
|
||||
const int bytes = sizeof(long);
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
if (startIndex < 0 || startIndex >= value.Length)
|
||||
throw new ArgumentOutOfRangeException("startIndex");
|
||||
if (startIndex > value.Length - bytes)
|
||||
throw new ArgumentException("Array plus start index too small");
|
||||
|
||||
long result = 0;
|
||||
for (int i = 0; i < bytes; i++)
|
||||
result |= (long)(value[i + startIndex]) << GetBitShift(i, bytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(int value)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return BitConverter.GetBytes(value);
|
||||
|
||||
const int total_bytes = sizeof(int);
|
||||
|
||||
byte[] response = new byte[total_bytes];
|
||||
|
||||
for (int i = 0; i < total_bytes; i++)
|
||||
response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE);
|
||||
|
||||
return response;
|
||||
}
|
||||
public static byte[] GetBytes(uint value)
|
||||
{
|
||||
return unchecked(GetBytes((int)value));
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(short value)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return BitConverter.GetBytes(value);
|
||||
|
||||
const int total_bytes = sizeof(short);
|
||||
|
||||
byte[] response = new byte[total_bytes];
|
||||
|
||||
for (int i = 0; i < total_bytes; i++)
|
||||
response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(ushort value)
|
||||
{
|
||||
return unchecked(GetBytes((short)value));
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(long value)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return BitConverter.GetBytes(value);
|
||||
|
||||
const int total_bytes = sizeof(long);
|
||||
|
||||
byte[] response = new byte[total_bytes];
|
||||
|
||||
for (int i = 0; i < total_bytes; i++)
|
||||
response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(ulong value)
|
||||
{
|
||||
return unchecked(GetBytes((long)value));
|
||||
}
|
||||
private static int GetBitShift(int byteNumber, int totalBytes)
|
||||
{
|
||||
return ((totalBytes - 1 - byteNumber) * 8);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
299
ICD.Common.Utils/Collections/ReverseLookupDictionary.cs
Normal file
299
ICD.Common.Utils/Collections/ReverseLookupDictionary.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if !SIMPLSHARP
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
#if !SIMPLSHARP
|
||||
[DebuggerDisplay("Count = {Count}")]
|
||||
#endif
|
||||
public class ReverseLookupDictionary<TKey, TValue> : IDictionary<TKey, TValue>
|
||||
{
|
||||
private readonly Dictionary<TKey, TValue> m_KeyToValue;
|
||||
private readonly Dictionary<TValue, IcdHashSet<TKey>> m_ValueToKeys;
|
||||
|
||||
#region Properties
|
||||
|
||||
public int Count { get { return m_KeyToValue.Count; } }
|
||||
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
|
||||
[NotNull]
|
||||
public ICollection<TKey> Keys { get { return m_KeyToValue.Keys; } }
|
||||
|
||||
[NotNull]
|
||||
public ICollection<TValue> Values { get { return m_ValueToKeys.Keys; } }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public ReverseLookupDictionary() :
|
||||
this(EqualityComparer<TKey>.Default, EqualityComparer<TValue>.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="keyComparer"></param>
|
||||
/// <param name="valueComparer"></param>
|
||||
public ReverseLookupDictionary(IEqualityComparer<TKey> keyComparer, IEqualityComparer<TValue> valueComparer)
|
||||
{
|
||||
m_KeyToValue = new Dictionary<TKey, TValue>(keyComparer);
|
||||
m_ValueToKeys = new Dictionary<TValue, IcdHashSet<TKey>>(valueComparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="dict"></param>
|
||||
/// <param name="keyComparer"></param>
|
||||
/// <param name="valueComparer"></param>
|
||||
public ReverseLookupDictionary([NotNull] Dictionary<TKey, TValue> dict, IEqualityComparer<TKey> keyComparer, IEqualityComparer<TValue> valueComparer)
|
||||
: this(keyComparer, valueComparer)
|
||||
{
|
||||
if (dict == null)
|
||||
throw new ArgumentNullException("dict");
|
||||
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in dict)
|
||||
Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="dict"></param>
|
||||
public ReverseLookupDictionary([NotNull] Dictionary<TKey, TValue> dict)
|
||||
: this(dict, EqualityComparer<TKey>.Default, EqualityComparer<TValue>.Default)
|
||||
{
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_KeyToValue.Clear();
|
||||
m_ValueToKeys.Clear();
|
||||
}
|
||||
|
||||
public bool ContainsKey([NotNull] TKey key)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
return m_KeyToValue.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool ContainsValue([NotNull] TValue value)
|
||||
{
|
||||
return m_ValueToKeys.ContainsKey(value);
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<TValue, IEnumerable<TKey>>> GetReverseDictionary()
|
||||
{
|
||||
// Cast stuff a layer deep cause weird
|
||||
return m_ValueToKeys.Select(kvp => new KeyValuePair<TValue, IEnumerable<TKey>>(kvp.Key, kvp.Value.ToArray(kvp.Value.Count)));
|
||||
}
|
||||
|
||||
public void Add([NotNull] TKey key, [NotNull] TValue value)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (ContainsKey(key))
|
||||
throw new ArgumentException("Key is already present in the collection", "key");
|
||||
|
||||
|
||||
m_KeyToValue.Add(key, value);
|
||||
m_ValueToKeys.GetOrAddNew(value, () => new IcdHashSet<TKey>()).Add(key);
|
||||
}
|
||||
|
||||
public void Set([NotNull] TKey key, [NotNull] TValue value)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
RemoveKey(key);
|
||||
|
||||
Add(key, value);
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
public IEnumerable<TKey> GetKeys([NotNull] TValue value)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
return m_ValueToKeys[value];
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
public TValue GetValue([NotNull] TKey key)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
return m_KeyToValue[key];
|
||||
}
|
||||
|
||||
public bool RemoveKey([NotNull] TKey key)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
if (!ContainsKey(key))
|
||||
return false;
|
||||
|
||||
TValue value = m_KeyToValue[key];
|
||||
|
||||
m_KeyToValue.Remove(key);
|
||||
|
||||
IcdHashSet<TKey> keys = m_ValueToKeys[value];
|
||||
keys.Remove(key);
|
||||
|
||||
if (keys.Count == 0)
|
||||
m_ValueToKeys.Remove(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the value from the collection, and any keys that were using it
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns>true if items were removed, false if not</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public bool RemoveValue([NotNull] TValue value)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (!ContainsValue(value))
|
||||
return false;
|
||||
|
||||
IcdHashSet<TKey> keys = m_ValueToKeys[value];
|
||||
|
||||
m_ValueToKeys.Remove(value);
|
||||
|
||||
foreach (TKey key in keys)
|
||||
{
|
||||
m_KeyToValue.Remove(key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetValue([NotNull] TKey key, out TValue value)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
return m_KeyToValue.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool TryGetKeys([NotNull] TValue value, out IEnumerable<TKey> keys)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
IcdHashSet<TKey> keysInternal;
|
||||
if (m_ValueToKeys.TryGetValue(value, out keysInternal))
|
||||
{
|
||||
keys = keysInternal;
|
||||
return true;
|
||||
}
|
||||
keys = Enumerable.Empty<TKey>();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDictionary
|
||||
|
||||
[NotNull]
|
||||
TValue IDictionary<TKey, TValue>.this[[NotNull] TKey key] { get { return GetValue(key); } set { Set(key, value); } }
|
||||
|
||||
bool IDictionary<TKey, TValue>.Remove([NotNull] TKey key)
|
||||
{
|
||||
return RemoveKey(key);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICollection
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return (m_KeyToValue as IDictionary<TKey, TValue>).Contains(item);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return RemoveKey(item.Key);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo([NotNull] KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
(m_KeyToValue as IDictionary<TKey, TValue>).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable
|
||||
|
||||
[NotNull]
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return m_KeyToValue.GetEnumerator();
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -448,7 +448,20 @@ namespace ICD.Common.Utils
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
return GetValuesUncached(type).Aggregate(0, (current, value) => current | (int)value);
|
||||
return GetValues(type).Aggregate(0, (current, value) => current | (int)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enum value of the given type with the inverse of the flags set
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T GetInverseFlags<T>(T value)
|
||||
where T : struct, IConvertible
|
||||
{
|
||||
int output = GetFlagsAllValue(typeof(T)) & ~(int)(object)value;
|
||||
return (T)Enum.ToObject(typeof(T), output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
|
||||
@@ -13,34 +13,61 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <returns></returns>
|
||||
public static string ToReadableString(this TimeSpan extends)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (extends.Days == 1)
|
||||
builder.AppendFormat("{0} day, ", extends.Days);
|
||||
else if (extends.Days > 1)
|
||||
builder.AppendFormat("{0} days, ", extends.Days);
|
||||
|
||||
if (extends.Hours == 1)
|
||||
builder.AppendFormat("{0} hour, ", extends.Hours);
|
||||
else if (extends.Hours > 1)
|
||||
builder.AppendFormat("{0} hours, ", extends.Hours);
|
||||
|
||||
if (extends.Minutes == 1)
|
||||
builder.AppendFormat("{0} minute, ", extends.Minutes);
|
||||
else if (extends.Minutes > 1)
|
||||
builder.AppendFormat("{0} minutes, ", extends.Minutes);
|
||||
|
||||
if (extends.Seconds == 1)
|
||||
builder.AppendFormat("{0} second, ", extends.Seconds);
|
||||
else if (extends.Seconds > 1)
|
||||
builder.AppendFormat("{0} seconds, ", extends.Seconds);
|
||||
|
||||
if (extends.Milliseconds > 0)
|
||||
builder.AppendFormat("{0} ms", extends.Milliseconds);
|
||||
|
||||
return builder.ToString().TrimEnd(',', ' ');
|
||||
return extends.ToReadableString(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the TimeSpan to a string in the format "A day/s, B hour/s, C minute/s, D second/s, E ms"
|
||||
/// Omits any items that are 0.
|
||||
/// Optionally hides the miliseconds
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="hideMilliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToReadableString(this TimeSpan extends, bool hideMilliseconds)
|
||||
{
|
||||
int zeroComparison = extends.CompareTo(TimeSpan.Zero);
|
||||
|
||||
if (zeroComparison == 0)
|
||||
return "Zero Time";
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// Handle negative time spans
|
||||
if (zeroComparison < 0)
|
||||
builder.Append("-");
|
||||
|
||||
// Get absolute value so negatives can be ignored
|
||||
TimeSpan timeSpan = extends.Duration();
|
||||
|
||||
if (timeSpan.Days == 1)
|
||||
builder.AppendFormat("{0} day, ", timeSpan.Days);
|
||||
else if (timeSpan.Days > 1)
|
||||
builder.AppendFormat("{0} days, ", timeSpan.Days);
|
||||
|
||||
if (timeSpan.Hours == 1)
|
||||
builder.AppendFormat("{0} hour, ", timeSpan.Hours);
|
||||
else if (timeSpan.Hours > 1)
|
||||
builder.AppendFormat("{0} hours, ", timeSpan.Hours);
|
||||
|
||||
if (timeSpan.Minutes == 1)
|
||||
builder.AppendFormat("{0} minute, ", timeSpan.Minutes);
|
||||
else if (timeSpan.Minutes > 1)
|
||||
builder.AppendFormat("{0} minutes, ", timeSpan.Minutes);
|
||||
|
||||
if (timeSpan.Seconds == 1)
|
||||
builder.AppendFormat("{0} second, ", timeSpan.Seconds);
|
||||
else if (timeSpan.Seconds > 1)
|
||||
builder.AppendFormat("{0} seconds, ", timeSpan.Seconds);
|
||||
else if (hideMilliseconds && (long)timeSpan.TotalSeconds == 0)
|
||||
builder.AppendFormat("0 seconds");
|
||||
|
||||
if (!hideMilliseconds && timeSpan.Milliseconds > 0)
|
||||
builder.AppendFormat("{0} ms", timeSpan.Milliseconds);
|
||||
|
||||
return builder.ToString().TrimEnd(',', ' ');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given number of hours to the time, wrapping every 24 hours without modifying the day.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Condition=" '$(EAZFUSCATOR_NET_HOME)' != '' and Exists('$(EAZFUSCATOR_NET_HOME)\Integration\MSBuild\Eazfuscator.NET.targets') " Project="$(EAZFUSCATOR_NET_HOME)\Integration\MSBuild\Eazfuscator.NET.targets" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
|
||||
@@ -8,9 +7,6 @@
|
||||
<RootNamespace>ICD.Common.Utils</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Deterministic>true</Deterministic>
|
||||
<EazfuscatorIntegration>MSBuild</EazfuscatorIntegration>
|
||||
<EazfuscatorActiveConfiguration>Release</EazfuscatorActiveConfiguration>
|
||||
<EazfuscatorCompatibilityVersion>2018.2</EazfuscatorCompatibilityVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
@@ -34,17 +30,17 @@
|
||||
<None Remove="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="Crestron.SimplSharp.SDK.Library" Version="2.17.69" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="Newtonsoft.Json" Version="13.0.1" Aliases="RealNewtonsoft"/>
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="5.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="Pastel" Version="2.1.0" />
|
||||
<PackageReference Include="System.Management" Version="5.0.0" />
|
||||
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="Crestron.SimplSharp.SDK.Library" Version="2.18.96" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="Newtonsoft.Json" Version="13.0.1" Aliases="RealNewtonsoft" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="Microsoft.Data.SQLite" Version="5.0.4" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="Microsoft.Extensions.DependencyModel" Version="5.0.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="Pastel" Version="2.1.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="System.Management" Version="5.0.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="System.Security.Principal.Windows" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="CultureInfo.sqlite">
|
||||
|
||||
@@ -79,11 +79,13 @@
|
||||
<Compile Include="Attributes\AbstractIcdAttribute.cs" />
|
||||
<Compile Include="Attributes\IIcdAttribute.cs" />
|
||||
<Compile Include="Attributes\RangeAttribute.cs" />
|
||||
<Compile Include="BigEndianBitConverter.cs" />
|
||||
<Compile Include="Collections\BiDictionary.cs" />
|
||||
<Compile Include="Collections\IcdOrderedDictionary.cs" />
|
||||
<Compile Include="Collections\IcdSortedDictionary.cs" />
|
||||
<Compile Include="Collections\INotifyCollectionChanged.cs" />
|
||||
<Compile Include="Collections\PriorityQueue.cs" />
|
||||
<Compile Include="Collections\ReverseLookupDictionary.cs" />
|
||||
<Compile Include="Collections\WeakKeyDictionary.cs" />
|
||||
<Compile Include="Comparers\FileNameEqualityComparer.cs" />
|
||||
<Compile Include="Comparers\PredicateComparer.cs" />
|
||||
@@ -126,7 +128,6 @@
|
||||
<Compile Include="Threading\KeyedLock.cs" />
|
||||
<Compile Include="Threading\ThreadedWorkerQueue.cs" />
|
||||
<Compile Include="TimeZoneInfo\IcdTimeZoneInfo.cs" />
|
||||
<Compile Include="ObfuscationSettings.cs" />
|
||||
<Compile Include="Extensions\BoolExtensions.cs" />
|
||||
<Compile Include="Extensions\ByteExtensions.cs" />
|
||||
<Compile Include="Extensions\CultureInfoExtensions.cs" />
|
||||
@@ -241,6 +242,8 @@
|
||||
<Compile Include="TimeZoneInfo\IcdTimeZoneInfoAdjustmentRule.cs" />
|
||||
<Compile Include="TimeZoneInfo\IcdTimeZoneInfoTransitionTime.cs" />
|
||||
<Compile Include="TryUtils.cs" />
|
||||
<Compile Include="Types\AbstractNotifyFlagsChanged.cs" />
|
||||
<Compile Include="Types\GenericNotifyFlagsChanged.cs" />
|
||||
<Compile Include="UriQueryBuilder.cs" />
|
||||
<Compile Include="UriUtils.cs" />
|
||||
<Compile Include="VersionSpan.cs" />
|
||||
@@ -262,8 +265,4 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>if /I "$(ConfigurationName)" == "Release" Eazfuscator.NET.exe "$(TargetPath)" --msbuild-project-path "$(ProjectPath)" --msbuild-project-configuration "$(ConfigurationName)" --msbuild-project-platform "$(PlatformName)" --msbuild-solution-path "$(SolutionPath)" -n --newline-flush -v 5.2 --configuration-file="$(ProjectDir)ObfuscationSettings.cs"
|
||||
rem S# Pro preparation will execute after these operations</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
#else
|
||||
using ICD.Common.Utils.Extensions;
|
||||
@@ -13,7 +13,7 @@ namespace ICD.Common.Utils.IO
|
||||
{
|
||||
public static string GetApplicationDirectory()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
return Directory.GetApplicationDirectory();
|
||||
#else
|
||||
string pathToDll = Assembly.GetExecutingAssembly().GetPath();
|
||||
@@ -27,7 +27,7 @@ namespace ICD.Common.Utils.IO
|
||||
/// <returns></returns>
|
||||
public static string GetApplicationRootDirectory()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
return Directory.GetApplicationRootDirectory();
|
||||
#else
|
||||
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetPath());
|
||||
|
||||
@@ -40,8 +40,8 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
if (s_IsConsoleApp == null)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
s_IsConsoleApp = true;
|
||||
#if !NETSTANDARD
|
||||
s_IsConsoleApp = false;
|
||||
#else
|
||||
try
|
||||
{
|
||||
@@ -94,13 +94,17 @@ namespace ICD.Common.Utils
|
||||
[PublicAPI]
|
||||
public static void ConsoleCommandResponse(string message, params object[] args)
|
||||
{
|
||||
// No console in Server
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return;
|
||||
|
||||
if (args != null && args.Any())
|
||||
message = string.Format(message, args);
|
||||
|
||||
message = FixLineEndings(message);
|
||||
|
||||
#if !NETSTANDARD
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Appliance)
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.SimplSharpPro)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -110,11 +114,10 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
PrintLine(message);
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
PrintLine(message);
|
||||
PrintLine(message);
|
||||
}
|
||||
|
||||
public static void PrintLine(string message)
|
||||
@@ -126,7 +129,7 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment != IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
if (IcdEnvironment.CrestronDevicePlatform != IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
CrestronConsole.PrintLine(fixedMessage);
|
||||
#else
|
||||
Trace.WriteLine(AnsiUtils.StripAnsi(fixedMessage));
|
||||
@@ -170,7 +173,7 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment != IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
if (IcdEnvironment.CrestronDevicePlatform != IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
CrestronConsole.Print(fixedMessage);
|
||||
#else
|
||||
Trace.Write(AnsiUtils.StripAnsi(fixedMessage));
|
||||
@@ -208,8 +211,8 @@ namespace ICD.Common.Utils
|
||||
public static bool SendControlSystemCommand(string command, ref string result)
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
// No console on VC4
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
// No console on Crestron Server
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return false;
|
||||
|
||||
return CrestronConsole.SendControlSystemCommand(command, ref result);
|
||||
@@ -222,7 +225,11 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
// Avoid crashing Simpl applications
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment != IcdEnvironment.eCrestronRuntimeEnvironment.Appliance)
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment != IcdEnvironment.eCrestronRuntimeEnvironment.SimplSharpPro)
|
||||
return false;
|
||||
|
||||
// No console in Crestron Server
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return false;
|
||||
|
||||
if (CrestronConsole.ConsoleRegistered)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharp;
|
||||
@@ -194,14 +194,16 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
// Cache the runtime environment
|
||||
s_Framework = eFramework.Crestron;
|
||||
|
||||
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SIMPL)
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Simpl;
|
||||
else if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Appliance;
|
||||
else
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Server;
|
||||
|
||||
s_CrestronRuntimeEnvironment = CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SIMPL
|
||||
? eCrestronRuntimeEnvironment.SimplPlus
|
||||
: eCrestronRuntimeEnvironment.SimplSharpPro;
|
||||
|
||||
s_CrestronDevicePlatform = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
|
||||
? eCrestronDevicePlatform.Appliance
|
||||
: eCrestronDevicePlatform.Server;
|
||||
|
||||
// todo: Make this check more robust
|
||||
s_CrestronSeries = Type.GetType("Mono.Runtime") != null ? eCrestronSeries.FourSeries : eCrestronSeries.ThreeSeries;
|
||||
|
||||
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironmentOnProgramStatusEventHandler;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -9,9 +9,7 @@ using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Timers;
|
||||
using AddressFamily = System.Net.Sockets.AddressFamily;
|
||||
using Dns = System.Net.Dns;
|
||||
#if !NETSTANDARD
|
||||
using Crestron.SimplSharp;
|
||||
#endif
|
||||
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
@@ -109,20 +107,10 @@ namespace ICD.Common.Utils
|
||||
|
||||
static IcdEnvironment()
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
s_Framework = eFramework.Framework;
|
||||
s_CrestronSeries = eCrestronSeries.FourSeries;
|
||||
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SIMPL)
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Simpl;
|
||||
else if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Appliance;
|
||||
else
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Server;
|
||||
#else
|
||||
s_Framework = eFramework.Standard;
|
||||
s_CrestronSeries = eCrestronSeries.Na;
|
||||
s_CrestronRuntimeEnvironment = eCrestronRuntimeEnvironment.Na;
|
||||
#endif
|
||||
s_CrestronDevicePlatform = eCrestronDevicePlatform.Na;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -32,9 +32,15 @@ namespace ICD.Common.Utils
|
||||
public enum eCrestronRuntimeEnvironment
|
||||
{
|
||||
Na, //Non-Crestron
|
||||
Simpl, // Running in Simpl, Non-Pro
|
||||
Appliance, // S#Pro running on a Crestron hardware appliance
|
||||
Server // S#Pro running on a server (VC-4)
|
||||
SimplPlus, // Running in Simpl+, Non-Pro
|
||||
SimplSharpPro // Running in Simpl#Pro
|
||||
}
|
||||
|
||||
public enum eCrestronDevicePlatform
|
||||
{
|
||||
Na, // Non-Crestron
|
||||
Appliance, // Running on Crestron hardware appliance
|
||||
Server // Running on VC-4 Server
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,14 +126,24 @@ namespace ICD.Common.Utils
|
||||
private static readonly eFramework s_Framework;
|
||||
private static readonly eCrestronSeries s_CrestronSeries;
|
||||
private static readonly eCrestronRuntimeEnvironment s_CrestronRuntimeEnvironment;
|
||||
private static readonly eCrestronDevicePlatform s_CrestronDevicePlatform;
|
||||
|
||||
private static readonly SafeCriticalSection s_ProgramInitializationSection = new SafeCriticalSection();
|
||||
private static bool s_ProgramInitializationComplete;
|
||||
|
||||
public static eFramework Framework {get { return s_Framework; }}
|
||||
public static eCrestronSeries CrestronSeries {get { return s_CrestronSeries; }}
|
||||
|
||||
/// <summary>
|
||||
/// Crestron environment being run in, SimplPlus or SimplSharpPro
|
||||
/// </summary>
|
||||
public static eCrestronRuntimeEnvironment CrestronRuntimeEnvironment {get { return s_CrestronRuntimeEnvironment; }}
|
||||
|
||||
/// <summary>
|
||||
/// Crestron platform being run on, Appliance (crestron hardware) or Server (VC-4)
|
||||
/// </summary>
|
||||
public static eCrestronDevicePlatform CrestronDevicePlatform { get { return s_CrestronDevicePlatform; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the program has been flagged as completely initialized.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: Obfuscation(Feature = "platform api: System.Threading.Thread, System.Reflection.*, System.IO.Stream, System.Windows.Forms.*", Exclude = true)]
|
||||
[assembly: Obfuscation(Feature = "rename symbol names with printable characters", Exclude = false)]
|
||||
[assembly: Obfuscation(Feature = "code control flow obfuscation", Exclude = false)]
|
||||
[assembly: Obfuscation(Feature = "Apply to type * when class: renaming", Exclude = true, ApplyToMembers = false)]
|
||||
@@ -26,7 +26,7 @@ namespace ICD.Common.Utils
|
||||
public static string RootPath {
|
||||
get
|
||||
{
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return IcdDirectory.GetApplicationRootDirectory();
|
||||
|
||||
return IcdDirectory.GetDirectoryRoot(IcdPath.DirectorySeparatorChar.ToString());
|
||||
@@ -63,13 +63,14 @@ namespace ICD.Common.Utils
|
||||
get
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
switch (IcdEnvironment.CrestronSeries)
|
||||
{
|
||||
case IcdEnvironment.eCrestronSeries.FourSeries:
|
||||
return Join(RootPath, "user");
|
||||
default:
|
||||
return Join(RootPath, "User");
|
||||
}
|
||||
|
||||
// Server uses "User" and rest of the e-seres uses "user" :facepalm:
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return Join(RootPath, "User");
|
||||
|
||||
// Rest of processors
|
||||
// 3-series traditionally used "User", but isn't case sensitive
|
||||
return Join(RootPath, "user");
|
||||
#elif LINUX
|
||||
return Join(RootPath, "opt", "ICD.Connect");
|
||||
#else
|
||||
@@ -94,7 +95,7 @@ namespace ICD.Common.Utils
|
||||
get
|
||||
{
|
||||
// Crestron Server doesn't have meaningful program number
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return "ProgramConfig";
|
||||
|
||||
return string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
|
||||
@@ -117,7 +118,7 @@ namespace ICD.Common.Utils
|
||||
get
|
||||
{
|
||||
// Crestron Server doesn't have meaningful program number
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return "ProgramData";
|
||||
|
||||
return string.Format("Program{0:D2}Data", ProgramUtils.ProgramNumber);
|
||||
@@ -157,7 +158,7 @@ namespace ICD.Common.Utils
|
||||
string directoryName;
|
||||
|
||||
// Crestron Server doesn't have meaningful program number
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Server)
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
directoryName = "ProgramLogs";
|
||||
else
|
||||
directoryName = string.Format("Program{0:D2}Logs", ProgramUtils.ProgramNumber);
|
||||
@@ -181,12 +182,13 @@ namespace ICD.Common.Utils
|
||||
if (IcdEnvironment.CrestronSeries == IcdEnvironment.eCrestronSeries.ThreeSeries)
|
||||
return Join(RootPath, "HTML");
|
||||
|
||||
// 4-series non-server (because Crestron)
|
||||
if (IcdEnvironment.CrestronRuntimeEnvironment == IcdEnvironment.eCrestronRuntimeEnvironment.Appliance)
|
||||
return Join(RootPath, "html");
|
||||
|
||||
// 4-series server (because Crestron)
|
||||
return Join(RootPath, "Html");
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return Join(RootPath, "Html");
|
||||
|
||||
|
||||
// 4-series non-server (because Crestron)
|
||||
return Join(RootPath, "html");
|
||||
}
|
||||
|
||||
#if LINUX
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using System.Globalization;
|
||||
using Crestron.SimplSharp;
|
||||
using ICD.Common.Utils.Services;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using ICD.Common.Utils.IO;
|
||||
using ICD.Common.Utils.Services;
|
||||
using ICD.Common.Utils.Services.Logging;
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using Crestron.SimplSharp;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
using ICD.Common.Utils.IO;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -24,19 +24,20 @@ namespace ICD.Common.Utils
|
||||
switch (IcdEnvironment.Framework)
|
||||
{
|
||||
case IcdEnvironment.eFramework.Crestron:
|
||||
// No console in servers
|
||||
if (IcdEnvironment.CrestronDevicePlatform == IcdEnvironment.eCrestronDevicePlatform.Server)
|
||||
return;
|
||||
|
||||
switch (IcdEnvironment.CrestronRuntimeEnvironment)
|
||||
{
|
||||
case IcdEnvironment.eCrestronRuntimeEnvironment.Simpl:
|
||||
case IcdEnvironment.eCrestronRuntimeEnvironment.SimplPlus:
|
||||
int length = Math.Min(13, name.Length);
|
||||
name = name.Substring(0, length).PadRight(13);
|
||||
break;
|
||||
case IcdEnvironment.eCrestronRuntimeEnvironment.Appliance:
|
||||
case IcdEnvironment.eCrestronRuntimeEnvironment.SimplSharpPro:
|
||||
int proLength = Math.Min(26 - 1, name.Length);
|
||||
name = name.Substring(0, proLength).PadRight(26);
|
||||
break;
|
||||
case IcdEnvironment.eCrestronRuntimeEnvironment.Server:
|
||||
// No console
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ using System.Reflection;
|
||||
[assembly: AssemblyTitle("ICD.Common.Utils")]
|
||||
[assembly: AssemblyCompany("ICD Systems")]
|
||||
[assembly: AssemblyProduct("ICD.Common.Utils")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2022")]
|
||||
[assembly: AssemblyVersion("16.0.2.0")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2023")]
|
||||
[assembly: AssemblyVersion("17.2.0.0")]
|
||||
|
||||
@@ -11,9 +11,11 @@ using Crestron.SimplSharp.Reflection;
|
||||
using Activator = Crestron.SimplSharp.Reflection.Activator;
|
||||
#else
|
||||
using System.Reflection;
|
||||
using Activator = System.Activator;
|
||||
#endif
|
||||
#if NETSTANDARD
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using System.Runtime.Loader;
|
||||
using Activator = System.Activator;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace ICD.Common.Utils
|
||||
/// Convert two ushort's to an int
|
||||
/// </summary>
|
||||
/// <param name="lowWord">ushort for the least significant 16 bits</param>
|
||||
/// <param name="highWord">ushort for the most significant 1 bits</param>
|
||||
/// <param name="highWord">ushort for the most significant 16 bits</param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI("S+")]
|
||||
public static int ConvertToInt(ushort lowWord, ushort highWord)
|
||||
@@ -20,4 +20,4 @@ namespace ICD.Common.Utils
|
||||
return (highWord << 16) + lowWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using SqliteCommand = Crestron.SimplSharp.SQLite.SQLiteCommand;
|
||||
#else
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using ICD.Common.Utils.IO;
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using SqliteConnection = Crestron.SimplSharp.SQLite.SQLiteConnection;
|
||||
#else
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using SqliteDataReader = Crestron.SimplSharp.SQLite.SQLiteDataReader;
|
||||
#else
|
||||
using System;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using SqliteParameter = Crestron.SimplSharp.SQLite.SQLiteParameter;
|
||||
#else
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using SqliteParameterCollection = Crestron.SimplSharp.SQLite.SQLiteParameterCollection;
|
||||
#else
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
using Crestron.SimplSharp.CrestronData;
|
||||
#else
|
||||
using System;
|
||||
@@ -41,14 +41,14 @@ namespace ICD.Common.Utils.Sqlite
|
||||
public static class DbTypeExtensions
|
||||
{
|
||||
public static
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
DbType
|
||||
#else
|
||||
SqliteType
|
||||
#endif
|
||||
ToParamType(this eDbType extends)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
return (DbType)extends;
|
||||
#else
|
||||
switch (extends)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
public sealed class TableBuilder
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
private const char HORIZONTAL = '-';
|
||||
private const char VERTICAL = '|';
|
||||
private const char INTERSECT = '+';
|
||||
@@ -230,7 +230,7 @@ namespace ICD.Common.Utils
|
||||
|
||||
private void AppendTopSeparator(StringBuilder builder, IList<int> columnWidths)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
// Can't do fancy tables so don't bother drawing the top row
|
||||
#else
|
||||
builder.Append(DOWN_RIGHT).Append(HORIZONTAL);
|
||||
@@ -256,7 +256,7 @@ namespace ICD.Common.Utils
|
||||
|
||||
private void AppendBottomSeparator(StringBuilder builder, IList<int> columnWidths)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
#if !NETSTANDARD
|
||||
AppendSeparator(builder, columnWidths);
|
||||
#else
|
||||
builder.Append(UP_RIGHT).Append(HORIZONTAL);
|
||||
@@ -282,7 +282,7 @@ namespace ICD.Common.Utils
|
||||
|
||||
private static void AppendRow(StringBuilder builder, IList<string> row, IList<int> columnWidths)
|
||||
{
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
builder.Append(VERTICAL).Append(' ');
|
||||
#endif
|
||||
|
||||
@@ -298,7 +298,7 @@ namespace ICD.Common.Utils
|
||||
builder.Append(VERTICAL);
|
||||
}
|
||||
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
builder.Append(VERTICAL);
|
||||
#endif
|
||||
|
||||
@@ -307,7 +307,7 @@ namespace ICD.Common.Utils
|
||||
|
||||
private static void AppendSeparator(StringBuilder builder, IList<int> columnWidths)
|
||||
{
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
builder.Append(VERTICAL_RIGHT).Append(HORIZONTAL);
|
||||
#endif
|
||||
|
||||
@@ -324,7 +324,7 @@ namespace ICD.Common.Utils
|
||||
builder.Append(INTERSECT);
|
||||
}
|
||||
|
||||
#if !SIMPLSHARP
|
||||
#if NETSTANDARD
|
||||
builder.Append(VERTICAL_LEFT);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the IcdManualResetEvent class with a Boolean value indicating whether to set the initial state to signaled.
|
||||
/// Initializes a new instance of the IcdAutoResetEvent class with a Boolean value indicating whether to set the initial state to signaled.
|
||||
/// </summary>
|
||||
/// <param name="initialState">true to set the initial state signaled; false to set the initial state to nonsignaled.</param>
|
||||
[PublicAPI]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
@@ -12,8 +12,10 @@ namespace ICD.Common.Utils
|
||||
/// done with it. This class is an attempt to gracefully handle the ObjectDisposedExceptions
|
||||
/// we see on program termination, ocassionally causing the program to restart instead of stop.
|
||||
/// </summary>
|
||||
public sealed class SafeMutex
|
||||
public sealed class SafeMutex : IDisposable
|
||||
{
|
||||
private bool _disposedValue;
|
||||
|
||||
#if SIMPLSHARP
|
||||
private readonly CMutex m_Mutex;
|
||||
#else
|
||||
@@ -21,8 +23,8 @@ namespace ICD.Common.Utils
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// Initializes a new instance of the <see cref="SafeMutex"/> class.
|
||||
/// </summary>
|
||||
public SafeMutex()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
@@ -31,7 +33,20 @@ namespace ICD.Common.Utils
|
||||
m_Mutex = new Mutex();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeMutex"/> class.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="System.Threading.Mutex.Mutex(bool)"/>
|
||||
public SafeMutex(bool initiallyOwned)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
m_Mutex = new CMutex(initiallyOwned);
|
||||
#else
|
||||
m_Mutex = new Mutex(initiallyOwned);
|
||||
#endif
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
@@ -46,7 +61,7 @@ namespace ICD.Common.Utils
|
||||
#if SIMPLSHARP
|
||||
return m_Mutex.WaitForMutex(timeout);
|
||||
#else
|
||||
return m_Mutex.WaitOne(timeout);
|
||||
return m_Mutex.WaitOne(timeout);
|
||||
#endif
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
@@ -71,5 +86,42 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// dispose managed state (managed objects)
|
||||
try
|
||||
{
|
||||
// disposing of a mutex automatically releases it. Match that behavior
|
||||
m_mutex.ReleaseMutex();
|
||||
m_Mutex.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Releasing a disposed mutex in this case is valid behaviour
|
||||
}
|
||||
}
|
||||
|
||||
// free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// set large fields to null
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.Services;
|
||||
using ICD.Common.Utils.Services.Logging;
|
||||
using ICD.Common.Utils.Timers;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
@@ -370,7 +372,15 @@ namespace ICD.Common.Utils
|
||||
while (true)
|
||||
{
|
||||
// Run the process action
|
||||
m_ProcessAction(item);
|
||||
// todo: Have exceptions raise an event in a new thread, maybe configurable exception handling
|
||||
try
|
||||
{
|
||||
m_ProcessAction(item);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ServiceProvider.GetService<ILoggerService>().AddEntry(eSeverity.Error, e, "Exception in ThreadedWorkingQueue process action:{0}", e.Message);
|
||||
}
|
||||
|
||||
m_QueueSection.Enter();
|
||||
try
|
||||
|
||||
@@ -61,7 +61,11 @@ namespace ICD.Common.Utils.TimeZoneInfo
|
||||
|
||||
public static IcdTimeZoneInfo FindSystemTimeZoneById(string timeZoneId)
|
||||
{
|
||||
return s_Cache[timeZoneId];
|
||||
IcdTimeZoneInfo timeZone;
|
||||
if (s_Cache.TryGetValue(timeZoneId, out timeZone))
|
||||
return timeZone;
|
||||
|
||||
throw new KeyNotFoundException(string.Format("Unable to find timezone with id:{0}", timeZoneId));
|
||||
}
|
||||
|
||||
public static bool TryFindSystemTimeZoneById(string timeZoneId, out IcdTimeZoneInfo output)
|
||||
|
||||
79
ICD.Common.Utils/Types/AbstractNotifyFlagsChanged.cs
Normal file
79
ICD.Common.Utils/Types/AbstractNotifyFlagsChanged.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
|
||||
namespace ICD.Common.Utils.Types
|
||||
{
|
||||
public abstract class AbstractNotifyFlagsChanged<T> where T : struct, IConvertible
|
||||
{
|
||||
private T m_Data;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when flags are set on the data
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnFlagsSet;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when flags are unset on the data
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnFlagsUnset;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the data changes
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnChange;
|
||||
|
||||
/// <summary>
|
||||
/// Data
|
||||
/// </summary>
|
||||
public T Data
|
||||
{
|
||||
get { return m_Data; }
|
||||
set
|
||||
{
|
||||
if (DataIsEqual(m_Data, value))
|
||||
return;
|
||||
|
||||
int intData = GetIntValue(m_Data);
|
||||
int intValue = GetIntValue(value);
|
||||
|
||||
int setFlags = intValue & ~intData;
|
||||
int unsetFlags = intData & ~intValue;
|
||||
|
||||
m_Data = value;
|
||||
|
||||
OnChange.Raise(this, value);
|
||||
|
||||
if (setFlags != 0)
|
||||
OnFlagsSet.Raise(this, GetEnumValue(setFlags));
|
||||
if (unsetFlags != 0)
|
||||
OnFlagsUnset.Raise(this, GetEnumValue(unsetFlags));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the enum to the backing int value
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract int GetIntValue(T value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the backing int value to enum
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract T GetEnumValue(int value);
|
||||
|
||||
/// <summary>
|
||||
/// Checks enums for equality
|
||||
/// Override for performance improvements
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual bool DataIsEqual(T a, T b)
|
||||
{
|
||||
return GetIntValue(a) == GetIntValue(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
ICD.Common.Utils/Types/GenericNotifyFlagsChanged.cs
Normal file
34
ICD.Common.Utils/Types/GenericNotifyFlagsChanged.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
|
||||
namespace ICD.Common.Utils.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to raise events when flags are set and unset on the data
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class GenericNotifyFlagsChanged<T> : AbstractNotifyFlagsChanged<T> where T : struct, IConvertible
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the enum to the backing int value
|
||||
/// Override for performance improvements
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected override int GetIntValue(T value)
|
||||
{
|
||||
return (int)(object)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the backing int value to enum
|
||||
/// Override for performance improvements
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected override T GetEnumValue(int value)
|
||||
{
|
||||
return (T)(object)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 ICD Systems
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Reference in New Issue
Block a user