Compare commits

...

909 Commits
3.5.0.0 ... dev

Author SHA1 Message Date
Drew Tingen
0de417b665 chore: Update Changelog, increment assembly minor version 2023-06-18 09:55:30 -04:00
Drew Tingen
da57fcb988 test[BigEndianBitConverter]: finished unit testing 2023-06-18 09:52:47 -04:00
Drew Tingen
c6b6711eb2 refactor[BigEndianBitConverter]: Reduce code reuse in GetBytes methods 2023-06-18 09:52:18 -04:00
Drew Tingen
138a6f3470 fix[BigEndianBitConverter]: Fix ToLong and ToUlong overflow errors 2023-06-18 09:51:22 -04:00
Scott Pidzarko
e84bc721ee chore: Update SafeMutex.cs to remove commented out boilerplate
IDisposable boilerplate generates commented out finalizer. Removing commented out finalizer at request of upstream maintainer.
2023-06-18 08:38:38 -04:00
Scott Pidzarko
2988912d44 Update SafeMutex.cs to use correct class name in boilerplate commented out finalizer 2023-06-18 08:38:38 -04:00
Scott Pidzarko
be94503e6a Update SafeMutex.cs to implement IDisposable 2023-06-18 08:38:38 -04:00
Drew Tingen
6877b5c800 chore: changelog 2023-06-16 15:01:06 -04:00
Drew Tingen
569066edc4 feat[Types]: Add NotifyFlagsChanged, with abstract and generic classes 2023-06-16 14:59:33 -04:00
Drew Tingen
73a716f9b9 feat[Collections]: ReverseLookupDictionary for fast value access 2023-06-16 14:59:16 -04:00
Drew Tingen
4e430731cc feat[BigEndianBitConverter]: Added BigEndianBitConverter 2023-06-16 14:58:59 -04:00
Drew Tingen
2b8f2a125a feat[EnumUtils]: add GetinverseFlags method 2023-06-16 12:12:29 -04:00
Drew Tingen
cc25c41805 chore: Update changelog, increment assembly minor version 2023-03-22 08:13:59 -04:00
Drew Tingen
2487a70891 chore: Update copyright year 2023-03-22 08:12:27 -04:00
Drew Tingen
5c5a25775b chore: Remove Obfuscation 2023-03-21 16:57:38 -04:00
Drew Tingen
27f6267f54 feat: Nicer timespan readable formatting 2023-02-10 09:41:25 -05:00
Drew Tingen
430eac8cb6 Merge pull request #1 from scottpidzarko/patch-1
PR: Update SPlusUtils.cs to fix typo in XMLdoc
2023-01-10 11:32:40 -05:00
Scott Pidzarko
b47e305d9f Update SPlusUtils.cs
Fix typo.
2023-01-06 15:07:11 -08:00
astingen
0c8f8242e8 Create LICENSE.md 2022-12-24 17:45:39 -05:00
Drew Tingen
a52e77c1e7 chore:Increment major version, update changelog 2022-12-02 14:40:36 -05:00
Drew Tingen
2aa05f3ee8 fix(ThreadedWorkerQueue): Exception handling of exceptions in process action 2022-11-30 12:29:50 -05:00
Drew Tingen
2700f5018a fix: Fixed preprocessors in IcdDirectory 2022-11-30 12:29:50 -05:00
Drew Tingen
b09b22266b fix: Fixed CrestronRuntimeEnvironment uses in utils 2022-11-30 12:29:50 -05:00
Drew Tingen
1c206c5539 doc:Fixed doc typo 2022-11-30 12:29:50 -05:00
Drew Tingen
56a48175c6 feat(IcdEnvironment):Updated environment to sperate Crestron platform for environment for SW on VC4 2022-11-30 12:29:41 -05:00
Drew Tingen
0acd0ae5d4 chore: Update Changelog, Increment assembly patch version 2022-07-11 18:54:12 -04:00
Drew Tingen
d2856c1983 fix: Fix Preprocessors and NetStandard package references 2022-07-11 14:48:10 -04:00
Drew Tingen
fa65a9de65 fix: Fix console command responses in Simpl runtime environment 2022-07-06 15:40:48 -04:00
Drew Tingen
e4b292f145 fix: Crestron apps aren't considered interactive console 2022-07-06 15:37:24 -04:00
Drew Tingen
11a5533fcd chore: Update changelog, increment assembly patch version 2022-07-01 12:02:45 -04:00
Drew Tingen
e0d0763306 chore: Update Crestron SDK to 2.18.96 2022-07-01 11:58:28 -04:00
Drew Tingen
7d42158bc7 chore: sqlite reference only for netstandard 2022-06-30 18:49:21 -04:00
Drew Tingen
92a28813e0 fix: Use Crestron SQLite for 4 series 2022-06-30 17:58:01 -04:00
Drew Tingen
3b313a442c fix: Fix preprocessors for netstandard vs simplsharp 2022-06-30 11:01:12 -04:00
Drew Tingen
16fb3683dd chore: Update changelog, increment assembly patch version 2022-06-23 15:07:50 -04:00
Drew Tingen
bb9bcf6cdf feat: TimeZone getting an invalid time zone now throws exception with time zone name 2022-06-23 15:05:45 -04:00
Drew Tingen
0490ffd572 chore: Update changelog, increment assembly patch version 2022-05-23 11:32:09 -04:00
Chris Cameron
3bf0aff0a0 feat: Added KeyedLock for async semaphore locking by some arbitrary key 2022-02-02 14:13:29 -05:00
Chris Cameron
e5b10a96f7 chore: Moved threading classes into Threading subdirectory 2022-02-02 13:49:03 -05:00
Chris Cameron
0c3c87308c chore: Updating AssemblyInfo year 2022-01-05 16:27:18 -05:00
Chris Cameron
68d1f1033a fix: AbstractGenericJsonConverter handles existing values properly 2021-12-21 16:11:17 -05:00
Chris Cameron
af66147648 Merge remote-tracking branch 'origin/Krang_v1.9' into Krang_v1.10 2021-10-28 11:15:02 -04:00
Chris Cameron
16067bca20 chore: Updating changelog, incrementing patch version 2021-10-28 11:13:30 -04:00
Austin Noska
57e64788c4 fix: Change sqlite connection strings for IcdCultureInfo & IcdTimeZoneInfo to work with SimplSharp 2021-10-27 18:06:29 -04:00
Chris Cameron
bc605bf8ae chore: Updating crestron nuget packages 2021-10-25 14:30:25 -04:00
Chris Cameron
be50aa3314 docs: Fixed typo 2021-10-20 10:11:50 -04:00
Drew Tingen
1b79bd21df Merge remote-tracking branch 'origin/Krang_v1.9' into Krang_v1.10 2021-10-05 10:17:58 -04:00
Drew Tingen
7d5ec0e636 chore: Update changelog, increment assembly major version 2021-10-04 12:21:41 -04:00
Drew Tingen
79c1c60d79 chore: changelog 2021-09-30 10:47:18 -04:00
Drew Tingen
033008616f remove: SafeCriticalSection - remove TryEnter method 2021-09-30 10:45:12 -04:00
Drew Tingen
84b5b636f6 remove: Removing RateLimitedEventQueue - Use ThreadedWorkerQueue instead 2021-09-30 10:45:12 -04:00
Drew Tingen
451cf08c0f fix: Fixing ThreadedWorkerQueue to not use TryEnter, and track the processing state with a bool 2021-09-30 10:45:12 -04:00
Drew Tingen
63d76d8cef feat: Adding IcdAutoResetEvent and IcdMaunalResetEvent 2021-09-30 10:44:30 -04:00
Drew Tingen
c08a6283b8 fix: Fixed EnumUtils.GetValuesExceptNone to work for non-flag enums 2021-09-30 10:44:01 -04:00
Austin Noska
df42a6674f fix: Uri builder builds relative path into valid URI 2021-09-18 16:12:42 -04:00
Chris Cameron
ae53812a98 fix: Fixed plugin loading for .net framework 2021-08-31 11:00:48 -04:00
Chris Cameron
74ff651798 fix: Fixed IcdEnvironment.Framework for .net framework 2021-08-30 17:23:34 -04:00
Chris Cameron
29013a2bf5 fix: Fixed a bug where plugins were not unzipping in .net framework 2021-08-30 17:09:04 -04:00
Chris Cameron
baa00f7b00 chore: S#, net framework and net standard all build to /bin 2021-08-30 14:05:42 -04:00
Chris Cameron
67a2b11ee6 chore: Added SimplSharp nuget packages, fixed SIMPLSHARP preprocessors 2021-08-30 13:39:43 -04:00
Chris Cameron
8f5fee2401 chore: Added net472 target 2021-08-25 16:21:56 -04:00
Drew Tingen
d00d2febf3 chore: Update Changelog, increment minor version 2021-08-18 10:45:49 -04:00
Austin Noska
af3d335079 feat: Add TryParse overload method to StringUtils, which tries to parse a GUID from a string 2021-08-17 16:04:52 -04:00
Drew Tingen
375e3154c6 chore: Update Changelog, increment minor version 2021-08-03 13:55:18 -04:00
Chris Cameron
37d799295c fix: Resolving warnings 2021-06-30 11:33:11 -04:00
Chris Cameron
06f40e5d22 fix: Resolving warning 2021-06-30 11:05:31 -04:00
Austin Noska
11c3e33fc1 fix: Use if statement instead of while when checking if SQL read was successful in IcdTimeZoneInfo 2021-06-30 10:09:58 -04:00
Chris Cameron
fc60e2b675 chore: Adding NotNull/CanBeNull attributes to StringUtils 2021-06-28 16:11:23 -04:00
Drew Tingen
531e9dfcf8 feat: Adding Equality Comparers to BiDictionary constructor 2021-06-24 11:48:52 -04:00
Drew Tingen
f601f9cda7 feat: SetFlags enum extension 2021-06-23 14:12:27 -04:00
Chris Cameron
841b692727 feat: Added Flush() method to ILoggerService 2021-06-23 14:11:37 -04:00
Chris Cameron
5f2c5e6dcb fix: Fixed a bug where EnumUtils.GetFlags, and overloads, would also return defined composites 2021-06-15 14:13:37 -04:00
Austin Noska
7ae9e86e1d fix: Fixed an issue where the SequenceComparer & the UndefinedVersionComparer were not handling null values properly 2021-06-07 14:43:53 -04:00
Chris Cameron
e6dec641f3 feat: Added ThreadingUtils overloads 2021-05-24 10:11:49 -04:00
Chris Cameron
8b848e5127 refactor: Tidying, resolving warnings 2021-05-20 17:09:12 -04:00
Chris Cameron
f328598f63 refactor: Tidying, resolving warnings 2021-05-20 14:45:49 -04:00
Chris Cameron
79db70211f fix: Removing "Microsoft" from windows model name 2021-05-20 09:55:05 -04:00
Chris Cameron
1390af967f feat: Logging when we intentionally restart the program or processor 2021-05-17 15:30:53 -04:00
Chris Cameron
28335ad99c chore: Updating changelog, incrementing major version 2021-05-14 10:59:54 -04:00
Chris Cameron
6967e9b013 fix: No longer automatically enabling ANSI color, must be enabled by the calling application 2021-05-14 10:17:01 -04:00
Chris Cameron
7784b99f75 fix: Logic for determining if there is a console output window, don't try to write to console if no console window 2021-05-14 10:17:01 -04:00
Chris Cameron
b3c1daaab5 fix: Fixed a bug where AbstractGenericXmlConverter was not reading out of empty elements 2021-05-04 17:26:01 -04:00
Austin Noska
ae10abd71e feat: Port open source CsvReader for CF 3.5 compatibility 2021-04-29 09:31:24 -04:00
Austin Noska
5aca963da0 feat: Expose wrapped stream for IcdStreamReader 2021-04-28 17:03:59 -04:00
Austin Noska
40330d0007 feat: Add method to IcdFile for getting the length in bytes of a specified file 2021-04-28 16:16:59 -04:00
Chris Cameron
a26783bd67 feat: IcdErrorLog traces to Visual Studio output 2021-04-22 14:26:54 -04:00
Chris Cameron
d58b8a9db9 feat: IcdConsole traces to Visual Studio output 2021-04-21 16:45:12 -04:00
Chris Cameron
5083f3d7ab fix: Fixing trailing whitespace in windows model name 2021-04-15 17:18:55 -04:00
Austin Noska
43fd348fae feat: Add enum extension method for cycling to next enum value 2021-04-13 15:59:37 -04:00
Chris Cameron
8cdddc94bc chore: Updating test projects to netcoreapp3.1 2021-04-13 11:46:10 -04:00
Chris Cameron
25d799fe7d fix: Fixed a bug where SafeTimer.Trigger would call the callback twice on NetStandard 2021-04-12 15:13:38 -04:00
Drew Tingen
f807db480e feat: added OnSystemDeviceAddedRemoved event to IcdEnviornment for NetStandard 2021-04-01 10:03:06 -04:00
Chris Cameron
985a81f961 refactor: Fixing warnings 2021-03-31 17:21:43 -04:00
Chris Cameron
0a9a382355 fix: GetProperty and CallMethod reflection utils use the FlattenHierarchy flag 2021-03-31 16:20:35 -04:00
Chris Cameron
86fabce6da feat: Initial commit of IcdOrderedDictionary 2021-03-30 13:43:59 -04:00
Chris Cameron
a7ab2ab3fe refactor: Renaming OrderedDictionary to SortedDictionary for consistency with .Net 2021-03-29 16:23:29 -04:00
Chris Cameron
370cadbaeb feat: Extension methods for joining enumerables of strings 2021-03-23 17:05:27 -04:00
Chris Cameron
e7bdcdfca5 feat: Adding methods for converting hex strings to byte arrays 2021-03-22 15:30:25 -04:00
Chris Cameron
cab1e237d5 chore: Updating nuget packages 2021-03-22 15:21:49 -04:00
Chris Cameron
da5e1d83a0 refactor: Tidying 2021-03-18 14:56:25 -04:00
Chris Cameron
63237b6fba feat: Added session change event to IcdEnvironment 2021-03-12 14:07:38 -05:00
Chris Cameron
a55480f8e5 fix: Preserve stack trace when rethrowing inner exceptions 2021-03-12 14:03:47 -05:00
Chris Cameron
d1f8096933 feat: Initial commit of RegistryExtensions 2021-03-03 16:45:19 -05:00
Chris Cameron
c41e61391e feat: Implementing ProcessorUtils for NetStandard 2021-03-03 13:50:28 -05:00
Chris Cameron
766e2da4e3 feat: Added property to ProgramUtils to determine if the application is running as admin 2021-03-02 11:44:36 -05:00
Chris Cameron
b83fba337f feat: Implementing RestartProgram and Reboot methods for windows 2021-03-01 09:46:10 -05:00
Austin Noska
766c265dac chore: Update changelog 2021-02-18 16:25:44 -05:00
Austin Noska
204d2a475d feat: Add MatchAny util method to RegexUtils that tries to match an input against a sequence of patterns. 2021-02-18 16:22:16 -05:00
Austin Noska
b5542fb0d2 feat: Add daylight time row entries & a new display name column to TimeZones.sqlite - Adjusted IcdTimeZoneInfo accordingly 2021-02-18 16:20:41 -05:00
Austin Noska
4ff4e9f3c6 feat: Add method to IcdEnvironment to get the name of the local time zone 2021-02-18 16:18:38 -05:00
Chris Cameron
456a8f74f9 feat: Adding shim for setting file attributes recursively 2021-02-11 11:43:18 -05:00
Chris Cameron
ffb00f960d feat: NetStandard krang plugins are archived to .kpz files 2021-02-10 14:21:31 -05:00
Chris Cameron
b44cbe0093 chore: Updating dependencies 2021-02-08 11:43:19 -05:00
Chris Cameron
cc79e88702 fix: Don't throw an ObjectDisposed exception when attempting to stop a disposed timer 2021-02-05 16:15:11 -05:00
Chris Cameron
1db7d4b45d Merge remote-tracking branch 'origin/ConnectPro_v1.8' into ConnectPro_v1.9
# Conflicts:
#	CHANGELOG.md
2021-02-04 11:34:06 -05:00
Chris Cameron
5bf8fcc71f chore: Updating changelog, incrementing minor version 2021-02-04 10:57:12 -05:00
Drew Tingen
b05373157a feat: Changed ProcessorUtils Uptimes to StartTime 2021-02-03 16:43:36 -05:00
Chris Cameron
8427f2c0c6 Merge remote-tracking branch 'origin/ConnectPro_v1.8' into ConnectPro_v1.9 2021-01-25 12:21:07 -05:00
Chris Cameron
572f069797 Merge remote-tracking branch 'origin/ConnectPro_v1.7' into ConnectPro_v1.8 2021-01-25 12:20:18 -05:00
Chris Cameron
e44bd3e2cc Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7 2021-01-25 12:19:35 -05:00
Chris Cameron
419b070375 chore: Fixing unit test 2021-01-25 12:18:24 -05:00
Chris Cameron
8411a27173 fix: Fixing 2008 build 2021-01-25 12:04:08 -05:00
Chris Cameron
e0287cfc7b Merge remote-tracking branch 'origin/ConnectPro_v1.8' into ConnectPro_v1.9 2021-01-21 10:42:51 -05:00
Chris Cameron
d7bee510c9 chore: Update changelog, increment minor version 2021-01-21 10:40:26 -05:00
Austin Noska
45a3c5c5a1 feat: Add overload to GuidUtils to combine an IEnumerable of guids into a new deterministic guid 2021-01-21 10:25:39 -05:00
Austin Noska
d090ab0085 fix: The SafeTimer constructor that executes the callback immediately now works as expected 2021-01-21 10:24:25 -05:00
Chris Cameron
e044c97af7 refactor: IcdUriBuilder.AppendPath returns itself for chaining 2021-01-18 15:22:46 -05:00
Chris Cameron
c7e8f09eeb feat: Added GetParentUri method to UriExtensions 2021-01-18 15:22:28 -05:00
Chris Cameron
9b53d77d6b feat: Added GetOrAddService method for lazy-loading services 2021-01-15 11:35:04 -05:00
Drew Tingen
c1b9426e32 chore: update changelog, increment assembly version 2021-01-14 23:41:26 -05:00
Drew Tingen
237b5d3e86 feat: Moving environment to 3 properties for Framework, Series, and Runtime 2021-01-12 16:25:09 -05:00
Drew Tingen
68365553ed feat: Adding SimplSharpMono environment (for non-pro 4-series environment)
fix: Fix error in console FixLineEndings
2021-01-12 16:25:09 -05:00
Drew Tingen
3abb792c5c fix: Replace \n with \r\n for 4series console writes, to help reabibility 2021-01-11 11:32:52 -05:00
Chris Cameron
342ac4ebca chore: Fixing warning on Net Standard 2021-01-07 12:09:21 -05:00
Chris Cameron
4174ed2e1f chore: Updating copyright year 2021-01-06 16:45:03 -05:00
Chris Cameron
41d86ecf48 perf: Adding faster breadth-first search for when paths are not important 2021-01-06 15:08:38 -05:00
Chris Cameron
6b28ae44d6 feat: Added program entry point to path utils 2021-01-06 15:08:34 -05:00
Drew Tingen
ca857a7aed chore: Changelog 2021-01-05 16:49:08 -05:00
Drew Tingen
ccb961fc2e feat: Add GetSystemStartTime, to pull the time the system started up 2021-01-05 16:49:08 -05:00
Drew Tingen
8fa1de991b refactor: Change Procesor model version to be a string, pull from CrestronEnvironment 2021-01-05 16:49:08 -05:00
Austin Noska
5acfed40ba Refactor: Rename SequenceEqual parameter 2021-01-05 16:09:58 -05:00
Austin Noska
6141a763ae Refactor: remove unused code in CsvWriter.cs 2021-01-05 10:04:41 -05:00
Drew Tingen
e61dcd8596 fix: Improved threadsafety for TypeExtensions 2021-01-04 11:18:31 -05:00
Drew Tingen
9819c44dcc fix: Fix threading issue in EnumUtils cache 2021-01-04 11:18:28 -05:00
Chris Cameron
f9a8be85d6 feat: Added TimeSpan extension methods to converting to/from universal time 2020-12-17 11:41:20 -05:00
Chris Cameron
3381977050 feat: Added ToStringUndefined method to EnumUtils for printing known flags of an undefined composite 2020-12-01 16:53:45 -05:00
Chris Cameron
81d1a97304 feat: Added DepthFirstSearch method to RecursionUtils 2020-12-01 16:53:10 -05:00
Chris Cameron
37d5468e20 feat: Enumerable.Consolidate extensions support predicates 2020-11-16 16:16:43 -05:00
Austin Noska
03be66983d feat: Support reading primitive type double in IcdXmlReader and XmlUtils 2020-11-06 10:03:01 -05:00
Drew Tingen
a13f1fd687 feat: Adding eDaysOfWeek enum 2020-11-02 12:08:15 -05:00
Chris Cameron
f0bcb3bbc9 chore: Added NotNull attributes to StringUtils methods 2020-10-28 16:45:24 -04:00
Chris Cameron
1e934c9877 fix: Added critical section to IcdConsole to clean up multi-threaded output 2020-10-28 14:42:30 -04:00
Chris Cameron
64cc662ee7 fix: Fixed bad Assembly path handling on 4-series 2020-10-28 11:00:28 -04:00
Chris Cameron
4aa76bd647 test: Added count to collection debugger displays 2020-10-26 11:48:24 -04:00
Chris Cameron
59f4585ae6 feat: Exposing RecursionUtils GetPath method 2020-10-23 16:52:12 -04:00
Chris Cameron
2235eeeb9d feat: Initial commit of INotifyCollectionChanged 2020-10-22 12:17:55 -04:00
Chris Cameron
2a7a051f1f chore: Added validation and [NotNull] attributes to ReflectionUtils 2020-10-22 12:17:37 -04:00
Chris Cameron
f174c32721 feat: Added breadth-first search method that returns the path from root for every node in the graph 2020-10-22 12:16:32 -04:00
Chris Cameron
c349757c00 refactor: Cleaned up SafeTimer, added duration validation to clarify bad values 2020-10-19 12:24:22 -04:00
Chris Cameron
8c70c8d534 refactor: ReflectionExtensions are generic, support for non-public members, reduced duplicate code 2020-10-15 14:30:46 -04:00
Chris Cameron
0d85fe8106 refactor: Using EqualityComparer instead of Comparer for equality... 2020-10-14 16:43:26 -04:00
Chris Cameron
c868034769 fix: Handling a Crestron bug where File.Exists throws an exception on 4-Series instead of returning false 2020-10-12 11:22:28 -04:00
Drew Tingen
55c0a7dc7e fix: Fixing Console for 4-series 2020-10-07 22:55:26 -04:00
Drew Tingen
4321ad6157 feat: Adding ThreadedWorkerQueue 2020-09-17 15:34:02 -04:00
Chris Cameron
9a68f0446d test: Moved version comparer tests from settings 2020-09-11 11:17:50 -04:00
Laura Gomez
0574314580 feat: Created extension class, comparer class and VersionSpan class to for Devices' version and model validation. 2020-09-10 17:01:24 -04:00
Chris Cameron
e5fc154858 feat: Add IcdTimeZoneInfo 2020-09-03 12:08:51 -04:00
Chris Cameron
7bc262b4e2 Merge remote-tracking branch 'origin/ConnectPro_v1.7' into ConnectPro_v1.8
# Conflicts:
#	CHANGELOG.md
2020-09-03 12:05:09 -04:00
Chris Cameron
867338eca2 chore: Updating changelog, incrementing major version 2020-09-03 11:59:46 -04:00
Chris Cameron
8625f0a3a4 Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7 2020-09-03 11:58:28 -04:00
Chris Cameron
09516d2f11 chore: Updating changelog 2020-09-03 11:57:58 -04:00
Laura Gomez
76591155d3 test: Fixed ScrollQueueTest after fixing deadlock bug 2020-09-03 11:54:30 -04:00
Chris Cameron
caa4878a37 feat: Adding dequeue overload to ScrollSqueue 2020-09-01 12:06:29 -04:00
Chris Cameron
a5d3a7c19d fix: Simplifying IcdErrorLog, fixed formatting on 4-Series processors 2020-08-31 16:43:44 -04:00
Chris Cameron
55457253b2 fix: Splitting runtime environment SimplSharpProMono into SimplSharpProServer and fixing usages 2020-08-31 16:43:13 -04:00
Chris Cameron
b8722af752 fix: Fixed 4-series version string date parsing error 2020-08-31 14:15:40 -04:00
Chris Cameron
bf8c320d66 feat: Added util methods for removing duplicate whitespace 2020-08-31 13:37:38 -04:00
Chris Cameron
28f4818ca3 fix: Fixed "version" regex for 4-series 2020-08-31 12:03:51 -04:00
Chris Cameron
00c876be7a feat: Replaced Crestron Unzip with Yallie Unzip 2020-08-31 12:03:46 -04:00
Austin Noska
1a0ea4119e feat: Add property to IcdEnvironment to determine if SSL communication is enabled 2020-08-21 12:09:16 -04:00
Chris Cameron
0ece381939 Merge remote-tracking branch 'origin/ConnectPro_v1.7' into ConnectPro_v1.8 2020-08-21 12:06:54 -04:00
Chris Cameron
ffeb313456 Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-08-21 12:06:14 -04:00
Chris Cameron
aeba163a0f chore: Updating changelog, incrementing patch version 2020-08-21 12:04:48 -04:00
Chris Cameron
49a154ebed fix: Removed the OnItemTrimmed event from the ScrollQueue due to deadlocks 2020-08-21 12:04:35 -04:00
Chris Cameron
4e1ed312a5 Merge remote-tracking branch 'origin/ConnectPro_v1.7' into ConnectPro_v1.8 2020-08-17 10:17:51 -04:00
Chris Cameron
3316ef9343 Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7 2020-08-17 10:16:58 -04:00
Chris Cameron
5ca76f7e7e Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6 2020-08-17 10:16:05 -04:00
Chris Cameron
66b8107233 Merge remote-tracking branch 'origin/ConnectPro_v1.4' into ConnectPro_v1.5 2020-08-17 10:15:39 -04:00
Chris Cameron
dd6dfa191e Merge remote-tracking branch 'origin/ConnectPro_v1.3' into ConnectPro_v1.4 2020-08-17 10:15:06 -04:00
Chris Cameron
5aa8b15472 Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-08-17 10:12:13 -04:00
Chris Cameron
c6cfdd4d72 chore: Updating changelog, incrementing patch version 2020-08-17 10:09:58 -04:00
Chris Cameron
ab699406a6 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-08-17 10:08:10 -04:00
Chris Cameron
15330d7dd0 chore: Updating changelog, incrementing patch version 2020-08-17 10:03:30 -04:00
Chris Cameron
34cfe8c7a3 fix: Workaround for logged XML format exceptions when failing to parse floats 2020-08-17 10:01:58 -04:00
Drew Tingen
6d93911766 chore:changelog 2020-08-13 22:44:44 -04:00
Drew Tingen
8dd8d48a8b fix: Fixed cultureinfo sqlite connection for 4 series compatability 2020-08-13 22:41:31 -04:00
Drew Tingen
c8edac0f14 feat: Add extensions to raise events for common event args 2020-08-03 17:59:41 -04:00
Laura Gomez
00a75c6d72 feat: Adding Extensions methods in order to handle the switching of the animations. 2020-08-03 16:15:05 -04:00
Chris Cameron
75404e8b20 Merge remote-tracking branch 'origin/ConnectPro_v1.7' into ConnectPro_v1.8 2020-07-29 10:24:18 -04:00
Chris Cameron
a9f1c57d1e Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7 2020-07-29 10:21:55 -04:00
Chris Cameron
27bb1e3482 Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6 2020-07-29 10:17:41 -04:00
Chris Cameron
6173be0a1d Merge remote-tracking branch 'origin/ConnectPro_v1.4' into ConnectPro_v1.5 2020-07-29 10:17:03 -04:00
Chris Cameron
66502d3617 Merge remote-tracking branch 'origin/ConnectPro_v1.3' into ConnectPro_v1.4 2020-07-29 10:16:24 -04:00
Chris Cameron
0db03f7fdf Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
2020-07-29 10:15:58 -04:00
Chris Cameron
a74cdc5614 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-07-29 10:14:02 -04:00
Drew Tingen
7f306801b3 chore: Updating changelog, incremeting patch version 2020-07-29 10:01:43 -04:00
Austin Noska
51ec3dd8ff docs: Update changelog 2020-07-28 18:09:00 -04:00
Austin Noska
7cc8359284 fix: Check if any & all characters in a string is a digit instead of just all 2020-07-28 17:31:41 -04:00
Chris Cameron
7ece973c2f fix: Workaround for logged XML format exceptions when failing to parse floats 2020-07-24 13:42:11 -04:00
Chris Cameron
d7e890d6c3 refactor: Removing redundant method 2020-07-17 13:57:38 -04:00
Chris Cameron
816f8984be feat: Added Collection extensions for setting and adding ranges of items 2020-07-16 12:13:57 -04:00
Drew Tingen
449bd41cb3 feat: Adding GetPropertyInfo test 2020-07-14 14:38:03 -04:00
Drew Tingen
8b53700c58 refactor: Use new property get/set extensions 2020-07-14 14:16:46 -04:00
Drew Tingen
6d5eb07b1f chore: changelog 2020-07-14 14:09:12 -04:00
Drew Tingen
67445de8b9 feat: PropertyInfo extensions in 2008 to mimic overloads in NetStandard 2020-07-14 14:07:17 -04:00
Laura Gomez
e093a57172 refactor : supporting feature where sleeptime changes due to a meeting. 2020-07-14 13:29:46 -04:00
Laura Gomez
878784586f refactor : refactored Repeater for easier implementation in other classes. 2020-07-14 13:29:46 -04:00
Drew Tingen
c6b2cd78cc fix: fixing 2008 compatibiltiy issues 2020-07-14 13:27:03 -04:00
Chris Cameron
5d9369b582 chore: Updating changelog, incrementing minor version 2020-07-14 13:21:37 -04:00
Drew Tingen
a822bc406b feat: Tests for GetProperty and SetProperty 2020-07-14 13:18:08 -04:00
Drew Tingen
c6a755f080 feat: Added GetPropertyInfo for properties at paths 2020-07-14 13:17:38 -04:00
Drew Tingen
21c68905d0 fix: Fix get/set property extensions to work with deep properties 2020-07-14 13:16:54 -04:00
Chris Cameron
4bbf0aec37 refactor: Reflection extension methods work in S# 2020-07-09 13:20:21 -04:00
Drew Tingen
0a87c4efe7 chore: update changelog 2020-07-07 21:31:34 -04:00
Drew Tingen
9882febede feat: Adding CallMethod reflection extensions 2020-07-07 21:31:33 -04:00
Drew Tingen
80b1412632 chore: changelog 2020-07-07 21:31:32 -04:00
Drew Tingen
a1d480d24b chore: documentation update 2020-07-07 21:31:32 -04:00
Drew Tingen
9c0d6a87df feat: Get and Set property extensions using reflection - NetStandard only (for now) 2020-07-07 21:31:31 -04:00
Chris Cameron
0da0c41fe2 chore: ObfuscationSettings are compiled 2020-07-06 15:52:17 -04:00
Chris Cameron
f8030a45f4 fix: Obfuscation attributes NEED to be in the System.Reflection namespace to work 2020-07-06 15:52:00 -04:00
Chris Cameron
48ff54de82 test: Adding test case for minimal interfaces 2020-07-02 14:32:11 -04:00
Chris Cameron
99945b41a4 fix: Fixing DHCP status return type and Hostnames property name 2020-07-02 13:42:52 -04:00
Chris Cameron
d31b698cea fix: Fixing error message 2020-06-30 17:08:36 -04:00
Austin Noska
5212cb9a7a feat: Add overload methods for MaxOrDefault & MinOrDefault that take a selector function as an argument 2020-06-29 11:51:58 -04:00
Austin Noska
ee670487dd feat: Added AggregateOrDefault extension method 2020-06-29 11:51:46 -04:00
Chris Cameron
4f34b3da7c feat: Added attributes for controlling obfuscation 2020-06-26 14:06:58 -04:00
Chris Cameron
9bf0a9b8a5 chore: Updating changelog, incrementing major version 2020-06-18 13:57:39 -04:00
Chris Cameron
f7b35e64ec feat: Added extension method for getting the EventArgs type for a given EventInfo 2020-06-05 12:26:25 -04:00
Chris Cameron
bfab3c77b0 feat: Adding extesion methods for reading a JSON token as a float or a double 2020-06-05 12:25:52 -04:00
Chris Cameron
4a68c0caad refactor: Tidying ILoggerService interface 2020-06-04 14:12:55 -04:00
Chris Cameron
07ee6ce586 fix: Deadlock detection works better for false positives 2020-06-04 14:11:48 -04:00
Chris Cameron
6f5deaf1ea feat: Added dictionary extension for removing a key and outputting the value 2020-06-04 13:23:14 -04:00
Chris Cameron
3da9b23e12 feat: Adding simple IGenericEventArgs interface 2020-06-03 16:14:43 -04:00
Chris Cameron
9deafaec9b feat: JSON conversion improvements for log items 2020-06-01 11:35:41 -04:00
Chris Cameron
28ea05e2f6 feat: Standardizing JSON Type conversion 2020-06-01 10:27:42 -04:00
Chris Cameron
f53d05936c fix: Better NiceName implementation, handles more cases of syntax, whitespace and punctuation 2020-05-28 16:21:12 -04:00
Chris Cameron
4339f02698 refactor: JSON DateTime cleanup 2020-05-28 13:46:49 -04:00
Chris Cameron
25fb5a0ad8 fix: Another round of JSON DateTime fixes 2020-05-27 19:38:04 -04:00
Chris Cameron
6240d3fccf Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7 2020-05-27 16:04:13 -04:00
Chris Cameron
88ff67b356 Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6 2020-05-27 16:02:50 -04:00
Chris Cameron
1d0ba453e3 Merge branch 'ConnectPro_v1.4' into ConnectPro_v1.5 2020-05-27 15:59:53 -04:00
Chris Cameron
121d267aad Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4 2020-05-27 15:59:40 -04:00
Chris Cameron
f23b051c3a Merge branch 'ConnectPro_v1.2' into ConnectPro_v1.3 2020-05-27 15:59:27 -04:00
Chris Cameron
b5ec51d9a4 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-05-27 15:59:12 -04:00
Chris Cameron
62f54f1213 chore: Updating changelog, incrementing patch version 2020-05-27 15:56:22 -04:00
Drew Tingen
dd3c0f530b chore: Changelog 2020-05-27 11:28:12 -04:00
Drew Tingen
fc74865c5b feat: Use CrestronEnvironment.SystemInfo.SerialNumber to retrieve the serial number, instead of trying to convert TSID from console. 2020-05-27 11:25:14 -04:00
Drew Tingen
4de7944286 fix: temp fix for 4-series shenanagans 2020-05-26 11:22:47 -04:00
Chris Cameron
dbad18925f feat: Clarifying which culture failed to load when throwing an exception 2020-05-26 11:18:58 -04:00
Chris Cameron
1a027bcea0 chore: Updating changelog 2020-05-26 10:25:22 -04:00
Chris Cameron
7053faede1 feat: Serializing JSON DateTimes to ISO-8601 2020-05-22 17:55:53 -04:00
Chris Cameron
582cbe9157 fix: Temp fix for annoying CompiledOn DateTime parsing bug 2020-05-21 13:59:09 -04:00
Chris Cameron
00803fcd66 Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7
# Conflicts:
#	CHANGELOG.md
2020-05-19 10:50:55 -04:00
Chris Cameron
9912097a33 chore: Updating changelog, incrementing minor version 2020-05-19 10:48:55 -04:00
Drew Tingen
cad3cf60cf chore: changelog 2020-05-18 15:27:51 -04:00
Drew Tingen
0431b5afe4 feat: DateTimeNullableEventArgs 2020-05-18 15:27:01 -04:00
Chris Cameron
d1c21ae7b4 fix: TableBuilder no longer draws redundant separators 2020-05-12 10:24:42 -04:00
Chris Cameron
f34e307a93 feat: Added method for combining GUIDs to make deterministic GUIDs 2020-05-11 10:11:56 -04:00
Drew Tingen
2ad9adf86c feat: ScrollQueue - added OnItemTrimmed event 2020-05-07 18:16:54 -04:00
Chris Cameron
bbb09666dd fix: Hack to catch System.Reflection constructor invocation exceptions on crestron 2020-05-04 18:36:59 -04:00
Chris Cameron
dd3c6b13fd Merge remote-tracking branch 'origin/ConnectPro_v1.6' into ConnectPro_v1.7 2020-05-01 13:30:26 -04:00
Chris Cameron
f9dccd30e5 Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6 2020-04-30 21:49:38 -04:00
Chris Cameron
db0029bbc1 Merge remote-tracking branch 'origin/ConnectPro_v1.4' into ConnectPro_v1.5 2020-04-30 21:29:50 -04:00
Chris Cameron
a5289e01f7 Merge remote-tracking branch 'origin/ConnectPro_v1.3' into ConnectPro_v1.4 2020-04-30 19:38:47 -04:00
Chris Cameron
9de5acfbe7 Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3
# Conflicts:
#	ICD.Common.Utils/ProgramUtils.SimplSharp.cs
2020-04-30 18:49:14 -04:00
Chris Cameron
a22c3626ab Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-04-30 15:16:23 -04:00
Chris Cameron
d90c60126e chore: Updating changelog, incrementing minor version 2020-04-30 13:02:14 -04:00
Drew Tingen
49d12d454f fix: Program and Processor utils actually return DateTimes for date properties 2020-04-30 12:58:23 -04:00
Chris Cameron
760ab259fa feat: Adding MathUtils.Clamp overload for bytes 2020-04-23 10:20:02 -04:00
Chris Cameron
40e00e0ab7 feat: Adding methods for reading DateTimes from XML 2020-04-20 16:09:20 -04:00
Chris Cameron
64405a1cd6 feat: Adding overloads for reading XML attributes as GUIDs 2020-04-18 18:57:13 -04:00
Chris Cameron
ffb217839c fix: Cleaning up TimeSpan.ToReadableString() output 2020-04-18 12:29:13 -04:00
Chris Cameron
0d8dbf4a30 feat: Added methods for getting user data paths 2020-04-14 16:13:13 -04:00
Chris Cameron
79344a3667 refactor: Reworking EnumUtils to rely less on casting back and forth to int, added method for getting enum names 2020-04-13 14:50:29 -04:00
Chris Cameron
5e61098e71 feat: Added extension method for dynamically converting a sequence to a generic list of the given item type 2020-04-13 14:50:29 -04:00
Jack Kanarish
e0663bdbfd core telemetry initial commit 2020-04-09 14:46:28 -04:00
Chris Cameron
96946d6323 refactor: Rewrote JsonItemWrapper serialization for JsonConvert friendliness 2020-04-09 12:21:42 -04:00
Chris Cameron
5067f5fdb3 feat: Added Type extension method for getting inner generic types 2020-04-06 13:11:05 -04:00
Chris Cameron
d002dda568 fix: Fixing null parameter exception in TableBuilder 2020-04-06 13:09:34 -04:00
Chris Cameron
08aeba756a feat: Added extension method for determining if a type is Anonymous 2020-04-01 13:58:03 -04:00
Chris Cameron
b29ae4c8c8 perf: Potential optimization when searching for Constructors/Methods 2020-03-27 14:50:02 -04:00
Chris Cameron
c1418ae4e2 feat: Adding Move method to IcdFile 2020-03-27 14:47:41 -04:00
Chris Cameron
5978d492cf feat: Added eIcdFileMode for IO platform agnosticism 2020-03-27 13:54:29 -04:00
Chris Cameron
a1775b281f feat: TableBuilder supports multi-line content 2020-03-26 14:16:40 -04:00
Chris Cameron
75ddc37cf1 feat: Added ToCollection extension method for copying an enumerable to a new collection 2020-03-23 16:35:16 -04:00
Chris Cameron
d07373b69e chore: Updating changelog, incrementing major version 2020-03-20 13:04:11 -04:00
Laura Gomez
3ebfa76970 feat : Added ToPrivateString Method to convert password into special characters for privacy. 2020-03-17 18:47:46 -04:00
Chris Cameron
ac5da50e98 feat: Added IsDistinct extension method 2020-03-16 10:07:15 -04:00
Chris Cameron
6c6d272511 feat: Added MinOrDefault extension method 2020-03-16 10:04:23 -04:00
Chris Cameron
022e625143 fix: Fixed a bug where table width calculations were not considering unprintable characters 2020-03-15 15:51:05 -04:00
Chris Cameron
b496594cd6 test: Using UTC in unit tests 2020-03-11 15:36:21 -04:00
Chris Cameron
e99a7f313f fix: Using UTC for tracking durations 2020-03-11 13:02:34 -04:00
Chris Cameron
ed2cf84a7e fix: Using UTC for tracking scheduled events 2020-03-10 13:39:38 -04:00
Chris Cameron
91684f25f2 refactor: Tidying 2020-03-04 14:50:38 -05:00
Chris Cameron
be5024271f chore: Fixing comments 2020-03-03 17:41:02 -05:00
Chris Cameron
dd90227ca1 fix: Resolving warning 2020-03-03 17:31:56 -05:00
Chris Cameron
2fa6ff3de6 fix: Fixing TableBuilder spacing for Net Standard 2020-03-03 15:57:57 -05:00
Chris Cameron
311d63204f refactor: Tidying 2020-02-28 12:24:04 -05:00
Chris Cameron
82d0598352 feat: AnsiUtils exposes ANSI codes 2020-02-28 11:27:39 -05:00
Chris Cameron
4229a6a73f chore: Exluding build directory from test project 2020-02-28 11:27:09 -05:00
Chris Cameron
f5c6b64ab7 fix: Fixing bugs in AnsiUtils color conversion 2020-02-26 12:25:25 -05:00
Chris Cameron
3f62e7e929 refactor: Splitting ANSI into codes and texts, instead of converting straight to HTML 2020-02-25 19:06:34 -05:00
Chris Cameron
a82645e902 feat: Console uses unicode for table drawing on Net Standard 2020-02-24 17:57:43 -05:00
Chris Cameron
985578985a feat: Simplifying ANSI color methods, better cross-platform color support 2020-02-21 21:53:27 -05:00
Chris Cameron
c453717998 feat: First attempt at an ANSI to HTML converter 2020-02-19 16:52:21 -05:00
Chris Cameron
fde3106389 refactor: Tidying 2020-02-19 13:48:04 -05:00
Chris Cameron
94265b1915 Merge branch 'ConnectPro_v1.5' into ConnectPro_v1.6 2020-02-18 13:01:11 -05:00
Chris Cameron
9b3294382f Merge branch 'ConnectPro_v1.4' into ConnectPro_v1.5
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 13:00:59 -05:00
Chris Cameron
d59eb00d6b Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 13:00:27 -05:00
Chris Cameron
d051ddb098 Merge branch 'ConnectPro_v1.2' into ConnectPro_v1.3
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 12:59:56 -05:00
Chris Cameron
a53ad74811 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 12:59:18 -05:00
Chris Cameron
69eb4b3d34 chore: Updating changelog, incrementing patch version 2020-02-18 12:13:00 -05:00
Drew Tingen
8e5486e1ef chore: Changelog 2020-02-14 23:56:56 -05:00
Drew Tingen
ecf7e626f3 fix: IcdTimer fix issue that prevents OnElapsed callback from firing when Length is less than (or close to) Heartbeat Interval 2020-02-14 23:55:32 -05:00
Chris Cameron
3b5c9ed51b fix: Fixed a bug where color formatted console output on Net Standard was not raising the OnConsolePrint event 2020-02-12 16:59:40 -05:00
Jeffery Thompson
e2646194b8 chore: changelog 2020-02-11 11:33:12 -05:00
Jeffery Thompson
0adad154c6 feat: add extensions for getting JsonReader value as long or ulong 2020-02-11 11:32:03 -05:00
Jeffery Thompson
0b8eb82e3b feat: add methods for creating a DateTime from epoch seconds or millis 2020-02-11 11:31:42 -05:00
Chris Cameron
13d1072d10 feat: Adding shims for converting DateTimes to/from XML 2020-02-03 16:32:04 -05:00
Chris Cameron
8d2321c350 refactor: Removing redundant code 2020-02-03 16:32:02 -05:00
Chris Cameron
55f494e2f5 Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6 2020-02-03 16:31:43 -05:00
Chris Cameron
859a2b0830 Merge remote-tracking branch 'origin/ConnectPro_v1.4' into ConnectPro_v1.5 2020-02-03 16:31:03 -05:00
Chris Cameron
9d5dfb3b64 Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4
# Conflicts:
#	ICD.Common.Utils/Extensions/DictionaryExtensions.cs
2020-02-03 16:30:18 -05:00
Chris Cameron
c60acf52ba Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3 2020-02-03 16:27:54 -05:00
Chris Cameron
311bf683e0 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Extensions/DictionaryExtensions.cs
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-03 16:12:26 -05:00
Chris Cameron
d025946948 chore: Updating changelog, incrementing minor version 2020-01-23 12:46:06 -05:00
Chris Cameron
b74d2c9d60 fix: Adding PriorityQueue EnqueueRemove overload for backwards compat 2020-01-23 12:44:08 -05:00
Jack Kanarish
ac4c0eccc9 feat: add ability to select when de-duplication should queue at the end of the queue, or at the first occurance
# Conflicts:
#	ICD.Common.Utils/Collections/PriorityQueue.cs
2020-01-23 11:44:31 -05:00
Jeffery Thompson
0cae292899 chore: changelog 2020-01-22 14:45:13 -05:00
Jeffery Thompson
9cdc8b26a2 fix: catch PlatformNotSupportedException for linux systems 2020-01-22 14:43:27 -05:00
Chris Cameron
80786dd84c Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-01-21 11:15:18 -05:00
Chris Cameron
bf8061046b chore: Updating changelog, incrementing minor version 2020-01-20 11:30:45 -05:00
Chris Cameron
201639b30b fix: Skip over invalid adapter ids when getting network information 2020-01-17 11:11:32 -05:00
Chris Cameron
89f0214cce fix: Ignoring Crestron ethernet parameters that say "Invalid Value" 2020-01-16 15:51:05 -05:00
Chris Cameron
49f8f116fd feat: Simplifying network interfaces, enumerating all adapter types
# Conflicts:
#	CHANGELOG.md
2020-01-16 15:49:40 -05:00
Laura Gomez
7598a451cc chore: XmlConverterAttribute is decorated as implicit 2020-01-14 14:08:32 -05:00
Laura Gomez
f03f49b376 fix: IcdXmlConvert supports serializing arrays of different items 2020-01-14 14:08:06 -05:00
Jack Kanarish
da4415a11c chore: changelog 2020-01-09 14:00:19 -05:00
Jack Kanarish
67c07b8833 feat: make get values public 2020-01-09 14:00:18 -05:00
Austin Noska
11c4d10a51 feat: added not null tag to ICDUriBuilder constructor that takes a Uri as an argument. 2020-01-06 12:54:02 -05:00
Chris Cameron
d1ec8a45d1 Merge branch 'ConnectPro_v1.5' into ConnectPro_v1.6 2020-01-06 10:30:00 -05:00
Chris Cameron
352121e25c Merge branch 'ConnectPro_v1.4' into ConnectPro_v1.5 2020-01-06 10:29:45 -05:00
Chris Cameron
0d5ee31d61 Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4 2020-01-06 10:28:48 -05:00
Chris Cameron
ec7004e053 Merge branch 'ConnectPro_v1.2' into ConnectPro_v1.3 2020-01-06 10:28:39 -05:00
Chris Cameron
ea0bcec2c3 Merge branch 'ConnectPro_v1.1' into ConnectPro_v1.2 2020-01-06 10:28:31 -05:00
Chris Cameron
55bf458a2b test: Fixing PriorityQueue unit tests 2020-01-06 10:28:03 -05:00
Chris Cameron
7562dddeff chore: Updating changelog 2020-01-06 09:50:08 -05:00
Laura Gomez
f66ddc7e03 refactor: cleaned up code. 2020-01-03 15:28:16 -05:00
Laura Gomez
b5fc25de7c feat: Added WriteAllByte method to IcdFile class. 2020-01-03 15:27:48 -05:00
Chris Cameron
d4ef4c3e1a feat: Added utils for building paths in the HTML directory 2020-01-03 14:17:13 -05:00
Chris Cameron
2a8a936b6f chore: Updating AssemblyInfo 2020-01-03 10:28:27 -05:00
Chris Cameron
bbe596c116 feat: Added methods for serializing an XML array 2019-12-13 12:21:41 -05:00
Laura Gomez
7689ffc3c8 feat: creating deserializItem method. Making xml changes. 2019-12-12 15:39:27 -05:00
Jeffery Thompson
1ab247f204 chore: changelog 2019-12-12 15:27:05 -05:00
Jeffery Thompson
5b5ee258ca chore: comments 2019-12-12 15:23:44 -05:00
Jeffery Thompson
4695a80575 feat: add DateTime extensions for add and wrap, like TimeSpan 2019-12-12 14:58:00 -05:00
Chris Cameron
79a98d8c10 feat: Added enum extensions for finding the inclusion and exclusion of enum flags 2019-12-05 15:31:20 -05:00
Chris Cameron
b68c5f1c97 feat: Added MathUtils methods for converting to and from percentages 2019-12-04 11:53:44 -05:00
Chris Cameron
3deec98f44 chore: Updating changelog, incrementing minor version 2019-12-04 11:51:18 -05:00
Chris Cameron
eb52b164bf feat: Added shim methods for finding closest DateTimes from a sequence 2019-11-19 17:08:21 -05:00
Chris Cameron
fb8abe2aa4 chore: Updating changelog, incrementing minor version 2019-11-18 14:17:31 -05:00
Chris Cameron
f61305856f refactor: Simplifying reflection code, potential micro-optimization 2019-11-14 11:24:10 -05:00
Chris Cameron
de00acbf79 feat: Adding extension method for getting max value from a sequence, otherwise a default value 2019-11-12 17:12:20 -05:00
Chris Cameron
5ffca5e7a3 feat: Adding overload for determining if a sorted list contains an item by a given predicate 2019-11-08 14:57:27 -05:00
Chris Cameron
2037c990b2 feat: Method for determining if a URI is default 2019-11-07 19:22:52 -05:00
Chris Cameron
13a2493f4c feat: Adding methods to get the data directory for a given room 2019-11-06 14:34:47 -05:00
Chris Cameron
09e0a20443 fix: IcdSqliteConnection CreateFile method will make directories recursively 2019-11-05 16:19:32 -05:00
Chris Cameron
7870d2c375 feat: Added method for getting a path in the ProgramData directory 2019-11-05 16:18:24 -05:00
Laura Gomez
7cf3d18127 feat: Adding CompareTo method wich helped with validation cheking on DeploymentTool. 2019-10-30 10:13:15 -04:00
Chris Cameron
f39b3897fc Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4 2019-10-29 14:58:27 -04:00
Chris Cameron
ab2fab0b3a Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3 2019-10-29 14:58:19 -04:00
Chris Cameron
9b69b2a712 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-10-29 14:57:38 -04:00
Chris Cameron
0a1f637b45 chore: Updating changelog, incrementing patch version 2019-10-29 14:52:36 -04:00
Chris Cameron
e0ace12ef9 Merge pull request #43 from Utils fix/SerialQueueFix
Fix/SerialQueueFix
2019-10-29 14:33:28 -04:00
Jack Kanarish
9f1541f843 chore: update changelog 2019-10-29 14:19:58 -04:00
Jack Kanarish
b9f5349055 fix: fix an issue where commands would collapse to the point of the last deleted command instead of the position in queue where the new command was going 2019-10-29 14:18:45 -04:00
Chris Cameron
0c7f82835c fix: Fixing Net Standard build 2019-10-15 14:06:37 -04:00
Chris Cameron
41755cb472 refactor: Adding NotNull attributes to collections 2019-10-09 10:47:29 -04:00
Chris Cameron
238d6518ab refactor: Adding NotNull attributes to RangeAttribute 2019-10-09 10:15:47 -04:00
Chris Cameron
89cde5c9a0 chore: Decorating extension methods with NotNull and CanBeNull attributes 2019-10-07 21:59:21 -04:00
Chris Cameron
38204314e7 chore: Updating changelog, incrementing major version 2019-10-07 11:56:23 -04:00
Chris Cameron
9e8cedfbfa feat: Overload for Modulus taking long params 2019-09-30 11:52:02 -04:00
Chris Cameron
52229c1472 feat: Adding AreOrdered enumerable extension methods 2019-09-30 11:51:20 -04:00
Drew Tingen
38c24d42a7 feat: GetUtcTime() 2019-09-30 11:50:42 -04:00
Chris Cameron
cff1ec8d7e feat: Initial commit of NullObject 2019-09-25 13:52:20 -04:00
Chris Cameron
5a64a6c269 refactor: Tidying 2019-09-25 13:52:02 -04:00
Chris Cameron
68d98021a5 perf: Micro-optimization for copying arrays 2019-09-23 11:43:54 -04:00
Chris Cameron
0e16606d75 feat: Additional binary search extensions, AddSorted methods renamed to InsertSorted 2019-09-23 11:43:43 -04:00
Chris Cameron
602f170091 fix: Moving SafeCriticalSection Enters outside of tryf block, don't want to Leave if the Enter fails 2019-09-20 10:01:07 -04:00
Laura Gomez
aae8bc5323 feat: Adding default implementation for AbstractGenericXmlConverter Instantiate method 2019-09-16 15:15:35 -04:00
Chris Cameron
11004085c5 chore: Updating changelog, incrementing minor version 2019-09-16 14:44:07 -04:00
Chris Cameron
6ca015a561 Merge branch 'feat/ProgramDataPath' of Common/Utils into dev 2019-09-16 18:19:58 +00:00
Drew Tingen
73b1c4819c chore: Update changelog 2019-09-16 14:10:45 -04:00
Drew Tingen
f913af6efe Merge remote-tracking branch 'origin/dev' into feat/ProgramDataPath 2019-09-16 14:05:48 -04:00
Drew Tingen
099517df7d feat: Adding program data path to PathUtils 2019-09-16 14:00:47 -04:00
Chris Cameron
6a7b58f50f docs: Updating changelog 2019-09-14 11:23:19 -04:00
Chris Cameron
2273d5b3a1 refactor: Removing unused code 2019-09-14 11:23:09 -04:00
Chris Cameron
aa17f29305 feat: Adding BinarySearch extension method for ILists 2019-09-13 16:35:38 -04:00
Chris Cameron
e65578584a docs: Updating changelog 2019-09-10 17:19:28 -04:00
Chris Cameron
96d2df8871 feat: Added CultureInfo extensions for converting between 12 hour and 24 hour time formatting 2019-09-10 17:19:00 -04:00
Chris Cameron
b4d82a855e feat: Added a dictionary extension method for getting or adding a new value via func 2019-09-10 17:18:12 -04:00
Chris Cameron
83bc344ab3 feat: Added an event that is raised when the system time is set 2019-09-10 17:17:09 -04:00
Chris Cameron
0821dcb3ca fix: Fixed a bug where CultureInfo was not being cloned correctly 2019-09-10 17:16:31 -04:00
Chris Cameron
b6f64bb9b2 Merge branch 'fix/ModulusRename' of Common/Utils into dev 2019-09-09 19:54:24 +00:00
Drew Tingen
6ae110a997 Merge remote-tracking branch 'origin/dev' into fix/ModulusRename 2019-09-09 15:38:56 -04:00
Chris Cameron
efdb48f2c3 Merge branch 'fix/programdata-path' of Common/Utils into ConnectPro_v1.4 2019-09-09 19:33:32 +00:00
Drew Tingen
9d02ee0022 fix: Fixing MathUtilsTest after rename 2019-09-09 15:33:31 -04:00
Austin Noska
8c0416f70e docs: updating changelog 2019-09-09 15:28:03 -04:00
Austin Noska
0f27d68edf fix: Net Standard: the Root Config Path is now ICD.Connect in the current environments ProgramData directory 2019-09-09 15:25:35 -04:00
Drew Tingen
f8fc68e08f chore: remarks explaining method name limitations 2019-09-09 15:17:32 -04:00
Drew Tingen
fc4ae67e40 chore: changelog slightly more specific 2019-09-09 15:16:23 -04:00
Drew Tingen
0f618198b5 fix: Rename "Mod" to "Modulus" to keep S+ from throwing a fit 2019-09-09 15:06:39 -04:00
Chris Cameron
9a6f197aa0 feat: Added TimeSpan extension methods for cycling hours and minutes without modifying the day 2019-09-09 10:07:08 -04:00
Chris Cameron
45ee3e70b0 feat: Added mod method to MathUtils 2019-09-09 10:06:08 -04:00
Chris Cameron
b09f614ef5 feat: Added a method for determining if a culture uses 24 hour format 2019-09-04 14:31:16 -04:00
Chris Cameron
027c9ffe82 refactor: Changed DateTime extension method to a simple util method 2019-09-04 14:30:45 -04:00
Chris Cameron
dc1b60e629 feat: Added an extension method for getting the hour in 12 hour format 2019-09-04 12:36:54 -04:00
Chris Cameron
091ad10068 test: Updating test framework version 2019-09-03 16:09:03 -04:00
Chris Cameron
71bb320057 chore: Updating changelog, incrementing minor version 2019-09-03 10:52:19 -04:00
Chris Cameron
e6b0fd5f7b Merge remote-tracking branch 'origin/feat/xml-array' into ConnectPro_v1.4 2019-09-03 10:27:42 -04:00
Chris Cameron
2a2bff2e92 Merge branch 'feat/uptime-utils' of Common/Utils into ConnectPro_v1.4 2019-09-03 14:02:26 +00:00
Austin Noska
9c07b3da04 docs: updating changelog 2019-08-30 17:21:17 -04:00
Austin Noska
438b3d48e4 feat: Implemented Processor Utils for Net Standard to get the system uptime and the program uptime. 2019-08-30 17:19:17 -04:00
Austin Noska
629ceec84e feat: Added Public API Property to get the program install date based on the creation date of core dll file for Net Standard and SimplSharp 2019-08-30 17:18:18 -04:00
Chris Cameron
bb41d59a4b feat: Adding methods for deserializing an XML array of items 2019-08-29 17:21:57 -04:00
Chris Cameron
c23d81e023 chore: Updating nuget packages 2019-08-29 14:13:55 -04:00
Chris Cameron
18abe78550 feat: Better handling of JSON DateTimes in Net Standard 2019-08-27 15:01:09 -04:00
Chris Cameron
f33218f7a6 chore: Updating nuget packages 2019-08-22 17:17:35 -04:00
Chris Cameron
4938dad882 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.4
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-08-22 10:42:57 -04:00
Chris Cameron
5900f5974b chore: Updating changelog, incrementing patch version 2019-08-22 10:41:00 -04:00
Drew Tingen
81f7eb9c66 Merge branch 'fix/ordered-dict' of Common/Utils into MetLife_v5.4.3 2019-08-22 14:30:40 +00:00
Chris Cameron
440c1c62f1 fix: Fixed a bug with the IcdOrderedDict index setter that was creating additional values 2019-08-22 10:17:32 -04:00
Chris Cameron
63b590a9ea feat: ToStringJsonConverter rethrows the inner exception for TargetInvocationExceptions 2019-08-20 15:40:01 -04:00
Chris Cameron
f8c88630fc fix: Fixed a bug where ANSI color encoded strings with percentages were being scrambled 2019-08-20 15:34:40 -04:00
Chris Cameron
3f1f9611ec chore: Updating changelog, incrementing minor version 2019-08-15 11:02:18 -04:00
Chris Cameron
47c611a0b4 Merge remote-tracking branch 'origin/MetLife_v5.4.3' into dev 2019-08-15 10:57:50 -04:00
Chris Cameron
e388f35efb Revert "fix: fix for logging deadlock, use mutexes, add logging for last message sent."
This reverts commit 7c238b9fef.
2019-08-15 10:56:34 -04:00
Jack Kanarish
89061b5cbf feat: add unit test for timer 2019-08-07 20:47:54 -04:00
Chris Cameron
ff6f15d3ef fix: Potential JSON under-read fix 2019-08-07 17:34:07 -04:00
Drew Tingen
02e6fe9f8c chore: formatting 2019-08-07 13:30:55 -04:00
Drew Tingen
edb5534b9d Merge remote-tracking branch 'origin/fix/json-dict' into KrangAtHome 2019-08-07 13:28:26 -04:00
Drew Tingen
6af3e5b2ff fix: Reflection - throw inner exception for parameterless constructors that throw exceptions 2019-08-07 13:28:11 -04:00
Chris Cameron
65f76402cc feat: Serializing both keys and values to JSON when serializing dicts 2019-08-07 13:02:18 -04:00
Chris Cameron
5700cf4ce2 feat: Re-adding missing util method for getting class attributes 2019-08-01 09:24:17 -04:00
Jack Kanarish
7c238b9fef fix: fix for logging deadlock, use mutexes, add logging for last message sent. 2019-07-31 16:22:05 -04:00
Laura Gomez
6eda848410 feat: Initial commit of EmailValidation class 2019-07-31 11:47:52 -04:00
Laura Gomez
7b44867f34 docs: updating changelog 2019-07-30 13:38:37 -04:00
Laura Gomez
149f480add fix: Fixing JSON datetime parsing in 2017 2019-07-30 12:16:29 -04:00
Austin Noska
0f5632ced8 refactor: changed public method to private as it is only being used from within EnumUtils 2019-07-18 11:37:33 -04:00
Chris Cameron
9df5f7ae37 feat: Clarifying method usage 2019-07-12 17:17:05 -04:00
Laura Gomez
6e056c9dcc feat: Added util extension method for converting a DateTime to a Unix timestamp 2019-07-12 13:57:52 -04:00
Chris Cameron
7add461a1a Merge branch 'feat/log-timestamps' of Common/Utils into ConnectPro_v1.3 2019-07-11 14:44:37 +00:00
Austin Noska
cb3677bd72 docs: updating changelog 2019-07-11 10:39:26 -04:00
Austin Noska
69ad4bb240 feat: Added timestamps to logs for non Simplsharp programs 2019-07-11 10:23:17 -04:00
Chris Cameron
1a868d5a7d chore: Updating changelog, incrementing minor version 2019-07-03 10:22:01 -04:00
Laura Gomez
bb6110931a feat : added a StartofDay and EndofDay DateTime methods. 2019-07-02 16:28:29 -04:00
Chris Cameron
909ebfbc97 fix: Throwing an exception when trying to read non-primitive JSON tokens as string 2019-07-01 17:07:50 -04:00
Chris Cameron
3d068aeb68 fix: Potential fix for errant '?' characters in URIs 2019-06-28 11:22:23 -04:00
Chris Cameron
1f6915a825 Merge branch 'feat/GetCliqueOptimization' of Common/Utils into ConnectPro_v1.3 2019-06-27 15:02:00 +00:00
Austin Noska
00e7fd6a6b docs: updating changelog 2019-06-27 11:00:03 -04:00
Austin Noska
e3f356a5db test: updating get cliques unit tests 2019-06-27 10:58:22 -04:00
Austin Noska
2d401959b6 feat: optimized get clique by using a bredth-first-search so it would not have to search the whole graph 2019-06-27 10:57:55 -04:00
Austin Noska
7cc5a47d6a feat: Added a hashset of visited nodes so bfs can be used on graphs 2019-06-27 10:57:00 -04:00
Chris Cameron
8c160c77c4 docs: Updating changelog 2019-06-26 13:33:37 -04:00
Austin Noska
65c50e8e90 feat: Added method to get a single clique given a starting node 2019-06-26 11:39:50 -04:00
Chris Cameron
3a2fc0eef7 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-24 12:52:24 -04:00
Chris Cameron
1be852685d chore: Updating changelog, incrementing minor version 2019-06-24 12:49:39 -04:00
Chris Cameron
6201184fab feat: IcdXmlException exposes LineNumber and LinePosition 2019-06-24 12:42:29 -04:00
Chris Cameron
e8acb42bb9 fix: Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder 2019-06-21 21:32:46 -04:00
Chris Cameron
d3d812265e Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-14 16:54:12 -04:00
Chris Cameron
b915401109 chore: Updating changelog, incrementing patch version 2019-06-14 16:52:56 -04:00
Austin Noska
3e3a4e33cb fix: SafeTimer Stopped now returns a SafeTimer with no due time and no repeat period 2019-06-14 16:51:36 -04:00
Chris Cameron
b680bab67a Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-14 10:28:13 -04:00
Chris Cameron
7666021925 chore: Updating changelog, incrementing minor version 2019-06-14 10:25:47 -04:00
Chris Cameron
7b6092c291 fix: Fixing issues with Remap methods, added unit tests 2019-06-13 17:35:03 -04:00
Chris Cameron
f7740aaea2 fix: Fixing overflow 2019-06-13 17:10:34 -04:00
Chris Cameron
c31b2b556b feat: Adding methods for remapping and clamping numeric values to ranges 2019-06-13 16:56:49 -04:00
Chris Cameron
8866a3e1e6 fix: Fixing tests, bad maths 2019-06-13 11:59:12 -04:00
Chris Cameron
e3273934a7 fix: Begin rewriting RangeAttribute 2019-06-12 23:42:59 -04:00
Chris Cameron
0152259a25 chore: Updating changelog, incrementing minor version 2019-06-10 13:50:37 -04:00
Chris Cameron
98c3f17602 docs: Updating changelog 2019-06-10 13:50:23 -04:00
Chris Cameron
bb3fba100d fix: Fixing NetStandard CultureInfo database connection string 2019-06-10 13:48:08 -04:00
Chris Cameron
9adad373f6 fix: Better determine builtin cultures on NetStandard 2019-06-10 13:47:45 -04:00
Chris Cameron
844f8b7b46 refactor: Tidying 2019-06-10 13:47:21 -04:00
Chris Cameron
43d7ea944e Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-06 15:54:04 -04:00
Chris Cameron
6526b2b811 chore: Updating changelog, incrementing minor version 2019-06-06 15:52:35 -04:00
Chris Cameron
ead365e251 chore: Fixing bad merge 2019-06-06 15:51:53 -04:00
Jack Kanarish
f24e6d2597 Merge branch 'feat/init-event' into MetLife_v5.4.2
# Conflicts:
#	CHANGELOG.md
2019-06-06 11:06:09 -04:00
Chris Cameron
311f2dfaf4 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-05 15:03:33 -04:00
Chris Cameron
1c38d9f04a fix: Fixing Net Standard build, changing method name 2019-06-05 15:01:07 -04:00
Chris Cameron
02c18d152f chore: Updating changelog, incrementing patch version 2019-06-05 14:34:59 -04:00
Chris Cameron
fc482ec685 Merge branch 'fix/processorUptimeCaching' of Common/Utils into MetLife_v5.4.2 2019-06-05 18:28:28 +00:00
Austin Noska
d649fb9dc4 docs: updating utils changelog 2019-06-05 14:18:53 -04:00
Austin Noska
4d76abe046 fix: cache the uptime values and calculate the uptime from those values instead of polling the crestron processor each time its needed 2019-06-05 14:15:53 -04:00
Chris Cameron
d6d3bfa9e0 Merge branch 'feat/XmlUtilsRoku' of Common/Utils into ConnectPro_v1.3 2019-06-04 17:17:33 +00:00
Austin Noska
536742a1c6 docs: updating changelog 2019-06-04 12:54:39 -04:00
Austin Noska
dc824b2034 feat: Added a URI query builder 2019-06-04 12:19:12 -04:00
Chris Cameron
0cc588ce15 Merge branch 'feat/XmlUtilsRoku' of Common/Utils into ConnectPro_v1.3 2019-05-31 20:16:55 +00:00
Austin Noska
b996a295f6 Merge remote-tracking branch 'origin/ConnectPro_v1.3' into feat/XmlUtilsRoku
# Conflicts:
#	CHANGELOG.md
2019-05-31 16:14:14 -04:00
Austin Noska
4312ad1a61 chore: updated changelog 2019-05-31 15:58:06 -04:00
Austin Noska
7792b01629 feat: Added Shim to read a list from xml with no root element 2019-05-31 15:52:47 -04:00
Chris Cameron
4953e40f9e docs: Updating changelog 2019-05-31 13:34:29 -04:00
Chris Cameron
69f872ced1 feat: Adding features to IcdEnvironment for tracking program initialization state 2019-05-31 13:33:21 -04:00
Chris Cameron
7e3aef4cb3 fix: Fixed threading exception in TypeExtensions 2019-05-28 09:52:06 -04:00
Chris Cameron
a6fbd5a6d2 chore: Updating changelog 2019-05-28 09:51:54 -04:00
Chris Cameron
6f67064d34 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2 2019-05-24 09:59:54 -04:00
Chris Cameron
723759f805 Merge remote-tracking branch 'origin/MetLife_v5.4' into MetLife_v5.4.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-05-24 09:59:07 -04:00
Chris Cameron
59f4411620 chore: Updating changelog, incrementing patch version 2019-05-24 09:55:48 -04:00
Chris Cameron
243e285948 feat: Added empty, placeholder interface for ICD Attributes 2019-05-24 09:55:33 -04:00
Chris Cameron
198bf8dac0 Merge branch 'fix/json-reader-extensions' of Common/Utils into ConnectPro_v1.3 2019-05-22 17:45:08 +00:00
Jeffery Thompson
78f5c4a7b6 fix: use ToString() instead of as string to support .NET Standard 2019-05-22 11:09:32 -04:00
Chris Cameron
c0ed7f9b26 feat: Clarifying neutral culture exception 2019-05-16 16:24:59 -04:00
Chris Cameron
6d08ee3bef Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
#	ICD.Common.Utils/PathUtils.cs
#	ICD.Common.Utils/ProcessorUtils.SimplSharp.cs
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-05-16 09:56:43 -04:00
Chris Cameron
2b376bff47 chore: Updating changelog, incrementing minor version 2019-05-15 15:59:09 -04:00
Chris Cameron
9f0e66e4a1 fix: XmlReaderExtensions handling both TimeSpan formats 2019-05-14 16:16:22 -04:00
Chris Cameron
4c93515f83 refactor: Exposing missing XmlConvert methods 2019-05-14 16:15:48 -04:00
Chris Cameron
9ad49540d2 fix: Fixing JSON converter error when handling default existing value with struct types 2019-05-10 16:04:11 -04:00
Chris Cameron
cbf7a3d79c chore: Updating changelog, incrementing minor version 2019-05-10 14:53:27 -04:00
Jeffery Thompson
5a4d3cabac Merge branch 'feat/localization' of Common/Utils into ConnectPro_v1.3 2019-05-10 18:35:34 +00:00
Jack Kanarish
dc0e65125a Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry
# Conflicts:
#	CHANGELOG.md
2019-05-10 12:06:13 -04:00
Chris Cameron
9d732ef4b2 feat: Adding RemoveRange method to IcdHashSet 2019-05-10 11:47:00 -04:00
Chris Cameron
ecdb4f4fb5 feat: AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization 2019-05-09 15:18:21 -04:00
Chris Cameron
6f5188909b fix: Fixing dumb mistake with extension method resolution order 2019-05-09 12:51:55 -04:00
Chris Cameron
3fa089b85e feat: Added methods for serializing additional types, arrays and dictionaries to JSON 2019-05-09 11:58:55 -04:00
Chris Cameron
fef667191b chore: Moving CultureInfo.sqlite into project root so it gets included in clz 2019-05-08 10:21:52 -04:00
Chris Cameron
28abb69c85 feat: Initial commit of IcdCultureInfo and associated CultureInfo.sqlite database 2019-05-07 11:52:13 -04:00
Chris Cameron
0bf88240b2 feat: Adding missing methods to sqlite wrappers 2019-05-07 11:51:08 -04:00
Drew Tingen
294afd1834 chore: update changelog 2019-05-02 20:22:54 -04:00
Drew Tingen
475f381991 feat: Breaking out Program/Common config directories from the full paths 2019-05-02 20:22:32 -04:00
Chris Cameron
1460bf2924 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
2019-05-02 10:28:09 -04:00
Chris Cameron
ab58ba721e chore: Updating changelog, incrementing patch version 2019-05-02 10:24:34 -04:00
Chris Cameron
d7bfb07c2c fix: Fixed PriorityQueue IndexOutOfRange exception when an inner queue becomes depleted 2019-05-02 10:23:53 -04:00
Chris Cameron
33b1d29781 fix: IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost" 2019-05-01 17:05:22 -04:00
Chris Cameron
78c20201ab fix: IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost" 2019-05-01 16:33:09 -04:00
Chris Cameron
66f4e797ed feat: Adding extension method for getting or adding a new item to a dictionary 2019-04-26 12:17:09 -04:00
Chris Cameron
94ac37b32a refactor: Tidying 2019-04-23 12:01:53 -04:00
Chris Cameron
22978e90c4 feat: Added extension method for peeking queues 2019-04-23 09:57:28 -04:00
Chris Cameron
995a57f8e4 chore: Updating changelog, incrementing minor version 2019-04-16 14:07:52 -04:00
Chris Cameron
d6d767d8f9 Merge remote-tracking branch 'origin/feat/logs' into ConnectPro_v1.2 2019-04-16 14:01:11 -04:00
Jack Kanarish
0931d6f1ec feat: add helper method for un-mapping a range from ushorts 2019-04-10 17:17:30 -04:00
Jack Kanarish
24859aaa31 feat: add types to maprange 2019-04-10 17:16:26 -04:00
Chris Cameron
798e9cc0a7 Merge branch 'feat/SPlusUtils' of Common/Utils into dev 2019-04-09 19:58:33 +00:00
Drew Tingen
1dac1bfb67 chore: Changelog + Docs 2019-04-09 15:57:10 -04:00
Drew Tingen
829c24b667 feat: Adding SPlusUtils to convert ushort's to int 2019-04-09 15:46:10 -04:00
Chris Cameron
715c198763 feat: Keeping paths as they were until we can agree on an approach going forwards 2019-04-08 17:00:10 -04:00
Chris Cameron
d8741773c5 refactor: Removing unused code 2019-04-08 16:38:01 -04:00
Chris Cameron
26b924dd48 feat: IcdStreamWriter exposes WriteLine(string) 2019-04-08 16:31:53 -04:00
Chris Cameron
8892e6e223 feat: Adding ProgramLogsPath to PathUtils 2019-04-08 15:48:05 -04:00
Chris Cameron
23afa8e025 feat: Windows and VC4 use Config directory for configuration 2019-04-08 15:47:52 -04:00
Chris Cameron
7d1cc3139f chore: Updating nuget packages 2019-04-08 14:00:47 -04:00
Chris Cameron
30ea6ced9e fix: Fixing bad merge 2019-04-08 10:59:37 -04:00
Chris Cameron
3041d0f402 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-04-08 10:55:52 -04:00
Chris Cameron
f4693df048 Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry
# Conflicts:
#	CHANGELOG.md
2019-04-05 14:31:59 -04:00
Chris Cameron
736c2aee33 chore: Updating changelog, incrementing patch version 2019-04-05 14:29:44 -04:00
Chris Cameron
40342e2d9e Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry 2019-04-03 16:23:52 -04:00
Chris Cameron
5756d9654b fix: Fixing FormatException when parsing some JSON DateTimes 2019-04-03 16:19:53 -04:00
Chris Cameron
b2ca43baf1 feat: Adding extension methods for writing properties to JSON 2019-04-02 16:37:18 -04:00
Chris Cameron
f36b9f7856 fix: Fixing format exception when parsing JSON DateTime with timezone info 2019-04-01 16:47:08 -04:00
Chris Cameron
bcf13ef972 perf: Optimizing object instantiation for default constructors 2019-04-01 14:16:56 -04:00
Chris Cameron
100b8e4753 fix: JsonReader GetValueAsString ignores token type 2019-04-01 12:27:06 -04:00
Chris Cameron
134ee85067 feat: Adding JsonReader extension to read current value as DateTime 2019-03-31 20:38:22 -04:00
Chris Cameron
c054a9d752 fix: Fixing argument exceptions when looking up LAN2 properties on a system without multiple network adapters 2019-03-28 10:36:04 -04:00
Chris Cameron
ef19e20d67 docs: Updating changelog 2019-03-27 11:24:35 -04:00
Chris Cameron
3fd344a308 fix: Adding missing methods to Net Standard 2019-03-27 10:49:29 -04:00
Chris Cameron
17e7f4d3c9 Merge remote-tracking branch 'origin/feat/seeded_guid' into Telemetry
# Conflicts:
#	ICD.Common.Utils/Attributes/RangeAttribute.cs
2019-03-26 11:58:07 -04:00
Chris Cameron
87d1f4da16 feat: Added util method for generating seeded guids 2019-03-26 11:28:59 -04:00
Chris Cameron
88a4801f8e feat: Added extension method for generating stable string hashcodes 2019-03-26 11:28:15 -04:00
Jack Kanarish
c55e35ac6e Saftey commit for CC 2019-03-25 13:51:29 -04:00
Chris Cameron
24601b0ef2 fix: Potential fix for sqlite database locked exception 2019-03-14 16:31:13 -04:00
Chris Cameron
4fa46ff5a0 Merge remote-tracking branch 'origin/fix/VC4_Fixes' into ConnectPro_v1.2 2019-03-13 16:28:18 -04:00
Chris Cameron
827ab2cd42 refactor: Removing unused code, loosening attribute type constraints 2019-03-13 16:26:53 -04:00
Drew Tingen
158c261d19 fix: VC4 Compat Fixes 2019-03-09 14:51:44 -05:00
Chris Cameron
c607d1254e chore: Updating changelog, incrementing minor version 2019-03-01 14:48:57 -05:00
Chris Cameron
e90914664f Merge remote-tracking branch 'origin/ConnectPro_v1.3' into ConnectPro_v1.2 2019-03-01 14:32:25 -05:00
Chris Cameron
fc855d407b Merge remote-tracking branch 'origin/fix/IcdConsole' into ConnectPro_v1.2 2019-03-01 14:32:13 -05:00
Chris Cameron
e3a4713b3b fix: Fixed bug preventing deserialization of XML lists 2019-03-01 14:29:46 -05:00
Drew Tingen
f85896e947 fix: PrintLine raises OnConoslePrint, Crestron Console Response uses PrintLine, Better environment checks 2019-02-24 16:19:03 -05:00
Chris Cameron
131e2f87f4 feat: Adding constructor to BiDictionary to build from an existing dict 2019-02-21 14:04:06 -05:00
Chris Cameron
4a330637a7 feat: Type IsAssignableTo extension shim 2019-02-19 14:32:32 -05:00
Chris Cameron
fa124a0afc refactor: Resolving warning 2019-02-11 12:13:56 -05:00
Chris Cameron
72fd823643 test: Fixing unit tests 2019-02-07 17:13:25 -05:00
Chris Cameron
644388edad chore: Updating changelog, incrementing minor version 2019-02-07 16:55:22 -05:00
Chris Cameron
cbb05c8b79 refactor: Removing unused code 2019-02-07 16:53:33 -05:00
Chris Cameron
066c9f93a7 chore: Updating AssemblyInfo 2019-02-07 15:32:49 -05:00
Chris Cameron
9aa7459b0f chore: Updating changelog 2019-02-07 14:42:22 -05:00
Jack Kanarish
7557e01c9f feat: add processor utilities and environment utilities for telemetry 2019-02-07 10:45:06 -05:00
Chris Cameron
f8a813c97b perf: Removing redundant code, logging micro-optimization 2019-02-07 10:37:35 -05:00
Chris Cameron
be6a6de65a perf: ReprBuilder micro-optimizations 2019-02-06 17:09:37 -05:00
Chris Cameron
ffe3e67241 perf: Better JSON serialization of nullable types 2019-02-06 13:10:52 -05:00
Chris Cameron
141d911eb0 perf: Reduced size of JSON serialized nullable types 2019-02-06 11:31:14 -05:00
Chris Cameron
d6abf3fdf6 perf: Don't serialize namespace for builtin types 2019-02-04 13:22:59 -05:00
Chris Cameron
46a1ea09b6 refactor: Moving JSON type name util into TypeExtensions 2019-02-04 12:03:15 -05:00
Chris Cameron
2dc705d335 perf: Significantly reducing the size of JSON serialized types 2019-02-04 11:38:39 -05:00
Chris Cameron
0700a357dd feat: Adding ToStringJsonConverter 2019-02-01 14:52:33 -05:00
Chris Cameron
5fb7636ed4 feat: Extension method for reading JSON token as a Guid 2019-01-30 10:52:44 -05:00
Chris Cameron
196c2a535a feat: Added shims for ReflectionUtils.SubscribeEvent for known callbacks 2019-01-29 21:59:10 -05:00
Chris Cameron
db50ada952 refactor: Tidying 2019-01-29 17:49:23 -05:00
Chris Cameron
087b04fd62 chore: Updating changelog, incrementing major version 2019-01-29 14:52:36 -05:00
Chris Cameron
ea73351d39 refactor: Removing redundant critical section, support for chaining TableBuilder methods 2019-01-28 16:58:21 -05:00
Chris Cameron
ca1fae29b0 chore: Updating nuget packages 2019-01-28 14:19:38 -05:00
Chris Cameron
1916c2b750 refactor: Reducing duplicate code 2019-01-28 14:02:16 -05:00
Chris Cameron
3af2544e70 feat: ReprBuilder better supports method chaining 2019-01-28 13:32:35 -05:00
Chris Cameron
20e8aa93f2 Merge branch 'feat/ConsoleOnPrint' of Common/Utils into dev 2019-01-28 13:04:40 +00:00
Drew Tingen
3937902f38 Merge remote-tracking branch 'origin/dev' into feat/ConsoleOnPrint
# Conflicts:
#	CHANGELOG.md
2019-01-27 22:59:25 -08:00
Drew Tingen
021d5781a3 Merge branch 'feat/json' of Common/Utils into dev 2019-01-28 06:56:15 +00:00
Drew Tingen
b429e4bc53 feat: OnConsolePrint event and better VC-4 console support 2019-01-27 22:55:24 -08:00
Chris Cameron
4a203e2449 refactor: Reducing duplicate code 2019-01-27 17:55:47 -05:00
Chris Cameron
d41203b856 docs: Updating changelog 2019-01-25 17:11:08 -05:00
Chris Cameron
2f21379e52 Merge remote-tracking branch 'origin/dev' into feat/json 2019-01-25 17:10:03 -05:00
Chris Cameron
f60de4321b chore: Updating changelog, incrementing minor version 2019-01-25 17:07:05 -05:00
Chris Cameron
bd2ea606ae docs: Updating changelog 2019-01-25 16:52:09 -05:00
Chris Cameron
1f20c07e94 refactor: Splitting JSON extensions into Reader and Writer extensions, removing unused code 2019-01-25 14:06:51 -05:00
Chris Cameron
1be588b86a refactor: Simplifying JSON converters 2019-01-25 13:57:41 -05:00
Chris Cameron
488df297fc refactor: Removing unused code 2019-01-25 13:57:19 -05:00
Chris Cameron
80a4d94358 refactor: Removing unused code 2019-01-24 17:28:59 -05:00
Chris Cameron
6a40f3ce18 refactor: Tidying 2019-01-24 16:46:07 -05:00
Chris Cameron
d564a0a423 feat: Adding shorthand method for serializing an object into a JSON message 2019-01-24 16:21:29 -05:00
Chris Cameron
a9a544c433 feat: Simplifying generic JSON converters 2019-01-24 15:58:46 -05:00
Chris Cameron
2e0837f5c8 feat: Extension methods for reading current JSON token to the given type 2019-01-24 15:58:21 -05:00
Chris Cameron
77be0ec477 refactor: Removing unused code 2019-01-24 15:57:53 -05:00
Chris Cameron
524cdc3e31 feat: EventArgs constructor overloads 2019-01-24 11:57:39 -05:00
Chris Cameron
1d6e8d55ca refactor: Tidying 2019-01-23 11:10:35 -05:00
Chris Cameron
3ba5f11587 Merge branch 'feat/VC-4' of Common/Utils into MetLife_v5.4 2019-01-22 17:51:47 +00:00
Drew Tingen
fb7a6e27b8 chore: update changelog 2019-01-22 09:50:42 -08:00
Drew Tingen
fffc8e4a60 fix: Fixed GetApplicationRootDirectory for NetStandard 2019-01-22 09:50:32 -08:00
Drew Tingen
1d7ada87c5 refactor: Removing preprocessors and adding better multi-platform support 2019-01-22 09:47:20 -08:00
Drew Tingen
3a4438ec1e chore: update changelog 2019-01-22 09:24:37 -08:00
Drew Tingen
21ce86de0f fix: Use IcdEnvironment instead of CrestronEnvironment 2019-01-22 09:24:25 -08:00
Drew Tingen
3cb29452a2 chore: tidying 2019-01-22 09:17:35 -08:00
Drew Tingen
114a5e4ec7 Merge remote-tracking branch 'origin/dev' into feat/VC-4 2019-01-22 09:13:06 -08:00
Drew Tingen
a9d411dcfd feat: Path support for VC-4 2019-01-22 09:11:48 -08:00
Chris Cameron
e708ef9603 fix: Fix for potential memory leak with timers 2019-01-21 11:49:21 -05:00
Drew Tingen
aae4fb6185 Merge branch 'feat/mono' of Common/Utils into dev 2019-01-17 23:12:09 +00:00
Chris Cameron
8401ab1852 feat: Added SimplSharpProMono to eRuntimeEnvironment enum 2019-01-17 17:15:34 -05:00
Chris Cameron
27760f2282 fix: Resolving warning 2019-01-14 16:42:32 -05:00
Chris Cameron
80a0ca26c5 chore: Updating changelog, incrementing minor version 2019-01-10 16:11:00 -05:00
Chris Cameron
b9ec2f3222 refactor: Tidying 2019-01-10 10:45:53 -05:00
Chris Cameron
a6ad52d492 refactor: Removing log from ReflectionUtils.CreateInstance, doesn't make sense here 2019-01-10 10:25:46 -05:00
Jack Kanarish
64e11db0bc Merge branch 'MetLife_v5.4' of https://cs-gogs.icdpf.net/Common/Utils into MetLife_v5.4 2019-01-10 09:53:03 -05:00
Jack Kanarish
d01e9345d5 feat: add range attribute, which describes the valid ranges of a property if that range doesnt match the range of the datatype 2019-01-10 09:52:54 -05:00
Chris Cameron
466dc6deb5 fix: Fixing bug where xml fragments were being written with prepended document info 2019-01-09 16:33:33 -05:00
Chris Cameron
ad47c890a8 refactor: Tidying 2019-01-08 14:47:03 -05:00
Chris Cameron
108317212c feat: Adding TryGetPortForScheme method to UriExtensions 2019-01-07 15:37:33 -05:00
Chris Cameron
4a411e8990 refactor: Removing unused code 2019-01-07 12:20:13 -05:00
Chris Cameron
4cd28a8a12 fix: IcdHashSet preserves comparer when an operation creates a new IcdHashSet 2019-01-03 13:03:51 -05:00
Chris Cameron
470c35cab7 chore: Updating changelog, incrementing minor version 2019-01-02 14:18:42 -05:00
Chris Cameron
a372d97868 feat: Adding RegexUtils shims for RegexOptions 2018-12-19 07:50:23 -05:00
Chris Cameron
f208ec521b feat: Added RegexUtils method for replacing a single group in a match 2018-12-19 06:40:39 -05:00
Jack Kanarish
347cf70b6c Merge branch 'MetLife_v5.4' of https://cs-gogs.icdpf.net/Common/Utils into MetLife_v5.4 2018-12-17 09:34:47 -05:00
Jack Kanarish
1076795fae refactor: make isenumtype public for use in other classes 2018-12-17 09:34:37 -05:00
Chris Cameron
7d059bc605 Merge remote-tracking branch 'origin/dev' into MetLife_v5.4 2018-12-10 11:37:15 -05:00
Chris Cameron
dd270adf9e feat: Added methods to IcdUriBuilder for appending path 2018-12-10 11:36:31 -05:00
Jack Kanarish
efb5e014ec feat: give better information when constructor lookup fails 2018-12-04 14:36:04 -05:00
Chris Cameron
083280cc64 chore: Updating changelog 2018-12-03 14:32:21 -05:00
Rashod Davis
e222ce424b feat: Adding short parsing methods to XML utils 2018-12-03 10:32:39 -05:00
Rashod Davis
ad7176506d feat: Added GetAttributeAsEnum xml utils method 2018-12-03 10:32:16 -05:00
Chris Cameron
e4e3e9b91a feat: IcdUriBuilder better supports null Uris 2018-11-28 13:28:40 -05:00
Chris Cameron
1721116908 chore: Removing bad null reference warning 2018-11-27 12:17:29 -05:00
Chris Cameron
d8489d31b6 chore: Updating changelog, incrementing major version 2018-11-20 14:59:21 -05:00
Chris Cameron
a8552ea0e3 chore: Adding xml encoding headers 2018-11-20 14:05:08 -05:00
Chris Cameron
e700650735 Merge remote-tracking branch 'origin/MetLife_v5.2' into MetLife_v5.4 2018-11-20 13:25:40 -05:00
Chris Cameron
ed9c017856 Merge branch 'fix/console-print' of Common/Utils into dev 2018-11-16 22:22:02 +00:00
Jeffery Thompson
0ee1b440ee fix: exception in NetStandard if console message contained curly braces 2018-11-16 17:19:49 -05:00
Chris Cameron
4184f85826 chore: Updating test framework sdk 2018-11-14 15:48:17 -05:00
Chris Cameron
42cc8c2cfc feat: Adding string extension method for removing all instances of a given string, fixes unexpected use of Remove characters method 2018-11-12 10:37:16 -05:00
Drew Tingen
6b37db3530 Merge branch 'fix/csv-nullref' of Common/Utils into dev 2018-11-09 21:09:50 +00:00
Chris Cameron
ad8fa216a5 fix: Fixed NullReferenceException when writing null strings to CSV 2018-11-09 16:08:25 -05:00
Chris Cameron
ef415bb20f fix: Removing default fragment xml conformance level, fixes StartDocument on net standard 2018-11-09 14:59:22 -05:00
Chris Cameron
fe614ae8ad chore: Updating .csproj 2018-11-09 13:40:54 -05:00
Chris Cameron
2d4bc57ed8 feat: Reworked xml attribute utils for performance 2018-11-09 11:42:36 -05:00
Chris Cameron
c048c4fc65 test: Adding test case for RemoveCharacters string extension method 2018-11-09 10:09:40 -05:00
Chris Cameron
2e2eebd95f chore: Updating changelog, incrementing minor version 2018-11-08 16:25:05 -05:00
Chris Cameron
e21830a7d5 perf: Moving enumerable extensions optimizations into correct place 2018-11-08 16:15:22 -05:00
Chris Cameron
f53607018c refactor: Enumerate over XML attributes 2018-11-08 15:50:12 -05:00
Chris Cameron
e0176741d2 fix: Fixing dumb mistake in TryFirst and TryLast extensions 2018-11-08 15:49:44 -05:00
Chris Cameron
742b7e99aa feat: Adding method for getting properties with a given attribute type 2018-11-08 13:03:23 -05:00
Chris Cameron
cf0c71d39b refactor: Removing redundant generic constraints 2018-11-08 13:02:49 -05:00
Chris Cameron
376f9c0837 refactor: Removing unused code 2018-11-08 11:46:14 -05:00
Chris Cameron
8b1c53ebe1 feat: IcdXmlTextWriter exposes WriteStartDocument and WriteEndDocument 2018-11-07 14:25:24 -05:00
Chris Cameron
2e0b0da87f chore: Updating test SDK 2018-11-07 12:57:35 -05:00
Chris Cameron
8311fe5c9d perf: Micro-optimization 2018-11-06 15:45:43 -05:00
Chris Cameron
fb41d76a9c docs: Clarifying method usages 2018-11-06 15:45:34 -05:00
Chris Cameron
8f107aa209 Merge remote-tracking branch 'origin/MetLife_v5.4' into ConnectPro_v1.1 2018-11-06 13:25:17 -05:00
Jack Kanarish
2024dc0171 fix: remove constraint 2018-11-06 13:06:39 -05:00
Chris Cameron
923866dbdf feat: Validation 2018-11-02 16:28:05 -04:00
Chris Cameron
a14b4a5803 refactor: Tidying 2018-11-02 14:03:13 -04:00
Chris Cameron
fac2610b83 Merge remote-tracking branch 'origin/MetLife_v5.4' into ConnectPro_v1.1 2018-11-02 11:29:28 -04:00
Jack Kanarish
0ef0286a9f Merge remote-tracking branch 'origin/dev' into MetLife_v5.4 2018-11-02 10:46:19 -04:00
Jack Kanarish
d084553600 fix: fix an issue where use of except causes phone numbers with repeat digits to be improperly truncated 2018-11-01 17:28:27 -04:00
Chris Cameron
2b14a6b65c refactor: Tidying 2018-10-30 17:20:52 -04:00
Chris Cameron
043a50669a perf: Small optimization in StringExtensions 2018-10-30 17:06:42 -04:00
Chris Cameron
b58220d3c7 perf: Small enumerable optimizations 2018-10-30 16:13:48 -04:00
Chris Cameron
03de74a494 perf: Potential performance improvement when comparing enumerables 2018-10-30 13:47:08 -04:00
Chris Cameron
6eacc21e45 chore: Updating changelog, incrementing major version 2018-10-30 11:52:55 -04:00
Chris Cameron
db14eb1dde feat: Adding TryFromIpIdString method 2018-10-29 14:13:46 -04:00
Chris Cameron
24e665de84 refactor: Removing unused code 2018-10-29 13:42:33 -04:00
Drew Tingen
7e8618d3e5 Merge branch 'perf/hashset' of Common/Utils into dev 2018-10-29 15:30:07 +00:00
Chris Cameron
e44a18b111 refactor: Tidying 2018-10-29 10:36:44 -04:00
Chris Cameron
5cec0e10f1 perf: Significant IcdHashSet optimizations 2018-10-27 20:36:22 -04:00
Chris Cameron
e01bc9ede6 feat: Adding write string method to IcdFileStream 2018-10-27 14:57:48 -04:00
Chris Cameron
9e6c7ca6b3 Merge branch 'feat/deprecate-nvram' of Common/Utils into dev 2018-10-26 18:34:32 +00:00
Chris Cameron
2a1d58f2ae chore: Updating changelog 2018-10-25 17:22:23 -04:00
Jeffery Thompson
51dcb41cdf feat: make ProgramNumber settable 2018-10-25 15:22:04 -04:00
Chris Cameron
11cff4f5bb chore: Updating changelog 2018-10-24 11:53:05 -04:00
Chris Cameron
7c29fb72d9 refactor: Tidying 2018-10-22 16:39:53 -04:00
Chris Cameron
fc234af43a fix: Fixing potential enumeration bug in StringExtensions 2018-10-22 16:28:59 -04:00
Chris Cameron
5afc676fbe refactor: Removing redundant code 2018-10-22 14:03:03 -04:00
Chris Cameron
ba8c1d98a1 refactor: Removing unused methods 2018-10-22 11:31:06 -04:00
Chris Cameron
63af420710 perf: Replacing recursion with loop 2018-10-22 09:56:03 -04:00
Chris Cameron
25109163fb perf: StartsWith and EndsWith char extensions optimization 2018-10-19 17:30:07 -04:00
Chris Cameron
91f64a4fb1 perf: Avoid throwing exceptions in XmlReaderExtensions 2018-10-19 16:25:57 -04:00
Chris Cameron
78a3373592 chore: Updating changelog, incrementing major version 2018-10-18 11:55:51 -04:00
Chris Cameron
14cce04c12 refactor: Tidying 2018-10-18 10:07:19 -04:00
Chris Cameron
d3d1dae2e1 feat: Implementing ReadXml for DefaultXmlConverter 2018-10-17 17:13:44 -04:00
Chris Cameron
e9063682ef refactor: Tidying 2018-10-17 17:13:18 -04:00
Chris Cameron
699c734389 feat: DefaultXmlConverter knows type it is serializing to/from 2018-10-17 16:56:36 -04:00
Chris Cameron
548220ba0e feat: Shims for deserializing xml lists and dictionaries 2018-10-17 14:56:55 -04:00
Chris Cameron
692da3253f feat: Adding IcdOrderedDictionary constructor for populating with an existing dictionary 2018-10-16 14:32:27 -04:00
Chris Cameron
85ab631ef5 feat: Better implementation of DictionaryExtensions.ToInverse 2018-10-16 14:31:53 -04:00
Chris Cameron
23a068d0c9 refactor: Tidying 2018-10-15 16:53:27 -04:00
Jeffery Thompson
b015c3a3d3 feat: deprecate NVRAM, renamed NvramPath to RootConfigPath 2018-10-11 17:59:41 -04:00
Chris Cameron
566884167f fix: Potential fix for weird profiling offset 2018-10-08 16:33:52 -04:00
Chris Cameron
015ffb2c35 perf: Fixing dumb mistake in RecursionUtils that was preventing the method from bailing early 2018-10-08 15:07:07 -04:00
Chris Cameron
6540ab5177 refactor: Tidying 2018-10-08 15:06:03 -04:00
Chris Cameron
e01e41c449 feat: Indenting stopwatch results into a tree format 2018-10-08 14:54:16 -04:00
Chris Cameron
8a260e0475 refactor: Adding validation to StringUtils.Repeat 2018-10-08 14:53:43 -04:00
Chris Cameron
381355beb9 perf: BreadthFirstSearchPathManyDestinations returns an IEnumerable to support early termination 2018-10-08 14:21:54 -04:00
Chris Cameron
2a25c3d733 fix: IcdUriBuilder better handles strings without scheme info 2018-10-06 20:50:52 -04:00
Chris Cameron
6b8fc19eb3 Merge remote-tracking branch 'origin/ConnectPro_v1.0' into dev 2018-10-01 14:32:41 -04:00
Chris Cameron
c3d73e1091 fix: Improved Type GetSyntaxName method 2018-09-27 15:07:21 -04:00
Chris Cameron
1f5625218f Merge branch 'ConnectPro_v1.0' into dev 2018-09-25 09:44:28 -04:00
Chris Cameron
588badbf58 chore: Adding xml header to .csproj 2018-09-24 15:16:34 -04:00
Chris Cameron
e0fae0b112 feat: Adding EmailClient 2018-09-24 12:33:29 -04:00
Chris Cameron
315bd703c7 Merge branch 'MetLife_v5.3' of Common/Utils into dev 2018-09-19 17:54:14 +00:00
Jack Kanarish
32aae27a7f chore: update changelog 2018-09-19 11:39:26 -04:00
Jack Kanarish
db15ea24d9 Merge branch 'dev' into MetLife_v5.3 2018-09-19 10:01:43 -04:00
Jack Kanarish
667c1cdd21 fix: fix test 2018-09-17 17:12:00 -04:00
Chris Cameron
df30585917 perf: Don't use reflection in AbstractGenericJsonConverter 2018-09-17 15:52:44 -04:00
Chris Cameron
c83bd04c8f chore: Incrementing major version, updating changelog 2018-09-14 14:06:09 -04:00
Jack Kanarish
09603b0537 refactor: make instantiaton abstract 2018-09-13 14:21:59 -04:00
Chris Cameron
d41aa6d111 feat: Xml recursion methods allow cancelling recursion into child nodes 2018-09-12 20:18:56 -04:00
Chris Cameron
d0740c915b refactor: Tidying 2018-09-12 09:49:30 -04:00
Chris Cameron
9867eae704 Merge remote-tracking branch 'origin/XmlConverters' into XmlConverters 2018-09-10 21:09:34 -04:00
Chris Cameron
e1693bc738 fix: Xml converter over-reading fixes 2018-09-10 21:09:18 -04:00
Jack Kanarish
2c87d8e988 fix: add preprocessor for 2008/crestron support 2018-09-10 11:17:51 -04:00
Jack Kanarish
deff0d5408 chore: commit 2008 csproj changes 2018-09-10 11:17:37 -04:00
Jack Kanarish
0ccf80c613 Merge branch 'MetLife_v5.3' into XmlConverters 2018-09-10 11:09:01 -04:00
Chris Cameron
a3e548290f fix: Potential fixes for over-reading XML 2018-09-09 21:24:39 -04:00
Chris Cameron
12ee533cbb feat: Shims for deserializing XML to object instance 2018-09-09 20:33:56 -04:00
Chris Cameron
2ae8fa9c2d feat: Begin implementing XmlConverters 2018-09-09 14:21:25 -04:00
Chris Cameron
7b30730ea0 feat: IcdXmlReader exposes IsEmptyElement property 2018-09-09 14:14:45 -04:00
Chris Cameron
d3f1fe3425 refactor: Tidying, removing duplicate/unused code, micro-optimization 2018-09-09 14:14:20 -04:00
Chris Cameron
48abd75d30 refactor: Additional validation, tidying 2018-09-09 14:13:48 -04:00
Jack Kanarish
0bfd6c4f48 Merge branch 'MetLife_v5.2' into MetLife_v5.3
# Conflicts:
#	ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
2018-09-06 10:23:08 -04:00
Jack Kanarish
c2b980a691 Merge branch 'MetLife_v5.3' of https://cs-gogs.icdpf.net/Common/Utils into MetLife_v5.3 2018-09-06 10:15:43 -04:00
Chris Cameron
ed299b8d4f feat: Initial commit of RegexUtils 2018-08-31 09:52:53 -04:00
Chris Cameron
0c35e3225c Merge branch 'IcdHashsetExt' of Common/Utils into dev 2018-08-29 17:38:02 +00:00
Rashod Davis
254ed85d83 chore: Added comparer to ToIcdHashset extention 2018-08-29 13:07:31 -04:00
Chris Cameron
8871fad40a feat: IcdHashSet constructor overloads for IEqualityComparer param 2018-08-29 10:52:07 -04:00
Jack Kanarish
2ff7073385 feat: add CSV Writer 2018-08-28 10:52:12 -04:00
Chris Cameron
957424e5ca fix: Fixing hidden properties 2018-08-27 17:32:18 -04:00
Chris Cameron
9cdb590d9f fix: Slightly more accurate profile times 2018-08-21 14:57:19 -04:00
Chris Cameron
ca10f049e5 perf: IcdOrderedDictionary maintains a collection of values ordered by key 2018-08-21 10:27:25 -04:00
Chris Cameron
d79c272df0 perf: Removing heavy-handed validation from enum utils 2018-08-21 10:26:24 -04:00
Chris Cameron
1c9d311422 feat: List AddSorted extension returns the insertion index 2018-08-21 10:25:11 -04:00
Chris Cameron
60a19fe7f8 refactor: Removing redundant code 2018-08-21 10:24:32 -04:00
Chris Cameron
54fbd7eaa8 feat: Initial commit of AsyncEventQueue 2018-08-14 15:02:18 -04:00
Chris Cameron
fd931b0b53 fix: Fixing potential null ref 2018-08-13 16:43:10 -04:00
Chris Cameron
2a222289ca fix: Fixing net standard build 2018-08-13 16:43:01 -04:00
Chris Cameron
e437a9442c feat: Invoke threads are tracked internally and can be printed to a table 2018-08-13 15:00:15 -04:00
Chris Cameron
478261e888 refactor: Tidying 2018-08-13 14:58:31 -04:00
Chris Cameron
09445da1e9 perf: IcdHashSet AddRange micro-optimization 2018-08-09 11:01:27 -04:00
Chris Cameron
eb7f3033fb perf: Disposing text readers 2018-08-07 17:09:23 -04:00
Chris Cameron
b1b12c76dd feat: Adding AppendPropertyRaw method to ReprStringBuilder 2018-08-02 13:32:21 -04:00
Chris Cameron
5e80ddcc16 pef: Micro-optimizations to LogItem and IcdXmlAttribute equality 2018-08-01 10:41:56 -04:00
Chris Cameron
84fa69d3e0 feat: IcdOrderedDictionary exposes constructor with equality comparer 2018-08-01 10:41:34 -04:00
Chris Cameron
86335e0d44 perf: String utils micro-optimizations 2018-07-31 14:43:55 -04:00
Chris Cameron
03893c2669 refactor: Removing unused code 2018-07-31 14:41:29 -04:00
Chris Cameron
1353468da6 chore: Updating test SDK version 2018-07-30 14:24:01 -04:00
Chris Cameron
2f78a25420 feat: Profiling text shows decimals 2018-07-30 10:54:30 -04:00
Chris Cameron
68caebb28b feat: Profiling in ticks, Net Standard too fast... 2018-07-30 09:54:36 -04:00
Chris Cameron
425d651eba feat: Additional EnumUtils methods for excluding/including flags 2018-07-27 11:14:59 -04:00
Chris Cameron
918e6f5b34 fix: Fixing enum casting exception in SimplSharp 2018-07-26 13:43:34 -04:00
Chris Cameron
6a979f5c12 perf: Reducing boxing 2018-07-26 12:56:01 -04:00
Chris Cameron
8f17d59694 perf: Massive performance improvements to enum HasFlag and HasFlags extensions 2018-07-26 12:10:50 -04:00
Chris Cameron
80e6fe33c7 perf: Massive optimization to enum utils 2018-07-26 11:48:22 -04:00
Chris Cameron
668994be18 perf: Adding contrains for enum methods, faster HasFlag/s checks 2018-07-26 10:56:08 -04:00
Chris Cameron
1a87ce9f00 feat: Adding missing enum utils methods for metlife 2018-07-26 09:56:36 -04:00
Chris Cameron
3129d3e60c perf: Further reducing enum boxing 2018-07-25 15:53:39 -04:00
Chris Cameron
fd3143ea6c refactor: Tidying 2018-07-25 14:45:28 -04:00
Chris Cameron
591240d973 perf: Reducing boxing operations in enum utils 2018-07-25 14:23:25 -04:00
Chris Cameron
b8225b7842 perf: Simpler HasAnyFlags check, some tidying 2018-07-25 14:02:14 -04:00
Chris Cameron
1193c8e3bb fix: Fixing specific enum assignment bug 2018-07-25 14:00:25 -04:00
Chris Cameron
aa3559cb4e perf: Massive optimization for enum utils 2018-07-25 13:26:38 -04:00
Chris Cameron
a13daa18db feat: Profile method for performing an action a given number of times and printing results 2018-07-25 11:59:25 -04:00
Chris Cameron
fa145644d1 feat: Extension method for getting a random item from a sequence 2018-07-25 11:59:00 -04:00
Chris Cameron
5f7d1214e9 Merge remote-tracking branch 'origin/MetLife_v5.3' into dev 2018-07-23 15:11:23 -04:00
Chris Cameron
d8d9f342c9 Merge remote-tracking branch 'origin/MetLife_v5.2' into MetLife_v5.3
# Conflicts:
#	ICD.Common.Utils/Json/JsonItemWrapper.cs
2018-07-23 13:34:49 -04:00
Chris Cameron
aeb2a5d91e perf: Micro-optimization 2018-07-20 16:50:13 -04:00
Chris Cameron
74c59bd7f3 perf: Micro-optimizations 2018-07-20 16:41:44 -04:00
Chris Cameron
6fb1e53776 perf: EnumUtils micro-optimization, potential thread safety improvements 2018-07-20 11:28:16 -04:00
Chris Cameron
0c462ad614 test: Adding missing test 2018-07-20 11:21:12 -04:00
Chris Cameron
f2d32fd355 test: Updating TypeExtensionsTest 2018-07-19 15:54:16 -04:00
Chris Cameron
4df2ede630 fix: Fixed issue with GetSyntaxName giving incorrect results for nullable types 2018-07-19 15:54:06 -04:00
Chris Cameron
8d0b4ca767 chore: Updating changelog, incrementing major version 2018-07-19 13:54:08 -04:00
Chris Cameron
035289f056 refactor: Whitespace 2018-07-19 13:47:08 -04:00
Chris Cameron
929f816398 perf: Micro-optimization for Unanimous extension method 2018-07-19 13:46:53 -04:00
Chris Cameron
6f69ea7fde refactor: Catch specific exception 2018-07-19 12:38:22 -04:00
Chris Cameron
b597448bdc feat: Event profiling messages contain consuming method information 2018-07-19 11:39:31 -04:00
Chris Cameron
cc9eaca87a feat: Extension method for getting a signature representation of a MethodInfo 2018-07-19 11:38:30 -04:00
Chris Cameron
a78ff6ad80 feat: Extension method for getting syntax representation of a Type 2018-07-19 11:37:34 -04:00
Chris Cameron
939f361b54 feat: Cross-platform extension for determining if a ParameterInfo represents an "out" parameter 2018-07-19 11:36:56 -04:00
Chris Cameron
6fb290a0ab feat: Cross-platform extension method for getting MethodInfo from a delegate 2018-07-19 11:35:23 -04:00
Chris Cameron
2166596726 feat: Extension method for checking if a string contains a character 2018-07-19 11:34:48 -04:00
Chris Cameron
073c231ef1 feat: Util methods for profiling event subscribers 2018-07-18 21:35:35 -04:00
Chris Cameron
220e778a76 fix: Dammit Jeff 2018-07-18 13:41:27 -04:00
Jeffery Thompson
560d3c861d fix: try adding _SimplSharp suffix to assembly if GetType fails 2018-07-18 13:38:36 -04:00
Chris Cameron
25ebb4b43d Merge branch 'feat/date-time-extensions-inclusive' of Common/Utils into dev 2018-07-13 20:28:17 +00:00
Jeffery Thompson
f7dba764d5 feat: add parameter to extensions for inclusivity 2018-07-13 16:25:13 -04:00
Chris Cameron
f2e39566e2 Merge branch 'fix/scheduler-service-time' of Common/Utils into dev 2018-07-13 20:03:12 +00:00
Jeffery Thompson
b4ef07fd45 fix: better time management skills 2018-07-13 16:01:23 -04:00
Chris Cameron
69b97779d9 perf: Micro-optimizations 2018-07-13 15:06:06 -04:00
Chris Cameron
e8ce1e94cc Merge branch 'feat/action-scheduler' of Common/Utils into dev 2018-07-13 16:25:14 +00:00
Jeffery Thompson
73af42e0f5 fix: guarantee positive duration for Timer.Reset 2018-07-13 12:23:06 -04:00
Chris Cameron
aa7a924d2b Merge branch 'feat/action-scheduler' of Common/Utils into dev 2018-07-13 15:52:53 +00:00
Jeffery Thompson
3185593977 fix: change DateTime.Now to IcdEnvironment.GetLocalTime() 2018-07-13 11:45:22 -04:00
Chris Cameron
bfd0f30437 Merge remote-tracking branch 'origin/feat/action-scheduler' into dev 2018-07-13 10:28:37 -04:00
Chris Cameron
7b372b5a72 chore: Updating changelog 2018-07-13 09:37:00 -04:00
Jeffery Thompson
dfcdbba05f fix: fucking csproj 2018-07-12 22:32:52 -04:00
Chris Cameron
4494192bdf refactor: Tidying 2018-07-12 22:09:14 -04:00
Chris Cameron
bfbbcff7e7 fix: Fixing bad include in .csproj 2018-07-12 16:52:53 -04:00
Chris Cameron
d1b8b5a01f Merge branch 'feat/action-scheduler' of Common/Utils into dev 2018-07-12 20:18:48 +00:00
Jeffery Thompson
1070cb00f8 fix: use TryFirst instead of comparison to default(DateTime) 2018-07-12 15:48:45 -04:00
Jeffery Thompson
a46987aabf refactor: UpdateRunTime -> GetNextRunTime, add UpdateRunTime for caching GetNextRunTime value
- also swap the operands on the delta time calculation
2018-07-12 15:09:52 -04:00
Jeffery Thompson
c25a82399d fix: remove unnecessary default timer interval 2018-07-12 14:36:58 -04:00
Jeffery Thompson
1f7819e536 feat: add DateTimeExtensions.PreviousLatestTime 2018-07-12 14:03:15 -04:00
Jeffery Thompson
465ac7c42c feat: timer rescheduling, abstract scheduled action, datetime and dayofweek extensions 2018-07-12 13:33:02 -04:00
Jeffery Thompson
928f8e5e04 feat: first go at ActionSchedulerService 2018-07-11 16:35:08 -04:00
Chris Cameron
ae885974da feat: Added extension method for getting type name without trailing generic info 2018-07-06 14:58:16 -04:00
Chris Cameron
21a583a57c feat: Re-raise base exception from ReflectionUtils.CreateInstance, TargetInvocationException and TypeLoadException don't say much 2018-07-03 14:55:04 -04:00
Chris Cameron
268e201f49 chore: Removing redundant REM that breaks on linux build 2018-07-02 13:37:17 -04:00
Chris Cameron
9e2ec3de63 chore: Updating changelog and incrementing minor version 2018-07-02 09:38:50 -04:00
Rashod Davis
8ed856eb98 Merge branch 'RateLimit' of Common/Utils into dev 2018-06-29 21:28:01 +00:00
Chris Cameron
514c0eaec5 fix: Fixing bug where Timer.Reset() would continue repeating on an interval in Net Standard 2018-06-29 17:11:32 -04:00
Chris Cameron
621d83d8dc feat: Added RateLimitedEventQueue collection for throttling events 2018-06-29 16:37:45 -04:00
Chris Cameron
588e3df86e chore: Adding obfuscation to Net Standard 2018-06-29 10:07:51 -04:00
Drew Tingen
336f39c9c2 Merge branch 'MetLife_v5.3' of Common/Utils into dev 2018-06-25 20:12:38 +00:00
Jack Kanarish
5d3b80938e chore: update changelog 2018-06-25 15:48:35 -04:00
Jack Kanarish
eb2a77b772 fix: for backwards json compatibility, if get type fails, try again after stripping assembly suffixes 2018-06-25 15:42:37 -04:00
Chris Cameron
1c420d111b chore: Updating test framework and sqlite versions 2018-06-21 13:46:36 -04:00
Chris Cameron
e1279fb860 fix: Don't write console to error out 2018-06-21 13:11:35 -04:00
Chris Cameron
bf91d9e87f fix: Potential fix for timer disposal on Net Standard 2018-06-21 11:48:59 -04:00
Chris Cameron
1c89ebc5c2 refactor: Reducing duplication 2018-06-21 11:32:29 -04:00
Chris Cameron
2cd744eb1c fix: Adding missing file to csproj 2018-06-20 16:21:03 -04:00
Rashod Davis
20350c0ab7 Merge branch 'SequenceComparer' of Common/Utils into dev 2018-06-20 19:47:54 +00:00
Chris Cameron
177e59edb6 feat: Initial commit of SequenceComparer 2018-06-20 15:38:22 -04:00
Chris Cameron
d8041bd94c chore: Updating changelog, incrementing minor version 2018-06-19 14:43:39 -04:00
Chris Cameron
f2122596b4 test: Adding unit tests for BiDictionary 2018-06-18 10:06:11 -04:00
Chris Cameron
653bf361ef feat: Splitting iterators from validation 2018-06-14 11:21:46 -04:00
Chris Cameron
3689517124 feat: Adding UnEnquote string util method 2018-06-12 15:11:12 -04:00
Chris Cameron
6fdd5a138e feat: Adding SequenceEqual shim 2018-06-12 14:52:13 -04:00
Chris Cameron
fb267465ce fix: Return false when unable to add console command 2018-06-12 14:50:02 -04:00
Jack Kanarish
f818653298 Merge branch 'Enquote' of Common/Utils into dev 2018-06-12 18:07:48 +00:00
Chris Cameron
f7b5d07c38 feat: Adding enquote util method 2018-06-12 13:31:44 -04:00
Chris Cameron
1a931e6ffb feat: Additional validation 2018-06-12 13:30:45 -04:00
Chris Cameron
2fab5d6fd4 fix: Better set key/value behaviour for BiDictionary 2018-06-11 17:04:26 -04:00
Rashod Davis
8d683f875b Merge branch 'BiDictionary' of Common/Utils into dev 2018-06-11 20:07:49 +00:00
Chris Cameron
74c96aac8a fix: Prevent breaking BiDictionary mappings 2018-06-11 16:00:28 -04:00
Chris Cameron
edc9fa300e feat: Initial commit of BiDictionary 2018-06-11 15:38:28 -04:00
Chris Cameron
37a21131d9 feat: Extension method for populating a dict with a sequence of kvps 2018-06-11 11:48:36 -04:00
Chris Cameron
f674d4c60d refactor: Separating iterators from validation 2018-06-07 18:16:24 -04:00
Chris Cameron
ce163629f3 refactor: Removing redundant code 2018-06-07 16:32:09 -04:00
Chris Cameron
18b07abb44 refactor: Resolving code smells 2018-06-07 14:59:31 -04:00
Chris Cameron
4bc6258b62 refactor: Tidying 2018-06-07 13:12:41 -04:00
Chris Cameron
086aee8167 refactor: More appropriate exceptions 2018-06-07 12:29:07 -04:00
Chris Cameron
cc115bafad refactor: Removing redundant code 2018-06-07 11:26:47 -04:00
Chris Cameron
00db478ef6 fix: Fixing bad validation in EnumerableExtensions 2018-06-07 11:26:37 -04:00
Chris Cameron
aa3fc3bccc refactor: Removing redundant code 2018-06-07 11:23:44 -04:00
Chris Cameron
2602380100 refactor: IcdZip Unzip raises an exception instead of generating a message 2018-06-06 13:45:05 -04:00
Chris Cameron
1f023c14d0 chore: Updating changelog 2018-06-06 11:02:11 -04:00
Chris Cameron
6ce52b74ac feat: Moved FileNameEqualityComparer from Settings 2018-06-06 11:01:16 -04:00
Jeffery Thompson
c500f1db5d Merge branch 'zip' of Common/Utils into dev 2018-06-06 14:57:45 +00:00
Chris Cameron
da58379dfa refactor: Tidying 2018-06-06 10:54:39 -04:00
Chris Cameron
1ae6a55c7d docs: Adding MIT license to ZIP entries method 2018-06-06 10:40:15 -04:00
Chris Cameron
381b19f2e6 fix: Fixing net standard build 2018-06-06 10:39:54 -04:00
Chris Cameron
2f3b1ef57d feat: Adding methods for inspecting contents of a ZIP file 2018-06-06 10:02:39 -04:00
Chris Cameron
da31fae213 feat: Exposing OpenRead method in IcdFile 2018-06-06 10:02:00 -04:00
Chris Cameron
e4b0c9f91a feat: Initial commit of eSeekOrigin enum 2018-06-06 10:01:31 -04:00
Chris Cameron
38dd85d79d feat: Exposing additional stream features in IcdStream 2018-06-06 10:00:46 -04:00
Chris Cameron
c306dd6eb9 feat: Initial commit of IcdBinaryReader 2018-06-06 10:00:24 -04:00
Chris Cameron
6fa3cc03ad feat: Adding ElementAtOrDefault extension method that takes a default value 2018-06-05 13:40:53 -04:00
Chris Cameron
eb58e65574 perf: Don't reinvent the wheel for TryElementAt extension method 2018-06-05 13:40:26 -04:00
Chris Cameron
f24f9458ca chore: Updating changelog, incrementing patch version 2018-06-04 16:33:23 -04:00
Chris Cameron
79bbbe277f Merge remote-tracking branch 'origin/collections' into dev
# Conflicts:
#	ICD.Common.Utils/Collections/PriorityQueue.cs
2018-06-04 16:30:38 -04:00
Jack Kanarish
c03833bf9d fix: dont insert at an index which was removed 2018-05-31 17:28:02 -04:00
Jack Kanarish
f816ae771b chore: merge util changes from dev needed for sharp bug backport to metlife 5.2 2018-05-30 16:50:25 -04:00
Chris Cameron
a178ebe8cb docs: Adding missing comments to IcdHashSet 2018-05-25 16:40:37 -04:00
Chris Cameron
3cddc14880 perf: BreadthFirstSearchPathManyDestinations optimizations 2018-05-25 14:13:22 -04:00
Chris Cameron
088222db47 fix: Potential fix - use breadth first node comparer in parents map 2018-05-25 12:18:02 -04:00
225 changed files with 21688 additions and 4047 deletions

View File

@@ -6,6 +6,555 @@ 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.
## [16.0.1] 2021-10-28
### Changed
- Changed sqlite connection strings in IcdCultureInfo & IcdTimeZoneInfo to work with SimplSharp.
## [16.0.0] 2021-10-04
### Added
- Added IcdAutoResetEvent and IcdManaualResetEvent
### Changed
- EnumUtils - Fixed bug where not all values were returned for GetValueExceptNone
- ThreadedWorkerQueue - Added BetweenTime property, to wait between process callbacks
- ThreadedWorkerQueue - Added RunProcess option to stop queue from processing items
- ThreadedWorkerQueue - Added WaitForFlush events to wait until the queue is empty
- ThreadedWorkerQueue - Added count property
- ThreadedWorkerQueue - Now implements IDisposable
### Removed
- Removed RateLimitedEventQueue and tests - features added to ThreadedWorkerQueue
- Removed TryEnter from SafeCriticalSection - incorrect behavior on Crestron systems
## [15.2.0] - 2021-08-18
### Added
- TryParse overload in StringUtils, attempts to parse a GUID from a string
## [15.1.0] - 2021-08-03
### Added
- Enum Extension "SetFlags", takes a bool to set or unset the given flags
- BiDictionay - Added constructors with TKey and TValue comparers
- ILoggerService - Added Flush() method
- Added log entries for intentional reboot and program restart
- Added ThreadingUtils TimeSpan overloads
### Changed
- IcdTimeZoneInfo - fixed issue when unable to read SQL
- WeakKeyDictionary - Fixe GetHashCode to handle null values
- ProcessorUtils - NetStandard - removed "Microsoft" from model name
- Fixed null handing in SequenceComparer and UndefinedVersionComparer
- EnumUtils - GetFlags no longer returns composite flags
## [15.0.0] - 2021-05-14
### Added
- Ported CsvReader for CF 3.5 compatibility from: https://github.com/tspence/csharp-csv-reader
- Added enum extension method for cycling to the next enum value
- Added GetLocalTimeZoneName method to IcdEnvironment
- Added MatchAny method to RegexUtils
- Added OnSystemDeviceAddedRemoved and associated raise methods to IcdEnvironment for NETSTANDARD
- Added GetParentUri method to UriExtensions
- Added RegistryExtensions for working with Windows registry
- Added session change event to IcdEnvironment for login/logout feedback
- Added OrderedDictionary collection
### Changed
- Updated TimeZones.sqlite to include daylight time zone info, added a new display name column.
- Implemented ProcessorUtils for Windows
- Renamed OrderedDictionary to SortedDictionary for consistency with .Net
- Fixed a bug where SafeTimer.Trigger() would run the callback twice on .Net Standard
- Fixed a bug where XML deserialization would fail to read out of empty elements
### Removed
- ANSI color is no longer enabled on .Net Standard by default - it must be enabled by the calling application
## [14.2.0] - 2021-02-04
### Changed
- ProcessorUtils Uptime methods changed to StartTime
## [14.1.0] - 2021-01-21
### Added
- Added overload to GuidUtils that takes an enumerable of guids and combines them into a new deterministic guid
### Changed
- A SafeTimer constructor that executes the callback immediately now does this instead of waiting infinitely
## [14.0.0] - 2021-01-14
### Added
- Added Get and Set extensions to PropertyInfo in SIMPLSHARP to mimic overloads avaliable in NETSTANDARD
- Added Collection extensions for setting and adding ranges of items
- Added a method for getting the total number of seconds in a date
- Added extensions to raise events with common event args using the data directly
- Added property to IcdEnvironment to determine whether SSL communication is enabled
- Added IcdTimeZoneInfo, a very light implementation of System.TimeZoneInfo for the .NET Compact Framework
- Added ThreadedWorkerQueue - a threadsafe way to enqueue items and have a worker thread process them one at a time
- Added eDaysOfWeek flags enum
- Added support for reading the primitive type double to IcdXmlReader and XmlUtils
- Added ProcessorUtils.GetSystemStartTime() to get DateTime the system started instead of a TimeSpan
### Changed
- Repeater changed to use configured callbacks instead of a dumb event
- Scheduled action callbacks allow a TimeSpan to be returned to delay actions
- Handling a Crestron bug where File.Exists throws an exception on 4-Series instead of returning false
- Changed ProcessorUtils.ModelVersion to be a string, Crestron pulls model version from CrestronEnvironment
- For 4-series console outputs, replacing \n with \r\n to help console readability
- Changed RuntimeEnvironment to be 3 variables - Framework for Crestron vs Standard, CrestronSeries for 3 vs 4, and CrestronRuntimeEnvironment for Simpl vs SimplSharpPro vs Server
## [13.0.0] - 2020-09-03
### Added
- Added util methods for removing duplicate whitespace in strings
- Added dequeue overload to ScrollQueue
### Changed
- Replaced Crestron Unzip with Yallie Unzip
- Fixed "version" regex for 4-series
- Fixed date parsing error for 4-series
- Split SimplSharpProMono runtime environment into SimplSharpProSever
- Fixed log formatting on 4-series
## [12.1.0] - 2020-07-14
### Added
- ReflectionExtensions : GetProperty, SetProperty, CallMethod extensions for NetStandard
- Added attributes for controlling obfuscation
- Added AggregateOrDefault extension method for applying an accumulator function over a sequence that returns a default value if the sequence is empty
### Changed
- DHCP status is a boolean
- Changed Hostname property to Hostnames
## [12.0.0] - 2020-06-18
### Added
- Added ToCollection extension method for copying an enumerable to a new collection
- TableBuilder supports multi-line content
- Added eIcdFileMode for IO platform agnosticism
- Extension method for determining if a Type is anonymous
- Extension method for getting inner generic Types
- Added extension method for dynamically converting a sequence to a generic list of the given item type
- Added methods for getting UserData paths
- Added methods for reading GUIDs from XML
- Added methods for reading DateTimes from XML
- Added method for combining GUIDs
- Added method for getting the EventArgs type for an EventHandler
- Added methods for getting a JSON value as a float or double
- Added dictionary Remove method for outputting the removed value
- Added IGenericEventArgs interface
- Added MinimalTypeConverter for serializing Types to JSON
- Added common JSON serializer settings for common, platform agnostic DateTime and Type conversion
### Changed
- Rewrote JsonItemWrapper serialization for JsonConvert friendliness
- Reflection optimizations
- Fixed NullParameterException in TableBuilder
- Improvements to EnumUtils, less reliance on casting to/from int
- Cleaned up TimeSpan.ToReadableString() output
- Fixed a bug where System.Reflection exceptions can't be caught in S#
- TableBuilder no longer draws redundant separators
- Fixed a bug where CompiledOn date was not being parsed correctly due to culture
- S# DateTimes are serialized to JSON in ISO-8601 format
- Deadlock detection works better for false positives
- Improved LogItem JSON serialization
- Improved NiceName method to better handle syntax, whitespace and punctuation
- Fixed a bug where IcdCultureInfo would fail to load on Crestron 4-series processors
- Clarifying which culture failed to load when IcdCultureInfo throws an exception
## [11.1.1] - 2020-08-21
### Removed
- Removed the OnItemTrimmed event from the ScrollQueue due to deadlocks
## [11.1.0] - 2020-05-19
### Added
- ScrollQueue - Added OnItemTrimmed event
- Added DateTimeNullableEventArgs
## [11.0.0] - 2020-03-20
### Added
- Added Not null tag for ICDUriBuilder Constructor that takes a URI as an argument.
- Added MathUtils methods for converting to and from percentages
- Added enum extensions for finding the inclusion and exclusion of enum flags
- Added DateTime extensions for adding years, months, days, hours, minutes and wrapping without modifying other values
- Added shims for deserializing an XML array using a callback for each item
- Added methods for serializing an XML array
- Added WriteAllByte method on IcdFile.
- Added PathUtils for building paths in the HTML directory
- Added public access to GetValues enumeration extension
- Added extensions for getting JsonReader values as long or ulong
- Added DateTimeUtils methods for creating DateTimes from epoch seconds or milliseconds
- Added utils for splitting ANSI into spans for conversion to XAML, HTML, etc
### Changed
- Fixed exception trying to get DHCP status of network interfaces on Linux
- Fixed a bug where color formatted console output on Net Standard was not raising the OnConsolePrint event
- Simplifying ANSI color methods, better cross-platform color support
- Console uses unicode for table drawing on Net Standard
- Using UTC for tracking scheduled events, fixes issues with DST
- Using UTC for tracking durations
- Fixed a bug where table width calculations were not considering unprintable characters
## [10.3.0] - 2020-01-20
### Changed
- Network/MAC/DNS address utils are now enumerating all adapter types
- Ignoring Crestron ethernet parameters that say "Invalid Value"
- Skipping network interfaces with an invalid adapter id
## [10.2.0] - 2019-12-04
### Added
- Added shim methods for finding closest DateTimes from a sequence
## [10.1.0] - 2019-11-18
### Added
- Added PathUtils methods for getting ProgramData paths
- Added a method for determining if a URI is defaults
- Added MaxOrDefault extension method for enumerables
- Added a method for finding an item in a sorted list by a given predicate
### Changed
- NullObject implements IComparable, fixes issues with null keys in ordered dictionaries
- IcdSqliteConnection CreateFile method will create directories recursively
## [10.0.0] - 2019-10-07
### Added
- IcdEnvironment.GetUtcTime() to get UTC representaiton of current time.
- Extension methods for determining if a sequence is in order
- Overload for calculating the modulus of longs
- Default implementation for AbstractGenericXmlConverter Instantiate method
- Additional binary search extensions, now working for all ILists
- Added NullObject as a means of having null keys in hash tables
### Changed
- Potential fix for unhelpful exception messages coming from SafeCriticalSection.Execute
- Small performance improvement when copying arrays
## [9.9.0] - 2019-09-16
### Added
- Added a method for converting 24 hour to 12 hour format
- Added a method for determining if a culture uses 24 hour format
- Added math util method for modulus
- Added TimeSpan extension methods for cycling hours and minutes without modifying the day
- Added a dictionary extension method for getting or adding a new value via func
- Added CultureInfo extensions for converting between 12 hour and 24 hour time formatting
- Added environment methods for setting the current date and time
- Added BinarySearch extension method for all IList types
- Added PathUtils methods to get ProgramData directory
### Changed
- The Root Config path in Net Standard will now be the ICD.Connect folder in the current environments ProgramData directory
- Fixed a bug where CultureInfo was not being cloned correctly
- List AddSorted extensions now work for all IList types
## [9.8.0] - 2019-09-03
### Added
- Added Public API Properties to get the program install date based on the creation date of core dll file for NetStandard and SimplSharp
- Implemented processor utils for NetStandard to get the system uptime and the program uptime
- Added methods for deserializing an XML array
### Changed
- Improvements to JSON DateTime parsing, particularly in Net Standard
## [9.7.1] - 2019-08-17
### Changed
- Fixed CultureInfo SQLite conection string for 4-series compatibility
## [9.7.0] - 2019-08-15
### Added
- Added logger timestamps to non simplsharp programs
- Added Net Standard Support for JSON DateTime formats
- Added EmailValidation class
### Changed
- JSON dict serialization serializes keys instead of converting to property name
- Fixed a bug where ANSI color encoded strings with percentages were being scrambled
## [9.6.0] - 2019-07-03
### Added
- Added RecursionUtils method to get a single clique given a starting node
- Breadth First Search can now search graphs in addition to trees
- Added StartOfDay and EndOfDay DateTime extension methods
### Changed
- Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder
- Throwing an exception when attempting to read a non-primitive JSON token as a string
## [9.5.0] - 2019-06-10
### Added
- Added Shim to read a list from xml with no root element
- Added a URI query builder
### Changed
- Fixed JSON DateTime parsing in .Net Standard
- Fixed threading exception in TypeExtensions
- Fixes for platform-agnostic culture handling
## [9.4.0] - 2019-05-10
### Added
- Added extension method for peeking queues
- Added extension method for getting or adding a new item to a dictionary
- Added methods for serializing additional types, arrays and dictionaries to JSON
- AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization
- Added RemoveRange method to IcdHashSet
- Added IcdCultureInfo and CultureInfo database for localization
### Changed
- IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost"
## [9.3.0] - 2019-04-16
### Added
- Added SPlusUtils with ConvertToInt method taking LowWord/HighWord ushorts
- Added JsonReader extension methods for reading DateTimes
- Added JsonReader extension methods for writing properties
- IcdStreamWriter exposes WriteLine(string)
- Added ProgramLogsPath to PathUtils
### Changed
- Fixes for VC4 compatibility
- Fixed JSON DateTime parsing for timezone information
- Small reflection optimizations
## [9.2.0] - 2019-03-01
### Added
- Added Type IsAssignableTo extension shim
- Added constructor to BiDictionary to instantiate from an existing dict
### Changed
- Fixed bug preventing deserialization of XML lists
- Crestron ConsoleResponse uses PrintLine instead of Print
- Use PrintLine instead of ConsoleResponse on Crestron server
## [9.1.0] - 2019-02-07
### Added
- Added SubscribeEvent shim for delegate callbacks
- Extension method for reading JSON token as a GUID
- Added ToStringJsonConverter
### Changed
- Significantly reduced size of JSON serialized Types
- Small logging optimizations
## [9.0.0] - 2019-01-29
### Added
- IcdConsole.OnConsolePrint event
### Changed
- Better VC-4 support for IcdConsole
- JSON refactoring for simpler deserialization
## [8.9.3] - 2020-08-17
### Changed
- Workaround for logged XML format exceptions when failing to parse floats
## [8.9.2] - 2020-07-28
### Changed
- StringExtensions - fixed an issue with IsNumeric where empty strings would return true
## [8.9.1] - 2020-05-27
### Changed
- Changed ProcessorUtils to use CrestronEnvironment to retrive serial number - this fixes issues with new serial numbers that aren't deciaml TSIDs
## [8.9.0] - 2020-04-30
### Changed
- ProgramUtils and ProcessorUtils return dates instead of strings for date properties
## [8.8.1] - 2020-02-18
### Changed
- IcdTimer - fixed issue that prevented OnElapsed event from firing when Length is less than (or close to) Heartbeat Interval
## [8.8.0] - 2020-01-23
### Added
- Added an overload to PriorityQueue for determing the de-duplication behaviour
## [8.7.2] - 2019-10-29
### Changed
- Fixed a bug with PriorityQueue de-duplication where a new command would be inserted in the wrong position
## [8.7.1] - 2019-08-22
### Changed
- Fixed a bug with the IcdOrderedDict index setter that was creating additional values
## [8.7.0] - 2019-06-24
### Added
- IcdXmlException exposes line number and position properties
## [8.6.1] - 2019-06-14
### Changed
- Fixed a bug where stopped timers on NetStandard would still have a periodic callback duration
## [8.6.0] - 2019-06-14
### Changed
- Overhaul of RangeAttribute remap methods to better avoid overflows
## [8.5.0] - 2019-06-06
### Added
- Adding features to IcdEnvironment for tracking program initialization state
## [8.4.1] - 2019-06-05
### Changed
- Caching the program/processor start time and calculating the uptime from those values instead of polling the crestron processor
## [8.4.0] - 2019-05-15
### Added
- Added GUID utils for generating seeded GUIDs
- Added extension method for getting stable hashcodes from strings
- Added environment and processor utilities for determining DNS status and hostname
### Changed
- RangeAttribute improvements for better type safety
- PathUtils breaking out ProgramConfigDirectory and CommonConfigDirectory from the full paths
## [8.3.3] - 2019-05-24
### Added
- Added empty, placeholder interface for ICD Attributes
## [8.3.2] - 2019-05-02
### Changed
- Fixed PriorityQueue IndexOutOfRange exception when an inner queue becomes depleted
## [8.3.1] - 2019-04-05
### Changed
- Fixed FormatException when parsing some JSON DateTimes
## [8.3.0] - 2019-01-25
### Added
- Added SimplSharpProMono to eRuntimeEnvironment enum
- Added path support for SimplSharpProMono environment
- Added GetApplicationRootDirectory for all platforms
### Changed
- Small fixes for better VC4 support
## [8.2.0] - 2019-01-10
### Added
- Added TryGetPortForScheme method to UriExtensions
- Added range attribute for clarifying numeric fields, properties and parameters
### Changed
- IcdHashSet preserves comparer when an operation creates a new IcdHashSet
- Fixed bug where XML fragments on Net Standard were being prepended with a document header
## [8.1.0] - 2019-01-02
### Added
- Added GetAttributeAsEnum xml utils method
- Adding short parsing methods to XML utils
- Added methods to IcdUriBuilder for appending path
- Added RegexUtils method for replacing a single group in a match
## [8.0.0] - 2018-11-20
### Added
- XML TryGetAttribute methods
### Changed
- Performance improvements when working with xml attributes
- Fixed NullReferenceException when writing null strings to CSV
- Fixed bug with string formatting console input on Net Standard
### Removed
- Removed IcdXmlAttribute
## [7.1.0] - 2018-11-08
### Added
- IcdXmlTextWriter exposes WriteStartDocument and WriteEndDocument
- AttributeUtils method for getting properties with the given attribute type
### Changed
- EnumerableExtensions performance improvements
- Fixed bug in StringExtensions when removing a sequence of characters from a string
## [7.0.0] - 2018-10-30
### Changed
- Micro-optimizations in string and XML manipulations
- Significant hashset optimizations
- Deprecated NVRAM in favor of USER directory
## [6.0.0] - 2018-10-18
### Added
- CsvWriter for creating CSV files + Settings
- AppendText method for IcdFile
- IcdStreamWriter, a wrapper for a StreamWriter
- New XML conversion framework for performance improvements
### Changed
- XmlUtils is now using the improved XML conversion framework
- Better implementation of DictionaryExtensions.ToInverse
## [5.0.0] - 2018-09-14
### Added
- Stopwatch profiling methods
- Attempt to interpret old assembly naming convention when parsing types
- Added RegexUtils
### Changed
- Significant performance improvements across the board
## [4.0.0] - 2018-07-19
### Added
- Added extension method for getting type name without trailing generic info
- Added DateTime extensions for getting next/last time in a sequence
- Added action scheduler service
- Added IcdTimer methods for profiling event performance
### Changed
- Re-raise base exception from ReflectionUtils.CreateInstance, TargetInvocationException and TypeLoadException don't say much
## [3.7.0] - 2018-07-02
### Added
- Adding SequenceComparer for ordering collections of lists, arrays, etc
- Added RateLimitedEventQueue collection for throttling events
### Changed
- Potential fix for timer disposal on Net Standard
- Added workaround for older RPC servers where the typestring being broadcast would stil include _SimplSharp, now will be stripped
- Fixing bug where Timer.Reset() would continue repeating on an interval in Net Standard
## [3.6.0] - 2018-06-19
### Added
- Added ZIP features for examining the contents of an archive
- Added FileNameEqualityComparer
- Added BiDictionary for one-to-one maps
## [3.5.1] - 2018-06-04
### Changed
- PriorityQueue indexing fix
- Pathfinding optimizations
## [3.5.0] - 2018-05-24
### Added
- Added GetFlagsExceptNone parameterless enum method
@@ -36,8 +585,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Adding extension method for getting Informational Version from an Assembly
- Adding WeakKeyDictionary for caching
- Reflection util methods
### Changed
- JSON serialization/deserialization features moved into base converter
- Removed suffix from assembly name

View File

@@ -0,0 +1,27 @@
using System.Linq;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class AnsiUtilsTest
{
[Test]
public void ToSpansTest()
{
string ansi = "\x1b[30mblack\x1b[37mwhite\x1b[0mdefault";
AnsiSpan[] spans = AnsiUtils.ToSpans(ansi).ToArray();
Assert.AreEqual(3, spans.Length);
Assert.AreEqual("black", spans[0].Text);
Assert.AreEqual("30", spans[0].Code);
Assert.AreEqual("white", spans[1].Text);
Assert.AreEqual("37", spans[1].Code);
Assert.AreEqual("default", spans[2].Text);
Assert.AreEqual("0", spans[2].Code);
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
using NUnit.Framework;
using RangeAttribute = ICD.Common.Utils.Attributes.RangeAttribute;
namespace ICD.Common.Utils.Tests.Attributes
{
[TestFixture]
public sealed class RangeAttributeTest : AbstractIcdAttributeTest<RangeAttribute>
{
#region Properties
[TestCase(1)]
[TestCase(1.0f)]
[TestCase(1.0)]
public void MinTest(object min)
{
Assert.AreEqual(min, new RangeAttribute(min, min).Min);
}
[TestCase(1)]
[TestCase(1.0f)]
[TestCase(1.0)]
public void MaxTest(object max)
{
Assert.AreEqual(max, new RangeAttribute(max, max).Max);
}
#endregion
#region Methods
[TestCase((double)0, (double)0)]
[TestCase((double)1, (double)1)]
[TestCase(ushort.MaxValue, double.MaxValue)]
[TestCase(short.MinValue, double.MinValue)]
public void RemapToDoubleTest(object value, double expected)
{
Assert.AreEqual(expected, RangeAttribute.RemapToDouble(value));
}
[TestCase((double)0, typeof(ushort), (ushort)32767)]
[TestCase(double.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(double.MaxValue, typeof(ushort), ushort.MaxValue)]
public void RemapFromDoubleTest(double value, Type type, object expected)
{
Assert.AreEqual(expected, RangeAttribute.RemapFromDouble(value, type));
}
[TestCase(short.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(short.MaxValue, typeof(ushort), short.MaxValue)]
public static void Clamp(object value, Type type, object expected)
{
Assert.AreEqual(expected, RangeAttribute.Clamp(value, type));
}
[TestCase(double.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(double.MaxValue, typeof(ushort), ushort.MaxValue)]
public void Clamp(double value, Type type, double expected)
{
Assert.AreEqual(expected, RangeAttribute.Clamp(value, type));
}
[TestCase(short.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(short.MaxValue, typeof(ushort), ushort.MaxValue)]
public void RemapTest(object value, Type type, object expected)
{
Assert.AreEqual(expected, RangeAttribute.Remap(value, type));
}
[TestCase(0, 100, ushort.MaxValue, typeof(ushort), ushort.MaxValue)]
[TestCase(0, 100, ushort.MaxValue, typeof(short), short.MaxValue)]
public void ClampMinMaxThenRemapTest(object min, object max, object value, Type type, object expected)
{
Assert.AreEqual(expected, new RangeAttribute(min, max).ClampMinMaxThenRemap(value, type));
}
[TestCase(0, 100, ushort.MaxValue, 100)]
[TestCase(0, 100, ushort.MinValue, 0)]
public void RemapMinMaxTest(object min, object max, object value, object expected)
{
Assert.AreEqual(expected, new RangeAttribute(min, max).RemapMinMax(value));
}
#endregion
}
}

View 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));
}
}
}

View File

@@ -0,0 +1,219 @@
using System;
using ICD.Common.Utils.Collections;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Collections
{
[TestFixture]
public sealed class BiDictionaryTest
{
#region Properties
[Test]
public void CountTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
dict.Set(1, "10");
dict.Set(2, "10");
dict.Set(3, "30");
Assert.AreEqual(2, dict.Count);
}
[Test]
public void KeysTest()
{
BiDictionary<int, string> dict = new BiDictionary<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));
}
[Test]
public void ValuesTest()
{
BiDictionary<int, string> dict = new BiDictionary<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"));
}
#endregion
#region Methods
[Test]
public void ClearTest()
{
BiDictionary<int, string> dict = new BiDictionary<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()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
Assert.IsFalse(dict.ContainsKey(1));
dict.Set(1, "10");
Assert.IsTrue(dict.ContainsKey(1));
}
[Test]
public void ContainsValueTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
Assert.IsFalse(dict.ContainsValue("10"));
dict.Set(1, "10");
Assert.IsTrue(dict.ContainsValue("10"));
}
[Test]
public void AddTest()
{
BiDictionary<int, string> dict = new BiDictionary<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.Throws<ArgumentException>(() => dict.Add(2, "10"));
Assert.DoesNotThrow(() => dict.Add(2, "20"));
Assert.AreEqual(2, dict.Count);
}
[Test]
public void SetTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
dict.Set(1, "10");
dict.Set(1, "20");
dict.Set(3, "30");
Assert.AreEqual("20", dict.GetValue(1));
Assert.AreEqual("30", dict.GetValue(3));
Assert.AreEqual(1, dict.GetKey("20"));
Assert.AreEqual(3, dict.GetKey("30"));
}
[Test]
public void GetKeyTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
dict.Set(1, "10");
dict.Set(1, "20");
dict.Set(3, "30");
Assert.AreEqual(1, dict.GetKey("20"));
Assert.AreEqual(3, dict.GetKey("30"));
}
[Test]
public void GetValueTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
dict.Set(1, "10");
dict.Set(1, "20");
dict.Set(3, "30");
Assert.AreEqual("20", dict.GetValue(1));
Assert.AreEqual("30", dict.GetValue(3));
}
[Test]
public void RemoveKeyTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
dict.Add(1, "10");
Assert.AreEqual(1, dict.Count);
dict.RemoveKey(1);
Assert.AreEqual(0, dict.Count);
}
[Test]
public void RemoveValueTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
dict.Add(1, "10");
Assert.AreEqual(1, dict.Count);
dict.RemoveValue("10");
Assert.AreEqual(0, dict.Count);
}
[Test]
public void TryGetValueTest()
{
BiDictionary<int, string> dict = new BiDictionary<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 TryGetKeyTest()
{
BiDictionary<int, string> dict = new BiDictionary<int, string>();
int value;
Assert.IsFalse(dict.TryGetKey("10", out value));
Assert.AreEqual(0, value);
dict.Add(1, "10");
Assert.IsTrue(dict.TryGetKey("10", out value));
Assert.AreEqual(1, value);
}
#endregion
}
}

View File

@@ -8,12 +8,6 @@ namespace ICD.Common.Utils.Tests.Collections
[TestFixture]
public sealed class IcdHashSetTest
{
[Test, UsedImplicitly]
public void NullSetTest()
{
Assert.AreEqual(0, IcdHashSet<int>.NullSet.Count);
}
[Test, UsedImplicitly]
public void CountTest()
{

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Collections;
using NUnit.Framework;
@@ -7,120 +8,85 @@ namespace ICD.Common.Utils.Tests.Collections
[TestFixture]
public sealed class IcdOrderedDictionaryTest
{
#region Properties
[Test]
public void CountTest()
public void OrderingTest()
{
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>
IcdOrderedDictionary<string, string> dict = new IcdOrderedDictionary<string, string>
{
{0, 0},
{1, 10},
{2, 20}
{"1", "a"},
{"2", "b"},
{"3", "c"}
};
Assert.AreEqual(3, dict.Count);
Assert.IsTrue(dict.Keys.SequenceEqual(new[] {"1", "2", "3"}));
Assert.IsTrue(dict.Values.SequenceEqual(new[] { "a", "b", "c" }));
// Remove the key and add to the end of the dictionary
dict.Remove("2");
dict["2"] = "d";
Assert.IsTrue(dict.Keys.SequenceEqual(new[] { "1", "3", "2" }));
Assert.IsTrue(dict.Values.SequenceEqual(new[] { "a", "c", "d" }));
// No key change
dict["1"] = "e";
Assert.IsTrue(dict.Keys.SequenceEqual(new[] { "1", "3", "2" }));
Assert.IsTrue(dict.Values.SequenceEqual(new[] { "e", "c", "d" }));
}
[Test]
public void IsReadOnlyTest()
public void GetTest()
{
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>();
Assert.IsFalse(dict.IsReadOnly);
}
[Test]
public void KeysTest()
{
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>
IcdOrderedDictionary<string, string> dict = new IcdOrderedDictionary<string, string>
{
{0, 0},
{1, 10},
{-1, -10}
{"1", "a"},
{"2", "b"},
{"3", "c"}
};
int[] keys = dict.Keys.ToArray();
KeyValuePair<string, string> kvp = dict.Get(0);
Assert.AreEqual("1", kvp.Key);
Assert.AreEqual("a", kvp.Value);
Assert.AreEqual(3, keys.Length);
Assert.AreEqual(-1, keys[0]);
Assert.AreEqual(0, keys[1]);
Assert.AreEqual(1, keys[2]);
kvp = dict.Get(1);
Assert.AreEqual("2", kvp.Key);
Assert.AreEqual("b", kvp.Value);
kvp = dict.Get(2);
Assert.AreEqual("3", kvp.Key);
Assert.AreEqual("c", kvp.Value);
// Remove the key and add to the end of the dictionary
dict.Remove("2");
dict["2"] = "d";
kvp = dict.Get(0);
Assert.AreEqual("1", kvp.Key);
Assert.AreEqual("a", kvp.Value);
kvp = dict.Get(1);
Assert.AreEqual("3", kvp.Key);
Assert.AreEqual("c", kvp.Value);
kvp = dict.Get(2);
Assert.AreEqual("2", kvp.Key);
Assert.AreEqual("d", kvp.Value);
// No key change
dict["1"] = "e";
kvp = dict.Get(0);
Assert.AreEqual("1", kvp.Key);
Assert.AreEqual("e", kvp.Value);
kvp = dict.Get(1);
Assert.AreEqual("3", kvp.Key);
Assert.AreEqual("c", kvp.Value);
kvp = dict.Get(2);
Assert.AreEqual("2", kvp.Key);
Assert.AreEqual("d", kvp.Value);
}
[Test]
public void ValuesTest()
{
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>
{
{0, 0},
{1, 10},
{-1, -10}
};
int[] values = dict.Values.ToArray();
Assert.AreEqual(3, values.Length);
Assert.AreEqual(-10, values[0]);
Assert.AreEqual(0, values[1]);
Assert.AreEqual(10, values[2]);
}
[Test]
public void IndexerTest()
{
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>
{
{0, 0},
{1, 10},
{-1, -10}
};
Assert.AreEqual(0, dict[0]);
Assert.AreEqual(10, dict[1]);
Assert.AreEqual(-10, dict[-1]);
}
#endregion
#region Methods
[Test]
public void GetEnumeratorTest()
{
Assert.Inconclusive();
}
[Test]
public void AddTest()
{
Assert.Inconclusive();
}
[Test]
public void ClearTest()
{
Assert.Inconclusive();
}
[Test]
public void ContainsKeyTest()
{
Assert.Inconclusive();
}
[Test]
public void RemoveTest()
{
Assert.Inconclusive();
}
[Test]
public void TryGetValueTest()
{
Assert.Inconclusive();
}
#endregion
}
}

View File

@@ -0,0 +1,136 @@
using System.Linq;
using ICD.Common.Utils.Collections;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Collections
{
[TestFixture]
public sealed class IcdSortedDictionaryTest
{
#region Properties
[Test]
public void CountTest()
{
IcdSortedDictionary<int, int> dict = new IcdSortedDictionary<int, int>
{
{0, 0},
{1, 10},
{2, 20}
};
Assert.AreEqual(3, dict.Count);
}
[Test]
public void IsReadOnlyTest()
{
IcdSortedDictionary<int, int> dict = new IcdSortedDictionary<int, int>();
Assert.IsFalse(dict.IsReadOnly);
}
[Test]
public void KeysTest()
{
IcdSortedDictionary<int, int> dict = new IcdSortedDictionary<int, int>
{
{0, 0},
{1, 10},
{-1, -10}
};
int[] keys = dict.Keys.ToArray();
Assert.AreEqual(3, keys.Length);
Assert.AreEqual(-1, keys[0]);
Assert.AreEqual(0, keys[1]);
Assert.AreEqual(1, keys[2]);
}
[Test]
public void ValuesTest()
{
IcdSortedDictionary<int, int> dict = new IcdSortedDictionary<int, int>
{
{0, 0},
{1, 10},
{-1, -10}
};
int[] values = dict.Values.ToArray();
Assert.AreEqual(3, values.Length);
Assert.AreEqual(-10, values[0]);
Assert.AreEqual(0, values[1]);
Assert.AreEqual(10, values[2]);
}
[Test]
public void IndexerTest()
{
// ReSharper disable UseObjectOrCollectionInitializer
IcdSortedDictionary<int, int> dict = new IcdSortedDictionary<int, int>();
// ReSharper restore UseObjectOrCollectionInitializer
dict[0] = 0;
dict[1] = 10;
dict[-1] = -10;
dict[-1] = -11;
Assert.AreEqual(0, dict[0]);
Assert.AreEqual(10, dict[1]);
Assert.AreEqual(-11, dict[-1]);
Assert.AreEqual(3, dict.Count);
int[] expectedKeys = {-1, 0, 1 };
int[] expectedValues = {-11, 0, 10};
Assert.AreEqual(expectedKeys, dict.Keys.ToArray());
Assert.AreEqual(expectedValues, dict.Values.ToArray());
}
#endregion
#region Methods
[Test]
public void GetEnumeratorTest()
{
Assert.Inconclusive();
}
[Test]
public void AddTest()
{
Assert.Inconclusive();
}
[Test]
public void ClearTest()
{
Assert.Inconclusive();
}
[Test]
public void ContainsKeyTest()
{
Assert.Inconclusive();
}
[Test]
public void RemoveTest()
{
Assert.Inconclusive();
}
[Test]
public void TryGetValueTest()
{
Assert.Inconclusive();
}
#endregion
}
}

View File

@@ -133,8 +133,8 @@ namespace ICD.Common.Utils.Tests.Collections
};
Assert.AreEqual(1, dequeue[0]);
Assert.AreEqual(4, dequeue[1]);
Assert.AreEqual(3, dequeue[2]);
Assert.AreEqual(3, dequeue[1]);
Assert.AreEqual(4, dequeue[2]);
}
[Test]
@@ -168,6 +168,29 @@ namespace ICD.Common.Utils.Tests.Collections
Assert.AreEqual(0, queue.Count);
}
[Test]
public void TryDequeueTest()
{
PriorityQueue<int> queue = new PriorityQueue<int>();
queue.Enqueue(10, 1);
queue.Enqueue(20, 2);
queue.Enqueue(30, 3);
int output;
Assert.IsTrue(queue.TryDequeue(out output));
Assert.AreEqual(10, output);
Assert.IsTrue(queue.TryDequeue(out output));
Assert.AreEqual(20, output);
Assert.IsTrue(queue.TryDequeue(out output));
Assert.AreEqual(30, output);
Assert.IsFalse(queue.TryDequeue(out output));
Assert.AreEqual(0, output);
}
[Test]
public void GetEnumeratorTest()
{

View File

@@ -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
}
}

View File

@@ -11,12 +11,14 @@ namespace ICD.Common.Utils.Tests.Collections
[Test, UsedImplicitly]
public void MaxSizeTest()
{
int unused;
ScrollQueue<int> test = new ScrollQueue<int>(5);
test.Enqueue(0);
test.Enqueue(1);
test.Enqueue(2);
test.Enqueue(3);
test.Enqueue(4);
test.Enqueue(0, out unused);
test.Enqueue(1, out unused);
test.Enqueue(2, out unused);
test.Enqueue(3, out unused);
test.Enqueue(4, out unused);
Assert.AreEqual(5, test.Count);
@@ -25,7 +27,7 @@ namespace ICD.Common.Utils.Tests.Collections
Assert.AreEqual(3, test.Count);
Assert.AreEqual(2, test.Peek());
test.Enqueue(0);
test.Enqueue(0, out unused);
Assert.AreEqual(3, test.Count);
Assert.AreEqual(3, test.Peek());
@@ -34,8 +36,10 @@ namespace ICD.Common.Utils.Tests.Collections
[Test, UsedImplicitly]
public void ClearTest()
{
int unused;
ScrollQueue<int> test = new ScrollQueue<int>(5);
test.Enqueue(0);
test.Enqueue(0, out unused);
test.Clear();
Assert.AreEqual(0, test.Count);
@@ -44,9 +48,11 @@ namespace ICD.Common.Utils.Tests.Collections
[Test, UsedImplicitly]
public void EnqueueTest()
{
int unused;
ScrollQueue<int> test = new ScrollQueue<int>(5);
test.Enqueue(0);
test.Enqueue(1);
test.Enqueue(0, out unused);
test.Enqueue(1, out unused);
Assert.AreEqual(2, test.Count);
@@ -59,9 +65,11 @@ namespace ICD.Common.Utils.Tests.Collections
[Test, UsedImplicitly]
public void DequeueTest()
{
int unused;
ScrollQueue<int> test = new ScrollQueue<int>(5);
test.Enqueue(0);
test.Enqueue(1);
test.Enqueue(0, out unused);
test.Enqueue(1, out unused);
Assert.AreEqual(0, test.Dequeue());
Assert.AreEqual(1, test.Count);
@@ -70,9 +78,11 @@ namespace ICD.Common.Utils.Tests.Collections
[Test, UsedImplicitly]
public void PeekTest()
{
int unused;
ScrollQueue<int> test = new ScrollQueue<int>(5);
test.Enqueue(0);
test.Enqueue(1);
test.Enqueue(0, out unused);
test.Enqueue(1, out unused);
Assert.AreEqual(0, test.Peek());
}

View File

@@ -0,0 +1,33 @@
using ICD.Common.Utils.Comparers;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Comparers
{
[TestFixture]
public sealed class SequenceComparerTest
{
[Test]
public void CompareTest()
{
SequenceComparer<int> comparer = new SequenceComparer<int>();
// Equal
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
Assert.AreEqual(0, comparer.Compare(a, b));
// A comes before B
a = new[] {1, 2};
b = new[] {1, 2, 3};
Assert.AreEqual(-1, comparer.Compare(a, b));
// B comes before A
a = new[] { 2, 2, 3 };
b = new[] { 1, 2, 3 };
Assert.AreEqual(1, comparer.Compare(a, b));
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using ICD.Common.Utils.Comparers;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Comparers
{
[TestFixture]
public sealed class UndefinedVersionComparerTest
{
[Test]
public void CompareToTest()
{
Assert.AreEqual(0, UndefinedVersionComparer.Instance.Compare(new Version(0, 0), new Version(0, 0, 0, 0)));
Assert.AreEqual(-1, UndefinedVersionComparer.Instance.Compare(new Version(0, 0), new Version(1, 0, 0, 0)));
Assert.AreEqual(1, UndefinedVersionComparer.Instance.Compare(new Version(1, 0), new Version(0, 0, 0, 0)));
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using ICD.Common.Utils.Comparers;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Comparers
{
[TestFixture]
public sealed class UndefinedVersionEqualityComparerTest
{
[Test]
public void Equals()
{
Assert.IsTrue(UndefinedVersionEqualityComparer.Instance.Equals(new Version(0, 0), new Version(0, 0, 0, 0)));
Assert.IsFalse(UndefinedVersionEqualityComparer.Instance.Equals(new Version(0, 0), new Version(1, 0, 0, 0)));
}
}
}

View File

@@ -0,0 +1,17 @@
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class DateTimeUtilsTest
{
[TestCase(1, 1)]
[TestCase(0, 12)]
[TestCase(12, 12)]
[TestCase(23, 11)]
public void To12HourTest(int hour, int expected)
{
Assert.AreEqual(expected, DateTimeUtils.To12Hour(hour));
}
}
}

View File

@@ -5,12 +5,12 @@ using System.Linq;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class EnumUtilsTest
{
public sealed class EnumUtilsTest
{
public enum eTestEnum
{
None = 0,
A = 1,
A = 1,
B = 2,
C = 3,
}
@@ -22,9 +22,10 @@ namespace ICD.Common.Utils.Tests
A = 1,
B = 2,
C = 4,
D = 32
D = 32,
BandC = B | C
}
[Test]
public void GetValuesTest()
{
@@ -36,16 +37,6 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(eTestEnum.B, values[2]);
Assert.AreEqual(eTestEnum.C, values[3]);
}
[Test]
public void IsEnumTypeTest()
{
Assert.IsTrue(EnumUtils.IsEnumType(typeof(eTestEnum)));
Assert.IsTrue(EnumUtils.IsEnumType(typeof(eTestFlagsEnum)));
Assert.IsTrue(EnumUtils.IsEnumType(typeof(Enum)));
Assert.IsFalse(EnumUtils.IsEnumType(typeof(EnumUtilsTest)));
Assert.Throws<ArgumentNullException>(() => EnumUtils.IsEnumType(null));
}
[Test]
public void IsEnumTypeGenericTest()
@@ -63,29 +54,32 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(EnumUtils.IsEnum(eTestFlagsEnum.A));
Assert.IsTrue(EnumUtils.IsEnum(eTestEnum.A as object));
Assert.IsTrue(EnumUtils.IsEnum(eTestEnum.A as Enum));
Assert.IsFalse(EnumUtils.IsEnum(null));
Assert.IsFalse(EnumUtils.IsEnum<Enum>(null));
Assert.IsFalse(EnumUtils.IsEnum(""));
}
[Test]
public void IsDefinedTest()
{
Assert.IsFalse(EnumUtils.IsDefined((eTestEnum)20));
Assert.IsTrue(EnumUtils.IsDefined((eTestEnum)2));
Assert.IsFalse(EnumUtils.IsDefined((eTestFlagsEnum)8));
Assert.IsTrue(EnumUtils.IsDefined((eTestFlagsEnum)3));
}
#region Values
[Test]
public void GetUnderlyingValueTest()
[Test]
public void IsDefinedTest()
{
Assert.AreEqual(0, EnumUtils.GetUnderlyingValue(eTestEnum.None));
Assert.AreEqual(1, EnumUtils.GetUnderlyingValue(eTestEnum.A));
Assert.AreEqual(2, EnumUtils.GetUnderlyingValue(eTestEnum.B));
Assert.AreEqual(3, EnumUtils.GetUnderlyingValue(eTestEnum.C));
Assert.IsFalse(EnumUtils.IsDefined((eTestEnum)20));
Assert.IsTrue(EnumUtils.IsDefined((eTestEnum)2));
Assert.IsFalse(EnumUtils.IsDefined((eTestFlagsEnum)8));
Assert.IsTrue(EnumUtils.IsDefined((eTestFlagsEnum)3));
}
#region Values
[Test]
public void GetNamesTest()
{
string[] names = EnumUtils.GetNames<eTestEnum>().ToArray();
Assert.AreEqual(4, names.Length);
Assert.IsTrue(names.Contains("None"));
Assert.IsTrue(names.Contains("A"));
Assert.IsTrue(names.Contains("B"));
Assert.IsTrue(names.Contains("C"));
}
[Test]
@@ -100,13 +94,6 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(values.Contains(eTestEnum.C));
}
[Test]
public void GetNoneValueGenericTest()
{
Assert.AreEqual(eTestEnum.None, EnumUtils.GetNoneValue<eTestEnum>());
Assert.AreEqual(eTestFlagsEnum.None, EnumUtils.GetNoneValue<eTestFlagsEnum>());
}
[Test]
public void GetValuesExceptNoneGenericTest()
{
@@ -119,18 +106,6 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(values.Contains(eTestEnum.C));
}
[Test]
public void GetValuesExceptNoneTest()
{
object[] values = EnumUtils.GetValuesExceptNone(typeof(eTestEnum)).ToArray();
Assert.AreEqual(3, values.Length);
Assert.IsFalse(values.Contains(eTestEnum.None));
Assert.IsTrue(values.Contains(eTestEnum.A));
Assert.IsTrue(values.Contains(eTestEnum.B));
Assert.IsTrue(values.Contains(eTestEnum.C));
}
#endregion
#region Flags
@@ -142,17 +117,12 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(EnumUtils.IsFlagsEnum<eTestFlagsEnum>());
}
[Test]
public void IsFlagsEnumTest()
{
Assert.IsFalse(EnumUtils.IsFlagsEnum(typeof(eTestEnum)));
Assert.IsTrue(EnumUtils.IsFlagsEnum(typeof(eTestFlagsEnum)));
}
[Test]
public void GetFlagsIntersectionGenericTest()
{
Assert.AreEqual(eTestFlagsEnum.B, EnumUtils.GetFlagsIntersection(eTestFlagsEnum.A | eTestFlagsEnum.B, eTestFlagsEnum.B | eTestFlagsEnum.C));
Assert.AreEqual(eTestFlagsEnum.B,
EnumUtils.GetFlagsIntersection(eTestFlagsEnum.A | eTestFlagsEnum.B,
eTestFlagsEnum.B | eTestFlagsEnum.C));
}
[Test]
@@ -183,11 +153,11 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(aValues.Contains(eTestFlagsEnum.D));
}
[Test]
public void GetAllFlagCombinationsExceptNoneGenericTest()
{
eTestFlagsEnum a = eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D;
eTestFlagsEnum[] aValues = EnumUtils.GetAllFlagCombinationsExceptNone(a).ToArray();
[Test]
public void GetAllFlagCombinationsExceptNoneGenericTest()
{
eTestFlagsEnum a = eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D;
eTestFlagsEnum[] aValues = EnumUtils.GetAllFlagCombinationsExceptNone(a).ToArray();
Assert.AreEqual(15, aValues.Length);
Assert.IsFalse(aValues.Contains(eTestFlagsEnum.None));
@@ -212,7 +182,18 @@ namespace ICD.Common.Utils.Tests
public void GetFlagsAllValueGenericTest()
{
eTestFlagsEnum value = EnumUtils.GetFlagsAllValue<eTestFlagsEnum>();
Assert.AreEqual(eTestFlagsEnum.None | eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D, value);
Assert.AreEqual(eTestFlagsEnum.None | eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D,
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]
@@ -226,7 +207,8 @@ namespace ICD.Common.Utils.Tests
public void HasFlagsGenericTest()
{
Assert.IsTrue(EnumUtils.HasFlags(eTestFlagsEnum.A | eTestFlagsEnum.B, eTestFlagsEnum.A | eTestFlagsEnum.B));
Assert.IsFalse(EnumUtils.HasFlags(eTestFlagsEnum.A | eTestFlagsEnum.B, eTestFlagsEnum.A | eTestFlagsEnum.C));
Assert.IsFalse(EnumUtils.HasFlags(eTestFlagsEnum.A | eTestFlagsEnum.B,
eTestFlagsEnum.A | eTestFlagsEnum.C));
}
[Test]
@@ -245,28 +227,28 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(EnumUtils.HasMultipleFlags(eTestFlagsEnum.A | eTestFlagsEnum.B));
}
[TestCase(false, eTestFlagsEnum.None)]
[TestCase(true, eTestFlagsEnum.B)]
[TestCase(true, eTestFlagsEnum.B | eTestFlagsEnum.C)]
public void HasAnyFlagsTest(bool expected, eTestFlagsEnum value)
{
Assert.AreEqual(expected, EnumUtils.HasAnyFlags(value));
}
[TestCase(false, eTestFlagsEnum.None)]
[TestCase(true, eTestFlagsEnum.B)]
[TestCase(true, eTestFlagsEnum.B | eTestFlagsEnum.C)]
public void HasAnyFlagsTest(bool expected, eTestFlagsEnum value)
{
Assert.AreEqual(expected, EnumUtils.HasAnyFlags(value));
}
[TestCase(false, eTestFlagsEnum.None, eTestFlagsEnum.None)]
[TestCase(false, eTestFlagsEnum.None, eTestFlagsEnum.B)]
[TestCase(true, eTestFlagsEnum.B, eTestFlagsEnum.B)]
[TestCase(false, eTestFlagsEnum.None | eTestFlagsEnum.A, eTestFlagsEnum.B | eTestFlagsEnum.C)]
public void HasAnyFlagsValueTest(bool expected, eTestFlagsEnum value, eTestFlagsEnum other)
{
Assert.AreEqual(expected, EnumUtils.HasAnyFlags(value, other));
}
[TestCase(false, eTestFlagsEnum.None, eTestFlagsEnum.None)]
[TestCase(false, eTestFlagsEnum.None, eTestFlagsEnum.B)]
[TestCase(true, eTestFlagsEnum.B, eTestFlagsEnum.B)]
[TestCase(false, eTestFlagsEnum.None | eTestFlagsEnum.A, eTestFlagsEnum.B | eTestFlagsEnum.C)]
public void HasAnyFlagsValueTest(bool expected, eTestFlagsEnum value, eTestFlagsEnum other)
{
Assert.AreEqual(expected, EnumUtils.HasAnyFlags(value, other));
}
#endregion
#endregion
#region Conversion
#region Conversion
[Test]
[Test]
public void ParseGenericTest()
{
Assert.AreEqual(eTestEnum.A, EnumUtils.Parse<eTestEnum>("A", false));
@@ -288,48 +270,46 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(default(eTestEnum), output);
}
[Test]
public void ParseStrictGenericTest()
{
Assert.AreEqual(eTestEnum.A, EnumUtils.ParseStrict<eTestEnum>("1", false));
Assert.Throws<ArgumentOutOfRangeException>(() => EnumUtils.ParseStrict<eTestEnum>("4", false));
Assert.AreEqual(eTestFlagsEnum.A | eTestFlagsEnum.B, EnumUtils.ParseStrict<eTestFlagsEnum>("3", false));
Assert.Throws<ArgumentOutOfRangeException>(() => EnumUtils.ParseStrict<eTestFlagsEnum>("8", false));
}
[Test]
public void TryParseStrictGenericTest()
{
eTestEnum outputA;
Assert.AreEqual(true, EnumUtils.TryParseStrict("1", false, out outputA));
Assert.AreEqual(eTestEnum.A, outputA);
Assert.AreEqual(false, EnumUtils.TryParseStrict("4", false, out outputA));
Assert.AreEqual(eTestEnum.None, outputA);
eTestFlagsEnum outputB;
Assert.AreEqual(true, EnumUtils.TryParseStrict("3", false, out outputB));
Assert.AreEqual(eTestFlagsEnum.A | eTestFlagsEnum.B, outputB);
Assert.AreEqual(false, EnumUtils.TryParseStrict("8", false, out outputB));
Assert.AreEqual(eTestFlagsEnum.None, outputB);
}
[Test]
public void ToEnumGenericTest()
[Test]
public void ParseStrictGenericTest()
{
Assert.AreEqual(eTestEnum.A, EnumUtils.ToEnum(eTestEnum.A));
Assert.AreNotEqual(eTestEnum.B, EnumUtils.ToEnum(eTestEnum.A));
Assert.AreEqual(eTestEnum.A, EnumUtils.ParseStrict<eTestEnum>("1", false));
Assert.Throws<ArgumentOutOfRangeException>(() => EnumUtils.ParseStrict<eTestEnum>("4", false));
Assert.AreEqual(eTestFlagsEnum.A | eTestFlagsEnum.B, EnumUtils.ParseStrict<eTestFlagsEnum>("3", false));
Assert.Throws<ArgumentOutOfRangeException>(() => EnumUtils.ParseStrict<eTestFlagsEnum>("8", false));
}
[Test]
public void ToEnumTest()
public void TryParseStrictGenericTest()
{
Assert.AreEqual(eTestEnum.A, EnumUtils.ToEnum((object)eTestEnum.A));
Assert.AreNotEqual(eTestEnum.B, EnumUtils.ToEnum((object)eTestEnum.A));
eTestEnum outputA;
Assert.AreEqual(true, EnumUtils.TryParseStrict("1", false, out outputA));
Assert.AreEqual(eTestEnum.A, outputA);
Assert.AreEqual(false, EnumUtils.TryParseStrict("4", false, out outputA));
Assert.AreEqual(eTestEnum.None, outputA);
eTestFlagsEnum outputB;
Assert.AreEqual(true, EnumUtils.TryParseStrict("3", false, out outputB));
Assert.AreEqual(eTestFlagsEnum.A | eTestFlagsEnum.B, outputB);
Assert.AreEqual(false, EnumUtils.TryParseStrict("8", false, out outputB));
Assert.AreEqual(eTestFlagsEnum.None, outputB);
}
#endregion
#region Formatting
[TestCase(eTestFlagsEnum.A | eTestFlagsEnum.B | eTestFlagsEnum.C | (eTestFlagsEnum)8,
"A, B, C, 8")]
public void ToStringUndefinedTest(eTestFlagsEnum value, string expected)
{
string toString = EnumUtils.ToStringUndefined(value);
Assert.AreEqual(expected, toString);
}
#endregion

View File

@@ -3,16 +3,16 @@
namespace ICD.Common.Utils.Tests.Extensions
{
[TestFixture]
public sealed class DateTimeExtensionsTest
{
[Test]
public static void ToShortTimeStringTest()
{
Assert.Inconclusive();
}
public sealed class DateTimeExtensionsTest
{
[Test]
public void ToShortTimeStringTest()
{
Assert.Inconclusive();
}
[Test]
public static void ToLongTimeStringWithMillisecondsTest()
public void ToLongTimeStringWithMillisecondsTest()
{
Assert.Inconclusive();
}

View File

@@ -301,5 +301,29 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(20, ordered[1]);
Assert.AreEqual(30, ordered[2]);
}
[Test]
public void ToInverseTest()
{
Dictionary<int, string> forward = new Dictionary<int, string>
{
{ 1, "testA" },
{ 2, "testA" },
{ 3, "testB" },
{ 4, "testB" }
};
Dictionary<string, List<int>> backwards = new Dictionary<string, List<int>>
{
{"testA", new List<int> {1, 2}},
{"testB", new List<int> {3, 4}}
};
Dictionary<string, List<int>> inverse = forward.ToInverse();
bool equal = inverse.DictionaryEqual(backwards, (v1, v2) => v1.ScrambledEquals(v2));
Assert.IsTrue(equal);
}
}
}

View File

@@ -32,5 +32,17 @@ namespace ICD.Common.Utils.Tests.Extensions
{
Assert.AreEqual(expected, value.HasFlags(flags));
}
[TestCase(eTestEnum.A, eTestEnum.B)]
[TestCase(eTestEnum.B, eTestEnum.C)]
[TestCase(eTestEnum.C, eTestEnum.A)]
[TestCase(eTestEnum.A | eTestEnum.B, null)]
public void CycleNextTest(eTestEnum value, eTestEnum? expected)
{
if (EnumUtils.HasMultipleFlags(value))
Assert.Catch(typeof(InvalidOperationException), () => value.CycleNext());
else
Assert.AreEqual(expected, value.CycleNext());
}
}
}

View File

@@ -284,6 +284,15 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(5, items.Length);
}
[TestCase(true)]
[TestCase(true, 1, 2, 3, 4)]
[TestCase(true, 1, 2, 2, 3, 4)]
[TestCase(false, 4, 3, 2, 1)]
public void AreOrderedTest(bool expected, params int[] items)
{
Assert.AreEqual(expected, items.AreOrdered());
}
[Test]
public void OrderTest()
{
@@ -335,9 +344,9 @@ namespace ICD.Common.Utils.Tests.Extensions
}
[Test]
public void ToDictionaryIntTest()
public void ToIndexedDictionaryTest()
{
Dictionary<int, int> values = new[] {1, 2, 3}.ToDictionary();
Dictionary<int, int> values = new[] {1, 2, 3}.ToIndexedDictionary();
Assert.AreEqual(3, values.Count);
Assert.AreEqual(1, values[0]);
@@ -346,9 +355,9 @@ namespace ICD.Common.Utils.Tests.Extensions
}
[Test]
public void ToDictionaryUIntTest()
public void ToIndexedDictionaryUIntTest()
{
Dictionary<uint, int> values = new[] {1, 2, 3}.ToDictionaryUInt();
Dictionary<uint, int> values = new[] {1, 2, 3}.ToIndexedDictionaryUInt();
Assert.AreEqual(3, values.Count);
Assert.AreEqual(1, values[0]);
@@ -400,10 +409,19 @@ namespace ICD.Common.Utils.Tests.Extensions
[Test]
public void UnanimousTest()
{
Assert.IsTrue(new[] {true, true, true}.Unanimous());
Assert.IsTrue(new[] {false, false, false}.Unanimous());
Assert.IsFalse(new[] {false, true, false}.Unanimous());
Assert.IsFalse(new bool[] { }.Unanimous());
bool result;
Assert.IsTrue(new[] {true, true, true}.Unanimous(out result));
Assert.IsTrue(result);
Assert.IsTrue(new[] {false, false, false}.Unanimous(out result));
Assert.IsFalse(result);
Assert.IsFalse(new[] {false, true, false}.Unanimous(out result));
Assert.AreEqual(default(bool), result);
Assert.IsFalse(new bool[] { }.Unanimous(out result));
Assert.AreEqual(default(bool), result);
}
[Test]
@@ -519,7 +537,7 @@ namespace ICD.Common.Utils.Tests.Extensions
[Test]
public void ConsolidateComparerTest()
{
string[] sequence = new[] {"A", "B", "B", "C"}.Consolidate(Comparer<string>.Default).ToArray();
string[] sequence = new[] {"A", "B", "B", "C"}.Consolidate(EqualityComparer<string>.Default).ToArray();
Assert.AreEqual(3, sequence.Length, StringUtils.ArrayFormat(sequence));
Assert.AreEqual("A", sequence[0]);

View File

@@ -1,9 +1,15 @@
using System.Collections.Generic;
#if NETFRAMEWORK
extern alias RealNewtonsoft;
using RealNewtonsoft.Newtonsoft.Json;
#else
using Newtonsoft.Json;
#endif
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ICD.Common.Utils.Extensions;
using Newtonsoft.Json;
using ICD.Common.Utils.IO;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
@@ -17,6 +23,36 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.Inconclusive();
}
[Test]
public void ReadObjectTest()
{
const string json =
"{\"name\":\"Test\",\"help\":\"Test test.\",\"type\":\"System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\",\"value\":\"Test\"}";
Dictionary<string, string> expected = new Dictionary<string, string>
{
{"name", "Test"},
{"help", "Test test."},
{"type", "System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"},
{"value", "Test"}
};
Dictionary<string, string> deserialized = new Dictionary<string, string>();
using (IcdStringReader textReader = new IcdStringReader(json))
{
using (JsonReader reader = new JsonTextReader(textReader.WrappedTextReader))
{
JsonSerializer serializer = new JsonSerializer();
reader.Read();
reader.ReadObject(serializer, (p, r, s) => deserialized.Add(p, (string)r.Value));
}
}
Assert.IsTrue(deserialized.DictionaryEqual(expected));
}
[Test]
public void GetValueAsIntTest()
{
@@ -78,53 +114,5 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.IsTrue(deserialized.SequenceEqual(new[] {1, 2, 3, 4}));
}
[Test]
public void SerializeDictionaryTest()
{
Dictionary<int, string> dict = new Dictionary<int, string>
{
{1, "Item 1"},
{10, "Item 2"},
{15, "Item 3"}
};
JsonSerializer serializer = new JsonSerializer();
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
{
using (JsonWriter writer = new JsonTextWriter(stringWriter))
{
serializer.SerializeDictionary(writer, dict);
}
}
string json = stringBuilder.ToString();
Assert.AreEqual("{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}", json);
}
[Test]
public void DeserializeDictionaryTest()
{
const string json = "{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}";
JsonSerializer serializer = new JsonSerializer();
Dictionary<int, string> deserialized;
using (StringReader stringReader = new StringReader(json))
{
using (JsonReader reader = new JsonTextReader(stringReader))
{
reader.Read();
deserialized = serializer.DeserializeDictionary<int, string>(reader).ToDictionary();
}
}
Assert.AreEqual(3, deserialized.Count);
Assert.AreEqual("Item 1", deserialized[1]);
Assert.AreEqual("Item 2", deserialized[10]);
Assert.AreEqual("Item 3", deserialized[15]);
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
@@ -9,14 +8,14 @@ namespace ICD.Common.Utils.Tests.Extensions
public sealed class ListExtensionsTest
{
[Test]
public void AddSortedTest()
public void InsertSortedTest()
{
List<int> testList = new List<int>();
testList.AddSorted(2);
testList.AddSorted(3);
testList.AddSorted(1);
testList.AddSorted(2);
Assert.AreEqual(0, testList.InsertSorted(2));
Assert.AreEqual(1, testList.InsertSorted(3));
Assert.AreEqual(0, testList.InsertSorted(1));
Assert.AreEqual(1, testList.InsertSorted(2));
Assert.AreEqual(4, testList.Count);
Assert.AreEqual(1, testList[0]);
@@ -26,15 +25,15 @@ namespace ICD.Common.Utils.Tests.Extensions
}
[Test]
public void AddSortedComparerTest()
public void InsertSortedComparerTest()
{
List<int> testList = new List<int>();
IComparer<int> comparer = new InverseComparer();
testList.AddSorted(2, comparer);
testList.AddSorted(3, comparer);
testList.AddSorted(1, comparer);
testList.AddSorted(2, comparer);
Assert.AreEqual(0, testList.InsertSorted(2, comparer));
Assert.AreEqual(0, testList.InsertSorted(3, comparer));
Assert.AreEqual(2, testList.InsertSorted(1, comparer));
Assert.AreEqual(1, testList.InsertSorted(2, comparer));
Assert.AreEqual(4, testList.Count);
Assert.AreEqual(3, testList[0]);
@@ -43,82 +42,6 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(1, testList[3]);
}
[Test]
public void PadRightTest()
{
List<int> testList = new List<int>();
testList.PadRight(10);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(0, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(10);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(15, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(1);
Assert.AreEqual(5, testList.Count);
Assert.AreEqual(15, testList.Sum());
}
[Test]
public void PadRightDefaultTest()
{
List<int> testList = new List<int>();
testList.PadRight(10, 1);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(10, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(10, 1);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(20, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(1, 1);
Assert.AreEqual(5, testList.Count);
Assert.AreEqual(15, testList.Sum());
}
private sealed class InverseComparer : IComparer<int>
{
public int Compare(int x, int y)

View File

@@ -1,4 +1,6 @@
using NUnit.Framework;
using System;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
{
@@ -10,5 +12,221 @@ namespace ICD.Common.Utils.Tests.Extensions
{
Assert.Inconclusive();
}
#region Get/Set Property Tests
private sealed class PropertyTestClass
{
private readonly InternalPropertyTestClass m_InternalClass;
public string PropertyString { get; set; }
public int PropertyInt { get; set; }
public DateTime PropertyDateTime { get; set; }
public InternalPropertyTestClass InternalClass { get { return m_InternalClass; } }
public PropertyTestClass()
{
m_InternalClass = new InternalPropertyTestClass();
}
internal sealed class InternalPropertyTestClass
{
private readonly DeepPropertyTestClass m_DeepClass;
public string InternalPropertyString { get; set; }
public int InternalPropertyInt { get; set; }
public DateTime InternalPropertyDateTime { get; set; }
public DeepPropertyTestClass DeepClass { get { return m_DeepClass; } }
public InternalPropertyTestClass()
{
m_DeepClass = new DeepPropertyTestClass();
}
internal sealed class DeepPropertyTestClass
{
public string DeepPropertyString { get; set; }
public int DeepPropertyInt { get; set; }
public DateTime DeepPropertyDateTime { get; set; }
}
}
}
[Test]
public void GetPropertyTest()
{
var testClass = new PropertyTestClass();
int testInt = 15;
string testString = "TestString";
var testDateTime = DateTime.Parse("1987-08-27");
testClass.PropertyInt = testInt;
testClass.PropertyString = testString;
testClass.PropertyDateTime = testDateTime;
int internalTestInt = 34;
string internalTestString = "InternalTestString";
var internalTestDateTime = DateTime.Parse("2011-12-05");
testClass.InternalClass.InternalPropertyInt = internalTestInt;
testClass.InternalClass.InternalPropertyString = internalTestString;
testClass.InternalClass.InternalPropertyDateTime = internalTestDateTime;
int deepTestInt = int.MaxValue;
string deepTestString = "HelloThere";
var deepTestDateTime = DateTime.Parse("1776-07-04");
testClass.InternalClass.DeepClass.DeepPropertyInt = deepTestInt;
testClass.InternalClass.DeepClass.DeepPropertyString = deepTestString;
testClass.InternalClass.DeepClass.DeepPropertyDateTime = deepTestDateTime;
object propertyInt;
object propertyString;
object propertyDateTime;
object fakeObject;
// Test at first level
Assert.True(testClass.GetProperty(out propertyInt, "PropertyInt"), "Couldn't get PropertyInt");
Assert.AreEqual(testInt, propertyInt, "PropertyInt wasn't expected value");
Assert.True(testClass.GetProperty(out propertyString, "PropertyString"), "Couldn't Get PropertyString");
Assert.AreEqual(testString, propertyString, "PropertyString wasn't expected value");
Assert.True(testClass.GetProperty(out propertyDateTime, "PropertyDateTime"), "Couldn't get PropertyDateTime");
Assert.AreEqual(testDateTime, propertyDateTime, "PropertyDateTime wasn't expected value");
// Test properties that don't exist
Assert.False(testClass.GetProperty(out fakeObject, "FakePropertyName"));
// Test at second level
Assert.True(testClass.GetProperty(out propertyInt, "InternalClass", "InternalPropertyInt"), "Couldn't get InternalPropertyInt");
Assert.AreEqual(internalTestInt, propertyInt, "InternalPropertyInt wasn't expected value");
Assert.True(testClass.GetProperty(out propertyString, "InternalClass", "InternalPropertyString"), "Couldn't Get InternalPropertyString");
Assert.AreEqual(internalTestString, propertyString, "InternalPropertyString wasn't expected value");
Assert.True(testClass.GetProperty(out propertyDateTime, "InternalClass", "InternalPropertyDateTime"), "Couldn't get InternalPropertyDateTime");
Assert.AreEqual(internalTestDateTime, propertyDateTime, "InternalPropertyDateTime wasn't expected value");
// Test properties that don't exist
Assert.False(testClass.GetProperty(out fakeObject, "InternalClass", "FakePropertyName"));
// Test at third level
Assert.True(testClass.GetProperty(out propertyInt, "InternalClass", "DeepClass", "DeepPropertyInt"), "Couldn't get DeepPropertyInt");
Assert.AreEqual(deepTestInt, propertyInt, "DeepPropertyInt wasn't expected value");
Assert.True(testClass.GetProperty(out propertyString, "InternalClass", "DeepClass", "DeepPropertyString"), "Couldn't Get DeepPropertyString");
Assert.AreEqual(deepTestString, propertyString, "DeepPropertyString wasn't expected value");
Assert.True(testClass.GetProperty(out propertyDateTime, "InternalClass", "DeepClass", "DeepPropertyDateTime"), "Couldn't get DeepPropertyDateTime");
Assert.AreEqual(deepTestDateTime, propertyDateTime, "DeepPropertyDateTime wasn't expected value");
// Test properties that don't exist
Assert.False(testClass.GetProperty(out fakeObject, "InternalClass", "DeepClass", "FakePropertyName"));
// Test Default/Null Cases
var emptyTestClass = new PropertyTestClass();
Assert.True(emptyTestClass.GetProperty(out propertyInt, "PropertyInt"), "Couldn't get empty PropertyInt");
Assert.AreEqual(default(int), propertyInt, "Empty PropertyInt wasn't expected value");
Assert.True(emptyTestClass.GetProperty(out propertyString, "PropertyString"), "Couldn't Get empty PropertyString");
Assert.AreEqual(default(string), propertyString, "Empty PropertyString wasn't expected value");
Assert.True(emptyTestClass.GetProperty(out propertyDateTime, "PropertyDateTime"), "Couldn't get empty PropertyDateTime");
Assert.AreEqual(default(DateTime), propertyDateTime, "Empty PropertyDateTime wasn't expected value");
}
[Test]
public void SetPropertyTest()
{
var testClass = new PropertyTestClass();
int testInt = 15;
string testString = "TestString";
var testDateTime = DateTime.Parse("1987-08-27");
int internalTestInt = 34;
string internalTestString = "InternalTestString";
var internalTestDateTime = DateTime.Parse("2011-12-05");
int deepTestInt = int.MaxValue;
string deepTestString = "HelloThere";
var deepTestDateTime = DateTime.Parse("1776-07-04");
// Test at first level
Assert.True(testClass.SetProperty(testInt, "PropertyInt"), "Couldn't get PropertyInt");
Assert.AreEqual(testInt, testClass.PropertyInt, "PropertyInt wasn't expected value");
Assert.True(testClass.SetProperty(testString, "PropertyString"), "Couldn't Get PropertyString");
Assert.AreEqual(testString, testClass.PropertyString, "PropertyString wasn't expected value");
Assert.True(testClass.SetProperty(testDateTime, "PropertyDateTime"), "Couldn't get PropertyDateTime");
Assert.AreEqual(testDateTime, testClass.PropertyDateTime, "PropertyDateTime wasn't expected value");
// Test properties that don't exist
Assert.False(testClass.SetProperty("SomeObject", "FakePropertyName"));
// Test at second level
Assert.True(testClass.SetProperty(internalTestInt, "InternalClass", "InternalPropertyInt"), "Couldn't get InternalPropertyInt");
Assert.AreEqual(internalTestInt, testClass.InternalClass.InternalPropertyInt, "InternalPropertyInt wasn't expected value");
Assert.True(testClass.SetProperty(internalTestString, "InternalClass", "InternalPropertyString"), "Couldn't Get InternalPropertyString");
Assert.AreEqual(internalTestString, testClass.InternalClass.InternalPropertyString, "InternalPropertyString wasn't expected value");
Assert.True(testClass.SetProperty(internalTestDateTime, "InternalClass", "InternalPropertyDateTime"), "Couldn't get InternalPropertyDateTime");
Assert.AreEqual(internalTestDateTime, testClass.InternalClass.InternalPropertyDateTime, "InternalPropertyDateTime wasn't expected value");
// Test properties that don't exist
Assert.False(testClass.SetProperty("SomeAdditionalObject", "InternalClass", "FakePropertyName"));
// Test at third level
Assert.True(testClass.SetProperty(deepTestInt, "InternalClass", "DeepClass", "DeepPropertyInt"), "Couldn't get DeepPropertyInt");
Assert.AreEqual(deepTestInt, testClass.InternalClass.DeepClass.DeepPropertyInt, "DeepPropertyInt wasn't expected value");
Assert.True(testClass.SetProperty(deepTestString, "InternalClass", "DeepClass", "DeepPropertyString"), "Couldn't Get DeepPropertyString");
Assert.AreEqual(deepTestString, testClass.InternalClass.DeepClass.DeepPropertyString, "DeepPropertyString wasn't expected value");
Assert.True(testClass.SetProperty(deepTestDateTime, "InternalClass", "DeepClass", "DeepPropertyDateTime"), "Couldn't get DeepPropertyDateTime");
Assert.AreEqual(deepTestDateTime, testClass.InternalClass.DeepClass.DeepPropertyDateTime, "DeepPropertyDateTime wasn't expected value");
// Test properties that don't exist
Assert.False(testClass.SetProperty("ThisIsAnObjectToo", "InternalClass", "DeepClass", "FakePropertyName"));
// Test Set Default/Null
Assert.True(testClass.SetProperty(default(int), "PropertyInt"), "Couldn't get empty PropertyInt");
Assert.AreEqual(default(int), testClass.PropertyInt, "Empty PropertyInt wasn't expected value");
Assert.True(testClass.SetProperty(default(string), "PropertyString"), "Couldn't Get empty PropertyString");
Assert.AreEqual(default(string), testClass.PropertyString, "Empty PropertyString wasn't expected value");
Assert.True(testClass.SetProperty(default(DateTime), "PropertyDateTime"), "Couldn't get empty PropertyDateTime");
Assert.AreEqual(default(DateTime), testClass.PropertyDateTime, "Empty PropertyDateTime wasn't expected value");
}
[Test]
public void GetPropertyInfoTest()
{
var testClass = new PropertyTestClass();
object instance;
// Test GetPropertyInfo at various levels
Assert.AreEqual(testClass.GetType().GetProperty("PropertyString"),
testClass.GetPropertyInfo(out instance, "PropertyString"),
"First level property not expected value");
Assert.AreEqual(testClass, instance, "Unexpected property parent");
Assert.AreEqual(testClass.InternalClass.GetType().GetProperty("InternalPropertyString"),
testClass.GetPropertyInfo(out instance, "InternalClass", "InternalPropertyString"),
"Second level property not expected value");
Assert.AreEqual(testClass.InternalClass, instance, "Unexpected property parent");
Assert.AreEqual(testClass.InternalClass.DeepClass.GetType().GetProperty("DeepPropertyString"),
testClass.GetPropertyInfo(out instance, "InternalClass", "DeepClass", "DeepPropertyString"),
"Third level property not expected value");
Assert.AreEqual(testClass.InternalClass.DeepClass, instance, "Unexpected property parent");
// Property that doesn't exits should return null
Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "DeepClass", "NonExistent"));
Assert.IsNull(instance);
Assert.IsNull(testClass.GetPropertyInfo(out instance, "FakeFirstLevel", "FakeSecondLevel" , "FakeThridLevel"));
Assert.IsNull(instance);
Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "FakeSecondLevel", "ThirdLevelCanNotBeReal"));
Assert.IsNull(instance);
Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "FakeSecondLevel"));
Assert.IsNull(instance);
Assert.IsNull(testClass.GetPropertyInfo(out instance, "FakeFirstLevel"));
Assert.IsNull(instance);
}
#endregion
}
}

View File

@@ -1,91 +1,82 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
{
[TestFixture]
public sealed class StringExtensionsTest
{
[Test]
public void IndexOfTest()
{
string first;
Assert.AreEqual(5, "test1test3test2".IndexOf(new[] { "test2", "test3" }, out first));
Assert.AreEqual("test3", first);
}
[TestFixture]
public sealed class StringExtensionsTest
{
[Test]
public void IndexOfTest()
{
string first;
Assert.AreEqual(5, "test1test3test2".IndexOf(new[] {"test2", "test3"}, out first));
Assert.AreEqual("test3", first);
}
[TestCase(true, "12345", '1')]
[TestCase(false, "12345", '2')]
public void StartsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.StartsWith(character));
}
[TestCase(true, "12345", '1')]
[TestCase(false, "12345", '2')]
public void StartsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.StartsWith(character));
}
[TestCase(true, "12345", '5')]
[TestCase(false, "12345", '2')]
public void EndsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.EndsWith(character));
}
[TestCase(true, "12345", '5')]
[TestCase(false, "12345", '2')]
public void EndsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.EndsWith(character));
}
[Test]
public void SplitCharCountTest()
{
string[] split = "123-456-789-0".Split('-', 2).ToArray();
[Test]
public void SplitCharCountTest()
{
string[] split = "123-456-789-0".Split('-', 2).ToArray();
Assert.AreEqual(2, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456-789-0", split[1]);
}
Assert.AreEqual(2, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456-789-0", split[1]);
}
[Test]
public void SplitChunksizeTest()
{
string[] split = "1234567890".Split(3).ToArray();
[Test]
public void SplitChunksizeTest()
{
string[] split = "1234567890".Split(3).ToArray();
Assert.AreEqual(4, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456", split[1]);
Assert.AreEqual("789", split[2]);
Assert.AreEqual("0", split[3]);
}
Assert.AreEqual(4, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456", split[1]);
Assert.AreEqual("789", split[2]);
Assert.AreEqual("0", split[3]);
}
[Test]
public void SplitStringDelimiterTest()
{
string[] split = "1234567890".Split("23").ToArray();
[TestCase("12345", " 12 3 4 \t 5\n")]
public void RemoveWhitespaceTest(string expected, string value)
{
Assert.AreEqual(expected, value.RemoveWhitespace());
}
Assert.AreEqual(2, split.Length);
Assert.AreEqual("14567890", string.Join("", split));
}
[TestCase("1234567890", "12345", "67890")]
[TestCase("foobarfoobar", "bar", "foofoo")]
public void RemoveStringTest(string value, string other, string expected)
{
Assert.AreEqual(expected, value.Remove(other));
}
[Test]
public void SplitStringDelimitersTest()
{
string[] split = "1234567890".Split(new[] { "23", "67" }).ToArray();
[TestCase("1234567890", new[] {'2', '6'}, "13457890")]
[TestCase("912529434324", new[] {'-', '(', ')', '.', '+'}, "912529434324")]
public void RemoveCharactersTest(string value, IEnumerable<char> characters, string expected)
{
Assert.AreEqual(expected, value.Remove(characters));
}
Assert.AreEqual(3, split.Length);
Assert.AreEqual("145890", string.Join("", split));
}
[TestCase("12345", " 12 3 4 \t 5\n")]
public void RemoveWhitespaceTest(string expected, string value)
{
Assert.AreEqual(expected, value.RemoveWhitespace());
}
[Test]
public void RemoveCharactersTest()
{
Assert.AreEqual("13457890", "1234567890".Remove(new[] { '2', '6' }));
}
[TestCase(true, "27652")]
[TestCase(false, "a27652")]
public void IsNumericTest(bool expected, string value)
{
Assert.AreEqual(expected, value.IsNumeric());
}
}
[TestCase(true, "27652")]
[TestCase(false, "a27652")]
public void IsNumericTest(bool expected, string value)
{
Assert.AreEqual(expected, value.IsNumeric());
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
{
[TestFixture]
public sealed class TimeSpanExtensionsTest
{
[Test]
public void ToReadableStringTest()
{
Assert.Inconclusive();
}
[TestCase(0, 0, 0)]
[TestCase(12, 1, 13)]
[TestCase(23, 1, 0)]
[TestCase(6, -12, 18)]
public void AddHoursAndWrapTest(int hours, int addHours, int expectedHours)
{
Assert.AreEqual(expectedHours, new TimeSpan(hours, 0, 0).AddHoursAndWrap(addHours).Hours);
}
[TestCase(0, 0, 0)]
[TestCase(12, 1, 13)]
[TestCase(23, 1, 12)]
[TestCase(6, -12, 6)]
public void AddHoursAndWrap12Hour(int hours, int addHours, int expectedHours)
{
Assert.AreEqual(expectedHours, new TimeSpan(hours, 0, 0).AddHoursAndWrap12Hour(addHours).Hours);
}
[TestCase(0, 0, 0)]
[TestCase(30, 1, 31)]
[TestCase(59, 1, 0)]
[TestCase(30, -60, 30)]
public void AddMinutesAndWrap(int minutes, int addMinutes, int expectedMinutes)
{
Assert.AreEqual(expectedMinutes, new TimeSpan(0, minutes, 0).AddMinutesAndWrap(addMinutes).Minutes);
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
@@ -86,6 +87,13 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(expected, value.IsIntegerNumeric());
}
[Test]
public void GetAssemblyTest()
{
Assembly assembly = typeof(TypeExtensionsTest).GetAssembly();
Assert.IsTrue(assembly.FullName.Contains("ICD.Common.Utils"));
}
[TestCase(typeof(string), typeof(object), true)]
[TestCase(typeof(object), typeof(string), false)]
public void IsAssignableToTest(Type a, Type b, bool expected)
@@ -134,6 +142,51 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(typeof(IEnumerable), interfaces[0]);
}
[Test]
public void GetMinimalInterfacesTest()
{
Type[] interfaces = typeof(ICollection<int>).GetMinimalInterfaces().ToArray();
Assert.AreEqual(1, interfaces.Length);
Assert.AreEqual(typeof(IEnumerable<int>), interfaces[0]);
interfaces = typeof(IEnumerable<int>).GetMinimalInterfaces().ToArray();
Assert.AreEqual(1, interfaces.Length);
Assert.AreEqual(typeof(IEnumerable), interfaces[0]);
}
[TestCase(typeof(int), "Int32")]
[TestCase(typeof(List<int>), "List")]
public void GetNameWithoutGenericArityTest(Type type, string expected)
{
Assert.AreEqual(expected, type.GetNameWithoutGenericArity());
}
[TestCase(typeof(int), "System.Int32")]
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32]]")]
[TestCase(typeof(KeyValuePair<int, string>), "System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]")]
[TestCase(typeof(List<>), "System.Collections.Generic.List`1")]
public void GetMinimalNameTest(Type type, string expected)
{
Assert.AreEqual(expected, type.GetMinimalName());
}
[TestCase(typeof(int), "System.Int32, System.Private.CoreLib")]
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")]
public void GetNameWithoutAssemblyDetailsTest(Type type, string expected)
{
Assert.AreEqual(expected, type.GetNameWithoutAssemblyDetails());
}
[TestCase(typeof(string), "string")]
[TestCase(typeof(int?), "int?")]
[TestCase(typeof(List<int?>), "List<int?>")]
public void GetSyntaxNameTest(Type type, string expected)
{
Assert.AreEqual(expected, type.GetSyntaxName());
}
private interface C
{
}

View File

@@ -18,5 +18,13 @@ namespace ICD.Common.Utils.Tests.Extensions
{
Assert.AreEqual(expected, new Uri(uriString).GetPassword());
}
[TestCase("http://www.test.com/a/b/c", "http://www.test.com/a/b/")]
[TestCase("http://www.test.com/a/b/", "http://www.test.com/a/")]
[TestCase("http://www.test.com/", "http://www.test.com/")]
public void GetParentUri(string uriString, string expected)
{
Assert.AreEqual(expected, new Uri(uriString).GetParentUri().ToString());
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
@@ -49,10 +50,10 @@ namespace ICD.Common.Utils.Tests.Extensions
reader.ReadToNextElement();
IcdXmlAttribute[] attributes = reader.GetAttributes().ToArray();
KeyValuePair<string, string>[] attributes = reader.GetAttributes().ToArray();
Assert.AreEqual(2, attributes.Length);
Assert.AreEqual("attr1", attributes[0].Name);
Assert.AreEqual("attr2", attributes[1].Name);
Assert.AreEqual("attr1", attributes[0].Key);
Assert.AreEqual("attr2", attributes[1].Key);
}
[Test]

View File

@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
<RootNamespace>ICD.Common.Utils.Tests</RootNamespace>
<AssemblyName>ICD.Common.Utils.Tests</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -10,18 +11,25 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;STANDARD</DefineConstants>
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<OutputPath>binNetCoreApp\$(Configuration)\</OutputPath>
<DefineConstants>TRACE;STANDARD</DefineConstants>
<OutputPath>bin\$(Configuration)\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
<Compile Remove="bin\**" />
<EmbeddedResource Remove="bin\**" />
<None Remove="bin\**" />
</ItemGroup>
<ItemGroup>
<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" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
class IcdAutoResetEventTest
{
[TestCase(true)]
[TestCase(false)]
public void InitialStateTest(bool initialState)
{
using (var waitHandleEvent = new IcdAutoResetEvent(initialState))
{
Assert.AreEqual(initialState, waitHandleEvent.WaitOne(1), "Initial state incorrect");
}
}
[Test]
public void DefaultInitialStateTest()
{
using (var waitHandleEvent = new IcdAutoResetEvent())
{
Assert.False(waitHandleEvent.WaitOne(1), "Initial state incorrect");
}
}
[TestCase(1)]
[TestCase(5)]
[TestCase(15)]
public void MultipleThreadSetTest(int count)
{
int releasedCount = 0;
SafeCriticalSection countSection = new SafeCriticalSection();
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
for (int i = 0; i < count; i++)
ThreadingUtils.SafeInvoke(() =>
{
waitHandleEvent.WaitOne();
countSection.Execute(() => releasedCount++);
;
});
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released early");
///Auto reset should only release one thread at a time
for (int i = 1; i <= count; i++)
{
waitHandleEvent.Set();
ThreadingUtils.Sleep(100);
Assert.AreEqual(i, countSection.Execute(() => releasedCount),
"Incorrect number of threads released");
}
waitHandleEvent.Dispose();
}
[TestCase(1)]
[TestCase(5)]
[TestCase(15)]
public void MultipleThreadResetTest(int count)
{
int releasedCount = 0;
SafeCriticalSection countSection = new SafeCriticalSection();
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(true);
Assert.True(waitHandleEvent.WaitOne(1), "Initial State Wrong");
waitHandleEvent.Reset();
for (int i = 0; i < count; i++)
ThreadingUtils.SafeInvoke(() =>
{
if (waitHandleEvent.WaitOne(100))
countSection.Execute(() => releasedCount++);
});
ThreadingUtils.Sleep(2000);
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Incorrect number of threads released");
waitHandleEvent.Set();
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released after timeout");
waitHandleEvent.Dispose();
}
[TestCase(1)]
[TestCase(200)]
[TestCase(5000)]
public void WaitOneTest(int waitTime)
{
bool released = false;
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
ThreadingUtils.SafeInvoke(() =>
{
waitHandleEvent.WaitOne();
released = true;
});
ThreadingUtils.Sleep(waitTime);
Assert.False(released, "Thread released when it shouldn't have");
waitHandleEvent.Set();
ThreadingUtils.Sleep(100);
Assert.True(released, "Thread didn't release after set event");
waitHandleEvent.Dispose();
}
[TestCase(200)]
[TestCase(500)]
[TestCase(5000)]
public void WaitOneTimeoutTest(int waitTime)
{
bool released = false;
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
ThreadingUtils.SafeInvoke(() =>
{
waitHandleEvent.WaitOne(waitTime * 2);
released = true;
});
ThreadingUtils.Sleep(waitTime);
Assert.False(released, "Thread released when it shouldn't have");
waitHandleEvent.Set();
ThreadingUtils.Sleep(100);
Assert.True(released, "Thread didn't release after set event");
waitHandleEvent.Dispose();
}
[TestCase(200)]
[TestCase(500)]
[TestCase(5000)]
public void WaitOneTimedOutTest(int waitTime)
{
bool released = false;
bool? returned = null;
IcdAutoResetEvent waitHandleEvent = new IcdAutoResetEvent(false);
ThreadingUtils.SafeInvoke(() =>
{
returned = waitHandleEvent.WaitOne(waitTime);
released = true;
});
ThreadingUtils.Sleep(100);
Assert.True(returned == null, "WaitOne returned when it shouldn't have");
Assert.False(released, "Thread released when it shouldn't have");
ThreadingUtils.Sleep(waitTime * 2);
Assert.True(released, "Thread didn't release after timeout");
Assert.True(returned.HasValue && returned.Value == false, "WaitOne timeout didn't return false");
waitHandleEvent.Set();
waitHandleEvent.Dispose();
}
}
}

View File

@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
class IcdManualResetEventTest
{
[TestCase(true)]
[TestCase(false)]
public void InitialStateTest(bool initialState)
{
using (var waitHandleEvent = new IcdManualResetEvent(initialState))
{
Assert.AreEqual(initialState, waitHandleEvent.WaitOne(1), "Initial state incorrect");
}
}
[Test]
public void DefaultInitialStateTest()
{
using (var waitHandleEvent = new IcdManualResetEvent())
{
Assert.False(waitHandleEvent.WaitOne(1), "Initial state incorrect");
}
}
[TestCase(1)]
[TestCase(5)]
[TestCase(15)]
public void MultipleThreadSetTest(int count)
{
int releasedCount = 0;
SafeCriticalSection countSection = new SafeCriticalSection();
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
for (int i = 0; i < count; i++)
ThreadingUtils.SafeInvoke(() =>
{
waitHandleEvent.WaitOne();
countSection.Execute(() => releasedCount++);
;
});
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released early");
waitHandleEvent.Set();
ThreadingUtils.Sleep(500);
Assert.AreEqual(count, countSection.Execute(() => releasedCount), "Incorrect number of threads released");
waitHandleEvent.Dispose();
}
[TestCase(1)]
[TestCase(5)]
[TestCase(15)]
public void MultipleThreadResetTest(int count)
{
int releasedCount = 0;
SafeCriticalSection countSection = new SafeCriticalSection();
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(true);
Assert.True(waitHandleEvent.WaitOne(1), "Initial State Wrong");
waitHandleEvent.Reset();
for (int i = 0; i < count; i++)
ThreadingUtils.SafeInvoke(() =>
{
if (waitHandleEvent.WaitOne(100))
countSection.Execute(() => releasedCount++);
});
ThreadingUtils.Sleep(2000);
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Incorrect number of threads released");
waitHandleEvent.Set();
Assert.AreEqual(0, countSection.Execute(() => releasedCount), "Threads released after timeout");
waitHandleEvent.Dispose();
}
[TestCase(1)]
[TestCase(200)]
[TestCase(5000)]
public void WaitOneTest(int waitTime)
{
bool released = false;
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
ThreadingUtils.SafeInvoke(() =>
{
waitHandleEvent.WaitOne();
released = true;
});
ThreadingUtils.Sleep(waitTime);
Assert.False(released, "Thread released when it shouldn't have");
waitHandleEvent.Set();
ThreadingUtils.Sleep(100);
Assert.True(released, "Thread didn't release after set event");
waitHandleEvent.Dispose();
}
[TestCase(200)]
[TestCase(500)]
[TestCase(5000)]
public void WaitOneTimeoutTest(int waitTime)
{
bool released = false;
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
ThreadingUtils.SafeInvoke(() =>
{
waitHandleEvent.WaitOne(waitTime * 2);
released = true;
});
ThreadingUtils.Sleep(waitTime);
Assert.False(released, "Thread released when it shouldn't have");
waitHandleEvent.Set();
ThreadingUtils.Sleep(100);
Assert.True(released, "Thread didn't release after set event");
waitHandleEvent.Dispose();
}
[TestCase(200)]
[TestCase(500)]
[TestCase(5000)]
public void WaitOneTimedOutTest(int waitTime)
{
bool released = false;
bool? returned = null;
IcdManualResetEvent waitHandleEvent = new IcdManualResetEvent(false);
ThreadingUtils.SafeInvoke(() =>
{
returned = waitHandleEvent.WaitOne(waitTime);
released = true;
});
ThreadingUtils.Sleep(100);
Assert.True(returned == null, "WaitOne returned when it shouldn't have");
Assert.False(released, "Thread released when it shouldn't have");
ThreadingUtils.Sleep(waitTime * 2);
Assert.True(released, "Thread didn't release after timeout");
Assert.True(returned.HasValue && returned.Value == false, "WaitOne timeout didn't return false");
waitHandleEvent.Set();
waitHandleEvent.Dispose();
}
}
}

View File

@@ -37,10 +37,11 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(port, new IcdUriBuilder {Port = port}.Port);
}
[TestCase("test")]
public void QueryTest(string query)
[TestCase("?test", "test")]
[TestCase("??test", "?test")]
public void QueryTest(string expected, string query)
{
Assert.AreEqual(query, new IcdUriBuilder {Query = query}.Query);
Assert.AreEqual(expected, new IcdUriBuilder {Query = query}.Query);
}
[TestCase("test")]
@@ -63,14 +64,17 @@ namespace ICD.Common.Utils.Tests
#endregion
[TestCase("http://localhost/", null, null, null, null, (ushort)0, null, null, null)]
[TestCase("http://localhost:80/", null, null, null, null, (ushort)80, null, null, null)]
[TestCase("http://username@localhost/", null, null, null, null, (ushort)0, null, null, "username")]
[TestCase("http://localhost/", null, null, "password", null, (ushort)0, null, null, null)]
[TestCase("https://localhost/", null, null, null, null, (ushort)0, null, "https", null)]
[TestCase("http://localhost/test", null, null, null, "test", (ushort)0, null, null, null)]
[TestCase("http://localhost/test", null, null, null, "/test", (ushort)0, null, null, null)]
[TestCase("http://localhost//test", null, null, null, "//test", (ushort)0, null, null, null)]
[TestCase("/", null, null, null, null, (ushort)0, null, null, null)]
[TestCase("http:///", null, null, null, null, (ushort)0, null, "http", null)]
[TestCase("http://localhost:80/", null, "localhost", null, null, (ushort)80, null, "http", null)]
[TestCase("http://username@localhost/", null, "localhost", null, null, (ushort)0, null, "http", "username")]
[TestCase("http://localhost/", null, "localhost", "password", null, (ushort)0, null, "http", null)]
[TestCase("https://localhost/", null, "localhost", null, null, (ushort)0, null, "https", null)]
[TestCase("http://localhost/test", null, "localhost", null, "test", (ushort)0, null, "http", null)]
[TestCase("http://localhost/test", null, "localhost", null, "/test", (ushort)0, null, "http", null)]
[TestCase("http://localhost//test", null, "localhost", null, "//test", (ushort)0, null, "http", null)]
[TestCase("http://localhost/test?a=b", null, "localhost", null, "/test", (ushort)0, "a=b", "http", null)]
[TestCase("http://localhost/test??a=b", null, "localhost", null, "/test", (ushort)0, "?a=b", "http", null)]
public void ToStringTest(string expected, string fragment, string address, string password, string path, ushort port,
string query, string scheme, string userName)
{

View File

@@ -0,0 +1,46 @@
#if NETFRAMEWORK
extern alias RealNewtonsoft;
using RealNewtonsoft.Newtonsoft.Json;
#else
using Newtonsoft.Json;
#endif
using System;
using ICD.Common.Utils.Json;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Json
{
[TestFixture]
public sealed class DateTimeIsoConverterTest : AbstractGenericJsonConverterTest
{
[Test]
public override void WriteJsonTest()
{
JsonSerializerSettings settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
};
settings.Converters.Add(new DateTimeIsoConverter());
DateTime dateTime = new DateTime(2020, 1, 2, 3, 4, 5, DateTimeKind.Utc);
string serial = JsonConvert.SerializeObject(dateTime, settings);
Assert.AreEqual("\"2020-01-02T03:04:05Z\"", serial);
}
[Test]
public override void ReadJsonTest()
{
JsonSerializerSettings settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
};
settings.Converters.Add(new DateTimeIsoConverter());
string serial = "\"2020-01-02T03:04:05Z\"";
DateTime dateTime = JsonConvert.DeserializeObject<DateTime>(serial, settings);
Assert.AreEqual(new DateTime(2020, 1, 2, 3, 4, 5, DateTimeKind.Utc), dateTime);
}
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using ICD.Common.Utils.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Json
@@ -14,7 +14,7 @@ namespace ICD.Common.Utils.Tests.Json
[TestCase(1, typeof(int))]
public void ItemTypeTest(object item, Type expected)
{
Assert.AreEqual(expected, new JsonItemWrapper(item).ItemType);
Assert.AreEqual(expected, new JsonItemWrapper(item).Type);
}
[TestCase("")]
@@ -27,19 +27,21 @@ namespace ICD.Common.Utils.Tests.Json
[Test]
public void WriteTest()
{
JsonItemWrapper wrapper = new JsonItemWrapper(new List<int> {1, 2, 3});
string json = JsonUtils.Serialize(wrapper.Write);
const string expected = @"{""t"":""System.Collections.Generic.List`1[[System.Int32]]"",""i"":[1,2,3]}";
Assert.Inconclusive();
JsonItemWrapper wrapper = new JsonItemWrapper(new List<int> {1, 2, 3});
string json = JsonConvert.SerializeObject(wrapper);
Assert.AreEqual(expected, json);
}
[Test]
public void ReadTest()
{
const string json = "{\"t\":\"System.Collections.Generic.List`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]\",\"i\":\"[1,2,3]\"}";
const string json = @"{""t"":""System.Collections.Generic.List`1[[System.Int32]]"",""i"":[1,2,3]}";
JObject jObject = JObject.Parse(json);
List<int> wrappedObject = JsonItemWrapper.ReadToObject(jObject) as List<int>;
JsonItemWrapper wrapper = JsonConvert.DeserializeObject<JsonItemWrapper>(json);
List<int> wrappedObject = wrapper.Item as List<int>;
Assert.NotNull(wrappedObject);
Assert.AreEqual(3, wrappedObject.Count);

View File

@@ -1,8 +1,12 @@
using ICD.Common.Utils.Extensions;
#if NETFRAMEWORK
extern alias RealNewtonsoft;
using RealNewtonsoft.Newtonsoft.Json;
#else
using Newtonsoft.Json;
#endif
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
using ICD.Common.Utils.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Json
@@ -11,25 +15,7 @@ namespace ICD.Common.Utils.Tests.Json
public sealed class JsonUtilsTest
{
[Test]
public void CacheTypeTest()
{
Assert.Inconclusive();
}
[Test]
public void ParseDateTimeTest()
{
Assert.Inconclusive();
}
[Test]
public void TryParseDateTimeTest()
{
Assert.Inconclusive();
}
[Test]
public void PrintTest()
public void FormatTest()
{
Assert.Inconclusive();
}
@@ -141,32 +127,6 @@ namespace ICD.Common.Utils.Tests.Json
Assert.AreEqual("test message", messageName);
}
[Test]
public void DeserializeTypeTest()
{
const string json = "{\"test\":10}";
JObject root = JObject.Parse(json);
JToken token = root["test"];
int value = (int)JsonUtils.Deserialize(typeof(int), token);
Assert.AreEqual(10, value);
}
[Test]
public void DeserializeTestSerializerTest()
{
const string json = "{\"test\":10}";
JObject root = JObject.Parse(json);
JToken token = root["test"];
int value = (int)JsonUtils.Deserialize(typeof(int), token, new JsonSerializer());
Assert.AreEqual(10, value);
}
public sealed class TestSerializable
{
private const string PROPERTY_NAME = "Test";

View File

@@ -1,14 +1,13 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Tests
{
[TestFixture, UsedImplicitly]
[TestFixture]
public sealed class MathUtilsTest
{
[Test, UsedImplicitly]
[Test]
public void ClampTest()
{
Assert.AreEqual(MathUtils.Clamp(-10, 0, 0), 0);
@@ -24,9 +23,13 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(MathUtils.Clamp(20, 10, 10), 10);
}
[Test, UsedImplicitly]
[Test]
public void MapRangeTest()
{
Assert.AreEqual(5, MathUtils.MapRange(-100, 100, 0, 10, 0));
Assert.AreEqual(7, MathUtils.MapRange(-100, 100, 0, 10, 50));
Assert.AreEqual(10, MathUtils.MapRange(-100, 100, 0, 10, 100));
Assert.AreEqual(0, MathUtils.MapRange(0, 100, 0, 10, 0));
Assert.AreEqual(5, MathUtils.MapRange(0, 100, 0, 10, 50));
Assert.AreEqual(10, MathUtils.MapRange(0, 100, 0, 10, 100));
@@ -36,18 +39,10 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(100, MathUtils.MapRange(0, 10, 0, 100, 10));
}
[UsedImplicitly]
[TestCase(-10000, 5)]
[TestCase(10000, 5)]
public void GetNumberOfDigitsTest(int number, int expected)
{
Assert.AreEqual(expected, MathUtils.GetNumberOfDigits(number));
}
[Test, UsedImplicitly]
[Test]
public void GetRangesTest()
{
IEnumerable<int> values = new int[] { 1, 3, 5, 6, 7, 8, 9, 10, 12 };
IEnumerable<int> values = new [] { 1, 3, 5, 6, 7, 8, 9, 10, 12 };
int[][] ranges = MathUtils.GetRanges(values).ToArray();
Assert.AreEqual(4, ranges.Length);
@@ -65,11 +60,21 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(12, ranges[3][1]);
}
[Test, UsedImplicitly]
[Test]
public void RoundToNearestTest()
{
IEnumerable<int> values = new int[] { 0, 15, 30, 45 };
IEnumerable<int> values = new [] { 0, 15, 30, 45 };
Assert.AreEqual(15, MathUtils.RoundToNearest(21, values));
}
[TestCase(10, 10, 0)]
[TestCase(-10, 10, 0)]
[TestCase(9, 3, 0)]
[TestCase(3, 2, 1)]
[TestCase(-3, 2, 1)]
public void ModulusTest(int value, int mod, int expected)
{
Assert.AreEqual(expected, MathUtils.Modulus(value, mod));
}
}
}

View File

@@ -127,6 +127,24 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(clique.Contains(6));
}
[Test]
public void GetCliqueSingleNodeTest()
{
int[] clique = RecursionUtils.GetClique(1, n => s_CliqueGraph[n]).ToArray();
Assert.AreEqual(4, clique.Length);
Assert.IsTrue(clique.Contains(1));
Assert.IsTrue(clique.Contains(2));
Assert.IsTrue(clique.Contains(3));
Assert.IsTrue(clique.Contains(4));
clique = RecursionUtils.GetClique(5, n => s_CliqueGraph[n]).ToArray();
Assert.AreEqual(2, clique.Length);
Assert.IsTrue(clique.Contains(5));
Assert.IsTrue(clique.Contains(6));
}
[Test]
public void BreadthFirstSearchTest()
{
@@ -178,11 +196,13 @@ namespace ICD.Common.Utils.Tests
[Test]
public void BreadthFirstSearchManyDestinationsTest()
{
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchManyDestinations(1, new[] { 1 }, null));
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchManyDestinations(1, null, Graph));
Assert.IsEmpty(RecursionUtils.BreadthFirstSearchManyDestinations(1, new[] { 5 }, Graph));
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchPathManyDestinations(1, new[] { 1 }, null));
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchPathManyDestinations(1, null, Graph));
Assert.AreEqual(0, RecursionUtils.BreadthFirstSearchPathManyDestinations(1, new[] { 5 }, Graph).Count());
Dictionary<int, IEnumerable<int>> paths = RecursionUtils.BreadthFirstSearchManyDestinations(1, new[] { 21, 22, 31, 43, 62 }, WideGraph);
Dictionary<int, IEnumerable<int>> paths =
RecursionUtils.BreadthFirstSearchPathManyDestinations(1, new[] {21, 22, 31, 43, 62}, WideGraph)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
//Make sure all paths were found
Assert.IsTrue(paths.Keys.Contains(21));
@@ -230,5 +250,40 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(6, paths[62].ToArray()[1]);
Assert.AreEqual(62, paths[62].ToArray()[2]);
}
[Test]
public void BreadthFirstSearchPathsTest()
{
Dictionary<int, IEnumerable<int>> paths =
RecursionUtils.BreadthFirstSearchPaths(1, Graph)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
// Verify we visited all destinations
Assert.AreEqual(4, paths.Count);
Assert.IsTrue(paths.ContainsKey(1));
Assert.IsTrue(paths.ContainsKey(2));
Assert.IsTrue(paths.ContainsKey(3));
Assert.IsTrue(paths.ContainsKey(4));
// Verify path for destination 1
Assert.AreEqual(1, paths[1].ToArray().Length);
Assert.AreEqual(1, paths[1].ToArray()[0]);
// Verify path for destination 2
Assert.AreEqual(2, paths[2].ToArray().Length);
Assert.AreEqual(1, paths[2].ToArray()[0]);
Assert.AreEqual(2, paths[2].ToArray()[1]);
// Verify path for destination 3
Assert.AreEqual(2, paths[3].ToArray().Length);
Assert.AreEqual(1, paths[3].ToArray()[0]);
Assert.AreEqual(3, paths[3].ToArray()[1]);
// Verify path for destination 4
Assert.AreEqual(3, paths[4].ToArray().Length);
Assert.AreEqual(1, paths[4].ToArray()[0]);
Assert.AreEqual(2, paths[4].ToArray()[1]);
Assert.AreEqual(4, paths[4].ToArray()[2]);
}
}
}

View File

@@ -2,6 +2,8 @@
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.EventArguments;
using ICD.Common.Utils.Extensions;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -149,5 +151,75 @@ namespace ICD.Common.Utils.Tests
// Everything else
Assert.AreEqual(10, ReflectionUtils.ChangeType("10", typeof(int)));
}
#region Subscription Tests
[Test]
public void SubscribeEventTest()
{
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
Delegate del = ReflectionUtils.SubscribeEvent<IntEventArgs>(this, eventInfo, IncrementCount);
Assert.NotNull(del);
m_Count = 0;
OnIncrementCount.Raise(this, new IntEventArgs(10));
Assert.AreEqual(10, m_Count);
OnIncrementCount = null;
}
[Test]
public void SubscribeEventMethodInfoTest()
{
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
MethodInfo methodInfo =
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
Assert.NotNull(del);
m_Count = 0;
OnIncrementCount.Raise(this, new IntEventArgs(10));
Assert.AreEqual(10, m_Count);
OnIncrementCount = null;
}
[Test]
public void UnsubscribeEventTest()
{
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
MethodInfo methodInfo =
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
Assert.NotNull(del);
m_Count = 0;
ReflectionUtils.UnsubscribeEvent(this, eventInfo, del);
OnIncrementCount.Raise(this, new IntEventArgs(10));
Assert.AreEqual(0, m_Count);
}
// Event has to be public
public event EventHandler<IntEventArgs> OnIncrementCount;
private int m_Count;
private void IncrementCount(object sender, IntEventArgs args)
{
m_Count += args.Data;
}
#endregion
}
}

View File

@@ -0,0 +1,38 @@
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class RegexUtilsTest
{
[Test]
public static void MatchesTest()
{
Assert.Inconclusive();
}
[Test]
public static void MatchesOptionsTest()
{
Assert.Inconclusive();
}
[TestCase(@"[assembly: AssemblyFileVersion(""1.2.3"")][assembly: AssemblyFileVersion(""1.2.3"")]",
@"[assembly: AssemblyFileVersion(""2.0.3.0"")][assembly: AssemblyFileVersion(""2.0.3.0"")]",
@"AssemblyFileVersion\(""(?<version>(\d+\.?){4})""\)",
"version",
"1.2.3")]
public static void ReplaceGroupTest(string expected, string input, string pattern, string groupName,
string replacement)
{
string result = RegexUtils.ReplaceGroup(input, pattern, groupName, replacement);
Assert.AreEqual(expected, result);
}
[Test]
public static void ReplaceGroupFuncTest()
{
Assert.Inconclusive();
}
}
}

View File

@@ -37,30 +37,5 @@ namespace ICD.Common.Utils.Tests
Assert.Inconclusive();
}
[Test]
public void TryEnterTest()
{
int result = 0;
SafeCriticalSection section = new SafeCriticalSection();
section.Enter();
// ReSharper disable once NotAccessedVariable
object handle = ThreadingUtils.SafeInvoke(() => { result = section.TryEnter() ? 0 : 1; });
Assert.IsTrue(ThreadingUtils.Wait(() => result == 1, 1000));
section.Leave();
// ReSharper disable once RedundantAssignment
handle = ThreadingUtils.SafeInvoke(() =>
{
result = section.TryEnter() ? 2 : 0;
section.Leave();
});
Assert.IsTrue(ThreadingUtils.Wait(() => result == 2, 1000));
}
}
}
}

View File

@@ -12,7 +12,7 @@ namespace ICD.Common.Utils.Tests.Services.Logging
public void TimestampTest()
{
LogItem item = new LogItem(eSeverity.Critical, null);
DateTime time = IcdEnvironment.GetLocalTime();
DateTime time = IcdEnvironment.GetUtcTime();
Assert.IsTrue((time - item.Timestamp).TotalSeconds <= 1);
}

View File

@@ -1,4 +1,5 @@
using ICD.Common.Properties;
using System.Linq;
using ICD.Common.Properties;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
@@ -24,11 +25,33 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual("\x08\x22\x00\x00\x00\x02", output);
}
[Test, UsedImplicitly]
public void NiceNameTest()
[TestCase("FF", new byte[] {0xFF})]
[TestCase("01FF", new byte[] { 0x01, 0xFF })]
public void HexToBytes(string value, byte[] expected)
{
string output = StringUtils.NiceName("TodayILiveInTheUSAWithSimon");
Assert.AreEqual("Today I Live In The USA With Simon", output);
byte[] bytes = StringUtils.HexToBytes(value);
Assert.IsTrue(bytes.SequenceEqual(expected));
}
[TestCase("1", 1)]
[TestCase("FF", 0xFF)]
public void HexToByte(string value, byte expected)
{
Assert.AreEqual(expected, StringUtils.HexToByte(value));
}
[TestCase("Test", "Test")]
[TestCase("test", "Test")]
[TestCase("TodayILiveInTheUSAWithSimon", "Today I Live In The USA With Simon")]
[TestCase("CONST_VALUE", "CONST VALUE")]
[TestCase("m_PrivateMember", "Private Member")]
[TestCase("variableName", "Variable Name")]
[TestCase("Comma, Delimited", "Comma, Delimited")]
[TestCase("Comma,Delimited", "Comma, Delimited")]
public void NiceNameTest(string input, string expected)
{
string output = StringUtils.NiceName(input);
Assert.AreEqual(expected, output);
}
[Test, UsedImplicitly]
@@ -61,10 +84,10 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual("[-3 - 5]", StringUtils.RangeFormat(-3, 5));
}
[Test, UsedImplicitly]
public void UppercaseFirstTest()
[TestCase("foobar", "Foobar")]
public void UppercaseFirstTest(string value, string expected)
{
Assert.AreEqual("Foobar", StringUtils.UppercaseFirst("foobar"));
Assert.AreEqual(expected, StringUtils.UppercaseFirst(value));
}
[TestCase("test", "Test")]
@@ -74,16 +97,24 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(expected, StringUtils.ToTitleCase(input));
}
[Test, UsedImplicitly]
public void ToIpIdStringTest()
[TestCase((byte)0x67, "0x67")]
public void ToIpIdStringTest(byte ipid, string expected)
{
Assert.AreEqual("0x67", StringUtils.ToIpIdString(0x67));
Assert.AreEqual(expected, StringUtils.ToIpIdString(ipid));
}
[Test, UsedImplicitly]
public void FromIpIdStringTest()
[TestCase("0x67", (byte)0x67)]
public void FromIpIdStringTest(string value, byte expected)
{
Assert.AreEqual(0x67, StringUtils.FromIpIdString("0x67"));
Assert.AreEqual(expected, StringUtils.FromIpIdString(value));
}
[TestCase("0x67", true, (byte)0x67)]
public void TryFromIpIdStringTest(string value, bool expected, byte expectedOutput)
{
byte output;
Assert.AreEqual(expected, StringUtils.TryFromIpIdString(value, out output));
Assert.AreEqual(expectedOutput, output);
}
[UsedImplicitly]
@@ -170,5 +201,20 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(StringUtils.TryParse("true", out testVal));
Assert.AreEqual(true, testVal);
}
[TestCase("test", "\"test\"")]
[TestCase("\"test\"", "\"test\"")]
[TestCase("test test", "\"test test\"")]
public void EnquoteTest(string input, string expected)
{
Assert.AreEqual(expected, StringUtils.Enquote(input));
}
[TestCase("\"test\"", "test")]
[TestCase("\"test test\"", "test test")]
public void UnEnquoteTest(string input, string expected)
{
Assert.AreEqual(expected, StringUtils.UnEnquote(input));
}
}
}

View File

@@ -0,0 +1,205 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class ThreadedWorkerQueueTest
{
[Test]
public void BetweenTimeTest()
{
List<int> callbacks = new List<int>();
using (ThreadedWorkerQueue<int> queue = new ThreadedWorkerQueue<int>((d) => callbacks.Add(d), true, 1000))
{
queue.Enqueue(10);
queue.Enqueue(20);
queue.Enqueue(30);
ThreadingUtils.Sleep(100);
Assert.AreEqual(1, callbacks.Count, "Initial enqueue did not trigger a dequeue");
ThreadingUtils.Sleep(1000);
Assert.AreEqual(2, callbacks.Count, "Second enqueue did not dequeue");
ThreadingUtils.Sleep(100);
Assert.AreEqual(2, callbacks.Count, "Third enqueue did not wait for process to complete");
ThreadingUtils.Sleep(1000);
Assert.AreEqual(3, callbacks.Count);
}
}
#region Properties
[TestCase(1000)]
[TestCase(0)]
[TestCase(long.MaxValue)]
public void BetweenMillisecondsTest(long milliseconds)
{
using (var queue = new ThreadedWorkerQueue<int>((d) => { }, true, milliseconds))
Assert.AreEqual(milliseconds, queue.BetweenTime);
}
[TestCase(5)]
[TestCase(0)]
[TestCase(30)]
public void CountTest(int count)
{
using (var queue = new ThreadedWorkerQueue<int>(d => { }, false))
{
for (int i = 0; i < count; i++)
queue.Enqueue(1);
Assert.AreEqual(count, queue.Count);
}
}
[Test]
public void ProcessBetweenTimeTest()
{
var processed = new List<int>();
using (var queue = new ThreadedWorkerQueue<int>(d => processed.Add(d), false, 1000))
{
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
ThreadingUtils.Sleep(100);
Assert.AreEqual(0, processed.Count, "Queue processed item early");
queue.SetRunProcess(true);
ThreadingUtils.Sleep(100);
Assert.AreEqual(1, processed.Count, "First item not processed");
ThreadingUtils.Sleep(1000);
Assert.AreEqual(2, processed.Count, "Second item not processed");
queue.SetRunProcess(false);
ThreadingUtils.Sleep(2000);
Assert.AreEqual(2, processed.Count, "Item processed after stopping run process");
Assert.AreEqual(1, queue.Count, "Incorrect number of items in queue");
// Queue lower priority item
queue.Enqueue(5, 1);
queue.SetRunProcess(true);
ThreadingUtils.Sleep(100);
Assert.AreEqual(3, processed.Count, "Third item not processed");
Assert.AreEqual(5, processed[2], "Dequeued incorrect priority item");
ThreadingUtils.Sleep(1000);
Assert.AreEqual(4, processed.Count, "Didn't process all items");
Assert.True(processed.SequenceEqual(new[] { 1, 2, 5, 3 }), "Processed sequence incorrect");
}
}
[Test]
public void FlushQueueBetweenTimeTest()
{
var processed = new List<int>();
using (var queue = new ThreadedWorkerQueue<int>(d => processed.Add(d), false, 1000))
{
Assert.True(queue.WaitForFlush(1), "WaitForFlush on empty queue failed");
queue.Enqueue(11);
queue.Enqueue(21);
queue.Enqueue(31);
queue.Enqueue(41);
queue.Enqueue(51);
queue.Enqueue(61);
queue.Enqueue(71);
queue.Enqueue(81);
queue.Enqueue(91);
queue.Enqueue(101);
queue.SetRunProcess(true);
Assert.False(queue.WaitForFlush(1250), "WaitForFlush didn't time out");
Assert.AreEqual(2, processed.Count, "Didn't process correct number of items in time frame");
Assert.True(queue.WaitForFlush(), "WaitForFlush failed");
Assert.AreEqual(10, processed.Count, "Not all items processed");
Assert.AreEqual(0, queue.Count, "Queue not empty");
}
}
#endregion
#region Methods
[TestCase(false)]
[TestCase(true)]
public void SetRunProcessTest(bool runProcess)
{
using (var queue = new ThreadedWorkerQueue<int>(d => { }, !runProcess))
{
Assert.AreEqual(!runProcess, queue.RunProcess, "Initial state wrong");
queue.SetRunProcess(runProcess);
Assert.AreEqual(runProcess, queue.RunProcess, "Didn't set to correct state 1st time");
queue.SetRunProcess(!runProcess);
Assert.AreEqual(!runProcess, queue.RunProcess, "Didn't set to correct state 2nd time");
}
}
[Test]
public void EnqueueTest()
{
var processed = new List<int>();
using (var queue = new ThreadedWorkerQueue<int>(d => processed.Add(d), false))
{
queue.Enqueue(10);
queue.Enqueue(20);
queue.Enqueue(30);
Assert.AreEqual(3, queue.Count, "First queue count wrong");
queue.Enqueue(40);
queue.Enqueue(50);
queue.Enqueue(60);
Assert.AreEqual(6, queue.Count, "Second queue count wrong");
queue.SetRunProcess(true);
Assert.True(queue.WaitForFlush(),"Queue didn't flush after processing");
Assert.True(processed.SequenceEqual(new[] { 10, 20, 30, 40, 50, 60 }), "Processed sequence wrong");
}
}
[Test]
public void ClearTest()
{
using (var queue = new ThreadedWorkerQueue<int>(d => { }, false))
{
queue.Enqueue(1);
queue.Enqueue(1);
queue.Enqueue(1);
queue.Clear();
Assert.AreEqual(0, queue.Count);
}
}
#endregion
}
}

View File

@@ -13,7 +13,7 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(ThreadingUtils.Wait(() => true, 100));
bool complete = false;
DateTime time = IcdEnvironment.GetLocalTime();
DateTime time = IcdEnvironment.GetUtcTime();
ThreadingUtils.SafeInvoke(() =>
{
@@ -22,15 +22,15 @@ namespace ICD.Common.Utils.Tests
});
Assert.IsTrue(ThreadingUtils.Wait(() => complete, 200));
Assert.AreEqual(100, (IcdEnvironment.GetLocalTime() - time).TotalMilliseconds, 20);
Assert.AreEqual(100, (IcdEnvironment.GetUtcTime() - time).TotalMilliseconds, 20);
}
[Test]
public void Sleep()
{
DateTime now = IcdEnvironment.GetLocalTime();
DateTime now = IcdEnvironment.GetUtcTime();
ThreadingUtils.Sleep(1000);
DateTime now2 = IcdEnvironment.GetLocalTime();
DateTime now2 = IcdEnvironment.GetUtcTime();
Assert.AreEqual(1000, (now2 - now).TotalMilliseconds, 100);
}

View File

@@ -0,0 +1,17 @@
using ICD.Common.Utils.Timers;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Timers
{
[TestFixture]
public sealed class IcdStopwatchTest
{
[Test]
public void ConstructorTest()
{
var stopwatch = new IcdStopwatch();
ThreadingUtils.Sleep(100);
Assert.AreEqual(0, stopwatch.ElapsedMilliseconds);
}
}
}

View File

@@ -49,12 +49,14 @@ namespace ICD.Common.Utils.Tests.Timers
[Test]
public void TriggerTest()
{
bool called = false;
SafeTimer timer = SafeTimer.Stopped(() => called = true);
int called = 0;
SafeTimer timer = SafeTimer.Stopped(() => called++);
timer.Trigger();
Assert.IsTrue(called);
ThreadingUtils.Sleep(50);
Assert.AreEqual(1, called);
timer.Dispose();
}

View 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);
}
}
}

View File

@@ -0,0 +1,155 @@
using System.Xml;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Xml
{
[TestFixture]
public sealed class GenericXmlConverterTest
{
[XmlConverter(typeof(TestClassConverter))]
private sealed class TestClass
{
public string A { get; set; }
public int B { get; set; }
}
private sealed class TestClassConverter : AbstractGenericXmlConverter<TestClass>
{
private const string ELEMENT_A = "A";
private const string ATTRIBUTE_B = "b";
/// <summary>
/// Override to handle the current attribute.
/// </summary>
/// <param name="reader"></param>
/// <param name="instance"></param>
protected override void ReadAttribute(IcdXmlReader reader, TestClass instance)
{
switch (reader.Name)
{
case ATTRIBUTE_B:
instance.B = int.Parse(reader.Value);
break;
default:
base.ReadAttribute(reader, instance);
break;
}
}
/// <summary>
/// Override to handle the current element.
/// </summary>
/// <param name="reader"></param>
/// <param name="instance"></param>
protected override void ReadElement(IcdXmlReader reader, TestClass instance)
{
switch (reader.Name)
{
case ELEMENT_A:
instance.A = reader.ReadElementContentAsString();
break;
default:
base.ReadElement(reader, instance);
break;
}
}
/// <summary>
/// Override to write attributes to the root element.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
protected override void WriteAttributes(IcdXmlTextWriter writer, TestClass value)
{
base.WriteAttributes(writer, value);
writer.WriteAttributeString(ATTRIBUTE_B, value.B.ToString());
}
/// <summary>
/// Override to write elements to the writer.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
protected override void WriteElements(IcdXmlTextWriter writer, TestClass value)
{
base.WriteElements(writer, value);
writer.WriteElementString(ELEMENT_A, value.A);
}
}
[Test]
public void TestElement()
{
const string xml = @"<Instances>
<Instance b=""1"">
<A>Test</A>
</Instance>
</Instances>";
using (IcdXmlReader reader = new IcdXmlReader(xml))
{
// Read into the Instances node
reader.Read();
Assert.AreEqual(XmlNodeType.Element, reader.NodeType);
Assert.AreEqual("Instances", reader.Name);
// Read into the Instance node
reader.Read();
reader.SkipInsignificantWhitespace();
Assert.AreEqual(XmlNodeType.Element, reader.NodeType);
Assert.AreEqual("Instance", reader.Name);
// Deserialize
TestClass instance = IcdXmlConvert.DeserializeObject<TestClass>(reader);
Assert.IsNotNull(instance);
Assert.AreEqual("Test", instance.A);
Assert.AreEqual(1, instance.B);
// Deserialization should land on the following node
reader.SkipInsignificantWhitespace();
Assert.AreEqual(XmlNodeType.EndElement, reader.NodeType);
Assert.AreEqual("Instances", reader.Name);
}
}
[Test]
public void TestEmptyElement()
{
const string xml = @"<Instances>
<Instance b=""1"" />
</Instances>";
using (IcdXmlReader reader = new IcdXmlReader(xml))
{
// Read into the Instances node
reader.Read();
Assert.AreEqual(XmlNodeType.Element, reader.NodeType);
Assert.AreEqual("Instances", reader.Name);
// Read into the Instance node
reader.Read();
reader.SkipInsignificantWhitespace();
Assert.AreEqual(XmlNodeType.Element, reader.NodeType);
Assert.AreEqual("Instance", reader.Name);
// Deserialize
TestClass instance = IcdXmlConvert.DeserializeObject<TestClass>(reader);
Assert.IsNotNull(instance);
Assert.IsNull(instance.A);
Assert.AreEqual(1, instance.B);
// Deserialization should land on the following node
reader.SkipInsignificantWhitespace();
Assert.AreEqual(XmlNodeType.EndElement, reader.NodeType);
Assert.AreEqual("Instances", reader.Name);
}
}
}
}

View File

@@ -1,17 +0,0 @@
using ICD.Common.Properties;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Xml
{
[TestFixture]
public sealed class IcdXmlAttributeTest
{
[Test, UsedImplicitly]
public void ValueAsIntTest()
{
IcdXmlAttribute attribute = new IcdXmlAttribute("test", "12");
Assert.AreEqual("12", attribute.Value);
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Linq;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Xml
{
[TestFixture]
public sealed class IcdXmlConvertTest
{
[Test]
public void DeserializeArrayGenericTest()
{
const string xml = @"<A>
<B>1</B>
<B>2</B>
</A>";
using (IcdXmlReader reader = new IcdXmlReader(xml))
{
// Read to the first element
reader.Read();
int[] values = IcdXmlConvert.DeserializeArray<int>(reader).ToArray();
Assert.AreEqual(new[] {1, 2}, values);
}
}
[Test]
public void DeserializeArrayTest()
{
Assert.Inconclusive();
}
}
}

View File

@@ -56,12 +56,12 @@ namespace ICD.Common.Utils.Tests.Xml
{
reader.ReadToNextElement();
IcdXmlAttribute[] attributes = reader.GetAttributes().ToArray();
KeyValuePair<string, string>[] attributes = reader.GetAttributes().ToArray();
Assert.AreEqual(2, attributes.Length);
Assert.AreEqual("attr1", attributes[0].Name);
Assert.AreEqual("attr1", attributes[0].Key);
Assert.AreEqual("1", attributes[0].Value);
Assert.AreEqual("attr2", attributes[1].Name);
Assert.AreEqual("attr2", attributes[1].Key);
Assert.AreEqual("2", attributes[1].Value);
}
}
@@ -90,6 +90,7 @@ namespace ICD.Common.Utils.Tests.Xml
{
paths.Add(args.Path);
nodes.Add(args.Outer);
return true;
}
);
@@ -176,13 +177,6 @@ namespace ICD.Common.Utils.Tests.Xml
}
}
[Test, UsedImplicitly]
public void IsValidXmlTest()
{
Assert.IsFalse(XmlUtils.IsValidXml(@"<Foo></Bar>"));
Assert.IsTrue(XmlUtils.IsValidXml(EXAMPLE_XML));
}
[Test]
public void FormatTest()
{
@@ -253,6 +247,7 @@ namespace ICD.Common.Utils.Tests.Xml
[TestCase("<Test><Child>A</Child></Test>", "Child", true, eTestEnum.A)]
[TestCase("<Test><Child>A, B</Child></Test>", "Child", true, eTestEnum.A | eTestEnum.B)]
public void ReadChildElementContentAsEnumTest<T>(string xml, string childElement, bool ignoreCase, T expected)
where T : struct, IConvertible
{
Assert.AreEqual(expected, XmlUtils.ReadChildElementContentAsEnum<T>(xml, childElement, ignoreCase));
}

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace ICD.Common.Utils
{
public static class AnsiUtils
{
public const string COLOR_RED = "\x1b[31;1m";
public const string COLOR_GREEN = "\x1b[32;1m";
public const string COLOR_YELLOW = "\x1b[33;1m";
public const string COLOR_BLUE = "\x1b[34;1m";
public const string COLOR_MAGENTA = "\x1b[35;1m";
public const string COLOR_CYAN = "\x1b[36;1m";
public const string COLOR_WHITE = "\x1b[37;1m";
public const string COLOR_YELLOW_ON_RED_BACKGROUND = "\x1b[93;41m";
public const string ANSI_RESET = "\x1b[0m";
public const string CODE_BLACK = "30";
public const string CODE_RED = "31";
public const string CODE_GREEN = "32";
public const string CODE_YELLOW = "33";
public const string CODE_BLUE = "34";
public const string CODE_MAGENTA = "35";
public const string CODE_CYAN = "36";
public const string CODE_WHITE = "37";
public const string CODE_BRIGHT_BLACK = "30;1";
public const string CODE_BRIGHT_RED = "31;1";
public const string CODE_BRIGHT_GREEN = "32;1";
public const string CODE_BRIGHT_YELLOW = "33;1";
public const string CODE_BRIGHT_BLUE = "34;1";
public const string CODE_BRIGHT_MAGENTA = "35;1";
public const string CODE_BRIGHT_CYAN = "36;1";
public const string CODE_BRIGHT_WHITE = "37;1";
/// <summary>
/// Matches ANSI escape codes, e.g. \x1b[31m and \x1b[30;1m
/// </summary>
public const string ANSI_REGEX = "(?'match'\x01b\\[(?'code'[\\d;]+)m)";
/// <summary>
/// Matches ANSI escape codes to HTML styles.
/// Color values are taken from PuTTY.
/// </summary>
private static readonly Dictionary<string, string> s_PuttyColors =
new Dictionary<string, string>
{
{CODE_BLACK, "#000000"},
{CODE_RED, "#BB0000"},
{CODE_GREEN, "#00BB00"},
{CODE_YELLOW, "#BBBB00"},
{CODE_BLUE, "#0000BB"},
{CODE_MAGENTA, "#BB00BB"},
{CODE_CYAN, "#00BBBB"},
{CODE_WHITE, "#BBBBBB"},
{CODE_BRIGHT_BLACK, "#555555"},
{CODE_BRIGHT_RED, "#FF5555"},
{CODE_BRIGHT_GREEN, "#55FF55"},
{CODE_BRIGHT_YELLOW, "#FFFF55"},
{CODE_BRIGHT_BLUE, "#5555FF"},
{CODE_BRIGHT_MAGENTA, "#FF55FF"},
{CODE_BRIGHT_CYAN, "#55FFFF"},
{CODE_BRIGHT_WHITE, "#FFFFFF"}
};
/// <summary>
/// Gets the color map matching PuTTY.
/// </summary>
public static IDictionary<string, string> PuttyColors { get { return s_PuttyColors; } }
#if NETSTANDARD
/// <summary>
/// Enables ANSI color in the console.
/// </summary>
public static void EnableAnsiColor()
{
Pastel.ConsoleExtensions.Enable();
}
/// <summary>
/// Disables ANSI color in the console.
/// </summary>
public static void DisableAnsiColor()
{
Pastel.ConsoleExtensions.Disable();
}
#endif
/// <summary>
/// Removes ANSI control sequences from the string.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static string StripAnsi(string data)
{
return Regex.Replace(data, ANSI_REGEX, string.Empty);
}
/// <summary>
/// Prefixes the given data with an ANSI control sequence and suffixes with a reset sequence.
/// </summary>
/// <param name="data"></param>
/// <param name="ansiSequence"></param>
/// <returns></returns>
public static string Format(string data, string ansiSequence)
{
// % needs to be escaped or weird things happen
data = string.IsNullOrEmpty(data) ? data : data.Replace("%", "%%");
return string.Format("{0}{1}{2}", ansiSequence, data, ANSI_RESET);
}
/// <summary>
/// Splits the given ANSI string into spans.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static IEnumerable<AnsiSpan> ToSpans(string data)
{
if (string.IsNullOrEmpty(data))
yield break;
Regex regex = new Regex(ANSI_REGEX);
Match match = regex.Match(data);
// No matches
if (!match.Success)
yield return new AnsiSpan {Text = data};
// Find the spans
while (match.Success)
{
// Get the code
string code = match.Groups["code"].Value;
// Get the text
Match next = match.NextMatch();
int startIndex = match.Index + match.Length;
int endIndex = next.Success ? next.Index : data.Length;
string text = data.Substring(startIndex, endIndex - startIndex);
// Build the span
if (text.Length > 0)
yield return new AnsiSpan { Code = code, Text = text };
// Loop
match = next;
}
}
/// <summary>
/// Removes the bright suffix from the code if present, otherwise appends a bright suffix.
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public static string InvertBright(string code)
{
return code.EndsWith(";1")
? code.Substring(0, code.Length - 2)
: code + ";1";
}
}
public sealed class AnsiSpan
{
public string Code { get; set; }
public string Text { get; set; }
/// <summary>
/// Gets the color value for the code.
/// </summary>
/// <param name="colors"></param>
/// <param name="invertBright"></param>
/// <returns></returns>
public string GetColor(IDictionary<string, string> colors, bool invertBright)
{
if (colors == null)
throw new ArgumentNullException("colors");
return GetColor<string>(colors, invertBright);
}
/// <summary>
/// Gets the color value for the code.
/// </summary>
/// <param name="colors"></param>
/// <param name="invertBright"></param>
/// <returns></returns>
public T GetColor<T>(IDictionary<string, T> colors, bool invertBright)
{
if (colors == null)
throw new ArgumentNullException("colors");
string code = invertBright ? AnsiUtils.InvertBright(Code) : Code;
return colors[code];
}
}
}

View File

@@ -0,0 +1,40 @@
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.IO;
#if SIMPLSHARP
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronXmlLinq;
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
namespace ICD.Common.Utils
{
public static class AssemblyUtils
{
/// <summary>
/// Gets the process executable in the default application domain. In other application domains,
/// this is the first executable that was executed by ExecuteAssembly(String).
/// </summary>
/// <returns></returns>
[CanBeNull]
public static Assembly GetEntryAssembly()
{
#if SIMPLSHARP
string appDir = InitialParametersClass.ProgramDirectory.ToString();
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SIMPL)
return null;
string proginfo = IcdFile.ReadToEnd(IcdPath.Combine(appDir, "ProgramInfo.config"), Encoding.UTF8);
XDocument doc = XDocument.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n" + proginfo);
XElement entry = doc.Descendants("EntryPoint").FirstOrDefault();
return entry == null ? null : Assembly.Load(entry.Value);
#else
return Assembly.GetEntryAssembly();
#endif
}
}
}

View File

@@ -2,10 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.Services;
using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -20,175 +17,6 @@ namespace ICD.Common.Utils
/// </summary>
public static class AttributeUtils
{
// Avoid caching the same assembly multiple times.
private static readonly IcdHashSet<Assembly> s_CachedAssemblies;
private static readonly IcdHashSet<Type> s_CachedTypes;
private static readonly Dictionary<Attribute, MethodInfo> s_AttributeToMethodCache;
private static readonly Dictionary<Attribute, Type> s_AttributeToTypeCache;
private static readonly Dictionary<Type, IcdHashSet<Attribute>> s_TypeToAttributesCache;
private static ILoggerService Logger { get { return ServiceProvider.TryGetService<ILoggerService>(); } }
/// <summary>
/// Constructor.
/// </summary>
static AttributeUtils()
{
s_CachedAssemblies = new IcdHashSet<Assembly>();
s_CachedTypes = new IcdHashSet<Type>();
s_AttributeToMethodCache = new Dictionary<Attribute, MethodInfo>();
s_AttributeToTypeCache = new Dictionary<Attribute, Type>();
s_TypeToAttributesCache = new Dictionary<Type, IcdHashSet<Attribute>>();
}
#region Caching
/// <summary>
/// Pre-emptively caches the given assemblies for lookup.
/// </summary>
/// <param name="assemblies"></param>
public static void CacheAssemblies(IEnumerable<Assembly> assemblies)
{
if (assemblies == null)
throw new ArgumentNullException("assemblies");
foreach (Assembly assembly in assemblies)
CacheAssembly(assembly);
}
/// <summary>
/// Pre-emptively caches the given assembly for lookup.
/// </summary>
/// <param name="assembly"></param>
public static bool CacheAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
if (s_CachedAssemblies.Contains(assembly))
return true;
#if SIMPLSHARP
CType[] types;
#else
Type[] types;
#endif
try
{
types = assembly.GetTypes();
}
#if STANDARD
catch (ReflectionTypeLoadException e)
{
foreach (Exception inner in e.LoaderExceptions)
{
if (inner is System.IO.FileNotFoundException)
{
Logger.AddEntry(eSeverity.Error,
"{0} failed to cache assembly {1} - Could not find one or more dependencies by path",
typeof(AttributeUtils).Name, assembly.GetName().Name);
continue;
}
Logger.AddEntry(eSeverity.Error, inner, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name,
assembly.GetName().Name);
}
return false;
}
#endif
catch (TypeLoadException e)
{
#if SIMPLSHARP
Logger.AddEntry(eSeverity.Error, e, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name,
assembly.GetName().Name);
#else
Logger.AddEntry(eSeverity.Error, e, "{0} failed to cache assembly {1} - could not load type {2}",
typeof(AttributeUtils).Name, assembly.GetName().Name, e.TypeName);
#endif
return false;
}
foreach (var type in types)
CacheType(type);
s_CachedAssemblies.Add(assembly);
return true;
}
/// <summary>
/// Pre-emptively caches the given type for lookup.
/// </summary>
/// <param name="type"></param>
#if SIMPLSHARP
public static void CacheType(CType type)
#else
public static void CacheType(Type type)
#endif
{
if (type == null)
throw new ArgumentNullException("type");
if (s_CachedTypes.Contains(type))
return;
s_CachedTypes.Add(type);
MethodInfo[] methods;
try
{
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetCustomAttributes<Attribute>(false));
foreach (Attribute attribute in s_TypeToAttributesCache[type])
s_AttributeToTypeCache[attribute] = type;
methods = type.GetMethods();
}
// GetMethods for Open Generic Types is not supported.
catch (NotSupportedException)
{
return;
}
// Not sure why this happens :/
catch (InvalidProgramException)
{
return;
}
foreach (MethodInfo method in methods)
CacheMethod(method);
}
/// <summary>
/// Caches the method.
/// </summary>
/// <param name="method"></param>
private static void CacheMethod(MethodInfo method)
{
if (method == null)
throw new ArgumentNullException("method");
foreach (Attribute attribute in ReflectionExtensions.GetCustomAttributes<Attribute>(method, false))
s_AttributeToMethodCache[attribute] = method;
}
#endregion
#region Lookup
/// <summary>
/// Gets the class attributes of the given generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetClassAttributes<T>()
where T : Attribute
{
return s_AttributeToTypeCache.Select(kvp => kvp.Key)
.OfType<T>();
}
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
@@ -197,12 +25,24 @@ namespace ICD.Common.Utils
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type)
where T : Attribute
{
return GetClassAttribute<T>(type, false);
}
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <param name="inherit"></param>
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type, bool inherit)
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes<T>(type).FirstOrDefault();
return GetClassAttributes<T>(type, inherit).FirstOrDefault();
}
/// <summary>
@@ -212,70 +52,56 @@ namespace ICD.Common.Utils
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<T> GetClassAttributes<T>(Type type)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes(type).OfType<T>();
return GetClassAttributes<T>(type, false);
}
/// <summary>
/// Gets the attributes on the given class.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Attribute> GetClassAttributes(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
CacheType(type);
return s_TypeToAttributesCache.ContainsKey(type)
? s_TypeToAttributesCache[type].ToArray()
: Enumerable.Empty<Attribute>();
}
/// <summary>
/// Gets the type with the given attribute.
/// </summary>
/// <param name="attribute"></param>
/// <returns></returns>
public static Type GetClass(Attribute attribute)
{
if (attribute == null)
throw new ArgumentNullException("attribute");
return s_AttributeToTypeCache[attribute];
}
/// <summary>
/// Gets all of the cached method attributes of the given type.
/// Gets the attributes on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <param name="inherit"></param>
/// <returns></returns>
public static IEnumerable<T> GetMethodAttributes<T>()
where T : Attribute
public static IEnumerable<T> GetClassAttributes<T>(Type type, bool inherit)
{
return s_AttributeToMethodCache.Select(p => p.Key)
.OfType<T>()
.ToArray();
if (type == null)
throw new ArgumentNullException("type");
// ReSharper disable InvokeAsExtensionMethod
return ReflectionExtensions.GetCustomAttributes<T>(
#if SIMPLSHARP
(CType)
#endif
type, inherit);
// ReSharper restore InvokeAsExtensionMethod
}
/// <summary>
/// Gets the cached method for the given attribute.
/// Returns the properties on the given instance with property attributes of the given type.
/// </summary>
/// <param name="attribute"></param>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <param name="inherit"></param>
/// <returns></returns>
public static MethodInfo GetMethod(Attribute attribute)
public static IEnumerable<PropertyInfo> GetProperties<T>(object instance, bool inherit)
{
if (attribute == null)
throw new ArgumentNullException("attribute");
if (instance == null)
throw new ArgumentNullException("instance");
return s_AttributeToMethodCache[attribute];
return instance.GetType()
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetProperties()
// ReSharper disable InvokeAsExtensionMethod
.Where(p => ReflectionExtensions.GetCustomAttributes<T>(p, inherit).Any());
// ReSharper restore InvokeAsExtensionMethod
}
#endregion
}
}

View File

@@ -5,7 +5,7 @@ namespace ICD.Common.Utils.Attributes
/// <summary>
/// AbstractIcdAttribute is the base class for all ICD attributes.
/// </summary>
public abstract class AbstractIcdAttribute : Attribute
public abstract class AbstractIcdAttribute : Attribute, IIcdAttribute
{
}
}

View File

@@ -0,0 +1,6 @@
namespace ICD.Common.Utils.Attributes
{
public interface IIcdAttribute
{
}
}

View File

@@ -0,0 +1,527 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Attributes
{
/// <summary>
/// Indicates the valid ranges for a given value if that range is not equal to the range of the data type.
/// </summary>
[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Parameter |
AttributeTargets.ReturnValue)]
public sealed class RangeAttribute : AbstractIcdAttribute
{
/// <summary>
/// Remaps from the source numeric min/max to double min/max.
/// </summary>
private static readonly Dictionary<Type, Func<double, double>> s_Clamp =
new Dictionary<Type, Func<double, double>>
{
// Duh
{typeof(double), o => o},
// Signed
{typeof(short), o => o < short.MinValue ? short.MinValue : o > short.MaxValue ? short.MaxValue : o},
{typeof(int), o => o < int.MinValue ? int.MinValue : o > int.MaxValue ? int.MaxValue : o},
{typeof(long), o => o < long.MinValue ? long.MinValue : o > long.MaxValue ? long.MaxValue : o},
{typeof(float),o => o < float.MinValue ? float.MinValue : o > float.MaxValue ? float.MaxValue : o},
{typeof(decimal), o => o < (double)decimal.MinValue ? (double)decimal.MinValue : o > (double)decimal.MaxValue ? (double)decimal.MaxValue : o},
// Unsigned
{typeof(ushort), o => o < ushort.MinValue ? ushort.MinValue : o > ushort.MaxValue ? ushort.MaxValue : o},
{typeof(uint), o => o < uint.MinValue ? uint.MinValue : o > uint.MaxValue ? uint.MaxValue : o},
{typeof(ulong), o => o < ulong.MinValue ? ulong.MinValue : o > ulong.MaxValue ? ulong.MaxValue : o},
{typeof(byte), o => o < byte.MinValue ? byte.MinValue : o > byte.MaxValue ? byte.MaxValue : o}
};
/// <summary>
/// Remaps from the source numeric min/max to double min/max.
/// </summary>
private static readonly Dictionary<Type, Func<object, double>> s_RemapToDouble =
new Dictionary<Type, Func<object, double>>
{
// Duh
{ typeof(double), o => (double)o},
// Signed - Clamping prevents an overflow due to loss of precision
{ typeof(short), o => MathUtils.Clamp(Convert.ToDouble(o) / short.MaxValue, -1, 1) * double.MaxValue},
{ typeof(int), o => MathUtils.Clamp(Convert.ToDouble(o) / int.MaxValue, -1, 1) * double.MaxValue},
{ typeof(long), o => MathUtils.Clamp(Convert.ToDouble(o) / long.MaxValue, -1, 1) * double.MaxValue},
{ typeof(float), o => MathUtils.Clamp(Convert.ToDouble(o) / float.MaxValue, -1, 1) * double.MaxValue},
{ typeof(decimal), o => MathUtils.Clamp(Convert.ToDouble(o) / (double)decimal.MaxValue, -1, 1) * double.MaxValue},
// Unsigned
{ typeof(ushort), o => MathUtils.Clamp((Convert.ToDouble(o) / ushort.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
{ typeof(uint), o => MathUtils.Clamp((Convert.ToDouble(o) / uint.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
{ typeof(ulong), o => MathUtils.Clamp((Convert.ToDouble(o) / ulong.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
{ typeof(byte), o => MathUtils.Clamp((Convert.ToDouble(o) / byte.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue}
};
/// <summary>
/// Remaps from the double min/max to target numeric min/max.
/// </summary>
private static readonly Dictionary<Type, Func<double, object>> s_RemapFromDouble =
new Dictionary<Type, Func<double, object>>
{
// Duh
{typeof(double), v => v},
// Signed
{typeof(short), v => (short)(v / double.MaxValue * short.MaxValue)},
{typeof(int), v => (int)(v / double.MaxValue * int.MaxValue)},
{typeof(long), v => (long)(v / double.MaxValue * long.MaxValue)},
{typeof(float), v => (float)(v / double.MaxValue * float.MaxValue)},
{typeof(decimal), v => (decimal)(v / double.MaxValue) * decimal.MaxValue},
// Unsigned
{typeof(ushort), v => (ushort)((v / double.MaxValue + 1) / 2 * ushort.MaxValue)},
{typeof(uint), v => (uint)((v / double.MaxValue + 1) / 2 * uint.MaxValue)},
{typeof(ulong), v => (ulong)((v / double.MaxValue + 1) / 2 * ulong.MaxValue)},
{typeof(byte), v => (byte)((v / double.MaxValue + 1) / 2 * byte.MaxValue)}
};
/// <summary>
/// Gets the min value of a given numeric type as a double.
/// </summary>
private static readonly Dictionary<Type, double> s_MinAsDouble =
new Dictionary<Type, double>
{
// Duh
{typeof(double), double.MinValue},
// Signed
{typeof(short), Convert.ToDouble(short.MinValue)},
{typeof(int), Convert.ToDouble(int.MinValue)},
{typeof(long), Convert.ToDouble(long.MinValue)},
{typeof(float), Convert.ToDouble(float.MinValue)},
{typeof(decimal), Convert.ToDouble(decimal.MinValue)},
// Unsigned
{typeof(ushort), Convert.ToDouble(ushort.MinValue)},
{typeof(uint), Convert.ToDouble(uint.MinValue)},
{typeof(ulong), Convert.ToDouble(ulong.MinValue)},
{typeof(byte), Convert.ToDouble(byte.MinValue)}
};
/// <summary>
/// Gets the min value of a given numeric type as a double.
/// </summary>
private static readonly Dictionary<Type, double> s_MaxAsDouble =
new Dictionary<Type, double>
{
// Duh
{typeof(double), double.MaxValue},
// Signed
{typeof(short), Convert.ToDouble(short.MaxValue)},
{typeof(int), Convert.ToDouble(int.MaxValue)},
{typeof(long), Convert.ToDouble(long.MaxValue)},
{typeof(float), Convert.ToDouble(float.MaxValue)},
{typeof(decimal), Convert.ToDouble(decimal.MaxValue)},
// Unsigned
{typeof(ushort), Convert.ToDouble(ushort.MaxValue)},
{typeof(uint), Convert.ToDouble(uint.MaxValue)},
{typeof(ulong), Convert.ToDouble(ulong.MaxValue)},
{typeof(byte), Convert.ToDouble(byte.MaxValue)}
};
private readonly object m_Min;
private readonly object m_Max;
#region Properties
/// <summary>
/// Gets the min value for this range.
/// </summary>
public object Min { get { return m_Min; } }
/// <summary>
/// Gets the max value for this range.
/// </summary>
public object Max { get { return m_Max; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(ushort min, ushort max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(short min, short max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(uint min, uint max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(int min, int max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(ulong min, ulong max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(long min, long max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(float min, float max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(double min, double max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(byte min, byte max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(sbyte min, sbyte max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(decimal min, decimal max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(object min, object max)
{
if (min == null)
throw new ArgumentNullException("min");
if (max == null)
throw new ArgumentNullException("max");
if (min.GetType() != max.GetType())
throw new ArgumentException("Min and Max types do not match");
if (!min.GetType().IsNumeric())
throw new ArgumentException("Given types are not numeric");
m_Min = min;
m_Max = max;
}
#endregion
#region Methods
/// <summary>
/// Remaps the numeric value into the min-max range of the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
[NotNull]
public static object Remap([NotNull] object value, [NotNull] Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double intermediate = RemapToDouble(value);
return RemapFromDouble(intermediate, type);
}
/// <summary>
/// Remaps the given numeric value from its min/max range into double min/max range.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static double RemapToDouble([NotNull] object value)
{
if (value == null)
throw new ArgumentNullException("value");
Func<object, double> remap;
if (!s_RemapToDouble.TryGetValue(value.GetType(), out remap))
throw new NotSupportedException("Value type is not supported.");
return remap(value);
}
/// <summary>
/// Remaps the given double value from its min/max range into the target type min/max range.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
[NotNull]
public static object RemapFromDouble(double value, [NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
Func<double, object> remap;
if (!s_RemapFromDouble.TryGetValue(type, out remap))
throw new NotSupportedException("Value type is not supported.");
return remap(value);
}
/// <summary>
/// Remaps the given numeric value to the defined min/max.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[NotNull]
public object RemapMinMax([NotNull] object value)
{
if (value == null)
throw new ArgumentNullException("value");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double sourceMin = GetMinAsDouble(value.GetType());
double sourceMax = GetMaxAsDouble(value.GetType());
double targetMin = Convert.ToDouble(Min);
double targetMax = Convert.ToDouble(Max);
double doubleValue = Convert.ToDouble(value);
double remapped = MathUtils.MapRange(sourceMin, sourceMax, targetMin, targetMax, doubleValue);
return Convert.ChangeType(remapped, value.GetType(), CultureInfo.InvariantCulture);
}
/// <summary>
/// Clamps the given numeric value into the valid ranges of the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
[NotNull]
public static object Clamp([NotNull] object value, [NotNull] Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double doubleValue = Convert.ToDouble(value);
double clamped = Clamp(doubleValue, type);
return Convert.ChangeType(clamped, value.GetType(), CultureInfo.InvariantCulture);
}
/// <summary>
/// Clamps the given double value into the valid ranges of the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static double Clamp(double value, [NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
Func<double, double> clamp;
if (!s_Clamp.TryGetValue(type, out clamp))
throw new NotSupportedException("Value type is not supported.");
return clamp(value);
}
/// <summary>
/// Clamps the given numeric value to the defined min/max then remaps to the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
[NotNull]
public object ClampMinMaxThenRemap([NotNull] object value, [NotNull] Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double min = Convert.ToDouble(Min);
double max = Convert.ToDouble(Max);
double doubleValue = Convert.ToDouble(value);
double clamped = MathUtils.Clamp(doubleValue, min, max);
object remapped = RemapMinMax(clamped, type);
return Convert.ChangeType(remapped, value.GetType(), CultureInfo.InvariantCulture);
}
#endregion
#region Private Methods
[NotNull]
private object RemapMinMax([NotNull] object value, [NotNull] Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double sourceMin = Convert.ToDouble(Min);
double sourceMax = Convert.ToDouble(Max);
double targetMin = GetMinAsDouble(type);
double targetMax = GetMaxAsDouble(type);
double doubleValue = Convert.ToDouble(value);
double remapped = MathUtils.MapRange(sourceMin, sourceMax, targetMin, targetMax, doubleValue);
return Convert.ChangeType(remapped, type, CultureInfo.InvariantCulture);
}
/// <summary>
/// Gets the min value for the given numeric type as a double.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static double GetMinAsDouble([NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
double min;
if (!s_MinAsDouble.TryGetValue(type, out min))
throw new NotSupportedException("Type is not supported.");
return min;
}
/// <summary>
/// Gets the max value for the given numeric type as a double.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static double GetMaxAsDouble([NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
double max;
if (!s_MaxAsDouble.TryGetValue(type, out max))
throw new NotSupportedException("Type is not supported.");
return max;
}
#endregion
}
}

View 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);
}
}
}

View File

@@ -0,0 +1,274 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Properties;
#if !SIMPLSHARP
using System.Diagnostics;
#endif
namespace ICD.Common.Utils.Collections
{
/// <summary>
/// Provides a 1-to-1 map of Keys to Values with O(1) Value->Key lookup time.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
#if !SIMPLSHARP
[DebuggerDisplay("Count = {Count}")]
#endif
public sealed class BiDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> m_KeyToValue;
private readonly Dictionary<TValue, TKey> m_ValueToKey;
#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_ValueToKey.Keys; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
public BiDictionary() :
this(EqualityComparer<TKey>.Default, EqualityComparer<TValue>.Default)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="keyComparer"></param>
/// <param name="valueComparer"></param>
public BiDictionary(IEqualityComparer<TKey> keyComparer, IEqualityComparer<TValue> valueComparer)
{
m_KeyToValue = new Dictionary<TKey, TValue>(keyComparer);
m_ValueToKey = new Dictionary<TValue, TKey>(valueComparer);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="dict"></param>
/// <param name="keyComparer"></param>
/// <param name="valueComparer"></param>
public BiDictionary([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 BiDictionary([NotNull] Dictionary<TKey, TValue> dict)
: this(dict, EqualityComparer<TKey>.Default, EqualityComparer<TValue>.Default)
{
}
#region Methods
public void Clear()
{
m_KeyToValue.Clear();
m_ValueToKey.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_ValueToKey.ContainsKey(value);
}
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");
if (ContainsValue(value))
throw new ArgumentException("Value is already present in the collection", "value");
m_KeyToValue.Add(key, value);
m_ValueToKey.Add(value, 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);
RemoveValue(value);
Add(key, value);
}
[NotNull]
public TKey GetKey([NotNull] TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
return m_ValueToKey[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);
m_ValueToKey.Remove(value);
return true;
}
public bool RemoveValue([NotNull] TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
if (!ContainsValue(value))
return false;
TKey key = m_ValueToKey[value];
return RemoveKey(key);
}
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 TryGetKey([NotNull] TValue value, out TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
return m_ValueToKey.TryGetValue(value, out key);
}
#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
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace ICD.Common.Utils.Collections
{
// Poor-mans System.Collections.Specialized
// Delete when we finally drop Crestron 3-series.
public interface INotifyCollectionChanged
{
/// <summary>
/// Raised when the contents of the collection change, or the order changes.
/// </summary>
event EventHandler OnCollectionChanged;
}
}

View File

@@ -3,6 +3,10 @@ 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
{
@@ -10,18 +14,15 @@ namespace ICD.Common.Utils.Collections
/// A collection containing only unique items.
/// </summary>
/// <typeparam name="T"></typeparam>
#if !SIMPLSHARP
[DebuggerDisplay("Count = {Count}")]
#endif
public sealed class IcdHashSet<T> : ICollection<T>
{
private readonly Dictionary<T, object> m_Dict;
#region Properties
/// <summary>
/// Returns a new, empty hashset.
/// </summary>
[PublicAPI]
public static IcdHashSet<T> NullSet { get { return new IcdHashSet<T>(); } }
/// <summary>
/// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
@@ -46,19 +47,42 @@ namespace ICD.Common.Utils.Collections
/// Constructor.
/// </summary>
public IcdHashSet()
: this(Enumerable.Empty<T>())
{
m_Dict = new Dictionary<T, object>();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="items"></param>
public IcdHashSet(IEnumerable<T> items)
: this()
public IcdHashSet([NotNull] IEnumerable<T> items)
: this(EqualityComparer<T>.Default, items)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
public IcdHashSet([NotNull] IEqualityComparer<T> comparer)
: this(comparer, Enumerable.Empty<T>())
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
/// <param name="items"></param>
public IcdHashSet([NotNull] IEqualityComparer<T> comparer, [NotNull] IEnumerable<T> items)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
if (items == null)
return;
throw new ArgumentNullException("items");
m_Dict = new Dictionary<T, object>(comparer);
AddRange(items);
}
@@ -67,26 +91,37 @@ namespace ICD.Common.Utils.Collections
#region Methods
/// <summary>
/// Returns a set containing all of this sets items plus all of the items in the given set.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> Union(IEnumerable<T> set)
[NotNull]
public IcdHashSet<T> Union([NotNull] IEnumerable<T> set)
{
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
if (set == null)
return unionSet;
throw new ArgumentNullException("set");
IcdHashSet<T> unionSet = new IcdHashSet<T>(m_Dict.Comparer, this);
unionSet.AddRange(set);
return unionSet;
}
/// <summary>
/// Returns a new set of this sets items exluding the items in the given set.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> Subtract(IEnumerable<T> set)
[NotNull]
public IcdHashSet<T> Subtract([NotNull] IEnumerable<T> set)
{
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
if (set == null)
return subtractSet;
throw new ArgumentNullException("set");
IcdHashSet<T> subtractSet = new IcdHashSet<T>(m_Dict.Comparer, this);
foreach (T item in set)
subtractSet.Remove(item);
@@ -94,23 +129,19 @@ namespace ICD.Common.Utils.Collections
return subtractSet;
}
/// <summary>
/// Returns all of the items that are common between this set and the given set.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsSubsetOf(IcdHashSet<T> set)
[NotNull]
public IcdHashSet<T> Intersection([NotNull] IEnumerable<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
return this.All(setToCompare.Contains);
}
[PublicAPI]
public IcdHashSet<T> Intersection(IcdHashSet<T> set)
{
IcdHashSet<T> intersectionSet = NullSet;
if (set == null)
return intersectionSet;
throw new ArgumentNullException("set");
foreach (T item in this.Where(set.Contains))
intersectionSet.Add(item);
IcdHashSet<T> intersectionSet = new IcdHashSet<T>(m_Dict.Comparer);
foreach (T item in set.Where(Contains))
intersectionSet.Add(item);
@@ -124,58 +155,109 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> NonIntersection(IcdHashSet<T> set)
[NotNull]
public IcdHashSet<T> NonIntersection([NotNull] IEnumerable<T> set)
{
return Subtract(set).Union(set.Subtract(this));
if (set == null)
throw new ArgumentNullException("set");
IcdHashSet<T> output = new IcdHashSet<T>(m_Dict.Comparer, this);
foreach (T item in set)
{
if (output.Contains(item))
output.Remove(item);
else
output.Add(item);
}
return output;
}
/// <summary>
/// Returns true if the given set contains all of the items in this set.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsProperSubsetOf(IcdHashSet<T> set)
public bool IsSubsetOf([NotNull] IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
if (set == null)
throw new ArgumentNullException("set");
// Is a proper subset if A is a subset of B and A != B
return (IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this));
return Count <= set.Count && this.All(set.Contains);
}
/// <summary>
/// Returns true if the given set contains all of the items in this set, and the sets are not equal.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsSupersetOf(IcdHashSet<T> set)
public bool IsProperSubsetOf([NotNull] IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
return setToCompare.IsSubsetOf(this);
if (set == null)
throw new ArgumentNullException("set");
return Count < set.Count && IsSubsetOf(set);
}
/// <summary>
/// Returns true if this set contains all of the items in the given set.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsProperSupersetOf(IcdHashSet<T> set)
public bool IsSupersetOf([NotNull] IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
if (set == null)
throw new ArgumentNullException("set");
// B is a proper superset of A if B is a superset of A and A != B
return (IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this));
return set.IsSubsetOf(this);
}
/// <summary>
/// Returns true if this set contains all of the items in the given set, and the sets are not equal.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool SetEquals(IcdHashSet<T> set)
public bool IsProperSupersetOf([NotNull] IcdHashSet<T> set)
{
var setToCompare = set ?? NullSet;
if (set == null)
throw new ArgumentNullException("set");
return (IsSubsetOf(setToCompare) && setToCompare.IsSubsetOf(this));
return set.IsProperSubsetOf(this);
}
/// <summary>
/// Returns true if this set contains all of the items in the given set, and vice versa.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool SetEquals([NotNull] IcdHashSet<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
return Count == set.Count && set.All(Contains);
}
#endregion
#region ICollection<T> Members
#region ICollection<T>
/// <summary>
/// Adds the item to the collection. Returns false if the item already exists.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Add(T item)
public bool Add([NotNull] T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("item");
if (m_Dict.ContainsKey(item))
@@ -189,7 +271,7 @@ namespace ICD.Common.Utils.Collections
/// Adds the item to the collection.
/// </summary>
/// <param name="item"></param>
void ICollection<T>.Add(T item)
void ICollection<T>.Add([NotNull] T item)
{
Add(item);
}
@@ -198,21 +280,13 @@ namespace ICD.Common.Utils.Collections
/// Adds each of the items in the sequence to the collection.
/// </summary>
/// <param name="items"></param>
public void AddRange(IEnumerable<T> items)
public void AddRange([NotNull] IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
foreach (T item in items)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new InvalidOperationException("item");
if (!m_Dict.ContainsKey(item))
m_Dict[item] = null;
}
m_Dict[item] = null;
}
/// <summary>
@@ -229,8 +303,13 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
public bool Contains([NotNull] T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("item");
return m_Dict.ContainsKey(item);
}
@@ -238,8 +317,11 @@ namespace ICD.Common.Utils.Collections
/// Copies the items of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the items copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of items in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type T cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
public void CopyTo(T[] array, int arrayIndex)
public void CopyTo([NotNull] T[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("array");
m_Dict.Keys.CopyTo(array, arrayIndex);
}
@@ -250,14 +332,31 @@ namespace ICD.Common.Utils.Collections
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public bool Remove(T item)
public bool Remove([NotNull] T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("item");
return m_Dict.Remove(item);
}
/// <summary>
/// Removes each of the items in the sequence from the collection.
/// </summary>
/// <param name="items"></param>
public void RemoveRange([NotNull] IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
m_Dict.RemoveAll(items);
}
#endregion
#region Implementation of IEnumerable
#region IEnumerable<T>
/// <summary>
/// Returns an enumerator that iterates through the collection.
@@ -266,6 +365,7 @@ namespace ICD.Common.Utils.Collections
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
[NotNull]
public IEnumerator<T> GetEnumerator()
{
return m_Dict.Keys.GetEnumerator();
@@ -278,6 +378,7 @@ namespace ICD.Common.Utils.Collections
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();

View File

@@ -1,159 +1,651 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Collections
{
public sealed class IcdOrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
public sealed class IcdOrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary
{
private readonly List<TKey> m_OrderedKeys;
private readonly Dictionary<TKey, TValue> m_Dictionary;
private readonly IComparer<TKey> m_Comparer;
private readonly IcdOrderedDictionary m_PrivateDictionary;
#region Properties
public int Count { get { return m_PrivateDictionary.Count; } }
public int Count { get { return m_Dictionary.Count; } }
int ICollection.Count { get { return m_PrivateDictionary.Count; } }
public bool IsReadOnly { get { return false; } }
public ICollection<TKey> Keys { get { return m_OrderedKeys; } }
public TValue this[TKey key]
{
get
{
if (key == null)
throw new ArgumentNullException("key");
if (m_PrivateDictionary.Contains(key))
return (TValue)m_PrivateDictionary[key];
throw new KeyNotFoundException();
}
set
{
if (key == null)
throw new ArgumentNullException("key");
m_PrivateDictionary[key] = value;
}
}
object IDictionary.this[object key]
{
get { return m_PrivateDictionary[key]; }
set { m_PrivateDictionary[key] = value; }
}
public ICollection<TKey> Keys
{
get
{
List<TKey> keys = new List<TKey>(m_PrivateDictionary.Count);
foreach (TKey key in m_PrivateDictionary.Keys)
{
keys.Add(key);
}
// Keys should be put in a ReadOnlyCollection,
// but since this is an internal class, for performance reasons,
// we choose to avoid creating yet another collection.
return keys;
}
}
ICollection IDictionary.Keys { get { return m_PrivateDictionary.Keys; } }
public ICollection<TValue> Values
{
get
{
return m_OrderedKeys.Select(k => m_Dictionary[k])
.ToArray(Count);
List<TValue> values = new List<TValue>(m_PrivateDictionary.Count);
foreach (TValue value in m_PrivateDictionary.Values)
values.Add(value);
// Values should be put in a ReadOnlyCollection,
// but since this is an internal class, for performance reasons,
// we choose to avoid creating yet another collection.
return values;
}
}
public TValue this[TKey key]
{
get { return m_Dictionary[key]; }
set
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
ICollection IDictionary.Values { get { return m_PrivateDictionary.Values; } }
if (!ContainsKey(key))
m_OrderedKeys.AddSorted(key, m_Comparer);
bool IDictionary.IsFixedSize { get { return ((IDictionary)m_PrivateDictionary).IsFixedSize; } }
m_Dictionary[key] = value;
}
}
bool IDictionary.IsReadOnly { get { return m_PrivateDictionary.IsReadOnly; } }
#endregion
bool ICollection.IsSynchronized { get { return ((ICollection)m_PrivateDictionary).IsSynchronized; } }
object ICollection.SyncRoot { get { return m_PrivateDictionary; } }
/// <summary>
/// Constructor.
/// </summary>
public IcdOrderedDictionary()
: this(Comparer<TKey>.Default)
{
m_PrivateDictionary = new IcdOrderedDictionary();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
public IcdOrderedDictionary(IComparer<TKey> comparer)
public IcdOrderedDictionary(IEnumerable<KeyValuePair<TKey, TValue>> dictionary)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
if (dictionary == null)
return;
m_Comparer = comparer;
m_OrderedKeys = new List<TKey>();
m_Dictionary = new Dictionary<TKey, TValue>();
m_PrivateDictionary = new IcdOrderedDictionary();
foreach (KeyValuePair<TKey, TValue> pair in dictionary)
{
m_PrivateDictionary.Add(pair.Key, pair.Value);
}
}
#region Methods
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
public void Add(KeyValuePair<TKey, TValue> item)
{
return m_OrderedKeys.Select(k => new KeyValuePair<TKey, TValue>(k, m_Dictionary[k]))
.GetEnumerator();
Add(item.Key, item.Value);
}
public void Add(TKey key, TValue value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
if (m_Dictionary.ContainsKey(key))
throw new ArgumentException("An item with the same key has already been added.", "key");
m_PrivateDictionary.Add(key, value);
}
this[key] = value;
public KeyValuePair<TKey, TValue> Get(int index)
{
DictionaryEntry entry = (DictionaryEntry)m_PrivateDictionary.ObjectsArray[index];
return new KeyValuePair<TKey, TValue>((TKey)entry.Key, (TValue)entry.Value);
}
public void Clear()
{
m_OrderedKeys.Clear();
m_Dictionary.Clear();
m_PrivateDictionary.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
if (item.Key == null || !m_PrivateDictionary.Contains(item.Key))
return false;
return m_PrivateDictionary[item.Key].Equals(item.Value);
}
public bool ContainsKey(TKey key)
{
return m_Dictionary.ContainsKey(key);
}
public bool Remove(TKey key)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
if (!m_Dictionary.Remove(key))
return false;
m_OrderedKeys.Remove(key);
return true;
return m_PrivateDictionary.Contains(key);
}
public bool TryGetValue(TKey key, out TValue value)
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
return m_Dictionary.TryGetValue(key, out value);
if (array == null)
{
throw new ArgumentNullException("array");
}
if (arrayIndex < 0)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
if (array.Rank > 1 || arrayIndex >= array.Length || array.Length - arrayIndex < m_PrivateDictionary.Count)
{
throw new ArgumentException("array");
}
int index = arrayIndex;
foreach (DictionaryEntry entry in m_PrivateDictionary)
{
array[index] = new KeyValuePair<TKey, TValue>((TKey)entry.Key, (TValue)entry.Value);
index++;
}
}
#endregion
#region Private Methods
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (DictionaryEntry entry in m_PrivateDictionary)
yield return new KeyValuePair<TKey, TValue>((TKey)entry.Key, (TValue)entry.Value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
public bool Remove(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
TValue value;
return TryGetValue(item.Key, out value) &&
EqualityComparer<TValue>.Default.Equals(value, item.Value);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
{
foreach (KeyValuePair<TKey, TValue> kvp in this)
if (Contains(item))
{
array.SetValue(kvp, index);
index++;
m_PrivateDictionary.Remove(item.Key);
return true;
}
return false;
}
public bool Remove(TKey key)
{
if (key == null)
throw new ArgumentNullException("key");
if (m_PrivateDictionary.Contains(key))
{
m_PrivateDictionary.Remove(key);
return true;
}
return false;
}
public bool TryGetValue(TKey key, out TValue value)
{
if (key == null)
throw new ArgumentNullException("key");
bool keyExists = m_PrivateDictionary.Contains(key);
value = keyExists ? (TValue)m_PrivateDictionary[key] : default(TValue);
return keyExists;
}
void IDictionary.Add(object key, object value)
{
m_PrivateDictionary.Add(key, value);
}
void IDictionary.Clear()
{
m_PrivateDictionary.Clear();
}
bool IDictionary.Contains(object key)
{
return m_PrivateDictionary.Contains(key);
}
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return m_PrivateDictionary.GetEnumerator();
}
void IDictionary.Remove(object key)
{
m_PrivateDictionary.Remove(key);
}
void ICollection.CopyTo(Array array, int index)
{
m_PrivateDictionary.CopyTo(array, index);
}
}
internal sealed class IcdOrderedDictionary : IDictionary
{
private ArrayList m_ObjectsArray;
private Hashtable m_ObjectsTable;
private readonly int m_InitialCapacity;
private readonly IEqualityComparer m_Comparer;
private readonly bool m_ReadOnly;
/// <summary>
/// Gets the size of the table.
/// </summary>
public int Count { get { return ObjectsArray.Count; } }
/// <summary>
/// Indicates that the collection can grow.
/// </summary>
bool IDictionary.IsFixedSize { get { return m_ReadOnly; } }
/// <summary>
/// Indicates that the collection is not read-only
/// </summary>
public bool IsReadOnly { get { return m_ReadOnly; } }
/// <summary>
/// Indicates that this class is not synchronized
/// </summary>
bool ICollection.IsSynchronized { get { return false; } }
/// <summary>
/// Gets the collection of keys in the table in order.
/// </summary>
public ICollection Keys { get { return new OrderedDictionaryKeyValueCollection(ObjectsArray, true); } }
/// <summary>
/// Returns an arrayList of the values in the table
/// </summary>
public ICollection Values { get { return new OrderedDictionaryKeyValueCollection(ObjectsArray, false); } }
public ArrayList ObjectsArray
{
get { return m_ObjectsArray ?? (m_ObjectsArray = new ArrayList(m_InitialCapacity)); }
}
private Hashtable ObjectsTable
{
get { return m_ObjectsTable ?? (m_ObjectsTable = new Hashtable(m_InitialCapacity, m_Comparer)); }
}
/// <summary>
/// The SyncRoot object. Not used because IsSynchronized is false
/// </summary>
object ICollection.SyncRoot { get { return this; } }
/// <summary>
/// Gets or sets the object at the specified index
/// </summary>
public object this[int index]
{
get { return ((DictionaryEntry)ObjectsArray[index]).Value; }
set
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
if (index < 0 || index >= ObjectsArray.Count)
{
throw new ArgumentOutOfRangeException("index");
}
object key = ((DictionaryEntry)ObjectsArray[index]).Key;
ObjectsArray[index] = new DictionaryEntry(key, value);
ObjectsTable[key] = value;
}
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
/// <summary>
/// Gets or sets the object with the specified key
/// </summary>
public object this[object key]
{
return (this as ICollection<KeyValuePair<TKey, TValue>>).Contains(item) && Remove(item.Key);
get { return ObjectsTable[key]; }
set
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
if (ObjectsTable.Contains(key))
{
ObjectsTable[key] = value;
ObjectsArray[IndexOfKey(key)] = new DictionaryEntry(key, value);
}
else
{
Add(key, value);
}
}
}
public IcdOrderedDictionary() : this(0)
{
}
public IcdOrderedDictionary(int capacity) : this(capacity, null)
{
}
public IcdOrderedDictionary(int capacity, IEqualityComparer comparer)
{
m_InitialCapacity = capacity;
m_Comparer = comparer;
}
private IcdOrderedDictionary(IcdOrderedDictionary dictionary)
{
if (dictionary == null)
{
throw new ArgumentNullException("dictionary");
}
m_ReadOnly = true;
m_ObjectsArray = dictionary.m_ObjectsArray;
m_ObjectsTable = dictionary.m_ObjectsTable;
m_Comparer = dictionary.m_Comparer;
m_InitialCapacity = dictionary.m_InitialCapacity;
}
/// <summary>
/// Adds a new entry to the table with the lowest-available index.
/// </summary>
public void Add(object key, object value)
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
ObjectsTable.Add(key, value);
ObjectsArray.Add(new DictionaryEntry(key, value));
}
/// <summary>
/// Clears all elements in the table.
/// </summary>
public void Clear()
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
ObjectsTable.Clear();
ObjectsArray.Clear();
}
/// <summary>
/// Returns a readonly IcdOrderedDictionary for the given IcdOrderedDictionary.
/// </summary>
public IcdOrderedDictionary AsReadOnly()
{
return new IcdOrderedDictionary(this);
}
/// <summary>
/// Returns true if the key exists in the table, false otherwise.
/// </summary>
public bool Contains(object key)
{
return ObjectsTable.Contains(key);
}
/// <summary>
/// Copies the table to an array. This will not preserve order.
/// </summary>
public void CopyTo(Array array, int index)
{
ObjectsTable.CopyTo(array, index);
}
private int IndexOfKey(object key)
{
for (int i = 0; i < ObjectsArray.Count; i++)
{
object o = ((DictionaryEntry)ObjectsArray[i]).Key;
if (m_Comparer != null)
{
if (m_Comparer.Equals(o, key))
{
return i;
}
}
else
{
if (o.Equals(key))
{
return i;
}
}
}
return -1;
}
/// <summary>
/// Inserts a new object at the given index with the given key.
/// </summary>
public void Insert(int index, object key, object value)
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
if (index > Count || index < 0)
{
throw new ArgumentOutOfRangeException("index");
}
ObjectsTable.Add(key, value);
ObjectsArray.Insert(index, new DictionaryEntry(key, value));
}
/// <summary>
/// Removes the entry at the given index.
/// </summary>
public void RemoveAt(int index)
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
if (index >= Count || index < 0)
{
throw new ArgumentOutOfRangeException("index");
}
object key = ((DictionaryEntry)ObjectsArray[index]).Key;
ObjectsArray.RemoveAt(index);
ObjectsTable.Remove(key);
}
/// <summary>
/// Removes the entry with the given key.
/// </summary>
public void Remove(object key)
{
if (m_ReadOnly)
{
throw new NotSupportedException();
}
if (key == null)
{
throw new ArgumentNullException("key");
}
int index = IndexOfKey(key);
if (index < 0)
{
return;
}
ObjectsTable.Remove(key);
ObjectsArray.RemoveAt(index);
}
#region IDictionary implementation
/// <internalonly/>
public IDictionaryEnumerator GetEnumerator()
{
return new OrderedDictionaryEnumerator(ObjectsArray, OrderedDictionaryEnumerator.DICTIONARY_ENTRY);
}
#endregion
#region IEnumerable implementation
/// <internalonly/>
IEnumerator IEnumerable.GetEnumerator()
{
return new OrderedDictionaryEnumerator(ObjectsArray, OrderedDictionaryEnumerator.DICTIONARY_ENTRY);
}
#endregion
/// <summary>
/// OrderedDictionaryEnumerator works just like any other IDictionaryEnumerator, but it retrieves DictionaryEntries
/// in the order by index.
/// </summary>
private sealed class OrderedDictionaryEnumerator : IDictionaryEnumerator
{
internal const int KEYS = 1;
internal const int VALUES = 2;
internal const int DICTIONARY_ENTRY = 3;
private readonly int m_ObjectReturnType;
private readonly IEnumerator m_ArrayEnumerator;
internal OrderedDictionaryEnumerator(ArrayList array, int objectReturnType)
{
m_ArrayEnumerator = array.GetEnumerator();
m_ObjectReturnType = objectReturnType;
}
/// <summary>
/// Retrieves the current DictionaryEntry. This is the same as Entry, but not strongly-typed.
/// </summary>
public object Current
{
get
{
if (m_ObjectReturnType == KEYS)
{
return ((DictionaryEntry)m_ArrayEnumerator.Current).Key;
}
if (m_ObjectReturnType == VALUES)
{
return ((DictionaryEntry)m_ArrayEnumerator.Current).Value;
}
return Entry;
}
}
/// <summary>
/// Retrieves the current DictionaryEntry
/// </summary>
public DictionaryEntry Entry
{
get
{
return new DictionaryEntry(((DictionaryEntry)m_ArrayEnumerator.Current).Key,
((DictionaryEntry)m_ArrayEnumerator.Current).Value);
}
}
/// <summary>
/// Retrieves the key of the current DictionaryEntry
/// </summary>
public object Key { get { return ((DictionaryEntry)m_ArrayEnumerator.Current).Key; } }
/// <summary>
/// Retrieves the value of the current DictionaryEntry
/// </summary>
public object Value { get { return ((DictionaryEntry)m_ArrayEnumerator.Current).Value; } }
/// <summary>
/// Moves the enumerator pointer to the next member
/// </summary>
public bool MoveNext()
{
return m_ArrayEnumerator.MoveNext();
}
/// <summary>
/// Resets the enumerator pointer to the beginning.
/// </summary>
public void Reset()
{
m_ArrayEnumerator.Reset();
}
}
/// <summary>
/// OrderedDictionaryKeyValueCollection implements a collection for the Values and Keys properties
/// that is "live"- it will reflect changes to the IcdOrderedDictionary on the collection made after the getter
/// was called.
/// </summary>
private sealed class OrderedDictionaryKeyValueCollection : ICollection
{
private readonly ArrayList m_Objects;
private readonly bool m_IsKeys;
public OrderedDictionaryKeyValueCollection(ArrayList array, bool isKeys)
{
m_Objects = array;
m_IsKeys = isKeys;
}
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
if (index < 0)
throw new ArgumentOutOfRangeException("index");
foreach (object o in m_Objects)
{
array.SetValue(m_IsKeys ? ((DictionaryEntry)o).Key : ((DictionaryEntry)o).Value, index);
index++;
}
}
int ICollection.Count { get { return m_Objects.Count; } }
bool ICollection.IsSynchronized { get { return false; } }
object ICollection.SyncRoot { get { return m_Objects.SyncRoot; } }
IEnumerator IEnumerable.GetEnumerator()
{
return new OrderedDictionaryEnumerator(m_Objects,
m_IsKeys
? OrderedDictionaryEnumerator.KEYS
: OrderedDictionaryEnumerator.VALUES);
}
}
}
}

View File

@@ -0,0 +1,213 @@
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 sealed class IcdSortedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly List<TKey> m_OrderedKeys;
private readonly List<TValue> m_ValuesOrderedByKey;
private readonly Dictionary<TKey, TValue> m_Dictionary;
private readonly IComparer<TKey> m_Comparer;
#region Properties
public int Count { get { return m_Dictionary.Count; } }
public bool IsReadOnly { get { return false; } }
[NotNull]
public ICollection<TKey> Keys { get { return m_OrderedKeys; } }
[NotNull]
public ICollection<TValue> Values { get { return m_ValuesOrderedByKey; } }
[CanBeNull]
public TValue this[[NotNull] TKey key]
{
get { return m_Dictionary[key]; }
set
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
Remove(key);
Add(key, value);
}
}
#endregion
/// <summary>
/// Constructor.
/// </summary>
public IcdSortedDictionary()
: this(Comparer<TKey>.Default)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
public IcdSortedDictionary([NotNull] IComparer<TKey> comparer)
: this(comparer, EqualityComparer<TKey>.Default)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
/// <param name="equalityComparer"></param>
public IcdSortedDictionary([NotNull] IComparer<TKey> comparer, [NotNull] IEqualityComparer<TKey> equalityComparer)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
if (equalityComparer == null)
throw new ArgumentNullException("equalityComparer");
m_Comparer = comparer;
m_OrderedKeys = new List<TKey>();
m_ValuesOrderedByKey = new List<TValue>();
m_Dictionary = new Dictionary<TKey, TValue>(equalityComparer);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="dictionary"></param>
public IcdSortedDictionary([NotNull] IEnumerable<KeyValuePair<TKey, TValue>> dictionary)
: this()
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
Add(kvp.Key, kvp.Value);
}
#region Methods
[NotNull]
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return m_OrderedKeys.Select(k => new KeyValuePair<TKey, TValue>(k, m_Dictionary[k]))
.GetEnumerator();
}
public void Add([NotNull] TKey key, [CanBeNull] TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
if (m_Dictionary.ContainsKey(key))
throw new ArgumentOutOfRangeException("key", "An item with the same key has already been added.");
int index = m_OrderedKeys.InsertSorted(key, m_Comparer);
m_ValuesOrderedByKey.Insert(index, value);
m_Dictionary[key] = value;
}
public void Clear()
{
m_OrderedKeys.Clear();
m_ValuesOrderedByKey.Clear();
m_Dictionary.Clear();
}
public bool ContainsKey([NotNull] TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return m_Dictionary.ContainsKey(key);
}
public bool Remove([NotNull] TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
if (!m_Dictionary.Remove(key))
return false;
int index = m_OrderedKeys.BinarySearch(key, m_Comparer);
m_OrderedKeys.RemoveAt(index);
m_ValuesOrderedByKey.RemoveAt(index);
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_Dictionary.TryGetValue(key, out value);
}
#endregion
#region Private Methods
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
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)
{
TValue value;
return TryGetValue(item.Key, out value) &&
EqualityComparer<TValue>.Default.Equals(value, item.Value);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo([NotNull] KeyValuePair<TKey, TValue>[] array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
foreach (KeyValuePair<TKey, TValue> kvp in this)
{
array.SetValue(kvp, index);
index++;
}
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
return (this as ICollection<KeyValuePair<TKey, TValue>>).Contains(item) && Remove(item.Key);
}
#endregion
}
}

View File

@@ -4,15 +4,21 @@ 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
{
/// <summary>
/// Provides a first-in first-out collection with enhanced insertion features.
/// </summary>
#if !SIMPLSHARP
[DebuggerDisplay("Count = {Count}")]
#endif
public sealed class PriorityQueue<T> : IEnumerable<T>, ICollection
{
private readonly IcdOrderedDictionary<int, List<T>> m_PriorityToQueue;
private readonly IcdSortedDictionary<int, List<T>> m_PriorityToQueue;
private int m_Count;
#region Properties
@@ -30,6 +36,7 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Gets a reference for locking.
/// </summary>
[NotNull]
public object SyncRoot { get { return this; } }
#endregion
@@ -39,7 +46,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
public PriorityQueue()
{
m_PriorityToQueue = new IcdOrderedDictionary<int, List<T>>();
m_PriorityToQueue = new IcdSortedDictionary<int, List<T>>();
}
#region Methods
@@ -59,7 +66,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
[PublicAPI]
public void Enqueue(T item)
public void Enqueue([CanBeNull] T item)
{
Enqueue(item, int.MaxValue);
}
@@ -71,12 +78,24 @@ namespace ICD.Common.Utils.Collections
/// <param name="item"></param>
/// <param name="priority"></param>
[PublicAPI]
public void Enqueue(T item, int priority)
public void Enqueue([CanBeNull] T item, int priority)
{
if (!m_PriorityToQueue.ContainsKey(priority))
m_PriorityToQueue.Add(priority, new List<T>());
m_PriorityToQueue.GetOrAddNew(priority, () => new List<T>())
.Add(item);
m_Count++;
}
m_PriorityToQueue[priority].Add(item);
/// <summary>
/// Adds the item to the queue with the given priority at the given index.
/// </summary>
/// <param name="item"></param>
/// <param name="priority"></param>
/// <param name="position"></param>
[PublicAPI]
public void Enqueue([CanBeNull] T item, int priority, int position)
{
m_PriorityToQueue.GetOrAddNew(priority, ()=> new List<T>())
.Insert(position, item);
m_Count++;
}
@@ -85,26 +104,22 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
[PublicAPI]
public void EnqueueFirst(T item)
public void EnqueueFirst([CanBeNull] T item)
{
const int priority = int.MinValue;
if (!m_PriorityToQueue.ContainsKey(priority))
m_PriorityToQueue.Add(priority, new List<T>());
m_PriorityToQueue[priority].Insert(0, item);
m_PriorityToQueue.GetOrAddNew(int.MinValue, () => new List<T>())
.Insert(0, item);
m_Count++;
}
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Inserts the given item in the position of the first removed item, or at the end of the queue.
/// This is useful for reducing duplication, or replacing items with something more pertinant.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
[PublicAPI]
public void EnqueueRemove(T item, Func<T, bool> remove)
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove)
{
if (remove == null)
throw new ArgumentNullException("remove");
@@ -114,21 +129,40 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Inserts the given item in the position of the first removed item, or at the end of the queue.
/// This is useful for reducing duplication, or replacing items with something more pertinant.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
/// <param name="priority"></param>
[PublicAPI]
public void EnqueueRemove(T item, Func<T, bool> remove, int priority)
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove, int priority)
{
if (remove == null)
throw new ArgumentNullException("remove");
bool inserted = false;
EnqueueRemove(item, remove, priority, false);
}
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue)
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
/// <param name="priority"></param>
/// <param name="deDuplicateToEndOfQueue"></param>
[PublicAPI]
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove, int priority, bool deDuplicateToEndOfQueue)
{
if (remove == null)
throw new ArgumentNullException("remove");
int lowestMatchingPriority = int.MaxValue;
int? firstMatchingIndex = null;
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue.ToArray())
{
int[] removeIndices =
kvp.Value
@@ -136,8 +170,11 @@ namespace ICD.Common.Utils.Collections
.Reverse()
.ToArray();
if (removeIndices.Length == 0)
continue;
if (removeIndices.Any() && kvp.Key < lowestMatchingPriority )
{
lowestMatchingPriority = kvp.Key;
firstMatchingIndex = removeIndices.Last();
}
foreach (int removeIndex in removeIndices)
{
@@ -145,18 +182,20 @@ namespace ICD.Common.Utils.Collections
m_Count--;
}
if (!inserted)
{
int insertIndex = removeIndices[0];
kvp.Value.Insert(insertIndex, item);
m_Count++;
inserted = true;
}
if (kvp.Value.Count == 0)
m_PriorityToQueue.Remove(kvp.Key);
}
if (!inserted)
if(deDuplicateToEndOfQueue)
Enqueue(item, priority);
else
{
if(firstMatchingIndex == null)
Enqueue(item, lowestMatchingPriority);
else
Enqueue(item, lowestMatchingPriority, firstMatchingIndex.Value);
}
}
/// <summary>
@@ -164,6 +203,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <returns></returns>
[PublicAPI]
[CanBeNull]
public T Dequeue()
{
T output;
@@ -181,30 +221,37 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public bool TryDequeue(out T output)
{
output = default(T);
while (true)
{
output = default(T);
KeyValuePair<int, List<T>> kvp;
if (!m_PriorityToQueue.TryFirst(out kvp))
return false;
KeyValuePair<int, List<T>> kvp;
if (!m_PriorityToQueue.TryFirst(out kvp))
return false;
int priority = kvp.Key;
List<T> queue = kvp.Value;
int priority = kvp.Key;
List<T> queue = kvp.Value;
output = queue[0];
queue.RemoveAt(0);
bool found = queue.TryFirst(out output);
if (found)
{
queue.RemoveAt(0);
m_Count--;
}
if (queue.Count == 0)
m_PriorityToQueue.Remove(priority);
if (queue.Count == 0)
m_PriorityToQueue.Remove(priority);
m_Count--;
return true;
if (found)
return true;
}
}
/// <summary>
/// Gets an enumerator for the items.
/// </summary>
/// <returns></returns>
[NotNull]
public IEnumerator<T> GetEnumerator()
{
return m_PriorityToQueue.Values
@@ -217,13 +264,13 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="array"></param>
/// <param name="index"></param>
public void CopyTo(Array array, int index)
public void CopyTo([NotNull] Array array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
foreach (T item in this)
{
array.SetValue(item, index);
index++;
}
array.SetValue(item, index++);
}
#endregion
@@ -234,6 +281,7 @@ namespace ICD.Common.Utils.Collections
/// Gets an enumerator for the items.
/// </summary>
/// <returns></returns>
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();

View 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
}
}

View File

@@ -2,7 +2,9 @@
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
#if !SIMPLSHARP
using System.Diagnostics;
#endif
namespace ICD.Common.Utils.Collections
{
@@ -11,13 +13,14 @@ namespace ICD.Common.Utils.Collections
/// are removed as new items are added.
/// </summary>
/// <typeparam name="TContents"></typeparam>
#if !SIMPLSHARP
[DebuggerDisplay("Count = {Count}")]
#endif
public sealed class ScrollQueue<TContents> : IEnumerable<TContents>, ICollection
{
private readonly LinkedList<TContents> m_Collection;
private int m_MaxSize;
private readonly SafeCriticalSection m_CollectionLock;
#region Properties
/// <summary>
@@ -34,20 +37,23 @@ namespace ICD.Common.Utils.Collections
m_MaxSize = value;
Trim();
TContents unused;
while (Trim(out unused))
{
}
}
}
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
public int Count { get { return m_CollectionLock.Execute(() => m_Collection.Count); } }
public int Count { get { return m_Collection.Count; } }
/// <summary>
/// The IsSynchronized Boolean property returns True if the
/// collection is designed to be thread safe; otherwise, it returns False.
/// </summary>
public bool IsSynchronized { get { return true; } }
public bool IsSynchronized { get { return false; } }
/// <summary>
/// The SyncRoot property returns an object, which is used for synchronizing
@@ -64,7 +70,6 @@ namespace ICD.Common.Utils.Collections
/// <param name="maxSize"></param>
public ScrollQueue(int maxSize)
{
m_CollectionLock = new SafeCriticalSection();
m_Collection = new LinkedList<TContents>();
MaxSize = maxSize;
}
@@ -76,27 +81,20 @@ namespace ICD.Common.Utils.Collections
/// </summary>
public void Clear()
{
m_CollectionLock.Execute(() => m_Collection.Clear());
m_Collection.Clear();
}
/// <summary>
/// Appends the item to the queue, trims old items that exceed max length.
/// </summary>
/// <param name="item"></param>
/// <param name="removed"></param>
/// <returns>Returns true if an item was dequeued.</returns>
[PublicAPI]
public void Enqueue(TContents item)
public bool Enqueue(TContents item, out TContents removed)
{
m_CollectionLock.Enter();
try
{
m_Collection.AddLast(item);
Trim();
}
finally
{
m_CollectionLock.Leave();
}
m_Collection.AddLast(item);
return Trim(out removed);
}
/// <summary>
@@ -106,18 +104,27 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public TContents Dequeue()
{
m_CollectionLock.Enter();
TContents output = Peek();
m_Collection.RemoveFirst();
return output;
}
try
{
TContents output = m_Collection.First.Value;
m_Collection.RemoveFirst();
return output;
}
finally
{
m_CollectionLock.Leave();
}
/// <summary>
/// Dequeues the next item in the queue. Returns false if the queue is empty.
/// </summary>
/// <typeparam name="TContents"></typeparam>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public bool Dequeue(out TContents item)
{
item = default(TContents);
if (Count == 0)
return false;
item = Dequeue();
return true;
}
/// <summary>
@@ -127,7 +134,7 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public TContents Peek()
{
return m_CollectionLock.Execute(() => m_Collection.First.Value);
return m_Collection.First.Value;
}
#endregion
@@ -141,24 +148,15 @@ namespace ICD.Common.Utils.Collections
public IEnumerator<TContents> GetEnumerator()
{
return m_CollectionLock.Execute(() => m_Collection.ToList(Count).GetEnumerator());
return m_Collection.GetEnumerator();
}
void ICollection.CopyTo(Array myArr, int index)
void ICollection.CopyTo(Array array, int index)
{
m_CollectionLock.Enter();
try
foreach (TContents item in m_Collection)
{
foreach (TContents item in m_Collection)
{
myArr.SetValue(item, index);
index++;
}
}
finally
{
m_CollectionLock.Leave();
array.SetValue(item, index);
index++;
}
}
@@ -169,19 +167,17 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Removes items that fall outside of the max size.
/// </summary>
private void Trim()
private bool Trim(out TContents removed)
{
m_CollectionLock.Enter();
removed = default(TContents);
try
{
while (Count > MaxSize)
m_Collection.RemoveFirst();
}
finally
{
m_CollectionLock.Leave();
}
if (Count <= MaxSize)
return false;
removed = m_Collection.First.Value;
m_Collection.RemoveFirst();
return true;
}
#endregion

View File

@@ -4,6 +4,9 @@ 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
{
@@ -58,9 +61,9 @@ namespace ICD.Common.Utils.Collections
m_Comparer = comparer;
}
public int GetHashCode(WeakKeyReference<T> weakKey)
public int GetHashCode(WeakKeyReference<T> obj)
{
return weakKey.HashCode;
return obj == null ? 0 : obj.HashCode;
}
// Note: There are actually 9 cases to handle here.
@@ -108,6 +111,9 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
#if !SIMPLSHARP
[DebuggerDisplay("Count = {Count}")]
#endif
public sealed class WeakKeyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly Dictionary<WeakKeyReference<TKey>, TValue> m_Dictionary;

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Comparers
{
public sealed class FileNameEqualityComparer : IEqualityComparer<string>
{
private static FileNameEqualityComparer s_Instance;
public static FileNameEqualityComparer Instance
{
get { return s_Instance ?? (s_Instance = new FileNameEqualityComparer()); }
}
private FileNameEqualityComparer()
{
}
public bool Equals(string x, string y)
{
return GetHashCode(x) == GetHashCode(y);
}
public int GetHashCode(string obj)
{
return obj == null ? 0 : IcdPath.GetFileName(obj).GetHashCode();
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils.Comparers
{
public sealed class SequenceComparer<T> : IComparer<IEnumerable<T>>
{
private readonly IComparer<T> m_ItemComparer;
/// <summary>
/// Constructor.
/// </summary>
public SequenceComparer()
: this(Comparer<T>.Default)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
public SequenceComparer(IComparer<T> comparer)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
m_ItemComparer = comparer;
}
public int Compare(IEnumerable<T> x, IEnumerable<T> y)
{
if (x == null && y == null)
return 0;
if (x == null)
return -1;
if (y == null)
return 1;
using (IEnumerator<T> firstPos = x.GetEnumerator())
{
using (IEnumerator<T> secondPos = y.GetEnumerator())
{
bool hasFirst = firstPos.MoveNext();
bool hasSecond = secondPos.MoveNext();
while (hasFirst && hasSecond)
{
int result = m_ItemComparer.Compare(firstPos.Current, secondPos.Current);
if (result != 0)
return result;
hasFirst = firstPos.MoveNext();
hasSecond = secondPos.MoveNext();
}
if (!hasFirst && !hasSecond)
return 0;
if (!hasFirst)
return -1;
return 1;
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Comparers
{
/// <summary>
/// Undefined Versions have a value of 0.0.-1.-1
/// This comparer Maxs Versions to 0.0.0.0
/// </summary>
public sealed class UndefinedVersionComparer : IComparer<Version>
{
private static UndefinedVersionComparer s_Instance;
public static UndefinedVersionComparer Instance
{
get { return s_Instance = s_Instance ?? new UndefinedVersionComparer(); }
}
public int Compare(Version x, Version y)
{
if (x == null && y == null)
return 0;
if (x == null)
return -1;
if (y == null)
return 1;
return x.ClearUndefined()
.CompareTo(y.ClearUndefined());
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Comparers
{
/// <summary>
/// Undefined Versions have a value of 0.0.-1.-1
/// This comparer Maxs Versions to 0.0.0.0
/// </summary>
public sealed class UndefinedVersionEqualityComparer : IEqualityComparer<Version>
{
private static UndefinedVersionEqualityComparer s_Instance;
public static UndefinedVersionEqualityComparer Instance
{
get { return s_Instance = s_Instance ?? new UndefinedVersionEqualityComparer(); }
}
public bool Equals(Version x, Version y)
{
return x.ClearUndefined()
.Equals(y.ClearUndefined());
}
public int GetHashCode(Version version)
{
return version.ClearUndefined()
.GetHashCode();
}
}
}

View File

@@ -1,108 +0,0 @@
using System;
namespace ICD.Common.Utils
{
public enum eConsoleColor
{
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
YellowOnRed
}
public static class ConsoleColorExtensions
{
public const string CONSOLE_RED = "\x1B[31;1m";
public const string CONSOLE_GREEN = "\x1B[32;1m";
public const string CONSOLE_YELLOW = "\x1B[33;1m";
public const string CONSOLE_BLUE = "\x1B[34;1m";
public const string CONSOLE_MAGENTA = "\x1B[35;1m";
public const string CONSOLE_CYAN = "\x1B[36;1m";
public const string CONSOLE_WHITE = "\x1B[37;1m";
public const string CONSOLE_YELLOW_ON_RED_BACKGROUND = "\x1B[93;41m";
public const string CONSOLE_RESET = "\x1B[0m";
public static string FormatAnsi(this eConsoleColor extends, string data)
{
return string.Format("{0}{1}{2}", extends.ToAnsiPrefix(), data, CONSOLE_RESET);
}
public static string ToAnsiPrefix(this eConsoleColor extends)
{
switch (extends)
{
case eConsoleColor.Red:
return CONSOLE_RED;
case eConsoleColor.Green:
return CONSOLE_GREEN;
case eConsoleColor.Yellow:
return CONSOLE_YELLOW;
case eConsoleColor.Blue:
return CONSOLE_BLUE;
case eConsoleColor.Magenta:
return CONSOLE_MAGENTA;
case eConsoleColor.Cyan:
return CONSOLE_CYAN;
case eConsoleColor.White:
return CONSOLE_WHITE;
case eConsoleColor.YellowOnRed:
return CONSOLE_YELLOW_ON_RED_BACKGROUND;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
#if STANDARD
public static ConsoleColor ToForegroundConsoleColor(this eConsoleColor extends)
{
switch (extends)
{
case eConsoleColor.Red:
return ConsoleColor.Red;
case eConsoleColor.Green:
return ConsoleColor.Green;
case eConsoleColor.Yellow:
case eConsoleColor.YellowOnRed:
return ConsoleColor.Yellow;
case eConsoleColor.Blue:
return ConsoleColor.Blue;
case eConsoleColor.Magenta:
return ConsoleColor.Magenta;
case eConsoleColor.Cyan:
return ConsoleColor.Cyan;
case eConsoleColor.White:
return ConsoleColor.White;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
public static ConsoleColor ToBackgroundConsoleColor(this eConsoleColor extends)
{
switch (extends)
{
case eConsoleColor.Red:
case eConsoleColor.Green:
case eConsoleColor.Yellow:
case eConsoleColor.Blue:
case eConsoleColor.Magenta:
case eConsoleColor.Cyan:
case eConsoleColor.White:
return ConsoleColor.Black;
case eConsoleColor.YellowOnRed:
return ConsoleColor.Red;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
#endif
}
}

310
ICD.Common.Utils/Csv/Csv.cs Normal file
View File

@@ -0,0 +1,310 @@
/*
* 2006 - 2018 Ted Spence, http://tedspence.com
* License: http://www.apache.org/licenses/LICENSE-2.0
* Home page: https://github.com/tspence/csharp-csv-reader
*/
using System;
using System.Collections.Generic;
using System.Text;
using ICD.Common.Utils.IO;
#if SIMPLSHARP
using ICD.Common.Utils.Extensions;
#endif
namespace ICD.Common.Utils.Csv
{
/// <summary>
/// Root class that contains static functions for straightforward Csv parsing
/// </summary>
public static class Csv
{
/// <summary>
/// The default Csv field delimiter.
/// </summary>
public const char DEFAULT_CSV_DELIMITER = ',';
/// <summary>
/// The default Csv text qualifier. This is used to encode strings that contain the field delimiter.
/// </summary>
public const char DEFAULT_CSV_QUALIFIER = '"';
/// <summary>
/// The default TSV (tab delimited file) field delimiter.
/// </summary>
public const char DEFAULT_TSV_DELIMITER = '\t';
/// <summary>
/// The default TSV (tabe delimited file) text qualifier. This is used to encode strings that contain the field delimiter.
/// </summary>
public const char DEFAULT_TSV_QUALIFIER = '"';
#region Methods to read Csv data
/// <summary>
/// Parse a Csv stream into IEnumerable&lt;string[]&gt;, while permitting embedded newlines
/// </summary>
/// <param name="inStream">The stream to read</param>
/// <param name="settings">The Csv settings to use for this parsing operation (Default: Csv)</param>
/// <returns>An enumerable object that can be examined to retrieve rows from the stream.</returns>
public static IEnumerable<string[]> ParseStream(IcdStreamReader inStream, CsvReaderSettings settings)
{
string line = "";
int i = -1;
List<string> list = new List<string>();
var work = new StringBuilder();
// Ensure settings are non-null
if (settings == null) {
settings = CsvReaderSettings.CSV;
}
// Begin reading from the stream
while (i < line.Length || !inStream.EndOfStream)
{
// Consume the next character of data
i++;
if (i >= line.Length) {
var newLine = inStream.ReadLine();
line += newLine + settings.LineSeparator;
}
char c = line[i];
// Are we at a line separator? If so, yield our work and begin again
if (String.Equals(line.Substring(i, settings.LineSeparator.Length), settings.LineSeparator)) {
list.Add(work.ToString());
yield return list.ToArray();
list.Clear();
work.Clear();
if (inStream.EndOfStream)
{
break;
}
// Read in next line
if (i + settings.LineSeparator.Length >= line.Length)
{
line = inStream.ReadLine() + settings.LineSeparator;
}
else
{
line = line.Substring(i + settings.LineSeparator.Length);
}
i = -1;
// While starting a field, do we detect a text qualifier?
}
else if ((c == settings.TextQualifier) && (work.Length == 0))
{
// Our next task is to find the end of this qualified-text field
int p2 = -1;
while (p2 < 0) {
// If we don't see an end in sight, read more from the stream
p2 = line.IndexOf(settings.TextQualifier, i + 1);
if (p2 < 0) {
// No text qualifiers yet? Let's read more from the stream and continue
work.Append(line.Substring(i + 1));
i = -1;
var newLine = inStream.ReadLine();
if (String.IsNullOrEmpty(newLine) && inStream.EndOfStream)
{
break;
}
line = newLine + settings.LineSeparator;
continue;
}
// Append the text between the qualifiers
work.Append(line.Substring(i + 1, p2 - i - 1));
i = p2;
// If the user put in a doubled-up qualifier, e.g. `""`, insert a single one and continue
if (((p2 + 1) < line.Length) && (line[p2 + 1] == settings.TextQualifier))
{
work.Append(settings.TextQualifier);
i++;
p2 = -1;
}
}
// Does this start a new field?
}
else if (c == settings.FieldDelimiter)
{
// Is this a null token, and do we permit null tokens?
AddToken(list, work, settings);
// Test for special case: when the user has written a casual comma, space, and text qualifier, skip the space
// Checks if the second parameter of the if statement will pass through successfully
// e.g. `"bob", "mary", "bill"`
if (i + 2 <= line.Length - 1)
{
if (line[i + 1].Equals(' ') && line[i + 2].Equals(settings.TextQualifier))
{
i++;
}
}
}
else
{
work.Append(c);
}
}
}
/// <summary>
/// Parse a single row of data from a Csv line into an array of objects, while permitting embedded newlines
/// DEPRECATED - Please use ParseStream instead.
/// </summary>
/// <param name="inStream">The stream to read</param>
/// <param name="settings">The Csv settings to use for this parsing operation (Default: Csv)</param>
/// <returns>An array containing all fields in the next row of data, or null if it could not be parsed.</returns>
public static string[] ParseMultiLine(IcdStreamReader inStream, CsvReaderSettings settings)
{
StringBuilder sb = new StringBuilder();
string[] array = null;
while (!inStream.EndOfStream)
{
// Read in a line
sb.Append(inStream.ReadLine());
// Does it parse?
string s = sb.ToString();
if (TryParseLine(s, out array, settings))
{
return array;
}
// We didn't succeed on the first try - our text must have an embedded newline in it.
// Let's assume that we were in the middle of parsing a field when we encountered a newline,
// and continue parsing.
sb.Append(settings.LineSeparator);
}
// Fails to parse - return the best array we were able to get
return array;
}
/// <summary>
/// Parse a line from a Csv file and return an array of fields, or null if
/// </summary>
/// <param name="line">One line of text from a Csv file</param>
/// <param name="settings">The Csv settings to use for this parsing operation (Default: Csv)</param>
/// <returns>An array containing all fields in the next row of data, or null if it could not be parsed.</returns>
public static string[] ParseLine(string line, CsvReaderSettings settings)
{
string[] row;
TryParseLine(line, out row, settings);
return row;
}
/// <summary>
/// Try to parse a line of Csv data. Can only return false if an unterminated text qualifier is encountered.
/// </summary>
/// <returns>False if there was an unterminated text qualifier in the <paramref name="line"/></returns>
/// <param name="line">The line of text to parse</param>
/// <param name="settings">The Csv settings to use for this parsing operation (Default: Csv)</param>
/// <param name="row">The array of fields found in the line</param>
public static bool TryParseLine(string line, out string[] row, CsvReaderSettings settings)
{
// Ensure settings are non-null
if (settings == null) settings = CsvReaderSettings.CSV;
// Okay, let's begin parsing
List<string> list = new List<string>();
var work = new StringBuilder();
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
// If we are starting a new field, is this field text qualified?
if ((c == settings.TextQualifier) && (work.Length == 0))
{
while (true)
{
int p2 = line.IndexOf(settings.TextQualifier, i + 1);
// If no closing qualifier is found, this string is broken; return failure.
if (p2 < 0)
{
work.Append(line.Substring(i + 1));
list.Add(work.ToString());
row = list.ToArray();
return false;
}
// Append this qualified string
work.Append(line.Substring(i + 1, p2 - i - 1));
i = p2;
// If this is a double quote, keep going!
if (((p2 + 1) < line.Length) && (line[p2 + 1] == settings.TextQualifier))
{
work.Append(settings.TextQualifier);
i++;
// otherwise, this is a single qualifier, we're done
}
else
{
break;
}
}
// Does this start a new field?
}
else if (c == settings.FieldDelimiter)
{
// Is this a null token, and do we permit null tokens?
AddToken(list, work, settings);
// Test for special case: when the user has written a casual comma, space, and text qualifier, skip the space
// Checks if the second parameter of the if statement will pass through successfully
// e.g. "bob", "mary", "bill"
if (i + 2 <= line.Length - 1)
{
if (line[i + 1].Equals(' ') && line[i + 2].Equals(settings.TextQualifier))
{
i++;
}
}
}
else
{
work.Append(c);
}
}
// We always add the last work as an element. That means `alice,bob,charlie,` will be four items long.
AddToken(list, work, settings);
row = list.ToArray();
return true;
}
/// <summary>
/// Add a single token to the list
/// </summary>
/// <param name="list">List.</param>
/// <param name="work">Work.</param>
/// <param name="settings">Settings.</param>
private static void AddToken(List<string> list, StringBuilder work, CsvReaderSettings settings)
{
var s = work.ToString();
if (settings.AllowNull && String.Equals(s, settings.NullToken, StringComparison.Ordinal))
{
list.Add(null);
}
else
{
list.Add(s);
}
work.Length = 0;
}
#endregion
}
}

View File

@@ -0,0 +1,100 @@
/*
* 2006 - 2018 Ted Spence, http://tedspence.com
* License: http://www.apache.org/licenses/LICENSE-2.0
* Home page: https://github.com/tspence/csharp-csv-reader
*/
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Csv
{
public sealed class CsvReader : IEnumerable<string[]>, IDisposable
{
private readonly CsvReaderSettings m_Settings;
private readonly IcdStreamReader m_Instream;
#region Public Variables
/// <summary>
/// If the first row in the file is a header row, this will be populated
/// </summary>
private string[] m_Headers;
#endregion
#region Constructors
/// <summary>
/// Construct a new Csv reader off a streamed source
/// </summary>
/// <param name="source">The stream source</param>
/// <param name="settings">The Csv settings to use for this reader (Default: Csv)</param>
public CsvReader(IcdStreamReader source, [CanBeNull] CsvReaderSettings settings)
{
m_Instream = source;
m_Settings = settings ?? CsvReaderSettings.CSV;
// Do we need to parse headers?
if (m_Settings.HeaderRowIncluded)
{
m_Headers = NextLine();
}
else
{
m_Headers = m_Settings.AssumedHeaders != null ? m_Settings.AssumedHeaders.ToArray() : null;
}
}
#endregion
#region Iterate through a Csv File
/// <summary>
/// Iterate through all lines in this Csv file
/// </summary>
/// <returns>An array of all data columns in the line</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return Lines().GetEnumerator();
}
/// <summary>
/// Iterate through all lines in this Csv file
/// </summary>
/// <returns>An array of all data columns in the line</returns>
IEnumerator<string[]> IEnumerable<string[]>.GetEnumerator()
{
return Lines().GetEnumerator();
}
/// <summary>
/// Iterate through all lines in this Csv file
/// </summary>
/// <returns>An array of all data columns in the line</returns>
public IEnumerable<string[]> Lines()
{
return Csv.ParseStream(m_Instream, m_Settings);
}
/// <summary>
/// Retrieve the next line from the file.
/// DEPRECATED -
/// </summary>
/// <returns>One line from the file.</returns>
public string[] NextLine()
{
return Csv.ParseMultiLine(m_Instream, m_Settings);
}
#endregion
#region Disposal
/// <summary>
/// Close our resources - specifically, the stream reader
/// </summary>
public void Dispose()
{
m_Instream.Dispose();
}
#endregion
}
}

View File

@@ -0,0 +1,105 @@
/*
* 2006 - 2018 Ted Spence, http://tedspence.com
* License: http://www.apache.org/licenses/LICENSE-2.0
* Home page: https://github.com/tspence/csharp-csv-reader
*/
using System.Collections.Generic;
namespace ICD.Common.Utils.Csv
{
/// <summary>
/// Settings to configure how a Csv file is parsed
/// </summary>
public sealed class CsvReaderSettings
{
/// <summary>
/// Default constructor picks Csv as the default
/// </summary>
public CsvReaderSettings()
{
FieldDelimiter = ',';
TextQualifier = '"';
ForceQualifiers = false;
LineSeparator = IcdEnvironment.NewLine;
NullToken = null;
AllowNull = false;
IgnoreDimensionErrors = true;
AssumedHeaders = null;
HeaderRowIncluded = true;
}
/// <summary>
/// The character used to delimit individual fields in the Csv.
/// </summary>
public char FieldDelimiter { get; set; }
/// <summary>
/// The character used to enclose fields that contain the delimiter character.
/// </summary>
public char TextQualifier { get; set; }
/// <summary>
/// The separator used to indicate the end of a line in the Csv file.
/// </summary>
public string LineSeparator { get; set; }
/// <summary>
/// Set this value to true to enclose all fields in the text qualifier character.
/// </summary>
public bool ForceQualifiers { get; set; }
/// <summary>
/// Set this value to true to allow nulls to be rendered.
/// Csv files by default do not permit null fields. If this field is set to true, all non-null fields
/// will be enclosed by the text qualifier
/// </summary>
public bool AllowNull { get; set; }
/// <summary>
/// If AllowNull is set to true, this token will be used to represent NULL values.
/// </summary>
public string NullToken { get; set; }
/// <summary>
/// The first line of the Csv file will include the names of each field.
/// </summary>
public bool HeaderRowIncluded { get; set; }
/// <summary>
/// If HeaderRowIncluded is false, use these values for the headers
/// </summary>
public List<string> AssumedHeaders { get; set; }
/// <summary>
/// Set this value to true to allow parsing for files where each row has a different number of fields
/// </summary>
public bool IgnoreDimensionErrors { get; set; }
/// <summary>
/// Set this value to true to ignore header errors when deserializing
/// </summary>
public bool IgnoreHeaderErrors { get; set; }
/// <summary>
/// Standard comma-separated value (Csv) file settings
/// </summary>
public static readonly CsvReaderSettings CSV = new CsvReaderSettings();
/// <summary>
/// Standard comma-separated value (Csv) file settings that permit rendering of NULL values
/// </summary>
public static readonly CsvReaderSettings CSV_PERMIT_NULL = new CsvReaderSettings
{
AllowNull = true,
NullToken = "NULL"
};
/// <summary>
/// Standard tab-separated value (TSV) file settings
/// </summary>
public static readonly CsvReaderSettings TSV = new CsvReaderSettings
{
FieldDelimiter = '\t'
};
}
}

View File

@@ -0,0 +1,121 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Csv
{
public sealed class CsvWriter : IDisposable
{
private const string QUOTATION_MARK = "\"";
private const string DOUBLE_QUOTE_MARK = "\"\"";
private readonly IcdTextWriter m_Writer;
private readonly CsvWriterSettings m_Settings;
/// <summary>
/// Are we currently at the beginning of a new line?
/// </summary>
private bool m_NewLine;
#region Properties
private string Separator { get { return m_Settings.InsertSpaceAfterComma ? ", " : ","; } }
private string LineTerminator { get { return m_Settings.NewLineSequence; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public CsvWriter([NotNull] IcdTextWriter writer,
[NotNull] CsvWriterSettings settings)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (settings == null)
throw new ArgumentNullException("settings");
m_NewLine = true;
m_Writer = writer;
m_Settings = settings;
}
#endregion
public void Dispose()
{
m_Writer.Dispose();
}
#region Methods
/// <summary>
/// Adds the row to the builder.
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AppendRow(params string[] row)
{
foreach (string value in row)
AppendValue(value);
AppendNewline();
}
/// <summary>
/// Calls ToString() on the item and adds it to the builder.
/// </summary>
/// <param name="value"></param>
[PublicAPI]
public void AppendValue(object value)
{
AppendValue(string.Format("{0}", value));
}
/// <summary>
/// Adds a value to the builder.
/// </summary>
/// <param name="value"></param>
[PublicAPI]
public void AppendValue(string value)
{
value = value ?? string.Empty;
if (!m_NewLine)
m_Writer.WrappedTextWriter.Write(Separator);
if (m_Settings.AlwaysEscapeEveryValue || value.Contains(","))
{
value = value.Replace(QUOTATION_MARK, DOUBLE_QUOTE_MARK);
// Append the value, surrounded by quotes
m_Writer.WrappedTextWriter.Write(QUOTATION_MARK);
m_Writer.WrappedTextWriter.Write(value);
m_Writer.WrappedTextWriter.Write(QUOTATION_MARK);
}
else
{
m_Writer.WrappedTextWriter.Write(value);
}
m_NewLine = false;
}
/// <summary>
/// Adds a New Line To the Builder
/// </summary>
[PublicAPI]
public void AppendNewline()
{
m_Writer.WrappedTextWriter.Write(LineTerminator);
m_NewLine = true;
}
#endregion
}
}

View File

@@ -0,0 +1,46 @@
using ICD.Common.Properties;
namespace ICD.Common.Utils.Csv
{
public sealed class CsvWriterSettings
{
private bool m_InsertSpaceAfterComma = true;
private bool m_AlwaysEscapeEveryValue = true;
private string m_NewLineSequence = IcdEnvironment.NewLine;
/// <summary>
/// Gets/Sets whether to insert a space between elements, after the comma
/// Defaults to true.
/// </summary>
[PublicAPI]
public bool InsertSpaceAfterComma
{
get { return m_InsertSpaceAfterComma; }
set { m_InsertSpaceAfterComma = value; }
}
/// <summary>
/// Gets/Sets whether to always escape the values.
/// If true, values are recorded surrounded by quotes, regardless of if they contain a comma or not. Quotes are escaped.
/// If false, values are recorded as the value without quotes, unless escaping is required.
/// Defaults to true.
/// </summary>
[PublicAPI]
public bool AlwaysEscapeEveryValue
{
get { return m_AlwaysEscapeEveryValue; }
set { m_AlwaysEscapeEveryValue = value; }
}
/// <summary>
/// Gets/Sets the newline character or characters to deliniate records.
/// Defaults to System.NewLine.
/// </summary>
[PublicAPI]
public string NewLineSequence
{
get { return m_NewLineSequence; }
set { m_NewLineSequence = value; }
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,48 @@
using System;
using System.Globalization;
namespace ICD.Common.Utils
{
public static class DateTimeUtils
{
/// <summary>
/// Converts the hour in 24 hour format to 12 hour format (1 through 12).
/// </summary>
/// <param name="hour"></param>
/// <returns></returns>
public static int To12Hour(int hour)
{
return MathUtils.Modulus(hour + 11, 12) + 1;
}
/// <summary>
/// Creates a DateTime from the given number of milliseconds since the epoch (1970-01-01T00:00:00Z)
/// </summary>
/// <param name="milliseconds">milliseconds since the epoch</param>
/// <returns></returns>
public static DateTime FromEpochMilliseconds(long milliseconds)
{
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(milliseconds);
}
/// <summary>
/// Creates a DateTime from the given number of seconds since the epoch (1970-01-01T00:00:00Z)
/// </summary>
/// <param name="seconds">seconds since the epoch</param>
/// <returns></returns>
public static DateTime FromEpochSeconds(long seconds)
{
return FromEpochMilliseconds(seconds * 1000);
}
/// <summary>
/// Returns a DateTime for the given ISO-8601 string.
/// </summary>
/// <param name="iso"></param>
/// <returns></returns>
public static DateTime FromIso8601(string iso)
{
return DateTime.Parse(iso, null, DateTimeStyles.RoundtripKind);
}
}
}

View File

@@ -0,0 +1,91 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Net.Mail;
#endif
using ICD.Common.Properties;
namespace ICD.Common.Utils.Email
{
public sealed class EmailClient
{
private readonly EmailStringCollection m_To;
private readonly EmailStringCollection m_Cc;
private readonly EmailStringCollection m_Bcc;
#region Properties
public string Host { get; set; }
public ushort Port { get; set; }
public bool Secure { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string From { get; set; }
public EmailStringCollection To { get { return m_To; } }
public EmailStringCollection Cc { get { return m_Cc; } }
public EmailStringCollection Bcc { get { return m_Bcc; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
public EmailClient()
{
m_To = new EmailStringCollection();
m_Cc = new EmailStringCollection();
m_Bcc = new EmailStringCollection();
}
#region Methods
/// <summary>
/// Sends the email.
/// </summary>
/// <param name="subject"></param>
/// <param name="message"></param>
/// <returns>Error codes.</returns>
[PublicAPI]
public eMailErrorCode Send(string subject, string message)
{
#if SIMPLSHARP
var response = CrestronMailFunctions.SendMail(Host, Port, Secure, Username, Password, From, m_To.ToString(), "",
m_Cc.ToString(), m_Bcc.ToString(), subject, message,
CrestronMailFunctions.eMailPriority.Normal, 0, "");
return MailErrorCodeUtils.FromSimplMailCode(response);
#else
try
{
MailMessage mailMessage = new MailMessage
{
From = new MailAddress(From),
To = {m_To.ToString()},
CC = {m_Cc.ToString()},
Bcc = {m_Bcc.ToString()},
Subject = subject,
Body = message
};
SmtpClient client = new SmtpClient
{
Port = Port,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Host = Host
};
client.Send(mailMessage);
}
catch (SmtpException ex)
{
return MailErrorCodeUtils.FromNetStandardMailCode(ex.StatusCode);
}
return eMailErrorCode.Ok;
#endif
}
#endregion
}
}

View File

@@ -0,0 +1,134 @@
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Email
{
/// <summary>
/// Stores addresses/paths and provides them in a ; delimited string.
/// </summary>
public sealed class EmailStringCollection : ICollection<string>
{
private const char DELIMITER = ';';
private readonly List<string> m_Items;
/// <summary>
/// Gets the number of items.
/// </summary>
public int Count { get { return m_Items.Count; } }
public bool IsReadOnly { get { return false; } }
/// <summary>
/// Constructor.
/// </summary>
public EmailStringCollection()
{
m_Items = new List<string>();
}
#region Methods
/// <summary>
/// Adds the item to the collection.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public bool Add(string item)
{
if (m_Items.Contains(item))
return false;
m_Items.Add(item);
return true;
}
/// <summary>
/// Removes the item from the collection.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public bool Remove(string item)
{
if (!m_Items.Contains(item))
return false;
m_Items.Remove(item);
return true;
}
/// <summary>
/// Clears all items.
/// </summary>
public void Clear()
{
m_Items.Clear();
}
/// <summary>
/// Returns true if the collection contains the item.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public bool Contains(string item)
{
return m_Items.Contains(item);
}
/// <summary>
/// Gets the items as a ; delimited string.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Join(DELIMITER.ToString(), m_Items.ToArray());
}
#endregion
#region Collection
void ICollection<string>.Add(string item)
{
Add(item);
}
/// <summary>
/// Adds multiple email addresses, seperated by ;
/// </summary>
/// <param name="items"></param>
public void AddMany(string items)
{
items = items.RemoveWhitespace();
string [] splitItems = items.Split(DELIMITER);
foreach (string item in splitItems)
Add(item);
}
public void CopyTo(string[] array, int arrayIndex)
{
m_Items.CopyTo(array, arrayIndex);
}
#endregion
#region Enumerable
public IEnumerator<string> GetEnumerator()
{
return m_Items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}

View File

@@ -0,0 +1,14 @@
using System.Text.RegularExpressions;
namespace ICD.Common.Utils.Email
{
public static class EmailValidation
{
private const string EMAIL_REGEX = @"(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])";
public static bool IsValidEmailAddress(string emailAddress)
{
return emailAddress != null && Regex.IsMatch(emailAddress, EMAIL_REGEX);
}
}
}

View File

@@ -0,0 +1,231 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Net.Mail;
#endif
namespace ICD.Common.Utils.Email
{
public enum eMailErrorCode
{
//
// Summary:
// The transaction could not occur. You receive this error when the specified SMTP
// host cannot be found.
GeneralFailure = -1,
//
// Summary:
// A system status or system Help reply.
SystemStatus = 211,
//
// Summary:
// A Help message was returned by the service.
HelpMessage = 214,
//
// Summary:
// The SMTP service is ready.
ServiceReady = 220,
//
// Summary:
// The SMTP service is closing the transmission channel.
ServiceClosingTransmissionChannel = 221,
//
// Summary:
// The email was successfully sent to the SMTP service.
Ok = 250,
//
// Summary:
// The user mailbox is not located on the receiving server; the server forwards
// the e-mail.
UserNotLocalWillForward = 251,
//
// Summary:
// The specified user is not local, but the receiving SMTP service accepted the
// message and attempted to deliver it. This status code is defined in RFC 1123,
// which is available at http://www.ietf.org/.
CannotVerifyUserWillAttemptDelivery = 252,
//
// Summary:
// The SMTP service is ready to receive the e-mail content.
StartMailInput = 354,
//
// Summary:
// The SMTP service is not available; the server is closing the transmission channel.
ServiceNotAvailable = 421,
//
// Summary:
// The destination mailbox is in use.
MailboxBusy = 450,
//
// Summary:
// The SMTP service cannot complete the request. This error can occur if the client's
// IP address cannot be resolved (that is, a reverse lookup failed). You can also
// receive this error if the client domain has been identified as an open relay
// or source for unsolicited e-mail (spam). For details, see RFC 2505, which is
// available at http://www.ietf.org/.
LocalErrorInProcessing = 451,
//
// Summary:
// The SMTP service does not have sufficient storage to complete the request.
InsufficientStorage = 452,
//
// Summary:
// The client was not authenticated or is not allowed to send mail using the specified
// SMTP host.
ClientNotPermitted = 454,
//
// Summary:
// The SMTP service does not recognize the specified command.
CommandUnrecognized = 500,
//
// Summary:
// The syntax used to specify a command or parameter is incorrect.
SyntaxError = 501,
//
// Summary:
// The SMTP service does not implement the specified command.
CommandNotImplemented = 502,
//
// Summary:
// The commands were sent in the incorrect sequence.
BadCommandSequence = 503,
//
// Summary:
// The SMTP service does not implement the specified command parameter.
CommandParameterNotImplemented = 504,
//
// Summary:
// The SMTP server is configured to accept only TLS connections, and the SMTP client
// is attempting to connect by using a non-TLS connection. The solution is for the
// user to set EnableSsl=true on the SMTP Client.
MustIssueStartTlsFirst = 530,
//
// Summary:
// The destination mailbox was not found or could not be accessed.
MailboxUnavailable = 550,
//
// Summary:
// The user mailbox is not located on the receiving server. You should resend using
// the supplied address information.
UserNotLocalTryAlternatePath = 551,
//
// Summary:
// The message is too large to be stored in the destination mailbox.
ExceededStorageAllocation = 552,
//
// Summary:
// The syntax used to specify the destination mailbox is incorrect.
MailboxNameNotAllowed = 553,
//
// Summary:
// The transaction failed.
TransactionFailed = 554
}
public static class MailErrorCodeUtils
{
#if !SIMPLSHARP
public static eMailErrorCode FromNetStandardMailCode(SmtpStatusCode code)
{
switch (code)
{
case SmtpStatusCode.BadCommandSequence:
return eMailErrorCode.BadCommandSequence;
case SmtpStatusCode.CannotVerifyUserWillAttemptDelivery:
return eMailErrorCode.CannotVerifyUserWillAttemptDelivery;
case SmtpStatusCode.ClientNotPermitted:
return eMailErrorCode.ClientNotPermitted;
case SmtpStatusCode.CommandNotImplemented:
return eMailErrorCode.CommandNotImplemented;
case SmtpStatusCode.CommandParameterNotImplemented:
return eMailErrorCode.CommandParameterNotImplemented;
case SmtpStatusCode.CommandUnrecognized:
return eMailErrorCode.CommandUnrecognized;
case SmtpStatusCode.ExceededStorageAllocation:
return eMailErrorCode.ExceededStorageAllocation;
case SmtpStatusCode.GeneralFailure:
return eMailErrorCode.GeneralFailure;
case SmtpStatusCode.HelpMessage:
return eMailErrorCode.HelpMessage;
case SmtpStatusCode.InsufficientStorage:
return eMailErrorCode.InsufficientStorage;
case SmtpStatusCode.LocalErrorInProcessing:
return eMailErrorCode.LocalErrorInProcessing;
case SmtpStatusCode.MailboxBusy:
return eMailErrorCode.MailboxBusy;
case SmtpStatusCode.MailboxNameNotAllowed:
return eMailErrorCode.MailboxNameNotAllowed;
case SmtpStatusCode.MailboxUnavailable:
return eMailErrorCode.MailboxUnavailable;
case SmtpStatusCode.MustIssueStartTlsFirst:
return eMailErrorCode.MustIssueStartTlsFirst;
case SmtpStatusCode.Ok:
return eMailErrorCode.Ok;
case SmtpStatusCode.ServiceClosingTransmissionChannel:
return eMailErrorCode.ServiceClosingTransmissionChannel;
case SmtpStatusCode.ServiceNotAvailable:
return eMailErrorCode.ServiceNotAvailable;
case SmtpStatusCode.ServiceReady:
return eMailErrorCode.ServiceReady;
case SmtpStatusCode.StartMailInput:
return eMailErrorCode.StartMailInput;
case SmtpStatusCode.SyntaxError:
return eMailErrorCode.SyntaxError;
case SmtpStatusCode.SystemStatus:
return eMailErrorCode.SystemStatus;
case SmtpStatusCode.TransactionFailed:
return eMailErrorCode.TransactionFailed;
case SmtpStatusCode.UserNotLocalTryAlternatePath:
return eMailErrorCode.UserNotLocalTryAlternatePath;
case SmtpStatusCode.UserNotLocalWillForward:
return eMailErrorCode.UserNotLocalWillForward;
default:
throw new ArgumentOutOfRangeException(nameof(code), code, null);
}
}
#else
public static eMailErrorCode FromSimplMailCode(CrestronMailFunctions.SendMailErrorCodes code)
{
switch (code)
{
case CrestronMailFunctions.SendMailErrorCodes.SMTP_OK:
return eMailErrorCode.Ok;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_FATAL:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_ILLEGAL_CMD:
return eMailErrorCode.CommandUnrecognized;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_CONNECT:
return eMailErrorCode.ServiceNotAvailable;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_SEND:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_RECV:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_NU_CONNECT:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_NU_BUFFERS:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_AUTHENTICATION:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_AUTH_LOGIN_UNSUPPORTED:
return eMailErrorCode.MustIssueStartTlsFirst;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_INV_PARAM:
return eMailErrorCode.SyntaxError;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ETHER_NOT_ENABLED:
return eMailErrorCode.ServiceNotAvailable;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_NO_SERVER_ADDRESS:
return eMailErrorCode.ServiceNotAvailable;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_SEND_FAILED:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_GENERAL_SENDMAIL_ERROR:
return eMailErrorCode.GeneralFailure;
case CrestronMailFunctions.SendMailErrorCodes.SMTP_INVALID_FIRMWARE:
return eMailErrorCode.GeneralFailure;
default:
throw new ArgumentOutOfRangeException("code");
}
}
#endif
}
}

View File

@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
#if SIMPLSHARP
using System.Globalization;
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
@@ -15,7 +15,10 @@ namespace ICD.Common.Utils
public static class EnumUtils
{
private static readonly Dictionary<Type, object[]> s_EnumValuesCache;
private static readonly SafeCriticalSection s_EnumValuesCacheSection;
private static readonly Dictionary<Type, Dictionary<object, object[]>> s_EnumFlagsCache;
private static readonly SafeCriticalSection s_EnumFlagsCacheSection;
/// <summary>
/// Static constructor.
@@ -23,24 +26,12 @@ namespace ICD.Common.Utils
static EnumUtils()
{
s_EnumValuesCache = new Dictionary<Type, object[]>();
s_EnumValuesCacheSection = new SafeCriticalSection();
s_EnumFlagsCache = new Dictionary<Type, Dictionary<object, object[]>>();
s_EnumFlagsCacheSection = new SafeCriticalSection();
}
/// <summary>
/// Returns true if the given type is an enum.
/// </summary>
/// <returns></returns>
public static bool IsEnumType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return type.IsAssignableTo(typeof(Enum)) || type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsEnum;
}
#region Validation
/// <summary>
/// Returns true if the given type is an enum.
@@ -51,15 +42,58 @@ namespace ICD.Common.Utils
return IsEnumType(typeof(T));
}
/// <summary>
/// Returns true if the given type is an enum.
/// </summary>
/// <returns></returns>
public static bool IsEnumType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsEnum || type.IsAssignableTo(typeof(Enum));
}
/// <summary>
/// Returns true if the given value is an enum.
/// </summary>
/// <returns></returns>
public static bool IsEnum(object value)
public static bool IsEnum<T>(T value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
return value != null && IsEnumType(value.GetType());
}
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool IsFlagsEnum<T>()
{
return IsFlagsEnum(typeof(T));
}
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// </summary>
/// <returns></returns>
public static bool IsFlagsEnum(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsDefined(typeof(FlagsAttribute), false);
}
/// <summary>
/// Returns true if the given value is defined as part of the given enum type.
/// </summary>
@@ -67,42 +101,56 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static bool IsDefined<T>(T value)
where T : struct, IConvertible
{
if (!IsEnumType(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
if (!IsFlagsEnum<T>())
return GetValues<T>().Any(v => v.Equals(value));
int valueInt = (int)GetUnderlyingValue(value);
// Check if all of the flag values are defined
foreach (T flag in GetFlags(value))
{
int flagInt = (int)GetUnderlyingValue(flag);
valueInt = valueInt - flagInt;
}
return valueInt == 0;
T all = GetFlagsAllValue<T>();
return HasFlags(all, value);
}
/// <summary>
/// Returns true if the given value is defined as part of the given enum type.
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool IsDefined(Type type, int value)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnumType(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
int all = GetFlagsAllValue(type);
return HasFlags(all, value);
}
#endregion
#region Values
/// <summary>
/// Gets the underlying value of the enum.
/// Gets the names of the values in the enumeration.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static object GetUnderlyingValue<T>(T value)
public static IEnumerable<string> GetNames<T>()
where T : struct, IConvertible
{
if (!IsEnumType(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return GetNames(typeof(T));
}
#if SIMPLSHARP
return Convert.ChangeType(value, ToEnum(value).GetTypeCode(), CultureInfo.InvariantCulture);
#else
return Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
#endif
/// <summary>
/// Gets the names of the values in the enumeration.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<string> GetNames([NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return GetValues(type).Select(v => v.ToString());
}
/// <summary>
@@ -111,6 +159,7 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValues<T>()
where T : struct, IConvertible
{
return GetValues(typeof(T)).Cast<T>();
}
@@ -118,7 +167,6 @@ namespace ICD.Common.Utils
/// <summary>
/// Gets the values from an enumeration.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValues(Type type)
{
@@ -126,16 +174,36 @@ namespace ICD.Common.Utils
throw new ArgumentNullException("type");
// Reflection is slow and this method is called a lot, so we cache the results.
if (!s_EnumValuesCache.ContainsKey(type))
s_EnumValuesCache[type] = GetValuesUncached(type).ToArray();
return s_EnumValuesCacheSection.Execute(() => s_EnumValuesCache.GetOrAddNew(type, () => GetValuesUncached(type).ToArray()));
}
return s_EnumValuesCache[type];
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValuesExceptNone<T>()
where T : struct, IConvertible
{
return GetValuesExceptNone(typeof(T)).Cast<T>();
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValuesExceptNone([NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return GetValues(type).Where(v => (int)v != 0);
}
/// <summary>
/// Gets the values from an enumeration without performing any caching. This is slow because of reflection.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static IEnumerable<object> GetValuesUncached(Type type)
{
@@ -149,52 +217,10 @@ namespace ICD.Common.Utils
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
.GetTypeInfo()
#endif
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Select(x => x.GetValue(null));
}
/// <summary>
/// Gets the 0 value for the given enum type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetNoneValue<T>()
{
if (!IsEnumType(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return (T)(object)0;
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValuesExceptNone<T>()
{
if (!IsEnumType(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return GetValuesExceptNone(typeof(T)).Cast<T>();
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValuesExceptNone(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnumType(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return GetValues(type).Where(v => (int)v != 0);
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Select(x => x.GetValue(null));
}
#endregion
@@ -202,35 +228,55 @@ namespace ICD.Common.Utils
#region Flags
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// Excludes b from a.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static bool IsFlagsEnum<T>()
public static T ExcludeFlags<T>(T a, T b)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
int aInt = (int)(object)a;
int bInt = (int)(object)b;
return IsFlagsEnum(typeof(T));
return (T)(object)ExcludeFlags(aInt, bInt);
}
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// Excludes b from a.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static bool IsFlagsEnum(Type type)
public static int ExcludeFlags(int a, int b)
{
if (type == null)
throw new ArgumentNullException("type");
return a & ~b;
}
if (!IsEnumType(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
/// <summary>
/// Includes a and b.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static T IncludeFlags<T>(T a, T b)
where T : struct, IConvertible
{
int aInt = (int)(object)a;
int bInt = (int)(object)b;
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsDefined(typeof(FlagsAttribute), false);
return (T)(object)IncludeFlags(aInt, bInt);
}
/// <summary>
/// Includes a and b.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static int IncludeFlags(int a, int b)
{
return a | b;
}
/// <summary>
@@ -240,15 +286,34 @@ namespace ICD.Common.Utils
/// <param name="values"></param>
/// <returns></returns>
public static T GetFlagsIntersection<T>(params T[] values)
where T : struct, IConvertible
{
if (values == null)
throw new ArgumentNullException("values");
if (values.Length == 0)
return GetNoneValue<T>();
return default(T);
int output = (int)(object)values.First();
foreach (T item in values.Skip(1))
output &= (int)(object)item;
int output = 0;
bool first = true;
return (T)Enum.ToObject(typeof(T), output);
foreach (T value in values)
{
if (first)
{
output = (int)(object)value;
first = false;
}
else
{
output &= (int)(object)value;
}
if (output == 0)
return default(T);
}
return (T)(object)output;
}
/// <summary>
@@ -259,11 +324,12 @@ namespace ICD.Common.Utils
/// <param name="b"></param>
/// <returns></returns>
public static T GetFlagsIntersection<T>(T a, T b)
where T : struct, IConvertible
{
int aInt = (int)(object)a;
int bInt = (int)(object)b;
return (T)Enum.ToObject(typeof(T), aInt & bInt);
return (T)(object)(aInt & bInt);
}
/// <summary>
@@ -273,20 +339,24 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
return GetFlags(typeof(T), value).Cast<T>();
}
Type type = typeof(T);
if (!s_EnumFlagsCache.ContainsKey(type))
s_EnumFlagsCache.Add(type, new Dictionary<object, object[]>());
if (!s_EnumFlagsCache[type].ContainsKey(value))
s_EnumFlagsCache[type][value] = GetValues<T>().Where(e => HasFlag(value, e)).Cast<object>().ToArray();
return s_EnumFlagsCache[type][value].Cast<T>();
/// <summary>
/// Gets all of the set flags on the given enum.
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<object> GetFlags(Type type, object value)
{
return s_EnumFlagsCacheSection.Execute(() => s_EnumFlagsCache
.GetOrAddNew(type, () => new Dictionary<object, object[]>())
.GetOrAddNew(value, () => GetValues(type)
.Where(f => !HasMultipleFlags((int)f) && HasFlag(value, f))
.ToArray()));
}
/// <summary>
@@ -295,12 +365,9 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetFlagsExceptNone<T>()
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
T allValue = GetFlagsAllValue<T>();
return GetFlagsExceptNone(allValue);
return GetFlagsExceptNone(typeof(T)).Cast<T>();
}
/// <summary>
@@ -310,13 +377,37 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlagsExceptNone<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
return GetFlagsExceptNone(typeof(T), value).Cast<T>();
}
T none = GetNoneValue<T>();
return GetFlags(value).Except(none);
/// <summary>
/// Gets all of the set flags on the given enum type except 0.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetFlagsExceptNone([NotNull] Type type)
{
if (type == null)
throw new ArgumentNullException("type");
object allValue = GetFlagsAllValue(type);
return GetFlagsExceptNone(type, allValue);
}
/// <summary>
/// Gets all of the set flags on the given enum except 0.
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<object> GetFlagsExceptNone([NotNull] Type type, object value)
{
if (type == null)
throw new ArgumentNullException("type");
return GetFlags(type, value).Where(f => (int)f != 0);
}
/// <summary>
@@ -329,12 +420,9 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetAllFlagCombinationsExceptNone<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
int maxEnumValue = (GetValues<T>().Max(v => (int)(object)v) * 2) -1 ;
int maxEnumValue = (GetValues<T>().Max(v => (int)(object)v) * 2) -1;
return Enumerable.Range(1, maxEnumValue).Select(i => (T)(object)i ).Where(v => HasFlags(value, v));
}
@@ -344,14 +432,38 @@ namespace ICD.Common.Utils
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetFlagsAllValue<T>()
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
int output = GetValues<T>().Aggregate(0, (current, value) => current | (int)(object)value);
return (T)Enum.ToObject(typeof(T), output);
}
/// <summary>
/// Gets an enum value of the given type with every flag set.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static int GetFlagsAllValue(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
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>
/// Returns true if the enum contains the given flag.
/// </summary>
@@ -360,16 +472,31 @@ namespace ICD.Common.Utils
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag<T>(T value, T flag)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
return HasFlags(value, flag);
}
if (!IsEnum(flag))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", flag == null ? "NULL" : flag.GetType().Name), "flag");
/// <summary>
/// Returns true if the enum contains the given flag.
/// </summary>
/// <param name="value"></param>
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag(object value, object flag)
{
return HasFlag((int)value, (int)flag);
}
return ToEnum(value).HasFlag(ToEnum(flag));
/// <summary>
/// Returns true if the enum contains the given flag.
/// </summary>
/// <param name="value"></param>
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag(int value, int flag)
{
return HasFlags(value, flag);
}
/// <summary>
@@ -380,16 +507,23 @@ namespace ICD.Common.Utils
/// <param name="flags"></param>
/// <returns></returns>
public static bool HasFlags<T>(T value, T flags)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
int a = (int)(object)value;
int b = (int)(object)flags;
if (!IsEnum(flags))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", flags == null ? "NULL" : flags.GetType().Name), "flags");
return HasFlags(a, b);
}
return ToEnum(value).HasFlags(ToEnum(flags));
/// <summary>
/// Returns true if the enum contains the given flag.
/// </summary>
/// <param name="value"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static bool HasFlags(int value, int flags)
{
return (value & flags) == flags;
}
/// <summary>
@@ -399,12 +533,11 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static bool HasSingleFlag<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
int numeric = (int)(object)value;
return (int)(object)value != (int)(object)GetNoneValue<T>() && !HasMultipleFlags(value);
return HasAnyFlags(numeric) && !HasMultipleFlags(numeric);
}
/// <summary>
@@ -413,11 +546,8 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <returns></returns>
public static bool HasMultipleFlags<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
return HasMultipleFlags((int)(object)value);
}
@@ -429,7 +559,7 @@ namespace ICD.Common.Utils
[PublicAPI]
public static bool HasMultipleFlags(int value)
{
return ((value & (value - 1)) != 0);
return (value & (value - 1)) != 0;
}
/// <summary>
@@ -439,8 +569,20 @@ namespace ICD.Common.Utils
/// <returns></returns>
[PublicAPI]
public static bool HasAnyFlags<T>(T value)
where T : struct, IConvertible
{
return GetFlagsExceptNone(value).Any();
return HasAnyFlags((int)(object)value);
}
/// <summary>
/// Returns true if the enum has any flags set.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static bool HasAnyFlags(int value)
{
return value > 0;
}
/// <summary>
@@ -451,6 +593,7 @@ namespace ICD.Common.Utils
/// <returns></returns>
[PublicAPI]
public static bool HasAnyFlags<T>(T value, T other)
where T : struct, IConvertible
{
T intersection = GetFlagsIntersection(value, other);
return HasAnyFlags(intersection);
@@ -468,10 +611,8 @@ namespace ICD.Common.Utils
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static T Parse<T>(string data, bool ignoreCase)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
T output;
if (TryParse(data, ignoreCase, out output))
return output;
@@ -480,6 +621,26 @@ namespace ICD.Common.Utils
throw new FormatException(message);
}
/// <summary>
/// Shorthand for parsing string to enum.
/// </summary>
/// <param name="type"></param>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static int Parse(Type type, string data, bool ignoreCase)
{
if (type == null)
throw new ArgumentNullException("type");
int output;
if (TryParse(type, data, ignoreCase, out output))
return output;
string message = string.Format("Failed to parse {0} as {1}", StringUtils.ToRepresentation(data), type.Name);
throw new FormatException(message);
}
/// <summary>
/// Shorthand for parsing a string to enum. Returns false if the parse failed.
/// </summary>
@@ -489,10 +650,8 @@ namespace ICD.Common.Utils
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParse<T>(string data, bool ignoreCase, out T result)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
result = default(T);
try
@@ -506,6 +665,32 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Shorthand for parsing a string to enum. Returns false if the parse failed.
/// </summary>
/// <param name="type"></param>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParse(Type type, string data, bool ignoreCase, out int result)
{
if (type == null)
throw new ArgumentNullException("type");
result = 0;
try
{
result = (int)Enum.Parse(type, data, ignoreCase);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Shorthand for parsing string to enum.
/// Will fail if the resulting value is not defined as part of the enum.
@@ -515,10 +700,8 @@ namespace ICD.Common.Utils
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static T ParseStrict<T>(string data, bool ignoreCase)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
T output;
try
@@ -537,6 +720,37 @@ namespace ICD.Common.Utils
return output;
}
/// <summary>
/// Shorthand for parsing string to enum.
/// Will fail if the resulting value is not defined as part of the enum.
/// </summary>
/// <param name="type"></param>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static int ParseStrict(Type type, string data, bool ignoreCase)
{
if (type == null)
throw new ArgumentNullException("type");
int output;
try
{
output = Parse(type, data, ignoreCase);
}
catch (Exception e)
{
throw new FormatException(
string.Format("Failed to parse {0} as {1}", StringUtils.ToRepresentation(data), type.Name), e);
}
if (!IsDefined(type, output))
throw new ArgumentOutOfRangeException(string.Format("{0} is not a valid {1}", output, type.Name));
return output;
}
/// <summary>
/// Shorthand for parsing a string to enum. Returns false if the parse failed.
/// Will fail if the resulting value is not defined as part of the enum.
@@ -547,10 +761,8 @@ namespace ICD.Common.Utils
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParseStrict<T>(string data, bool ignoreCase, out T result)
where T : struct, IConvertible
{
if (!IsEnumType<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
result = default(T);
try
@@ -564,19 +776,38 @@ namespace ICD.Common.Utils
}
}
#endregion
#region Formatting
/// <summary>
/// Converts the given enum value to an Enum.
/// Builds a comma delimited string of the defined enum flags, followed by the numeric remainder.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static Enum ToEnum<T>(T value)
public static string ToStringUndefined<T>(T value)
where T : struct, IConvertible
{
if (!IsEnum(value))
// ReSharper disable once CompareNonConstrainedGenericWithNull
throw new ArgumentException(string.Format("{0} is not an enum", value == null ? "NULL" : value.GetType().Name), "value");
if (!IsFlagsEnum<T>())
return value.ToString();
return (Enum)(object)value;
long remainder = (int)(object)value;
StringBuilder output = new StringBuilder();
string format = "{0}";
foreach (T flag in GetFlagsExceptNone(value))
{
output.AppendFormat(format, flag);
remainder -= (int)(object)flag;
format = ", {0}";
}
if (remainder != 0)
output.AppendFormat(", {0}", remainder);
return output.ToString();
}
#endregion

View File

@@ -1,4 +1,8 @@
namespace ICD.Common.Utils.EventArguments
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
public sealed class BoolEventArgs : GenericEventArgs<bool>
{
@@ -6,8 +10,32 @@
/// Constructor.
/// </summary>
/// <param name="data"></param>
public BoolEventArgs(bool data) : base(data)
public BoolEventArgs(bool data)
: base(data)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eventArgs"></param>
public BoolEventArgs(BoolEventArgs eventArgs)
: this(eventArgs.Data)
{
}
}
public static class BoolEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<BoolEventArgs> extends, object sender, bool data)
{
extends.Raise(sender, new BoolEventArgs(data));
}
}
}

View File

@@ -1,4 +1,6 @@
using ICD.Common.Properties;
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
@@ -9,4 +11,18 @@ namespace ICD.Common.Utils.EventArguments
{
}
}
public static class CharEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<CharEventArgs> extends, object sender, char data)
{
extends.Raise(sender, new CharEventArgs(data));
}
}
}

View File

@@ -1,4 +1,6 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
@@ -13,4 +15,18 @@ namespace ICD.Common.Utils.EventArguments
{
}
}
public static class DateTimeEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<DateTimeEventArgs> extends, object sender, DateTime data)
{
extends.Raise(sender, new DateTimeEventArgs(data));
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
public sealed class DateTimeNullableEventArgs : GenericEventArgs<DateTime?>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public DateTimeNullableEventArgs(DateTime? data) : base(data)
{
}
}
public static class DateTimeNullableEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<DateTimeNullableEventArgs> extends, object sender, DateTime? data)
{
extends.Raise(sender, new DateTimeNullableEventArgs(data));
}
}
}

View File

@@ -1,4 +1,8 @@
namespace ICD.Common.Utils.EventArguments
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
public sealed class FloatEventArgs : GenericEventArgs<float>
{
@@ -11,4 +15,18 @@
{
}
}
public static class FloatEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<FloatEventArgs> extends, object sender, float data)
{
extends.Raise(sender, new FloatEventArgs(data));
}
}
}

View File

@@ -1,13 +1,22 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
public class GenericEventArgs<T> : EventArgs, IGenericEventArgs<T>
{
private readonly T m_Data;
/// <summary>
/// Gets the wrapped data associated with the event.
/// </summary>
public T Data { get; private set; }
object IGenericEventArgs.Data { get { return Data; } }
/// <summary>
/// Gets the wrapped data associated with the event.
/// </summary>
public T Data { get { return m_Data; } }
/// <summary>
/// Constructor.
@@ -15,7 +24,21 @@ namespace ICD.Common.Utils.EventArguments
/// <param name="data"></param>
public GenericEventArgs(T data)
{
Data = data;
m_Data = data;
}
}
public static class GenericEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise<T>([CanBeNull]this EventHandler<GenericEventArgs<T>> extends, object sender, T data)
{
extends.Raise(sender, new GenericEventArgs<T>(data));
}
}
}

View File

@@ -1,10 +1,18 @@
namespace ICD.Common.Utils.EventArguments
{
public interface IGenericEventArgs<T>
public interface IGenericEventArgs
{
/// <summary>
/// Gets the wrapped data associated with the event.
/// </summary>
T Data { get; }
object Data { get; }
}
public interface IGenericEventArgs<T> : IGenericEventArgs
{
/// <summary>
/// Gets the wrapped data associated with the event.
/// </summary>
new T Data { get; }
}
}

View File

@@ -1,4 +1,8 @@
namespace ICD.Common.Utils.EventArguments
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
public sealed class IntEventArgs : GenericEventArgs<int>
{
@@ -10,4 +14,18 @@
{
}
}
public static class IntEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<IntEventArgs> extends, object sender, int data)
{
extends.Raise(sender, new IntEventArgs(data));
}
}
}

View File

@@ -1,4 +1,8 @@
namespace ICD.Common.Utils.EventArguments
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
public sealed class StringEventArgs : GenericEventArgs<string>
{
@@ -9,5 +13,28 @@
public StringEventArgs(string data) : base(data)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eventArgs"></param>
public StringEventArgs(StringEventArgs eventArgs)
: base(eventArgs.Data)
{
}
}
public static class StringEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<StringEventArgs> extends, object sender, string data)
{
extends.Raise(sender, new StringEventArgs(data));
}
}
}

View File

@@ -1,4 +1,6 @@
using ICD.Common.Properties;
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
@@ -13,4 +15,18 @@ namespace ICD.Common.Utils.EventArguments
{
}
}
public static class UShortEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="data"></param>
public static void Raise([CanBeNull]this EventHandler<UShortEventArgs> extends, object sender, ushort data)
{
extends.Raise(sender, new UShortEventArgs(data));
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.EventArguments
{
@@ -26,4 +27,19 @@ namespace ICD.Common.Utils.EventArguments
#endregion
}
public static class XmlRecursionEventArgsExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="outer"></param>
/// <param name="path"></param>
public static void Raise([CanBeNull]this EventHandler<XmlRecursionEventArgs> extends, object sender, string outer, string[] path)
{
extends.Raise(sender, new XmlRecursionEventArgs(outer, path));
}
}
}

View File

@@ -18,7 +18,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[CanBeNull]
public static string GetPath(this Assembly extends)
public static string GetPath([NotNull]this Assembly extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -29,17 +29,16 @@ namespace ICD.Common.Utils.Extensions
#endif
.CodeBase;
if (path == null)
{
#if STANDARD
#if !SIMPLSHARP
if (string.IsNullOrEmpty(path))
path = extends.Location;
#endif
}
else
const string prefix = @"file:/";
if (path != null && path.StartsWith(prefix))
{
const string prefix = @"file:///";
if (path.StartsWith(prefix))
path = path.Substring(prefix.Length);
Uri uri = new Uri(path);
path = uri.LocalPath;
}
return IcdFile.Exists(path) ? path : null;
@@ -51,7 +50,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static DateTime GetCreationTime(this Assembly extends)
public static DateTime GetCreationTime([NotNull]this Assembly extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -66,7 +65,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string GetInformationalVersion(this Assembly extends)
public static string GetInformationalVersion([NotNull]this Assembly extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -85,7 +84,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="version"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryGetInformationalVersion(this Assembly extends, out string version)
public static bool TryGetInformationalVersion([NotNull]this Assembly extends, out string version)
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class CollectionExtensions
{
/// <summary>
/// Clears the collection and adds the given range of items.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="range"></param>
public static void SetRange<T>([NotNull] this ICollection<T> extends, [NotNull] IEnumerable<T> range)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (range == null)
throw new ArgumentNullException("range");
extends.Clear();
extends.AddRange(range);
}
/// <summary>
/// Adds the given range of items to the collection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="range"></param>
public static void AddRange<T>([NotNull] this ICollection<T> extends, [NotNull] IEnumerable<T> range)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (range == null)
throw new ArgumentNullException("range");
foreach (T item in range)
extends.Add(item);
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Globalization;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class CultureInfoExtensions
{
/// <summary>
/// Returns true if the given culture uses a 24 hour time format.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool Uses24HourFormat([NotNull]this CultureInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.DateTimeFormat.ShortTimePattern.Contains("H");
}
/// <summary>
/// Updates the time patterns for the given culture to use 12 hour time.
/// </summary>
/// <param name="extends"></param>
public static void ConvertTo12HourCulture([NotNull]this CultureInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.IsReadOnly)
throw new InvalidOperationException("Culture is readonly");
DateTimeFormatInfo dateTimeFormat = extends.DateTimeFormat;
dateTimeFormat.FullDateTimePattern = To12HourPattern(dateTimeFormat.FullDateTimePattern);
dateTimeFormat.LongTimePattern = To12HourPattern(dateTimeFormat.LongTimePattern);
dateTimeFormat.ShortTimePattern = To12HourPattern(dateTimeFormat.ShortTimePattern);
}
/// <summary>
/// Updates the time patterns for the given culture to use 24 hour time.
/// </summary>
/// <param name="extends"></param>
public static void ConvertTo24HourCulture([NotNull]this CultureInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.IsReadOnly)
throw new InvalidOperationException("Culture is readonly");
DateTimeFormatInfo dateTimeFormat = extends.DateTimeFormat;
dateTimeFormat.FullDateTimePattern = To24HourPattern(dateTimeFormat.FullDateTimePattern);
dateTimeFormat.LongTimePattern = To24HourPattern(dateTimeFormat.LongTimePattern);
dateTimeFormat.ShortTimePattern = To24HourPattern(dateTimeFormat.ShortTimePattern);
}
/// <summary>
/// Converts the given format pattern to use 24 hour time.
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static string To24HourPattern(string pattern)
{
if (pattern == null)
return null;
pattern = pattern.Replace(" tt", "");
return pattern.Replace("h", "H");
}
/// <summary>
/// Converts the given format pattern to use 12 hour time.
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static string To12HourPattern(string pattern)
{
if (pattern == null)
return null;
if (!pattern.Contains("t"))
pattern = pattern + " tt";
return pattern.Replace("H", "h");
}
}
}

View File

@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -25,11 +28,211 @@ namespace ICD.Common.Utils.Extensions
/// <returns></returns>
public static string ToLongTimeStringWithMilliseconds(this DateTime extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
// Todo - Better handle different cultures
return extends.ToString("HH:mm:ss:fff");
}
/// <summary>
/// Returns the closest DateTime to the target time that is greater than the target time
/// </summary>
/// <param name="target"></param>
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? NextEarliestTime(this DateTime target, bool inclusive, [NotNull] params DateTime[] times)
{
if (times == null)
throw new ArgumentNullException("times");
return target.NextEarliestTime(inclusive, (IEnumerable<DateTime>)times);
}
/// <summary>
/// Returns the closest DateTime to the target time that is greater than the target time
/// </summary>
/// <param name="target"></param>
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? NextEarliestTime(this DateTime target, bool inclusive, [NotNull] IEnumerable<DateTime> times)
{
if (times == null)
throw new ArgumentNullException("times");
DateTime earliestTime;
bool success = times.OrderBy(dt => dt).TryFirst(dt => inclusive ? target <= dt : target < dt, out earliestTime);
return success ? earliestTime : (DateTime?)null;
}
/// <summary>
/// Returns the closest DateTime to the target time that is less than the target time
/// </summary>
/// <param name="target"></param>
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? PreviousLatestTime(this DateTime target, bool inclusive, [NotNull] params DateTime[] times)
{
if (times == null)
throw new ArgumentNullException("times");
return target.PreviousLatestTime(inclusive, (IEnumerable<DateTime>)times);
}
/// <summary>
/// Returns the closest DateTime to the target time that is less than the target time
/// </summary>
/// <param name="target"></param>
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? PreviousLatestTime(this DateTime target, bool inclusive, [NotNull] IEnumerable<DateTime> times)
{
if (times == null)
throw new ArgumentNullException("times");
DateTime latestTime;
bool success = times.OrderByDescending(dt => dt).TryFirst(dt => inclusive ? target >= dt : target > dt, out latestTime);
return success ? latestTime : (DateTime?)null;
}
/// <summary>
/// Returns the DateTime representing the very start of the current day.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static DateTime StartOfDay(this DateTime extends)
{
return new DateTime(extends.Year, extends.Month, extends.Day, 0, 0, 0);
}
/// <summary>
/// Returns the DateTime representing the very end of the current day.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static DateTime EndOfDay(this DateTime extends)
{
return extends.StartOfDay() + new TimeSpan(24, 0, 0);
}
/// <summary>
/// Returns the give date in ISO-8601 format.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string ToIso(this DateTime extends)
{
return extends.ToString("o");
}
/// <summary>
/// Returns the given date in unix timestamp format.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static double ToUnixTimestamp(this DateTime extends)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = extends.ToUniversalTime() - origin;
return Math.Floor(diff.TotalSeconds);
}
/// <summary>
/// Adds the given number of years to the date, and checks if the day is still valid (basically only for leap days).
/// </summary>
/// <param name="extends"></param>
/// <param name="years"></param>
/// <returns></returns>
public static DateTime AddYearsAndWrap(this DateTime extends, int years)
{
years += extends.Year;
// need to check days in month due to leap year
int daysInMonth = DateTime.DaysInMonth(years, extends.Month);
int day = daysInMonth < extends.Day ? daysInMonth : extends.Day;
return new DateTime(years, extends.Month, day, extends.Hour, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of months to the date, wrapping every 12 months, and lowering the day in the month is not valid.
/// </summary>
/// <param name="extends"></param>
/// <param name="months"></param>
/// <returns></returns>
public static DateTime AddMonthsAndWrap(this DateTime extends, int months)
{
months = MathUtils.Modulus(months + extends.Month - 1, 12) + 1;
int daysInMonth = DateTime.DaysInMonth(extends.Year, months);
int day = daysInMonth < extends.Day ? daysInMonth : extends.Day;
return new DateTime(extends.Year, months, day, extends.Hour, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of days to the date, wrapping when the number of days exceeds the days in a month.
/// </summary>
/// <param name="extends"></param>
/// <param name="days"></param>
/// <returns></returns>
public static DateTime AddDaysAndWrap(this DateTime extends, int days)
{
days = MathUtils.Modulus(days + extends.Day - 1, DateTime.DaysInMonth(extends.Year, extends.Month)) + 1;
return new DateTime(extends.Year, extends.Month, days, extends.Hour, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of hours to the time, wrapping every 24 hours without modifying the day.
/// </summary>
/// <param name="extends"></param>
/// <param name="hours"></param>
/// <returns></returns>
public static DateTime AddHoursAndWrap(this DateTime extends, int hours)
{
hours = MathUtils.Modulus(hours + extends.Hour, 24);
return new DateTime(extends.Year, extends.Month, extends.Day, hours, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of hours to the time, wrapping within the current 12 hour span, without modifying the day.
/// </summary>
/// <param name="extends"></param>
/// <param name="hours"></param>
/// <returns></returns>
public static DateTime AddHoursAndWrap12Hour(this DateTime extends, int hours)
{
int currentHour = extends.Hour;
bool am = extends.Hour < 12;
int current12Hour = MathUtils.Modulus(currentHour, 12);
int new12Hour = MathUtils.Modulus(current12Hour + hours, 12);
return am
? new DateTime(extends.Year, extends.Month, extends.Day, new12Hour, extends.Minute, extends.Second, extends.Millisecond)
: new DateTime(extends.Year, extends.Month, extends.Day, new12Hour + 12, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of minutes to the time, wrapping every 60 minutes without modifying the hour.
/// </summary>
/// <param name="extends"></param>
/// <param name="minutes"></param>
/// <returns></returns>
public static DateTime AddMinutesAndWrap(this DateTime extends, int minutes)
{
minutes = MathUtils.Modulus(minutes + extends.Minute, 60);
return new DateTime(extends.Year, extends.Month, extends.Day, extends.Hour, minutes, extends.Second, extends.Millisecond);
}
/// <summary>
/// Returns the total number of seconds since DateTime.MinValue
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static double GetTotalSeconds(this DateTime extends)
{
return (extends - DateTime.MinValue).TotalSeconds;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace ICD.Common.Utils.Extensions
{
public static class DayOfWeekExtensions
{
public static bool IsWeekday(this DayOfWeek day)
{
return !IsWeekend(day);
}
public static bool IsWeekend(this DayOfWeek day)
{
return day == DayOfWeek.Saturday || day == DayOfWeek.Sunday;
}
}
}

Some files were not shown because too many files have changed in this diff Show More