Fastpaths for equivalency + super/sub set tests for certain types#5224
Conversation
| /// </summary> | ||
| /// <param name="c">The collection to be included in the tally</param> | ||
| [Obsolete("This method will be removed in a future release.")] | ||
| protected CollectionTally Tally(IEnumerable c) |
There was a problem hiding this comment.
I held off marking the non-generic CollectionTally obsolete for now as it becomes a bit tricky to do gracefully with the nested class that still gets referenced from a non-generic context
| /// <summary> | ||
| /// Converts a generic CollectionTallyResult to the non-generic version. | ||
| /// </summary> | ||
| internal static CollectionTallyResult FromGenericResult<T>(CollectionTally<T>.CollectionTallyResult genericResult) |
There was a problem hiding this comment.
I've put this here rather than on the generic version with the long-term thought that the non-generic class will become obsolete and removed over time, and the need to convert to it will go away with it
3fbb1bc to
08b69de
Compare
| private const int LargeCollectionWarnTime = 100; | ||
| private const int LargeCollectionFailTime = 500; | ||
| private const int LargeCollectionWarnTime = 20; | ||
| private const int LargeCollectionFailTime = 100; |
There was a problem hiding this comment.
I suspect there to be lots of buffer baked into even these numbers, but I don't think we should reduce them further. The affected tests each pass in single-digit ms times on my own machine (albeit with nothing running in the background).
In practice, these numbers on my own machine also correctly trigger warnings or failures if the "wrong" tallying strategy gets chosen, causing the algorithmic complexity and time to increase.
|
I'm marking this as Ready for Review. I think the changes are largely stable now, aside from perhaps if I notice any missing test coverage |
There was a problem hiding this comment.
Pull request overview
This PR improves performance of collection equivalency, subset, and superset constraints by introducing typed fast paths (avoiding O(n·m) removal where possible) and by bypassing NUnitEqualityComparer in cases where EqualityComparer<T>.Default is behaviorally identical.
Changes:
- Added
CollectionTally<T>and updated collection constraints to use a newTallyResult(...)helper with typed fast paths for common element types. - Introduced generic
IsSortable<T>/ImplementsIComparable<T>helpers and expanded tests to cover generic paths. - Updated/expanded tests for null handling and adjusted “large collection” timing thresholds.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/NUnitFramework/framework/Constraints/CollectionItemsEqualConstraint.cs | Adds TallyResult/TallyResultCore helper selecting typed fast paths. |
| src/NUnitFramework/framework/Constraints/CollectionEquivalentConstraint.cs | Uses TallyResult instead of CollectionTally for equivalency checks. |
| src/NUnitFramework/framework/Constraints/CollectionSubsetConstraint.cs | Uses TallyResult for subset checks. |
| src/NUnitFramework/framework/Constraints/CollectionSupersetConstraint.cs | Uses TallyResult for superset checks. |
| src/NUnitFramework/framework/Constraints/CollectionTally{T}.cs | New generic tally implementation with multiple removal strategies. |
| src/NUnitFramework/framework/Constraints/CollectionTally.cs | Adds conversion helper from generic tally result to non-generic result type. |
| src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs | Adds IsModified flag for deciding when default equality can be used safely. |
| src/NUnitFramework/framework/Constraints/NUnitEqualityComparerAdapter.cs | New adapter to use NUnitEqualityComparer as an IEqualityComparer<T>. |
| src/NUnitFramework/framework/Internal/Extensions/TypeExtensions.cs | Adds generic ImplementsIComparable<T> and IsSortable<T>. |
| src/NUnitFramework/framework/Internal/Extensions/IEnumerableExtensions.cs | Adds generic IsSortable<T>(IEnumerable<T>?) overload. |
| src/NUnitFramework/tests/Internal/CollectionTallyTests.cs | Updates tests to exercise CollectionTally<T> under multiple comparer configurations. |
| src/NUnitFramework/tests/Internal/Extensions/TypeExtensionTests.cs | Updates tests to validate both generic and reflection-based type checks. |
| src/NUnitFramework/tests/Internal/Extensions/IEnumerableExtensionTests.cs | Adds generic sortability tests and reworks test case sources. |
| src/NUnitFramework/tests/Constraints/CollectionEquivalentConstraintTests.cs | Expands null/modifier coverage and updates large-collection timing constants. |
| .github/copilot-instructions.md | Adds repository guidance about preserving existing performance optimizations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
manfred-brands
left a comment
There was a problem hiding this comment.
I added 2 commits to address 2 issues found.
Others are questions
| bool fuzzyCompare = comparer.IsModified; | ||
| if (!fuzzyCompare) | ||
| { | ||
| var underlyingType = c.GetType().FindPrimaryEnumerableInterfaceGenericTypeArgument(); |
There was a problem hiding this comment.
We should not get here if c is IEquatable<T>.
| /// <param name="comparer">The <see cref="NUnitEqualityComparer"/> to adapt. If null, a new instance is created.</param> | ||
| public NUnitEqualityComparerAdapter(NUnitEqualityComparer? comparer = null) | ||
| { | ||
| _comparer = comparer ?? new NUnitEqualityComparer(); |
There was a problem hiding this comment.
As we call this several times for the same type T, I wonder if we can cache the EqualMethod
It is either:
- The user specified external comparer of type
EqualityAdapter - The
EqualMethodfound in the list of NUnitsComparers PropertiesComparer.Equal
There was a problem hiding this comment.
Great minds think alike.
I had actually initially worked on #3985 instead of this equivalency issue and had started going down a related but slightly different route which didn't quite feel right at the time.
I think your idea is a great way we could take some of the performance in both these areas further, however I'd prefer we not add it here in order to keep the PR focused more on the collectiontally and related algorithms there.
|
@manfred-brands One of your commits has broken a test. |
That is weird, I have a green build. |
|
@manfred-brands Please hold off on pushing further commits for now. There were a few conscious design choices of mine that I haven't had the opportunity to respond to your questions about yet |
I won't, but the error is caused by the code picking the HashableItemStrategy and the HashCode of identical arrays is not the same: So for the |
This by moving fields from the CollectionTally class to the ItemsStrategy class.
…raintTests.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com>
This reverts commit b9b7e90.
05d46a4 to
78281a5
Compare
|
@manfred-brands Thanks for your detailed suggestions. I think I've been able to chip away at most of the suggested changes in bits of free time I had today. Comments which have been addressed by code changes have been marked resolved, but those which I have just responded to with comments haven't. I've also responded with some of my thinking for the design decisions around generic and non-generic collectiontally There's still a handful of nullability-related items I'd like to investigate as well as changing ownership of |
|
I think I've addressed all the suggestions. The three remaining unaddressed improvements which I would prefer be tackled separately are:
The last of those already has #3985. I can create tracking issues for the others as part of merging |
|
@stevenaw There are several comments above that are not marked as Resolved. Your comment seems to indicate that they are resolved - do I read you correctly? |
|
@OsirisTerje I consider a few to be "by design", however I left the actual comments unresolved in order to invite future discussion instead of hiding the ideas. There are also separately two future improvements which can be made to take this further which I would feel more comfortable doing later. I think there's a lot of value merging this as it is already as it sets up several patterns for us to build on and/or use to modernise the codebase going forward |
* Exclude null from the "Special handling when sole argument is an object[]" * Change the test to reflect the new behaviour * Exclude null from the "Special handling when sole argument is an object[]" * Change the test to reflect the new behaviour * Update Cake.Tool from 4.0.0 to 5.1.0 Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Agent-Logs-Url: https://github.com/nunit/nunit/sessions/eff1c2d0-f67d-4b74-995e-4e0592f2ec27 * Update Cake.Tool to 5.1.0 in .config-macos/dotnet-tools.json Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Agent-Logs-Url: https://github.com/nunit/nunit/sessions/b5ea6ea3-eed1-40bd-924e-f4822f0803fc * Add `mainthread` argument parsing to nunitlite * Update src/NUnitFramework/framework/Attributes/PlatformNames.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix comments * Fix with GetEffectiveProperty * Fix syntax in IncludeExcludeAttribute * Remove unused using * Restore baseclass checking that the constraint expects string arguments. * Clarify intent by replacing anonymous `new` with `new ResultState` * Add SameAs<T> to constraintexpression * Do not unpack an array if it is generic or assignable from IEnumerable<> * Don't unpack array if the target method only expects a single parameter. * Update Cake to version 6.1 (#5201) * Bump cake versions to 6.1 * Update our cakescripts project to match the runtime of the current cake version * Updated minver, made it match with the adapter code, and get rid of the warning. * Fix minver version on std --------- Co-authored-by: Terje Sandstrom <terje@hermit.no> * Optimize the unpack method and add some edge case test coverage for existing behaviour. * Ensure the same exception is thrown today as before * Update partition filter to use our GC polyfill * Update src/NUnitFramework/framework/Internal/Extensions/ArgumentsExtensions.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add test for copilot-identified feedback * Moved benchmark code to NUnit.InternalTools repo, and removed it from… (#5203) * Moved benchmark code to NUnit.InternalTools repo, and removed it from framework * Fixing copilot review comments, removing benchmark related stuff in some other files. * Updated third party dev packages licence and versions * Add test coverage for platform attribute behaviours * Respond to feedback * Use non-standard names to augment PlatformHelper. That way it won't affect the standard operation * Add real os specific tests * Add examples of test with Excludes * Fixes #5211 * Add missing invalid depth guard and test coverage of generic configuration * Changed to more informative exception type * Review changes * Exposed the last Recorded Exception in TestResult (#5217) * Exposed the last Recorded Exception in TestResult * Update src/NUnitFramework/tests/TestContextTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Display values of properties in case of an unexpected Exception (#5216) * Display values of properties in case of an unexpected Exception * Cache Exception properties and don't add overridden base class properties * Phase 1 - moving towards dotnet build (#5210) * Phase 1 - moving towards dotnet build * Update src/NUnitFramework/Directory.Build.props Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * removed Version property * fixed unreadable logs (blue color) and added copilot deletions to the target file * updated minver * Changed to correct sdk for building, kept an error to check the output * Updated yml * adding a compiler error * fix compiler error again * Adding caching * remove caching * Updated tests that were flaky --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Phase 2 - Issue5207 simplify testing and building in cake (#5213) * Phase 1 - moving towards dotnet build * Update src/NUnitFramework/Directory.Build.props Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * removed Version property * fixed unreadable logs (blue color) and added copilot deletions to the target file * updated minver * Fixing cake builds and converting testing * fixing action workflows * fixed copilot comments * fixed copilot comments * increased time for LargeStringCollectionsInReversedOrder * increased time for LargeStringCollectionsInSameOrder * increased time for LargeStringCollectionsInSameOrder * removed SA1001, it crashes with VS formatting * Increased timeout so that CI builds works, they run fast locally * removed windows runs from linux and mac * removed windows runs from linux and mac * reducing CI noise * reducing CI noise * fix flaky windows test * fix other flaky windows tests * Revert "removed SA1001, it crashes with VS formatting" This reverts commit 6547a48. * Fix so that VS and SA agree on formatting. * Changed to correct sdk for building, kept an error to check the output * Updated yml * adding a compiler error * fix compiler error again * Adding caching * Adding trx reporting * removed cache again * Changed to Dorny due to container usage of enrico * changed to minimal * Changed failed on error * trying to get linux/mac to work too * Fixed error in reporting * Getting back a bit more than quiet * adjusting verbosity * changed output from tests * reverted change to test that didnt actually work, it might still be flaky * Updated Ci workflow * updated workflow * finickling the workflow again * converted to python and fixed paths * adding debugging * converted to python and fixed paths * adding debugging 2 * test became wrong, now fails correctly * fixing linux/mac * fixing stacktrace * fixing header * fixing stacktrace * Set the delibertaelyfailing test back to Explicit * Fix null reference warning in TestResultsParser * Remove netstandard/netcoreapp from FrameworkPattern Drop IgnoreCase and ToLower as frameworks are case-sensitive. We also only use lower case consistently. * Making flaky test explicit * Reverted TextOutputTests * UPdated building instructions * Updated adapter to 6.2 for all but the net6 which uses 5.2 * Tried to make the DelayedConstraintTests a bit less flaky * New attempt to make it work on linux/mac, * And again * Set TestingPlatformDotnetTestSupport=true, and simplified conditionals * and again, MTP is a mess * Reverted back to adapter 5.2.0 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Issue4824 replace delegates (#5196) * Remove Obsolute Apply(ref TActual) * Add overloads for Action and Func<Task> This is meant to replace TestDelegate and AsyncTestDelegate respectively. To prevent overload resolution conflicts with Lambda, the old methods are deprioritized * Add overloads for Func<TActual> * Add NUnit.Analyzer suppressions for Func<T> Revert when nunit/nunit.analyzers#982 is released * Mark Delegate declarations as Obsolete * Remove some test usages of delegates * Fix merge conflicts after rebase * Fix merge conflicts after rebase --------- Co-authored-by: Terje Sandstrom <terje@hermit.no> * Fastpaths for equivalency + super/sub set tests for certain types (#5224) * Add generic collectiontally and supported classes. * Move the tally fastpath into a base class so that sub/super sets can use it too * A bit of cleanup before trying to fix O(n^2) impl * O(n+m) optimization * Fastpath for bytes * Add "unsorted" dictionary-based path. 5x faster for strings * Add copilot instruction to preserve performance * Convert CollectionTally{T} to use strategy pattern internally with different paths for primitives or others * Lazily instantiate the strategies * A bit of usability cleanup for CollectionTally{T} * Make the generic collectiontally{t} work for types not explicitly targeted * Fix a few bugs * Better encapsulate the state management required by the collection tally strategies and ensure all paths go to new collection tally class * Mark the public protected method obsolete * Use AssignableFrom for sortable check since it's available on all runtimes and still intrinsic * Update the collectiontally tests to target the generic version * Lower the largecollection timing thresholds by factor of 5 since the perf improvements seem to speed it up by at least factor of 6 * Re-add stringcollection special case as it previously existed in non-generic CollectionTally * Add test coverage for generic IEnumerable<T>.IsSortable() method and for some additional collectiontally paths * Update src/NUnitFramework/framework/Constraints/CollectionTally{T}.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/NUnitFramework/tests/Constraints/CollectionEquivalentConstraintTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/NUnitFramework/framework/Constraints/CollectionTally{T}.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/NUnitFramework/tests/Internal/Extensions/IEnumerableExtensionTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Improve sort-related fastpath inference not types not explicity targeted * Fix some outstanding bugs when dealing with object-based collections to maximize the chosen strategy * Make some new things internal instead of public. Make it so tuples + valuetuples can use more efficient strategies if their underlying types support it * Allow the NUnit Comparer adapter to adhere to hashcode/equality semantics * Update src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Rename HashCodeExtensions.cs to HashCode.cs to match the contained type Agent-Logs-Url: https://github.com/nunit/nunit/sessions/f62a73e3-7ab5-4940-8412-0921b378452c Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> * Remove the need to base a base class field to a base class method. * Fix strangling between CollectionTally and ItemsStrategy This by moving fields from the CollectionTally class to the ItemsStrategy class. * Update src/NUnitFramework/tests/Constraints/CollectionEquivalentConstraintTests.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Revert "Fix strangling between CollectionTally and ItemsStrategy" This reverts commit b9b7e90. * Remove tolerance from the equality adapter for now * Make arguments consistent in test helper * Move instantiation back to a SetUp callback * Remove unneccesary check on _comparePropertiesConfiguration * Add descriptive comment for why to target a few explicit type fast-paths * Re-add descriptive elapsed time for the equivalency performance tests * Rename "MergeSortItemsStrategy" to "SortAndScanItemsStrategy" for better clarity * Remove null default arg. It's unused * Add test for nulls * Explicitly allow for nullable missing/extra items * Avoid accessing private variables from both class and inner class --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Reorganize collectionequiavelncy tests so that only performance-focused ones are excluded from MacOS. * Enable collectionequivalency tests on MacOS * Make TestParameters.ArgDisplayNames getter public, #3822 (#5236) * Adjust a few cases for passing exceptions to AfterTest hook * Add coverage for capturing exception for setup/teardown * After exception-related test cases for hooks and test actions * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove unused result variables to fix CS0219 warnings-as-errors build failure Agent-Logs-Url: https://github.com/nunit/nunit/sessions/cf703463-aadb-4e1b-9dfc-e810ffaba573 Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> * Ensure the approach to testing path constraints is consistent across OSes and sub-constraint * chore: Bump NUnit.Analyzers and remove TODOs (#5248) * fix RetryAttribute * add unit test * improve unit test * Apply suggestions from code review Co-authored-by: Terje Sandstrom <terje@hermit.no> * fix `RetryOnAllowedStopsOnOtherException` and add `using (Assert.EnterMultipleScope())` to applicable tests in `RetryAttributeTests` * apply suggestions * Refactor DateTimeOffsetEquality tests to use explicit [Test] methods to avoid invalid cases being generated from data points * Reduce skipped count by filtering out invalid test cases for runtimeframework ParseByClrVersion tests * Remove tests duplicated by DatapointTests.WorksOnField * Move the nullvaluesource tests into testdata so that we can remove the "explicit" usage on the original test method and prevent them reporting as "skipped" * Respond to most feedback * Merged with main, and fixed #5253 * Fixed some comments * Apply suggestion from @stevenaw * Apply suggestions from code review Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> * Fix up a few things from the in-browser suggestions. It all passed locally * Update src/NUnitFramework/tests/AsyncExecutionApiAdapter.Constraint-based.cs Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fixed comments * Fix comment * Fix nullanble issue --------- Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Co-authored-by: stevenaw <sweerdenburg@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> Co-authored-by: Will Dean <will.dean@indcomp.co.uk> Co-authored-by: Paul Irwin <paulirwin@gmail.com> Co-authored-by: Mikkel Nylander Bundgaard <mikkelbu@users.noreply.github.com> Co-authored-by: ackhack <christoph.fuerbacher@gmail.com> Co-authored-by: Christoph Fürbacher <43985368+ackhack@users.noreply.github.com>
* Remove the non-generic sameas methods and constraint * feat: Drop .NET 6 as a build target of the framework * TestCaseData rework (#5138) * Reworked the TestCaseData.cs type into a hierarchy with generic types providing type safety without code duplication - Added type TestCaseDataBase.cs to be the new root of the tree of types for test case data. Migrated all Fluent Access Modifiers on TestCaseData except for Returns here. - Added type TestCaseDataWithReturnBase.cs to extend TestCaseDataBase with return values. Migrated the Returns Fluent Access Modifier here. - Reworked the non-generic TestCaseData class in TestCaseData.cs as a subclass of TestCaseDataWithReturnBase<TestCaseData, object>. Added an implicit conversion operator to TestCaseDataBase<TSelf> so that existing code that assumes any derived TestCaseData can be assigned to TestCaseData still works. - Reworked the generic TestCaseData<T...> classes to inherit from TestCaseDataBase<...>. - Added class TestCaseDataWithReturn.cs that provides subclasses of TestCaseDataWithReturn.cs for up to 5 generic argumnents. - Updated IgnoredTestCaseData.cs to use TestCaseParameters as the common non-generic root type for all test case data, since TestCaseData is now no longer an ancestor. - Added automated testing of TestCaseData<T...> and TestCaseDataWithReturn<T..., TReturn>. * Added missing constructors in TestCaseDataBase.cs and TestCaseDataWithReturnBase.cs to allow cloning from another TestCaseParameters object. * Added static Create methods to TestCaseData.cs. Removed unnecessary constructors from TestCaseDataBase.cs and TestCaseDataWithReturnBase.cs. Removed constructors accepting expectedReturnValue from each of the TestCaseDataWithReturn generic types in TestCaseDataWithReturn.cs. Removed associated tests from TestCaseSourceTests.cs. Added a static Return method to each of the TestCaseData generic types in TestCaseData.cs which transform the instance to a TestCaseDataWithReturn<.., TReturn>. Added an internal constructor to each of the TestCaseDataWithReturn generic types to import data from any object of a type deriving from TestCaseParameters. Added tests in TestCaseDataTests.cs that verify (at compile time) that TestCaseData.Create<..> and TestCaseData<..>.Returns<TReturn> yield a reference compatible with the expected type and that the migration of data from TestCaseData<..> to TestCaseDataWithReturn<.., TReturn> works properly. * Showcase the use of the Create factory method alongside the constructor * Added test cases for TestCaseDataWithReturn<T> with 2 and 3 arguments --------- Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Update src/NUnitFramework/framework/Attributes/OSPlatformConverter.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * chore: Update platform constants * `#if NET8_0_OR_GREATER` => `+#if !NETFRAMEWORK` * `#if !NET8_0_OR_GREATER` => `#if NETFRAMEWORK` I've kept the explanation and the constants in BUILDING.md * Fix merge issue * Change namespace for string, collection, file and directory classes * Remove the non-generic sameas methods and constraint * TestCaseData rework (#5138) * Reworked the TestCaseData.cs type into a hierarchy with generic types providing type safety without code duplication - Added type TestCaseDataBase.cs to be the new root of the tree of types for test case data. Migrated all Fluent Access Modifiers on TestCaseData except for Returns here. - Added type TestCaseDataWithReturnBase.cs to extend TestCaseDataBase with return values. Migrated the Returns Fluent Access Modifier here. - Reworked the non-generic TestCaseData class in TestCaseData.cs as a subclass of TestCaseDataWithReturnBase<TestCaseData, object>. Added an implicit conversion operator to TestCaseDataBase<TSelf> so that existing code that assumes any derived TestCaseData can be assigned to TestCaseData still works. - Reworked the generic TestCaseData<T...> classes to inherit from TestCaseDataBase<...>. - Added class TestCaseDataWithReturn.cs that provides subclasses of TestCaseDataWithReturn.cs for up to 5 generic argumnents. - Updated IgnoredTestCaseData.cs to use TestCaseParameters as the common non-generic root type for all test case data, since TestCaseData is now no longer an ancestor. - Added automated testing of TestCaseData<T...> and TestCaseDataWithReturn<T..., TReturn>. * Added missing constructors in TestCaseDataBase.cs and TestCaseDataWithReturnBase.cs to allow cloning from another TestCaseParameters object. * Added static Create methods to TestCaseData.cs. Removed unnecessary constructors from TestCaseDataBase.cs and TestCaseDataWithReturnBase.cs. Removed constructors accepting expectedReturnValue from each of the TestCaseDataWithReturn generic types in TestCaseDataWithReturn.cs. Removed associated tests from TestCaseSourceTests.cs. Added a static Return method to each of the TestCaseData generic types in TestCaseData.cs which transform the instance to a TestCaseDataWithReturn<.., TReturn>. Added an internal constructor to each of the TestCaseDataWithReturn generic types to import data from any object of a type deriving from TestCaseParameters. Added tests in TestCaseDataTests.cs that verify (at compile time) that TestCaseData.Create<..> and TestCaseData<..>.Returns<TReturn> yield a reference compatible with the expected type and that the migration of data from TestCaseData<..> to TestCaseDataWithReturn<.., TReturn> works properly. * Showcase the use of the Create factory method alongside the constructor * Added test cases for TestCaseDataWithReturn<T> with 2 and 3 arguments --------- Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * feat: Drop .NET 6 as a build target of the framework * Update src/NUnitFramework/framework/Attributes/OSPlatformConverter.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * chore: Update platform constants * `#if NET8_0_OR_GREATER` => `+#if !NETFRAMEWORK` * `#if !NET8_0_OR_GREATER` => `#if NETFRAMEWORK` I've kept the explanation and the constants in BUILDING.md * Change namespace for string, collection, file and directory classes * Add generic type constraints * Add tests and missing xmldoc * Add throwsconstraint tests * Update src/NUnitFramework/framework/Assert.Exceptions.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Update src/NUnitFramework/framework/Assert.Exceptions.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Update src/NUnitFramework/framework/Assert.Exceptions.Async.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Update src/NUnitFramework/framework/Assert.Exceptions.Async.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Restore binary-compliant return type * Restructure some of the inheritance hierarchy to have all generic type constraints under a common generic TypeContraint<T> * Re-add tests and adjust existing to account for new inheritance hierarchy * Completely separate inheritance hierarchy for generic type-checking constraints * Add quick paramname validation to existing test * Release5x mainmerge issue5253 (#5262) * Exclude null from the "Special handling when sole argument is an object[]" * Change the test to reflect the new behaviour * Exclude null from the "Special handling when sole argument is an object[]" * Change the test to reflect the new behaviour * Update Cake.Tool from 4.0.0 to 5.1.0 Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Agent-Logs-Url: https://github.com/nunit/nunit/sessions/eff1c2d0-f67d-4b74-995e-4e0592f2ec27 * Update Cake.Tool to 5.1.0 in .config-macos/dotnet-tools.json Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Agent-Logs-Url: https://github.com/nunit/nunit/sessions/b5ea6ea3-eed1-40bd-924e-f4822f0803fc * Add `mainthread` argument parsing to nunitlite * Update src/NUnitFramework/framework/Attributes/PlatformNames.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix comments * Fix with GetEffectiveProperty * Fix syntax in IncludeExcludeAttribute * Remove unused using * Restore baseclass checking that the constraint expects string arguments. * Clarify intent by replacing anonymous `new` with `new ResultState` * Add SameAs<T> to constraintexpression * Do not unpack an array if it is generic or assignable from IEnumerable<> * Don't unpack array if the target method only expects a single parameter. * Update Cake to version 6.1 (#5201) * Bump cake versions to 6.1 * Update our cakescripts project to match the runtime of the current cake version * Updated minver, made it match with the adapter code, and get rid of the warning. * Fix minver version on std --------- Co-authored-by: Terje Sandstrom <terje@hermit.no> * Optimize the unpack method and add some edge case test coverage for existing behaviour. * Ensure the same exception is thrown today as before * Update partition filter to use our GC polyfill * Update src/NUnitFramework/framework/Internal/Extensions/ArgumentsExtensions.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add test for copilot-identified feedback * Moved benchmark code to NUnit.InternalTools repo, and removed it from… (#5203) * Moved benchmark code to NUnit.InternalTools repo, and removed it from framework * Fixing copilot review comments, removing benchmark related stuff in some other files. * Updated third party dev packages licence and versions * Add test coverage for platform attribute behaviours * Respond to feedback * Use non-standard names to augment PlatformHelper. That way it won't affect the standard operation * Add real os specific tests * Add examples of test with Excludes * Fixes #5211 * Add missing invalid depth guard and test coverage of generic configuration * Changed to more informative exception type * Review changes * Exposed the last Recorded Exception in TestResult (#5217) * Exposed the last Recorded Exception in TestResult * Update src/NUnitFramework/tests/TestContextTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Display values of properties in case of an unexpected Exception (#5216) * Display values of properties in case of an unexpected Exception * Cache Exception properties and don't add overridden base class properties * Phase 1 - moving towards dotnet build (#5210) * Phase 1 - moving towards dotnet build * Update src/NUnitFramework/Directory.Build.props Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * removed Version property * fixed unreadable logs (blue color) and added copilot deletions to the target file * updated minver * Changed to correct sdk for building, kept an error to check the output * Updated yml * adding a compiler error * fix compiler error again * Adding caching * remove caching * Updated tests that were flaky --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Phase 2 - Issue5207 simplify testing and building in cake (#5213) * Phase 1 - moving towards dotnet build * Update src/NUnitFramework/Directory.Build.props Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * removed Version property * fixed unreadable logs (blue color) and added copilot deletions to the target file * updated minver * Fixing cake builds and converting testing * fixing action workflows * fixed copilot comments * fixed copilot comments * increased time for LargeStringCollectionsInReversedOrder * increased time for LargeStringCollectionsInSameOrder * increased time for LargeStringCollectionsInSameOrder * removed SA1001, it crashes with VS formatting * Increased timeout so that CI builds works, they run fast locally * removed windows runs from linux and mac * removed windows runs from linux and mac * reducing CI noise * reducing CI noise * fix flaky windows test * fix other flaky windows tests * Revert "removed SA1001, it crashes with VS formatting" This reverts commit 6547a48. * Fix so that VS and SA agree on formatting. * Changed to correct sdk for building, kept an error to check the output * Updated yml * adding a compiler error * fix compiler error again * Adding caching * Adding trx reporting * removed cache again * Changed to Dorny due to container usage of enrico * changed to minimal * Changed failed on error * trying to get linux/mac to work too * Fixed error in reporting * Getting back a bit more than quiet * adjusting verbosity * changed output from tests * reverted change to test that didnt actually work, it might still be flaky * Updated Ci workflow * updated workflow * finickling the workflow again * converted to python and fixed paths * adding debugging * converted to python and fixed paths * adding debugging 2 * test became wrong, now fails correctly * fixing linux/mac * fixing stacktrace * fixing header * fixing stacktrace * Set the delibertaelyfailing test back to Explicit * Fix null reference warning in TestResultsParser * Remove netstandard/netcoreapp from FrameworkPattern Drop IgnoreCase and ToLower as frameworks are case-sensitive. We also only use lower case consistently. * Making flaky test explicit * Reverted TextOutputTests * UPdated building instructions * Updated adapter to 6.2 for all but the net6 which uses 5.2 * Tried to make the DelayedConstraintTests a bit less flaky * New attempt to make it work on linux/mac, * And again * Set TestingPlatformDotnetTestSupport=true, and simplified conditionals * and again, MTP is a mess * Reverted back to adapter 5.2.0 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Issue4824 replace delegates (#5196) * Remove Obsolute Apply(ref TActual) * Add overloads for Action and Func<Task> This is meant to replace TestDelegate and AsyncTestDelegate respectively. To prevent overload resolution conflicts with Lambda, the old methods are deprioritized * Add overloads for Func<TActual> * Add NUnit.Analyzer suppressions for Func<T> Revert when nunit/nunit.analyzers#982 is released * Mark Delegate declarations as Obsolete * Remove some test usages of delegates * Fix merge conflicts after rebase * Fix merge conflicts after rebase --------- Co-authored-by: Terje Sandstrom <terje@hermit.no> * Fastpaths for equivalency + super/sub set tests for certain types (#5224) * Add generic collectiontally and supported classes. * Move the tally fastpath into a base class so that sub/super sets can use it too * A bit of cleanup before trying to fix O(n^2) impl * O(n+m) optimization * Fastpath for bytes * Add "unsorted" dictionary-based path. 5x faster for strings * Add copilot instruction to preserve performance * Convert CollectionTally{T} to use strategy pattern internally with different paths for primitives or others * Lazily instantiate the strategies * A bit of usability cleanup for CollectionTally{T} * Make the generic collectiontally{t} work for types not explicitly targeted * Fix a few bugs * Better encapsulate the state management required by the collection tally strategies and ensure all paths go to new collection tally class * Mark the public protected method obsolete * Use AssignableFrom for sortable check since it's available on all runtimes and still intrinsic * Update the collectiontally tests to target the generic version * Lower the largecollection timing thresholds by factor of 5 since the perf improvements seem to speed it up by at least factor of 6 * Re-add stringcollection special case as it previously existed in non-generic CollectionTally * Add test coverage for generic IEnumerable<T>.IsSortable() method and for some additional collectiontally paths * Update src/NUnitFramework/framework/Constraints/CollectionTally{T}.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/NUnitFramework/tests/Constraints/CollectionEquivalentConstraintTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/NUnitFramework/framework/Constraints/CollectionTally{T}.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/NUnitFramework/tests/Internal/Extensions/IEnumerableExtensionTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Improve sort-related fastpath inference not types not explicity targeted * Fix some outstanding bugs when dealing with object-based collections to maximize the chosen strategy * Make some new things internal instead of public. Make it so tuples + valuetuples can use more efficient strategies if their underlying types support it * Allow the NUnit Comparer adapter to adhere to hashcode/equality semantics * Update src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Rename HashCodeExtensions.cs to HashCode.cs to match the contained type Agent-Logs-Url: https://github.com/nunit/nunit/sessions/f62a73e3-7ab5-4940-8412-0921b378452c Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> * Remove the need to base a base class field to a base class method. * Fix strangling between CollectionTally and ItemsStrategy This by moving fields from the CollectionTally class to the ItemsStrategy class. * Update src/NUnitFramework/tests/Constraints/CollectionEquivalentConstraintTests.cs Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Revert "Fix strangling between CollectionTally and ItemsStrategy" This reverts commit b9b7e90. * Remove tolerance from the equality adapter for now * Make arguments consistent in test helper * Move instantiation back to a SetUp callback * Remove unneccesary check on _comparePropertiesConfiguration * Add descriptive comment for why to target a few explicit type fast-paths * Re-add descriptive elapsed time for the equivalency performance tests * Rename "MergeSortItemsStrategy" to "SortAndScanItemsStrategy" for better clarity * Remove null default arg. It's unused * Add test for nulls * Explicitly allow for nullable missing/extra items * Avoid accessing private variables from both class and inner class --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> * Reorganize collectionequiavelncy tests so that only performance-focused ones are excluded from MacOS. * Enable collectionequivalency tests on MacOS * Make TestParameters.ArgDisplayNames getter public, #3822 (#5236) * Adjust a few cases for passing exceptions to AfterTest hook * Add coverage for capturing exception for setup/teardown * After exception-related test cases for hooks and test actions * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove unused result variables to fix CS0219 warnings-as-errors build failure Agent-Logs-Url: https://github.com/nunit/nunit/sessions/cf703463-aadb-4e1b-9dfc-e810ffaba573 Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> * Ensure the approach to testing path constraints is consistent across OSes and sub-constraint * chore: Bump NUnit.Analyzers and remove TODOs (#5248) * fix RetryAttribute * add unit test * improve unit test * Apply suggestions from code review Co-authored-by: Terje Sandstrom <terje@hermit.no> * fix `RetryOnAllowedStopsOnOtherException` and add `using (Assert.EnterMultipleScope())` to applicable tests in `RetryAttributeTests` * apply suggestions * Refactor DateTimeOffsetEquality tests to use explicit [Test] methods to avoid invalid cases being generated from data points * Reduce skipped count by filtering out invalid test cases for runtimeframework ParseByClrVersion tests * Remove tests duplicated by DatapointTests.WorksOnField * Move the nullvaluesource tests into testdata so that we can remove the "explicit" usage on the original test method and prevent them reporting as "skipped" * Respond to most feedback * Merged with main, and fixed #5253 * Fixed some comments * Apply suggestion from @stevenaw * Apply suggestions from code review Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> * Fix up a few things from the in-browser suggestions. It all passed locally * Update src/NUnitFramework/tests/AsyncExecutionApiAdapter.Constraint-based.cs Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fixed comments * Fix comment * Fix nullanble issue --------- Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Co-authored-by: stevenaw <sweerdenburg@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> Co-authored-by: Will Dean <will.dean@indcomp.co.uk> Co-authored-by: Paul Irwin <paulirwin@gmail.com> Co-authored-by: Mikkel Nylander Bundgaard <mikkelbu@users.noreply.github.com> Co-authored-by: ackhack <christoph.fuerbacher@gmail.com> Co-authored-by: Christoph Fürbacher <43985368+ackhack@users.noreply.github.com> * fixed compiler errors * fixed 4th copilot comment on PR * fixed 3rd copilot comment on PR --------- Co-authored-by: stevenaw <sweerdenburg@gmail.com> Co-authored-by: Mikkel Bundgaard <mikkelbu@gmail.com> Co-authored-by: Jonathan Gilbert <logic@deltaq.org> Co-authored-by: Manfred Brands <manfred-brands@users.noreply.github.com> Co-authored-by: Mikkel Nylander Bundgaard <mikkelbu@users.noreply.github.com> Co-authored-by: Steven Weerdenburg <stevenaw@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stevenaw <439844+stevenaw@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Will Dean <will.dean@indcomp.co.uk> Co-authored-by: Paul Irwin <paulirwin@gmail.com> Co-authored-by: ackhack <christoph.fuerbacher@gmail.com> Co-authored-by: Christoph Fürbacher <43985368+ackhack@users.noreply.github.com>
Fixes #4254
This PR adds some fastpaths for certain commonly used types of collections. It:
CollectionTally<T>classCollectionTally<T>for a predefined list of common types.EqualityComparer<T>.Defaultinstead of theNUnitEqualityComparerwhen there would be no behavioural differenceO(n+m)algorithms instead of aO(n*m)where possibleI am submitting this as a draft for now as I'm still completing some cleanup of different paths, as well as some final investigation and experimentation for which types to "light up" for these fast paths. My performance testing has focused on updating the following equivalency tests to apply the constraint 500 times. I then run the test 5 times, discard the first timing, and average the next 4. All tests were run against .NET 10.
All times are for the full 500 iterations to run. "Before" is on
mainbranch and "After" is using this branch.StringCollectionIEnumerable<string>IEnumerable<string>IEnumerable<int>byte[]There is a general speedup of 6-12x for most data types based on: