diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index dab16c723..1434359fd 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,10 +3,16 @@
"isRoot": true,
"tools": {
"dotnet-t4": {
- "version": "2.0.5",
+ "version": "2.3.0",
"commands": [
"t4"
]
+ },
+ "dotnet-reportgenerator-globaltool": {
+ "version": "5.1.11",
+ "commands": [
+ "reportgenerator"
+ ]
}
}
}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
index 43ffc671d..46779ac64 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,13 +1,59 @@
+# http://editorconfig.org/
+
root = true
[*]
+indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
-[*.xml]
-indent_style = space
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
+indent_size = 2
+
+[*.Build.{props,targets}]
+indent_size = 2
+
+[*.{sln}]
+indent_style = tab
+
+[*.{json,yml}]
+indent_size = 2
[*.{cs,tt}]
charset = utf-8
indent_style = space
indent_size = 4
+max_line_length = 100
+
+[*.cs]
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = true:suggestion
+
+# Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+
+# Spacing
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+
+# Wrapping
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
diff --git a/.gitignore b/.gitignore
index cc7e1a503..68976a434 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+*.opencover.xml
+**/TestResults/
+
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 7bafdbf6b..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-language: csharp
-os:
- - linux
- - osx
-osx_image: xcode9.4
-solution: MoreLinq.sln
-mono: 5.0.1
-dist: xenial
-sudo: required
-dotnet: 3.0.100
-env:
- - CONFIGURATION=Debug
- - CONFIGURATION=Release
-addons:
- apt:
- sources:
- - sourceline: 'deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main'
- key_url: 'https://packages.microsoft.com/keys/microsoft.asc'
- packages:
- - dotnet-runtime-2.1
-
-before_install:
- - |
- if [ "$TRAVIS_OS_NAME" == "osx" ] || [ `uname` == "Darwin" ]; then
- # Handle too many files on OS X
- ulimit -n 4096
- # Install dotnet core 2.1 runtime
- wget --retry-connrefused --waitretry=1 -O /tmp/dn21.pkg 'https://download.visualstudio.microsoft.com/download/pr/9314da31-774c-4d2b-8743-998f2a21f5ab/bc918ca05ab6b650f2991b205c04f623/dotnet-runtime-2.1.13-osx-x64.pkg'
- sudo installer -pkg /tmp/dn21.pkg -target /
- fi
- - dotnet --info
-
-install:
- - npm install -g eclint
-
-before_script:
- - git rm .editorconfig
- - eclint check -n "**/*.{cs,tt,cmd,sh,md,txt,yml}"
- - eclint check -w "**/*.{cs,tt,cmd,sh,md,txt,yml,json,sln,csproj,shfbproj}"
- - git reset --hard
-
-script:
- - |
- if grep --extended-regexp '^[[:space:]]*using[[:space:]]+System\.Linq;' $(ls MoreLinq.Test/*Test.cs); then
- echo "System.Linq import found, failing the build!" >&2
- exit 1
- fi
- - ./build.sh $CONFIGURATION
- - dotnet exec MoreLinq.Test/bin/$CONFIGURATION/netcoreapp2.1/MoreLinq.Test.dll
- - dotnet exec MoreLinq.Test/bin/$CONFIGURATION/netcoreapp3.0/MoreLinq.Test.dll
- - mono MoreLinq.Test/bin/$CONFIGURATION/net451/MoreLinq.Test.exe
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..0b85fe477
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,9 @@
+
+
+ 11
+ enable
+ true
+ 7.0-all
+ true
+
+
diff --git a/MoreLinq.Test/.editorconfig b/MoreLinq.Test/.editorconfig
new file mode 100644
index 000000000..cc328a0d1
--- /dev/null
+++ b/MoreLinq.Test/.editorconfig
@@ -0,0 +1,28 @@
+[*.cs]
+
+# CA1034: Nested types should not be visible
+dotnet_diagnostic.CA1034.severity = none
+
+# CA1062: Validate arguments of public methods
+dotnet_diagnostic.CA1062.severity = none
+
+# CA1825: Avoid zero-length array allocations
+dotnet_diagnostic.CA1825.severity = suggestion
+
+# CA1032: Implement standard exception constructors
+dotnet_diagnostic.CA1032.severity = none
+
+# CA1064: Exceptions should be public
+dotnet_diagnostic.CA1064.severity = none
+
+# CA1303: Do not pass literals as localized parameters
+dotnet_diagnostic.CA1303.severity = none
+
+# CA5394: Do not use insecure randomness
+dotnet_diagnostic.CA5394.severity = none
+
+# CA1707: Identifiers should not contain underscores
+dotnet_diagnostic.CA1707.severity = none
+
+# CA1308: Normalize strings to uppercase
+dotnet_diagnostic.CA1308.severity = none
diff --git a/MoreLinq.Test/AcquireTest.cs b/MoreLinq.Test/AcquireTest.cs
index 119d4c3e4..18050ed78 100644
--- a/MoreLinq.Test/AcquireTest.cs
+++ b/MoreLinq.Test/AcquireTest.cs
@@ -1,6 +1,6 @@
#region License and Terms
// MoreLINQ - Extensions to LINQ to Objects
-// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+// Copyright (c) 2012 Atif Aziz. 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.
@@ -26,9 +26,9 @@ public class AcquireTest
[Test]
public void AcquireAll()
{
- Disposable a = null;
- Disposable b = null;
- Disposable c = null;
+ Disposable? a = null;
+ Disposable? b = null;
+ Disposable? c = null;
var allocators = MoreEnumerable.From(() => a = new Disposable(),
() => b = new Disposable(),
@@ -48,16 +48,16 @@ public void AcquireAll()
[Test]
public void AcquireSome()
{
- Disposable a = null;
- Disposable b = null;
- Disposable c = null;
+ Disposable? a = null;
+ Disposable? b = null;
+ Disposable? c = null;
var allocators = MoreEnumerable.From(() => a = new Disposable(),
() => b = new Disposable(),
() => throw new TestException(),
() => c = new Disposable());
- Assert.Throws(() => allocators.Acquire());
+ Assert.That(allocators.Acquire, Throws.TypeOf());
Assert.That(a, Is.Not.Null);
Assert.That(a.Disposed, Is.True);
@@ -66,7 +66,7 @@ public void AcquireSome()
Assert.That(c, Is.Null);
}
- class Disposable : IDisposable
+ sealed class Disposable : IDisposable
{
public bool Disposed { get; private set; }
public void Dispose() { Disposed = true; }
diff --git a/MoreLinq.Test/AggregateRightTest.cs b/MoreLinq.Test/AggregateRightTest.cs
index 0d3aa62af..7ecd4825e 100644
--- a/MoreLinq.Test/AggregateRightTest.cs
+++ b/MoreLinq.Test/AggregateRightTest.cs
@@ -17,7 +17,6 @@
namespace MoreLinq.Test
{
- using System;
using NUnit.Framework;
[TestFixture]
@@ -28,8 +27,8 @@ public class AggregateRightTest
[Test]
public void AggregateRightWithEmptySequence()
{
- Assert.Throws(
- () => new int[0].AggregateRight((a, b) => a + b));
+ Assert.That(() => new int[0].AggregateRight((a, b) => a + b),
+ Throws.InvalidOperationException);
}
[Test]
@@ -47,9 +46,9 @@ public void AggregateRightFuncIsNotInvokedOnSingleElementSequence()
[TestCase(SourceKind.Sequence)]
public void AggregateRight(SourceKind sourceKind)
{
- var enumerable = Enumerable.Range(1, 5).Select(x => x.ToString()).ToSourceKind(sourceKind);
+ var enumerable = Enumerable.Range(1, 5).Select(x => x.ToInvariantString()).ToSourceKind(sourceKind);
- var result = enumerable.AggregateRight((a, b) => string.Format("({0}+{1})", a, b));
+ var result = enumerable.AggregateRight((a, b) => $"({a}+{b})");
Assert.That(result, Is.EqualTo("(1+(2+(3+(4+5))))"));
}
@@ -61,7 +60,7 @@ public void AggregateRight(SourceKind sourceKind)
[TestCase(true)]
public void AggregateRightSeedWithEmptySequence(object defaultValue)
{
- Assert.That(new int[0].AggregateRight(defaultValue, (a, b) => b), Is.EqualTo(defaultValue));
+ Assert.That(new int[0].AggregateRight(defaultValue, (_, b) => b), Is.EqualTo(defaultValue));
}
[Test]
@@ -78,7 +77,7 @@ public void AggregateRightSeedFuncIsNotInvokedOnEmptySequence()
public void AggregateRightSeed()
{
var result = Enumerable.Range(1, 4)
- .AggregateRight("5", (a, b) => string.Format("({0}+{1})", a, b));
+ .AggregateRight("5", (a, b) => $"({a}+{b})");
Assert.That(result, Is.EqualTo("(1+(2+(3+(4+5))))"));
}
@@ -90,14 +89,14 @@ public void AggregateRightSeed()
[TestCase(true)]
public void AggregateRightResultorWithEmptySequence(object defaultValue)
{
- Assert.That(new int[0].AggregateRight(defaultValue, (a, b) => b, a => a == defaultValue), Is.EqualTo(true));
+ Assert.That(new int[0].AggregateRight(defaultValue, (_, b) => b, a => a == defaultValue), Is.EqualTo(true));
}
[Test]
public void AggregateRightResultor()
{
var result = Enumerable.Range(1, 4)
- .AggregateRight("5", (a, b) => string.Format("({0}+{1})", a, b), a => a.Length);
+ .AggregateRight("5", (a, b) => $"({a}+{b})", a => a.Length);
Assert.That(result, Is.EqualTo("(1+(2+(3+(4+5))))".Length));
}
diff --git a/MoreLinq.Test/AggregateTest.cs b/MoreLinq.Test/AggregateTest.cs
index 55b531658..d9cf0e6fb 100644
--- a/MoreLinq.Test/AggregateTest.cs
+++ b/MoreLinq.Test/AggregateTest.cs
@@ -26,6 +26,7 @@ namespace MoreLinq.Test
using System.Reactive.Linq;
using System.Reflection;
using NUnit.Framework.Interfaces;
+ using static FuncModule;
[TestFixture]
public class AggregateTest
@@ -51,8 +52,8 @@ from m in typeof(MoreEnumerable).GetMethods(BindingFlags.Public | BindingFlags.S
Source = source,
Expectation = sum,
Instantiation = m.MakeGenericMethod(Enumerable.Repeat(typeof(int), m.GetGenericArguments().Length - 1)
- .Append(typeof(int[])) // TResult
- .ToArray()),
+ .Append(typeof(int[])) // TResult
+ .ToArray()),
}
into m
let rst = m.Instantiation.GetParameters().Last().ParameterType
@@ -64,10 +65,11 @@ into m
AccumulatorCount = (m.Instantiation.GetParameters().Length - 2 /* source + resultSelector */) / 2 /* seed + accumulator */,
ResultSelectorType = rst,
Parameters =
- rst.GetMethod("Invoke")
- .GetParameters()
- .Select(p => Expression.Parameter(p.ParameterType))
- .ToArray(),
+ rst.GetMethod("Invoke") is { } invoke
+ ? invoke.GetParameters()
+ .Select(p => Expression.Parameter(p.ParameterType))
+ .ToArray()
+ : throw new MissingMethodException("""Method "Invoke" not found."""),
}
into m
let resultSelector =
@@ -75,7 +77,7 @@ into m
Expression.NewArrayInit(typeof(int), m.Parameters),
m.Parameters)
.Compile()
- let accumulator = new Func((s, n) => s + n)
+ let accumulator = Func((int s, int n) => s + n)
select new
{
Name = $"{name}({m.AccumulatorCount})",
@@ -95,7 +97,7 @@ into t
select new TestCaseData(t.Method, t.Args).SetName(t.Name).Returns(t.Expectation);
[TestCaseSource(nameof(AccumulatorsTestSource), new object[] { nameof(Accumulators), 10 })]
- public object Accumulators(MethodInfo method, object[] args) =>
+ public object? Accumulators(MethodInfo method, object[] args) =>
method.Invoke(null, args);
[Test]
@@ -110,8 +112,8 @@ public void SevenUniqueAccumulators()
0, (s, e) => s + e.Num,
0, (s, e) => e.Num % 2 == 0 ? s + e.Num : s,
0, (s, _) => s + 1,
- (int?)null, (s, e) => s is int n ? Math.Min(n, e.Num) : e.Num,
- (int?)null, (s, e) => s is int n ? Math.Max(n, e.Num) : e.Num,
+ (int?)null, (s, e) => s is {} n ? Math.Min(n, e.Num) : e.Num,
+ (int?)null, (s, e) => s is {} n ? Math.Max(n, e.Num) : e.Num,
new HashSet(), (s, e) => { s.Add(e.Str.Length); return s; },
new List<(int Num, string Str)>(), (s, e) => { s.Add((e.Num, e.Str)); return s; },
(sum, esum, count, min, max, lengths, items) => new
@@ -120,8 +122,8 @@ public void SevenUniqueAccumulators()
EvenSum = esum,
Count = count,
Average = (double)sum / count,
- Min = min is int mn ? mn : throw new InvalidOperationException(),
- Max = max is int mx ? mx : throw new InvalidOperationException(),
+ Min = min ?? throw new InvalidOperationException(),
+ Max = max ?? throw new InvalidOperationException(),
UniqueLengths = lengths,
Items = items,
}
diff --git a/MoreLinq.Test/AppendTest.cs b/MoreLinq.Test/AppendTest.cs
index df46b13c7..580a74875 100644
--- a/MoreLinq.Test/AppendTest.cs
+++ b/MoreLinq.Test/AppendTest.cs
@@ -46,7 +46,7 @@ public void AppendWithEmptyHeadSequence()
public void AppendWithNullTail()
{
var head = new[] { "first", "second" };
- string tail = null;
+ string? tail = null;
var whole = head.Append(tail);
whole.AssertSequenceEqual("first", "second", null);
}
diff --git a/MoreLinq.Test/AssertCountTest.cs b/MoreLinq.Test/AssertCountTest.cs
index 2a05912f8..2a6e5ddf3 100644
--- a/MoreLinq.Test/AssertCountTest.cs
+++ b/MoreLinq.Test/AssertCountTest.cs
@@ -1,6 +1,6 @@
#region License and Terms
// MoreLINQ - Extensions to LINQ to Objects
-// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
+// Copyright (c) 2009 Atif Aziz. 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.
@@ -27,10 +27,10 @@ public class AssertCountTest
public void AssertCountNegativeCount()
{
var source = new object[0];
- AssertThrowsArgument.OutOfRangeException("count", () =>
- source.AssertCount(-1));
- AssertThrowsArgument.OutOfRangeException("count", () =>
- source.AssertCount(-1, BreakingFunc.Of()));
+ Assert.That(() => source.AssertCount(-1),
+ Throws.ArgumentOutOfRangeException("count"));
+ Assert.That(() => source.AssertCount(-1, BreakingFunc.Of()),
+ Throws.ArgumentOutOfRangeException("count"));
}
[Test]
@@ -42,46 +42,51 @@ public void AssertCountSequenceWithMatchingLength()
[Test]
public void AssertCountShortSequence()
{
- Assert.Throws(() =>
- "foo,bar,baz".GenerateSplits(',').AssertCount(4).Consume());
+ Assert.That(() => "foo,bar,baz".GenerateSplits(',').AssertCount(4).Consume(),
+ Throws.TypeOf());
}
[Test]
public void AssertCountLongSequence()
{
- Assert.Throws(() =>
- "foo,bar,baz".GenerateSplits(',').AssertCount(2).Consume());
+ Assert.That(() => "foo,bar,baz".GenerateSplits(',').AssertCount(2).Consume(),
+ Throws.TypeOf());
}
- [Test]
- public void AssertCountDefaultExceptionMessageVariesWithCase()
+ [TestCase("", 1, "Sequence contains too few elements when exactly 1 was expected.")]
+ [TestCase("foo,bar,baz", 1, "Sequence contains too many elements when exactly 1 was expected.")]
+ [TestCase("foo,bar,baz", 4, "Sequence contains too few elements when exactly 4 were expected.")]
+ [TestCase("foo,bar,baz", 2, "Sequence contains too many elements when exactly 2 were expected.")]
+ public void AssertCountDefaultExceptionMessageVariesWithCase(string str, int count, string expectedMessage)
{
- var tokens = "foo,bar,baz".GenerateSplits(',');
- var e1 = Assert.Throws(() => tokens.AssertCount(4).Consume());
- var e2 = Assert.Throws(() => tokens.AssertCount(2).Consume());
- Assert.That(e1.Message, Is.Not.EqualTo(e2.Message));
+ var tokens = str.GenerateSplits(',')
+ .Where(t => t.Length > 0)
+ .AssertCount(count);
+
+ Assert.That(() => tokens.Consume(),
+ Throws.TypeOf().With.Message.EqualTo(expectedMessage));
}
[Test]
public void AssertCountLongSequenceWithErrorSelector()
{
- var e =
- Assert.Throws(() =>
- "foo,bar,baz".GenerateSplits(',').AssertCount(2, (cmp, count) => new TestException(cmp, count))
- .Consume());
- Assert.That(e.Cmp, Is.GreaterThan(0));
- Assert.That(e.Count, Is.EqualTo(2));
+ Assert.That(() =>
+ "foo,bar,baz".GenerateSplits(',').AssertCount(2, (cmp, count) => new TestException(cmp, count))
+ .Consume(),
+ Throws.TypeOf()
+ .With.Property(nameof(TestException.Cmp)).GreaterThan(0)
+ .And.Count.EqualTo(2));
}
[Test]
public void AssertCountShortSequenceWithErrorSelector()
{
- var e =
- Assert.Throws(() =>
- "foo,bar,baz".GenerateSplits(',').AssertCount(4, (cmp, count) => new TestException(cmp, count))
- .Consume());
- Assert.That(e.Cmp, Is.LessThan(0));
- Assert.That(e.Count, Is.EqualTo(4));
+ Assert.That(() =>
+ "foo,bar,baz".GenerateSplits(',').AssertCount(4, (cmp, count) => new TestException(cmp, count))
+ .Consume(),
+ Throws.TypeOf()
+ .With.Property(nameof(TestException.Cmp)).LessThan(0)
+ .And.Count.EqualTo(4));
}
sealed class TestException : Exception
@@ -105,14 +110,14 @@ public void AssertCountIsLazy()
[Test]
public void AssertCountWithCollectionIsLazy()
{
- new BreakingCollection