diff --git a/.editorconfig b/.editorconfig
index be9f7c581..4cab270c3 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,29 +1,109 @@
-; EditorConfig to support per-solution formatting.
-; Use the EditorConfig VS add-in to make this work.
-; http://editorconfig.org/
+# EditorConfig is awesome:http://EditorConfig.org
-; This is the default for the codeline.
+# top-most EditorConfig file
root = true
+# Don't use tabs for indentation.
[*]
-end_of_line = CRLF
+indent_style = space
+# (Please don't specify an indent_size here; that has too many unintended consequences.)
-[*.{cs,txt,md}]
-indent_style = tab
+# Code files
+[*.{cs,csx,vb,vbx}]
indent_size = 4
-[*.{sln,proj,csproj,fsproj,vbproj,props,targets,xml,xdoc,config,nuspec}]
-indent_style = tab
+# Xml project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}]
indent_size = 2
-[*.Designer.cs]
-indent_style = space
-indent_size = 4
+# Xml config files
+[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
-[*.resx]
-indent_style = space
+# YAML files
+[*.{yaml,yml}]
indent_size = 2
-[appveyor.yml]
-indent_style = space
+# JSON files
+[*.json]
indent_size = 2
+
+# Dotnet code style settings:
+[*.{cs,vb}]
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# CSharp code style settings:
+
+# IDE0040: Add accessibility modifiers
+dotnet_style_require_accessibility_modifiers = omit_if_default:error
+
+# IDE0040: Add accessibility modifiers
+dotnet_diagnostic.IDE0040.severity = error
+
+[*.cs]
+# Top-level files are definitely OK
+csharp_using_directive_placement = outside_namespace:silent
+csharp_style_namespace_declarations = block_scoped:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_prefer_braces = true:silent
+
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = true:suggestion
+
+# Prefer method-like constructs to have an expression-body
+csharp_style_expression_bodied_methods = true:none
+csharp_style_expression_bodied_constructors = true:none
+csharp_style_expression_bodied_operators = true:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:error
+csharp_style_pattern_matching_over_as_with_null_check = true:error
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Newline settings
+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
+
+# Test settings
+[**/*Tests*/**{.cs,.vb}]
+# xUnit1013: Public method should be marked as test. Allows using records as test classes
+dotnet_diagnostic.xUnit1013.severity = none
+
+# CS9113: Parameter is unread (usually, ITestOutputHelper)
+dotnet_diagnostic.CS9113.severity = none
+
+# Default severity for analyzer diagnostics with category 'Style'
+dotnet_analyzer_diagnostic.category-Style.severity = none
+
+# VSTHRD200: Use "Async" suffix for async methods
+dotnet_diagnostic.VSTHRD200.severity = none
diff --git a/.gitattributes b/.gitattributes
index b4bc13442..7c375796c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,24 @@
-# Auto detect text files and perform LF normalization
-* text=auto
\ No newline at end of file
+# sln, csproj files (and friends) are always CRLF, even on linux
+*.sln text eol=crlf
+*.proj text eol=crlf
+*.csproj text eol=crlf
+
+# These are windows specific files which we may as well ensure are
+# always crlf on checkout
+*.bat text eol=crlf
+*.cmd text eol=crlf
+
+# Opt in known filetypes to always normalize line endings on checkin
+# and always use native endings on checkout
+*.c text
+*.config text
+*.h text
+*.cs text
+*.md text
+*.tt text
+*.txt text
+
+# Some must always be checked out as lf so enforce that for those files
+# If these are not lf then bash/cygwin on windows will not be able to
+# excute the files
+*.sh text eol=lf
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..ec364b622
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,34 @@
+# 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
+ directory: /
+ schedule:
+ interval: daily
+ groups:
+ Azure:
+ patterns:
+ - "Azure*"
+ - "Microsoft.Azure*"
+ System:
+ patterns:
+ - "System*"
+ Extensions:
+ patterns:
+ - "Microsoft.Extensions*"
+ Web:
+ patterns:
+ - "Microsoft.AspNetCore*"
+ Tests:
+ patterns:
+ - "Microsoft.NET.Tests*"
+ - "xunit*"
+ - "coverlet*"
+ ThisAssembly:
+ patterns:
+ - "ThisAssembly*"
+ ProtoBuf:
+ patterns:
+ - "protobuf-*"
diff --git a/.github/release.yml b/.github/release.yml
new file mode 100644
index 000000000..9a018cd4f
--- /dev/null
+++ b/.github/release.yml
@@ -0,0 +1,32 @@
+changelog:
+ exclude:
+ labels:
+ - bydesign
+ - dependencies
+ - duplicate
+ - question
+ - invalid
+ - wontfix
+ - need info
+ - docs
+ - techdebt
+ authors:
+ - devlooped-bot
+ - dependabot
+ - github-actions
+ categories:
+ - title: β¨ Implemented enhancements
+ labels:
+ - enhancement
+ - title: π Fixed bugs
+ labels:
+ - bug
+ - title: π Documentation updates
+ labels:
+ - docs
+ - title: π¨ Other
+ labels:
+ - '*'
+ exclude:
+ labels:
+ - dependencies
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..0007ac7b2
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,67 @@
+ο»Ώ# Builds and runs tests in all three supported OSes
+# Pushes CI feed if secrets.SLEET_CONNECTION is provided
+
+name: build
+on:
+ workflow_dispatch:
+ push:
+ branches: [ main, dev, 'dev/*', 'feature/*', 'rel/*' ]
+ paths-ignore:
+ - changelog.md
+ - code-of-conduct.md
+ - security.md
+ - support.md
+ - readme.md
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+env:
+ DOTNET_NOLOGO: true
+ VersionPrefix: 42.42.${{ github.run_number }}
+ VersionLabel: ${{ github.ref }}
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ build:
+ runs-on: windows-latest
+ steps:
+ - name: π€ checkout
+ uses: actions/checkout@v2
+ with:
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: π build
+ run: dotnet build -m:1
+
+ - name: π§ͺ test
+ uses: ./.github/workflows/test
+
+ - name: π¦ pack
+ run: dotnet pack -m:1
+
+ # Only push CI package to sleet feed if building on ubuntu (fastest)
+ - name: π sleet
+ env:
+ SLEET_CONNECTION: ${{ secrets.SLEET_CONNECTION }}
+ if: env.SLEET_CONNECTION != ''
+ run: |
+ dotnet tool install -g --version 4.0.18 sleet
+ sleet push bin --config none -f --verbose -p "SLEET_FEED_CONTAINER=nuget" -p "SLEET_FEED_CONNECTIONSTRING=${{ secrets.SLEET_CONNECTION }}" -p "SLEET_FEED_TYPE=azure" || echo "No packages found"
+
+ dotnet-format:
+ runs-on: windows-latest
+ steps:
+ - name: π€ checkout
+ uses: actions/checkout@v2
+ with:
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: β ensure format
+ run: |
+ dotnet format whitespace --verify-no-changes -v:diag --exclude ~/.nuget
+ dotnet format style --verify-no-changes -v:diag --exclude ~/.nuget
diff --git a/.github/workflows/changelog.config b/.github/workflows/changelog.config
new file mode 100644
index 000000000..cd34ee757
--- /dev/null
+++ b/.github/workflows/changelog.config
@@ -0,0 +1,9 @@
+usernames-as-github-logins=true
+issues_wo_labels=true
+pr_wo_labels=true
+exclude-labels=bydesign,dependencies,duplicate,question,invalid,wontfix,need info,docs
+enhancement-label=:sparkles: Implemented enhancements:
+bugs-label=:bug: Fixed bugs:
+issues-label=:hammer: Other:
+pr-label=:twisted_rightwards_arrows: Merged:
+unreleased=false
diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml
new file mode 100644
index 000000000..b120b7360
--- /dev/null
+++ b/.github/workflows/changelog.yml
@@ -0,0 +1,39 @@
+ο»Ώname: changelog
+on:
+ workflow_dispatch:
+ release:
+ types: [released]
+
+jobs:
+ changelog:
+ runs-on: ubuntu-latest
+ steps:
+ - name: π€ defaults
+ uses: devlooped/actions-bot@v1
+ with:
+ name: ${{ secrets.BOT_NAME }}
+ email: ${{ secrets.BOT_EMAIL }}
+ gh_token: ${{ secrets.GH_TOKEN }}
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: π€ checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ ref: main
+ token: ${{ env.GH_TOKEN }}
+
+ - name: β ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.0.3
+
+ - name: β changelog
+ run: |
+ gem install github_changelog_generator
+ github_changelog_generator --user ${GITHUB_REPOSITORY%/*} --project ${GITHUB_REPOSITORY##*/} --token $GH_TOKEN --o changelog.md --config-file .github/workflows/changelog.config
+
+ - name: π changelog
+ run: |
+ git add changelog.md
+ (git commit -m "π Update changelog with ${GITHUB_REF#refs/*/}" && git push) || echo "Done"
\ No newline at end of file
diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml
new file mode 100644
index 000000000..0255974f2
--- /dev/null
+++ b/.github/workflows/combine-prs.yml
@@ -0,0 +1,157 @@
+# Source: https://github.com/hrvey/combine-prs-workflow
+# Tweaks: regex support for branch
+
+name: 'β combine-prs'
+
+on:
+ workflow_dispatch:
+ inputs:
+ branchExpression:
+ description: 'Regular expression to match against PR branches to find combinable PRs'
+ required: true
+ default: 'dependabot'
+ mustBeGreen:
+ description: 'Only combine PRs that are green (status is success)'
+ required: true
+ default: true
+ combineTitle:
+ description: 'Title of the combined PR'
+ required: true
+ default: 'β¬οΈ Bump dependencies'
+ combineBranchName:
+ description: 'Name of the branch to combine PRs into'
+ required: true
+ default: 'combine-prs'
+ ignoreLabel:
+ description: 'Exclude PRs with this label'
+ required: true
+ default: 'nocombine'
+
+jobs:
+ combine-prs:
+ name: ${{ github.event.inputs.combineBranchName }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/github-script@v6
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
+ owner: context.repo.owner,
+ repo: context.repo.repo
+ });
+ const branchRegExp = new RegExp(`${{github.event.inputs.branchExpression}}`);
+ let branchesAndPRStrings = [];
+ let baseBranch = null;
+ let baseBranchSHA = null;
+ for (const pull of pulls) {
+ const branch = pull['head']['ref'];
+ console.log('Pull for branch: ' + branch);
+ if (branchRegExp.test(branch)) {
+ console.log('Branch matched: ' + branch);
+ let statusOK = true;
+ if(${{ github.event.inputs.mustBeGreen }}) {
+ console.log('Checking green status: ' + branch);
+ const stateQuery = `query($owner: String!, $repo: String!, $pull_number: Int!) {
+ repository(owner: $owner, name: $repo) {
+ pullRequest(number:$pull_number) {
+ commits(last: 1) {
+ nodes {
+ commit {
+ statusCheckRollup {
+ state
+ }
+ }
+ }
+ }
+ }
+ }
+ }`
+ const vars = {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: pull['number']
+ };
+ const result = await github.graphql(stateQuery, vars);
+ const [{ commit }] = result.repository.pullRequest.commits.nodes;
+ const state = commit.statusCheckRollup.state
+ console.log('Validating status: ' + state);
+ if(state != 'SUCCESS') {
+ console.log('Discarding ' + branch + ' with status ' + state);
+ statusOK = false;
+ }
+ }
+ console.log('Checking labels: ' + branch);
+ const labels = pull['labels'];
+ for(const label of labels) {
+ const labelName = label['name'];
+ console.log('Checking label: ' + labelName);
+ if(labelName == '${{ github.event.inputs.ignoreLabel }}') {
+ console.log('Discarding ' + branch + ' with label ' + labelName);
+ statusOK = false;
+ }
+ }
+ if (statusOK) {
+ console.log('Adding branch to array: ' + branch);
+ const prString = '#' + pull['number'] + ' ' + pull['title'];
+ branchesAndPRStrings.push({ branch, prString });
+ baseBranch = pull['base']['ref'];
+ baseBranchSHA = pull['base']['sha'];
+ }
+ }
+ }
+ if (branchesAndPRStrings.length == 0) {
+ core.setFailed('No PRs/branches matched criteria');
+ return;
+ }
+ if (branchesAndPRStrings.length == 1) {
+ core.setFailed('Only one PR/branch matched criteria');
+ return;
+ }
+
+ try {
+ await github.rest.git.createRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: 'refs/heads/' + '${{ github.event.inputs.combineBranchName }}',
+ sha: baseBranchSHA
+ });
+ } catch (error) {
+ console.log(error);
+ core.setFailed('Failed to create combined branch - maybe a branch by that name already exists?');
+ return;
+ }
+
+ let combinedPRs = [];
+ let mergeFailedPRs = [];
+ for(const { branch, prString } of branchesAndPRStrings) {
+ try {
+ await github.rest.repos.merge({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ base: '${{ github.event.inputs.combineBranchName }}',
+ head: branch,
+ });
+ console.log('Merged branch ' + branch);
+ combinedPRs.push(prString);
+ } catch (error) {
+ console.log('Failed to merge branch ' + branch);
+ mergeFailedPRs.push(prString);
+ }
+ }
+
+ console.log('Creating combined PR');
+ const combinedPRsString = combinedPRs.join('\n');
+ let body = 'β Combined PRs:\n' + combinedPRsString;
+ if(mergeFailedPRs.length > 0) {
+ const mergeFailedPRsString = mergeFailedPRs.join('\n');
+ body += '\n\nβ οΈ The following PRs were left out due to merge conflicts:\n' + mergeFailedPRsString
+ }
+ await github.rest.pulls.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ title: 'β ${{github.event.inputs.combineTitle}}',
+ head: '${{ github.event.inputs.combineBranchName }}',
+ base: baseBranch,
+ body: body
+ });
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..f3e8d0a94
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,38 @@
+ο»Ώ# Builds a final release version and pushes to nuget.org
+# whenever a release is published.
+# Requires: secrets.NUGET_API_KEY
+
+name: publish
+on:
+ release:
+ types: [released]
+
+env:
+ DOTNET_NOLOGO: true
+ Configuration: Release
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ publish:
+ runs-on: windows-latest
+ steps:
+ - name: π€ checkout
+ uses: actions/checkout@v2
+ with:
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: π build
+ run: dotnet build -m:1 -p:version=${GITHUB_REF#refs/*/v}
+
+ - name: π§ͺ test
+ uses: ./.github/workflows/test
+
+ - name: π¦ pack
+ run: dotnet pack -m:1 -p:version=${GITHUB_REF#refs/*/v}
+
+ - name: π nuget
+ run: dotnet nuget push ./bin/**/*.nupkg -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} --skip-duplicate
diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml
new file mode 100644
index 000000000..4a7dbae33
--- /dev/null
+++ b/.github/workflows/test/action.yml
@@ -0,0 +1,36 @@
+name: test
+description: runs dotnet tests with retry
+runs:
+ using: "composite"
+ steps:
+ - name: π§ͺ test
+ shell: bash --noprofile --norc {0}
+ env:
+ LC_ALL: en_US.utf8
+ run: |
+ [ -f .bash_profile ] && source .bash_profile
+ counter=0
+ exitcode=0
+ reset="\e[0m"
+ warn="\e[0;33m"
+ while [ $counter -lt 6 ]
+ do
+ # run test and forward output also to a file in addition to stdout (tee command)
+ if [ $filter ]
+ then
+ echo -e "${warn}Retry $counter for $filter ${reset}"
+ dotnet test --no-build -m:1 --blame-hang --blame-hang-timeout 5m --filter=$filter | tee ./output.log
+ else
+ dotnet test --no-build -m:1 --blame-hang --blame-hang-timeout 5m | tee ./output.log
+ fi
+ # capture dotnet test exit status, different from tee
+ exitcode=${PIPESTATUS[0]}
+ if [ $exitcode == 0 ]
+ then
+ exit 0
+ fi
+ # cat output, get failed test names, remove trailing whitespace, sort+dedupe, join as FQN~TEST with |, remove trailing |.
+ filter=$(cat ./output.log | grep -o -P '(?<=\sFailed\s)[\w\._]*' | sed 's/ *$//g' | sort -u | awk 'BEGIN { ORS="|" } { print("FullyQualifiedName~" $0) }' | grep -o -P '.*(?=\|$)')
+ ((counter++))
+ done
+ exit $exitcode
diff --git a/.gitignore b/.gitignore
index 0f7dd1ba4..0c18de793 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,35 @@
-out
bin
+app
obj
+artifacts
+pack
+TestResults
+.vs
+.vscode
+.idea
+
*.suo
+*.sdf
+*.userprefs
*.user
+*.nupkg
+*.metaproj
+*.tmp
+*.log
*.cache
-.vs
-*/**/.*
+*.binlog
+*.zip
+__azurite*.*
+__*__
+
+.nuget
+*.lock.json
+*.nuget.props
+*.nuget.targets
+
+node_modules
+_site
+.jekyll-metadata
+.jekyll-cache
+Gemfile.lock
+package-lock.json
diff --git a/.netconfig b/.netconfig
index c2bb4a84e..e5d80548a 100644
--- a/.netconfig
+++ b/.netconfig
@@ -18,3 +18,96 @@
sha = 8990ebb36199046e0b8098bad9e46dcef739c56e
etag = e1dc114d2e8b57d50649989d32dbf0c9080ec77da3738a4cc79e9256d6ca5d3e
weak
+[file]
+ url = https://github.com/devlooped/oss
+[file ".netconfig"]
+ url = https://github.com/devlooped/oss/blob/main/.netconfig
+ skip
+[file "readme.md"]
+ url = https://github.com/devlooped/oss/blob/main/readme.md
+ skip
+[file ".editorconfig"]
+ url = https://github.com/devlooped/oss/blob/main/.editorconfig
+ sha = c779d3d4e468358106dea03e93ba2cd35bb01ecb
+ etag = 7298c6450967975a8782b5c74f3071e1910fc59686e48f9c9d5cd7c68213cf59
+ weak
+[file ".gitattributes"]
+ url = https://github.com/devlooped/oss/blob/main/.gitattributes
+ sha = 0683ee777d7d878d4bf013d7deea352685135a05
+ etag = 7acb32f5fa6d4ccd9c824605a7c2b8538497f0068c165567807d393dcf4d6bb7
+ weak
+[file ".github/dependabot.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/dependabot.yml
+ sha = cba10bbf7bb08d841d2ddc990b67bc3f2c58fba0
+ etag = fc84e2bb7a348609b75bb20145333306e2030083c6929edcc4f675907b8c52ad
+ weak
+[file ".github/release.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/release.yml
+ sha = 1afd173fe8f81b510c597737b0d271218e81fa73
+ etag = 482dc2c892fc7ce0cb3a01eb5d9401bee50ddfb067d8cb85873555ce63cf5438
+ weak
+[file ".github/workflows/build.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/workflows/build.yml
+ skip
+[file ".github/workflows/changelog.config"]
+ url = https://github.com/devlooped/oss/blob/main/.github/workflows/changelog.config
+ sha = 055a8b7c94b74ae139cce919d60b83976d2a9942
+ etag = ddb17acb5872e9e69a76f9dec0ca590f25382caa2ccf750df058dcabb674db2b
+ weak
+[file ".github/workflows/changelog.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/workflows/changelog.yml
+ sha = a4b66eb5f4dfb9704502f19f59ba33cb4855188c
+ etag = 54c0b571648b1055beb3ddac180b34e93a9869b9f0277de306901b2c1dbe0b2c
+ weak
+[file ".github/workflows/combine-prs.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/workflows/combine-prs.yml
+ sha = c1610886eba42cb250e3894aed40c0a258cd383d
+ etag = 598ee294649a44d4c5d5934416c01183597d08aa7db7938453fd2bbf52a4e64d
+ weak
+[file ".github/workflows/publish.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/workflows/publish.yml
+ skip
+[file ".github/workflows/test/action.yml"]
+ url = https://github.com/devlooped/oss/blob/main/.github/workflows/test/action.yml
+ sha = 9a1b07589b9bde93bc12528e9325712a32dec418
+ etag = b54216ac431a83ce5477828d391f02046527e7f6fffd21da1d03324d352c3efb
+ weak
+[file ".gitignore"]
+ url = https://github.com/devlooped/oss/blob/main/.gitignore
+ sha = b87a8a795a4c2b6830602225c066c11108552a99
+ etag = 96e0860052044780f1fc9e3bdfbee09d82d5dddb8b1217d67460fc7330a64dd8
+ weak
+[file "Directory.Build.rsp"]
+ url = https://github.com/devlooped/oss/blob/main/Directory.Build.rsp
+ sha = ae25fae9d7daf0cb47d537ba870914aa3052f0c9
+ etag = 6a6c6e1d3895df953abf14c82b0899e3eea75cdcd679f6212dcfea15183d73d6
+ weak
+[file "_config.yml"]
+ url = https://github.com/devlooped/oss/blob/main/_config.yml
+ sha = fa83a5161ba52bc5d510ce0ba75ee0b1f8d4bc63
+ etag = 9139148f845adf503fd3c3c140eb64421fc476a1f9c027fc50825c0efb05f557
+ weak
+[file "assets/css/style.scss"]
+ url = https://github.com/devlooped/oss/blob/main/assets/css/style.scss
+ sha = 9db26e2710b084d219d6355339d822f159bf5780
+ etag = f710d8919abfd5a8d00050b74ba7d0bb05c6d02e40842a3012eb96555c208504
+ weak
+[file "license.txt"]
+ url = https://github.com/devlooped/oss/blob/main/license.txt
+ skip
+[file "src/Directory.Build.props"]
+ url = https://github.com/devlooped/oss/blob/main/src/Directory.Build.props
+ sha = 6ae80a175a8f926ac5d9ffb0f6afd55d85cc9320
+ etag = 69d4b16c14d5047b3ed812dbf556b0b8d77deb86f73af04b9bd3640220056fa8
+ weak
+[file "src/Directory.Build.targets"]
+ url = https://github.com/devlooped/oss/blob/main/src/Directory.Build.targets
+ sha = 1514d15399a7d545ad92a0e9d57dc8295fdd6af8
+ etag = 428f80b0786ff17b836c7a5b0640948724855d17933e958642b22849ac00dadb
+ weak
+[file "src/kzu.snk"]
+ url = https://github.com/devlooped/oss/blob/main/src/kzu.snk
+ skip
+[file "src/nuget.config"]
+ url = https://github.com/devlooped/oss/blob/main/src/nuget.config
+ skip
diff --git a/Before.Moq.sln.targets b/Before.Moq.sln.targets
deleted file mode 100644
index ebca5240d..000000000
--- a/Before.Moq.sln.targets
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f48ff339a..c79d0f448 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,13 +3,6 @@
Moq welcomes your contributions! :heart:
-## A quick word about the upcoming next major version of Moq (v5)
-
-The next major version of Moq is currently in active development (over at the [moq/moq](https://github.com/moq/moq) repository). Because of this, we are somewhat hesitant about big API changes in Moq v4. The plan for v5 is to have an API very similar to Moq v4 (to make migration easy). Therefore, any radical changes in v4 might have to be reproduced in v5, which costs additional time.
-
-For this reason, the main (but not sole!) focus at this repository (v4) is on bug fixing, improving stability, and performance. That being said, small additions stand a good chance of getting in if they seem generally useful.
-
-
## Asking usage questions
This repository's focus is on the development of Moq (i.e. fixing bugs and improving features; see above). Because the Moq team is rather small, our resources to answer usage questions is very limited. You might be better off asking usage questions over at [Stack Overflow](https://stackoverflow.com) as your question will meet with a much larger audience. Please observe SO's rules and etiquette, and tag your question with `moq`.
@@ -17,9 +10,9 @@ This repository's focus is on the development of Moq (i.e. fixing bugs and impro
## Submitting a bug report (as an issue)
-If you think you've found a bug, please start by searching [the changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md) and [GitHub issues](https://github.com/moq/moq4/issues) (both open and closed ones!) to see if the problem has already been addressed or documented in any way.
+If you think you've found a bug, please start by searching [the changelog](https://github.com/moq/moq/blob/main/CHANGELOG.md) and [GitHub issues](https://github.com/moq/moq/issues) (both open and closed ones!) to see if the problem has already been addressed or documented in any way.
-If you find nothing of relevance, [open a new issue](https://github.com/moq/moq4/issues/new).
+If you find nothing of relevance, [open a new issue](https://github.com/moq/moq/issues/new).
**What to include:** Try to include the following information in it:
diff --git a/Directory.Build.props b/Directory.Build.props
deleted file mode 100644
index 304a15010..000000000
--- a/Directory.Build.props
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- $(MSBuildThisFileDirectory)
- $(RootDirectory)build\
- $(RootDirectory)out\
- Release
-
-
-
-
-
-
-
-
diff --git a/Directory.Build.rsp b/Directory.Build.rsp
new file mode 100644
index 000000000..7c0dbc1ec
--- /dev/null
+++ b/Directory.Build.rsp
@@ -0,0 +1,5 @@
+# See https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files
+-nr:false
+-m:1
+-v:m
+-clp:Summary;ForceNoAlign
\ No newline at end of file
diff --git a/GitInfo.txt b/GitInfo.txt
deleted file mode 100644
index df66f9557..000000000
--- a/GitInfo.txt
+++ /dev/null
@@ -1 +0,0 @@
-4.18.4
diff --git a/Moq.sln b/Moq.sln
index 3b630c3d8..5075d6c07 100644
--- a/Moq.sln
+++ b/Moq.sln
@@ -1,24 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2002
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.33913.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A5A5B8C3-D43F-43C6-AEC7-6FA7C35B8BE9}"
ProjectSection(SolutionItems) = preProject
- appveyor.yml = appveyor.yml
+ .netconfig = .netconfig
+ .github\workflows\build.yml = .github\workflows\build.yml
CHANGELOG.md = CHANGELOG.md
CONTRIBUTING.md = CONTRIBUTING.md
- GitInfo.txt = GitInfo.txt
+ src\Directory.props = src\Directory.props
License.txt = License.txt
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq", "src\Moq\Moq.csproj", "{1C91AC30-5977-4BE5-BA67-8EB186C03514}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Tests", "tests\Moq.Tests\Moq.Tests.csproj", "{81BBC911-4916-4E10-A955-752AE47CB2B9}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Tests", "src\Moq.Tests\Moq.Tests.csproj", "{81BBC911-4916-4E10-A955-752AE47CB2B9}"
EndProject
-Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Moq.Tests.VisualBasic", "tests\Moq.Tests.VisualBasic\Moq.Tests.VisualBasic.vbproj", "{840A8B2E-3D4B-4521-A61A-0291562CDC8B}"
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Moq.Tests.VisualBasic", "src\Moq.Tests.VisualBasic\Moq.Tests.VisualBasic.vbproj", "{840A8B2E-3D4B-4521-A61A-0291562CDC8B}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Moq.Tests.FSharpTypes", "tests\Moq.Tests.FSharpTypes\Moq.Tests.FSharpTypes.fsproj", "{2D9EE4E0-8433-4F9C-A330-C4D74B956E0B}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Moq.Tests.FSharpTypes", "src\Moq.Tests.FSharpTypes\Moq.Tests.FSharpTypes.fsproj", "{2D9EE4E0-8433-4F9C-A330-C4D74B956E0B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/_config.yml b/_config.yml
new file mode 100644
index 000000000..a61f7e0bf
--- /dev/null
+++ b/_config.yml
@@ -0,0 +1,3 @@
+theme: jekyll-theme-slate
+
+exclude: [ 'src/', '*.sln', 'Gemfile*', '*.rsp' ]
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 34b318e3e..000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-image: Visual Studio 2022
-
-init:
- - git config --global core.autocrlf input
-
-environment:
- MSBUILD_LOGGER: C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll
- SN_EXE: C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7 Tools\x64\sn.exe
- SNK_FILE: Moq.snk
- FSHARPTYPES_DLL: .\tests\Moq.Tests\bin\Release\net472\Moq.Tests.FSharpTypes.dll
-
-build_script:
- - dotnet restore Moq.sln # --logger:"%MSBUILD_LOGGER%"
- - dotnet build Moq.sln --configuration Release --no-restore # --logger:"%MSBUILD_LOGGER%"
-
-before_test:
- - call "%SN_EXE%" -R %FSHARPTYPES_DLL% %SNK_FILE%
-
-test_script:
- - dotnet test --no-build --configuration Release .\tests\Moq.Tests\Moq.Tests.csproj # --logger:"%MSBUILD_LOGGER%"
-
-after_test:
- - dotnet pack Moq.sln --no-build --no-restore --configuration Release --output out # --logger:"%MSBUILD_LOGGER%"
-
-deploy:
- - provider: NuGet
- api_key:
- secure: 5dsPohRA1/Bm/yD1DTUDZ5ZUAH7+jjWWcy6wnFZrWDKG4C8VOInfdWj/71SZgHYG
- on:
- appveyor_repo_tag: true
-
-nuget:
- project_feed: true
-
-artifacts:
- - path: 'out\*.nupkg'
diff --git a/assets/css/style.scss b/assets/css/style.scss
new file mode 100644
index 000000000..5e165a3ca
--- /dev/null
+++ b/assets/css/style.scss
@@ -0,0 +1,26 @@
+---
+---
+
+@import "jekyll-theme-slate";
+
+.inner {
+ max-width: 960px;
+}
+
+pre, code {
+ background-color: unset;
+ font-size: unset;
+}
+
+ code {
+ font-size: 0.80em;
+}
+
+h1 > img {
+ border: unset;
+ box-shadow: unset;
+ vertical-align: middle;
+ -moz-box-shadow: unset;
+ -o-box-shadow: unset;
+ -ms-box-shadow: unset;
+}
diff --git a/moq-bigger.png b/assets/img/moq-bigger.png
similarity index 100%
rename from moq-bigger.png
rename to assets/img/moq-bigger.png
diff --git a/moq-icon.png b/assets/img/moq-icon.png
similarity index 100%
rename from moq-icon.png
rename to assets/img/moq-icon.png
diff --git a/moq-small.png b/assets/img/moq-small.png
similarity index 100%
rename from moq-small.png
rename to assets/img/moq-small.png
diff --git a/moq.png b/assets/img/moq.png
similarity index 100%
rename from moq.png
rename to assets/img/moq.png
diff --git a/build/AssemblyInfo.props b/build/AssemblyInfo.props
deleted file mode 100644
index 9899c3eda..000000000
--- a/build/AssemblyInfo.props
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- True
- $(MSBuildProjectName)
- Moq
- Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors
-
-
-
diff --git a/build/GitVersion.props b/build/GitVersion.props
deleted file mode 100644
index 78ae6e9e5..000000000
--- a/build/GitVersion.props
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- True
- True
- False
-
-
-
-
-
-
-
-
- $(GitBaseVersionMajor).$(GitBaseVersionMinor).0.0
- $(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch).$(GitCommits)
- $(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch)$(GitSemVerDashLabel)+sha.$(GitCommit)
- $(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch).$(GitCommits)$(GitSemVerDashLabel)+sha.$(GitCommit)
-
-
-
-
-
- $(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)
- configuration=$(Configuration);version=$(PackageVersion)
-
-
-
-
diff --git a/build/SignAssembly.props b/build/SignAssembly.props
deleted file mode 100644
index 732e172fd..000000000
--- a/build/SignAssembly.props
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- True
- False
- False
- $(RootDirectory)Moq.snk
-
-
-
diff --git a/build/SourceLink.props b/build/SourceLink.props
deleted file mode 100644
index e36e2b217..000000000
--- a/build/SourceLink.props
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- True
-
-
-
-
-
-
-
diff --git a/build/xUnit.props b/build/xUnit.props
deleted file mode 100644
index 3872eb94f..000000000
--- a/build/xUnit.props
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 000000000..6b9a668f1
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,146 @@
+
+
+
+
+ false
+
+ true
+
+
+
+
+ $(CI)
+
+
+
+ Daniel Cazzulino
+ Copyright (C) Daniel Cazzulino and Contributors. All rights reserved.
+ false
+ MIT
+
+
+ icon.png
+ readme.md
+
+ icon.png
+ readme.md
+
+ true
+ true
+
+ $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\bin'))
+
+
+ true
+
+
+ true
+
+
+
+ Release
+ true
+ false
+ Latest
+
+
+ false
+
+ embedded
+ true
+ enable
+
+ strict
+
+
+ $(MSBuildProjectName)
+ $(MSBuildProjectName.IndexOf('.'))
+ $(MSBuildProjectName.Substring(0, $(RootNamespaceDot)))
+
+
+ $(DefaultItemExcludes);*.binlog;*.zip;*.rsp;*.items;**/TestResults/**/*.*
+
+ true
+ true
+ true
+ true
+
+
+ true
+
+
+ false
+
+
+ NU5105;$(NoWarn)
+
+ true
+
+
+ true
+
+
+ LatestMinor
+
+
+
+
+ $(MSBuildThisFileDirectory)kzu.snk
+
+ 002400000480000094000000060200000024000052534131000400000100010051155fd0ee280be78d81cc979423f1129ec5dd28edce9cd94fd679890639cad54c121ebdb606f8659659cd313d3b3db7fa41e2271158dd602bb0039a142717117fa1f63d93a2d288a1c2f920ec05c4858d344a45d48ebd31c1368ab783596b382b611d8c92f9c1b3d338296aa21b12f3bc9f34de87756100c172c52a24bad2db
+ 00352124762f2aa5
+ true
+
+
+
+
+ 42.42.42
+
+
+
+ <_VersionLabel>$(VersionLabel.Replace('refs/heads/', ''))
+
+ <_VersionLabel Condition="$(_VersionLabel.Contains('refs/pull/'))">$(VersionLabel.TrimEnd('.0123456789'))
+
+ <_VersionLabel>$(_VersionLabel.Replace('refs/pull/', 'pr'))
+
+ <_VersionLabel>$(_VersionLabel.Replace('/merge', ''))
+
+ <_VersionLabel>$(_VersionLabel.Replace('/', '-'))
+
+
+ $(_VersionLabel)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
new file mode 100644
index 000000000..5bd401967
--- /dev/null
+++ b/src/Directory.Build.targets
@@ -0,0 +1,178 @@
+
+
+
+
+ CI;$(DefineConstants)
+
+
+
+ true
+ true
+
+
+
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.0.0
+ $(VersionPrefix)-$(VersionSuffix)
+ $(VersionPrefix)
+
+
+
+
+ $(PackFolder)
+ $(PackFolderPath.Replace('\$(TargetFramework)', ''))
+ $(IntermediateOutputPath)$(PackFolderPath)\
+ $(OutputPath)$(PackFolderPath)\
+ $(OutputPath)
+
+
+
+
+ pr$(GITHUB_REF.Replace('refs/pull/', '').Replace('/merge', ''))
+ $(GITHUB_REF.Replace('refs/heads/', '').Replace('refs/tags/', ''))
+
+ $(BUILD_SOURCEBRANCH.Replace('refs/heads/', '').Replace('refs/tags/', ''))
+
+ pr$(APPVEYOR_PULL_REQUEST_NUMBER)
+ $(APPVEYOR_REPO_TAG_NAME)
+ $(APPVEYOR_REPO_BRANCH)
+
+ $(TEAMCITY_BUILD_BRANCH)
+
+ pr$(TRAVIS_PULL_REQUEST)
+ $(TRAVIS_BRANCH)
+
+ pr$(CIRCLE_PR_NUMBER)
+ $(CIRCLE_TAG)
+ $(CIRCLE_BRANCH)
+
+ $(CI_COMMIT_TAG)
+ pr$(CI_MERGE_REQUEST_IID)
+ pr$(CI_EXTERNAL_PULL_REQUEST_IID)
+ $(CI_COMMIT_BRANCH)
+
+ pr$(BUDDY_EXECUTION_PULL_REQUEST_NO)
+ $(BUDDY_EXECUTION_TAG)
+ $(BUDDY_EXECUTION_BRANCH)
+
+
+
+
+ PrepareResources;$(CoreCompileDependsOn)
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ $(IntermediateOutputPath)\$([MSBuild]::ValueOrDefault('%(RelativeDir)', '').Replace('\', '.').Replace('/', '.'))%(Filename).g$(DefaultLanguageSourceExtension)
+ $(Language)
+ $(RootNamespace)
+ $(RootNamespace).$([MSBuild]::ValueOrDefault('%(RelativeDir)', '').Replace('\', '.').Replace('/', '.').TrimEnd('.'))
+ %(Filename)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(PrivateRepositoryUrl)
+
+
+
+ $(SourceRevisionId)
+ $(SourceRevisionId.Substring(0, 9))
+
+ $(RepositorySha)
+
+
+
+
+ <_GitSourceRoot Include="@(SourceRoot -> WithMetadataValue('SourceControl', 'git'))" />
+
+
+
+ @(_GitSourceRoot)
+
+
+
+
+
+
+ $(RepositoryUrl)
+ $(Description)
+ $(RepositoryUrl)/blob/main/changelog.md
+
+
+
+
+
+
+
+
diff --git a/src/Directory.props b/src/Directory.props
new file mode 100644
index 000000000..e242467ce
--- /dev/null
+++ b/src/Directory.props
@@ -0,0 +1,15 @@
+
+
+
+ annotations
+ Moq
+ Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors
+ $(MSBuildThisFileDirectory)Moq.snk
+ true
+ 00240000048000009400000006020000002400005253413100040000010001009f7a95086500f8f66d892174803850fed9c22225c2ccfff21f39c8af8abfa5415b1664efd0d8e0a6f7f2513b1c11659bd84723dc7900c3d481b833a73a2bcf1ed94c16c4be64d54352c86956c89930444e9ac15124d3693e3f029818e8410f167399d6b995324b635e95353ba97bfab856abbaeb9b40c9b160070c6325e22ddc
+ 69f491c39445e920
+
+ $(MSBuildThisFileDirectory)..\
+
+
+
diff --git a/tests/Moq.Tests.ComTypes/BuildDLLFromIDL.cmd b/src/Moq.Tests.ComTypes/BuildDLLFromIDL.cmd
similarity index 100%
rename from tests/Moq.Tests.ComTypes/BuildDLLFromIDL.cmd
rename to src/Moq.Tests.ComTypes/BuildDLLFromIDL.cmd
diff --git a/tests/Moq.Tests.ComTypes/ComTypes.idl b/src/Moq.Tests.ComTypes/ComTypes.idl
similarity index 100%
rename from tests/Moq.Tests.ComTypes/ComTypes.idl
rename to src/Moq.Tests.ComTypes/ComTypes.idl
diff --git a/tests/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll b/src/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll
similarity index 100%
rename from tests/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll
rename to src/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll
diff --git a/tests/Moq.Tests.ComTypes/README.md b/src/Moq.Tests.ComTypes/README.md
similarity index 100%
rename from tests/Moq.Tests.ComTypes/README.md
rename to src/Moq.Tests.ComTypes/README.md
diff --git a/tests/Moq.Tests.FSharpTypes/HasAbstractActionEvent.fs b/src/Moq.Tests.FSharpTypes/HasAbstractActionEvent.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasAbstractActionEvent.fs
rename to src/Moq.Tests.FSharpTypes/HasAbstractActionEvent.fs
diff --git a/tests/Moq.Tests.FSharpTypes/HasAbstractEventHandlerEvent.fs b/src/Moq.Tests.FSharpTypes/HasAbstractEventHandlerEvent.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasAbstractEventHandlerEvent.fs
rename to src/Moq.Tests.FSharpTypes/HasAbstractEventHandlerEvent.fs
diff --git a/tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs b/src/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs
rename to src/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs
diff --git a/tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs b/src/Moq.Tests.FSharpTypes/HasAbstractProperty.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs
rename to src/Moq.Tests.FSharpTypes/HasAbstractProperty.fs
diff --git a/tests/Moq.Tests.FSharpTypes/HasActionEvent.fs b/src/Moq.Tests.FSharpTypes/HasActionEvent.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasActionEvent.fs
rename to src/Moq.Tests.FSharpTypes/HasActionEvent.fs
diff --git a/tests/Moq.Tests.FSharpTypes/HasIndexer.fs b/src/Moq.Tests.FSharpTypes/HasIndexer.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasIndexer.fs
rename to src/Moq.Tests.FSharpTypes/HasIndexer.fs
diff --git a/tests/Moq.Tests.FSharpTypes/HasProperty.fs b/src/Moq.Tests.FSharpTypes/HasProperty.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/HasProperty.fs
rename to src/Moq.Tests.FSharpTypes/HasProperty.fs
diff --git a/tests/Moq.Tests.FSharpTypes/IHasActionEvent.fs b/src/Moq.Tests.FSharpTypes/IHasActionEvent.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/IHasActionEvent.fs
rename to src/Moq.Tests.FSharpTypes/IHasActionEvent.fs
diff --git a/tests/Moq.Tests.FSharpTypes/IHasEventHandlerEvent.fs b/src/Moq.Tests.FSharpTypes/IHasEventHandlerEvent.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/IHasEventHandlerEvent.fs
rename to src/Moq.Tests.FSharpTypes/IHasEventHandlerEvent.fs
diff --git a/tests/Moq.Tests.FSharpTypes/IHasIndexer.fs b/src/Moq.Tests.FSharpTypes/IHasIndexer.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/IHasIndexer.fs
rename to src/Moq.Tests.FSharpTypes/IHasIndexer.fs
diff --git a/tests/Moq.Tests.FSharpTypes/IHasProperty.fs b/src/Moq.Tests.FSharpTypes/IHasProperty.fs
similarity index 100%
rename from tests/Moq.Tests.FSharpTypes/IHasProperty.fs
rename to src/Moq.Tests.FSharpTypes/IHasProperty.fs
diff --git a/tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj b/src/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj
similarity index 66%
rename from tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj
rename to src/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj
index fc94860d7..862a558be 100644
--- a/tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj
+++ b/src/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj
@@ -1,17 +1,17 @@
-
-
-
-
+ο»Ώ
- net472;netcoreapp3.1;net6.0
+ net472;net6.0
True
portable
False
-
+
+
+
+
diff --git a/src/Moq.Tests.VisualBasic/IssueReports.vb b/src/Moq.Tests.VisualBasic/IssueReports.vb
new file mode 100644
index 000000000..fd2274bcb
--- /dev/null
+++ b/src/Moq.Tests.VisualBasic/IssueReports.vb
@@ -0,0 +1,127 @@
+' Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
+' All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.
+
+Imports Xunit
+
+Public Class IssueReports
+
+ Class Issue278
+
+
+ Sub SetupsForPropertiesWithMultipleArgsDoNotOverwriteEachOther()
+ Dim mock As New Mock(Of ISimpleInterface)()
+
+ mock.Setup(Function(m) m.PropertyWithMultipleArgs(1, 1)).Returns(1)
+ mock.Setup(Function(m) m.PropertyWithMultipleArgs(1, 2)).Returns(2)
+
+ Assert.Equal(1, mock.Object.PropertyWithMultipleArgs(1, 1))
+ Assert.Equal(2, mock.Object.PropertyWithMultipleArgs(1, 2))
+
+ End Sub
+
+ Interface ISimpleInterface
+
+ ReadOnly Property PropertyWithMultipleArgs(setting As Integer, setting2 As Integer) As Integer
+
+ End Interface
+ End Class
+
+ Class Issue1067
+
+
+ Sub Test_NonGeneric()
+ Dim userManagerMock = New Mock(Of IUserManager)()
+ Setup_NonGeneric(userManagerMock, 42)
+
+ Dim user As New User()
+ userManagerMock.Object.Create(user)
+
+ Assert.Equal(42, user.Id)
+ End Sub
+
+
+ Sub Test_Generic()
+ Dim userManagerMock = New Mock(Of IUserManager)()
+ Setup_Generic(Of User)(userManagerMock, 42)
+
+ Dim user As New User()
+ userManagerMock.Object.Create(user)
+
+ Assert.Equal(42, user.Id)
+ End Sub
+
+ Class User
+ Property Id As Integer
+ End Class
+
+ Interface IUserManager
+ Sub Create(User As User)
+ End Interface
+
+ Protected Sub Setup_NonGeneric(userManagerMock As Mock(Of IUserManager), expectedId As Integer)
+ userManagerMock.Setup(Sub(manager) manager.Create(It.IsAny(Of User))).Callback(Sub(user) user.Id = expectedId)
+ End Sub
+
+ Protected Sub Setup_Generic(Of TUser As User)(userManagerMock As Mock(Of IUserManager), expectedId As Integer)
+ userManagerMock.Setup(Sub(manager) manager.Create(It.IsAny(Of TUser))).Callback(Sub(user) user.Id = expectedId)
+ ' ^
+ ' The use of generics will cause the VB.NET compiler to wrap the `It.IsAny<>` call with two `Convert` nodes.
+ ' The inner conversion will convert to `Object`, and the outer conversion will convert to `User` (i.e. the type that
+ ' `TUser` is constrained to). `MatcherFactory` needs to be able to recognize the `It.IsAny<>` matcher even if it
+ ' is doubly wrapped!
+ End Sub
+
+ End Class
+
+ Class Issue1129
+
+
+ Sub Test()
+ Dim classMock = New Mock(Of IndexerInterface)()
+
+ classMock.SetupAllProperties()
+
+ Assert.False(classMock.Object.Value)
+ End Sub
+ Interface IndexerInterface
+ ReadOnly Property SystemDefault() As Boolean
+ Property Value() As Boolean
+ Property Value(ByVal OverrideLevel As Integer) As Boolean
+ Property Value(ByVal OverrideLevel As Integer, ByVal OverrideID As String) As Boolean
+ End Interface
+ End Class
+
+ Class Issue1153
+
+
+ Sub Indexer_overload_can_be_distinguished_from_property_when_mocking_declaring_class()
+ Dim mock = New Mock(Of MyVBClassBase)()
+ mock.Setup(Function(m) m.Prop).Returns(True)
+ End Sub
+
+
+ Sub Indexer_overload_can_be_distinguished_from_property_when_mocking_subclass_of_declaring_class()
+ Dim mock = New Mock(Of MyVBClass)()
+ mock.Setup(Function(m) m.Prop).Returns(True)
+ End Sub
+
+ Class MyVBClassBase
+ Overridable ReadOnly Property Prop() As Boolean
+ Get
+ Return True
+ End Get
+ End Property
+ Overridable ReadOnly Property Prop(ByVal userID As Guid) As Boolean
+ Get
+ Return False
+ End Get
+ End Property
+ End Class
+
+ Class MyVBClass
+ Inherits MyVBClassBase
+ End Class
+
+ End Class
+
+End Class
diff --git a/src/Moq.Tests.VisualBasic/Moq.Tests.VisualBasic.vbproj b/src/Moq.Tests.VisualBasic/Moq.Tests.VisualBasic.vbproj
new file mode 100644
index 000000000..31f679a49
--- /dev/null
+++ b/src/Moq.Tests.VisualBasic/Moq.Tests.VisualBasic.vbproj
@@ -0,0 +1,21 @@
+ο»Ώ
+
+
+ net472;net6.0
+ True
+ portable
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Moq.Tests/ActionObserverFixture.cs b/src/Moq.Tests/ActionObserverFixture.cs
new file mode 100644
index 000000000..d7b8f7a8f
--- /dev/null
+++ b/src/Moq.Tests/ActionObserverFixture.cs
@@ -0,0 +1,466 @@
+// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
+// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.
+
+using System;
+using System.Linq.Expressions;
+
+using Xunit;
+
+namespace Moq.Tests
+{
+ public class ActionObserverFixture
+ {
+ public class Reconstructibility
+ {
+ // NOTE: These tests might look pointless at first glance, until you notice
+ // the signature of `AssertReconstructable`: delegates are being compared to
+ // LINQ expression trees for equality.
+
+ [Fact]
+ public void Void_method_call()
+ {
+ AssertReconstructable(
+ x => x.Void(),
+ x => x.Void());
+ }
+
+ [Fact]
+ public void Void_method_call_with_arg()
+ {
+ AssertReconstructable(
+ x => x.VoidWithInt(42),
+ x => x.VoidWithInt(42));
+ }
+
+ [Fact]
+ public void Void_method_call_with_coerced_arg()
+ {
+ AssertReconstructable(
+ x => x.VoidWithLong(42),
+ x => x.VoidWithLong(42));
+ }
+
+ [Fact]
+ public void Void_method_call_with_coerced_nullable_arg()
+ {
+ AssertReconstructable(
+ "x => x.VoidWithNullableInt(42)",
+ x => x.VoidWithNullableInt(42));
+ }
+
+ [Fact]
+ public void Void_method_call_with_cast_arg()
+ {
+ AssertReconstructable(
+ x => x.VoidWithInt((int)42L),
+ x => x.VoidWithInt((int)42L));
+ }
+
+ [Fact]
+ public void Void_method_call_with_arg_evaluated()
+ {
+ int arg = 42;
+ AssertReconstructable(
+ x => x.VoidWithInt(42),
+ x => x.VoidWithInt(arg));
+ }
+
+ [Fact]
+ public void Void_method_call_on_sub_object()
+ {
+ AssertReconstructable(
+ x => x.GetY().Z.Void(),
+ x => x.GetY().Z.Void());
+ }
+
+ [Fact]
+ public void Void_method_call_on_sub_with_several_args()
+ {
+ AssertReconstructable(
+ x => x.GetY(1).Z.VoidWithIntInt(2, 3),
+ x => x.GetY(1).Z.VoidWithIntInt(2, 3));
+ }
+
+ [Fact]
+ public void Void_method_call_with_matcher()
+ {
+ AssertReconstructable(
+ x => x.VoidWithInt(It.IsAny()),
+ x => x.VoidWithInt(It.IsAny()));
+ }
+
+ [Fact]
+ public void Void_method_call_with_matcher_of_assignment_compatible_type()
+ {
+ AssertReconstructable(
+ x => x.VoidWithObject(It.IsAny()),
+ x => x.VoidWithObject(It.IsAny()));
+ }
+
+ [Fact]
+ public void Void_method_call_with_matcher_in_first_of_three_invocations()
+ {
+ AssertReconstructable(
+ x => x.GetY(It.IsAny()).Z.VoidWithIntInt(0, 0),
+ x => x.GetY(It.IsAny()).Z.VoidWithIntInt(0, 0));
+ }
+
+ [Fact]
+ public void Void_method_call_with_matcher_in_third_of_three_invocations_1()
+ {
+ AssertReconstructable(
+ x => x.GetY(0).Z.VoidWithIntInt(1, It.IsAny()),
+ x => x.GetY(0).Z.VoidWithIntInt(1, It.IsAny()));
+ }
+
+ [Fact]
+ public void Void_method_call_with_matcher_in_third_of_three_invocations_2()
+ {
+ AssertReconstructable(
+ x => x.GetY(0).Z.VoidWithIntInt(It.IsAny(), 2),
+ x => x.GetY(0).Z.VoidWithIntInt(It.IsAny(), 2));
+ }
+
+ [Fact]
+ public void Void_method_call_with_matcher_in_first_and_third_of_three_invocations()
+ {
+ AssertReconstructable(
+ "x => x.GetY(It.Is(i => i % 2 == 0)).Z.VoidWithIntInt(It.IsAny(), 2)",
+ x => x.GetY(It.Is(i => i % 2 == 0)).Z.VoidWithIntInt(It.IsAny(), 2));
+ }
+
+ [Fact]
+ public void Method_with_matchers_after_default_arg()
+ {
+ // This demonstrates that even though the first argument has a default value,
+ // the matcher isn't placed there, because it has a type (string) that won't fit (int).
+
+ AssertReconstructable(
+ x => x.VoidWithIntString(0, It.IsAny()),
+ x => x.VoidWithIntString(0, It.IsAny()));
+ }
+
+ [Fact]
+ public void Assignment()
+ {
+ AssertReconstructable(
+ "x => x.GetY().Z.Property = \"value\"",
+ x => x.GetY().Z.Property = "value");
+ }
+
+ [Fact]
+ public void Assignment_with_captured_var_on_rhs()
+ {
+ var arg = "value";
+ AssertReconstructable(
+ "x => x.GetY().Z.Property = \"value\"",
+ x => x.GetY().Z.Property = arg);
+ }
+
+ [Fact]
+ public void Assignment_with_matcher_on_rhs()
+ {
+ AssertReconstructable(
+ "x => x.GetY().Z.Property = It.IsAny()",
+ x => x.GetY().Z.Property = It.IsAny());
+ }
+
+ [Fact]
+ public void Indexer_assignment_with_arg()
+ {
+ AssertReconstructable(
+ "x => x[1] = null",
+ x => x[1] = null);
+ }
+
+ [Fact]
+ public void Indexer_assignment_with_matcher_on_lhs_1()
+ {
+ AssertReconstructable(
+ "x => x[It.IsAny()] = null",
+ x => x[It.IsAny()] = null);
+ }
+
+ [Fact]
+ public void Indexer_assignment_with_matcher_on_lhs_2()
+ {
+ AssertReconstructable(
+ "x => x[1, It.IsAny()] = 0",
+ x => x[1, It.IsAny()] = 0);
+ }
+
+ [Fact]
+ public void Indexer_assignment_with_matcher_on_rhs()
+ {
+ AssertReconstructable(
+ "x => x[1] = It.IsAny()",
+ x => x[1] = It.IsAny());
+ }
+
+ [Fact]
+ public void Indexer_assignment_with_matchers_everywhere()
+ {
+ AssertReconstructable(
+ "x => x[It.Is(i => i == 0), It.Is(i => i == 2)] = It.Is(i => i == 3)",
+ x => x[It.Is(i => i == 0), It.Is(i => i == 2)] = It.Is(i => i == 3));
+ }
+
+ [Fact]
+ public void Widening_and_narrowing_and_enum_convertions()
+ {
+ ushort arg = 123;
+ AssertReconstructable(
+ "x => x.VoidWithShort(123)",
+ x => x.VoidWithShort((short)arg));
+ AssertReconstructable(
+ "x => x.VoidWithInt(123)",
+ x => x.VoidWithInt(arg));
+ AssertReconstructable(
+ "x => x.VoidWithLong(123)",
+ x => x.VoidWithLong(arg));
+
+ long longArg = 654L;
+ AssertReconstructable(
+ "x => x.VoidWithShort(654)",
+ x => x.VoidWithShort((short)longArg));
+
+ AssertReconstructable(
+ "x => x.VoidWithObject(ActionObserverFixture.Reconstructibility.Color.Green)",
+ x => x.VoidWithObject(Color.Green));
+ AssertReconstructable(
+ "x => x.VoidWithEnum(ActionObserverFixture.Reconstructibility.Color.Green)",
+ x => x.VoidWithEnum(Color.Green));
+ AssertReconstructable(
+ "x => x.VoidWithNullableEnum(ActionObserverFixture.Reconstructibility.Color.Green)",
+ x => x.VoidWithNullableEnum(Color.Green));
+ }
+
+ [Fact]
+ public void It_IsAny_enum_converted_and_assigned_to_int_parameter()
+ {
+ AssertReconstructable(
+ x => x.VoidWithInt((int)It.IsAny()),
+ x => x.VoidWithInt((int)It.IsAny()));
+ }
+
+ [Fact]
+ public void It_IsAny_short_widened_to_int_parameter()
+ {
+ AssertReconstructable(
+ x => x.VoidWithInt(It.IsAny()),
+ x => x.VoidWithInt(It.IsAny()));
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private void AssertReconstructable(string expected, Action action)
+ After:
+ void AssertReconstructable(string expected, Action action)
+ */
+ }
+
+ void AssertReconstructable(string expected, Action action)
+ {
+ Expression actual = ActionObserver.Instance.ReconstructExpression(action);
+ actual = PrepareForComparison.Instance.Visit(actual);
+ Assert.Equal(expected, actual.ToStringFixed());
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private void AssertReconstructable(Expression> expected, Action action)
+ After:
+ void AssertReconstructable(Expression> expected, Action action)
+ */
+ }
+
+ void AssertReconstructable(Expression> expected, Action action)
+ {
+ Expression actual = ActionObserver.Instance.ReconstructExpression(action);
+ expected = (Expression>)PrepareForComparison.Instance.Visit(expected);
+ actual = PrepareForComparison.Instance.Visit(actual);
+ Assert.Equal(expected, actual, ExpressionComparer.Default);
+ }
+
+ public interface IX
+ {
+ IY this[int index] { get; set; }
+ int this[int index1, int index2] { get; set; }
+ IY GetY();
+ IY GetY(int arg);
+ void Void();
+ void VoidWithShort(short arg);
+ void VoidWithInt(int arg);
+ void VoidWithLong(long arg);
+ void VoidWithNullableInt(int? arg);
+ void VoidWithIntString(int arg1, string arg2);
+ void VoidWithObject(object arg);
+ void VoidWithEnum(Color arg);
+ void VoidWithNullableEnum(Color? arg);
+ }
+
+ public interface IY
+ {
+ IZ Z { get; }
+ }
+
+ public interface IZ
+ {
+ object Property { get; set; }
+ void Void();
+ void VoidWithIntInt(int arg1, int arg2);
+ }
+
+ public enum Color
+ {
+ Red,
+ Green,
+ Blue,
+ Yellow,
+ }
+ }
+
+ public class Error_detection
+ {
+ [Fact]
+ public void Stops_before_non_interceptable_method()
+ {
+ AssertFailsAfter("x => x...", x => x.NonVirtual());
+ }
+
+ [Fact]
+ public void Stops_before_non_interceptable_property()
+ {
+ AssertFailsAfter("x => x...", x => x.NonVirtualProperty = It.IsAny());
+ }
+
+ [Fact]
+ public void Stops_after_non_interceptable_return_type()
+ {
+ AssertFailsAfter("x => x.SealedY...", x => x.SealedY.Method());
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private void AssertFailsAfter(string expectedPartial, Action action)
+ After:
+ void AssertFailsAfter(string expectedPartial, Action action)
+ */
+ }
+
+ void AssertFailsAfter(string expectedPartial, Action action)
+ {
+ var error = Assert.Throws(() => ActionObserver.Instance.ReconstructExpression(action));
+ Assert.Contains($": {expectedPartial}", error.Message);
+ }
+
+ public interface IX
+ {
+ IY Y { get; }
+ SealedY SealedY { get; }
+ }
+
+ public class X
+ {
+ public IY NonVirtualProperty { get; set; }
+ public void NonVirtual() { }
+ }
+
+ public interface IY
+ {
+ void Method(int arg1, int arg2);
+ }
+
+ public sealed class SealedY
+ {
+ public void Method() { }
+ }
+ }
+
+ // These tests document limitations of the current implementation.
+ public class Limitations
+ {
+ [Fact]
+ public void Method_with_matchers_after_default_arg()
+ {
+ // This is because parameters with default values are filled from left to right.
+
+ AssertIncorrectlyReconstructsAs(
+ x => x.Method(It.IsAny(), 0),
+ x => x.Method(0, It.IsAny()));
+ }
+
+ [Fact]
+ public void Indexer_with_default_value_on_lfs_and_matcher_on_rhs_both_having_same_types()
+ {
+ // Same as above, since LHS and RHS are actually both part of a single parameter list of a method call `get_Item(...lhs, rhs).
+ AssertIncorrectlyReconstructsAs(
+ "x => x[It.IsAny()] = 0",
+ x => x[0] = It.IsAny());
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private void AssertIncorrectlyReconstructsAs(string expected, Action action)
+ After:
+ void AssertIncorrectlyReconstructsAs(string expected, Action action)
+ */
+ }
+
+ void AssertIncorrectlyReconstructsAs(string expected, Action action)
+ {
+ Expression actual = ActionObserver.Instance.ReconstructExpression(action);
+ actual = PrepareForComparison.Instance.Visit(actual);
+ Assert.Equal(expected, actual.ToStringFixed());
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private void AssertIncorrectlyReconstructsAs(Expression> expected, Action action)
+ After:
+ void AssertIncorrectlyReconstructsAs(Expression> expected, Action action)
+ */
+ }
+
+ void AssertIncorrectlyReconstructsAs(Expression> expected, Action action)
+ {
+ Expression actual = ActionObserver.Instance.ReconstructExpression(action);
+ expected = (Expression>)PrepareForComparison.Instance.Visit(expected);
+ actual = PrepareForComparison.Instance.Visit(actual);
+ Assert.Equal(expected, actual, ExpressionComparer.Default);
+ }
+
+ public interface IX
+ {
+ int this[int index] { get; set; }
+ void Method(int arg1, int arg2);
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private sealed class PrepareForComparison : ExpressionVisitor
+ After:
+ sealed class PrepareForComparison : ExpressionVisitor
+ */
+ }
+ }
+
+ // The expression trees reconstructed by `ActionObserver` may differ from those
+ // produced by the Roslyn compilers in some minor regards that shouldn't actually
+ // matter to program execution; however `ExpressionComparer` will notice the
+ // differences, making above tests fail. Because of this, we try to "equalize"
+ // expressions created by the Roslyn compilers (`expected`) and those produced
+ // by `ActionObserver` (`actual`) using this expression visitor:
+ sealed class PrepareForComparison : ExpressionVisitor
+ {
+ public static readonly PrepareForComparison Instance = new PrepareForComparison();
+
+ protected override Expression VisitExtension(Expression node)
+ {
+ if (node is MatchExpression me)
+ {
+ // Resolve `MatchExpression`s to their matcher's `RenderExpression`:
+ return me.Match.RenderExpression;
+ }
+ else
+ {
+ return base.VisitExtension(node);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Moq.Tests/AfterReturnCallbackDelegateValidationFixture.cs b/src/Moq.Tests/AfterReturnCallbackDelegateValidationFixture.cs
new file mode 100644
index 000000000..1ebf70c3e
--- /dev/null
+++ b/src/Moq.Tests/AfterReturnCallbackDelegateValidationFixture.cs
@@ -0,0 +1,103 @@
+// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
+// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.
+
+using System;
+
+using Moq.Language.Flow;
+
+using Xunit;
+
+namespace Moq.Tests
+{
+ public class AfterReturnCallbackDelegateValidationFixture
+
+ /* Unmerged change from project 'Moq.Tests(net6.0)'
+ Before:
+ private readonly ISetup setup;
+ After:
+ readonly ISetup setup;
+ */
+ {
+ readonly ISetup setup;
+
+ public AfterReturnCallbackDelegateValidationFixture()
+ {
+ this.setup = new Mock().Setup(m => m.Method(It.IsAny(), It.IsAny