diff --git a/Source/Code/UtilPack.Configuration/UtilPack.Configuration.csproj b/Source/Code/UtilPack.Configuration/UtilPack.Configuration.csproj index 3f4b339..76c0c65 100644 --- a/Source/Code/UtilPack.Configuration/UtilPack.Configuration.csproj +++ b/Source/Code/UtilPack.Configuration/UtilPack.Configuration.csproj @@ -6,8 +6,6 @@ True - True - diff --git a/Source/Code/UtilPack.Documentation/UtilPack.Documentation.csproj b/Source/Code/UtilPack.Documentation/UtilPack.Documentation.csproj index dfbb7c0..69eb3f9 100644 --- a/Source/Code/UtilPack.Documentation/UtilPack.Documentation.csproj +++ b/Source/Code/UtilPack.Documentation/UtilPack.Documentation.csproj @@ -5,10 +5,7 @@ - True - True - latest diff --git a/Source/Code/UtilPack.JSON/UtilPack.JSON.csproj b/Source/Code/UtilPack.JSON/UtilPack.JSON.csproj index a25bc7c..da1ee8e 100644 --- a/Source/Code/UtilPack.JSON/UtilPack.JSON.csproj +++ b/Source/Code/UtilPack.JSON/UtilPack.JSON.csproj @@ -5,8 +5,6 @@ - True - True diff --git a/Source/Code/UtilPack.Logging/UtilPack.Logging.csproj b/Source/Code/UtilPack.Logging/UtilPack.Logging.csproj index 9ca5a7b..6cb0201 100644 --- a/Source/Code/UtilPack.Logging/UtilPack.Logging.csproj +++ b/Source/Code/UtilPack.Logging/UtilPack.Logging.csproj @@ -6,9 +6,6 @@ True - True - - latest $(DefineConstants);INTERNALIZE diff --git a/Source/Code/UtilPack.MSBuild.AsyncExec/UtilPack.MSBuild.AsyncExec.csproj b/Source/Code/UtilPack.MSBuild.AsyncExec/UtilPack.MSBuild.AsyncExec.csproj index c484a8d..61d67a9 100644 --- a/Source/Code/UtilPack.MSBuild.AsyncExec/UtilPack.MSBuild.AsyncExec.csproj +++ b/Source/Code/UtilPack.MSBuild.AsyncExec/UtilPack.MSBuild.AsyncExec.csproj @@ -5,8 +5,6 @@ - True - True diff --git a/Source/Code/UtilPack.TabularData/UtilPack.TabularData.csproj b/Source/Code/UtilPack.TabularData/UtilPack.TabularData.csproj index 069e501..fc13efa 100644 --- a/Source/Code/UtilPack.TabularData/UtilPack.TabularData.csproj +++ b/Source/Code/UtilPack.TabularData/UtilPack.TabularData.csproj @@ -6,8 +6,6 @@ True - True - diff --git a/Source/Code/UtilPack/ArgumentValidator.cs b/Source/Code/UtilPack/ArgumentValidator.cs index c6e06a2..6b72765 100644 --- a/Source/Code/UtilPack/ArgumentValidator.cs +++ b/Source/Code/UtilPack/ArgumentValidator.cs @@ -35,6 +35,21 @@ namespace UtilPack #endif static class ArgumentValidator { + /// + /// This message will be the error message of exception thrown by . + /// + public const String NULLREF_MESSAGE = "Extension method 'this' parameter is null."; + + /// + /// The parameter name will be suffixed by this string when throwing an error inside . + /// + public const String EMPTY_STRING_SUFFIX = " was empty string."; + + /// + /// The parameter name will be suffixed by this string when throwing an error inside or . + /// + public const String EMPTY_SUFFIX = " was empty."; + /// /// Checks whether a method parameter is null. /// @@ -75,7 +90,7 @@ public static T ValidateNotNullReference( T value ) { if ( value == null ) { - throw new NullReferenceException( "Extension method 'this' parameter is null." ); + throw new NullReferenceException( NULLREF_MESSAGE ); } return value; } @@ -97,7 +112,7 @@ public static IEnumerable ValidateNotEmpty( String parameterName, IEnumera ValidateNotNull( parameterName, value ); if ( !value.Any() ) { - throw new ArgumentException( parameterName + " was empty." ); + throw new ArgumentException( parameterName + EMPTY_SUFFIX ); } return value; } @@ -119,7 +134,7 @@ public static T[] ValidateNotEmpty( String parameterName, T[] value ) ValidateNotNull( parameterName, value ); if ( value.Length <= 0 ) { - throw new ArgumentException( parameterName + " was empty." ); + throw new ArgumentException( parameterName + EMPTY_SUFFIX ); } return value; } @@ -140,7 +155,7 @@ public static String ValidateNotEmpty( String parameterName, String value ) ValidateNotNull( parameterName, value ); if ( value.Length == 0 ) { - throw new ArgumentException( parameterName + " was empty string." ); + throw new ArgumentException( parameterName + EMPTY_STRING_SUFFIX ); } return value; } diff --git a/Source/Code/UtilPack/Asynchrony.cs b/Source/Code/UtilPack/Asynchrony.cs index fb0e71e..fa5f732 100644 --- a/Source/Code/UtilPack/Asynchrony.cs +++ b/Source/Code/UtilPack/Asynchrony.cs @@ -22,6 +22,14 @@ using System.Threading.Tasks; using UtilPack; +using TTaskExt = System.Threading.Tasks. +#if NET40 + TaskEx +#else + Task +#endif + ; + namespace UtilPack { /// @@ -64,7 +72,7 @@ static class TaskUtils /// /// Gets the task which is completed. /// - public static System.Threading.Tasks.Task CompletedTask { get; } + public static Task CompletedTask { get; } /// /// Gets the task which is completed to a boolean value true. @@ -80,25 +88,13 @@ static class TaskUtils static TaskUtils() { - var src = new System.Threading.Tasks.TaskCompletionSource(); + var src = new TaskCompletionSource(); src.SetResult( null ); CompletedTask = src.Task; - True = -#if NET40 - TaskEx -#else - Task -#endif - .FromResult( true ); - False = -#if NET40 - TaskEx -#else - Task -#endif - .FromResult( false ); + True = TTaskExt.FromResult( true ); + False = TTaskExt.FromResult( false ); } /// @@ -147,9 +143,122 @@ public static Task FromCanceled( CancellationToken token ) { throw new ArgumentException( nameof( token ) ); } - return new Task( () => default( T ), token, TaskCreationOptions.None ); + return new Task( () => default, token, TaskCreationOptions.None ); + } + + } + + public static partial class UtilPackExtensions + { + /// + /// This is helper method to return task which will throw a if this task has not completed in given timeout. + /// + /// This task. + /// The maximum of time to wait for this task to complete. + /// The to use. + /// A task which either completes when this task does, or throws an . + /// If given amount of time has passed before this task completes. + /// If gets canceled before this task completes and before timeout has expired. +#if !NET40 + [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining )] +#endif + public static Task TimeoutAfter( this Task task, TimeSpan timeout, CancellationToken token ) + { + if ( task.IsCompleted || timeout == TimeSpan.FromMilliseconds( -1 ) ) + { + // The task is done or will never timeout anyway + return task; + } + else if ( timeout == TimeSpan.Zero || token.IsCancellationRequested ) + { + // We have already timeouted +#if NET40 || NET45 || NETSTANDARD1_0 || NETSTANDARD1_1 + var tsc = new TaskCompletionSource(); + tsc.SetException( new TimeoutException() ); + return tsc.Task; +#else + return Task.FromException( new TimeoutException() ); +#endif + } + else + { + return task.TimeoutAfterImpl( timeout, token ); + } + + } + + private static async Task TimeoutAfterImpl( this Task task, TimeSpan timeout, CancellationToken token ) + { + using ( var linked = CancellationTokenSource.CreateLinkedTokenSource( token ) ) + { + + if ( ReferenceEquals( task, await TTaskExt.WhenAny( task, TTaskExt.Delay( timeout, linked.Token ) ) ) ) + { + // Task completed before the timeout, cancel timeout (thus disposing of timer) + linked.Cancel(); + await task; + } + else + { + throw new TimeoutException(); + } + } } + /// + /// This is helper method to return task which will throw a if this task has not completed in given timeout. + /// + /// This task. + /// The maximum of time to wait for this task to complete. + /// The to use. + /// A task which either completes when this task does, or throws an . + /// If given amount of time has passed before this task completes. + /// If gets canceled before this task completes and before timeout has expired. +#if !NET40 + [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining )] +#endif + public static Task TimeoutAfter( this Task task, TimeSpan timeout, CancellationToken token ) + { + if ( task.IsCompleted || timeout == TimeSpan.FromMilliseconds( -1 ) ) + { + // The task is done or will never timeout anyway + return task; + } + else if ( timeout == TimeSpan.Zero || token.IsCancellationRequested ) + { + // We have already timeouted +#if NET40 || NET45 || NETSTANDARD1_0 || NETSTANDARD1_1 + var tsc = new TaskCompletionSource(); + tsc.SetException( new TimeoutException() ); + return tsc.Task; +#else + return Task.FromException( new TimeoutException() ); +#endif + } + else + { + return task.TimeoutAfterImpl( timeout, token ); + } + + } + + private static async Task TimeoutAfterImpl( this Task task, TimeSpan timeout, CancellationToken token ) + { + using ( var linked = CancellationTokenSource.CreateLinkedTokenSource( token ) ) + { + + if ( ReferenceEquals( task, await TTaskExt.WhenAny( task, TTaskExt.Delay( timeout, linked.Token ) ) ) ) + { + // Task completed before the timeout, cancel timeout (thus disposing of timer) + linked.Cancel(); + return await task; + } + else + { + throw new TimeoutException(); + } + } + } } /// @@ -252,27 +361,9 @@ public void Dispose() public AsyncLock() { this._semaphore = new SemaphoreSlim( 1, 1 ); - this._completed = -#if NET40 - TaskEx -#else - Task -#endif - .FromResult( new LockUseScope( this ) ); - this._completedNullable = -#if NET40 - TaskEx -#else - Task -#endif - .FromResult( new LockUseScope( this ) ); - this._notCompletedNullable = -#if NET40 - TaskEx -#else - Task -#endif - .FromResult( null ); + this._completed = TTaskExt.FromResult( new LockUseScope( this ) ); + this._completedNullable = TTaskExt.FromResult( new LockUseScope( this ) ); + this._notCompletedNullable = TTaskExt.FromResult( null ); } /// @@ -429,13 +520,7 @@ public static async Task InvokeAndWaitForAwaitables /// At least current implementation is most likely not very efficient... /// - public static async Task WaitAsync( this SemaphoreSlim semaphore, Int32 tick = 100 ) + public static async Task WaitAsync( + this SemaphoreSlim semaphore, + Int32 tick = 100 + ) { while ( !semaphore.Wait( 0 ) ) { @@ -512,12 +600,19 @@ public static async Task WaitAsync( this SemaphoreSlim semaphore, Int32 tick = 1 /// /// At least current implementation is most likely not very efficient... /// - public static async Task WaitAsync( this SemaphoreSlim semaphore, TimeSpan timeout, CancellationToken token = default, Int32 tick = 100 ) + public static async Task WaitAsync( + this SemaphoreSlim semaphore, + TimeSpan timeout, + CancellationToken token = default, + Int32 tick = 100 + ) { var curTimeout = 0L; Boolean retVal; - while ( !( retVal = semaphore.Wait( 0 ) ) && curTimeout < timeout.TotalMilliseconds ) + var noTimeout = TimeSpan.FromMilliseconds( -1 ) == timeout; + while ( !( retVal = semaphore.Wait( 0 ) ) && ( noTimeout || curTimeout < timeout.TotalMilliseconds ) ) { + // Delay is not precise (waits _at least_ given amount), TODO refactor this to use DateTime.UtcNow await TaskEx.Delay( tick, token ); curTimeout += tick; } diff --git a/Source/Code/UtilPack/BinaryExtensions.cs b/Source/Code/UtilPack/BinaryExtensions.cs index 5bae879..d311dd8 100644 --- a/Source/Code/UtilPack/BinaryExtensions.cs +++ b/Source/Code/UtilPack/BinaryExtensions.cs @@ -291,6 +291,20 @@ public static Byte ReadByteFromBytes( this Byte[] array, ref Int32 idx ) return array[idx++]; } + /// + /// Reads a single byte at specified index in byte array. + /// + /// The byte array. + /// The index to read byte at. + /// The byte at specified index. +#if !NET40 + [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining )] +#endif + public static Byte ReadByteFromBytesNoRef( this Byte[] array, Int32 idx ) + { + return array[idx]; + } + /// /// Reads a single byte as at specified index in byte array. /// @@ -303,7 +317,22 @@ public static Byte ReadByteFromBytes( this Byte[] array, ref Int32 idx ) #endif public static SByte ReadSByteFromBytes( this Byte[] array, ref Int32 idx ) { - return (SByte) array[idx++]; + return unchecked((SByte) array[checked(idx++)]); + } + + /// + /// Reads a single byte as at specified index in byte array. + /// + /// The byte array. + /// The index to read byte at. + /// The byte at specified index casted to . + [CLSCompliant( false )] +#if !NET40 + [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining )] +#endif + public static SByte ReadSByteFromBytesNoRef( this Byte[] array, Int32 idx ) + { + return unchecked((SByte) array[idx]); } #region Little-Endian Conversions @@ -1134,8 +1163,8 @@ public static Single ReadSingleBEFromBytes( this Byte[] array, ref Int32 idx ) { if ( BitConverter.IsLittleEndian ) { - // Read little-endian Int32, get bytes for it, and convert back to single - return BitConverter.ToSingle( BitConverter.GetBytes( array.ReadInt32LEFromBytes( ref idx ) ), 0 ); + // Read big-endian Int32, get bytes for it, and convert back to single + return BitConverter.ToSingle( BitConverter.GetBytes( array.ReadInt32BEFromBytes( ref idx ) ), 0 ); } else { @@ -1594,7 +1623,7 @@ public static String ReadZeroTerminatedStringFromBytes( this Byte[] array, ref I /// /// Helper method to write the given ASCII string (as byte array) to this byte array. - /// Essentially, this is call-through to . + /// Essentially, this is call-through to . /// /// This array where to write ASCII string to. /// The index in this array where to start writing. @@ -1823,6 +1852,22 @@ public static Byte[] WriteByteToBytes( this Byte[] array, ref Int32 idx, Byte aB return array; } + /// + /// Sets a single byte in byte array at specified offset to given value. + /// + /// The byte array. + /// The offset to set byte. + /// The value to set. + /// The . +#if !NET40 + [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining )] +#endif + public static Byte[] WriteByteToBytesNoRef( this Byte[] array, Int32 idx, Byte aByte ) + { + array[idx] = aByte; + return array; + } + /// /// Sets a single byte in byte array at specified offset to given value, and increments the offset. /// @@ -1836,7 +1881,24 @@ public static Byte[] WriteByteToBytes( this Byte[] array, ref Int32 idx, Byte aB #endif public static Byte[] WriteSByteToBytes( this Byte[] array, ref Int32 idx, SByte sByte ) { - array[idx++] = sByte < 0 ? (Byte) ( 256 + sByte ) : (Byte) sByte; + array[idx++] = unchecked(sByte < 0 ? (Byte) ( 256 + sByte ) : (Byte) sByte); + return array; + } + + /// + /// Sets a single byte in byte array at specified offset to given value. + /// + /// The byte array. + /// The offset to set byte. + /// The value to set. Even though it is integer, it is interpreted as signed byte. + /// The . + [CLSCompliant( false )] +#if !NET40 + [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining )] +#endif + public static Byte[] WriteSByteToBytesNoRef( this Byte[] array, Int32 idx, SByte sByte ) + { + array[idx] = unchecked(sByte < 0 ? (Byte) ( 256 + sByte ) : (Byte) sByte); return array; } @@ -1942,7 +2004,7 @@ public static Int32 ReadInt32LEEncoded7Bit( this Byte[] array, ref Int32 idx, Bo // Int32 encoded as 1-5 bytes. If highest bit set -> more bytes to follow. var retVal = 0; var shift = 0; - byte b; + Byte b; do { if ( shift > 32 ) // 5 bytes max per Int32, shift += 7 @@ -1985,7 +2047,7 @@ public static Int64 ReadInt64LEEncoded7Bit( this Byte[] array, ref Int32 idx, Bo // Int64 encoded as 1-9 bytes. If highest bit set -> more bytes to follow. var retVal = 0L; var shift = 0; - byte b; + Byte b; do { if ( shift > 64 ) // 9 bytes max per Int64, shift += 7 @@ -2078,7 +2140,7 @@ public static Int32 ReadInt32BEEncoded7Bit( this Byte[] array, ref Int32 idx, Bo // Int32 encoded as 1-5 bytes. If highest bit set -> more bytes to follow. var retVal = 0; var shift = 0; - byte b; + Byte b; do { if ( shift > 32 ) // 5 bytes max per Int32, shift += 7 @@ -2121,7 +2183,7 @@ public static Int64 ReadInt64BEEncoded7Bit( this Byte[] array, ref Int32 idx, Bo // Int64 encoded as 1-9 bytes. If highest bit set -> more bytes to follow. var retVal = 0L; var shift = 0; - byte b; + Byte b; do { if ( shift > 64 ) // 9 bytes max per Int64, shift += 7 diff --git a/Source/Code/UtilPack/BinaryStringPool.cs b/Source/Code/UtilPack/BinaryStringPool.cs index 9358dce..030a12e 100644 --- a/Source/Code/UtilPack/BinaryStringPool.cs +++ b/Source/Code/UtilPack/BinaryStringPool.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; using System.Text; +using UtilPack; namespace UtilPack { @@ -54,7 +55,7 @@ public static class BinaryStringPoolFactory /// /// Creates a new instance of which will perform correctly in single-threaded scenarios only. /// - /// The encoding to use when deserializing strings. If null, then will be used, passing false to both parameters of + /// The encoding to use when deserializing strings. If null, then will be used, passing false to both parameters of /// A new instance of which will perform correctly in single-threaded scenarios only. public static BinaryStringPool NewNotConcurrentBinaryStringPool( Encoding encoding = null ) { @@ -67,7 +68,7 @@ public static BinaryStringPool NewNotConcurrentBinaryStringPool( Encoding encodi /// /// Creates a new instance of which will perform correctly in both single- and multi-threaded scenarios. /// - /// The encoding to use when deserializing strings. If null, then will be used, passing false to both parameters of + /// The encoding to use when deserializing strings. If null, then will be used, passing false to both parameters of /// A new instance of which will perform correctly in single-threaded scenarios only. public static BinaryStringPool NewConcurrentBinaryStringPool( Encoding encoding = null ) { @@ -232,3 +233,19 @@ public void ClearPool() } #endif } + +public static partial class E_UtilPack +{ + /// + /// This is helper method to invoke giving whole array as argumnent. + /// + /// This . + /// The array containing serialized string. + /// Newly created or cached string. + public static String GetString( + this BinaryStringPool pool, + Byte[] array ) + { + return pool.GetString( array, 0, ArgumentValidator.ValidateNotNull( nameof( array ), array ).Length ); + } +} \ No newline at end of file diff --git a/Source/Code/UtilPack/CollectionExtensions.cs b/Source/Code/UtilPack/CollectionExtensions.cs index d061bd9..4f03001 100644 --- a/Source/Code/UtilPack/CollectionExtensions.cs +++ b/Source/Code/UtilPack/CollectionExtensions.cs @@ -202,7 +202,7 @@ public static TValue GetOrAdd_WithLock( this IDictionaryThe value to return if no value exists for in . /// The value for in , or if does not have value associated for . /// If is null. - public static TValue GetOrDefault( this IDictionary dic, TKey key, TValue defaultValue = default( TValue ) ) + public static TValue GetOrDefault( this IDictionary dic, TKey key, TValue defaultValue = default ) { TValue value; return dic.TryGetValue( key, out value ) ? value : defaultValue; @@ -438,7 +438,7 @@ public static Boolean EmptyOrAllEqual( this IEnumerable enumerable, out T } else { - first = default( T ); + first = default; } } diff --git a/Source/Code/UtilPack/Empty.cs b/Source/Code/UtilPack/Empty.cs index f28e23c..86be86a 100644 --- a/Source/Code/UtilPack/Empty.cs +++ b/Source/Code/UtilPack/Empty.cs @@ -33,8 +33,6 @@ namespace UtilPack #endif static class Empty { - private static readonly IEnumerable ENUMERABLE = System.Linq.Enumerable.Empty(); - /// /// Returns instance of array with zero elements. /// diff --git a/Source/Code/UtilPack/Loading.cs b/Source/Code/UtilPack/Loading.cs deleted file mode 100644 index 2923ae3..0000000 --- a/Source/Code/UtilPack/Loading.cs +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright 2017 Stanislav Muhametsin. All rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#if false //NETSTANDARD1_5 (System.Runtime.Loader does not exist on any .NET -> need to rethink and possibly redesign -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.Loader; -using System.Text; -using UtilPack; - -namespace UtilPack -{ - /// - /// This class allows to explicitly load assembly from given location (e.g. file path), and keep track of loaded assemblies. - /// Furthermore, the load of dependent assemblies (which must be done since loads assemblies lazily) is done in controlled and customizable way. - /// - /// - /// This class is not safe to be used concurrently. - /// - public class ExplicitAssemblyLoader - { - private sealed class LoadedAssemblyInfo - { - public LoadedAssemblyInfo( - String originalPath, - String loadedPath, - Assembly assembly - ) - { - this.OriginalPath = originalPath; - this.LoadedPath = loadedPath; - this.Assembly = assembly; - } - - public String OriginalPath { get; } - - public String LoadedPath { get; } - - public Assembly Assembly { get; } - } - - private readonly AssemblyLoadContext _assemblyLoader; - private readonly IDictionary _assembliesByOriginalPath; - private readonly Func _assemblyPathProcessor; - private readonly Func> _candidatePathGetter; - - /// - /// Creates new instance of with given optional customizers. - /// - /// The callback to process the assembly path from which to actually load assembly. Only invoked when the file exists. Receives original assembly path as argument. - /// The callback to scan through potential assembly locations. Receives referencing assembly path and assembly name reference as arguments. By default, is used. - /// The actual to use. By default the is used. - /// - /// The may e.g. copy the assembly file from original location to some other location and return the copied path, thus behaving somewhat like shadow copying. - /// The may e.g. file paths in NuGet repository. - /// Not all paths returned by need to exist - this loader will check whether paths exist. - /// - public ExplicitAssemblyLoader( - Func assemblyPathProcessor = null, - Func> candidatePathGetter = null, - AssemblyLoadContext assemblyLoadContext = null - ) - { - this._assemblyPathProcessor = assemblyPathProcessor; - this._candidatePathGetter = candidatePathGetter ?? GetDefaultAssemblyReferenceCandidatePaths; - this._assembliesByOriginalPath = new Dictionary(); - this._assemblyLoader = assemblyLoadContext ?? AssemblyLoadContext.Default; - } - - /// - /// Loads the assembly from given location, if it is not already loaded. - /// - /// The location to load assembly from. Is case-sensitive. - /// Whether to load dependencies, if assembly was loaded. - /// Loaded or cached assembly. If assembly was loaded, and is true, the second tuple item will be non-null containing recursive dependency load information. - /// - /// This method recursively loads all dependencies of the assembly, if actual load is performed. - /// - public (Assembly LoadedAssembly, IDictionary LoadedDependencies) LoadAssemblyFrom( - String location, - Boolean loadDependencies = true - ) - { - var assemblyPath = System.IO.Path.GetFullPath( location ); - - var assembly = this.LoadLibraryAssembly( assemblyPath, out Boolean actuallyLoaded ); - - IDictionary loadedDeps; - if ( actuallyLoaded && loadDependencies ) - { - // Load recursively all dependant assemblies right here, since the loader is lazy, and if the dependant assembly load happens later, our callback will be gone. - loadedDeps = this.LoadDependenciesRecursively( assembly ); - } - else - { - loadedDeps = null; - } - - return (assembly.Assembly, loadedDeps); - } - - /// - /// Loads all the dependencies of given assembly, if it is loaded by this . - /// - /// The assembly to load dependencies of. - /// Possibly empty dictionary of assembly dependencies. Will return null if was not loaded by this . - public IDictionary LoadAllDependenciesOf( Assembly assembly ) - { - return this._assembliesByOriginalPath.TryGetValue( assembly.Location, out LoadedAssemblyInfo info ) ? - this.LoadDependenciesRecursively( info ) : - null; - } - - /// - /// Checks whether the assembly at given location has been loaded by this . - /// - /// The location of the assembly. - /// true if assebmly at given location has been loaded by this ; false otherwise. - public Boolean IsAssemblyLoaded( String location ) - { - return this._assembliesByOriginalPath.ContainsKey( location ); - } - - private IDictionary LoadDependenciesRecursively( - LoadedAssemblyInfo loadedAssembly - ) - { - var assemblies = this._assembliesByOriginalPath; - - var assembliesToProcess = new List - { - loadedAssembly - }; - var addedThisRound = new List(); - var loadedDeps = new Dictionary( - ComparerFromFunctions.NewEqualityComparer( - ( a1, a2 ) => ReferenceEquals( a1, a2 ) || ( a1 != null && a2 != null && String.Equals( a1.Name, a2.Name ) && String.Equals( a1.CultureName, a2.CultureName ) && a1.Version.Equals( a2.Version ) && ArrayEqualityComparer.ArrayEquality( a1.GetPublicKey(), a2.GetPublicKey() ) ), - a => a.Name.GetHashCodeSafe() - ) - ); - do - { - addedThisRound.Clear(); - - foreach ( var loadedInfo in assembliesToProcess ) - { - - foreach ( var aRef in loadedInfo.Assembly.GetReferencedAssemblies() ) - { - var curRef = aRef; - var oldCount = assemblies.Count; - var originalPath = loadedInfo.OriginalPath; - var assemblyPath = this.GetFirstExistingAssemblyPath( originalPath, curRef ); - - // We *must* use loading by assembly name here - otherwise we end up with multiple loaded assemblies with the same assembly name! - Assembly curAssembly = null; - try - { - curAssembly = this.LoadAssemblyReference( - originalPath, - curRef - ); - } - catch - { - // Ignore - loadedDeps.Add( aRef, null ); - } - - if ( curAssembly != null && System.IO.File.Exists( assemblyPath ) ) - { - var newCount = assemblies.Count; - - if ( newCount > oldCount ) - { - addedThisRound.Add( this._assembliesByOriginalPath[assemblyPath] ); - loadedDeps.Add( aRef, curAssembly ); - } - } - - } - } - - assembliesToProcess.Clear(); - assembliesToProcess.AddRange( addedThisRound ); - } while ( addedThisRound.Count > 0 ); - - return loadedDeps; - } - - private LoadedAssemblyInfo LoadLibraryAssembly( - String originalPathParam, - out Boolean actuallyLoaded - ) - { - var assemblies = this._assembliesByOriginalPath; - var oldCount = assemblies.Count; - var retVal = assemblies.GetOrAdd_NotThreadSafe( originalPathParam, originalPath => - { - var processed = this._assemblyPathProcessor?.Invoke( originalPath ); - if ( String.IsNullOrEmpty( processed ) ) - { - processed = originalPath; - } - - return new LoadedAssemblyInfo( - originalPath, - processed, - this.LoadAssemblyReference( originalPath, processed ) - ); - } ); - actuallyLoaded = assemblies.Count > oldCount; - - return retVal; - } - - private Assembly LoadAssemblyReference( - String referencingAssemblyOriginalPath, - EitherOr assemblyRef - ) - { - Func eventHandler = ( ctx, aName ) => - { - var assemblyPath = this.GetFirstExistingAssemblyPath( referencingAssemblyOriginalPath, aName ); - - return String.IsNullOrEmpty( assemblyPath ) ? - null : - this.LoadLibraryAssembly( assemblyPath, out Boolean actuallyLoaded ).Assembly; - }; - - var loader = this._assemblyLoader; - loader.Resolving += eventHandler; - try - { - return assemblyRef.IsFirst ? - loader.LoadFromAssemblyPath( assemblyRef.First ) : - loader.LoadFromAssemblyName( assemblyRef.Second ); - } - finally - { - loader.Resolving -= eventHandler; - } - } - - /// - /// This is default callback which returns the string of file located in same directory as and having file name of property of . - /// Currently, only .dll file extension is used. - /// - /// The path of the assembly which needs this reference. - /// The of the reference. - /// The file path representing to the .dll reference to assembly in the same directory as . - public static IEnumerable GetDefaultAssemblyReferenceCandidatePaths( - String referencingAssemblyPath, - AssemblyName assemblyName - ) - { - var assemblyBasePath = System.IO.Path.Combine( System.IO.Path.GetDirectoryName( referencingAssemblyPath ), assemblyName.Name ); - - // TODO something else than .dll in the future...? - yield return assemblyBasePath + ".dll"; - } - - private String GetFirstExistingAssemblyPath( - String referencingAssemblyOriginalPath, - AssemblyName assemblyName - ) - { - return this._candidatePathGetter( referencingAssemblyOriginalPath, assemblyName ).FirstOrDefault( aPath => System.IO.File.Exists( aPath ) ); - } - - } -} - -public static partial class E_UtilPack -{ - /// - /// Tries to create an instance of class which is either specified by and pair, or by assembly-qualified . - /// - /// The type of the class. - /// This . - /// The name of the type. It should be the full name if is specified, and assembly-qualified name if is not specified. It can be null if is specified; in that case the first suitable type is returned. - /// The location of the assembly file. If it is specified, this is not used. Instead, the type is loaded using , if is specified. - /// The optional callback to create an instance once the type has been acquired. By default, the is used. - /// An instance of type , or null. - /// If is specified, and this is null. - public static T TryLoadClassInstanceFromAssembly( - this ExplicitAssemblyLoader loader, - String typeName, - String assemblyLocation, - Func instanceCreator = null - ) - where T : class - { - return (T) ( loader.TryLoadInstanceFromAssembly( - typeName, - assemblyLocation, - requiredParentType: typeof( T ).GetTypeInfo(), - additionalTypeCheck: t => t.GetTypeInfo().IsClass, - instanceCreator: instanceCreator - ) ); - } - - /// - /// Tries to create an instance of struct which is either specified by and pair, or by assembly-qualified . - /// - /// The type of the struct. - /// This . - /// The name of the type. It should be the full name if is specified, and assembly-qualified name if is not specified. It can be null if is specified; in that case the first suitable type is returned. - /// The location of the assembly file. If it is specified, this is not used. Instead, the type is loaded using , if is specified. - /// The optional callback to create an instance once the type has been acquired. By default, the is used. - /// An instance of type , or null. - /// If is specified, and this is null. - public static T? TryLoadStructInstanceFromAssembly( - this ExplicitAssemblyLoader loader, - String typeName, - String assemblyLocation, - Func instanceCreator = null - ) - where T : struct - { - return (T?) ( loader.TryLoadInstanceFromAssembly( - typeName, - assemblyLocation, - additionalTypeCheck: t => !t.GetTypeInfo().IsClass, - instanceCreator: instanceCreator - ) ); - } - - /// - /// Tries to create an instance of type which is either specified by and pair, or by assembly-qualified . - /// - /// This . - /// The name of the type. It should be the full name if is specified, and assembly-qualified name if is not specified. It can be null if and are both specified; in that case the first suitable type is returned. - /// The location of the assembly file. If it is specified, this is not used. Instead, the type is loaded using , if is specified. - /// Optional parent type which the loaded type must be assignable from. - /// Optional additional callback to check loaded type. - /// The optional callback to create an instance once the type has been acquired. By default, the is used. - /// An instance of given type, or null. - /// If is specified, and this is null. - public static Object TryLoadInstanceFromAssembly( - this ExplicitAssemblyLoader loader, - String typeName, - String assemblyLocation, - TypeInfo requiredParentType = null, - Func additionalTypeCheck = null, - Func instanceCreator = null - ) - { - var type = loader.TryLoadTypeFromAssembly( - typeName, - assemblyLocation, - requiredParentType: requiredParentType, - additionalTypeCheck: additionalTypeCheck - ); - return type == null ? null : ( instanceCreator?.Invoke( type ) ?? Activator.CreateInstance( type ) ); - } - - /// - /// Tries to load type which is either specified by and pair, or by assembly-qualified . - /// - /// This . - /// The name of the type. It should be the full name if is specified, and assembly-qualified name if is not specified. It can be null if and are both specified; in that case the first suitable type is returned. - /// The location of the assembly file. If it is specified, this is not used. Instead, the type is loaded using , if is specified. - /// Optional parent type which the loaded type must be assignable from. - /// Optional additional callback to check loaded type. - /// The loaded type, or null. - /// If is specified, and this is null. - public static Type TryLoadTypeFromAssembly( - this ExplicitAssemblyLoader loader, - String typeName, - String assemblyLocation, - TypeInfo requiredParentType = null, - Func additionalTypeCheck = null - ) - { - var providerTypeNameSpecified = !String.IsNullOrEmpty( typeName ); - Type providerType; - //String errorMessage; - if ( String.IsNullOrEmpty( assemblyLocation ) ) - { - if ( providerTypeNameSpecified ) - { - providerType = Type.GetType( typeName, false ); - //errorMessage = $"Failed to load type \"{providerTypeName}\", make sure the name is assembly-qualified."; - } - else - { - providerType = null; - //errorMessage = $"The task must receive {nameof( ConnectionPoolProviderAssemblyLocation )} and/or {nameof( ConnectionPoolProviderTypeName )} parameters."; - } - } - else - { - var providerAssembly = ArgumentValidator.ValidateNotNullReference( loader ).LoadAssemblyFrom( assemblyLocation, true ).LoadedAssembly; - if ( providerTypeNameSpecified ) - { - providerType = providerAssembly.GetType( typeName, false ); - //errorMessage = $"No type \"{providerTypeName}\" in assembly located in \"{providerAssemblyLocation}\"."; - } - else if ( requiredParentType != null ) - { - providerType = providerAssembly.DefinedTypes.FirstOrDefault( t => requiredParentType.IsAssignableFrom( t ) )?.AsType(); - //errorMessage = $"Failed to find any type implementing \"{providerBaseType.AssemblyQualifiedName}\" in assembly located in \"{providerAssemblyLocation}\"."; - } - else - { - providerType = null; - } - } - - return providerType != null - && ( requiredParentType?.IsAssignableFrom( providerType ) ?? true ) - && ( additionalTypeCheck?.Invoke( providerType ) ?? true ) ? - providerType : - null; - } -} -#endif \ No newline at end of file diff --git a/Source/Code/UtilPack/NullableComparer.cs b/Source/Code/UtilPack/NullableComparer.cs index 8d3f87b..1cdb323 100644 --- a/Source/Code/UtilPack/NullableComparer.cs +++ b/Source/Code/UtilPack/NullableComparer.cs @@ -32,27 +32,11 @@ namespace UtilPack public sealed class NullableEqualityComparer : IEqualityComparer where T : struct { - private static IEqualityComparer INSTANCE = null; - /// /// Returns the equality comparer for nullable type which uses the default equality comparer when comparing actual values. /// /// The equality comparer for nullable type which uses the default equality comparer when comparing actual values. - public static IEqualityComparer DefaultComparer - { - get - { - var retVal = INSTANCE; - if ( retVal == null ) - { - retVal = new NullableEqualityComparer( null, 0 ); - INSTANCE = retVal; - } - - return retVal; - } - } - + public static IEqualityComparer DefaultComparer { get; } = new NullableEqualityComparer( null, 0 ); private readonly IEqualityComparer _itemComparer; private readonly Int32 _hashCodeForNoValue; diff --git a/Source/Code/UtilPack/ResizableArray.cs b/Source/Code/UtilPack/ResizableArray.cs index 199ddca..29143bd 100644 --- a/Source/Code/UtilPack/ResizableArray.cs +++ b/Source/Code/UtilPack/ResizableArray.cs @@ -15,12 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -using UtilPack; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; +using UtilPack; namespace UtilPack { @@ -31,7 +31,6 @@ namespace UtilPack /// The type of elements in the array. public class ResizableArray { - private readonly Int32 _maxLimit; private Int32 _exponentialResize; private Int32 _currentCapacity; private T[] _array; @@ -49,9 +48,10 @@ public ResizableArray( Int32 initialSize = 0, Int32 maxLimit = -1, Boolean expon { initialSize = 0; } - this._maxLimit = maxLimit; + this.MaximumSize = maxLimit; this._currentCapacity = initialSize; this._array = new T[initialSize]; + this.ExponentialResize = exponentialResize; } /// @@ -104,13 +104,7 @@ public Boolean ExponentialResize /// /// Gets the maximum size for this , as specified in constructor. /// - public Int32 MaximumSize - { - get - { - return this._maxLimit; - } - } + public Int32 MaximumSize { get; } /// /// Gets the reference to the current array of this . @@ -129,7 +123,7 @@ public T[] Array private void EnsureArraySize( Int32 size, Int32 currentCapacity ) { - var max = this._maxLimit; + var max = this.MaximumSize; if ( max < 0 || size <= max ) { var array = this._array; @@ -143,7 +137,7 @@ private void EnsureArraySize( Int32 size, Int32 currentCapacity ) { newLen *= 2; } while ( newLen < size ); - if ( newLen > max ) + if ( max >= 0 && newLen > max ) { newLen = max; } diff --git a/Source/Code/UtilPack/StreamRelated.cs b/Source/Code/UtilPack/StreamRelated.cs index 990155f..1c59f0c 100644 --- a/Source/Code/UtilPack/StreamRelated.cs +++ b/Source/Code/UtilPack/StreamRelated.cs @@ -45,12 +45,12 @@ public interface AbstractStreamWithResizableBuffer /// /// This interface provides methods to read from the underlying . - /// The basic principle is that there is a marker index (accessible by ), which can be expanded by method. - /// The method will discard any bytes previously read into buffer and read the next bytes starting from 0 index. + /// The basic principle is that there is a marker index (accessible by ), which can be expanded by method. + /// The method will discard any bytes previously read into buffer and read the next bytes starting from 0 index. /// The amount of useable bytes of will always be , starting from 0 index of . /// /// - /// The default implementation will read underlying in chunks, therefore the return types of and are , since asynchrony will happen only when it is actually needed to read from stream. + /// The default implementation will read underlying in chunks, therefore the return types of and are , since asynchrony will happen only when it is actually needed to read from stream. /// class provides methods to create objects implementing this interface. /// public interface StreamReaderWithResizableBuffer : AbstractStreamWithResizableBuffer @@ -117,7 +117,7 @@ public interface StreamReaderWithResizableBuffer : AbstractStreamWithResizableBu void UnreadBytes( Int32 amount = -1 ); /// - /// Gets amount of bytes that is used as starting point when determining how many bytes to read from underlying stream for one call of or . + /// Gets amount of bytes that is used as starting point when determining how many bytes to read from underlying stream for one call of or . /// /// The amount of bytes that is used as starting point when determining how many bytes to read from underlying stream. Int32 ChunkSize { get; } @@ -829,7 +829,7 @@ public ValueTask TryReadAsync( Int32 amount ) return new ValueTask( amount <= 0 ); } - public ValueTask TryReadMoreAsync( int amount ) + public ValueTask TryReadMoreAsync( Int32 amount ) { return new ValueTask( amount <= 0 ); } @@ -1223,9 +1223,16 @@ public static Task ConnectAsync( this System.Net.Sockets.Socket socket, System.N // Theraot.Core does not provide (yet?) extension methods for async write/read for streams /// - public static Task ReadAsync( this Stream stream, Byte[] buffer, Int32 offset, Int32 count, CancellationToken token ) + public static Task ReadAsync( + this Stream stream, + Byte[] buffer, + Int32 offset, + Int32 count, + CancellationToken token + ) { token.ThrowIfCancellationRequested(); + // Bind parameters to tuple to avoid allocation of delegate class var readArgs = (stream, buffer, offset, count); return Task.Factory.FromAsync( ( rArgs, cb, state ) => rArgs.Item1.BeginRead( rArgs.Item2, rArgs.Item3, rArgs.Item4, cb, state ), @@ -1236,9 +1243,16 @@ public static Task ReadAsync( this Stream stream, Byte[] buffer, Int32 of } /// - public static Task WriteAsync( this Stream stream, Byte[] buffer, Int32 offset, Int32 count, CancellationToken token ) + public static Task WriteAsync( + this Stream stream, + Byte[] buffer, + Int32 offset, + Int32 count, + CancellationToken token + ) { token.ThrowIfCancellationRequested(); + // Bind parameters to tuple to avoid allocation of delegate class var writeArgs = (stream, buffer, offset, count); return Task.Factory.FromAsync( ( wArgs, cb, state ) => wArgs.Item1.BeginWrite( wArgs.Item2, wArgs.Item3, wArgs.Item4, cb, state ), @@ -1249,8 +1263,12 @@ public static Task WriteAsync( this Stream stream, Byte[] buffer, Int32 offset, } /// - public static Task FlushAsync( this Stream stream, CancellationToken token ) + public static Task FlushAsync( + this Stream stream, + CancellationToken token + ) { + token.ThrowIfCancellationRequested(); return TaskEx.Run( () => stream.Flush(), token ); } @@ -1261,8 +1279,10 @@ public static Task AuthenticateAsClientAsync( System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation + // TODO no CancellationToken in official API but maybe we could provide it? ) { + // Bind parameters to tuple to avoid allocation of delegate class var authArgs = (stream, targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation); return Task.Factory.FromAsync( ( aArgs, cb, state ) => aArgs.stream.BeginAuthenticateAsClient( aArgs.targetHost, aArgs.clientCertificates, aArgs.enabledSslProtocols, aArgs.checkCertificateRevocation, cb, state ), @@ -1280,7 +1300,7 @@ Boolean checkCertificateRevocation /// /// This class describes which range of the contains read data, and how much of that read data has been read. /// - /// + /// public sealed class BufferAdvanceState { /// @@ -1391,7 +1411,8 @@ public static async ValueTask ReadAllBytesToBuffer( this StreamReaderWith var chunkSize = ArgumentValidator.ValidateNotNullReference( stream ).ChunkSize; if ( chunkSize > 0 ) { - while ( await stream.TryReadMoreAsync( chunkSize ) ) ; + while ( await stream.TryReadMoreAsync( chunkSize ) ) + ; // One more time, since TryReadMoreAsync returns false even if it read 1 byte less than given. await stream.TryReadMoreAsync( chunkSize ); } @@ -1421,7 +1442,8 @@ public static async ValueTask SkipThroughRemainingBytes( this StreamRea var chunkSize = ArgumentValidator.ValidateNotNullReference( stream ).ChunkSize; if ( chunkSize > 0 ) { - while ( await stream.TryReadAsync( chunkSize ) ) ; + while ( await stream.TryReadAsync( chunkSize ) ) + ; // One more time, since TryReadAsync returns false even if it read 1 byte less than given. await stream.TryReadAsync( chunkSize ); } @@ -1435,7 +1457,7 @@ public static async ValueTask SkipThroughRemainingBytes( this StreamRea /// The amount of bytes to read and append to buffer. /// Task which completes when last of the required bytes has been read into , always returning true. /// If this is null. - /// If method returns false. + /// If method returns false. public static async ValueTask ReadMoreOrThrow( this StreamReaderWithResizableBuffer stream, Int32 count ) { if ( !await ArgumentValidator.ValidateNotNullReference( stream ).TryReadMoreAsync( count ) ) @@ -1471,7 +1493,7 @@ internal static void ShiftArraySegmentLeft( this Array array, ref Int32 wholeSeg /// The amount of bytes to read and overwrite to buffer. /// Task which completes when last of the required bytes has been read into , always returning true. /// If this is null. - /// If returns false. + /// If returns false. public static async ValueTask ReadOrThrow( this StreamReaderWithResizableBuffer stream, Int32 count ) { if ( !await ArgumentValidator.ValidateNotNullReference( stream ).TryReadAsync( count ) ) @@ -1693,12 +1715,12 @@ Int32 streamReadCount } /// - /// This is helper method to call and throw and exception if false is returned. + /// This is helper method to call and throw and exception if false is returned. /// /// This . /// The amount to add to . /// If this is null. - /// If returns false for given . + /// If returns false for given . public static void Advance( this BufferAdvanceState state, Int32 amount ) { if ( !state.TryAdvance( amount ) ) @@ -1708,12 +1730,12 @@ public static void Advance( this BufferAdvanceState state, Int32 amount ) } /// - /// This is helper method to call and throw and exception if false is returned. + /// This is helper method to call and throw and exception if false is returned. /// /// This . /// The amount to add to . /// If this is null. - /// If returns false for given . + /// If returns false for given . public static void ReadMore( this BufferAdvanceState state, Int32 amount ) { if ( !state.TryReadMore( amount ) ) diff --git a/Source/Code/UtilPack/TimeComparers.cs b/Source/Code/UtilPack/TimeComparers.cs index 6a40c25..b5b00ba 100644 --- a/Source/Code/UtilPack/TimeComparers.cs +++ b/Source/Code/UtilPack/TimeComparers.cs @@ -27,24 +27,10 @@ namespace UtilPack /// public sealed class DateTimeComparer : IEqualityComparer, System.Collections.IEqualityComparer { - private static IEqualityComparer DEFAULT = null; - /// /// Gets the default comparer for , which preforms exact equality check. /// - public static IEqualityComparer Default - { - get - { - var retVal = DEFAULT; - if ( retVal == null ) - { - retVal = new DateTimeComparer( TimeSpan.Zero ); - DEFAULT = retVal; - } - return retVal; - } - } + public static IEqualityComparer Default { get; } = new DateTimeComparer( TimeSpan.Zero ); /// /// Creates a new equality comparer which will truncate both s to certain precision before performing equality check. @@ -76,7 +62,7 @@ Int32 IEqualityComparer.GetHashCode( DateTime obj ) Boolean System.Collections.IEqualityComparer.Equals( Object x, Object y ) { - return ( x == null && y == null ) || ( x is DateTime && y is DateTime && ( (IEqualityComparer) this ).Equals( (DateTime) x, (DateTime) y ) ); + return ( x == null && y == null ) || ( x is DateTime xdt && y is DateTime ydt && ( (IEqualityComparer) this ).Equals( xdt, ydt ) ); } Int32 System.Collections.IEqualityComparer.GetHashCode( Object obj ) diff --git a/Source/Code/UtilPack/UtilPack.csproj b/Source/Code/UtilPack/UtilPack.csproj index 3266c4c..aa34ef5 100644 --- a/Source/Code/UtilPack/UtilPack.csproj +++ b/Source/Code/UtilPack/UtilPack.csproj @@ -4,12 +4,6 @@ netstandard1.0;netstandard1.1;netstandard1.5;netstandard1.6;netstandard2.0;net40;net45 - - True - - latest - - $(DefineConstants);IS_NETSTANDARD @@ -25,7 +19,7 @@ - + diff --git a/Source/Tests/Tests.UtilPack/AbstractDisposable.cs b/Source/Tests/Tests.UtilPack/AbstractDisposable.cs new file mode 100644 index 0000000..af086ad --- /dev/null +++ b/Source/Tests/Tests.UtilPack/AbstractDisposable.cs @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class AbstractDisposableTests + { + [TestMethod] + public void TestThatDisposeGetsCalled() + { + var disposable = new TestDisposable(); + using ( disposable ) + { + Assert.IsFalse( disposable.Disposed ); + Assert.IsFalse( disposable.DisposeCalled ); + } + + Assert.IsTrue( disposable.Disposed ); + Assert.IsTrue( disposable.DisposeCalled ); + } + + private sealed class TestDisposable : AbstractDisposable + { + protected override void Dispose( Boolean disposing ) + { + this.DisposeCalled = true; + } + + public Boolean DisposeCalled { get; private set; } + } + + } +} diff --git a/Source/Tests/Tests.UtilPack/ArgumentValidator.cs b/Source/Tests/Tests.UtilPack/ArgumentValidator.cs new file mode 100644 index 0000000..1c4bbe6 --- /dev/null +++ b/Source/Tests/Tests.UtilPack/ArgumentValidator.cs @@ -0,0 +1,136 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class ArgumentValidatorTests + { + [TestMethod] + public void TestValidateNotNullReference() + { + var obj = new Object(); + Assert.IsTrue( ReferenceEquals( obj, ArgumentValidator.ValidateNotNullReference( obj ) ) ); + } + + [TestMethod, + ExpectedException( typeof( NullReferenceException ), ArgumentValidator.NULLREF_MESSAGE, AllowDerivedTypes = false )] + public void TestValidateNotNullReferenceWithNull() + { + ArgumentValidator.ValidateNotNullReference( null ); + } + + [TestMethod] + public void TestValidateNotNull() + { + var obj = new Object(); + Assert.IsTrue( ReferenceEquals( obj, ArgumentValidator.ValidateNotNull( nameof( obj ), obj ) ) ); + } + + private const String OBJ = "obj"; + + [TestMethod, + ExpectedException( typeof( ArgumentNullException ), OBJ, AllowDerivedTypes = false )] + public void TestValidateNotNullWithNull() + { + ArgumentValidator.ValidateNotNull( OBJ, null ); + } + + [TestMethod] + public void TestValidateNotEmptyString() + { + ArgumentValidator.ValidateNotEmpty( OBJ, "nonempty" ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentException ), OBJ + ArgumentValidator.EMPTY_STRING_SUFFIX, AllowDerivedTypes = false ) + ] + public void TestValidateNotEmptyStringWithEmptyString() + { + ArgumentValidator.ValidateNotEmpty( OBJ, "" ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentNullException ), OBJ, AllowDerivedTypes = false )] + public void TestValidateNotEmptyStringWithNullString() + { + ArgumentValidator.ValidateNotEmpty( OBJ, null ); + } + + [TestMethod] + public void TestValidateNonEmptyEnumerable() + { + ArgumentValidator.ValidateNotEmpty( OBJ, Enumerable.Repeat( new Object(), 1 ) ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentException ), OBJ + ArgumentValidator.EMPTY_SUFFIX, AllowDerivedTypes = false )] + public void TestValidateNonEmptyEnumerableWithEmptyEnumerable() + { + ArgumentValidator.ValidateNotEmpty( OBJ, Enumerable.Empty() ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentNullException ), OBJ, AllowDerivedTypes = false )] + public void TestValidateNonEmptyEnumerableWithNull() + { + ArgumentValidator.ValidateNotEmpty( OBJ, null as IEnumerable ); + } + + [TestMethod] + public void TestValidateNonEmptyArray() + { + ArgumentValidator.ValidateNotEmpty( OBJ, new[] { new Object() } ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentException ), OBJ + ArgumentValidator.EMPTY_SUFFIX, AllowDerivedTypes = false )] + public void TestValidateNonEmptyEnumerableWithEmptyArray() + { + ArgumentValidator.ValidateNotEmpty( OBJ, new Object[] { } ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentNullException ), OBJ, AllowDerivedTypes = false )] + public void TestValidateNonEmptyArrayWithNull() + { + ArgumentValidator.ValidateNotEmpty( OBJ, null as Object[] ); + } + + [TestMethod] + public void TestValidateAllNotNull() + { + ArgumentValidator.ValidateAllNotNull( OBJ, new Object[] { } ); + ArgumentValidator.ValidateAllNotNull( OBJ, new[] { new Object() } ); + } + + [TestMethod, + ExpectedException( typeof( ArgumentNullException ), AllowDerivedTypes = false )] + public void TestValidateAllNotNullWithNull() + { + ArgumentValidator.ValidateAllNotNull( OBJ, new Object[] { null } ); + } + } + +} diff --git a/Source/Tests/Tests.UtilPack/Asynchrony.cs b/Source/Tests/Tests.UtilPack/Asynchrony.cs new file mode 100644 index 0000000..129a2e6 --- /dev/null +++ b/Source/Tests/Tests.UtilPack/Asynchrony.cs @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class AsynchronyTests + { + [TestMethod, Timeout( 1500 )] + public async Task TestTimeoutAfter() + { + await Task.Delay( TimeSpan.FromMilliseconds( 1000 ) ) + .TimeoutAfter( TimeSpan.FromMilliseconds( 2000 ), default ); + } + + [TestMethod, + Timeout( 1500 ), + ExpectedException( typeof( TimeoutException ), AllowDerivedTypes = false ) + ] + public async Task TestTimeoutAfterWithExpectedException() + { + await Task.Delay( TimeSpan.FromMilliseconds( 1000 ) ) + .TimeoutAfter( TimeSpan.FromMilliseconds( 500 ), default ); + } + + [TestMethod, Timeout( 1500 )] + public async Task TestTimeoutAfterWithResult() + { + await this.DelayWithResult( TimeSpan.FromMilliseconds( 1000 ), new Object() ) + .TimeoutAfter( TimeSpan.FromMilliseconds( 2000 ), default ); + } + + [TestMethod, + Timeout( 1500 ), + ExpectedException( typeof( TimeoutException ), AllowDerivedTypes = false ) + ] + public async Task TestTimeoutAfterWithresultAndExpectedException() + { + await this.DelayWithResult( TimeSpan.FromMilliseconds( 1000 ), new Object() ) + .TimeoutAfter( TimeSpan.FromMilliseconds( 500 ), default ); + } + + private async Task DelayWithResult( TimeSpan delay, T result ) + { + await Task.Delay( delay ); + return result; + } + } +} diff --git a/Source/Tests/Tests.UtilPack/BinaryExtensions.cs b/Source/Tests/Tests.UtilPack/BinaryExtensions.cs new file mode 100644 index 0000000..79c1611 --- /dev/null +++ b/Source/Tests/Tests.UtilPack/BinaryExtensions.cs @@ -0,0 +1,296 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using Tests.UtilPack; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class BinaryExtensions + { + [TestMethod] + public void TestStreamExtensions() + { + using ( var stream = new MemoryStream( new Byte[20] ) ) + { + Assert.AreEqual( 0, stream.Position ); + stream.SeekFromBegin( 10 ); + Assert.AreEqual( 10, stream.Position ); + stream.SeekFromCurrent( 10 ); + Assert.AreEqual( 20, stream.Position ); + stream.SeekFromCurrent( -10 ); + Assert.AreEqual( 10, stream.Position ); + stream.SeekFromBegin( 0 ); + Assert.AreEqual( 0, stream.Position ); + } + } + } + + [TestClass] + public class ByteArraySerializationFuzzyTests + { + private static ByteArraySerializationFuzzyTestPerformer _performer = new ByteArraySerializationFuzzyTestPerformer(); + + [TestMethod] + public void TestSByte() + { + _performer.PerformTest( + val => unchecked((SByte) val), + UtilPackExtensions.WriteSByteToBytes, + UtilPackExtensions.ReadSByteFromBytes, + UtilPackExtensions.WriteSByteToBytesNoRef, + UtilPackExtensions.ReadSByteFromBytesNoRef + ); + } + + [TestMethod] + public void TestByte() + { + _performer.PerformTest( + val => unchecked((Byte) val), + UtilPackExtensions.WriteByteToBytes, + UtilPackExtensions.ReadByteFromBytes, + UtilPackExtensions.WriteByteToBytesNoRef, + UtilPackExtensions.ReadByteFromBytesNoRef + ); + } + + [TestMethod] + public void TestInt16() + { + _performer.PerformTest( + val => unchecked((Int16) val), + UtilPackExtensions.WriteInt16LEToBytes, + UtilPackExtensions.ReadInt16LEFromBytes, + UtilPackExtensions.WriteInt16LEToBytesNoRef, + UtilPackExtensions.ReadInt16LEFromBytesNoRef, + UtilPackExtensions.WriteInt16BEToBytes, + UtilPackExtensions.ReadInt16BEFromBytes, + UtilPackExtensions.WriteInt16BEToBytesNoRef, + UtilPackExtensions.ReadInt16BEFromBytesNoRef + ); + } + + [TestMethod] + public void TestUInt16() + { + _performer.PerformTest( + val => unchecked((UInt16) val), + UtilPackExtensions.WriteUInt16LEToBytes, + UtilPackExtensions.ReadUInt16LEFromBytes, + UtilPackExtensions.WriteUInt16LEToBytesNoRef, + UtilPackExtensions.ReadUInt16LEFromBytesNoRef, + UtilPackExtensions.WriteUInt16BEToBytes, + UtilPackExtensions.ReadUInt16BEFromBytes, + UtilPackExtensions.WriteUInt16BEToBytesNoRef, + UtilPackExtensions.ReadUInt16BEFromBytesNoRef + ); + } + + [TestMethod] + public void TestInt32() + { + _performer.PerformTest( + val => unchecked((Int32) val), + UtilPackExtensions.WriteInt32LEToBytes, + UtilPackExtensions.ReadInt32LEFromBytes, + UtilPackExtensions.WriteInt32LEToBytesNoRef, + UtilPackExtensions.ReadInt32LEFromBytesNoRef, + UtilPackExtensions.WriteInt32BEToBytes, + UtilPackExtensions.ReadInt32BEFromBytes, + UtilPackExtensions.WriteInt32BEToBytesNoRef, + UtilPackExtensions.ReadInt32BEFromBytesNoRef + ); + } + + [TestMethod] + public void TestUInt32() + { + _performer.PerformTest( + val => unchecked((UInt32) val), + UtilPackExtensions.WriteUInt32LEToBytes, + UtilPackExtensions.ReadUInt32LEFromBytes, + UtilPackExtensions.WriteUInt32LEToBytesNoRef, + UtilPackExtensions.ReadUInt32LEFromBytesNoRef, + UtilPackExtensions.WriteUInt32BEToBytes, + UtilPackExtensions.ReadUInt32BEFromBytes, + UtilPackExtensions.WriteUInt32BEToBytesNoRef, + UtilPackExtensions.ReadUInt32BEFromBytesNoRef + ); + } + + [TestMethod] + public void TestInt64() + { + _performer.PerformTest( + val => val, + UtilPackExtensions.WriteInt64LEToBytes, + UtilPackExtensions.ReadInt64LEFromBytes, + UtilPackExtensions.WriteInt64LEToBytesNoRef, + UtilPackExtensions.ReadInt64LEFromBytesNoRef, + UtilPackExtensions.WriteInt64BEToBytes, + UtilPackExtensions.ReadInt64BEFromBytes, + UtilPackExtensions.WriteInt64BEToBytesNoRef, + UtilPackExtensions.ReadInt64BEFromBytesNoRef + ); + } + + [TestMethod] + public void TestUInt64() + { + _performer.PerformTest( + val => unchecked((UInt64) val), + UtilPackExtensions.WriteUInt64LEToBytes, + UtilPackExtensions.ReadUInt64LEFromBytes, + UtilPackExtensions.WriteUInt64LEToBytesNoRef, + UtilPackExtensions.ReadUInt64LEFromBytesNoRef, + UtilPackExtensions.WriteUInt64BEToBytes, + UtilPackExtensions.ReadUInt64BEFromBytes, + UtilPackExtensions.WriteUInt64BEToBytesNoRef, + UtilPackExtensions.ReadUInt64BEFromBytesNoRef + ); + } + + [TestMethod] + public void TestDouble() + { + _performer.PerformTest( + val => BitConverter.Int64BitsToDouble( val ), + UtilPackExtensions.WriteDoubleLEToBytes, + UtilPackExtensions.ReadDoubleLEFromBytes, + UtilPackExtensions.WriteDoubleLEToBytesNoRef, + UtilPackExtensions.ReadDoubleLEFromBytesNoRef, + UtilPackExtensions.WriteDoubleBEToBytes, + UtilPackExtensions.ReadDoubleBEFromBytes, + UtilPackExtensions.WriteDoubleBEToBytesNoRef, + UtilPackExtensions.ReadDoubleBEFromBytesNoRef + ); + } + + [TestMethod] + public void TestSingle() + { + _performer.PerformTest( + val => BitConverter.Int32BitsToSingle( unchecked((Int32) val) ), + UtilPackExtensions.WriteSingleLEToBytes, + UtilPackExtensions.ReadSingleLEFromBytes, + UtilPackExtensions.WriteSingleLEToBytesNoRef, + UtilPackExtensions.ReadSingleLEFromBytesNoRef, + UtilPackExtensions.WriteSingleBEToBytes, + UtilPackExtensions.ReadSingleBEFromBytes, + UtilPackExtensions.WriteSingleBEToBytesNoRef, + UtilPackExtensions.ReadSingleBEFromBytesNoRef + ); + } + } + + public delegate Byte[] WriteWithRef( Byte[] array, ref Int32 index, T value ); + + public delegate T ReadWithRef( Byte[] array, ref Int32 index ); + + public delegate Byte[] WriteWithoutRef( Byte[] array, Int32 index, T value ); + + public delegate T ReadWithoutRef( Byte[] array, Int32 index ); + + + public sealed class ByteArraySerializationFuzzyTestPerformer + { + public ByteArraySerializationFuzzyTestPerformer( + ) + { + var array = new Byte[sizeof( Int64 )]; + + RandomNumberGenerator.Fill( array ); + this.Value = BitConverter.ToInt64( array ); + } + + public Int64 Value { get; } + + public void PerformTest( + Func convert, + WriteWithRef write, + ReadWithRef read, + WriteWithoutRef writeNoRef, + ReadWithoutRef readNoRef + ) + { + var val = convert( this.Value ); + PerformTestWithRef( val, write, read ); + PerformTestWithoutRef( val, writeNoRef, readNoRef ); + } + + private static void PerformTestWithRef( + T val, + WriteWithRef write, + ReadWithRef read + ) + { + var size = Marshal.SizeOf(); + var array = new Byte[size]; + var idx = 0; + write( array, ref idx, val ); + Assert.AreEqual( size, idx ); + idx = 0; + var deserialized = read( array, ref idx ); + Assert.AreEqual( size, idx ); + Assert.AreEqual( deserialized, val, "Value was different for methods: " + write.Method + ", " + read.Method ); + } + + private static void PerformTestWithoutRef( + T val, + WriteWithoutRef write, + ReadWithoutRef read + ) + { + var size = Marshal.SizeOf(); + var array = new Byte[size]; + var idx = 0; + write( array, idx, val ); + var deserialized = read( array, idx ); + Assert.AreEqual( deserialized, val ); + } + + } +} + +public static partial class E_UtilPack +{ + public static void PerformTest( + this ByteArraySerializationFuzzyTestPerformer performer, + Func convert, + WriteWithRef writeLE, + ReadWithRef readLE, + WriteWithoutRef writeNoRefLE, + ReadWithoutRef readNoRefLE, + WriteWithRef writeBE, + ReadWithRef readBE, + WriteWithoutRef writeNoRefBE, + ReadWithoutRef readNoRefBE + ) + { + performer.PerformTest( convert, writeLE, readLE, writeNoRefLE, readNoRefLE ); + performer.PerformTest( convert, writeBE, readBE, writeNoRefBE, readNoRefBE ); + } +} \ No newline at end of file diff --git a/Source/Tests/Tests.UtilPack/BinaryStringPool.cs b/Source/Tests/Tests.UtilPack/BinaryStringPool.cs new file mode 100644 index 0000000..3a0705f --- /dev/null +++ b/Source/Tests/Tests.UtilPack/BinaryStringPool.cs @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class BinaryStringPoolTests + { + [TestMethod] + public void TestBinaryStringPoolCaching() + { + var encoding = new UTF8Encoding( false, false ); + var pool = BinaryStringPoolFactory.NewNotConcurrentBinaryStringPool( encoding ); + var str1 = "Test"; + var str1Pooled = pool.GetString( encoding.GetBytes( str1 ) ); + Assert.AreEqual( str1, str1Pooled ); + Assert.AreNotSame( str1, str1Pooled ); + var str1PooledAgain = pool.GetString( encoding.GetBytes( str1 ) ); + Assert.AreSame( str1Pooled, str1PooledAgain ); + } + + [TestMethod] + public void TestBinaryStringPoolDifferentStrings() + { + var encoding = new UTF8Encoding( false, false ); + var pool = BinaryStringPoolFactory.NewNotConcurrentBinaryStringPool( encoding ); + var str1 = "Test"; + var str1Pooled = pool.GetString( encoding.GetBytes( str1 ) ); + Assert.AreEqual( str1, str1Pooled ); + Assert.AreNotSame( str1, str1Pooled ); + var str2 = "AnotherTest"; + var str2Pooled = pool.GetString( encoding.GetBytes( str2 ) ); + Assert.AreEqual( str2, str2Pooled ); + Assert.AreNotSame( str2, str2Pooled ); + } + + [TestMethod] + public void TestBinaryStringPoolArrayModification() + { + var encoding = new UTF8Encoding( false, false ); + var pool = BinaryStringPoolFactory.NewNotConcurrentBinaryStringPool( encoding ); + var str = "Test"; + var strBytes = encoding.GetBytes( str ); + var strPooled = pool.GetString( strBytes ); + strBytes[1] = 1; + var strPooled2 = pool.GetString( encoding.GetBytes( str ) ); + Assert.AreSame( strPooled, strPooled2 ); + } + } +} diff --git a/Source/Tests/Tests.UtilPack/Log10Test.cs b/Source/Tests/Tests.UtilPack/BinaryUtils.cs similarity index 67% rename from Source/Tests/Tests.UtilPack/Log10Test.cs rename to Source/Tests/Tests.UtilPack/BinaryUtils.cs index 018d3d9..5b46674 100644 --- a/Source/Tests/Tests.UtilPack/Log10Test.cs +++ b/Source/Tests/Tests.UtilPack/BinaryUtils.cs @@ -18,13 +18,14 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; +using System.Linq; using System.Text; using UtilPack; namespace Tests.UtilPack { [TestClass] - public class NumericTest + public class BinaryUtilsTest { [TestMethod] @@ -48,5 +49,29 @@ public void TestLog10() Assert.AreEqual( 19, BinaryUtils.Log10( 10000000000000000000UL ) ); Assert.AreEqual( 19, BinaryUtils.Log10( 18446744073709551615UL ) ); // 2^64 } + + [TestMethod] + public void TestLog2() + { + Assert.AreEqual( -1, BinaryUtils.Log2( 0 ) ); + + foreach ( var i in Enumerable.Range( 1, 31 ) ) + { + var number = unchecked((UInt32) 1 << i); + Assert.AreEqual( i, BinaryUtils.Log2( number ) ); + Assert.AreEqual( i - 1, BinaryUtils.Log2( number - 1 ) ); + } + Assert.AreEqual( 31, BinaryUtils.Log2( UInt32.MaxValue ) ); + + Assert.AreEqual( -1, BinaryUtils.Log2( 0UL ) ); + + foreach ( var i in Enumerable.Range( 1, 31 ) ) + { + var number = unchecked((UInt64) 1L << i); + Assert.AreEqual( i, BinaryUtils.Log2( number ) ); + Assert.AreEqual( i - 1, BinaryUtils.Log2( number - 1 ) ); + } + Assert.AreEqual( 63, BinaryUtils.Log2( UInt64.MaxValue ) ); + } } } diff --git a/Source/Tests/Tests.UtilPack/Empty.cs b/Source/Tests/Tests.UtilPack/Empty.cs new file mode 100644 index 0000000..1143e4b --- /dev/null +++ b/Source/Tests/Tests.UtilPack/Empty.cs @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class EmptyTests + { + [TestMethod] + public void TestEmpty() + { + Assert.AreEqual( 0, Empty.Array.Length ); + Assert.IsFalse( Empty.Enumerable.Any() ); + } + } +} diff --git a/Source/Tests/Tests.UtilPack/ResizableArray.cs b/Source/Tests/Tests.UtilPack/ResizableArray.cs new file mode 100644 index 0000000..c6693d0 --- /dev/null +++ b/Source/Tests/Tests.UtilPack/ResizableArray.cs @@ -0,0 +1,46 @@ +/* + * Copyright 2018 Stanislav Muhametsin. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; +using UtilPack; + +namespace Tests.UtilPack +{ + [TestClass] + public class ResizableArrayTests + { + + [TestMethod] + public void TestResizableArrayUsage() + { + var resizable = new ResizableArray(); + Assert.AreEqual( -1, resizable.MaximumSize ); + Assert.IsTrue( resizable.ExponentialResize ); + + Assert.AreEqual( 0, resizable.CurrentMaxCapacity ); + Assert.AreEqual( 0, resizable.Array.Length ); + + resizable.CurrentMaxCapacity = 10; + Assert.AreEqual( 10, resizable.CurrentMaxCapacity ); + Assert.AreEqual( 16, resizable.Array.Length ); + } + + } +}