Conversation
…port # Conflicts: # src/Altinn.App.Core/Internal/Expressions/ExpressionValue.cs
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis pull request converts the expression evaluation system's numeric handling from double to decimal precision, implements four new arithmetic operations (plus, minus, multiply, divide), and adds comprehensive test coverage for all new functionality across multiple input types and edge cases. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs`:
- Around line 947-956: In Average, materialize the enumerable returned by
PrepareMultipleNumericArgs (e.g., call ToArray() or ToList() on numericArgs) to
avoid double enumeration, then validate that the materialized collection has at
least one element and handle the empty case (throw an ArgumentException or
similar) before performing the sum and division; keep using
PrepareMultipleNumericArgs and CultureInfo.InvariantCulture so the method uses
the concrete collection count for division and avoids divide-by-zero.
- Around line 936-945: The Divide method currently uses
PrepareMultipleNumericArgs and divides the first value by subsequent args
without checking for zero; update Divide (and use numericArgs.First() and
numericArgs.Skip(1) locations) to detect any divisor equal to 0 before
performing the division and instead raise/return the same kind of user-friendly
expression error used elsewhere (e.g., an Expression evaluation
exception/message) indicating "Division by zero" so it fails gracefully rather
than throwing a raw DivideByZeroException.
🧹 Nitpick comments (6)
src/Altinn.App.Core/Internal/Expressions/ExpressionValue.cs (3)
18-19: Stale comment referencesdoubleinstead ofdecimal.The comment on line 18 still mentions "double" but the field is now
decimal. Consider updating for consistency.📝 Suggested comment update
- // double is a value type where nullable takes extra space, and we only read it when it should be set + // decimal is a value type where nullable takes extra space, and we only read it when it should be set private readonly decimal _numberValue = 0;
103-106: XML documentation referencesdoubleinstead ofdecimal.The summary comment should be updated to match the new parameter type.
📝 Suggested documentation update
/// <summary> - /// Convert a nullable double to ExpressionValue + /// Convert a nullable decimal to ExpressionValue /// </summary> public static implicit operator ExpressionValue(decimal? value) => new(value);
134-135: Misleading comments on float/double conversion.The comments state "expressions uses double" but the code is actually casting to
decimal. The comments should reflect the current behavior.📝 Suggested comment update
- float numberValue => (decimal?)numberValue, // expressions uses double which needs an explicit cast - double numberValue => (decimal?)numberValue, // expressions uses double which needs an explicit cast + float numberValue => (decimal?)numberValue, // expressions uses decimal which needs an explicit cast + double numberValue => (decimal?)numberValue, // expressions uses decimal which needs an explicit casttest/Altinn.App.Core.Tests/LayoutExpressions/ExpressionEvaluatorTests/ExpressionValueTests.cs (1)
58-71: Variable namedoubleValueis misleading now that it holds adecimal.Consider renaming to
decimalValueornumberValuefor clarity.📝 Suggested rename
[Fact] - public void TestDouble() + public void TestDecimal() { - decimal doubleValue = 123.456m; - ExpressionValue value = doubleValue; - Assert.Equal(doubleValue, value.ToObject()); - Assert.Equal(doubleValue, value.Number); + decimal decimalValue = 123.456m; + ExpressionValue value = decimalValue; + Assert.Equal(decimalValue, value.ToObject()); + Assert.Equal(decimalValue, value.Number); - value = ExpressionValue.FromObject(doubleValue); - Assert.Equal(doubleValue, value.ToObject()); + value = ExpressionValue.FromObject(decimalValue); + Assert.Equal(decimalValue, value.ToObject()); - Assert.Equal(doubleValue.ToString(CultureInfo.InvariantCulture), value.ToString()); + Assert.Equal(decimalValue.ToString(CultureInfo.InvariantCulture), value.ToString()); Assert.Throws<NotImplementedException>(() => value.GetHashCode()); - // Assert.Equal(doubleValue.GetHashCode(), value.GetHashCode()); + // Assert.Equal(decimalValue.GetHashCode(), value.GetHashCode()); }src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs (2)
829-837: Multiple enumeration issue withIEnumerable<decimal>return type.
PrepareMultipleNumericArgsreturnsIEnumerable<decimal>, but callers likeMinus,Multiply,Divide, andAverageenumerate it multiple times (e.g.,First(),Skip(1),Count()). This causes the LINQ chain to execute repeatedly.Consider materializing to an array or list:
♻️ Proposed fix to avoid multiple enumeration
- private static IEnumerable<decimal> PrepareMultipleNumericArgs(ExpressionValue[] args) + private static decimal[] PrepareMultipleNumericArgs(ExpressionValue[] args) { return args.Select(arg => PrepareNumericArg(arg)) .Select(x => !x.HasValue ? throw new ExpressionEvaluatorTypeErrorException("At least one of the arguments is not a number") : x.Value - ); + ) + .ToArray(); }
907-923: Missing minimum argument validation inPlusandMinus.
PlusandMinusdon't validate that at least one argument is provided. Ifargsis empty:
Plus:Sum()returns 0 (may be acceptable)Minus:First()throwsInvalidOperationExceptionConsider adding argument count validation for consistency with other functions like
AndandOr.🔧 Proposed fix for Minus
private static string Minus(ExpressionValue[] args) { + if (args.Length == 0) + { + throw new ExpressionEvaluatorTypeErrorException("Expected 1+ argument(s), got 0"); + } var numericArgs = PrepareMultipleNumericArgs(args); var sum = numericArgs.First();
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs
Outdated
Show resolved
Hide resolved
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/multiply/multiply-multiple-decimals.json`:
- Around line 3-4: Update the expected string for the multiply expression
["multiply", 0.1, 0.2, 15, 1.50] from "0.4500" to "0.45" so it matches the
evaluator's decimal.ToString(CultureInfo.InvariantCulture) output and the
Assert.Equal comparison; locate the test entry with the expression and replace
the expects value accordingly.
...ayoutExpressions/CommonTests/shared-tests/functions/multiply/multiply-multiple-decimals.json
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Altinn.App.Core/Internal/Expressions/ExpressionValue.cs (1)
134-145:⚠️ Potential issue | 🟠 MajorGuard float/double → decimal conversion for non-finite or out-of-range values.
Explicit casts from
float/doubletodecimalthrowOverflowExceptionon NaN, Infinity, or values outside the decimal range. This will surface as an unhandled exception in expression evaluation when user data contains such values. Wrap the conversion with a validation check and throwExpressionEvaluatorTypeErrorException(consistent with error handling patterns in this codebase) to keep failures controlled.Suggested fix
- float numberValue => (decimal?)numberValue, // expressions uses decimal which needs an explicit cast - double numberValue => (decimal?)numberValue, // expressions uses decimal which needs an explicit cast + float numberValue => ValidateAndCastFloatingPoint(numberValue), + double numberValue => ValidateAndCastFloatingPoint(numberValue),private static decimal? ValidateAndCastFloatingPoint(double value) { if (double.IsNaN(value) || double.IsInfinity(value) || value > (double)decimal.MaxValue || value < (double)decimal.MinValue) { throw new ExpressionEvaluatorTypeErrorException($"Cannot convert non-finite or out-of-range number to decimal: {value}"); } return (decimal?)value; }
🤖 Fix all issues with AI agents
In `@src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs`:
- Around line 907-974: The Multiply implementation can throw
InvalidOperationException when given zero arguments because numericArgs.First()
is called without a guard; add the same zero-argument check used in
Average/Divide so Multiply throws an ExpressionEvaluatorTypeErrorException with
a clear message (e.g., "At least one argument must be provided") before calling
PrepareMultipleNumericArgs, ensuring failures are consistent and testable;
update the Multiply method to check args.Length == 0 and throw
ExpressionEvaluatorTypeErrorException, then proceed with
PrepareMultipleNumericArgs and the existing multiplication logic.
In
`@test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/divide/divide-one-argument.json`:
- Line 2: Update the test case title string "Should throw exception when less
then two arguments are provided" to correct the typo by replacing "less then"
with "less than" so it reads "Should throw exception when less than two
arguments are provided"; locate and modify the JSON property value for the test
name in the entry containing that exact string.
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs
Outdated
Show resolved
Hide resolved
...e.Tests/LayoutExpressions/CommonTests/shared-tests/functions/divide/divide-one-argument.json
Outdated
Show resolved
Hide resolved
TomasEng
left a comment
There was a problem hiding this comment.
Er det slik å forstå at både plus, minus, multiply og divide kan ta imot et ubegrenset antall operander? Det er ikke noe problem i addisjon og multiplikasjon siden de er kommutative, men for subtraksjon og divisjon synes jeg ikke det gir mening med mer enn to operander (én minuend og én subtrahend for subtraksjon, og én dividend og én divisor for divisjon). Er det ytret noe ønske om at de skal ta imot flere?
Er det for øvrig gjort noen vurdering av navngivning på de nye funksjonene? For eksempel er jo både add og sum gode alternativer for plus, mens subtract og difference godt kan brukes i stedet for minus. Jeg har ikke noen umiddelbar formening om hva som er best, men tenker det er lurt å vurdere dette grundig siden det blir vanskelig å endre det senere.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs`:
- Around line 902-910: Remove the special-case zero-args guard from Minus so it
behaves like Plus/Multiply/Divide and always routes through
PrepareTwoNumericArgs; then update the error message in PrepareTwoNumericArgs
(which currently says "Invalid number of args for compare") to a neutral and
accurate message such as "Invalid number of args for numeric binary operation"
so a single-arg call to Minus yields a correct, non-misleading error.
In
`@test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/minus/subtracting-multiple-decimals.json`:
- Line 2: The test case name string "Should throw exception when more then two
arguments is present" contains a typo; update the test description used in the
JSON (the "name" field) to "Should throw exception when more than two arguments
is present" so it reads "than" instead of "then".
- Line 4: The hardcoded error string in PrepareTwoNumericArgs() wrongly
references "compare" and misleads arithmetic callers; update
PrepareTwoNumericArgs() to return a generic, function-agnostic message (e.g.,
"Invalid number of args" or "Expected 2 arguments") instead of "Invalid number
of args for compare" so callers like Minus, Plus, Multiply, Divide and
comparators (LessThan, GreaterThan) receive a correct message; change the error
text only (preserve validation logic) and run tests that exercise
PrepareTwoNumericArgs(), Minus, and comparison functions to confirm updated
message appears where appropriate.
In
`@test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/plus/adding-multiple-values.json`:
- Around line 2-4: Fix the test metadata: correct the "name" string typo from
"more then two" to "more than two", and update the expectsFailure expectation to
match the corrected production error from PrepareTwoNumericArgs() for the plus
operator by changing the value to "Invalid number of args for plus"; ensure the
expression remains ["plus", 0.1, 0.2, 15, 1.50] so the test asserts the
plus-specific error message.
🧹 Nitpick comments (3)
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs (3)
814-826: Error message is misleading for arithmetic callers.
PrepareTwoNumericArgsis now shared by comparison and arithmetic functions, but the error message still says"Invalid number of args for compare". This will confuse users when triggered fromplus,minus,multiply, ordivide.Proposed fix
- private static (decimal?, decimal?) PrepareTwoNumericArgs(ExpressionValue[] args) + private static (decimal?, decimal?) PrepareTwoNumericArgs(ExpressionValue[] args) { if (args.Length != 2) { - throw new ExpressionEvaluatorTypeErrorException("Invalid number of args for compare"); + throw new ExpressionEvaluatorTypeErrorException($"Expected 2 argument(s), got {args.Length}"); }
912-920: Guard partially overlaps withPrepareTwoNumericArgs.The
args.Length <= 1check provides a better error message for 0-1 args, butargs.Length > 2still falls through toPrepareTwoNumericArgswith its generic message. If the intent is exactly-two-args semantics (matching the commit message "changed functions to accept only two arguments"), the guard should check!= 2— or rely solely on the shared helper (especially after updating its error message).
869-869: Consider usingGeneratedRegexfor better performance.This
Regexis allocated once on a static field, but it's not compiled. Since this is on the expression evaluation hot path, using the .NET source generator ([GeneratedRegex]) would give compile-time optimized matching. This would require making the containing classpartial.
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs
Outdated
Show resolved
Hide resolved
...ayoutExpressions/CommonTests/shared-tests/functions/minus/subtracting-multiple-decimals.json
Outdated
Show resolved
Hide resolved
...ayoutExpressions/CommonTests/shared-tests/functions/minus/subtracting-multiple-decimals.json
Outdated
Show resolved
Hide resolved
....Tests/LayoutExpressions/CommonTests/shared-tests/functions/plus/adding-multiple-values.json
Outdated
Show resolved
Hide resolved
…d-object-support' into feature/expressions-with-list-and-object-support
TomasEng
left a comment
There was a problem hiding this comment.
Jeg har ikke så mye å utsette på C#-koden, men der har kanskje @ivarne mer å bidra med?
Ellers har jeg sett nærmere på de delte testene. Utenom det jeg har kommentert, savner jeg at de dekker litt flere formater for inndata. Jeg ser at de inkluderer både desimaltall og negative tall, og det er veldig bra. Men det mangler hele tall, eksponentformat og strengformat. Hvis jeg skulle skrevet disse testene, ville jeg startet med å sette opp en tabell med forskjellig inndata og forventet resultat. Eksempel for minus:
| Minuend | Subtrahend | Ventet resultat |
|---|---|---|
| 3 | 2 | 1 |
| 3.2 | 2 | 1.2 |
| -3 | 2 | -5 |
| 3E2 | 2 | 198 |
| 3E-2 | 2 | -1.97 |
| "3" | 2 | 1 |
| 0 | 2 | -2 |
| null | 2 | null |
| 3 | 2.2 | 0.8 |
| 3 | -2 | 5 |
| 3 | 2E2 | -197 |
| 3 | 2E-2 | 2.98 |
| 3 | "2" | 1 |
| 3 | 0 | 3 |
| 3 | null | null |
Ideen her er å variere én og én variabel og verifisere resultatet. Jeg liker denne måten å strukturere testdataen på fordi det gir god oversikt over hvilke caser som er dekket av testene. Testene for antall argumenter kommer da i tillegg til dette. Vi trenger ikke nødvendigvis gå så grundig til verks, i hvert fall ikke på de kommutative operasjonene, men se gjerne på testene på eksempelvis greaterThan for inspirasjon.
...ts/LayoutExpressions/CommonTests/shared-tests/functions/divide/divide-multiple-decimals.json
Outdated
Show resolved
Hide resolved
...ts/LayoutExpressions/CommonTests/shared-tests/functions/divide/divide-multiple-decimals.json
Outdated
Show resolved
Hide resolved
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs`:
- Around line 895-921: In Divide, ensure null-propagation matches
Plus/Minus/Multiply: call PrepareNumericArgs(args) (as currently done) then
immediately return null if either returned value is null (i.e., if a == null ||
b == null) before checking for zero; only after confirming b is non-null do the
b == 0 check and throw ExpressionEvaluatorTypeErrorException if zero, otherwise
perform and return a / b. This preserves lifted nullable behavior and prevents
throwing when a is null and b is 0.
In
`@test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/divide/error-bool-int.json`:
- Around line 2-3: The test's "name" and "expression" disagree: the "name" says
"[boolean, integer]" but the "expression" is ["divide", 100, true] (integer,
boolean); update the "name" field to "Should fail with [integer, boolean]" to
match the existing "expression", or alternatively swap the operands in
"expression" to ["divide", true, 100] if you intended boolean first—edit the
"name" or "expression" field accordingly so they describe the same operand
order.
🧹 Nitpick comments (2)
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs (1)
868-868: Consider usingGeneratedRegexsource generator for the static regex.The project targets .NET 8.0, which fully supports the
[GeneratedRegex]attribute. This would provide compile-time regex generation with equivalent performance to the current static readonly field. The class would need to be declaredpartialto support the generated method.Example
- private static readonly Regex _numberRegex = new(@"^-?\d+(\.\d+)?$"); + [GeneratedRegex(@"^-?\d+(\.\d+)?$")] + private static partial Regex NumberRegex();Update usage from
_numberRegex.IsMatch(s)toNumberRegex().IsMatch(s).Note: The containing class must be declared
partial.test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/TestFunctions.cs (1)
289-292:positionalArgumentsstill parses numbers asdoublewhile evaluation now usesdecimal.Line 291 uses
e.GetDouble()forJsonValueKind.Numberin positional arguments, but the evaluator has migrated todecimal. If any test ever supplies a numeric positional argument that gets compared against a decimal-based result, this type mismatch (doublevsdecimal) could cause a subtle assertion failure or incorrect coercion.Currently this only affects
argvtests (which likely don't hit decimal arithmetic paths), so the risk is low — but aligning this toGetDecimal()would keep things consistent.♻️ Suggested fix
JsonValueKind.String => e.GetString(), - JsonValueKind.Number => e.GetDouble(), + JsonValueKind.Number => e.GetDecimal(), JsonValueKind.True => true,
src/Altinn.App.Core/Internal/Expressions/ExpressionEvaluator.cs
Outdated
Show resolved
Hide resolved
...p.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/divide/error-bool-int.json
Outdated
Show resolved
Hide resolved
| ) | ||
| { | ||
| throw new ExpressionEvaluatorTypeErrorException( | ||
| $"Cannot convert non-finite or out-of-range number to decimal: {value}" |
There was a problem hiding this comment.
Jeg tror dette gjør at vi bør holde oss til double som backing data type for expressions, og heller gjøre denne konverteringen i de matematiske uttrykkene. Det som skjer nå er at man ikke kan bruke en double større enn decimal.MaxValue til noen ting.
There was a problem hiding this comment.
Godt poeng! Det kan antageligvis føre til problemer for folk vil jeg tro 👍
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/divide/same-types-with-remainder.json`:
- Around line 1-5: The expected result for the divide expression ["divide", 10,
3] is using C# decimal precision (3.3333333333333333333333333333) which will
break JS/TS (IEEE 754 double) comparisons; update the "expects" value in the
JSON to a double-compatible precision such as 3.3333333333333333, or if the test
harness supports it, add language-specific expected variants, ensuring the
"expression" (["divide", 10, 3]) remains unchanged.
🧹 Nitpick comments (2)
test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/minus/same-types-multiple-decimals.json (1)
1-5: Consider a more descriptive filename for this error test case.The filename
same-types-multiple-decimals.jsonsuggests it tests decimal subtraction with same types, but the actual intent is to verify that passing more than two arguments produces a failure. Sibling tests use clearer names likeerror-one-argument.json. A name such aserror-too-many-arguments.jsonorerror-multiple-arguments.jsonwould better communicate the test's purpose.test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/shared-tests/functions/divide/same-types-multiple-decimals.json (1)
1-5: Slightly misleading filename for an argument-count validation test.The filename
same-types-multiple-decimals.jsonsuggests it tests decimal arithmetic with matching types, but the actual test validates that more than two arguments are rejected. A name likeerror-too-many-arguments.jsonwould better convey intent — especially since there's already anerror-multiple-decimals.jsonin the same directory per the summary.
...s/LayoutExpressions/CommonTests/shared-tests/functions/divide/same-types-with-remainder.json
Outdated
Show resolved
Hide resolved
Godt forslag! 👍 Jeg har fått Claude til å generere noen flere .json filer. Også har jeg lagt til noen selv og justert litt på navngivning osv. Føler at jeg kan sitte og plukke på disse i en evighet, men det er kanskje ikke noe poeng å bruke så fryktelig mye tid på det hvis det er tilstrekkelig det som er der nå. Lyst til å hjelpe meg å se over @TomasEng? |
|
Supert, @olavsorl! Jeg skal ta en nærmere kikk, men sånn umiddelbart ser jeg at Coderabbit allerede har lagt inn noen gode kommentarer. I testen som tester Det er i grunn litt synd at hver testcase må være en egen fil, for det gjør jo terskelen for å legge til nye tester høyere enn den burde være. |
test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/TestFunctions.cs
Fixed
Show fixed
Hide fixed
…st files. Only convert to decimal when doing arithmetic operations.
| foreach (var file in files) | ||
| { | ||
| var data = File.ReadAllText(file); | ||
| var rootCases = JsonSerializer.Deserialize<ExpressionTestCaseRoot>(data, _jsonSerializerOptions)!; | ||
| if (rootCases.TestCases is not null) | ||
| { | ||
| theoryData.AddRange(rootCases.TestCases); | ||
| } | ||
| } |
Check notice
Code scanning / CodeQL
Missed opportunity to use Select Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, to fix this kind of issue you replace the foreach loop whose first action is to map the loop variable into another value with a LINQ query that performs that mapping explicitly via Select (and SelectMany if flattening collections). This makes it explicit that you are really iterating over a transformed sequence rather than the original one.
Here, files is a string array of file paths. For each file, we read its contents, deserialize to ExpressionTestCaseRoot, and, if TestCases is not null, add all of them to theoryData. We can express this as a LINQ pipeline:
- Start from
files. Selecteach file path into its deserializedExpressionTestCaseRoot.- From each root, select
TestCasesor an empty sequence if it is null. - Flatten all test cases across all files with
SelectMany, and materialize into aList<ExpressionTestCaseRoot.TestCaseItem>.
Concretely, in GetData, we can replace:
var theoryData = new List<ExpressionTestCaseRoot.TestCaseItem>();
foreach (var file in files)
{
var data = File.ReadAllText(file);
var rootCases = JsonSerializer.Deserialize<ExpressionTestCaseRoot>(data, _jsonSerializerOptions)!;
if (rootCases.TestCases is not null)
{
theoryData.AddRange(rootCases.TestCases);
}
}with a LINQ expression:
var theoryData = files
.Select(file =>
{
var data = File.ReadAllText(file);
return JsonSerializer.Deserialize<ExpressionTestCaseRoot>(data, _jsonSerializerOptions)!;
})
.Where(rootCases => rootCases.TestCases is not null)
.SelectMany(rootCases => rootCases.TestCases!)
.ToList();This keeps the logic the same: only non-null TestCases are included, and all items from all files are added. The rest of the method stays the same. No new imports are required because System.Linq is already available in most test projects and LINQ extension methods are from the BCL; if it is not yet imported in this file, we do not add it (per the instructions), but the project can add it separately.
| @@ -22,16 +22,15 @@ | ||
| throw new DirectoryNotFoundException($"Folder not found: {folder}"); | ||
| } | ||
| var files = Directory.GetFiles(folder); | ||
| var theoryData = new List<ExpressionTestCaseRoot.TestCaseItem>(); | ||
| foreach (var file in files) | ||
| { | ||
| var data = File.ReadAllText(file); | ||
| var rootCases = JsonSerializer.Deserialize<ExpressionTestCaseRoot>(data, _jsonSerializerOptions)!; | ||
| if (rootCases.TestCases is not null) | ||
| var theoryData = files | ||
| .Select(file => | ||
| { | ||
| theoryData.AddRange(rootCases.TestCases); | ||
| } | ||
| } | ||
| var data = File.ReadAllText(file); | ||
| return JsonSerializer.Deserialize<ExpressionTestCaseRoot>(data, _jsonSerializerOptions)!; | ||
| }) | ||
| .Where(rootCases => rootCases.TestCases is not null) | ||
| .SelectMany(rootCases => rootCases.TestCases!) | ||
| .ToList(); | ||
|
|
||
| return theoryData.Select(x => new object[] { x.Name ?? string.Empty, x }); | ||
| } |
…d-object-support' into feature/expressions-with-list-and-object-support
|



Description
Added +-*/ and changed parsing of JsonTokenType.Number to Decimal instead of Double.
Related Issue(s)
Verification
Documentation
Summary by CodeRabbit
New Features
Improvements