removed unneeded files

This commit is contained in:
timerix 2022-09-26 02:25:27 +06:00
parent 8db93654c2
commit 785619aaab
35 changed files with 0 additions and 1925 deletions

View File

@ -1,94 +0,0 @@
# ASP.NET Core EditorConfig file
# NOTE: This file focuses on settings Visual Studio 2017 supports natively. For example, VS does not support insert_final_newline.
# We do use it, but it's harder to enforce without a separate VS extension or an editor that supports it.
# See https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options for more
# Mark this file as the "root" for everything below this point. This means that editor config files above
# this file will be ignored
root = true
# Default settings
[*]
indent_style = space
indent_size = 4
charset = utf-8
insert_final_newline = true
# Unix-only files
[*.sh]
end_of_line = lf
# 2-space files
[{*.json,*.yml}]
indent_size = 2
# .NET Code Style Settings
# See https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
# REVIEW: Should these be errors? warnings? suggestions?
[{*.cs,*.vb}]
dotnet_sort_system_directives_first = true
# Don't use 'this.'/'Me.' prefix for anything
dotnet_style_qualification_for_field = false:error
dotnet_style_qualification_for_property = false:error
dotnet_style_qualification_for_method = false:error
dotnet_style_qualification_for_event = false:error
# Use language keywords over framework type names for type references
# i.e. prefer 'string' over 'String'
dotnet_style_predefined_type_for_locals_parameters_members = true:error
dotnet_style_predefined_type_for_member_access = true:error
# Prefer object/collection initializers
# This is a suggestion because there are cases where this is necessary
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
# C# 7: Prefer using named tuple names over '.Item1', '.Item2', etc.
dotnet_style_explicit_tuple_names = true:error
# Prefer using 'foo ?? bar' over 'foo != null ? foo : bar'
dotnet_style_coalesce_expression = true:error
# Prefer using '?.' over ternary null checking where possible
dotnet_style_null_propagation = true:error
# Use 'var' in all cases where it can be used
csharp_style_var_for_built_in_types = true:error
csharp_style_var_when_type_is_apparent = true:error
csharp_style_var_elsewhere = true:error
# C# 7: Prefer using pattern matching over "if(x is T) { var t = (T)x; }" and "var t = x as T; if(t != null) { ... }"
# REVIEW: Since this is a new C# 7 feature that replaces an existing pattern, I'm making it a suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
# C# 7: Prefer using 'out var' where possible
# REVIEW: Since this is a new C# 7 feature that replaces an existing pattern, I'm making it a suggestion
csharp_style_inlined_variable_declaration = true:error
# C# 7: Use throw expressions when null-checking
# @davidfowl hates them :)
csharp_style_throw_expression = false:error
# Prefer using "func?.Invoke(args)" over "if(func != null) { func(args); }"
# REVIEW: Maybe an error?
csharp_style_conditional_delegate_call = true:error
# Newline settings
# Unsure where docs are. Got these from https://github.com/dotnet/roslyn/blob/master/.editorconfig
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
# Prefer expression-bodied methods, constructors, operators, etc.
csharp_style_expression_bodied_methods = true:suggestion
csharp_style_expression_bodied_constructors = true:suggestion
csharp_style_expression_bodied_operators = true:suggestion
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion

2
.github/FUNDING.yml vendored
View File

@ -1,2 +0,0 @@
github: [benaadams]

View File

@ -1,11 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "nuget" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View File

@ -1,50 +0,0 @@
name: Demystifier PR Build
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: "Build for PR"
runs-on: ${{ matrix.os }}
env:
DOTNET_NOLOGO: true
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-18.04, macOS-latest]
config: [Debug, Release]
steps:
- name: Clone source
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup .NET SDK (v2.1)
uses: actions/setup-dotnet@v1.7.2
with:
dotnet-version: '2.1.818'
- name: Setup .NET SDK (v3.1)
uses: actions/setup-dotnet@v1.7.2
with:
dotnet-version: '3.1.414'
- name: Setup .NET SDK (v5.0)
uses: actions/setup-dotnet@v1.7.2
with:
dotnet-version: '5.0.402'
- name: Setup .NET SDK (v6.0)
uses: actions/setup-dotnet@v1.7.2
with:
dotnet-version: '6.0.100-rc.2.21505.57'
- name: Get .NET information
run: dotnet --info
- name: Build
run: dotnet build -c ${{ matrix.config }}
- name: "Test"
run: dotnet test -c ${{ matrix.config }}

View File

@ -1,12 +0,0 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
</Project>

201
LICENSE
View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@ -1,27 +0,0 @@
<#
.SYNOPSIS
This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
to see if an error occcured. If an error is detected then an exception is thrown.
This function allows you to run command-line programs without having to
explicitly check the $lastexitcode variable.
.EXAMPLE
exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
#>
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd)
)
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
}
if(Test-Path .\artifacts) { Remove-Item .\artifacts -Force -Recurse }
exec { & dotnet test .\test\Ben.Demystifier.Test -c Release }
exec { & dotnet pack .\src\Ben.Demystifier -c Release -o .\artifacts }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

View File

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Ply" Version="0.3.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="6.0.1" />
</ItemGroup>
</Project>

View File

@ -1,34 +0,0 @@
// Learn more about F# at http://fsharp.org
open System
open System.Diagnostics
open FSharp.Control.Tasks
let call i = async {
do! Async.Sleep 1
if i = 10 then
failwith "BOOM!"
return i
}
let run count = async {
let calls = Array.init count call
for call in calls do
let! _ = call
()
return 0
}
let makeTheCall () = task {
let! x = run 20
return x
}
[<EntryPoint>]
let main argv =
try
let results = makeTheCall().GetAwaiter().GetResult()
printfn "%A" results
with e ->
printfn "%s" <| string (e.Demystify())
0 // return an integer exit code

View File

@ -1,157 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Exception exception = null;
try
{
new Program();
}
catch (Exception ex)
{
Console.WriteLine(ex);
exception = ex.Demystify();
}
Console.WriteLine();
Console.WriteLine(exception);
}
static Action<string, bool> s_action = (string s, bool b) => s_func(s, b);
static Func<string, bool, (string val, bool)> s_func = (string s, bool b) => (RefMethod(s), b);
Action<Action<object>, object> _action = (Action<object> lambda, object state) => lambda(state);
static string s = "";
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
Program() : this(() => Start())
{
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
Program(Action action) => RunAction((state) => _action((s) => action(), state), null);
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static IEnumerable<string> Iterator(int startAt)
{
var list = new List<int>() { 1, 2, 3, 4 };
foreach (var item in list)
{
// Throws the exception
list.Add(item);
yield return item.ToString();
}
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static async Task<string> MethodAsync(int value)
{
await Task.Delay(0);
return GenericClass<byte>.GenericMethod(ref value);
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static async Task<string> MethodAsync<TValue>(TValue value)
{
return await MethodLocalAsync();
async Task<string> MethodLocalAsync()
{
return await MethodAsync(1);
}
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void RunAction(Action<object> lambda, object state) => lambda(state);
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static string RunLambda(Func<string> lambda) => lambda();
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static (string val, bool) Method(string value)
{
#pragma warning disable IDE0039 // Use local function
Func<string> func = () => MethodAsync(value).GetAwaiter().GetResult();
#pragma warning restore IDE0039 // Use local function
var anonType = new { func };
return (RunLambda(() => anonType.func()), true);
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static ref string RefMethod(int value) => ref s;
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static string RefMethod(in string value)
{
var val = value;
return LocalFuncParam(value).ToString();
int LocalFuncParam(string s)
{
return int.Parse(LocalFuncRefReturn());
}
ref string LocalFuncRefReturn()
{
Method(val);
return ref s;
}
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static string Start()
{
return LocalFunc2(true, false).ToString();
void LocalFunc1(long l)
{
Start((val: "", true));
}
bool LocalFunc2(bool b1, bool b2)
{
LocalFunc1(1);
return true;
}
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static ref string RefMethod(bool value) => ref s;
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Start((string val, bool) param) => s_action.Invoke(param.val, param.Item2);
class GenericClass<TSuperType>
{
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
public static string GenericMethod<TSubType>(ref TSubType value)
{
var returnVal = "";
for (var i = 0; i < 10; i++)
{
try
{
returnVal += string.Join(", ", Iterator(5).Select(s => s));
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
return returnVal;
}
}
}

View File

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" />
</ItemGroup>
</Project>

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net462;net5.0</TargetFrameworks>
<Configuration>Release</Configuration>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" />
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>
</Project>

View File

@ -1,43 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
namespace Ben.Demystifier.Benchmarks
{
[SimpleJob(RuntimeMoniker.Net48)]
[SimpleJob(RuntimeMoniker.NetCoreApp21)]
[SimpleJob(RuntimeMoniker.NetCoreApp31)]
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[Config(typeof(Config))]
public class ExceptionTests
{
[Benchmark(Baseline = true, Description = ".ToString()")]
public string Baseline() => new Exception().ToString();
[Benchmark(Description = "Demystify().ToString()")]
public string Demystify() => new Exception().Demystify().ToString();
[Benchmark(Description = "(left, right).ToString()")]
public string ToStringForTupleBased() => GetException(() => ReturnsTuple()).ToString();
[Benchmark(Description = "(left, right).Demystify().ToString()")]
public string ToDemystifyForTupleBased() => GetException(() => ReturnsTuple()).Demystify().ToString();
private static Exception GetException(Action action)
{
try
{
action();
throw new InvalidOperationException("Should not be reachable.");
}
catch (Exception e)
{
return e;
}
}
private static List<(int left, int right)> ReturnsTuple() => throw new Exception();
}
}

View File

@ -1,48 +0,0 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Running;
using System;
using System.Linq;
using System.Reflection;
namespace Ben.Demystifier.Benchmarks
{
public static class Program
{
private const string BenchmarkSuffix = "Tests";
public static void Main(string[] args)
{
var benchmarks = Assembly.GetEntryAssembly()
.DefinedTypes.Where(t => t.Name.EndsWith(BenchmarkSuffix))
.ToDictionary(t => t.Name.Substring(0, t.Name.Length - BenchmarkSuffix.Length), t => t, StringComparer.OrdinalIgnoreCase);
if (args.Length > 0 && args[0].Equals("all", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("Running full benchmarks suite");
benchmarks.Select(pair => pair.Value).ToList().ForEach(action => BenchmarkRunner.Run(action));
return;
}
if (args.Length == 0 || !benchmarks.ContainsKey(args[0]))
{
Console.WriteLine("Please, select benchmark, list of available:");
benchmarks
.Select(pair => pair.Key)
.ToList()
.ForEach(Console.WriteLine);
Console.WriteLine("All");
return;
}
BenchmarkRunner.Run(benchmarks[args[0]]);
Console.Read();
}
}
internal class Config : ManualConfig
{
public Config() => AddDiagnoser(MemoryDiagnoser.Default);
}
}

View File

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class AggregateException
{
[Fact]
public void DemystifiesAggregateExceptions()
{
Exception demystifiedException = null;
try
{
var tasks = new List<Task>
{
Task.Run(async () => await Throw1()),
Task.Run(async () => await Throw2()),
Task.Run(async () => await Throw3())
};
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
// Remove items that vary between test runners
.Where(s =>
(s != " at Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()+() => { }" &&
!s.Contains("System.Threading.Tasks.Task.WaitAll"))
)
.Skip(1)
.ToArray())
// Remove Full framework back arrow
.Replace("<---", "");
#if NETCOREAPP3_0_OR_GREATER
var expected = string.Join("", new[] {
" ---> System.ArgumentException: Value does not fall within the expected range.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw1()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
" --- End of inner exception stack trace ---",
" at void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()",
" ---> (Inner Exception #1) System.NullReferenceException: Object reference not set to an instance of an object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw2()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
" ---> (Inner Exception #2) System.InvalidOperationException: Operation is not valid due to the current state of the object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw3()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }"
});
#else
var expected = string.Join("", new[] {
" at async Task Ben.Demystifier.Test.AggregateException.Throw1()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
" --- End of inner exception stack trace ---",
" at void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()",
"---> (Inner Exception #0) System.ArgumentException: Value does not fall within the expected range.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw1()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
"---> (Inner Exception #1) System.NullReferenceException: Object reference not set to an instance of an object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw2()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
"---> (Inner Exception #2) System.InvalidOperationException: Operation is not valid due to the current state of the object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw3()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }"});
#endif
Assert.Equal(expected, trace);
}
async Task Throw1()
{
await Task.Delay(1).ConfigureAwait(false);
throw new ArgumentException();
}
async Task Throw2()
{
await Task.Delay(1).ConfigureAwait(false);
throw new NullReferenceException();
}
async Task Throw3()
{
await Task.Delay(1).ConfigureAwait(false);
throw new InvalidOperationException();
}
}
}

View File

@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class AsyncEnumerableTests
{
[Fact]
public async Task DemystifiesAsyncEnumerable()
{
Exception demystifiedException = null;
try
{
await foreach (var val in Start(CancellationToken.None))
{
_ = val;
}
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => Regex.Replace(s, " x [0-9]+", " x N"))
.Skip(1)
.ToArray());
var expected = string.Join("", new[] {
" at async IAsyncEnumerable<int> Ben.Demystifier.Test.AsyncEnumerableTests.Throw(CancellationToken cancellationToken)+MoveNext()",
" at async IAsyncEnumerable<long> Ben.Demystifier.Test.AsyncEnumerableTests.Start(CancellationToken cancellationToken)+MoveNext() x N",
" at async Task Ben.Demystifier.Test.AsyncEnumerableTests.DemystifiesAsyncEnumerable() x N"
});
Assert.Equal(expected, trace);
}
async IAsyncEnumerable<long> Start([EnumeratorCancellation] CancellationToken cancellationToken)
{
await Task.Delay(1, cancellationToken).ConfigureAwait(false);
yield return 1;
await foreach (var @throw in Throw(cancellationToken))
{
yield return @throw;
}
}
async IAsyncEnumerable<int> Throw([EnumeratorCancellation] CancellationToken cancellationToken)
{
yield return 2;
await Task.Delay(1, cancellationToken).ConfigureAwait(false);
throw new InvalidOperationException();
}
}
}

View File

@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">$(TargetFrameworks);net461</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\src\Ben.Demystifier\key.snk</AssemblyOriginatorKeyFile>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" Condition="'$(TargetFramework)' == 'net461' or '$(TargetFramework)' == 'netcoreapp2.1'" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" />
</ItemGroup>
</Project>

View File

@ -1,58 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class DynamicCompilation
{
[Fact]
public async Task DoesNotPreventStackTrace()
{
// Arrange
var expression = Expression.Throw(
Expression.New(
typeof(ArgumentException).GetConstructor(
new Type[] {typeof(string)}),
Expression.Constant( "Message")));
var lambda = Expression.Lambda<Action>(expression);
var action = lambda.Compile();
// Act
Exception demystifiedException = null;
try
{
await Task.Run(() => action()).ConfigureAwait(false);
}
catch(Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
// Remove items that vary between test runners
.Where(s =>
s != " at void System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, object state)" &&
s != " at Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()+() => { }"
)
.Select(s => Regex.Replace(s, "lambda_method[0-9]+\\(", "lambda_method("))
.ToArray();
Assert.Equal(
new[] {
"System.ArgumentException: Message",
" at void lambda_method(Closure)",
" at async Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()"},
trace);
}
}
}

View File

@ -1,43 +0,0 @@
using System.Diagnostics;
using Xunit;
namespace Ben.Demystifier.Test
{
public class EnhancedStackTraceTests
{
[Theory]
[InlineData(@"file://Sources\MySolution\Foo.cs", @"/MySolution/Foo.cs")]
[InlineData(@"d:\Public\Src\Foo.cs", @"d:/Public/Src/Foo.cs")]
// To be deterministic, the C# compiler can take a /pathmap command line option.
// This option force the compiler to emit the same bits even when their built from the
// differrent locations.
// The binaries built with the pathmap usually don't have an absolute path,
// but have some prefix like \.\.
// This test case makes sure that EhancedStackTrace can deal with such kind of paths.
[InlineData(@"\.\Public\Src\Foo.cs", @"/./Public/Src/Foo.cs")]
public void RelativePathIsConvertedToAnAbsolutePath(string original, string expected)
{
var converted = EnhancedStackTrace.TryGetFullPath(original);
Assert.Equal(expected, NormalizePath(converted));
}
[Theory]
[InlineData(@"file://Sources\My 100%.Done+Solution\Foo`1.cs", @"/My 100%.Done+Solution/Foo`1.cs", false)]
[InlineData(@"d:\Public Files+50%.Done\Src\Foo`1.cs", @"d:/Public Files+50%.Done/Src/Foo`1.cs", false)]
[InlineData(@"\.\Public Files+50%.Done\Src\Foo`1.cs", @"/./Public Files+50%.Done/Src/Foo`1.cs", true)]
public void SpecialPathCharactersAreHandledCorrectly(string original, string expected, bool normalize)
{
var converted = EnhancedStackTrace.TryGetFullPath(original);
if (normalize)
{
converted = NormalizePath(converted);
}
Assert.Equal(expected, converted);
}
// Used in tests to avoid platform-specific issues.
private static string NormalizePath(string path)
=> path.Replace("\\", "/");
}
}

View File

@ -1,42 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class GenericMethodDisplayStringTests
{
private static class Example<T>
{
// ReSharper disable once StaticMemberInGenericType
public static readonly StackFrame StackFrame;
static Example()
{
var fun = new Func<StackFrame>(() => new StackFrame(0, true));
StackFrame = fun();
}
}
[Fact]
public void DiagnosesGenericMethodDisplayString()
{
var sf = Example<Type>.StackFrame;
try
{
var s = EnhancedStackTrace.GetMethodDisplayString(sf.GetMethod());
Assert.True(true, "Does not throw exception when diagnosing generic method display string.");
}
catch (Exception)
{
Assert.True(false, "Must not throw an exception when diagnosing generic method display string.");
}
}
}
}

View File

@ -1,53 +0,0 @@
using System.Diagnostics.Internal;
using Xunit;
namespace Ben.Demystifier.Test
{
public class ILReaderTests
{
public static TheoryData<byte[]> InlineCilSamples =>
new TheoryData<byte[]>
{
// https://github.com/benaadams/Ben.Demystifier/issues/56#issuecomment-366490463
{ new byte[] {
2, 123, 209, 5, 0, 4, 20, 254, 1, 114, 193, 103, 1, 112, 40, 160, 22, 0, 6,
2, 115, 183, 10, 0, 10, 125, 210, 5, 0, 4, 2, 123, 212, 5, 0, 4, 2, 123, 211,
5, 0, 4, 40, 221, 15, 0, 6, 44, 68, 2, 123, 212, 5, 0, 4, 111, 103, 17, 0, 6, 2,
111, 222, 9, 0, 6, 2, 40, 184, 10, 0, 10, 2, 254, 6, 249, 15, 0, 6, 115, 185, 10,
0, 10, 2, 123, 210, 5, 0, 4, 111, 186, 10, 0, 10, 22, 40, 101, 6, 0, 10, 111, 221,
0, 0, 43, 40, 188, 10, 0, 10, 125, 209, 5, 0, 4, 42, 2, 123, 212, 5, 0, 4, 111,
103, 17, 0, 6, 111, 216, 9, 0, 6, 2, 123, 211, 5, 0, 4, 111, 166, 14, 0, 6, 111,
125, 16, 0, 6, 254, 1, 22, 254, 1, 114, 235, 103, 1, 112, 40, 160, 22, 0, 6, 114,
160, 104, 1, 112, 40, 210, 0, 0, 10, 114, 194, 5, 0, 112, 40, 221, 0, 0, 10, 44, 51,
2, 40, 184, 10, 0, 10, 2, 254, 6, 250, 15, 0, 6, 115, 185, 10, 0, 10, 2, 123, 210,
5, 0, 4, 111, 186, 10, 0, 10, 22, 40, 196, 21, 0, 6, 111, 221, 0, 0, 43, 40, 188,
10, 0, 10, 125, 209, 5, 0, 4, 42, 2, 40, 184, 10, 0, 10, 2, 254, 6, 251, 15, 0, 6,
115, 185, 10, 0, 10, 2, 123, 210, 5, 0, 4, 111, 186, 10, 0, 10, 24, 40, 101, 6, 0,
10, 111, 221, 0, 0, 43, 40, 188, 10, 0, 10, 125, 209, 5, 0, 4, 42
} },
// https://github.com/benaadams/Ben.Demystifier/issues/56#issuecomment-390654651
{ new byte[] {
115, 31, 5, 0, 6, 37, 2, 125, 94, 1, 0, 4, 37, 3, 125, 91, 1, 0, 4, 37, 4, 125, 92,
1, 0, 4, 37, 5, 125, 93, 1, 0, 4, 37, 123, 91, 1, 0, 4, 40, 61, 0, 0, 10, 44, 16,
40, 160, 4, 0, 6, 114, 253, 15, 0, 112, 115, 90, 0, 0, 10, 122, 254, 6, 32, 5, 0,
6, 115, 137, 2, 0, 10, 115, 61, 2, 0, 6, 42
} },
{ new byte[] {
31, 254, 115, 42, 2, 0, 6, 37, 2, 125, 159, 0, 0, 4, 37, 3, 125, 158, 0, 0, 4, 42
} },
};
// https://github.com/benaadams/Ben.Demystifier/issues/56
[Theory, MemberData(nameof(InlineCilSamples))]
public void ReadsInlinedOpcodes(byte[] cil)
{
var sut = new ILReader(cil);
while (sut.Read(GetType().GetMethod(nameof(ReadsInlinedOpcodes))))
{
}
}
}
}

View File

@ -1,46 +0,0 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class InheritenceTests
{
private abstract class BaseClass
{
public abstract Task<object> Method();
}
private class ImplClass : BaseClass
{
[MethodImpl(MethodImplOptions.NoInlining)]
public override Task<object> Method()
{
throw new Exception();
}
}
[Fact]
public async Task ImplementedAbstractMethodDoesNotThrow()
{
// Arrange
var instance = new ImplClass();
// Act
Exception exception = null;
try
{
await instance.Method();
}
catch (Exception ex)
{
exception = ex;
}
// Act
var est = new EnhancedStackTrace(exception);
}
}
}

View File

@ -1,14 +0,0 @@
using System.Text.RegularExpressions;
namespace Ben.Demystifier.Test
{
internal static class LineEndingsHelper
{
private static readonly Regex ReplaceLineEndings = new Regex(" in [^\n\r]+");
public static string RemoveLineEndings(string original)
{
return ReplaceLineEndings.Replace(original, "");
}
}
}

View File

@ -1,137 +0,0 @@
namespace Ben.Demystifier.Test
{
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xunit;
public class MethodTests
{
[Fact]
public void DemistifiesMethodWithNullableInt()
{
Exception dex = null;
try
{
MethodWithNullableInt(1);
}
catch (Exception e)
{
dex = e.Demystify();
}
// Assert
var stackTrace = dex.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join(string.Empty, stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join(string.Empty,
"System.ArgumentException: Value does not fall within the expected range.",
" at bool Ben.Demystifier.Test.MethodTests.MethodWithNullableInt(int? number)",
" at void Ben.Demystifier.Test.MethodTests.DemistifiesMethodWithNullableInt()");
Assert.Equal(expected, trace);
}
[Fact]
public void DemistifiesMethodWithDynamic()
{
Exception dex = null;
try
{
MethodWithDynamic(1);
}
catch (Exception e)
{
dex = e.Demystify();
}
// Assert
var stackTrace = dex.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join(string.Empty, stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join(string.Empty,
"System.ArgumentException: Value does not fall within the expected range.",
" at bool Ben.Demystifier.Test.MethodTests.MethodWithDynamic(dynamic value)",
" at void Ben.Demystifier.Test.MethodTests.DemistifiesMethodWithDynamic()");
Assert.Equal(expected, trace);
}
[Fact]
public void DemistifiesMethodWithLambda()
{
Exception dex = null;
try
{
MethodWithLambda();
}
catch (Exception e)
{
dex = e.Demystify();
}
// Assert
var stackTrace = dex.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join(string.Empty, stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join(string.Empty,
"System.ArgumentException: Value does not fall within the expected range.",
" at void Ben.Demystifier.Test.MethodTests.MethodWithLambda()+() => { }",
" at void Ben.Demystifier.Test.MethodTests.MethodWithLambda()",
" at void Ben.Demystifier.Test.MethodTests.DemistifiesMethodWithLambda()");
Assert.Equal(expected, trace);
}
[Fact]
public async Task DemistifiesMethodWithAsyncLambda()
{
Exception dex = null;
try
{
await MethodWithAsyncLambda();
}
catch (Exception e)
{
dex = e.Demystify();
}
// Assert
var stackTrace = dex.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join(string.Empty, stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join(string.Empty,
"System.ArgumentException: Value does not fall within the expected range.",
" at async Task Ben.Demystifier.Test.MethodTests.MethodWithAsyncLambda()+(?) => { }",
" at async Task Ben.Demystifier.Test.MethodTests.MethodWithAsyncLambda()",
" at async Task Ben.Demystifier.Test.MethodTests.DemistifiesMethodWithAsyncLambda()");
Assert.Equal(expected, trace);
}
private bool MethodWithNullableInt(int? number) => throw new ArgumentException();
private bool MethodWithDynamic(dynamic value) => throw new ArgumentException();
private void MethodWithLambda()
{
Func<bool> action = () => throw new ArgumentException();
action();
}
private async Task MethodWithAsyncLambda()
{
Func<Task> action = async () =>
{
await Task.CompletedTask;
throw new ArgumentException();
};
await action();
}
}
}

View File

@ -1,126 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class MixedStack
{
[Fact]
public void ProducesReadableFrames()
{
// Arrange
var exception = GetMixedStackException();
// Act
var methodNames = new EnhancedStackTrace(exception)
.Select(
stackFrame => stackFrame.MethodInfo.ToString()
)
// Remove Framework method that can be optimized out (inlined)
.Where(methodName => !methodName.StartsWith("bool System.Collections.Generic.List<T>+"));
var count = methodNames.Count();
methodNames = methodNames.Take(count - 1);
// Assert
var expected = ExpectedCallStack.ToArray();
var trace = methodNames.ToArray();
Assert.Equal(expected.Length, trace.Length);
for (var i = 0; i < expected.Length; i++)
{
Assert.Equal(expected[i], trace[i]);
}
}
Exception GetMixedStackException()
{
Exception exception = null;
try
{
Start((val: "", true));
}
catch (Exception ex)
{
exception = ex;
}
return exception;
}
static List<string> ExpectedCallStack = new List<string>()
{
"IEnumerable<string> Ben.Demystifier.Test.MixedStack.Iterator()+MoveNext()",
"string string.Join(string separator, IEnumerable<string> values)",
"string Ben.Demystifier.Test.MixedStack+GenericClass<T>.GenericMethod<V>(ref V value)",
"async Task<string> Ben.Demystifier.Test.MixedStack.MethodAsync(int value)",
"async ValueTask<string> Ben.Demystifier.Test.MixedStack.MethodAsync<TValue>(TValue value)",
"(string val, bool) Ben.Demystifier.Test.MixedStack.Method(string value)",
"ref string Ben.Demystifier.Test.MixedStack.RefMethod(string value)",
"(string val, bool) Ben.Demystifier.Test.MixedStack.s_func(string s, bool b)",
"void Ben.Demystifier.Test.MixedStack.s_action(string s, bool b)",
"void Ben.Demystifier.Test.MixedStack.Start((string val, bool) param)"
};
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static IEnumerable<string> Iterator()
{
var list = new List<int>() { 1, 2, 3, 4 };
foreach (var item in list)
{
// Throws the exception
list.Add(item);
yield return item.ToString();
}
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static async Task<string> MethodAsync(int value)
{
await Task.Delay(0);
return GenericClass<byte>.GenericMethod(ref value);
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static async ValueTask<string> MethodAsync<TValue>(TValue value) => await MethodAsync(1);
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static (string val, bool) Method(string value) => (MethodAsync(value).GetAwaiter().GetResult(), true);
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static ref string RefMethod(string value)
{
Method(value);
return ref s;
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Start((string val, bool) param) => s_action.Invoke(param.val, param.Item2);
static Action<string, bool> s_action = (string s, bool b) => s_func(s, b);
static Func<string, bool, (string val, bool)> s_func = (string s, bool b) => (RefMethod(s), b);
static string s = "";
static class GenericClass<T>
{
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
public static string GenericMethod<V>(ref V value)
{
var returnVal = "";
for (var i = 0; i < 10; i++)
{
returnVal += string.Join(", ", Iterator());
}
return returnVal;
}
}
}
}

View File

@ -1,121 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class NonThrownException
{
[Fact]
public async Task DoesNotPreventThrowStackTrace()
{
// Arrange
Exception innerException = null;
try
{
await Task.Run(() => throw new Exception()).ConfigureAwait(false);
}
catch(Exception ex)
{
innerException = ex;
}
// Act
var demystifiedException = new Exception(innerException.Message, innerException).Demystify();
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = stackTrace.Split(new[]{Environment.NewLine}, StringSplitOptions.None);
#if NETCOREAPP3_0_OR_GREATER
Assert.Equal(
new[] {
"System.Exception: Exception of type 'System.Exception' was thrown.",
" ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---"},
trace);
#else
Assert.Equal(
new[] {
"System.Exception: Exception of type 'System.Exception' was thrown. ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---"},
trace);
#endif
// Act
try
{
throw demystifiedException;
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
trace = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
#if NETCOREAPP3_0_OR_GREATER
Assert.Equal(
new[] {
"System.Exception: Exception of type 'System.Exception' was thrown.",
" ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()"
},
trace);
#else
Assert.Equal(
new[] {
"System.Exception: Exception of type 'System.Exception' was thrown. ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()"
},
trace);
#endif
}
[Fact]
public async Task Current()
{
// Arrange
EnhancedStackTrace est = null;
// Act
await Task.Run(() => est = EnhancedStackTrace.Current()).ConfigureAwait(false);
// Assert
var stackTrace = est.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
// Remove Full framework entries
.Where(s => !s.StartsWith(" at bool System.Threading._ThreadPoolWaitCallbac") &&
!s.StartsWith(" at void System.Threading.Tasks.Task.System.Thre"));
Assert.Equal(
new[] {
" at bool System.Threading.ThreadPoolWorkQueue.Dispatch()",
#if NET6_0_OR_GREATER
" at void System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()",
" at void System.Threading.Thread.StartCallback()",
#endif
},
trace);
}
}
}

View File

@ -1,40 +0,0 @@
namespace Ben.Demystifier.Test
{
using System;
using System.Diagnostics;
using Xunit;
public class ParameterParamTests
{
[Fact]
public void DemistifiesMethodWithParams()
{
Exception dex = null;
try
{
MethodWithParams(1, 2, 3);
}
catch (Exception e)
{
dex = e.Demystify();
}
// Assert
var stackTrace = dex.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join(string.Empty, stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join(string.Empty, new[] {
"System.ArgumentException: Value does not fall within the expected range.",
" at bool Ben.Demystifier.Test.ParameterParamTests.MethodWithParams(params int[] numbers)",
" at void Ben.Demystifier.Test.ParameterParamTests.DemistifiesMethodWithParams()"});
Assert.Equal(expected, trace);
}
private bool MethodWithParams(params int[] numbers)
{
throw new ArgumentException();
}
}
}

View File

@ -1,74 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class RecursionTests
{
[Fact]
public async Task DemystifiesAsyncRecursion()
{
Exception demystifiedException = null;
try
{
await RecurseAsync(10);
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var traces = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => Regex.Replace(s, " x [0-9]+", " x N"))
.Skip(1)
.ToArray();
Assert.Contains(" at async Task<int> Ben.Demystifier.Test.RecursionTests.RecurseAsync(int depth) x N", traces);
}
[Fact]
public void DemystifiesRecursion()
{
Exception demystifiedException = null;
try
{
Recurse(10);
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var traces = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => Regex.Replace(s, " x [0-9]+", " x N"))
.Skip(1)
.ToArray();
Assert.Contains(" at int Ben.Demystifier.Test.RecursionTests.Recurse(int depth) x N", traces);
}
async Task<int> RecurseAsync(int depth)
{
if (depth > 0) await RecurseAsync(depth - 1);
throw new InvalidOperationException();
}
int Recurse(int depth)
{
if (depth > 0) Recurse(depth - 1);
throw new InvalidOperationException();
}
}
}

View File

@ -1,27 +0,0 @@
using System;
using System.Diagnostics.Internal;
using Xunit;
namespace Ben.Demystifier.Test
{
public class ReflectionHelperTest
{
[Fact]
public void IsValueTupleReturnsTrueForTupleWith1Element()
{
Assert.True(typeof(ValueTuple<int>).IsValueTuple());
}
[Fact]
public void IsValueTupleReturnsTrueForTupleWith1ElementWithOpenedType()
{
Assert.True(typeof(ValueTuple<>).IsValueTuple());
}
[Fact]
public void IsValueTupleReturnsTrueForTupleWith6ElementsWithOpenedType()
{
Assert.True(typeof(ValueTuple<,,,,,>).IsValueTuple());
}
}
}

View File

@ -1,26 +0,0 @@
using System.Diagnostics;
using System.Linq;
using System.Text;
using Xunit;
namespace Ben.Demystifier.Test
{
public class ResolvedMethodTests
{
[Fact]
public void AppendWithFullNameTrueTest()
{
var resolvedMethod = EnhancedStackTrace.GetMethodDisplayString(GetType().GetMethods().First(m => m.Name == nameof(AppendWithFullNameTrueTest)));
var sb = new StringBuilder();
Assert.Equal($"void {GetType().Namespace}.{GetType().Name}.{nameof(AppendWithFullNameTrueTest)}()", resolvedMethod.Append(sb).ToString());
}
[Fact]
public void AppendWithFullNameFalseTest()
{
var resolvedMethod = EnhancedStackTrace.GetMethodDisplayString(GetType().GetMethods().First(m => m.Name == nameof(AppendWithFullNameFalseTest)));
var sb = new StringBuilder();
Assert.Equal($"void {GetType().Name}.{nameof(AppendWithFullNameFalseTest)}()", resolvedMethod.Append(sb, false).ToString());
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
namespace Ben.Demystifier.Test
{
public sealed class ToDemystifiedStringTests
{
private readonly ITestOutputHelper _output;
public ToDemystifiedStringTests(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void DemystifyShouldNotAffectTheOriginalStackTrace()
{
try
{
SimpleMethodThatThrows(null).Wait();
}
catch (Exception e)
{
var original = e.ToString();
var stringDemystified = e.ToStringDemystified();
_output.WriteLine("Demystified: ");
_output.WriteLine(stringDemystified);
_output.WriteLine("Original: ");
var afterDemystified = e.ToString();
_output.WriteLine(afterDemystified);
Assert.Equal(original, afterDemystified);
}
async Task SimpleMethodThatThrows(string value)
{
if (value == null)
{
throw new InvalidOperationException("message");
}
await Task.Yield();
}
}
[Fact]
public void DemystifyKeepsMessage()
{
Exception ex = null;
try
{
throw new InvalidOperationException("aaa")
{
Data =
{
["bbb"] = "ccc",
["ddd"] = "eee",
}
};
}
catch (Exception e)
{
ex = e;
}
var original = ex.ToString();
var endLine = (int)Math.Min((uint)original.IndexOf('\n'), original.Length);
original = original.Substring(0, endLine);
var stringDemystified = ex.ToStringDemystified();
endLine = (int)Math.Min((uint)stringDemystified.IndexOf('\n'), stringDemystified.Length);
stringDemystified = stringDemystified.Substring(0, endLine);
Assert.Equal(original, stringDemystified);
}
}
}

View File

@ -1,76 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Xunit;
namespace Ben.Demystifier.Test
{
public class TuplesTests
{
[Fact]
public void DemistifiesAsyncMethodWithTuples()
{
Exception demystifiedException = null;
try
{
AsyncThatReturnsTuple().GetAwaiter().GetResult();
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join("", new[] {
"System.ArgumentException: Value does not fall within the expected range.",
" at async Task<(int left, int right)> Ben.Demystifier.Test.TuplesTests.AsyncThatReturnsTuple()",
" at void Ben.Demystifier.Test.TuplesTests.DemistifiesAsyncMethodWithTuples()"});
Assert.Equal(expected, trace);
}
[Fact]
public void DemistifiesListOfTuples()
{
Exception demystifiedException = null;
try
{
ListOfTuples();
}
catch (Exception ex)
{
demystifiedException = ex.Demystify();
}
// Assert
var stackTrace = demystifiedException.ToString();
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries));
var expected = string.Join("", new[] {
"System.ArgumentException: Value does not fall within the expected range.",
" at List<(int left, int right)> Ben.Demystifier.Test.TuplesTests.ListOfTuples()",
" at void Ben.Demystifier.Test.TuplesTests.DemistifiesListOfTuples()"});
Assert.Equal(expected, trace);
}
async Task<(int left, int right)> AsyncThatReturnsTuple()
{
await Task.Delay(1).ConfigureAwait(false);
throw new ArgumentException();
}
List<(int left, int right)> ListOfTuples()
{
throw new ArgumentException();
}
}
}

View File

@ -1,29 +0,0 @@
using System;
using System.Diagnostics;
using Xunit;
namespace Ben.Demystifier.Test
{
public class TypeNameTests
{
[Fact]
public void NestedGenericTypes()
{
try
{
Throw(new Generic<(int, string)>.Nested());
}
catch (Exception ex)
{
var text = ex.ToStringDemystified();
}
}
private void Throw(Generic<(int a, string b)>.Nested nested)
{
throw null;
}
}
public static class Generic<T> { public struct Nested { } }
}

View File

@ -1,17 +0,0 @@
{
"version": "0.4.1",
"publicReleaseRefSpec": [
"^refs/heads/main", // we release out of master
"^refs/heads/dev$", // we release out of develop
"^refs/tags/v\\d+\\.\\d+" // we also release tags starting with vN.N
],
"nugetPackageVersion":{
"semVer": 2
},
"cloudBuild": {
"buildNumber": {
"enabled": true,
"setVersionVariables": true
}
}
}