diff --git a/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs b/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs new file mode 100644 index 0000000..f811d1d --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/BytesExtensions.cs @@ -0,0 +1,24 @@ +using System.IO; + +namespace System.Extensions +{ + public static class BytesExtensions + { + public static byte[] ReadAllBytes(this Stream stream) + { + if (stream is null) throw new ArgumentNullException(nameof(stream)); + + var buffer = new byte[256]; + using (MemoryStream ms = new MemoryStream()) + { + int read; + while ((read = stream.Read(buffer, 0, 256)) > 0) + { + ms.Write(buffer, 0, read); + } + + return ms.ToArray(); + } + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/CastExtensions.cs b/SystemExtensions.NetStandard/Extensions/CastExtensions.cs new file mode 100644 index 0000000..2ca904e --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/CastExtensions.cs @@ -0,0 +1,50 @@ +namespace System.Extensions +{ + public static class CastExtensions + { + public static int Floor(this double value) + { + return (int)Math.Floor(value); + } + + public static int Ceiling(this double value) + { + return (int)Math.Ceiling(value); + } + + public static int Round(this double value) + { + return (int)Math.Round(value); + } + + public static int Floor(this float value) + { + return (int)Math.Floor(value); + } + + public static int Ceiling(this float value) + { + return (int)Math.Ceiling(value); + } + + public static int Round(this float value) + { + return (int)Math.Round(value); + } + + public static int ToInt(this double value) + { + return (int)value; + } + + public static int ToInt(this float value) + { + return (int)value; + } + + public static int ToInt(this decimal value) + { + return (int)value; + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs b/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs new file mode 100644 index 0000000..d84ad93 --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/LinqExtensions.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Linq; + +namespace System.Extensions +{ + public static class LinqExtensions + { + public static bool None(this IEnumerable enumerable, Func predicate) + { + enumerable.ThrowIfNull(nameof(enumerable)); + predicate.ThrowIfNull(nameof(predicate)); + + return !enumerable.Any(predicate); + } + + public static bool None(this IEnumerable enumerable) + { + enumerable.ThrowIfNull(nameof(enumerable)); + + return !enumerable.Any(); + } + + public static ICollection ClearAnd(this ICollection collection) + { + if (collection is null) throw new ArgumentNullException(nameof(collection)); + + collection.Clear(); + return collection; + } + + public static ICollection AddRange(this ICollection collection, IEnumerable values) + { + if (collection is null) throw new ArgumentNullException(nameof(collection)); + if (values is null) throw new ArgumentNullException(nameof(values)); + + foreach(var item in values) + { + collection.Add(item); + } + + return collection; + } + + public static int IndexOfWhere(this ICollection collection, Func selector) + { + if (collection is null) throw new ArgumentNullException(nameof(collection)); + if (selector is null) throw new ArgumentNullException(nameof(selector)); + + var index = 0; + foreach (var item in collection) + { + if (selector(item)) + { + return index; + } + index++; + } + + return -1; + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs b/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..ab0594e --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/ObjectExtensions.cs @@ -0,0 +1,32 @@ +namespace System.Extensions +{ + public static class ObjectExtensions + { + public static T Cast(this object obj) + { + return (T)obj; + } + + public static T As(this object obj) where T : class + { + return obj as T; + } + + public static Optional ToOptional(this T obj) + { + return Optional.FromValue(obj); + } + + public static T ThrowIfNull([ValidatedNotNull] this T obj, string name) where T : class + { + if (obj is null) throw new ArgumentNullException(name); + + return obj; + } + + [AttributeUsage(AttributeTargets.Parameter)] + sealed class ValidatedNotNullAttribute : Attribute + { + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/Optional.cs b/SystemExtensions.NetStandard/Extensions/Optional.cs new file mode 100644 index 0000000..3e0bd87 --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/Optional.cs @@ -0,0 +1,178 @@ +namespace System.Extensions +{ + public static class Optional + { + public static Optional None() + { + return new Optional.None(); + } + + public static Optional FromValue(T value) + { + if (value == null) + { + return new Optional.None(); + } + + return new Optional.Some(value); + } + } + + public abstract class Optional : IEquatable> + { + public Optional(T value) + { + this.Value = value; + } + + private T Value { get; } + + public T ExtractValue() + { + if (this is None) + { + return default; + } + else + { + return Value; + } + } + public Optional Do(Action onSome, Action onNone) + { + if (onSome is null) throw new ArgumentNullException(nameof(onSome)); + if (onNone is null) throw new ArgumentNullException(nameof(onNone)); + + if (this is Some) + { + onSome.Invoke(this.Value); + } + else + { + onNone.Invoke(); + } + return this; + } + public Optional DoAny(Action onSome = null, Action onNone = null) + { + if (this is Some) + { + onSome?.Invoke(this.Value); + } + else + { + onNone?.Invoke(); + } + return this; + } + public Optional Switch(Func onSome, Func onNone) + { + if (onSome is null) throw new ArgumentNullException($"{nameof(onSome)}"); + if (onNone is null) throw new ArgumentNullException($"{nameof(onNone)}"); + + if (this is Some) + { + return Optional.FromValue(onSome.Invoke(this.Value)); + } + else + { + return Optional.FromValue(onNone.Invoke()); + } + } + public Optional SwitchAny(Func onSome = null, Func onNone = null) + { + if (this is Some) + { + return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V)); + } + else + { + return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V)); + } + } + + public override bool Equals(object obj) + { + if (obj is Optional) + { + return this.Equals(obj); + } + + return base.Equals(obj); + } + + public bool Equals(Optional other) + { + if (this is Some && other is Some) + { + return this.As().Equals(other.As()); + } + + return false; + } + + public static implicit operator Optional(T value) + { + return Optional.FromValue(value); + } + + public override int GetHashCode() + { + return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode(); + } + + internal class Some : Optional, IEquatable + { + public Some(T value) : base(value) + { + } + + public override bool Equals(object obj) + { + if (obj is Some) + { + return this.Equals(obj.As()); + } + + return base.Equals(obj); + } + + public bool Equals(Some other) + { + if (other is None) + { + return false; + } + + if (other is Some) + { + return this.Value.Equals(other.Value); + } + + return false; + } + + public static bool operator ==(Some left, Some right) + { + return left?.Equals(right) == true; + } + + public static bool operator !=(Some left, Some right) + { + return left?.Equals(right) != true; + } + + public override int GetHashCode() + { + return this.Value is object ? this.Value.GetHashCode() : this.As().GetHashCode(); + } + } + + internal class None : Optional + { + public None() : base(default) + { + } + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/Result.cs b/SystemExtensions.NetStandard/Extensions/Result.cs new file mode 100644 index 0000000..5246ef8 --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/Result.cs @@ -0,0 +1,185 @@ +namespace System.Extensions +{ + public class Result + { + private readonly object value; + + public Result(TSuccess successValue) + { + value = successValue; + } + public Result(TFailure failureValue) + { + value = failureValue; + } + + public bool TryExtractSuccess(out TSuccess successValue) + { + + if (value is TSuccess success) + { + successValue = success; + return true; + } + else + { + successValue = default; + return false; + } + } + public bool TryExtractFailure(out TFailure failureValue) + { + + if (value is TFailure failure) + { + failureValue = failure; + return true; + } + else + { + failureValue = default; + return false; + } + } + public Result Do(Action onSuccess, Action onFailure) + { + if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess)); + + if (onFailure is null) throw new ArgumentNullException(nameof(onFailure)); + + if (value is TSuccess) + { + onSuccess.Invoke(); + } + else if (value is TFailure) + { + onFailure.Invoke(); + } + return this; + } + public Result DoAny(Action onSuccess = null, Action onFailure = null) + { + if (value is TSuccess) + { + onSuccess?.Invoke(); + } + else if (value is TFailure) + { + onFailure?.Invoke(); + } + return this; + } + public Result Do(Action onSuccess, Action onFailure) + { + if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess)); + + if (onFailure is null) throw new ArgumentNullException(nameof(onFailure)); + + if (value is TSuccess success) + { + onSuccess.Invoke(success); + } + else if (value is TFailure failure) + { + onFailure.Invoke(failure); + } + return this; + } + public Result DoAny(Action onSuccess = null, Action onFailure = null) + { + if (value is TSuccess success) + { + onSuccess?.Invoke(success); + } + else if (value is TFailure failure) + { + onFailure?.Invoke(failure); + } + return this; + } + public T Switch(Func onSuccess, Func onFailure) + { + if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess)); + + if (onFailure is null) throw new ArgumentNullException(nameof(onFailure)); + + if (value is TSuccess success) + { + return onSuccess.Invoke(success); + } + else if (value is TFailure failure) + { + return onFailure.Invoke(failure); + } + throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); + } + public T SwitchAny(Func onSuccess = null, Func onFailure = null) + { + if (value is TSuccess success) + { + return onSuccess is null ? default : onSuccess.Invoke(success); + } + else if (value is TFailure failure) + { + return onFailure is null ? default : onFailure.Invoke(failure); + } + throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); + } + public Result Switch(Func onSuccess, Func onFailure) + { + if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess)); + + if (onFailure is null) throw new ArgumentNullException(nameof(onFailure)); + + if (value is TSuccess success) + { + return Result.Success(onSuccess.Invoke(success)); + } + else if (value is TFailure failure) + { + return Result.Failure(onFailure.Invoke(failure)); + } + throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); + } + public Result SwitchAny(Func onSuccess, Func onFailure) + { + if (value is TSuccess success) + { + return Result.Success(onSuccess is null ? default : onSuccess.Invoke(success)); + } + else if (value is TFailure failure) + { + return Result.Failure(onFailure is null ? default : onFailure.Invoke(failure)); + } + throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); + } + public Optional ToOptional() + { + if (value is TSuccess) + { + return Optional.FromValue(value.Cast()); + } + + return Optional.None(); + } + + public static implicit operator Result(TSuccess success) + { + return Success(success); + } + + public static implicit operator Result(TFailure failure) + { + return Failure(failure); + } + + public static Result Success(TSuccess value) + { + return new Result(value); + } + public static Result Failure(TFailure value) + { + return new Result(value); + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs b/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs new file mode 100644 index 0000000..db0183c --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/StreamExtensions.cs @@ -0,0 +1,40 @@ +using System.IO; + +namespace System.Extensions +{ + public static class StreamExtensions + { + public static void DoWhileReading(this Stream stream, Action action, int bufferLength = 256) + { + if (stream is null) throw new ArgumentNullException(nameof(stream)); + if (action is null) throw new ArgumentNullException(nameof(action)); + + var buffer = new byte[bufferLength]; + var read = stream.Read(buffer, 0, bufferLength); + while(read > 0) + { + action(bufferLength, buffer); + read = stream.Read(buffer, 0, bufferLength); + } + } + + public static byte[] ReadBytes(this Stream stream, int count) + { + if (stream is null) throw new ArgumentNullException(nameof(stream)); + + var buffer = new byte[count]; + stream.Read(buffer, 0, count); + return buffer; + } + + public static Stream Rewind(this Stream stream) + { + if (stream is null) throw new ArgumentNullException(nameof(stream)); + + if (!stream.CanSeek) throw new InvalidOperationException("Stream doesn't support rewinding"); + + stream.Seek(0, SeekOrigin.Begin); + return stream; + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/StringExtensions.cs b/SystemExtensions.NetStandard/Extensions/StringExtensions.cs new file mode 100644 index 0000000..15317f9 --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/StringExtensions.cs @@ -0,0 +1,17 @@ +using System.Text; + +namespace System.Extensions +{ + public static class StringExtensions + { + public static byte[] GetBytes(this string s) + { + return Encoding.UTF8.GetBytes(s); + } + + public static string GetString(this byte[] bytes) + { + return Encoding.UTF8.GetString(bytes); + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs b/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs new file mode 100644 index 0000000..3e9e9ce --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/TaskExtensions.cs @@ -0,0 +1,180 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Extensions +{ + public static class TaskExtensions + { + /// + /// Mark task as . + /// + /// Result type. + /// Task. + /// The started + public static Task LongRunning(this Task task) + { + return Task.Factory.StartNew(async () => + { + return await task; + }, TaskCreationOptions.LongRunning).Unwrap(); + } + + /// + /// Mark task as . + /// + /// Task. + /// The started + public static Task LongRunning(this Task task) + { + return Task.Factory.StartNew(async () => + { + await task; + }, TaskCreationOptions.LongRunning).Unwrap(); + } + + /// + /// Execute action periodically and asynchronously. + /// + /// Action to be executed. + /// Time to pass before starting to execute. + /// Interval between procs. + /// Cancellation token used to cancel the cycle. + /// + public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token) + { + if (dueTime > TimeSpan.Zero) + await Task.Delay(dueTime, token).ConfigureAwait(false); + + while (!token.IsCancellationRequested) + { + onTick?.Invoke(); + if (interval > TimeSpan.Zero) + await Task.Delay(interval, token).ConfigureAwait(false); + } + } + + /// + /// Execute's an async Task method which has a void return value synchronously + /// + /// Task method to execute + public static void RunSync(this Func task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + synch.Post(async _ => + { + try + { + await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + + SynchronizationContext.SetSynchronizationContext(oldContext); + } + + /// + /// Execute's an async Task method which has a T return type synchronously + /// + /// Return Type + /// Task method to execute + /// + public static T RunSync(this Func> task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + T ret = default(T); + synch.Post(async _ => + { + try + { + ret = await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + SynchronizationContext.SetSynchronizationContext(oldContext); + return ret; + } + + private class ExclusiveSynchronizationContext : SynchronizationContext + { + private bool done; + public Exception InnerException { get; set; } + readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); + readonly Queue> items = + new Queue>(); + + public override void Send(SendOrPostCallback d, object state) + { + throw new NotSupportedException("We cannot send to our same thread"); + } + + public override void Post(SendOrPostCallback d, object state) + { + lock (items) + { + items.Enqueue(Tuple.Create(d, state)); + } + workItemsWaiting.Set(); + } + + public void EndMessageLoop() + { + Post(_ => done = true, null); + } + + public void BeginMessageLoop() + { + while (!done) + { + Tuple task = null; + lock (items) + { + if (items.Count > 0) + { + task = items.Dequeue(); + } + } + if (task != null) + { + task.Item1(task.Item2); + if (InnerException != null) // the method threw an exeption + { + throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); + } + } + else + { + workItemsWaiting.WaitOne(); + } + } + } + + public override SynchronizationContext CreateCopy() + { + return this; + } + } + } +} diff --git a/SystemExtensions.NetStandard/Extensions/Try.cs b/SystemExtensions.NetStandard/Extensions/Try.cs new file mode 100644 index 0000000..5cba3e2 --- /dev/null +++ b/SystemExtensions.NetStandard/Extensions/Try.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; + +namespace System.Extensions +{ + public static class Try + { + public static Try Action(Func act) + { + return new Try(act); + } + } + public class Try + { + private readonly Func action; + private readonly List> catchActions = new List>(); + internal Try(Func action) + { + this.action = action; + } + public static Try Action(Func act) + { + return new Try(act); + } + + public Try Catch(Func act) where TException : Exception + { + this.catchActions.Add((Func)act); + return this; + } + + public TResult Run() + { + try + { + return action(); + } + catch (Exception ex) + { + foreach (var catchAction in this.catchActions) + { + return catchAction(ex); + } + throw; + } + } + + public TResult Finally(Action act) + { + if (act is null) throw new ArgumentNullException(nameof(act)); + + try + { + return this.action(); + } + catch (Exception ex) + { + foreach (var catchAction in this.catchActions) + { + return catchAction(ex); + } + throw; + } + finally + { + act(); + } + } + } +} diff --git a/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj b/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj index 0d0fbb0..60731bf 100644 --- a/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj +++ b/SystemExtensions.NetStandard/SystemExtensions.NetStandard.csproj @@ -5,6 +5,8 @@ true LICENSE true + System + 1.1 diff --git a/SystemExtensionsTests/Collections/AVLTreeTests.cs b/SystemExtensionsTests/Collections/AVLTreeTests.cs index aa7a62d..c1a044f 100644 --- a/SystemExtensionsTests/Collections/AVLTreeTests.cs +++ b/SystemExtensionsTests/Collections/AVLTreeTests.cs @@ -1,10 +1,9 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; -namespace SystemExtensions.Collections.Tests +namespace System.Collections.Tests { [TestClass()] public class AVLTreeTests diff --git a/SystemExtensionsTests/Collections/BinaryHeapTests.cs b/SystemExtensionsTests/Collections/BinaryHeapTests.cs index 54d22c2..8abb4dc 100644 --- a/SystemExtensionsTests/Collections/BinaryHeapTests.cs +++ b/SystemExtensionsTests/Collections/BinaryHeapTests.cs @@ -1,13 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System; using System.Runtime.Serialization.Formatters.Binary; -using System.Xml.Serialization; using System.IO; namespace System.Collections.Tests diff --git a/SystemExtensionsTests/Collections/FibonacciHeapTests.cs b/SystemExtensionsTests/Collections/FibonacciHeapTests.cs index bfc16f5..8090f97 100644 --- a/SystemExtensionsTests/Collections/FibonacciHeapTests.cs +++ b/SystemExtensionsTests/Collections/FibonacciHeapTests.cs @@ -1,11 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Threading; using System.Runtime.Serialization.Formatters.Binary; using System.IO; diff --git a/SystemExtensionsTests/Collections/PriorityQueueTests.cs b/SystemExtensionsTests/Collections/PriorityQueueTests.cs index 6e30ae4..9e7fa4f 100644 --- a/SystemExtensionsTests/Collections/PriorityQueueTests.cs +++ b/SystemExtensionsTests/Collections/PriorityQueueTests.cs @@ -1,11 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System; using System.Runtime.Serialization.Formatters.Binary; using System.IO; diff --git a/SystemExtensionsTests/Collections/SkipListTests.cs b/SystemExtensionsTests/Collections/SkipListTests.cs index 7cc4a8c..ad5de4a 100644 --- a/SystemExtensionsTests/Collections/SkipListTests.cs +++ b/SystemExtensionsTests/Collections/SkipListTests.cs @@ -1,10 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Runtime.Serialization.Formatters.Binary; using System.IO; diff --git a/SystemExtensionsTests/Collections/TreapTests.cs b/SystemExtensionsTests/Collections/TreapTests.cs index bf0d808..c1e8d29 100644 --- a/SystemExtensionsTests/Collections/TreapTests.cs +++ b/SystemExtensionsTests/Collections/TreapTests.cs @@ -1,10 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Runtime.Serialization.Formatters.Binary; using System.IO; diff --git a/SystemExtensionsTests/Extensions/OptionalTests.cs b/SystemExtensionsTests/Extensions/OptionalTests.cs new file mode 100644 index 0000000..747dbd6 --- /dev/null +++ b/SystemExtensionsTests/Extensions/OptionalTests.cs @@ -0,0 +1,111 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace System.Extensions.Tests +{ + [TestClass] + public class OptionalTests + { + [TestMethod] + public void SomeValueShouldEqualOptional() + { + var value = string.Empty; + var optional = value.ToOptional(); + + Assert.IsTrue(optional.Equals(value)); + } + + [TestMethod] + public void OptionalFromNullShouldNotEqual() + { + object value = null; + var optional = value.ToOptional(); + + Assert.IsFalse(optional.Equals(value)); + } + + [TestMethod] + public void OptionalFromValueShouldBeSome() + { + var optional = Optional.FromValue(new object()); + + optional.DoAny( + onNone: () => throw new InvalidOperationException()); + } + + [TestMethod] + public void OptionalFromNullShouldBeNone() + { + var optional = Optional.FromValue(null); + + optional.DoAny( + onSome: _ => throw new InvalidOperationException()); + } + + [TestMethod] + public void DoShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); + + optional.Do( + onSome: _ => { }, + onNone: () => throw new InvalidOperationException()); + + nullOptional.Do( + onSome: _ => throw new InvalidOperationException(), + onNone: () => { }); + } + + [TestMethod] + public void DoAnyShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); + + optional.DoAny( + onNone: () => throw new InvalidOperationException()); + + nullOptional.DoAny( + onSome: _ => throw new InvalidOperationException()); + } + + [TestMethod] + public void SwitchShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); + + var newValue = optional.Switch( + onSome: _ => string.Empty, + onNone: () => throw new InvalidOperationException()) + .ExtractValue(); + + var newNullValue = nullOptional.Switch( + onSome: _ => throw new InvalidOperationException(), + onNone: () => null) + .ExtractValue(); + + newValue.Should().Be(string.Empty); + newNullValue.Should().Be(null); + } + + [TestMethod] + public void SwitchAnyShouldExecute() + { + var optional = Optional.FromValue(string.Empty); + var nullOptional = Optional.FromValue(null); + + var newValue = optional.SwitchAny( + onSome: _ => string.Empty) + .ExtractValue(); + + var newNullValue = nullOptional.SwitchAny( + onNone: () => null) + .ExtractValue(); + + newValue.Should().Be(string.Empty); + newNullValue.Should().Be(null); + } + } +} diff --git a/SystemExtensionsTests/Extensions/ResultTests.cs b/SystemExtensionsTests/Extensions/ResultTests.cs new file mode 100644 index 0000000..828aee5 --- /dev/null +++ b/SystemExtensionsTests/Extensions/ResultTests.cs @@ -0,0 +1,117 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace System.Extensions.Tests +{ + [TestClass] + public class ResultTests + { + [TestMethod] + public void SuccessResultShouldCreateFromSuccess() + { + var success = string.Empty; + var result = Result.Success(success); + + result.DoAny( + onFailure: () => throw new InvalidOperationException()); + } + + [TestMethod] + public void FailureResultShouldCreateFromFailure() + { + var failure = new object(); + var result = Result.Failure(failure); + + result.DoAny( + onSuccess: () => throw new InvalidOperationException()); + } + + [TestMethod] + public void DoShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); + + var failure = new object(); + var failedResult = Result.Failure(failure); + + successResult.Do( + onSuccess: _ => { }, + onFailure: _ => throw new InvalidOperationException()); + + failedResult.Do( + onSuccess: _ => throw new InvalidOperationException(), + onFailure: _ => { }); + } + + [TestMethod] + public void DoAnyShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); + + var failure = new object(); + var failedResult = Result.Failure(failure); + + successResult.DoAny( + onSuccess: _ => { }); + + failedResult.DoAny( + onFailure: _ => { }); + } + + [TestMethod] + public void SwitchShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); + + var failure = new object(); + var failedResult = Result.Failure(failure); + + var successSwitch = successResult.Switch( + onSuccess: _ => string.Empty, + onFailure: _ => throw new InvalidOperationException()); + + var failedSwitch = failedResult.Switch( + onSuccess: _ => throw new InvalidOperationException(), + onFailure: _ => string.Empty); + + success.Should().Be(failedSwitch); + } + + [TestMethod] + public void SwitchAnyShouldExecute() + { + var success = string.Empty; + var successResult = Result.Success(success); + + var failure = new object(); + var failedResult = Result.Failure(failure); + + var successSwitch = successResult.SwitchAny( + onSuccess: _ => string.Empty); + + var failedSwitch = failedResult.SwitchAny( + onFailure: _ => string.Empty); + + success.Should().Be(failedSwitch); + } + + [TestMethod] + public void ToOptionalShouldConvert() + { + var success = string.Empty; + var successResult = Result.Success(success); + + var failure = new object(); + var failedResult = Result.Failure(failure); + + var successOptional = successResult.ToOptional(); + var failureOptional = failedResult.ToOptional(); + + successOptional.Should().NotBeNull(); + failureOptional.Should().NotBeNull(); + } + } +} diff --git a/SystemExtensionsTests/Structures/Int32BitStructTests.cs b/SystemExtensionsTests/Structures/Int32BitStructTests.cs index 321c84e..ff3066d 100644 --- a/SystemExtensionsTests/Structures/Int32BitStructTests.cs +++ b/SystemExtensionsTests/Structures/Int32BitStructTests.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Structures.BitStructures; -namespace SystemExtensionsTests.Structures +namespace System.Structures.BitStructures.Tests { [TestClass] public class Int32BitStructTests diff --git a/SystemExtensionsTests/Structures/Int64BitStructTests.cs b/SystemExtensionsTests/Structures/Int64BitStructTests.cs index f2e5daa..76bb945 100644 --- a/SystemExtensionsTests/Structures/Int64BitStructTests.cs +++ b/SystemExtensionsTests/Structures/Int64BitStructTests.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Structures.BitStructures; -namespace SystemExtensionsTests.Structures +namespace System.Structures.BitStructures.Tests { [TestClass] public class Int64BitStructTests diff --git a/SystemExtensionsTests/SystemExtensionsTests.csproj b/SystemExtensionsTests/SystemExtensionsTests.csproj index 3d3224d..22244c8 100644 --- a/SystemExtensionsTests/SystemExtensionsTests.csproj +++ b/SystemExtensionsTests/SystemExtensionsTests.csproj @@ -1,6 +1,6 @@  - + Debug AnyCPU @@ -39,14 +39,26 @@ 4 + + ..\packages\FluentAssertions.6.0.0-alpha0002\lib\net47\FluentAssertions.dll + - ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + ..\packages\MSTest.TestFramework.2.2.3\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll - ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + ..\packages\MSTest.TestFramework.2.2.3\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0-preview.2.21154.6\lib\net45\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + @@ -63,12 +75,15 @@ + + + @@ -101,10 +116,10 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + + - +