-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
Copyright 2022 Jeffrey Sharp | ||
Permission to use, copy, modify, and distribute this software for any | ||
purpose with or without fee is hereby granted, provided that the above | ||
copyright notice and this permission notice appear in all copies. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | ||
|
||
namespace Subatomix.Testing; | ||
|
||
[TestFixture] | ||
[Parallelizable(ParallelScope.All)] | ||
public class ExceptionTestsTests : ExceptionTests<Exception> | ||
{ | ||
// Tests defined by base class | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
Copyright 2022 Jeffrey Sharp | ||
Permission to use, copy, modify, and distribute this software for any | ||
purpose with or without fee is hereby granted, provided that the above | ||
copyright notice and this permission notice appear in all copies. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | ||
|
||
using System.Runtime.Serialization; | ||
using System.Runtime.Serialization.Formatters.Binary; | ||
|
||
using static System.Reflection.BindingFlags; | ||
|
||
namespace Subatomix.Testing; | ||
|
||
// Squelch Visual Studio's incorrect hint to remove the next suppression | ||
#pragma warning disable IDE0079 | ||
|
||
// Allow obsolete BinaryFormatter to test legacy deserialization constructor | ||
// https://docs.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0011 | ||
#pragma warning disable SYSLIB0011 | ||
|
||
/// <summary> | ||
/// Base class for tests of exception types. | ||
/// </summary> | ||
/// <typeparam name="T"> | ||
/// The exception type to test. | ||
/// </typeparam> | ||
public abstract class ExceptionTests<T> | ||
where T : Exception | ||
{ | ||
// As told by Dennis Ritchie: | ||
// https://www.bell-labs.com/usr/dmr/www/odd.html | ||
private const string ArcaneMessage = "values of β will give rise to dom!"; | ||
|
||
[Test] | ||
public virtual void Construct_Default() | ||
{ | ||
var exception = Create(); | ||
|
||
exception.Message .Should().NotBeNullOrWhiteSpace(); | ||
exception.InnerException.Should().BeNull(); | ||
} | ||
|
||
[Test] | ||
public virtual void Construct_Message() | ||
{ | ||
var exception = Create(ArcaneMessage); | ||
|
||
exception.Message .Should().BeSameAs(ArcaneMessage); | ||
exception.InnerException.Should().BeNull(); | ||
} | ||
|
||
[Test] | ||
public virtual void Construct_Message_Null() | ||
{ | ||
var exception = Create(null as string); | ||
|
||
exception.Message .Should().NotBeNullOrWhiteSpace(); | ||
exception.InnerException.Should().BeNull(); | ||
} | ||
|
||
[Test] | ||
public virtual void Construct_MessageAndInnerException() | ||
{ | ||
var innerException = new InvalidProgramException(); | ||
var exception = Create(ArcaneMessage, innerException); | ||
|
||
exception.Message .Should().BeSameAs(ArcaneMessage); | ||
exception.InnerException.Should().BeSameAs(innerException); | ||
} | ||
|
||
[Test] | ||
public virtual void Construct_MessageAndInnerException_NullMessage() | ||
{ | ||
var innerException = new InvalidProgramException(); | ||
var exception = Create(null as string, innerException); | ||
|
||
exception.Message .Should().NotBeNullOrWhiteSpace(); | ||
exception.InnerException.Should().BeSameAs(innerException); | ||
} | ||
|
||
[Test] | ||
public virtual void Construct_MessageAndInnerException_NullInnerException() | ||
{ | ||
var exception = Create(ArcaneMessage, null as Exception); | ||
|
||
exception.Message .Should().BeSameAs(ArcaneMessage); | ||
exception.InnerException.Should().BeNull(); | ||
} | ||
|
||
[Test] | ||
public void SerializableAttribute() | ||
{ | ||
typeof(T).IsSerializable.Should().BeTrue(); | ||
} | ||
|
||
[Test] | ||
public void DeserializationConstructor() | ||
{ | ||
var constructor = typeof(T).GetConstructor( | ||
Instance | Public | NonPublic | ExactBinding, | ||
null, | ||
new[] { typeof(SerializationInfo), typeof(StreamingContext) }, | ||
null | ||
); | ||
|
||
constructor.Should().NotBeNull( | ||
"exception type {0} must provide a deserialization constructor; " + | ||
"see notes in the test for further information", | ||
typeof(T).FullName | ||
); | ||
|
||
constructor!.IsFamily.Should().BeTrue( | ||
"exception type {0} deserialization constructor must be protected; " + | ||
"see notes in the test for further information", | ||
typeof(T).FullName | ||
); | ||
} | ||
|
||
[Test] | ||
public virtual void SerializeThenDeserialize() // tests protected serialization constructor | ||
{ | ||
var innerException = new InvalidProgramException(); | ||
var exception = Create(ArcaneMessage, innerException); | ||
|
||
var deserialized = Roundtrip(exception); | ||
|
||
deserialized .Should().NotBeNull(); | ||
deserialized.Message .Should().Be(ArcaneMessage); | ||
deserialized.InnerException.Should().BeOfType<InvalidProgramException>(); | ||
} | ||
|
||
private static T Create(params object?[] args) | ||
{ | ||
// T is Exception or some type derived from it, not Nullable<_>. | ||
// Thus Activator.CreateInstance is guaranteed to not return null. | ||
return (T) Activator.CreateInstance(typeof(T), args)!; | ||
} | ||
|
||
private static T Roundtrip(T obj) | ||
{ | ||
using var memory = new MemoryStream(); | ||
|
||
// Serialize | ||
var formatter = new BinaryFormatter(); | ||
formatter.Serialize(memory, obj); | ||
|
||
// Rewind | ||
memory.Position = 0; | ||
|
||
// Deserialize | ||
return (T) formatter.Deserialize(memory); | ||
} | ||
} |