Skip to content

feat: Add public IConditionEvaluator interface for standalone condition evaluation - #29

Merged
vaceslav merged 2 commits into
mainfrom
feature/issue-24-condition-evaluator-interface
Dec 1, 2025
Merged

feat: Add public IConditionEvaluator interface for standalone condition evaluation#29
vaceslav merged 2 commits into
mainfrom
feature/issue-24-condition-evaluator-interface

Conversation

@vaceslav

@vaceslav vaceslav commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

Summary

  • Add IConditionEvaluator interface in TriasDev.Templify.Conditionals namespace
  • Add ConditionEvaluator implementation wrapping internal ConditionalEvaluator
  • Support Dictionary, JSON string, and IEvaluationContext inputs
  • Include sync and async methods (EvaluateAsync wraps sync for API compatibility)
  • Add CreateContext methods for batch evaluation scenarios
  • Add null parameter validation with ArgumentNullException
  • Add 26 unit tests covering all methods and edge cases

Closes #24

Test plan

  • All 716 existing tests pass
  • 26 new tests for ConditionEvaluator pass
  • Null parameter validation tested
  • JSON and Dictionary inputs tested
  • Context creation and batch evaluation tested

…on evaluation

Implements #24

- Add IConditionEvaluator interface in TriasDev.Templify.Conditionals namespace
- Add ConditionEvaluator implementation wrapping internal ConditionalEvaluator
- Support Dictionary, JSON string, and IEvaluationContext inputs
- Include sync and async methods (EvaluateAsync wraps sync for API compatibility)
- Add CreateContext methods for batch evaluation scenarios
- Add null parameter validation with ArgumentNullException
- Add 26 unit tests covering all methods and edge cases

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a public API for standalone condition evaluation by exposing the internal condition evaluation engine through a new IConditionEvaluator interface and ConditionEvaluator implementation.

Key Changes:

  • New public IConditionEvaluator interface with synchronous and asynchronous evaluation methods
  • ConditionEvaluator class that wraps the internal ConditionalEvaluator
  • Support for Dictionary, JSON string, and IEvaluationContext inputs with context creation for batch operations
  • Comprehensive test suite with 26 unit tests covering all public methods and edge cases

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
TriasDev.Templify/Conditionals/IConditionEvaluator.cs Defines the public interface for condition evaluation with multiple overloads supporting Dictionary, JSON, and context-based inputs
TriasDev.Templify/Conditionals/ConditionEvaluator.cs Implements the interface by wrapping the internal ConditionalEvaluator with proper null validation and async method support
TriasDev.Templify.Tests/ConditionEvaluatorTests.cs Provides comprehensive test coverage for all public methods, including null validation, JSON parsing, and batch evaluation scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +91 to +110
Task<bool> EvaluateAsync(string expression, Dictionary<string, object> data);

/// <summary>
/// Asynchronously evaluates a conditional expression against JSON data.
/// </summary>
/// <param name="expression">The expression to evaluate.</param>
/// <param name="jsonData">A JSON string representing the data object.</param>
/// <returns>A task that resolves to true if the condition is met; otherwise, false.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="expression"/> or <paramref name="jsonData"/> is null.</exception>
/// <exception cref="System.Text.Json.JsonException">Thrown when JSON is invalid or root is not an object.</exception>
Task<bool> EvaluateAsync(string expression, string jsonData);

/// <summary>
/// Asynchronously evaluates a conditional expression using a pre-created evaluation context.
/// </summary>
/// <param name="expression">The expression to evaluate.</param>
/// <param name="context">The evaluation context containing variable data.</param>
/// <returns>A task that resolves to true if the condition is met; otherwise, false.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="expression"/> or <paramref name="context"/> is null.</exception>
Task<bool> EvaluateAsync(string expression, IEvaluationContext context);

Copilot AI Dec 1, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The async methods lack CancellationToken parameters, which is a best practice for async APIs. While the current implementation uses Task.FromResult (which completes synchronously), adding CancellationToken support would:

  1. Follow .NET async/await best practices
  2. Make the API future-proof if true async operations are added later
  3. Allow callers to cancel long-running operations

Consider adding overloads with CancellationToken cancellationToken = default parameters to all EvaluateAsync methods. Example:

Task<bool> EvaluateAsync(string expression, Dictionary<string, object> data, CancellationToken cancellationToken = default);

The implementation can check cancellationToken.ThrowIfCancellationRequested() before calling the sync method.

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +188
#region EvaluateAsync

[Fact]
public async Task EvaluateAsync_WithDictionary_ReturnsCorrectResult()
{
Dictionary<string, object> data = new() { ["IsActive"] = true };

bool result = await _evaluator.EvaluateAsync("IsActive", data);

Assert.True(result);
}

[Fact]
public async Task EvaluateAsync_WithJson_ReturnsCorrectResult()
{
string json = """{"IsActive": true}""";

bool result = await _evaluator.EvaluateAsync("IsActive", json);

Assert.True(result);
}

[Fact]
public async Task EvaluateAsync_WithContext_ReturnsCorrectResult()
{
Dictionary<string, object> data = new() { ["IsActive"] = true };
IEvaluationContext context = _evaluator.CreateContext(data);

bool result = await _evaluator.EvaluateAsync("IsActive", context);

Assert.True(result);
}

Copilot AI Dec 1, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EvaluateAsync methods lack explicit null parameter validation tests. While these methods delegate to the synchronous Evaluate methods which do validate parameters, it's a best practice to have explicit tests for each public API method to ensure they throw ArgumentNullException for null parameters.

Consider adding tests like:

[Fact]
public async Task EvaluateAsync_WithNullExpression_ThrowsArgumentNullException()
{
    var data = new Dictionary<string, object> { ["Key"] = "Value" };
    await Assert.ThrowsAsync<ArgumentNullException>(() => _evaluator.EvaluateAsync(null!, data));
}

Similar tests should be added for all three EvaluateAsync overloads with null parameters.

Copilot uses AI. Check for mistakes.
- Add CancellationToken parameter to all EvaluateAsync methods
- Add cancellationToken.ThrowIfCancellationRequested() in implementation
- Add null validation tests for EvaluateAsync methods
- Add cancellation token test for EvaluateAsync
@vaceslav
vaceslav merged commit 951a027 into main Dec 1, 2025
11 checks passed
@vaceslav
vaceslav deleted the feature/issue-24-condition-evaluator-interface branch December 1, 2025 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add public IConditionEvaluator interface for standalone condition evaluation

2 participants