diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index b6011aa..0000000 --- a/.editorconfig +++ /dev/null @@ -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 \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 5c919e1..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ - -github: [benaadams] diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 03ec545..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -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" diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml deleted file mode 100644 index 2f682e6..0000000 --- a/.github/workflows/pull-request.yaml +++ /dev/null @@ -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 }} - diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index 9a043fe..0000000 --- a/Directory.Build.props +++ /dev/null @@ -1,12 +0,0 @@ - - - latest - true - - - - - - true - - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 8dada3e..0000000 --- a/LICENSE +++ /dev/null @@ -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. diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index 7b5ffcc..0000000 --- a/build.ps1 +++ /dev/null @@ -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 } diff --git a/images/icon.png b/images/icon.png deleted file mode 100644 index b109397..0000000 Binary files a/images/icon.png and /dev/null differ diff --git a/sample/FSharpStackTrace/FSharpStackTrace.fsproj b/sample/FSharpStackTrace/FSharpStackTrace.fsproj deleted file mode 100644 index e313f1a..0000000 --- a/sample/FSharpStackTrace/FSharpStackTrace.fsproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - netcoreapp3.1;net5.0 - - - - - - - - - - - - - - - - - - - diff --git a/sample/FSharpStackTrace/Program.fs b/sample/FSharpStackTrace/Program.fs deleted file mode 100644 index 4482eb7..0000000 --- a/sample/FSharpStackTrace/Program.fs +++ /dev/null @@ -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 -} - -[] -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 diff --git a/sample/StackTrace/Program.cs b/sample/StackTrace/Program.cs deleted file mode 100644 index b3bbd90..0000000 --- a/sample/StackTrace/Program.cs +++ /dev/null @@ -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 s_action = (string s, bool b) => s_func(s, b); - static Func s_func = (string s, bool b) => (RefMethod(s), b); - - Action, object> _action = (Action 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 Iterator(int startAt) - { - var list = new List() { 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 MethodAsync(int value) - { - await Task.Delay(0); - return GenericClass.GenericMethod(ref value); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - static async Task MethodAsync(TValue value) - { - return await MethodLocalAsync(); - - async Task MethodLocalAsync() - { - return await MethodAsync(1); - } - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - static void RunAction(Action lambda, object state) => lambda(state); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - static string RunLambda(Func lambda) => lambda(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - static (string val, bool) Method(string value) - { -#pragma warning disable IDE0039 // Use local function - Func 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 - { - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public static string GenericMethod(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; - } - } -} diff --git a/sample/StackTrace/StackTrace.csproj b/sample/StackTrace/StackTrace.csproj deleted file mode 100644 index 8699af6..0000000 --- a/sample/StackTrace/StackTrace.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - netcoreapp2.1 - - - - - - - diff --git a/test/Ben.Demystifier.Benchmarks/Ben.Demystifier.Benchmarks.csproj b/test/Ben.Demystifier.Benchmarks/Ben.Demystifier.Benchmarks.csproj deleted file mode 100644 index 6c761d2..0000000 --- a/test/Ben.Demystifier.Benchmarks/Ben.Demystifier.Benchmarks.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - netcoreapp2.1;netcoreapp3.1;net462;net5.0 - Release - Exe - - - - - - \ No newline at end of file diff --git a/test/Ben.Demystifier.Benchmarks/Exceptions.cs b/test/Ben.Demystifier.Benchmarks/Exceptions.cs deleted file mode 100644 index c41396e..0000000 --- a/test/Ben.Demystifier.Benchmarks/Exceptions.cs +++ /dev/null @@ -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(); - } -} diff --git a/test/Ben.Demystifier.Benchmarks/Program.cs b/test/Ben.Demystifier.Benchmarks/Program.cs deleted file mode 100644 index ac893e7..0000000 --- a/test/Ben.Demystifier.Benchmarks/Program.cs +++ /dev/null @@ -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); - } -} diff --git a/test/Ben.Demystifier.Test/AggregateException.cs b/test/Ben.Demystifier.Test/AggregateException.cs deleted file mode 100644 index 0e646da..0000000 --- a/test/Ben.Demystifier.Test/AggregateException.cs +++ /dev/null @@ -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.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(); - } - } -} diff --git a/test/Ben.Demystifier.Test/AsyncEnumerableTests.cs b/test/Ben.Demystifier.Test/AsyncEnumerableTests.cs deleted file mode 100644 index 26df76d..0000000 --- a/test/Ben.Demystifier.Test/AsyncEnumerableTests.cs +++ /dev/null @@ -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 Ben.Demystifier.Test.AsyncEnumerableTests.Throw(CancellationToken cancellationToken)+MoveNext()", - " at async IAsyncEnumerable 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 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 Throw([EnumeratorCancellation] CancellationToken cancellationToken) - { - yield return 2; - await Task.Delay(1, cancellationToken).ConfigureAwait(false); - throw new InvalidOperationException(); - } - } -} diff --git a/test/Ben.Demystifier.Test/Ben.Demystifier.Test.csproj b/test/Ben.Demystifier.Test/Ben.Demystifier.Test.csproj deleted file mode 100644 index 2abc975..0000000 --- a/test/Ben.Demystifier.Test/Ben.Demystifier.Test.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - netcoreapp2.1;netcoreapp3.1;net5.0;net6.0 - $(TargetFrameworks);net461 - true - ..\..\src\Ben.Demystifier\key.snk - false - - - - - - - - - - - - - - - diff --git a/test/Ben.Demystifier.Test/DynamicCompilation.cs b/test/Ben.Demystifier.Test/DynamicCompilation.cs deleted file mode 100644 index e9a7364..0000000 --- a/test/Ben.Demystifier.Test/DynamicCompilation.cs +++ /dev/null @@ -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(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); - } - } -} diff --git a/test/Ben.Demystifier.Test/EnhancedStackTraceTests.cs b/test/Ben.Demystifier.Test/EnhancedStackTraceTests.cs deleted file mode 100644 index b03675d..0000000 --- a/test/Ben.Demystifier.Test/EnhancedStackTraceTests.cs +++ /dev/null @@ -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("\\", "/"); - } -} diff --git a/test/Ben.Demystifier.Test/GenericMethodDisplayStringTests.cs b/test/Ben.Demystifier.Test/GenericMethodDisplayStringTests.cs deleted file mode 100644 index 2c02707..0000000 --- a/test/Ben.Demystifier.Test/GenericMethodDisplayStringTests.cs +++ /dev/null @@ -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 - { - // ReSharper disable once StaticMemberInGenericType - public static readonly StackFrame StackFrame; - - static Example() - { - var fun = new Func(() => new StackFrame(0, true)); - - StackFrame = fun(); - - } - - } - - [Fact] - public void DiagnosesGenericMethodDisplayString() - { - var sf = Example.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."); - } - - } - } -} diff --git a/test/Ben.Demystifier.Test/ILReaderTests.cs b/test/Ben.Demystifier.Test/ILReaderTests.cs deleted file mode 100644 index f426b39..0000000 --- a/test/Ben.Demystifier.Test/ILReaderTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Diagnostics.Internal; - -using Xunit; - -namespace Ben.Demystifier.Test -{ - public class ILReaderTests - { - public static TheoryData InlineCilSamples => - new TheoryData - { - // 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)))) - { - } - } - } -} diff --git a/test/Ben.Demystifier.Test/InheritenceTests.cs b/test/Ben.Demystifier.Test/InheritenceTests.cs deleted file mode 100644 index 449a569..0000000 --- a/test/Ben.Demystifier.Test/InheritenceTests.cs +++ /dev/null @@ -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 Method(); - } - - private class ImplClass : BaseClass - { - [MethodImpl(MethodImplOptions.NoInlining)] - public override Task 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); - } - } -} diff --git a/test/Ben.Demystifier.Test/LineEndingsHelper.cs b/test/Ben.Demystifier.Test/LineEndingsHelper.cs deleted file mode 100644 index 8a475f2..0000000 --- a/test/Ben.Demystifier.Test/LineEndingsHelper.cs +++ /dev/null @@ -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, ""); - } - } -} diff --git a/test/Ben.Demystifier.Test/MethodTests.cs b/test/Ben.Demystifier.Test/MethodTests.cs deleted file mode 100644 index a897e13..0000000 --- a/test/Ben.Demystifier.Test/MethodTests.cs +++ /dev/null @@ -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 action = () => throw new ArgumentException(); - action(); - } - - private async Task MethodWithAsyncLambda() - { - Func action = async () => - { - await Task.CompletedTask; - throw new ArgumentException(); - }; - - await action(); - } - } -} diff --git a/test/Ben.Demystifier.Test/MixedStack.cs b/test/Ben.Demystifier.Test/MixedStack.cs deleted file mode 100644 index ee11454..0000000 --- a/test/Ben.Demystifier.Test/MixedStack.cs +++ /dev/null @@ -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+")); - - 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 ExpectedCallStack = new List() - { - "IEnumerable Ben.Demystifier.Test.MixedStack.Iterator()+MoveNext()", - "string string.Join(string separator, IEnumerable values)", - "string Ben.Demystifier.Test.MixedStack+GenericClass.GenericMethod(ref V value)", - "async Task Ben.Demystifier.Test.MixedStack.MethodAsync(int value)", - "async ValueTask Ben.Demystifier.Test.MixedStack.MethodAsync(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 Iterator() - { - var list = new List() { 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 MethodAsync(int value) - { - await Task.Delay(0); - return GenericClass.GenericMethod(ref value); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - static async ValueTask MethodAsync(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 s_action = (string s, bool b) => s_func(s, b); - static Func s_func = (string s, bool b) => (RefMethod(s), b); - static string s = ""; - - static class GenericClass - { - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public static string GenericMethod(ref V value) - { - var returnVal = ""; - for (var i = 0; i < 10; i++) - { - returnVal += string.Join(", ", Iterator()); - } - return returnVal; - } - } - } -} diff --git a/test/Ben.Demystifier.Test/NonThrownException.cs b/test/Ben.Demystifier.Test/NonThrownException.cs deleted file mode 100644 index 2bdf188..0000000 --- a/test/Ben.Demystifier.Test/NonThrownException.cs +++ /dev/null @@ -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); - } - } -} diff --git a/test/Ben.Demystifier.Test/ParameterParamTests.cs b/test/Ben.Demystifier.Test/ParameterParamTests.cs deleted file mode 100644 index 3ce908b..0000000 --- a/test/Ben.Demystifier.Test/ParameterParamTests.cs +++ /dev/null @@ -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(); - } - } -} diff --git a/test/Ben.Demystifier.Test/RecursionTests.cs b/test/Ben.Demystifier.Test/RecursionTests.cs deleted file mode 100644 index 410afc1..0000000 --- a/test/Ben.Demystifier.Test/RecursionTests.cs +++ /dev/null @@ -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 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 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(); - } - } -} diff --git a/test/Ben.Demystifier.Test/ReflectionHelperTests.cs b/test/Ben.Demystifier.Test/ReflectionHelperTests.cs deleted file mode 100644 index 5773e6b..0000000 --- a/test/Ben.Demystifier.Test/ReflectionHelperTests.cs +++ /dev/null @@ -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).IsValueTuple()); - } - - [Fact] - public void IsValueTupleReturnsTrueForTupleWith1ElementWithOpenedType() - { - Assert.True(typeof(ValueTuple<>).IsValueTuple()); - } - - [Fact] - public void IsValueTupleReturnsTrueForTupleWith6ElementsWithOpenedType() - { - Assert.True(typeof(ValueTuple<,,,,,>).IsValueTuple()); - } - } -} diff --git a/test/Ben.Demystifier.Test/ResolvedMethodTests.cs b/test/Ben.Demystifier.Test/ResolvedMethodTests.cs deleted file mode 100644 index 008b554..0000000 --- a/test/Ben.Demystifier.Test/ResolvedMethodTests.cs +++ /dev/null @@ -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()); - } - } -} diff --git a/test/Ben.Demystifier.Test/ToDemystifiedStringTests.cs b/test/Ben.Demystifier.Test/ToDemystifiedStringTests.cs deleted file mode 100644 index f4b6cd2..0000000 --- a/test/Ben.Demystifier.Test/ToDemystifiedStringTests.cs +++ /dev/null @@ -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); - } - } -} diff --git a/test/Ben.Demystifier.Test/TuplesTests.cs b/test/Ben.Demystifier.Test/TuplesTests.cs deleted file mode 100644 index 698336e..0000000 --- a/test/Ben.Demystifier.Test/TuplesTests.cs +++ /dev/null @@ -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(); - } - } -} diff --git a/test/Ben.Demystifier.Test/TypeNameTests.cs b/test/Ben.Demystifier.Test/TypeNameTests.cs deleted file mode 100644 index 6c1151a..0000000 --- a/test/Ben.Demystifier.Test/TypeNameTests.cs +++ /dev/null @@ -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 { public struct Nested { } } -} diff --git a/version.json b/version.json deleted file mode 100644 index f7312b8..0000000 --- a/version.json +++ /dev/null @@ -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 - } - } -}