-
Notifications
You must be signed in to change notification settings - Fork 752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EnumerableRetriever does not play together with NullValueRetriever #2626
Comments
The EnumerableValueRetriever (which processes lists/collections) makes an assumption that every item in the list can be processed by the same underlying value retriever. So when the Value string has "1, My assumption is that this was done for performance reasons so that the search for the underlying retriever would not be repeated needlessly (under most circumstances). @SabotageAndi - would you consider a PR that removes the null coalescing assignment operator? Code in question: private IEnumerable GetItems(string[] strings, KeyValuePair<string, string> keyValuePair, Type targetType, Type itemType)
{
IValueRetriever retriever = null;
foreach (var splitValue in strings)
{
var itemKeyValuePair = new KeyValuePair<string, string>(keyValuePair.Key, splitValue.Trim());
retriever ??= GetValueRetriever(itemKeyValuePair, targetType, itemType);
yield return retriever?.Retrieve(itemKeyValuePair, targetType, itemType);
}
} |
Modified location of variable declaration in EnumerableValueRetriever to make the code cleaner. Added this change to the changelog.txt
@SabotageAndi Maybe continue here the discussion instead of polluting the PR. What's the definition of a ValueRetriever? Is the expectation that there is one for a type, or should there be multiple allowed? (If it is the latter, can you shed some light on some usecases? Why am I asking? => If there should only be one, then the PR fixes it the wrong way. If there should be multiple, then the PR is fine. But I'm then questioning the reasoning behind the multiple ones. :) |
I don't have the background that you all do, so I'll defer to you on the original intent. I can imagine the input being quite messy with special values that don't map/parse cleanly to values of the type system. This would imply that we should be open to the idea of having multiple value retrievers for any given Property Type. One way, perhaps, to think of the NullValueRetriever, is as a special case of the more generic problem of recognizing special tokens in the enumerable and then replacing them with values that match the Property Type of the Enumerable. For example, a recognizer/s that replaces all instances of the string "Foo" with 0, and "Bar" with 1. The string values in the input list are supposed to make sense to the business, not necessarily perfectly align with the language's type system. An alternative design, then, would be to restrict these components as strict recognizers, not full-fledged Value Retrievers. Place these recognizers up front in the pipeline and run them across all elements, substituting appropriate 'real' values, then run the built-in Value Retrievers against these values. Another alternative that I believe would meet @bollhals's intent, is to design the NullValueRetriever as a wrapper instead of a full-fledged ValueRetriever. It would defer recognition of the special value until the time of retrieval, substitute in a different value, then delegate to the built-in retriever that is appropriate for that Type. The null-coalescing logic of the existing EnumerableValueRetriever would then be correct and could stay in place. In the example of the NullValueRetriever<Int?>, the NullValueRetriever CanRetrieve method would return true if the Property Type matched Int?. Thus, it would be used for every element in a List<Int?> regardless of whether the trigger value was the first item in the list or the last. |
I don't think there is an actual definition of a ValurRetriever or @gasparnagy? If a ValueRetriever calls another ValueRetriever is a case, that is fine for me. It's all about making it easier. |
#2638 is merged |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
SpecFlow Version
3.9.74
Which test runner are you using?
xUnit
Test Runner Version Number
3.9.74
.NET Implementation
.NET 6.0
Project Format of the SpecFlow project
Sdk-style project format
.feature.cs files are generated using
SpecFlow.Tools.MsBuild.Generation NuGet package
Test Execution Method
Visual Studio Test Explorer
SpecFlow Section in app.config or content of specflow.json
No response
Issue Description
It seems like the NullValueRetriever is ignored by the EnumerableRetriever when using nullable types in enumerables in tabular data.
In short I want to be able to write this:
But instead have to write this:
Steps to Reproduce
Given a feature step that contains tabular data with an enumerable with a nullable type:
The type to deserialize to:
Given there is a NullValueRetriever registered:
I expect the result of this to contain Enumerable<int?> { 1,2, null }
However, it doesn't. The actual result is Enumerable<int?> { 1,2, 0 }, Seems like the NullValueRetriever is ignored by the EnumerableRetriever.
I have to write this to get a null value:
Personally I feel that is not very readable.
Link to Repro Project
No response
The text was updated successfully, but these errors were encountered: