diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index 345674a..a425700 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -1,4 +1,4 @@ -ARG NGINX_VERSION=1.31.2-alpine +ARG NGINX_VERSION=1.31-alpine FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base RUN rm -rf /usr/share/nginx/html/* diff --git a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt index 5cba9a2..06c6641 100644 --- a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.1.2 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.1.1 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt index 50257c6..272eb19 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.1.2 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.1.1 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt index 1da8645..7e7ed72 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.1.2 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.1.1 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt index e6537e3..ae4565e 100644 --- a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.1.2 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.1.1 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b14c3..65a7933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,25 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba > [!NOTE] > Changelog entries prior to version 8.4.0 was migrated from previous versions of Cuemon.Extensions.Xunit, Cuemon.Extensions.Xunit.Hosting, and Cuemon.Extensions.Xunit.Hosting.AspNetCore. +## [11.1.2] - 2026-07-18 + +This is a patch release that updates package dependencies across all supported target frameworks and introduces query performance benchmarks for the InMemoryTestStore implementation. All changes are non-breaking service refinements. + +### Added + +- InMemoryTestStoreBenchmark class in the tuning folder with 7 query performance methods covering null-predicate fast path, selective filtering at varying selectivity rates, type filtering with QueryFor, and materialization cost measurement across workload sizes of 10, 100, and 1000 items, +- Query performance analysis reports documenting benchmark results across .NET 10.0, 9.0, and 4.8 runtimes. + +### Changed + +- Upgraded Codebelt.Bootstrapper.Console, Codebelt.Bootstrapper.Web, and Codebelt.Bootstrapper.Worker from 5.1.1 to 5.1.2, +- Upgraded Codebelt.Extensions.BenchmarkDotNet.Console from 1.3.0 to 1.3.1, +- Upgraded Cuemon.Core, Cuemon.Extensions.AspNetCore, and Cuemon.Extensions.IO from 10.5.4 to 10.5.5, +- Upgraded Microsoft.NET.Test.Sdk from 18.7.0 to 18.8.1, +- Upgraded Microsoft.Bcl.AsyncInterfaces from 10.0.9 to 10.0.10 for netstandard2.0, +- Upgraded Microsoft.Extensions.* packages (Configuration, EnvironmentVariables, FileExtensions, Json, Hosting, AspNetCore.TestHost) from 9.0.17 to 9.0.18 for .NET 9, +- Upgraded Microsoft.Extensions.* packages (Configuration, EnvironmentVariables, FileExtensions, Json, Hosting, AspNetCore.TestHost) from 10.0.9 to 10.0.10 for .NET 10. + ## [11.1.1] - 2026-06-25 This is a patch release that improves documentation clarity, enhances DocFX infrastructure, and updates test framework dependencies. All changes are non-breaking service refinements. @@ -435,7 +454,8 @@ This major release is first and foremost focused on ironing out any wrinkles tha -[Unreleased]: https://github.com/codebeltnet/xunit/compare/v11.1.1...HEAD +[Unreleased]: https://github.com/codebeltnet/xunit/compare/v11.1.2...HEAD +[11.1.2]: https://github.com/codebeltnet/xunit/compare/v11.1.1...v11.1.2 [11.1.1]: https://github.com/codebeltnet/xunit/compare/v11.1.0...v11.1.1 [11.1.0]: https://github.com/codebeltnet/xunit/compare/v11.0.10...v11.1.0 [11.0.10]: https://github.com/codebeltnet/xunit/compare/v11.0.9...v11.0.10 diff --git a/Directory.Packages.props b/Directory.Packages.props index 278cd44..6711341 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,14 +6,14 @@ - - - - - - - - + + + + + + + + @@ -26,23 +26,23 @@ - + - - - - - - + + + + + + - - - - - - + + + + + + \ No newline at end of file diff --git a/reports/tuning/Codebelt.Extensions.Xunit.InMemoryTestStoreBenchmark-report-github.md b/reports/tuning/Codebelt.Extensions.Xunit.InMemoryTestStoreBenchmark-report-github.md new file mode 100644 index 0000000..7f54fc7 --- /dev/null +++ b/reports/tuning/Codebelt.Extensions.Xunit.InMemoryTestStoreBenchmark-report-github.md @@ -0,0 +1,78 @@ +``` + +BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2) +12th Gen Intel Core i9-12900KF 3.20GHz, 1 CPU, 24 logical and 16 physical cores +.NET SDK 11.0.100-preview.4.26230.115 + [Host] : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3 + Job-LDLMHG : .NET 10.0.10 (10.0.10, 10.0.1026.32716), X64 RyuJIT x86-64-v3 + Job-IOAYXE : .NET 9.0.18 (9.0.18, 9.0.1826.31522), X64 RyuJIT x86-64-v3 + Job-GEUVPA : .NET Framework 4.8.1 (4.8.9337.0), X64 RyuJIT VectorSize=256 + +PowerPlanMode=00000000-0000-0000-0000-000000000000 IterationTime=250ms MaxIterationCount=20 +MinIterationCount=15 WarmupCount=1 + +``` +| Method | Runtime | Count | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio | +|---------------------------------------------- |------------------- |------ |--------------:|--------------:|--------------:|--------------:|--------------:|--------------:|------:|--------:|-------:|----------:|------------:| +| **'Query(predicate).Count() - all items match'** | **.NET 10.0** | **256** | **486.19 ns** | **34.108 ns** | **37.911 ns** | **485.88 ns** | **359.47 ns** | **554.43 ns** | **?** | **?** | **0.0041** | **72 B** | **?** | +| 'Query(predicate).Count() - half items match' | .NET 10.0 | 256 | 788.08 ns | 37.360 ns | 43.023 ns | 789.28 ns | 667.98 ns | 860.36 ns | ? | ? | 0.0025 | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET 10.0 | 256 | 535.49 ns | 26.691 ns | 30.737 ns | 538.63 ns | 461.68 ns | 589.39 ns | ? | ? | 0.0031 | 72 B | ? | +| | | | | | | | | | | | | | | +| 'Query(predicate).Count() - all items match' | .NET 9.0 | 256 | 166.94 ns | 13.729 ns | 15.810 ns | 169.24 ns | 102.71 ns | 180.89 ns | ? | ? | 0.0046 | 72 B | ? | +| 'Query(predicate).Count() - half items match' | .NET 9.0 | 256 | 755.63 ns | 67.404 ns | 77.622 ns | 766.26 ns | 560.41 ns | 865.63 ns | ? | ? | 0.0044 | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET 9.0 | 256 | 137.16 ns | 18.372 ns | 21.157 ns | 142.14 ns | 76.57 ns | 153.13 ns | ? | ? | 0.0044 | 72 B | ? | +| | | | | | | | | | | | | | | +| 'Query(predicate).Count() - all items match' | .NET Framework 4.8 | 256 | 2,780.37 ns | 303.660 ns | 349.695 ns | 2,827.17 ns | 1,987.71 ns | 3,207.74 ns | ? | ? | 0.0080 | 72 B | ? | +| 'Query(predicate).Count() - half items match' | .NET Framework 4.8 | 256 | 2,737.73 ns | 139.743 ns | 160.928 ns | 2,708.28 ns | 2,510.94 ns | 3,024.14 ns | ? | ? | 0.0068 | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET Framework 4.8 | 256 | 1,702.18 ns | 401.519 ns | 462.390 ns | 1,861.91 ns | 1,005.25 ns | 2,310.27 ns | ? | ? | 0.0081 | 72 B | ? | +| | | | | | | | | | | | | | | +| **'Query(predicate).Count() - all items match'** | **.NET 10.0** | **4096** | **7,560.18 ns** | **1,202.244 ns** | **1,384.506 ns** | **8,142.52 ns** | **5,113.88 ns** | **8,937.35 ns** | **?** | **?** | **-** | **72 B** | **?** | +| 'Query(predicate).Count() - half items match' | .NET 10.0 | 4096 | 12,204.71 ns | 1,677.461 ns | 1,931.767 ns | 13,007.85 ns | 9,766.58 ns | 15,321.51 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET 10.0 | 4096 | 8,452.84 ns | 884.280 ns | 1,018.339 ns | 8,679.65 ns | 5,949.62 ns | 9,637.66 ns | ? | ? | - | 72 B | ? | +| | | | | | | | | | | | | | | +| 'Query(predicate).Count() - all items match' | .NET 9.0 | 4096 | 2,561.76 ns | 602.033 ns | 693.302 ns | 2,891.90 ns | 1,415.56 ns | 3,223.20 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - half items match' | .NET 9.0 | 4096 | 9,479.95 ns | 41.398 ns | 38.724 ns | 9,476.20 ns | 9,408.77 ns | 9,545.46 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET 9.0 | 4096 | 1,223.50 ns | 6.127 ns | 5.431 ns | 1,223.26 ns | 1,215.82 ns | 1,233.80 ns | ? | ? | - | 72 B | ? | +| | | | | | | | | | | | | | | +| 'Query(predicate).Count() - all items match' | .NET Framework 4.8 | 4096 | 31,206.51 ns | 139.450 ns | 130.442 ns | 31,249.54 ns | 30,966.07 ns | 31,347.75 ns | ? | ? | - | 71 B | ? | +| 'Query(predicate).Count() - half items match' | .NET Framework 4.8 | 4096 | 26,401.17 ns | 47.010 ns | 43.973 ns | 26,395.60 ns | 26,337.25 ns | 26,473.50 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET Framework 4.8 | 4096 | 15,524.36 ns | 73.356 ns | 68.617 ns | 15,532.35 ns | 15,360.02 ns | 15,630.49 ns | ? | ? | - | 72 B | ? | +| | | | | | | | | | | | | | | +| **'Query(predicate).Count() - all items match'** | **.NET 10.0** | **65536** | **95,347.05 ns** | **185.107 ns** | **164.093 ns** | **95,347.39 ns** | **95,071.70 ns** | **95,654.66 ns** | **?** | **?** | **-** | **72 B** | **?** | +| 'Query(predicate).Count() - half items match' | .NET 10.0 | 65536 | 148,640.18 ns | 1,916.770 ns | 1,792.948 ns | 148,486.59 ns | 144,905.11 ns | 151,601.37 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET 10.0 | 65536 | 108,930.15 ns | 246.646 ns | 192.565 ns | 109,003.67 ns | 108,645.38 ns | 109,125.46 ns | ? | ? | - | 72 B | ? | +| | | | | | | | | | | | | | | +| 'Query(predicate).Count() - all items match' | .NET 9.0 | 65536 | 60,707.35 ns | 2,205.203 ns | 2,539.515 ns | 60,570.73 ns | 55,538.29 ns | 64,007.15 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - half items match' | .NET 9.0 | 65536 | 138,382.02 ns | 631.612 ns | 590.810 ns | 138,379.11 ns | 137,269.57 ns | 139,327.25 ns | ? | ? | - | 72 B | ? | +| 'Query(predicate).Count() - no items match' | .NET 9.0 | 65536 | 59,290.61 ns | 3,400.160 ns | 3,915.629 ns | 60,341.58 ns | 50,645.71 ns | 64,947.46 ns | ? | ? | - | 72 B | ? | +| | | | | | | | | | | | | | | +| 'Query(predicate).Count() - all items match' | .NET Framework 4.8 | 65536 | 487,925.14 ns | 3,789.195 ns | 3,544.416 ns | 488,684.38 ns | 481,920.31 ns | 494,299.80 ns | ? | ? | - | 64 B | ? | +| 'Query(predicate).Count() - half items match' | .NET Framework 4.8 | 65536 | 431,345.99 ns | 2,383.974 ns | 2,229.970 ns | 430,600.34 ns | 427,991.22 ns | 435,213.01 ns | ? | ? | - | 69 B | ? | +| 'Query(predicate).Count() - no items match' | .NET Framework 4.8 | 65536 | 249,407.48 ns | 2,384.811 ns | 2,114.073 ns | 249,935.94 ns | 245,151.66 ns | 253,267.58 ns | ? | ? | - | 72 B | ? | +| | | | | | | | | | | | | | | +| **'Query(type-equality predicate).Count()'** | **.NET 10.0** | **256** | **478.94 ns** | **6.868 ns** | **6.745 ns** | **477.84 ns** | **468.76 ns** | **497.91 ns** | **1.00** | **0.02** | **0.0039** | **72 B** | **1.00** | +| QueryFor<Derived1>().Count() | .NET 10.0 | 256 | 810.52 ns | 4.057 ns | 3.596 ns | 810.79 ns | 804.73 ns | 815.75 ns | 1.69 | 0.02 | 0.0065 | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| 'Query(type-equality predicate).Count()' | .NET 9.0 | 256 | 92.89 ns | 1.053 ns | 0.934 ns | 92.50 ns | 91.82 ns | 94.92 ns | 1.00 | 0.01 | 0.0045 | 72 B | 1.00 | +| QueryFor<Derived1>().Count() | .NET 9.0 | 256 | 766.62 ns | 5.193 ns | 4.858 ns | 765.63 ns | 760.25 ns | 778.11 ns | 8.25 | 0.09 | 0.0061 | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| 'Query(type-equality predicate).Count()' | .NET Framework 4.8 | 256 | 1,467.92 ns | 4.804 ns | 4.494 ns | 1,468.57 ns | 1,459.29 ns | 1,477.86 ns | 1.00 | 0.00 | 0.0059 | 72 B | 1.00 | +| QueryFor<Derived1>().Count() | .NET Framework 4.8 | 256 | 3,146.21 ns | 16.584 ns | 14.702 ns | 3,143.60 ns | 3,127.95 ns | 3,173.05 ns | 2.14 | 0.01 | 0.0125 | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| **'Query(type-equality predicate).Count()'** | **.NET 10.0** | **4096** | **7,527.07 ns** | **142.080 ns** | **152.024 ns** | **7,566.75 ns** | **7,254.28 ns** | **7,707.01 ns** | **1.00** | **0.03** | **-** | **72 B** | **1.00** | +| QueryFor<Derived1>().Count() | .NET 10.0 | 4096 | 12,557.97 ns | 139.609 ns | 108.997 ns | 12,545.04 ns | 12,427.51 ns | 12,733.85 ns | 1.67 | 0.04 | - | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| 'Query(type-equality predicate).Count()' | .NET 9.0 | 4096 | 1,146.01 ns | 12.824 ns | 11.996 ns | 1,144.08 ns | 1,128.64 ns | 1,168.73 ns | 1.00 | 0.01 | 0.0045 | 72 B | 1.00 | +| QueryFor<Derived1>().Count() | .NET 9.0 | 4096 | 11,531.14 ns | 57.844 ns | 48.302 ns | 11,514.52 ns | 11,481.89 ns | 11,627.61 ns | 10.06 | 0.11 | - | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| 'Query(type-equality predicate).Count()' | .NET Framework 4.8 | 4096 | 22,921.91 ns | 257.502 ns | 240.867 ns | 22,903.08 ns | 22,595.50 ns | 23,343.91 ns | 1.00 | 0.01 | - | 72 B | 1.00 | +| QueryFor<Derived1>().Count() | .NET Framework 4.8 | 4096 | 48,256.16 ns | 556.949 ns | 493.721 ns | 48,061.74 ns | 47,608.44 ns | 49,229.78 ns | 2.11 | 0.03 | - | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| **'Query(type-equality predicate).Count()'** | **.NET 10.0** | **65536** | **123,428.92 ns** | **2,082.105 ns** | **1,845.732 ns** | **124,128.12 ns** | **118,452.44 ns** | **125,003.91 ns** | **1.00** | **0.02** | **-** | **72 B** | **1.00** | +| QueryFor<Derived1>().Count() | .NET 10.0 | 65536 | 189,344.37 ns | 1,021.614 ns | 955.618 ns | 189,505.28 ns | 187,238.69 ns | 190,478.50 ns | 1.53 | 0.02 | - | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| 'Query(type-equality predicate).Count()' | .NET 9.0 | 65536 | 34,952.85 ns | 690.115 ns | 767.061 ns | 35,169.69 ns | 32,416.76 ns | 35,580.01 ns | 1.00 | 0.03 | - | 72 B | 1.00 | +| QueryFor<Derived1>().Count() | .NET 9.0 | 65536 | 191,255.43 ns | 822.440 ns | 729.071 ns | 191,409.22 ns | 190,129.88 ns | 192,548.32 ns | 5.47 | 0.12 | - | 128 B | 1.78 | +| | | | | | | | | | | | | | | +| 'Query(type-equality predicate).Count()' | .NET Framework 4.8 | 65536 | 365,193.58 ns | 1,548.863 ns | 1,448.807 ns | 365,755.01 ns | 362,013.44 ns | 366,651.24 ns | 1.00 | 0.01 | - | 71 B | 1.00 | +| QueryFor<Derived1>().Count() | .NET Framework 4.8 | 65536 | 794,356.49 ns | 15,709.234 ns | 15,428.568 ns | 791,422.77 ns | 762,669.64 ns | 819,878.87 ns | 2.18 | 0.04 | - | 122 B | 1.72 | diff --git a/tuning/Codebelt.Extensions.Xunit.Benchmarks/InMemoryTestStoreBenchmark.cs b/tuning/Codebelt.Extensions.Xunit.Benchmarks/InMemoryTestStoreBenchmark.cs new file mode 100644 index 0000000..3b8f36f --- /dev/null +++ b/tuning/Codebelt.Extensions.Xunit.Benchmarks/InMemoryTestStoreBenchmark.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; + +namespace Codebelt.Extensions.Xunit; + +/// +/// Benchmarks the consumer-visible querying cost of . +/// +/// +/// Two questions are answered: +/// +/// How does with a predicate scale with store size and selectivity when consumed by a terminal Count()? +/// Does add measurable overhead beyond the equivalent lean type-equality predicate, when both terminate in Count() and return the same count? +/// +/// +[MemoryDiagnoser] +[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] +public class InMemoryTestStoreBenchmark +{ + [Params(256, 4096, 65536)] + public int Count { get; set; } + + private InMemoryTestStore _stringStore; + private InMemoryTestStore _mixedStore; + + private int _expectedAllMatch; + private int _expectedHalfMatch; + private int _expectedNoMatch; + private int _expectedDerived1Count; + + [GlobalSetup] + public void Setup() + { + _stringStore = new InMemoryTestStore(); + for (int i = 0; i < Count; i++) + { + _stringStore.Add("item-" + i.ToString("D5")); + } + + _expectedAllMatch = Count; + _expectedHalfMatch = 0; + for (int i = 0; i < Count; i++) + { + int lastDigit = i % 10; + if (lastDigit % 2 == 0) + { + _expectedHalfMatch++; + } + } + _expectedNoMatch = 0; + + if (_stringStore.Query(x => x.Length == 10).Count() != _expectedAllMatch) + { + throw new InvalidOperationException("AllMatch oracle mismatch"); + } + if (_stringStore.Query(IsLastDigitEven).Count() != _expectedHalfMatch) + { + throw new InvalidOperationException("HalfMatch oracle mismatch"); + } + if (_stringStore.Query(x => x.Length > 100).Count() != _expectedNoMatch) + { + throw new InvalidOperationException("NoMatch oracle mismatch"); + } + + _mixedStore = new InMemoryTestStore(); + for (int i = 0; i < Count; i++) + { + _mixedStore.Add(i % 2 == 0 ? new Derived1() : new Derived2()); + } + _expectedDerived1Count = (Count + 1) / 2; + + if (_mixedStore.Query(item => item.GetType() == typeof(Derived1)).Count() != _expectedDerived1Count) + { + throw new InvalidOperationException("Lean predicate Derived1 oracle mismatch"); + } + if (_mixedStore.QueryFor().Count() != _expectedDerived1Count) + { + throw new InvalidOperationException("QueryFor oracle mismatch"); + } + } + + [BenchmarkCategory("Query")] + [Benchmark(Description = "Query(predicate).Count() - all items match")] + public int Query_Predicate_AllMatch() + { + return _stringStore.Query(x => x.Length == 10).Count(); + } + + [BenchmarkCategory("Query")] + [Benchmark(Description = "Query(predicate).Count() - half items match")] + public int Query_Predicate_HalfMatch() + { + return _stringStore.Query(IsLastDigitEven).Count(); + } + + [BenchmarkCategory("Query")] + [Benchmark(Description = "Query(predicate).Count() - no items match")] + public int Query_Predicate_NoMatch() + { + return _stringStore.Query(x => x.Length > 100).Count(); + } + + [BenchmarkCategory("QueryFor")] + [Benchmark(Baseline = true, Description = "Query(type-equality predicate).Count()")] + public int Query_LeanTypePredicate() + { + return _mixedStore.Query(item => item.GetType() == typeof(Derived1)).Count(); + } + + [BenchmarkCategory("QueryFor")] + [Benchmark(Description = "QueryFor().Count()")] + public int QueryFor_TypeFilter() + { + return _mixedStore.QueryFor().Count(); + } + + private static bool IsLastDigitEven(string value) + { + return (value[value.Length - 1] - '0') % 2 == 0; + } + + private abstract class ItemBase + { + } + + private sealed class Derived1 : ItemBase + { + } + + private sealed class Derived2 : ItemBase + { + } +} \ No newline at end of file