diff --git a/docs/BlockBodiedMethods.md b/docs/BlockBodiedMethods.md new file mode 100644 index 0000000..fe19c69 --- /dev/null +++ b/docs/BlockBodiedMethods.md @@ -0,0 +1,301 @@ +# Block-Bodied Methods Support + +As of this version, EntityFrameworkCore.Projectables now supports "classic" block-bodied methods decorated with `[Projectable]`, in addition to expression-bodied methods. + +## What's Supported + +Block-bodied methods can now be transformed into expression trees when they contain: + +### 1. Simple Return Statements +```csharp +[Projectable] +public int GetConstant() +{ + return 42; +} +``` + +### 2. If-Else Statements (converted to ternary expressions) +```csharp +[Projectable] +public string GetCategory() +{ + if (Value > 100) + { + return "High"; + } + else + { + return "Low"; + } +} +``` + +### 3. Nested If-Else Statements +```csharp +[Projectable] +public string GetLevel() +{ + if (Value > 100) + { + return "High"; + } + else if (Value > 50) + { + return "Medium"; + } + else + { + return "Low"; + } +} +``` + +### 4. Local Variable Declarations (inlined into the expression) +```csharp +[Projectable] +public int CalculateDouble() +{ + var doubled = Value * 2; + return doubled + 5; +} + +// Transitive inlining is also supported: +[Projectable] +public int CalculateComplex() +{ + var a = Value * 2; + var b = a + 5; + return b + 10; // Fully expanded to: Value * 2 + 5 + 10 +} +``` + +**⚠️ Important Notes:** +- Local variables are inlined at each usage point, which duplicates the initializer expression +- If a local variable is used multiple times, its initializer expression is duplicated at each usage, which can change semantics if the initializer has side effects +- Local variables can only be declared at the method body level, not inside nested blocks (if/switch/etc.) +- Variables are fully expanded transitively (variables that reference other variables are fully inlined) + +### 5. Switch Statements (converted to nested ternary expressions) +```csharp +[Projectable] +public string GetValueLabel() +{ + switch (Value) + { + case 1: + return "One"; + case 2: + return "Two"; + case 3: + return "Three"; + default: + return "Many"; + } +} +``` + +### 6. If Statements Without Else (uses default value) +```csharp +// Pattern 1: Explicit null return +[Projectable] +public int? GetPremiumIfActive() +{ + if (IsActive) + { + return Value * 2; + } + return null; // Explicit return for all code paths +} + +// Pattern 2: Explicit fallback return +[Projectable] +public string GetStatus() +{ + if (IsActive) + { + return "Active"; + } + return "Inactive"; // Explicit fallback +} +``` + +### 7. Multiple Early Returns (converted to nested ternary expressions) +```csharp +[Projectable] +public string GetValueCategory() +{ + if (Value > 100) + { + return "Very High"; + } + + if (Value > 50) + { + return "High"; + } + + if (Value > 10) + { + return "Medium"; + } + + return "Low"; +} + +// Converted to: Value > 100 ? "Very High" : (Value > 50 ? "High" : (Value > 10 ? "Medium" : "Low")) +``` + +## Limitations and Warnings + +The source generator will produce **warning EFP0003** when it encounters unsupported statements in block-bodied methods: + +### Unsupported Statements: +- While, for, foreach loops +- Try-catch-finally blocks +- Throw statements +- New object instantiation in statement position + +### Example of Unsupported Pattern: +```csharp +[Projectable] +public int GetValue() +{ + for (int i = 0; i < 10; i++) // ❌ Loops not supported + { + // ... + } + return 0; +} +``` + +Supported patterns: +```csharp +[Projectable] +public int GetValue() +{ + if (IsActive) // ✅ If without else is now supported! + { + return Value; + } + else + { + return 0; + } +} +``` + +Additional supported patterns: +```csharp +// If without else using fallback return: +[Projectable] +public int GetValue() +{ + if (IsActive) + { + return Value; + } + return 0; // ✅ Fallback return +} + +// Switch statement: +[Projectable] +public string GetLabel() +{ + switch (Value) // ✅ Switch statements now supported! + { + case 1: + return "One"; + case 2: + return "Two"; + default: + return "Other"; + } +} +``` + +Or as expression-bodied: +```csharp +[Projectable] +public int GetValue() => IsActive ? Value : 0; // ✅ Expression-bodied +``` + +## How It Works + +The source generator: +1. Parses block-bodied methods +2. Converts if-else statements to conditional (ternary) expressions +3. Converts switch statements to nested conditional expressions +4. Inlines local variables into the return expression +5. Rewrites the resulting expression using the existing expression transformation pipeline +6. Generates the same output as expression-bodied methods + +## Benefits + +- **More readable code**: Complex logic with nested conditions and switch statements is often easier to read than nested ternary operators +- **Gradual migration**: Existing code with block bodies can now be marked as `[Projectable]` without rewriting +- **Intermediate variables**: Local variables can make complex calculations more understandable +- **Switch support**: Traditional switch statements now work alongside switch expressions + +## SQL Output Examples + +### Switch Statement with Multiple Cases +Given this code: +```csharp +switch (Value) +{ + case 1: + case 2: + return "Low"; + case 3: + case 4: + case 5: + return "Medium"; + default: + return "High"; +} +``` + +Generates optimized SQL: +```sql +SELECT CASE + WHEN [e].[Value] IN (1, 2) THEN N'Low' + WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium' + ELSE N'High' +END +FROM [Entity] AS [e] +``` + +### If-Else Example Output + +Given this code: +```csharp +public record Entity +{ + public int Value { get; set; } + public bool IsActive { get; set; } + + [Projectable] + public int GetAdjustedValue() + { + if (IsActive && Value > 0) + { + return Value * 2; + } + else + { + return 0; + } + } +} +``` + +The generated SQL will be: +```sql +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 + THEN [e].[Value] * 2 + ELSE 0 +END +FROM [Entity] AS [e] +``` diff --git a/docs/PatternMatchingSupport.md b/docs/PatternMatchingSupport.md new file mode 100644 index 0000000..e81be3c --- /dev/null +++ b/docs/PatternMatchingSupport.md @@ -0,0 +1,195 @@ +# Pattern Matching Support in Block-Bodied Methods + +This document describes how pattern matching is handled in block-bodied projectable methods. + +## Overview + +C# pattern matching (the `is` operator with patterns) is not supported in expression trees and will cause a CS8122 compilation error. The source generator automatically converts pattern matching syntax into equivalent boolean expressions that work in expression trees. + +## Supported Pattern Types + +### 1. Recursive Patterns (Property Patterns) + +**Syntax:** +```csharp +[Projectable] +public static string GetCategory(this Entity entity) +{ + if (entity is { IsActive: true, Value: > 100 }) + { + return "Active High"; + } + return "Other"; +} +``` + +**Converted To:** +```csharp +entity != null && entity.IsActive == true && entity.Value > 100 ? "Active High" : "Other" +``` + +The pattern is converted to: +1. Null check: `entity != null` +2. Property checks: `entity.IsActive == true && entity.Value > 100` +3. Combined with logical AND + +### 2. Relational Patterns + +**Syntax:** +```csharp +[Projectable] +public static string GetCategory(this Entity entity) +{ + if (entity.Value is > 100) + { + return "High"; + } + return "Low"; +} +``` + +**Converted To:** +```csharp +entity.Value > 100 ? "High" : "Low" +``` + +Supported relational operators: +- `>` (greater than) +- `>=` (greater than or equal) +- `<` (less than) +- `<=` (less than or equal) + +### 3. Constant Patterns + +**Syntax:** +```csharp +[Projectable] +public static bool IsNull(this Entity entity) +{ + if (entity is null) + { + return true; + } + return false; +} +``` + +**Converted To:** +```csharp +entity == null ? true : false +``` + +### 4. Unary Patterns (Not Patterns) + +**Syntax:** +```csharp +[Projectable] +public static bool IsNotNull(this Entity entity) +{ + if (entity is not null) + { + return true; + } + return false; +} +``` + +**Converted To:** +```csharp +!(entity == null) ? true : false +``` + +### 5. Binary Patterns (And/Or) + +**Syntax:** +```csharp +[Projectable] +public static bool IsInRange(this Entity entity) +{ + if (entity.Value is > 10 and < 100) + { + return true; + } + return false; +} +``` + +**Converted To:** +```csharp +entity.Value > 10 && entity.Value < 100 ? true : false +``` + +## Benefits + +1. **Modern C# Syntax**: Use pattern matching in block-bodied methods just like regular C# code +2. **Automatic Conversion**: No manual rewriting needed - the generator handles it +3. **Expression Tree Compatibility**: Generated code compiles without CS8122 errors +4. **Semantic Equivalence**: Converted expressions maintain the same behavior as patterns + +## Limitations + +Not all pattern types are currently supported: +- Type patterns with variable declarations may have limited support +- List patterns are not yet supported +- Some complex nested patterns may not be supported + +If you encounter an unsupported pattern, you'll receive an error message indicating which pattern type is not supported. + +## Examples + +### Complex Property Pattern +```csharp +[Projectable] +public static string GetStatus(this Order order) +{ + if (order is { Status: "Completed", Amount: > 1000, Customer.IsVip: true }) + { + return "VIP High Value Completed"; + } + return "Other"; +} +``` + +**Generates:** +```csharp +order != null && +order.Status == "Completed" && +order.Amount > 1000 && +order.Customer.IsVip == true + ? "VIP High Value Completed" + : "Other" +``` + +### Range Check with Relational Patterns +```csharp +[Projectable] +public static string GetRange(this Entity entity) +{ + if (entity.Value is >= 0 and < 50) + { + return "Low"; + } + else if (entity.Value is >= 50 and < 100) + { + return "Medium"; + } + return "High"; +} +``` + +**Generates:** +```csharp +entity.Value >= 0 && entity.Value < 50 ? "Low" : +entity.Value >= 50 && entity.Value < 100 ? "Medium" : +"High" +``` + +## Technical Details + +The conversion is implemented in `ExpressionSyntaxRewriter.VisitIsPatternExpression` which: +1. Visits the expression being tested +2. Converts the pattern to an equivalent expression using `ConvertPatternToExpression` +3. Handles nested patterns recursively +4. Combines multiple property checks with logical AND operators + +This ensures that all pattern matching is transformed into expression tree-compatible code before code generation. diff --git a/docs/SideEffectDetection.md b/docs/SideEffectDetection.md new file mode 100644 index 0000000..891294e --- /dev/null +++ b/docs/SideEffectDetection.md @@ -0,0 +1,110 @@ +# Side Effect Detection in Block-Bodied Methods + +This document describes the improved error reporting for side effects in block-bodied projectable methods. + +## Overview + +When using block-bodied methods with the `[Projectable]` attribute, the source generator now provides specific error messages that point to the exact line where side effects occur, making it much easier to identify and fix issues. + +## Detected Side Effects + +### 1. Property Assignments (EFP0004 - Error) + +**Code:** +```csharp +[Projectable] +public int Foo() +{ + Bar = 10; // ❌ Error on this line + return Bar; +} +``` + +**Error Message:** +``` +(11,13): error EFP0004: Assignment operation has side effects and cannot be used in projectable methods +``` + +### 2. Compound Assignments (EFP0004 - Error) + +**Code:** +```csharp +[Projectable] +public int Foo() +{ + Bar += 10; // ❌ Error on this line + return Bar; +} +``` + +**Error Message:** +``` +(11,13): error EFP0004: Compound assignment operator '+=' has side effects and cannot be used in projectable methods +``` + +### 3. Increment/Decrement Operators (EFP0004 - Error) + +**Code:** +```csharp +[Projectable] +public int Foo() +{ + var x = 5; + x++; // ❌ Error on this line + return x; +} +``` + +**Error Message:** +``` +(12,13): error EFP0004: Increment/decrement operator '++' has side effects and cannot be used in projectable methods +``` + +### 4. Non-Projectable Method Calls (EFP0005 - Warning) + +**Code:** +```csharp +[Projectable] +public int Foo() +{ + Console.WriteLine("test"); // ⚠️ Warning on this line + return Bar; +} +``` + +**Warning Message:** +``` +(11,13): warning EFP0005: Method call 'WriteLine' may have side effects. Only calls to methods marked with [Projectable] are guaranteed to be safe in projectable methods +``` + +## Before vs After + +### Before +Generic error message at the beginning of the method: +``` +warning EFP0003: Method 'Foo' contains an unsupported statement: Expression statements are not supported +``` + +### After +Specific error message pointing to the exact problematic line: +``` +error EFP0004: Property assignment 'Bar' has side effects and cannot be used in projectable methods +``` + +## Benefits + +1. **Precise Location**: Error messages now point to the exact line containing the side effect +2. **Specific Messages**: Clear explanation of what kind of side effect was detected +3. **Better Developer Experience**: Easier to identify and fix issues +4. **Severity Levels**: Errors for definite side effects, warnings for potential ones +5. **Actionable Guidance**: Messages explain why the code is problematic + +## Diagnostic Codes + +- **EFP0004**: Statement with side effects in block-bodied method (Error) +- **EFP0005**: Potential side effect in block-bodied method (Warning) + +These are in addition to the existing: +- **EFP0001**: Method or property should expose an expression body definition (Error) +- **EFP0002**: Method or property is not configured to support null-conditional expressions (Error) +- **EFP0003**: Unsupported statement in block-bodied method (Warning) diff --git a/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md b/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md index ef168b8..c1b0078 100644 --- a/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md +++ b/src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md @@ -3,3 +3,6 @@ Rule ID | Category | Severity | Notes --------|----------|----------|-------------------- EFP0002 | Design | Error | +EFP0003 | Design | Warning | +EFP0004 | Design | Error | Statement with side effects in block-bodied method +EFP0005 | Design | Warning | Potential side effect in block-bodied method diff --git a/src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs b/src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs new file mode 100644 index 0000000..55abd92 --- /dev/null +++ b/src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs @@ -0,0 +1,539 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace EntityFrameworkCore.Projectables.Generator +{ + /// + /// Converts block-bodied methods to expression syntax that can be used in expression trees. + /// Only supports a subset of C# statements. + /// + public class BlockStatementConverter + { + private readonly SourceProductionContext _context; + private readonly ExpressionSyntaxRewriter _expressionRewriter; + private readonly Dictionary _localVariables = new(); + + public BlockStatementConverter(SourceProductionContext context, ExpressionSyntaxRewriter expressionRewriter) + { + _context = context; + _expressionRewriter = expressionRewriter; + } + + /// + /// Attempts to convert a block statement into a single expression. + /// Returns null if the block contains unsupported statements. + /// + public ExpressionSyntax? TryConvertBlock(BlockSyntax block, string memberName) + { + if (block.Statements.Count == 0) + { + var diagnostic = Diagnostic.Create( + Diagnostics.UnsupportedStatementInBlockBody, + block.GetLocation(), + memberName, + "Block body must contain at least one statement" + ); + _context.ReportDiagnostic(diagnostic); + return null; + } + + // Try to convert the block statements into an expression + return TryConvertStatements(block.Statements.ToList(), memberName); + } + + private ExpressionSyntax? TryConvertStatements(List statements, string memberName) + { + if (statements.Count == 0) + { + return null; + } + + if (statements.Count == 1) + { + return TryConvertStatement(statements[0], memberName); + } + + // Multiple statements - try to convert them into a chain of expressions + // This is done by converting local variable declarations and then the final return + var nonReturnStatements = statements.Take(statements.Count - 1).ToList(); + var lastStatement = statements.Last(); + + // First, process any local variable declarations at the beginning + var localDeclStatements = new List(); + var remainingStatements = new List(); + + foreach (var stmt in nonReturnStatements) + { + if (stmt is LocalDeclarationStatementSyntax localDecl) + { + localDeclStatements.Add(localDecl); + } + else + { + remainingStatements.Add(stmt); + } + } + + // Process local variable declarations first + foreach (var localDecl in localDeclStatements) + { + if (!TryProcessLocalDeclaration(localDecl, memberName)) + { + return null; + } + } + + // Check if we have a pattern like multiple if statements without else followed by a final return: + // var x = ...; if (a) return 1; if (b) return 2; return 3; + // This can be converted to nested ternaries: a ? 1 : (b ? 2 : 3) + if (lastStatement is ReturnStatementSyntax finalReturn && + remainingStatements.All(s => s is IfStatementSyntax { Else: null })) + { + // All remaining non-return statements are if statements without else + var ifStatements = remainingStatements.Cast().ToList(); + + // Start with the final return as the base expression + var elseBody = TryConvertReturnStatement(finalReturn, memberName); + if (elseBody == null) + { + return null; + } + + // Build nested conditionals from right to left (last to first) + for (var i = ifStatements.Count - 1; i >= 0; i--) + { + var ifStmt = ifStatements[i]; + var ifBody = TryConvertStatement(ifStmt.Statement, memberName); + if (ifBody == null) + { + return null; + } + + // Rewrite the condition and replace any local variables + var condition = (ExpressionSyntax)_expressionRewriter.Visit(ifStmt.Condition); + condition = ReplaceLocalVariables(condition); + + elseBody = SyntaxFactory.ConditionalExpression(condition, ifBody, elseBody); + } + + return elseBody; + } + + // If there are any remaining non-if statements, try to convert them individually + // This will provide better error messages for unsupported statements + if (remainingStatements.Count > 0) + { + // Try converting each remaining statement - this will provide specific error messages + foreach (var stmt in remainingStatements) + { + var converted = TryConvertStatement(stmt, memberName); + if (converted == null) + { + return null; + } + } + + // If we got here but had non-if statements, they weren't properly handled + ReportUnsupportedStatement(remainingStatements[0], memberName, + "Only local variable declarations and if statements without else (with return) are supported before the final return statement"); + return null; + } + + // Convert the final statement (should be a return) + return TryConvertStatement(lastStatement, memberName); + } + + private bool TryProcessLocalDeclaration(LocalDeclarationStatementSyntax localDecl, string memberName) + { + foreach (var variable in localDecl.Declaration.Variables) + { + if (variable.Initializer == null) + { + ReportUnsupportedStatement(localDecl, memberName, "Local variables must have an initializer"); + return false; + } + + var variableName = variable.Identifier.Text; + + // Rewrite the initializer expression NOW while it's still in the tree + var rewrittenInitializer = (ExpressionSyntax)_expressionRewriter.Visit(variable.Initializer.Value); + + // Also expand any previously defined local variables in this initializer + // This ensures transitive inlining (e.g., var a = 1; var b = a + 2; return b; -> 1 + 2) + rewrittenInitializer = ReplaceLocalVariables(rewrittenInitializer); + + _localVariables[variableName] = rewrittenInitializer; + } + + return true; + } + + private ExpressionSyntax? TryConvertStatement(StatementSyntax statement, string memberName) + { + switch (statement) + { + case ReturnStatementSyntax returnStmt: + return TryConvertReturnStatement(returnStmt, memberName); + + case IfStatementSyntax ifStmt: + return TryConvertIfStatement(ifStmt, memberName); + + case SwitchStatementSyntax switchStmt: + return TryConvertSwitchStatement(switchStmt, memberName); + + case BlockSyntax blockStmt: + // Prevent locals declared in nested blocks from leaking into outer scopes + var nestedLocal = blockStmt.DescendantNodes() + .OfType() + .FirstOrDefault(); + + if (nestedLocal is not null) + { + ReportUnsupportedStatement(nestedLocal, memberName, "Local declarations in nested blocks are not supported"); + return null; + } + + return TryConvertStatements(blockStmt.Statements.ToList(), memberName); + + case ExpressionStatementSyntax exprStmt: + // Expression statements may contain side effects - analyze them + return AnalyzeExpressionStatement(exprStmt, memberName); + + case LocalDeclarationStatementSyntax: + // Local declarations should be handled before the return statement + ReportUnsupportedStatement(statement, memberName, "Local declarations must appear before the return statement"); + return null; + + default: + ReportUnsupportedStatement(statement, memberName, $"Statement type '{statement.GetType().Name}' is not supported"); + return null; + } + } + + private ExpressionSyntax? TryConvertReturnStatement(ReturnStatementSyntax returnStmt, string memberName) + { + if (returnStmt.Expression == null) + { + ReportUnsupportedStatement(returnStmt, memberName, "Return statement must have an expression"); + return null; + } + + // First rewrite the return expression + var expression = (ExpressionSyntax)_expressionRewriter.Visit(returnStmt.Expression); + + // Then replace any local variable references with their already-rewritten initializers + expression = ReplaceLocalVariables(expression); + + return expression; + } + + private ConditionalExpressionSyntax? TryConvertIfStatement(IfStatementSyntax ifStmt, string memberName) + { + // Convert if-else to conditional (ternary) expression + // First, rewrite the condition using the expression rewriter + var condition = (ExpressionSyntax)_expressionRewriter.Visit(ifStmt.Condition); + + // Then replace any local variable references with their already-rewritten initializers + condition = ReplaceLocalVariables(condition); + + var whenTrue = TryConvertStatement(ifStmt.Statement, memberName); + if (whenTrue == null) + { + return null; + } + + ExpressionSyntax? whenFalse; + if (ifStmt.Else != null) + { + whenFalse = TryConvertStatement(ifStmt.Else.Statement, memberName); + if (whenFalse == null) + { + return null; + } + } + else + { + // If there's no else clause, use a default literal + // This will be inferred to the correct type by the compiler + whenFalse = SyntaxFactory.LiteralExpression( + SyntaxKind.DefaultLiteralExpression, + SyntaxFactory.Token(SyntaxKind.DefaultKeyword) + ); + } + + // Create a conditional expression with the rewritten nodes + return SyntaxFactory.ConditionalExpression( + condition, + whenTrue, + whenFalse + ); + } + + private ExpressionSyntax? TryConvertSwitchStatement(SwitchStatementSyntax switchStmt, string memberName) + { + // Convert switch statement to nested conditional expressions + // Process sections in reverse order to build from the default case up + + var switchExpression = (ExpressionSyntax)_expressionRewriter.Visit(switchStmt.Expression); + // Replace any local variable references in the switch expression + switchExpression = ReplaceLocalVariables(switchExpression); + + ExpressionSyntax? currentExpression; + + // Find default case first + SwitchSectionSyntax? defaultSection = null; + var nonDefaultSections = new List(); + + foreach (var section in switchStmt.Sections) + { + var hasDefault = section.Labels.Any(label => label is DefaultSwitchLabelSyntax); + if (hasDefault) + { + defaultSection = section; + } + else + { + nonDefaultSections.Add(section); + } + } + + // Start with default case or null + if (defaultSection != null) + { + currentExpression = ConvertSwitchSection(defaultSection, memberName); + if (currentExpression == null) + { + return null; + } + } + else + { + // No default case - use default literal + currentExpression = SyntaxFactory.LiteralExpression( + SyntaxKind.DefaultLiteralExpression, + SyntaxFactory.Token(SyntaxKind.DefaultKeyword) + ); + } + + // Process non-default sections in reverse order + for (var i = nonDefaultSections.Count - 1; i >= 0; i--) + { + var section = nonDefaultSections[i]; + var sectionExpression = ConvertSwitchSection(section, memberName); + if (sectionExpression == null) + { + return null; + } + + // Build condition for all labels in this section (OR'd together) + ExpressionSyntax? condition = null; + foreach (var label in section.Labels) + { + if (label is CaseSwitchLabelSyntax caseLabel) + { + // Rewrite and replace locals in case label value + var caseLabelValue = (ExpressionSyntax)_expressionRewriter.Visit(caseLabel.Value); + caseLabelValue = ReplaceLocalVariables(caseLabelValue); + + var labelCondition = SyntaxFactory.BinaryExpression( + SyntaxKind.EqualsExpression, + switchExpression, + caseLabelValue + ); + + condition = condition == null + ? labelCondition + : SyntaxFactory.BinaryExpression( + SyntaxKind.LogicalOrExpression, + condition, + labelCondition + ); + } + else if (label is not DefaultSwitchLabelSyntax) + { + // Unsupported label type (e.g., pattern-based switch in older syntax) + ReportUnsupportedStatement(switchStmt, memberName, + $"Switch label type '{label.GetType().Name}' is not supported. Use case labels or switch expressions instead."); + return null; + } + } + + if (condition != null) + { + currentExpression = SyntaxFactory.ConditionalExpression( + condition, + sectionExpression, + currentExpression + ); + } + } + + return currentExpression; + } + + private ExpressionSyntax? ConvertSwitchSection(SwitchSectionSyntax section, string memberName) + { + // Convert the statements in the switch section + // Most switch sections end with break, return, or throw + var statements = section.Statements.ToList(); + + // Remove trailing break statements as they're not needed in expressions + if (statements.Count > 0 && statements.Last() is BreakStatementSyntax) + { + statements = statements.Take(statements.Count - 1).ToList(); + } + + if (statements.Count != 0) + { + return TryConvertStatements(statements, memberName); + } + + // Use the section's first label location for error reporting + var firstLabel = section.Labels.FirstOrDefault(); + if (firstLabel == null) + { + return null; + } + + var diagnostic = Diagnostic.Create( + Diagnostics.UnsupportedStatementInBlockBody, + firstLabel.GetLocation(), + memberName, + "Switch section must have at least one statement" + ); + _context.ReportDiagnostic(diagnostic); + return null; + + } + + private ExpressionSyntax ReplaceLocalVariables(ExpressionSyntax expression) + { + // Use a rewriter to replace local variable references with their initializer expressions + var rewriter = new LocalVariableReplacer(_localVariables); + return (ExpressionSyntax)rewriter.Visit(expression); + } + + private ExpressionSyntax? AnalyzeExpressionStatement(ExpressionStatementSyntax exprStmt, string memberName) + { + var expression = exprStmt.Expression; + + // Check for specific side effects + switch (expression) + { + case AssignmentExpressionSyntax assignment: + ReportSideEffect(assignment, GetAssignmentErrorMessage(assignment)); + return null; + + case PostfixUnaryExpressionSyntax postfix when + postfix.IsKind(SyntaxKind.PostIncrementExpression) || + postfix.IsKind(SyntaxKind.PostDecrementExpression): + ReportSideEffect(postfix, $"Increment/decrement operator '{postfix.OperatorToken.Text}' has side effects and cannot be used in projectable methods"); + return null; + + case PrefixUnaryExpressionSyntax prefix when + prefix.IsKind(SyntaxKind.PreIncrementExpression) || + prefix.IsKind(SyntaxKind.PreDecrementExpression): + ReportSideEffect(prefix, $"Increment/decrement operator '{prefix.OperatorToken.Text}' has side effects and cannot be used in projectable methods"); + return null; + + case InvocationExpressionSyntax invocation: + // Check if this is a potentially impure method call + var symbolInfo = _expressionRewriter.GetSemanticModel().GetSymbolInfo(invocation); + if (symbolInfo.Symbol is IMethodSymbol methodSymbol) + { + // Check if method has [Projectable] attribute - those are safe + var hasProjectableAttr = methodSymbol.GetAttributes() + .Any(attr => attr.AttributeClass?.Name == "ProjectableAttribute"); + + if (!hasProjectableAttr) + { + ReportPotentialSideEffect(invocation, + $"Method call '{methodSymbol.Name}' may have side effects. Only calls to methods marked with [Projectable] are guaranteed to be safe in projectable methods"); + return null; + } + } + break; + } + + // If we got here, it's an expression statement we don't support + ReportUnsupportedStatement(exprStmt, memberName, "Expression statements are not supported in projectable methods"); + return null; + } + + private string GetAssignmentErrorMessage(AssignmentExpressionSyntax assignment) + { + var operatorText = assignment.OperatorToken.Text; + + if (assignment.IsKind(SyntaxKind.SimpleAssignmentExpression)) + { + if (assignment.Left is MemberAccessExpressionSyntax memberAccess) + { + return $"Property assignment '{memberAccess.Name}' has side effects and cannot be used in projectable methods"; + } + return $"Assignment operation has side effects and cannot be used in projectable methods"; + } + else + { + // Compound assignment like +=, -=, etc. + return $"Compound assignment operator '{operatorText}' has side effects and cannot be used in projectable methods"; + } + } + + private void ReportSideEffect(SyntaxNode node, string message) + { + var diagnostic = Diagnostic.Create( + Diagnostics.SideEffectInBlockBody, + node.GetLocation(), + message + ); + _context.ReportDiagnostic(diagnostic); + } + + private void ReportPotentialSideEffect(SyntaxNode node, string message) + { + var diagnostic = Diagnostic.Create( + Diagnostics.PotentialSideEffectInBlockBody, + node.GetLocation(), + message + ); + _context.ReportDiagnostic(diagnostic); + } + + private void ReportUnsupportedStatement(StatementSyntax statement, string memberName, string reason) + { + var diagnostic = Diagnostic.Create( + Diagnostics.UnsupportedStatementInBlockBody, + statement.GetLocation(), + memberName, + reason + ); + _context.ReportDiagnostic(diagnostic); + } + + + private class LocalVariableReplacer : CSharpSyntaxRewriter + { + private readonly Dictionary _localVariables; + + public LocalVariableReplacer(Dictionary localVariables) + { + _localVariables = localVariables; + } + + public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node) + { + var identifier = node.Identifier.Text; + if (_localVariables.TryGetValue(identifier, out var replacement)) + { + // Replace the identifier with the expression it was initialized with + return replacement.WithTriviaFrom(node); + } + + return base.VisitIdentifierName(node); + } + } + } +} diff --git a/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs b/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs index 18f87c1..6bcfaf1 100644 --- a/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs +++ b/src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs @@ -25,5 +25,29 @@ public static class Diagnostics DiagnosticSeverity.Error, isEnabledByDefault: true); + public static readonly DiagnosticDescriptor UnsupportedStatementInBlockBody = new DiagnosticDescriptor( + id: "EFP0003", + title: "Unsupported statement in block-bodied method", + messageFormat: "Method '{0}' contains an unsupported statement: {1}", + category: "Design", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor SideEffectInBlockBody = new DiagnosticDescriptor( + id: "EFP0004", + title: "Statement with side effects in block-bodied method", + messageFormat: "{0}", + category: "Design", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor PotentialSideEffectInBlockBody = new DiagnosticDescriptor( + id: "EFP0005", + title: "Potential side effect in block-bodied method", + messageFormat: "{0}", + category: "Design", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + } } diff --git a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs index f51c8f6..a73ca06 100644 --- a/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs +++ b/src/EntityFrameworkCore.Projectables.Generator/ExpressionSyntaxRewriter.cs @@ -1,4 +1,7 @@ -using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; @@ -26,6 +29,8 @@ public ExpressionSyntaxRewriter(INamedTypeSymbol targetTypeSymbol, NullCondition _extensionParameterName = extensionParameterName; } + public SemanticModel GetSemanticModel() => _semanticModel; + private SyntaxNode? VisitThisBaseExpression(CSharpSyntaxNode node) { // Swap out the use of this and base to @this and keep leading and trailing trivias @@ -386,8 +391,47 @@ private ExpressionSyntax CreateMethodCallOnEnumValue(IMethodSymbol methodSymbol, continue; } + // Handle relational patterns (<=, <, >=, >) + if (arm.Pattern is RelationalPatternSyntax relational) + { + // Map the pattern operator token to a binary expression kind + var binaryKind = relational.OperatorToken.Kind() switch + { + SyntaxKind.LessThanToken => SyntaxKind.LessThanExpression, + SyntaxKind.LessThanEqualsToken => SyntaxKind.LessThanOrEqualExpression, + SyntaxKind.GreaterThanToken => SyntaxKind.GreaterThanExpression, + SyntaxKind.GreaterThanEqualsToken => SyntaxKind.GreaterThanOrEqualExpression, + _ => throw new InvalidOperationException( + $"Unsupported relational operator in switch expression: {relational.OperatorToken.Kind()}") + }; + + var condition = SyntaxFactory.BinaryExpression( + binaryKind, + (ExpressionSyntax)Visit(node.GoverningExpression), + (ExpressionSyntax)Visit(relational.Expression) + ); + + // Add the when clause as a AND expression + if (arm.WhenClause != null) + { + condition = SyntaxFactory.BinaryExpression( + SyntaxKind.LogicalAndExpression, + condition, + (ExpressionSyntax)Visit(arm.WhenClause.Condition) + ); + } + + currentExpression = SyntaxFactory.ConditionalExpression( + condition, + armExpression, + currentExpression + ); + + continue; + } + throw new InvalidOperationException( - $"Switch expressions rewriting supports only constant values and declaration patterns (Type var). " + + $"Switch expressions rewriting supports constant values, relational patterns (<=, <, >=, >), and declaration patterns (Type var). " + $"Unsupported pattern: {arm.Pattern.GetType().Name}" ); } @@ -635,5 +679,130 @@ private ExpressionSyntax ReplaceVariableWithCast(ExpressionSyntax expression, De return expression; } + + public override SyntaxNode? VisitIsPatternExpression(IsPatternExpressionSyntax node) + { + // Pattern matching is not supported in expression trees (CS8122) + // We need to convert patterns into equivalent expressions + + var expression = (ExpressionSyntax)Visit(node.Expression); + var convertedPattern = ConvertPatternToExpression(node.Pattern, expression); + + return convertedPattern; + } + + private ExpressionSyntax ConvertPatternToExpression(PatternSyntax pattern, ExpressionSyntax expression) + { + switch (pattern) + { + case RecursivePatternSyntax recursivePattern: + return ConvertRecursivePattern(recursivePattern, expression); + + case ConstantPatternSyntax constantPattern: + // e is null or e is 5 + return SyntaxFactory.BinaryExpression( + SyntaxKind.EqualsExpression, + expression, + (ExpressionSyntax)Visit(constantPattern.Expression) + ); + + case DeclarationPatternSyntax declarationPattern: + // e is string s -> e is string (type check) + return SyntaxFactory.BinaryExpression( + SyntaxKind.IsExpression, + expression, + declarationPattern.Type + ); + + case RelationalPatternSyntax relationalPattern: + // e is > 100 + var binaryKind = relationalPattern.OperatorToken.Kind() switch + { + SyntaxKind.LessThanToken => SyntaxKind.LessThanExpression, + SyntaxKind.LessThanEqualsToken => SyntaxKind.LessThanOrEqualExpression, + SyntaxKind.GreaterThanToken => SyntaxKind.GreaterThanExpression, + SyntaxKind.GreaterThanEqualsToken => SyntaxKind.GreaterThanOrEqualExpression, + _ => throw new NotSupportedException($"Relational operator {relationalPattern.OperatorToken} not supported") + }; + + return SyntaxFactory.BinaryExpression( + binaryKind, + expression, + (ExpressionSyntax)Visit(relationalPattern.Expression) + ); + + case BinaryPatternSyntax binaryPattern: + // e is > 10 and < 100 + var left = ConvertPatternToExpression(binaryPattern.Left, expression); + var right = ConvertPatternToExpression(binaryPattern.Right, expression); + + var logicalKind = binaryPattern.OperatorToken.Kind() switch + { + SyntaxKind.AndKeyword => SyntaxKind.LogicalAndExpression, + SyntaxKind.OrKeyword => SyntaxKind.LogicalOrExpression, + _ => throw new NotSupportedException($"Binary pattern operator {binaryPattern.OperatorToken} not supported") + }; + + return SyntaxFactory.BinaryExpression(logicalKind, left, right); + + case UnaryPatternSyntax unaryPattern when unaryPattern.OperatorToken.IsKind(SyntaxKind.NotKeyword): + // e is not null + var innerPattern = ConvertPatternToExpression(unaryPattern.Pattern, expression); + return SyntaxFactory.PrefixUnaryExpression( + SyntaxKind.LogicalNotExpression, + SyntaxFactory.ParenthesizedExpression(innerPattern) + ); + + default: + throw new NotSupportedException($"Pattern type {pattern.GetType().Name} is not yet supported in projectable methods"); + } + } + + private ExpressionSyntax ConvertRecursivePattern(RecursivePatternSyntax recursivePattern, ExpressionSyntax expression) + { + // entity is { IsActive: true, Value: > 100 } + // Convert to: entity != null && entity.IsActive == true && entity.Value > 100 + + var conditions = new List(); + + // Add null check first (unless pattern explicitly includes null) + var nullCheck = SyntaxFactory.BinaryExpression( + SyntaxKind.NotEqualsExpression, + expression, + SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression) + ); + conditions.Add(nullCheck); + + // Handle property patterns + if (recursivePattern.PropertyPatternClause != null) + { + foreach (var subpattern in recursivePattern.PropertyPatternClause.Subpatterns) + { + var memberAccess = subpattern.NameColon != null + ? SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + expression, + SyntaxFactory.IdentifierName(subpattern.NameColon.Name.Identifier) + ) + : expression; + + var condition = ConvertPatternToExpression(subpattern.Pattern, memberAccess); + conditions.Add(condition); + } + } + + // Combine all conditions with && + var result = conditions[0]; + for (int i = 1; i < conditions.Count; i++) + { + result = SyntaxFactory.BinaryExpression( + SyntaxKind.LogicalAndExpression, + result, + conditions[i] + ); + } + + return result; + } } } diff --git a/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs b/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs index 8a84310..5006081 100644 --- a/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs +++ b/src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs @@ -120,7 +120,7 @@ x is IPropertySymbol xProperty && return false; } else if (x is MethodDeclarationSyntax xMethod && - xMethod.ExpressionBody is not null) + (xMethod.ExpressionBody is not null || xMethod.Body is not null)) { return true; } @@ -302,7 +302,28 @@ x is IPropertySymbol xProperty && if (memberBody is MethodDeclarationSyntax methodDeclarationSyntax) { - if (methodDeclarationSyntax.ExpressionBody is null) + ExpressionSyntax? bodyExpression = null; + + if (methodDeclarationSyntax.ExpressionBody is not null) + { + // Expression-bodied method (e.g., int Foo() => 1;) + bodyExpression = methodDeclarationSyntax.ExpressionBody.Expression; + } + else if (methodDeclarationSyntax.Body is not null) + { + // Block-bodied method (e.g., int Foo() { return 1; }) + var blockConverter = new BlockStatementConverter(context, expressionSyntaxRewriter); + bodyExpression = blockConverter.TryConvertBlock(methodDeclarationSyntax.Body, memberSymbol.Name); + + if (bodyExpression is null) + { + // Diagnostics already reported by BlockStatementConverter + return null; + } + + // The expression has already been rewritten by BlockStatementConverter, so we don't rewrite it again + } + else { var diagnostic = Diagnostic.Create(Diagnostics.RequiresExpressionBodyDefinition, methodDeclarationSyntax.GetLocation(), memberSymbol.Name); context.ReportDiagnostic(diagnostic); @@ -312,7 +333,10 @@ x is IPropertySymbol xProperty && var returnType = declarationSyntaxRewriter.Visit(methodDeclarationSyntax.ReturnType); descriptor.ReturnTypeName = returnType.ToString(); - descriptor.ExpressionBody = (ExpressionSyntax)expressionSyntaxRewriter.Visit(methodDeclarationSyntax.ExpressionBody.Expression); + // Only rewrite expression-bodied methods, block-bodied methods are already rewritten + descriptor.ExpressionBody = methodDeclarationSyntax.ExpressionBody is not null + ? (ExpressionSyntax)expressionSyntaxRewriter.Visit(bodyExpression) + : bodyExpression; foreach (var additionalParameter in ((ParameterListSyntax)declarationSyntaxRewriter.Visit(methodDeclarationSyntax.ParameterList)).Parameters) { descriptor.ParametersList = descriptor.ParametersList.AddParameters(additionalParameter); diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..3eaf767 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT (CAST([e].[Value] AS float) / 100.0E0) * 50.0E0 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..3eaf767 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT (CAST([e].[Value] AS float) / 100.0E0) * 50.0E0 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.verified.txt new file mode 100644 index 0000000..3eaf767 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ArithmeticInReturn_WorksCorrectly.verified.txt @@ -0,0 +1,2 @@ +SELECT (CAST([e].[Value] AS float) / 100.0E0) * 50.0E0 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..dab6bd4 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT 15 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..dab6bd4 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT 15 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.verified.txt new file mode 100644 index 0000000..dab6bd4 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BlockMethodWithParameters_WorksCorrectly.verified.txt @@ -0,0 +1,2 @@ +SELECT 15 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..e5b6efb --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..e5b6efb --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.verified.txt new file mode 100644 index 0000000..e5b6efb --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.BooleanReturn_WorksCorrectly.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..a19f725 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 THEN [e].[Value] * 2 + ELSE 0 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..a19f725 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 THEN [e].[Value] * 2 + ELSE 0 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.verified.txt new file mode 100644 index 0000000..a19f725 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ComplexConditional_IsTranslatedCorrectly.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 0 THEN [e].[Value] * 2 + ELSE 0 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..ba1f2c1 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT CAST(LEN([e].[Name]) AS int) +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..ba1f2c1 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT CAST(LEN([e].[Name]) AS int) +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.verified.txt new file mode 100644 index 0000000..ba1f2c1 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalAccess_WorksCorrectly.verified.txt @@ -0,0 +1,2 @@ +SELECT CAST(LEN([e].[Name]) AS int) +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..4d0592a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(0 AS bit) THEN N'Not Active' + ELSE N'Active' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..4d0592a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(0 AS bit) THEN N'Not Active' + ELSE N'Active' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.verified.txt new file mode 100644 index 0000000..4d0592a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ConditionalWithNegation_WorksCorrectly.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(0 AS bit) THEN N'Not Active' + ELSE N'Active' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet10_0.verified.txt new file mode 100644 index 0000000..a29be77 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet10_0.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(0 AS bit) THEN 0 + WHEN [e].[Value] < 0 THEN 0 + ELSE [e].[Value] * 2 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet9_0.verified.txt new file mode 100644 index 0000000..a29be77 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.DotNet9_0.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(0 AS bit) THEN 0 + WHEN [e].[Value] < 0 THEN 0 + ELSE [e].[Value] * 2 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.verified.txt new file mode 100644 index 0000000..a29be77 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.GuardClause_WithEarlyReturn.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(0 AS bit) THEN 0 + WHEN [e].[Value] < 0 THEN 0 + ELSE [e].[Value] * 2 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet10_0.verified.txt new file mode 100644 index 0000000..26ac26b --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet9_0.verified.txt new file mode 100644 index 0000000..26ac26b --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.verified.txt new file mode 100644 index 0000000..26ac26b --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfElseStatement_IsTranslatedToTernary.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet10_0.verified.txt new file mode 100644 index 0000000..0c5fe1e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet10_0.verified.txt @@ -0,0 +1,4 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN [e].[Value] * 2 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet9_0.verified.txt new file mode 100644 index 0000000..0c5fe1e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.DotNet9_0.verified.txt @@ -0,0 +1,4 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN [e].[Value] * 2 +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.verified.txt new file mode 100644 index 0000000..7e3c8c6 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_UsesDefault.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN [e].[Value] * 2 + ELSE NULL +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet10_0.verified.txt new file mode 100644 index 0000000..f3f5c43 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active' + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet9_0.verified.txt new file mode 100644 index 0000000..f3f5c43 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active' + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.verified.txt new file mode 100644 index 0000000..f3f5c43 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.IfWithoutElse_WithFallbackReturn.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active' + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet10_0.verified.txt new file mode 100644 index 0000000..eec38d9 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + [e].[Value] * 2 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet9_0.verified.txt new file mode 100644 index 0000000..eec38d9 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + [e].[Value] * 2 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.verified.txt new file mode 100644 index 0000000..eec38d9 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariableReuse_IsInlinedMultipleTimes.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + [e].[Value] * 2 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet10_0.verified.txt new file mode 100644 index 0000000..9689484 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 5 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet9_0.verified.txt new file mode 100644 index 0000000..9689484 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 5 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.verified.txt new file mode 100644 index 0000000..9689484 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.LocalVariable_IsInlined.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 5 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet10_0.verified.txt new file mode 100644 index 0000000..257f6f0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet10_0.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] > 100 THEN N'Active High' + WHEN [e].[Value] > 50 THEN N'Active Medium' + ELSE N'Active Low' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet9_0.verified.txt new file mode 100644 index 0000000..257f6f0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.DotNet9_0.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] > 100 THEN N'Active High' + WHEN [e].[Value] > 50 THEN N'Active Medium' + ELSE N'Active Low' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.verified.txt new file mode 100644 index 0000000..257f6f0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MixedIfAndSwitch_WithMultiplePatterns.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] > 100 THEN N'Active High' + WHEN [e].[Value] > 50 THEN N'Active Medium' + ELSE N'Active Low' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet10_0.verified.txt new file mode 100644 index 0000000..1ae6355 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'Very High' + WHEN [e].[Value] > 50 THEN N'High' + WHEN [e].[Value] > 10 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet9_0.verified.txt new file mode 100644 index 0000000..1ae6355 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'Very High' + WHEN [e].[Value] > 50 THEN N'High' + WHEN [e].[Value] > 10 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.verified.txt new file mode 100644 index 0000000..1ae6355 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleEarlyReturns_ConvertedToNestedTernaries.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'Very High' + WHEN [e].[Value] > 50 THEN N'High' + WHEN [e].[Value] > 10 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..4a903b0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + [e].[Value] * 3 + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..4a903b0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + [e].[Value] * 3 + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.verified.txt new file mode 100644 index 0000000..4a903b0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.MultipleLocalVariables_AreInlinedCorrectly.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + [e].[Value] * 3 + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet10_0.verified.txt new file mode 100644 index 0000000..6973619 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100 THEN N'Active High' + WHEN [e].[IsActive] = CAST(1 AS bit) OR [e].[Value] > 50 THEN N'Active or Medium' + WHEN [e].[IsActive] = CAST(0 AS bit) AND [e].[Value] <= 10 THEN N'Inactive Low' + ELSE N'Other' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet9_0.verified.txt new file mode 100644 index 0000000..6973619 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100 THEN N'Active High' + WHEN [e].[IsActive] = CAST(1 AS bit) OR [e].[Value] > 50 THEN N'Active or Medium' + WHEN [e].[IsActive] = CAST(0 AS bit) AND [e].[Value] <= 10 THEN N'Inactive Low' + ELSE N'Other' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.verified.txt new file mode 100644 index 0000000..6973619 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedConditionals_WithLogicalOperators.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100 THEN N'Active High' + WHEN [e].[IsActive] = CAST(1 AS bit) OR [e].[Value] > 50 THEN N'Active or Medium' + WHEN [e].[IsActive] = CAST(0 AS bit) AND [e].[Value] <= 10 THEN N'Inactive Low' + ELSE N'Other' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet10_0.verified.txt new file mode 100644 index 0000000..9d42002 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet10_0.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + WHEN [e].[Value] > 50 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet9_0.verified.txt new file mode 100644 index 0000000..9d42002 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.DotNet9_0.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + WHEN [e].[Value] > 50 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.verified.txt new file mode 100644 index 0000000..9d42002 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedIfElse_IsTranslatedToNestedTernary.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + WHEN [e].[Value] > 50 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..5f5a209 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] = 1 THEN N'Active One' + WHEN [e].[Value] = 2 THEN N'Active Two' + ELSE N'Active Other' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..5f5a209 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] = 1 THEN N'Active One' + WHEN [e].[Value] = 2 THEN N'Active Two' + ELSE N'Active Other' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.verified.txt new file mode 100644 index 0000000..5f5a209 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedSwitchInIf_WorksCorrectly.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] = 1 THEN N'Active One' + WHEN [e].[Value] = 2 THEN N'Active Two' + ELSE N'Active Other' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..9d42002 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + WHEN [e].[Value] > 50 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..9d42002 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + WHEN [e].[Value] > 50 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.verified.txt new file mode 100644 index 0000000..9d42002 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NestedTernary_WorksCorrectly.verified.txt @@ -0,0 +1,6 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'High' + WHEN [e].[Value] > 50 THEN N'Medium' + ELSE N'Low' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..52f2a3e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT COALESCE([e].[Name], N'Unknown') +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..52f2a3e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT COALESCE([e].[Name], N'Unknown') +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.verified.txt new file mode 100644 index 0000000..52f2a3e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.NullCoalescing_WorksCorrectly.verified.txt @@ -0,0 +1,2 @@ +SELECT COALESCE([e].[Name], N'Unknown') +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet10_0.verified.txt new file mode 100644 index 0000000..06a56fa --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet9_0.verified.txt new file mode 100644 index 0000000..06a56fa --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.verified.txt new file mode 100644 index 0000000..06a56fa --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.ReturnWithPropertyAccess_IsTranslatedToSql.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet10_0.verified.txt new file mode 100644 index 0000000..6efc8d2 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet9_0.verified.txt new file mode 100644 index 0000000..6efc8d2 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.verified.txt new file mode 100644 index 0000000..6efc8d2 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SimpleReturn_IsTranslatedToSql.verified.txt @@ -0,0 +1,2 @@ +SELECT 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..e6bf43e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..e6bf43e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.verified.txt new file mode 100644 index 0000000..e6bf43e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.StringInterpolation_WorksCorrectly.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet10_0.verified.txt new file mode 100644 index 0000000..9ed7fa8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 THEN N'One' + WHEN [e].[Value] = 2 THEN N'Two' + WHEN [e].[Value] = 3 THEN N'Three' + ELSE N'Many' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet9_0.verified.txt new file mode 100644 index 0000000..9ed7fa8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 THEN N'One' + WHEN [e].[Value] = 2 THEN N'Two' + WHEN [e].[Value] = 3 THEN N'Three' + ELSE N'Many' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.verified.txt new file mode 100644 index 0000000..9ed7fa8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_Simple.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 THEN N'One' + WHEN [e].[Value] = 2 THEN N'Two' + WHEN [e].[Value] = 3 THEN N'Three' + ELSE N'Many' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet10_0.verified.txt new file mode 100644 index 0000000..727148f --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] <= 2 THEN N'Low' + WHEN [e].[Value] <= 5 THEN N'Medium' + WHEN [e].[Value] <= 8 THEN N'High' + ELSE N'Critical' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet9_0.verified.txt new file mode 100644 index 0000000..727148f --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] <= 2 THEN N'Low' + WHEN [e].[Value] <= 5 THEN N'Medium' + WHEN [e].[Value] <= 8 THEN N'High' + ELSE N'Critical' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.verified.txt new file mode 100644 index 0000000..727148f --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchExpression_WithDiscard.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] <= 2 THEN N'Low' + WHEN [e].[Value] <= 5 THEN N'Medium' + WHEN [e].[Value] <= 8 THEN N'High' + ELSE N'Critical' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet10_0.verified.txt new file mode 100644 index 0000000..9ed7fa8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 THEN N'One' + WHEN [e].[Value] = 2 THEN N'Two' + WHEN [e].[Value] = 3 THEN N'Three' + ELSE N'Many' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet9_0.verified.txt new file mode 100644 index 0000000..9ed7fa8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 THEN N'One' + WHEN [e].[Value] = 2 THEN N'Two' + WHEN [e].[Value] = 3 THEN N'Three' + ELSE N'Many' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.verified.txt new file mode 100644 index 0000000..9ed7fa8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_Simple.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 THEN N'One' + WHEN [e].[Value] = 2 THEN N'Two' + WHEN [e].[Value] = 3 THEN N'Three' + ELSE N'Many' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet10_0.verified.txt new file mode 100644 index 0000000..9c8b78e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] IN (1, 2) THEN N'Low' + WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium' + WHEN [e].[Value] IN (6, 7, 8) THEN N'High' + ELSE N'Critical' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet9_0.verified.txt new file mode 100644 index 0000000..9c8b78e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] IN (1, 2) THEN N'Low' + WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium' + WHEN [e].[Value] IN (6, 7, 8) THEN N'High' + ELSE N'Critical' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.verified.txt new file mode 100644 index 0000000..9c8b78e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchStatement_WithMultipleCases.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] IN (1, 2) THEN N'Low' + WHEN [e].[Value] IN (3, 4, 5) THEN N'Medium' + WHEN [e].[Value] IN (6, 7, 8) THEN N'High' + ELSE N'Critical' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..f2343d3 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active One' + WHEN [e].[Value] = 1 THEN N'Inactive One' + WHEN [e].[Value] > 10 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active High' + ELSE N'Other' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..f2343d3 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active One' + WHEN [e].[Value] = 1 THEN N'Inactive One' + WHEN [e].[Value] > 10 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active High' + ELSE N'Other' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.verified.txt new file mode 100644 index 0000000..f2343d3 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.SwitchWithWhenClause_WorksCorrectly.verified.txt @@ -0,0 +1,7 @@ +SELECT CASE + WHEN [e].[Value] = 1 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active One' + WHEN [e].[Value] = 1 THEN N'Inactive One' + WHEN [e].[Value] > 10 AND [e].[IsActive] = CAST(1 AS bit) THEN N'Active High' + ELSE N'Other' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000..f3f5c43 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active' + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet9_0.verified.txt new file mode 100644 index 0000000..f3f5c43 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active' + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.verified.txt new file mode 100644 index 0000000..f3f5c43 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.TernaryExpression_WorksCorrectly.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN N'Active' + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.cs b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.cs new file mode 100644 index 0000000..9622f34 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodiedMethodTests.cs @@ -0,0 +1,672 @@ +using EntityFrameworkCore.Projectables.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; + +namespace EntityFrameworkCore.Projectables.FunctionalTests.BlockBodiedMethods +{ + [UsesVerify] + public class BlockBodiedMethodTests + { + public record Entity + { + public int Id { get; set; } + public int Value { get; set; } + public bool IsActive { get; set; } + public string? Name { get; set; } + } + + [Fact] + public Task SimpleReturn_IsTranslatedToSql() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetConstant()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task ReturnWithPropertyAccess_IsTranslatedToSql() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetValuePlusTen()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task IfElseStatement_IsTranslatedToTernary() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetCategory()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task NestedIfElse_IsTranslatedToNestedTernary() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetLevel()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task LocalVariable_IsInlined() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.CalculateDouble()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task ComplexConditional_IsTranslatedCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetAdjustedValue()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockMethodWithParameters_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.Add(5, 10)); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task IfWithoutElse_UsesDefault() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetPremiumIfActive()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task IfWithoutElse_WithFallbackReturn() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetStatus()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task SwitchStatement_Simple() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetValueLabel()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task SwitchStatement_WithMultipleCases() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetPriority()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task MultipleEarlyReturns_ConvertedToNestedTernaries() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetValueCategory()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task NullCoalescing_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetNameOrDefault()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task ConditionalAccess_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetNameLength()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task SwitchExpression_Simple() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetValueLabelModern()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task SwitchExpression_WithDiscard() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetPriorityModern()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task MultipleLocalVariables_AreInlinedCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.CalculateComplex()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task NestedConditionals_WithLogicalOperators() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetComplexCategory()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task GuardClause_WithEarlyReturn() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetGuardedValue()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task NestedSwitchInIf_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetCombinedLogic()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task TernaryExpression_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetValueUsingTernary()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task NestedTernary_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetNestedTernary()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task MixedIfAndSwitch_WithMultiplePatterns() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetComplexMix()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task SwitchWithWhenClause_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetValueWithCondition()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task LocalVariableReuse_IsInlinedMultipleTimes() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.CalculateWithReuse()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BooleanReturn_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.IsHighValue()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task ConditionalWithNegation_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetInactiveStatus()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task StringInterpolation_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.GetFormattedValue()); + + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task ArithmeticInReturn_WorksCorrectly() + { + using var dbContext = new SampleDbContext(); + + var query = dbContext.Set() + .Select(x => x.CalculatePercentage()); + + return Verifier.Verify(query.ToQueryString()); + } + } + + public static class EntityExtensions + { + [Projectable] + public static int GetConstant(this BlockBodiedMethodTests.Entity entity) + { + return 42; + } + + [Projectable] + public static int GetValuePlusTen(this BlockBodiedMethodTests.Entity entity) + { + return entity.Value + 10; + } + + [Projectable] + public static string GetCategory(this BlockBodiedMethodTests.Entity entity) + { + if (entity.Value > 100) + { + return "High"; + } + else + { + return "Low"; + } + } + + [Projectable] + public static string GetLevel(this BlockBodiedMethodTests.Entity entity) + { + if (entity.Value > 100) + { + return "High"; + } + else if (entity.Value > 50) + { + return "Medium"; + } + else + { + return "Low"; + } + } + + [Projectable] + public static int CalculateDouble(this BlockBodiedMethodTests.Entity entity) + { + var doubled = entity.Value * 2; + return doubled + 5; + } + + [Projectable] + public static int GetAdjustedValue(this BlockBodiedMethodTests.Entity entity) + { + if (entity.IsActive && entity.Value > 0) + { + return entity.Value * 2; + } + else + { + return 0; + } + } + + [Projectable] + public static int Add(this BlockBodiedMethodTests.Entity entity, int a, int b) + { + return a + b; + } + + [Projectable] + public static int? GetPremiumIfActive(this BlockBodiedMethodTests.Entity entity) + { + if (entity.IsActive) + { + return entity.Value * 2; + } + return null; + } + + [Projectable] + public static string GetStatus(this BlockBodiedMethodTests.Entity entity) + { + if (entity.IsActive) + { + return "Active"; + } + return "Inactive"; + } + + [Projectable] + public static string GetValueLabel(this BlockBodiedMethodTests.Entity entity) + { + switch (entity.Value) + { + case 1: + return "One"; + case 2: + return "Two"; + case 3: + return "Three"; + default: + return "Many"; + } + } + + [Projectable] + public static string GetPriority(this BlockBodiedMethodTests.Entity entity) + { + switch (entity.Value) + { + case 1: + case 2: + return "Low"; + case 3: + case 4: + case 5: + return "Medium"; + case 6: + case 7: + case 8: + return "High"; + default: + return "Critical"; + } + } + + [Projectable] + public static string GetValueCategory(this BlockBodiedMethodTests.Entity entity) + { + if (entity.Value > 100) + { + return "Very High"; + } + + if (entity.Value > 50) + { + return "High"; + } + + if (entity.Value > 10) + { + return "Medium"; + } + + return "Low"; + } + + [Projectable] + public static string GetNameOrDefault(this BlockBodiedMethodTests.Entity entity) + { + return entity.Name ?? "Unknown"; + } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static int? GetNameLength(this BlockBodiedMethodTests.Entity entity) + { + return entity.Name?.Length; + } + + [Projectable] + public static string GetValueLabelModern(this BlockBodiedMethodTests.Entity entity) + { + return entity.Value switch + { + 1 => "One", + 2 => "Two", + 3 => "Three", + _ => "Many" + }; + } + + [Projectable] + public static string GetPriorityModern(this BlockBodiedMethodTests.Entity entity) + { + return entity.Value switch + { + <= 2 => "Low", + <= 5 => "Medium", + <= 8 => "High", + _ => "Critical" + }; + } + + [Projectable] + public static int CalculateComplex(this BlockBodiedMethodTests.Entity entity) + { + var doubled = entity.Value * 2; + var tripled = entity.Value * 3; + var sum = doubled + tripled; + return sum + 10; + } + + [Projectable] + public static string GetComplexCategory(this BlockBodiedMethodTests.Entity entity) + { + if (entity.IsActive && entity.Value > 100) + { + return "Active High"; + } + + if (entity.IsActive || entity.Value > 50) + { + return "Active or Medium"; + } + + if (!entity.IsActive && entity.Value <= 10) + { + return "Inactive Low"; + } + + return "Other"; + } + + [Projectable] + public static int GetGuardedValue(this BlockBodiedMethodTests.Entity entity) + { + if (!entity.IsActive) + { + return 0; + } + + if (entity.Value < 0) + { + return 0; + } + + return entity.Value * 2; + } + + [Projectable] + public static string GetCombinedLogic(this BlockBodiedMethodTests.Entity entity) + { + if (entity.IsActive) + { + switch (entity.Value) + { + case 1: + return "Active One"; + case 2: + return "Active Two"; + default: + return "Active Other"; + } + } + + return "Inactive"; + } + + [Projectable] + public static string GetValueUsingTernary(this BlockBodiedMethodTests.Entity entity) + { + return entity.IsActive ? "Active" : "Inactive"; + } + + [Projectable] + public static string GetNestedTernary(this BlockBodiedMethodTests.Entity entity) + { + return entity.Value > 100 ? "High" : entity.Value > 50 ? "Medium" : "Low"; + } + + [Projectable] + public static string GetComplexMix(this BlockBodiedMethodTests.Entity entity) + { + if (entity.IsActive) + { + return entity.Value switch + { + > 100 => "Active High", + > 50 => "Active Medium", + _ => "Active Low" + }; + } + + return "Inactive"; + } + + [Projectable] + public static string GetValueWithCondition(this BlockBodiedMethodTests.Entity entity) + { + return entity.Value switch + { + 1 when entity.IsActive => "Active One", + 1 => "Inactive One", + > 10 when entity.IsActive => "Active High", + _ => "Other" + }; + } + + [Projectable] + public static int CalculateWithReuse(this BlockBodiedMethodTests.Entity entity) + { + var doubled = entity.Value * 2; + return doubled + doubled; + } + + [Projectable] + public static bool IsHighValue(this BlockBodiedMethodTests.Entity entity) + { + if (entity.Value > 100) + { + return true; + } + return false; + } + + [Projectable] + public static string GetInactiveStatus(this BlockBodiedMethodTests.Entity entity) + { + if (!entity.IsActive) + { + return "Not Active"; + } + else + { + return "Active"; + } + } + + [Projectable] + public static string GetFormattedValue(this BlockBodiedMethodTests.Entity entity) + { + return $"Value: {entity.Value}"; + } + + [Projectable] + public static double CalculatePercentage(this BlockBodiedMethodTests.Entity entity) + { + return (double)entity.Value / 100.0 * 50.0; + } + } +} diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTest.cs b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTest.cs new file mode 100644 index 0000000..c09237b --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTest.cs @@ -0,0 +1,273 @@ +using EntityFrameworkCore.Projectables.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; + +namespace EntityFrameworkCore.Projectables.FunctionalTests.BlockBodiedMethods +{ + /// + /// Tests for calling projectable methods from within block-bodied methods + /// + [UsesVerify] + public class BlockBodyProjectableCallTests + { + public record Entity + { + public int Id { get; set; } + public int Value { get; set; } + public bool IsActive { get; set; } + public string? Name { get; set; } + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_Simple() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetAdjustedWithConstant()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InReturn() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetDoubledValue()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InCondition() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetCategoryBasedOnAdjusted()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_Multiple() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.CombineProjectableMethods()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InSwitch() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetLabelBasedOnCategory()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InSwitchExpression() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetDescriptionByLevel()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_WithLocalVariable() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.CalculateUsingProjectable()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_Nested() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetNestedProjectableCall()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InEarlyReturn() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetStatusWithProjectableCheck()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InTernary() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.GetConditionalProjectable()); + return Verifier.Verify(query.ToQueryString()); + } + + [Fact] + public Task BlockBodyCallingProjectableMethod_InLogicalExpression() + { + using var dbContext = new SampleDbContext(); + var query = dbContext.Set() + .Select(x => x.IsComplexCondition()); + return Verifier.Verify(query.ToQueryString()); + } + } + + public static class ProjectableCallExtensions + { + // Base projectable methods (helper methods) + [Projectable] + public static int GetConstant(this BlockBodyProjectableCallTests.Entity entity) + { + return 42; + } + + [Projectable] + public static int GetDoubled(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.Value * 2; + } + + [Projectable] + public static string GetCategory(this BlockBodyProjectableCallTests.Entity entity) + { + if (entity.Value > 100) + return "High"; + else + return "Low"; + } + + [Projectable] + public static string GetLevel(this BlockBodyProjectableCallTests.Entity entity) + { + if (entity.Value > 100) return "Level3"; + if (entity.Value > 50) return "Level2"; + return "Level1"; + } + + [Projectable] + public static bool IsHighValue(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.Value > 100; + } + + // Block-bodied methods calling projectable methods + + [Projectable] + public static int GetAdjustedWithConstant(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.Value + entity.GetConstant(); + } + + [Projectable] + public static int GetDoubledValue(this BlockBodyProjectableCallTests.Entity entity) + { + var doubled = entity.GetDoubled(); + return doubled; + } + + [Projectable] + public static string GetCategoryBasedOnAdjusted(this BlockBodyProjectableCallTests.Entity entity) + { + if (entity.GetDoubled() > 200) + { + return "Very High"; + } + else + { + return "Normal"; + } + } + + [Projectable] + public static int CombineProjectableMethods(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.GetDoubled() + entity.GetConstant(); + } + + [Projectable] + public static string GetLabelBasedOnCategory(this BlockBodyProjectableCallTests.Entity entity) + { + switch (entity.GetCategory()) + { + case "High": + return "Premium"; + case "Low": + return "Standard"; + default: + return "Unknown"; + } + } + + [Projectable] + public static string GetDescriptionByLevel(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.GetLevel() switch + { + "Level3" => "Expert", + "Level2" => "Intermediate", + "Level1" => "Beginner", + _ => "Unknown" + }; + } + + [Projectable] + public static int CalculateUsingProjectable(this BlockBodyProjectableCallTests.Entity entity) + { + var doubled = entity.GetDoubled(); + var withConstant = doubled + entity.GetConstant(); + return withConstant * 2; + } + + [Projectable] + public static int GetNestedProjectableCall(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.GetAdjustedWithConstant() + 10; + } + + [Projectable] + public static string GetStatusWithProjectableCheck(this BlockBodyProjectableCallTests.Entity entity) + { + if (entity.IsHighValue()) + return "Premium"; + + if (entity.GetCategory() == "High") + return "Standard High"; + + return "Normal"; + } + + [Projectable] + public static string GetConditionalProjectable(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.IsActive ? entity.GetCategory() : "Inactive"; + } + + [Projectable] + public static string GetChainedResult(this BlockBodyProjectableCallTests.Entity entity) + { + var doubled = entity.GetDoubled(); + + if (doubled > 200) + { + return entity.GetCategory() + " Priority"; + } + + return entity.GetLevel(); + } + + [Projectable] + public static bool IsComplexCondition(this BlockBodyProjectableCallTests.Entity entity) + { + return entity.IsActive && entity.IsHighValue() || entity.GetDoubled() > 150; + } + } +} diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet10_0.verified.txt new file mode 100644 index 0000000..478d0ba --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] * 2 > 200 THEN N'Very High' + ELSE N'Normal' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet9_0.verified.txt new file mode 100644 index 0000000..478d0ba --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] * 2 > 200 THEN N'Very High' + ELSE N'Normal' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.verified.txt new file mode 100644 index 0000000..478d0ba --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InCondition.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN [e].[Value] * 2 > 200 THEN N'Very High' + ELSE N'Normal' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet10_0.verified.txt new file mode 100644 index 0000000..bd650a0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet10_0.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'Premium' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'High' THEN N'Standard High' + ELSE N'Normal' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet9_0.verified.txt new file mode 100644 index 0000000..bd650a0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.DotNet9_0.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'Premium' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'High' THEN N'Standard High' + ELSE N'Normal' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.verified.txt new file mode 100644 index 0000000..bd650a0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InEarlyReturn.verified.txt @@ -0,0 +1,9 @@ +SELECT CASE + WHEN [e].[Value] > 100 THEN N'Premium' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'High' THEN N'Standard High' + ELSE N'Normal' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet10_0.verified.txt new file mode 100644 index 0000000..de3373a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet10_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN ([e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100) OR [e].[Value] * 2 > 150 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet9_0.verified.txt new file mode 100644 index 0000000..de3373a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.DotNet9_0.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN ([e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100) OR [e].[Value] * 2 > 150 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.verified.txt new file mode 100644 index 0000000..de3373a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InLogicalExpression.verified.txt @@ -0,0 +1,5 @@ +SELECT CASE + WHEN ([e].[IsActive] = CAST(1 AS bit) AND [e].[Value] > 100) OR [e].[Value] * 2 > 150 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet10_0.verified.txt new file mode 100644 index 0000000..dea1914 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet9_0.verified.txt new file mode 100644 index 0000000..dea1914 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.verified.txt new file mode 100644 index 0000000..dea1914 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InReturn.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet10_0.verified.txt new file mode 100644 index 0000000..927c6ff --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet10_0.verified.txt @@ -0,0 +1,12 @@ +SELECT CASE + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'High' THEN N'Premium' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'Low' THEN N'Standard' + ELSE N'Unknown' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet9_0.verified.txt new file mode 100644 index 0000000..927c6ff --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.DotNet9_0.verified.txt @@ -0,0 +1,12 @@ +SELECT CASE + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'High' THEN N'Premium' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'Low' THEN N'Standard' + ELSE N'Unknown' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.verified.txt new file mode 100644 index 0000000..927c6ff --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitch.verified.txt @@ -0,0 +1,12 @@ +SELECT CASE + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'High' THEN N'Premium' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END = N'Low' THEN N'Standard' + ELSE N'Unknown' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet10_0.verified.txt new file mode 100644 index 0000000..409a445 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet10_0.verified.txt @@ -0,0 +1,19 @@ +SELECT CASE + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level3' THEN N'Expert' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level2' THEN N'Intermediate' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level1' THEN N'Beginner' + ELSE N'Unknown' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet9_0.verified.txt new file mode 100644 index 0000000..409a445 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.DotNet9_0.verified.txt @@ -0,0 +1,19 @@ +SELECT CASE + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level3' THEN N'Expert' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level2' THEN N'Intermediate' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level1' THEN N'Beginner' + ELSE N'Unknown' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.verified.txt new file mode 100644 index 0000000..409a445 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InSwitchExpression.verified.txt @@ -0,0 +1,19 @@ +SELECT CASE + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level3' THEN N'Expert' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level2' THEN N'Intermediate' + WHEN CASE + WHEN [e].[Value] > 100 THEN N'Level3' + WHEN [e].[Value] > 50 THEN N'Level2' + ELSE N'Level1' + END = N'Level1' THEN N'Beginner' + ELSE N'Unknown' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet10_0.verified.txt new file mode 100644 index 0000000..ad971d0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet10_0.verified.txt @@ -0,0 +1,8 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet9_0.verified.txt new file mode 100644 index 0000000..ad971d0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.DotNet9_0.verified.txt @@ -0,0 +1,8 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.verified.txt new file mode 100644 index 0000000..ad971d0 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_InTernary.verified.txt @@ -0,0 +1,8 @@ +SELECT CASE + WHEN [e].[IsActive] = CAST(1 AS bit) THEN CASE + WHEN [e].[Value] > 100 THEN N'High' + ELSE N'Low' + END + ELSE N'Inactive' +END +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet10_0.verified.txt new file mode 100644 index 0000000..69eb4b8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet9_0.verified.txt new file mode 100644 index 0000000..69eb4b8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.verified.txt new file mode 100644 index 0000000..69eb4b8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Multiple.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet10_0.verified.txt new file mode 100644 index 0000000..72fc7ea --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 42 + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet9_0.verified.txt new file mode 100644 index 0000000..72fc7ea --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 42 + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.verified.txt new file mode 100644 index 0000000..72fc7ea --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Nested.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 42 + 10 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet10_0.verified.txt new file mode 100644 index 0000000..0bb6121 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet9_0.verified.txt new file mode 100644 index 0000000..0bb6121 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.verified.txt new file mode 100644 index 0000000..0bb6121 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_Simple.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] + 42 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet10_0.verified.txt new file mode 100644 index 0000000..0294ea7 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet10_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 84 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet9_0.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet9_0.verified.txt new file mode 100644 index 0000000..0294ea7 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.DotNet9_0.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 84 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.verified.txt new file mode 100644 index 0000000..0294ea7 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethods/BlockBodyProjectableCallTests.BlockBodyCallingProjectableMethod_WithLocalVariable.verified.txt @@ -0,0 +1,2 @@ +SELECT [e].[Value] * 2 + 84 +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt new file mode 100644 index 0000000..a6b0b53 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt @@ -0,0 +1,3 @@ +[ + (11,13): error EFP0004: Compound assignment operator '+=' has side effects and cannot be used in projectable methods +] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt new file mode 100644 index 0000000..b5f9f5b --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar > 10 ? 1 : default; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt new file mode 100644 index 0000000..c22d885 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar > 10 ? 1 : 0; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt new file mode 100644 index 0000000..d47a3ba --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt @@ -0,0 +1,3 @@ +[ + (12,13): error EFP0004: Increment/decrement operator '++' has side effects and cannot be used in projectable methods +] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt new file mode 100644 index 0000000..e940c26 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar * 2 > 10 ? 1 : 0; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt new file mode 100644 index 0000000..0a7e7da --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar * 2 == 2 ? "Two" : @this.Bar * 2 == 4 ? "Four" : "Other"; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt new file mode 100644 index 0000000..587f792 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt @@ -0,0 +1,3 @@ +[ + (13,17): warning EFP0003: Method 'Foo' contains an unsupported statement: Local declarations in nested blocks are not supported +] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt new file mode 100644 index 0000000..26e6a19 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt @@ -0,0 +1,3 @@ +[ + (11,13): warning EFP0005: Method call 'WriteLine' may have side effects. Only calls to methods marked with [Projectable] are guaranteed to be safe in projectable methods +] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt new file mode 100644 index 0000000..e684d40 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt @@ -0,0 +1,3 @@ +[ + (11,13): error EFP0004: Assignment operation has side effects and cannot be used in projectable methods +] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt new file mode 100644 index 0000000..eeb0754 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => 42; + } + } +} diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt new file mode 100644 index 0000000..d1a7eb5 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar == 1 ? "One" : @this.Bar == 2 ? "Two" : "Other"; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt new file mode 100644 index 0000000..c90d6b7 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar == 1 || @this.Bar == 2 ? "Low" : @this.Bar == 3 || @this.Bar == 4 || @this.Bar == 5 ? "Medium" : "High"; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt new file mode 100644 index 0000000..0a4d15d --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar == 1 ? "One" : @this.Bar == 2 ? "Two" : default; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithConstantPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithConstantPattern.verified.txt new file mode 100644 index 0000000..6356921 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithConstantPattern.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_Extensions_IsNull_P0_Foo_Entity + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.Entity entity) => entity == null ? true : false; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt new file mode 100644 index 0000000..c22d885 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar > 10 ? 1 : 0; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt new file mode 100644 index 0000000..ef8f31a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.IsActive && @this.Bar > 0 ? @this.Bar * 2 : 0; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt new file mode 100644 index 0000000..d863659 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar * 2 + 5; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt new file mode 100644 index 0000000..7c1426a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Add_P0_int_P1_int + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this, int a, int b) => a + b; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt new file mode 100644 index 0000000..216b8f2 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar > 10 ? "High" : @this.Bar > 5 ? "Medium" : "Low"; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNotPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNotPattern.verified.txt new file mode 100644 index 0000000..797a367 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNotPattern.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_Extensions_IsNotNull_P0_Foo_Entity + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.Entity entity) => !(entity == null) ? true : false; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPatternMatching.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPatternMatching.verified.txt new file mode 100644 index 0000000..a11076d --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPatternMatching.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_Extensions_GetComplexCategory_P0_Foo_Entity + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.Entity entity) => entity != null && entity.IsActive == true && entity.Value > 100 ? "Active High" : "Other"; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt new file mode 100644 index 0000000..19e29c9 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar + 10; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithRelationalPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithRelationalPattern.verified.txt new file mode 100644 index 0000000..55dcb0a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithRelationalPattern.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_Extensions_GetCategory_P0_Foo_Entity + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.Entity entity) => entity.Value > 100 ? "High" : "Low"; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt new file mode 100644 index 0000000..24ae821 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt @@ -0,0 +1,17 @@ +// +#nullable disable +using System; +using EntityFrameworkCore.Projectables; +using Foo; + +namespace EntityFrameworkCore.Projectables.Generated +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + static class Foo_C_Foo + { + static global::System.Linq.Expressions.Expression> Expression() + { + return (global::Foo.C @this) => @this.Bar * 2 + 5 + 10; + } + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs index e5b07d2..bab5608 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs @@ -493,7 +493,7 @@ public int Foo } [Fact] - public void BlockBodiedMethod_RaisesDiagnostics() + public void BlockBodiedMethod_NoLongerRaisesDiagnostics() { var compilation = CreateCompilation(@" using System; @@ -511,7 +511,9 @@ public int Foo() var result = RunGenerator(compilation); - Assert.Single(result.Diagnostics); + // Block-bodied methods are now supported, so no diagnostics should be raised + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); } [Fact] @@ -1977,6 +1979,770 @@ public static Dictionary ToDictionary(this Entity entity) return Verifier.Verify(result.GeneratedTrees[0].ToString()); } + [Fact] + public Task BlockBodiedMethod_SimpleReturn() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo() + { + return 42; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithPropertyAccess() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + return Bar + 10; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithIfElse() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + if (Bar > 10) + { + return 1; + } + else + { + return 0; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithNestedIfElse() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public string Foo() + { + if (Bar > 10) + { + return ""High""; + } + else if (Bar > 5) + { + return ""Medium""; + } + else + { + return ""Low""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithLocalVariable() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + var temp = Bar * 2; + return temp + 5; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithTransitiveLocalVariables() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + var a = Bar * 2; + var b = a + 5; + return b + 10; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_LocalInIfCondition() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + var threshold = Bar * 2; + if (threshold > 10) + { + return 1; + } + else + { + return 0; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_LocalInSwitchExpression() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public string Foo() + { + var value = Bar * 2; + switch (value) + { + case 2: + return ""Two""; + case 4: + return ""Four""; + default: + return ""Other""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + if (Bar > 10) + { + var temp = Bar * 2; + return temp; + } + return 0; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + // Should have a diagnostic about locals in nested blocks + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0003"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_WithMultipleParameters() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Add(int a, int b) + { + return a + b; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithIfElseAndCondition() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + public bool IsActive { get; set; } + + [Projectable] + public int Foo() + { + if (IsActive && Bar > 0) + { + return Bar * 2; + } + else + { + return 0; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + + [Fact] + public Task BlockBodiedMethod_IfWithoutElse_UsesDefault() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + if (Bar > 10) + { + return 1; + } + return 0; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_IfWithoutElse_ImplicitReturn() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int? Foo() + { + if (Bar > 10) + { + return 1; + } + } + } +} +", expectedToCompile: false); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_SwitchStatement_Simple() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public string Foo() + { + switch (Bar) + { + case 1: + return ""One""; + case 2: + return ""Two""; + default: + return ""Other""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_SwitchStatement_WithMultipleCases() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public string Foo() + { + switch (Bar) + { + case 1: + case 2: + return ""Low""; + case 3: + case 4: + case 5: + return ""Medium""; + default: + return ""High""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_SwitchStatement_WithoutDefault() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public string? Foo() + { + switch (Bar) + { + case 1: + return ""One""; + case 2: + return ""Two""; + } + } + } +} +", expectedToCompile: false); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_PropertyAssignment_ReportsError() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + Bar = 10; + return Bar; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + // Should have a diagnostic about side effects + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_CompoundAssignment_ReportsError() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + Bar += 10; + return Bar; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + // Should have a diagnostic about side effects + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_IncrementOperator_ReportsError() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + var x = 5; + x++; + return x; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + // Should have a diagnostic about side effects + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo() + { + Console.WriteLine(""test""); + return Bar; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + // Should have a diagnostic about potential side effects + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0005"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_WithPatternMatching() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public bool IsActive { get; set; } + public int Value { get; set; } + } + + static class Extensions { + [Projectable] + public static string GetComplexCategory(this Entity entity) + { + if (entity is { IsActive: true, Value: > 100 }) + { + return ""Active High""; + } + return ""Other""; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + // The generator should not crash and should handle pattern matching + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithRelationalPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public int Value { get; set; } + } + + static class Extensions { + [Projectable] + public static string GetCategory(this Entity entity) + { + if (entity.Value is > 100) + { + return ""High""; + } + return ""Low""; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithConstantPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public string Status { get; set; } + } + + static class Extensions { + [Projectable] + public static bool IsNull(this Entity entity) + { + if (entity is null) + { + return true; + } + return false; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithNotPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public string Name { get; set; } + } + + static class Extensions { + [Projectable] + public static bool IsNotNull(this Entity entity) + { + if (entity is not null) + { + return true; + } + return false; + } + } +} +", expectedToCompile: true); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + [Fact] public Task MethodOverloads_WithDifferentParameterTypes() {