Skip to content

Commit cac287f

Browse files
committed
Implemented #312
* Added support for conversion of mixed line endings - This is now the default behavior, explicit conversion is still possible by specifying the source kind directly. - This is ONLY allowed on the source of normalization as it is not sensible for a destination. * Added tests for `Ubiquity.NET.Extensions` to verify new behavior and test existing behavior.
1 parent 8f8d9bd commit cac287f

13 files changed

Lines changed: 513 additions & 27 deletions
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
using System.Runtime.InteropServices;
5+
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
8+
// In SDK-style projects such as this one, several assembly attributes that were historically
9+
// defined in this file are now automatically added during build and populated with
10+
// values defined in project properties. For details of which attributes are included
11+
// and how to customise this process see: https://aka.ms/assembly-info-properties
12+
13+
// Setting ComVisible to false makes the types in this assembly not visible to COM
14+
// components. If you need to access a type in this assembly from COM, set the ComVisible
15+
// attribute to true on that type.
16+
17+
[assembly: ComVisible(false)]
18+
19+
// The following GUID is for the ID of the typelib if this project is exposed to COM.
20+
21+
[assembly: Guid("312c3354-ea8c-4819-8823-ac78064c645c")]
22+
23+
// Tests are so trivial they perform better when not individually parallelized.
24+
// Unfortunately this is an assembly wide choice and not class or method level
25+
// see: https://github.com/microsoft/testfx/issues/5555#issuecomment-3448956323
26+
[assembly: Parallelize( Scope = ExecutionScope.ClassLevel )]
27+
28+
// NOTE: use of this and `internal` test classes results in a flurry of
29+
// error CA1812: '<class name>' is an internal class that is apparently never instantiated. If so, remove the code from the assembly. If this class is intended to contain only static members, make it 'static' (Module in Visual Basic). (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1812)
30+
// In other words, not worth the bother...
31+
// [assembly: DiscoverInternals]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
using System;
5+
using System.Collections.Immutable;
6+
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
9+
namespace Ubiquity.NET.Extensions.UT
10+
{
11+
[TestClass]
12+
public sealed class DictionaryBuilderTests
13+
{
14+
[TestMethod]
15+
public void Inintialization_of_KvpArray_is_successfull( )
16+
{
17+
ImmutableDictionary<string, int> testDictionary = new DictionaryBuilder<string, int>()
18+
{
19+
["one"] = 1,
20+
["two"] = 2,
21+
}.ToImmutable();
22+
23+
Assert.AreEqual( 1, testDictionary[ "one" ] );
24+
Assert.AreEqual( 2, testDictionary[ "two" ] );
25+
}
26+
27+
[TestMethod]
28+
public void Getting_enumerator_from_KvpArrayBuilder_throws( )
29+
{
30+
var testBuilder = new DictionaryBuilder<string, int>()
31+
{
32+
["one"] = 1,
33+
["two"] = 2,
34+
};
35+
36+
Assert.ThrowsExactly<NotImplementedException>( ( ) =>
37+
{
38+
#pragma warning disable IDISP004 // Don't ignore created IDisposable
39+
// NOT disposable, no idea where the analyzer gets this from but System.Collections.IEnumerator
40+
// does not implement IDisposable. [Methods is supposed to throw anyway]
41+
_ = testBuilder.GetEnumerator();
42+
#pragma warning restore IDISP004 // Don't ignore created IDisposable
43+
}
44+
, "Syntactic sugar only for initialization" );
45+
}
46+
}
47+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
using System;
5+
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
8+
namespace Ubiquity.NET.Extensions.UT
9+
{
10+
[TestClass]
11+
public sealed class DisposableActionTests
12+
{
13+
[TestMethod]
14+
public void DisposableAction_CreateNOP_succeeds( )
15+
{
16+
using var disp = DisposableAction.CreateNOP();
17+
Assert.IsNotNull(disp);
18+
}
19+
20+
[TestMethod]
21+
public void DisposableAction_with_null_Action_throws( )
22+
{
23+
var ex = Assert.ThrowsExactly<ArgumentNullException>(static ()=>
24+
{
25+
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
26+
// Testing explicit case of null param.
27+
using var x = new DisposableAction(null);
28+
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
29+
} );
30+
Assert.IsNotNull( ex );
31+
Assert.AreEqual("null", ex.ParamName);
32+
}
33+
34+
[TestMethod]
35+
[System.Diagnostics.CodeAnalysis.SuppressMessage( "IDisposableAnalyzers.Correctness", "IDISP017:Prefer using", Justification = "Explicit testing" )]
36+
public void DisposableAction_called_correctly()
37+
{
38+
bool actionCalled = false;
39+
40+
var raiiAction = new DisposableAction( ()=> actionCalled = true );
41+
raiiAction.Dispose(); // Should trigger call to action
42+
43+
Assert.IsTrue(actionCalled);
44+
}
45+
}
46+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
using System;
5+
using System.ComponentModel;
6+
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
9+
namespace Ubiquity.NET.Extensions.UT
10+
{
11+
[TestClass]
12+
public sealed class FluentValidationExtensionsTests
13+
{
14+
[TestMethod]
15+
public void ThrowIfNull_throws_expected_exception_when_null( )
16+
{
17+
var ex = Assert.ThrowsExactly<ArgumentNullException>(()=>
18+
{
19+
FluentValidationExtensions.ThrowIfNull<string>( null );
20+
} );
21+
Assert.AreEqual("null", ex.ParamName, "parameter name should match input expression");
22+
}
23+
24+
[TestMethod]
25+
public void ThrowIfNull_does_not_throw_on_non_null_input()
26+
{
27+
const string input = "This is a test";
28+
29+
Assert.AreSame(input, FluentValidationExtensions.ThrowIfNull(input), "Fluent API should return input value on success" );
30+
}
31+
32+
[TestMethod]
33+
public void ThrowIfNull_reports_exception_whith_provided_expression( )
34+
{
35+
const string exp = "My-Expression";
36+
var ex = Assert.ThrowsExactly<ArgumentNullException>(()=>
37+
{
38+
FluentValidationExtensions.ThrowIfNull<string>( null, exp );
39+
} );
40+
Assert.AreEqual( exp, ex.ParamName, "parameter name should match input expression" );
41+
}
42+
43+
[TestMethod]
44+
public void ThrowIfNotDefined_does_not_throw_for_defined_value()
45+
{
46+
Assert.AreEqual(TestEnum.Max, FluentValidationExtensions.ThrowIfNotDefined(TestEnum.Max), "Fluent API should return input value on success" );
47+
}
48+
49+
[TestMethod]
50+
public void ThrowIfOutOfRange_does_not_throw_for_inrange_values( )
51+
{
52+
double value = 1.0;
53+
double min = 0.0;
54+
double max = 2.0;
55+
56+
Assert.AreEqual(value, FluentValidationExtensions.ThrowIfOutOfRange(value, min, max), "Fluent API should return input value on success");
57+
}
58+
59+
[TestMethod]
60+
public void ThrowIfOutOfRange_throws_for_out_of_range_values( )
61+
{
62+
double value = 2.0;
63+
double min = 1.0;
64+
double max = 1.5;
65+
66+
var ex = Assert.ThrowsExactly<ArgumentOutOfRangeException>(()=>
67+
{
68+
_ = FluentValidationExtensions.ThrowIfOutOfRange( value, min, max );
69+
} );
70+
Assert.AreEqual(value, ex.ActualValue);
71+
Assert.AreEqual(nameof(value), ex.ParamName);
72+
}
73+
74+
[TestMethod]
75+
public void ThrowIfOutOfRange_throws_with_custom_expression_for_out_of_range_values( )
76+
{
77+
double value = 2.0;
78+
double min = 1.0;
79+
double max = 1.5;
80+
81+
const string exp = "My Expression";
82+
var ex = Assert.ThrowsExactly<ArgumentOutOfRangeException>(()=>
83+
{
84+
_ = FluentValidationExtensions.ThrowIfOutOfRange( value, min, max, exp );
85+
} );
86+
Assert.AreEqual( value, ex.ActualValue );
87+
Assert.AreEqual( exp, ex.ParamName );
88+
}
89+
90+
[TestMethod]
91+
public void ThrowIfNotDefined_throws_for_undefined_values( )
92+
{
93+
var temp = (TestEnum)4;
94+
var ex = Assert.ThrowsExactly<InvalidEnumArgumentException>( ( ) =>
95+
{
96+
FluentValidationExtensions.ThrowIfNotDefined(temp);
97+
} );
98+
Assert.AreEqual(nameof(temp), ex.ParamName, "parameter name should match input expression" );
99+
100+
var temp2 = (TestByteEnum)4;
101+
var ex2 = Assert.ThrowsExactly<InvalidEnumArgumentException>( ( ) =>
102+
{
103+
FluentValidationExtensions.ThrowIfNotDefined(temp2);
104+
} );
105+
Assert.AreEqual( nameof( temp2 ), ex2.ParamName, "parameter name should match input expression" );
106+
107+
// This still fits an int so the normal constructor that sets paramName is available
108+
var temp3 = (TestU64Enum)int.MaxValue;
109+
var ex3 = Assert.ThrowsExactly<InvalidEnumArgumentException>( ( ) =>
110+
{
111+
FluentValidationExtensions.ThrowIfNotDefined(temp3);
112+
} );
113+
Assert.AreEqual( nameof( temp3 ), ex3.ParamName, "parameter name should match input expression" );
114+
115+
// This can't fit into an int so, the exception constructor that does not provide paramName is
116+
// the only option :( [But at least this scenario is VERY rare in the real world]
117+
var temp4 = (TestU64Enum)(UInt64.MaxValue - 1);
118+
var ex4 = Assert.ThrowsExactly<InvalidEnumArgumentException>( ( ) =>
119+
{
120+
FluentValidationExtensions.ThrowIfNotDefined(temp4);
121+
} );
122+
Assert.IsNull( ex4.ParamName, "parameter name not available for non-int formattable enums" );
123+
}
124+
125+
private enum TestEnum // default underling type is Int32
126+
{
127+
Zero,
128+
One,
129+
Two,
130+
Max = int.MaxValue
131+
}
132+
133+
private enum TestByteEnum
134+
: byte
135+
{
136+
Zero,
137+
One,
138+
Two,
139+
Max = byte.MaxValue
140+
}
141+
142+
private enum TestU64Enum
143+
: UInt64
144+
{
145+
Zero,
146+
One,
147+
Two,
148+
Max = UInt64.MaxValue
149+
}
150+
}
151+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
// This file is used by Code Analysis to maintain SuppressMessage
5+
// attributes that are applied to this project.
6+
// Project-level suppressions either have no target or are given
7+
// a specific target and scoped to a namespace, type, member, etc.
8+
9+
using System.Diagnostics.CodeAnalysis;
10+
11+
[assembly: SuppressMessage( "StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Test module" )]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Collections.Immutable;
7+
8+
using Microsoft.VisualStudio.TestTools.UnitTesting;
9+
10+
namespace Ubiquity.NET.Extensions.UT
11+
{
12+
[TestClass]
13+
public sealed class KvpArrayBuilderTests
14+
{
15+
[TestMethod]
16+
public void Inintialization_of_KvpArray_is_successfull( )
17+
{
18+
ImmutableArray<KeyValuePair<string, int>> testArray = new KvpArrayBuilder<string, int>()
19+
{
20+
["one"] = 1,
21+
["two"] = 2,
22+
}.ToImmutable();
23+
24+
Assert.AreEqual( "one", testArray[ 0 ].Key);
25+
Assert.AreEqual( 1, testArray[ 0 ].Value );
26+
27+
Assert.AreEqual( "two", testArray[ 1 ].Key );
28+
Assert.AreEqual( 2, testArray[ 1 ].Value );
29+
}
30+
31+
[TestMethod]
32+
public void Getting_enumerator_from_KvpArrayBuilder_throws( )
33+
{
34+
var testBuilder = new KvpArrayBuilder<string, int>()
35+
{
36+
["one"] = 1,
37+
["two"] = 2,
38+
};
39+
40+
Assert.ThrowsExactly<NotImplementedException>(()=>
41+
{
42+
#pragma warning disable IDISP004 // Don't ignore created IDisposable
43+
// NOT disposable, no idea where the analyzer gets this from but System.Collections.IEnumerator
44+
// does not implement IDisposable. [Methods is supposed to throw anyway]
45+
_ = testBuilder.GetEnumerator();
46+
#pragma warning restore IDISP004 // Don't ignore created IDisposable
47+
}
48+
, "Syntactic sugar only for initialization");
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)