Skip to content

Commit a537548

Browse files
authored
fix:Property set expression builder does not accept null values and lambdas (#239)
1 parent 713a464 commit a537548

File tree

4 files changed

+79
-29
lines changed

4 files changed

+79
-29
lines changed

Telerik.JustMock/Expr.cs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
JustMock Lite
3-
Copyright © 2022 Progress Software Corporation
3+
Copyright © 2022,2025 Progress Software Corporation
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -24,15 +24,43 @@ namespace Telerik.JustMock
2424
{
2525
#if !PORTABLE
2626
/// <summary>
27-
/// Defines helper methods used for easily building expressions.
27+
/// Provides utility methods for simplifying the creation of expression trees used in mocking scenarios.
28+
/// This class offers a fluent API for building property access expressions that can be used to configure
29+
/// mock behavior for property getters and setters.
2830
/// </summary>
2931
public static class Expr
3032
{
3133
/// <summary>
32-
/// Creates a <see cref="IPropertyExpressionBuilder<T>"/> from an expression.
33-
/// Commonly used to easily build an expression for a property set.
34+
/// Creates an <see cref="IPropertyExpressionBuilder{T}"/> for the specified property access expression.
35+
/// This method analyzes a lambda expression that accesses a property and builds a property expression
36+
/// that can be used to configure mock behavior for property getters or setters.
3437
/// </summary>
35-
/// <typeparam name="T">The type of the property.</typeparam>
38+
/// <typeparam name="T">The type of the property being accessed.</typeparam>
39+
/// <param name="expression">
40+
/// A lambda expression representing the property access, such as <c>() => obj.Property</c> for
41+
/// instance properties or <c>() => Class.StaticProperty</c> for static properties.
42+
/// </param>
43+
/// <returns>
44+
/// An <see cref="IPropertyExpressionBuilder{T}"/> that provides fluent methods for configuring
45+
/// property getter and setter behavior in mock objects.
46+
/// </returns>
47+
/// <exception cref="ArgumentException">
48+
/// Thrown when the provided expression is not a property access expression. The expression must
49+
/// be in the form of accessing a property, such as <c>obj.Property</c> or <c>Class.StaticProperty</c>.
50+
/// </exception>
51+
/// <exception cref="MockException">
52+
/// Thrown when attempting to mock a field instead of a property. JustMock only supports mocking
53+
/// properties, not fields.
54+
/// </exception>
55+
/// <example>
56+
/// <code>
57+
/// // Setting up a mock for a property getter
58+
/// Mock.Arrange(Expr.Property(() => mock.SomeProperty)).Returns(expectedValue);
59+
///
60+
/// // Setting up a mock for a property setter
61+
/// Mock.Arrange(Expr.Property(() => mock.SomeProperty).Set(Arg.IsAny&lt;string&gt;).DoNothing();
62+
/// </code>
63+
/// </example>
3664
public static IPropertyExpressionBuilder<T> Property<T>(Expression<Func<T>> expression)
3765
{
3866
return ProfilerInterceptor.GuardInternal(() =>
@@ -41,8 +69,7 @@ public static IPropertyExpressionBuilder<T> Property<T>(Expression<Func<T>> expr
4169

4270
if (memberExpression.NodeType != ExpressionType.MemberAccess)
4371
{
44-
throw new MockException("Wrong expression used, property access expression looks like obj.Property or Class.StaticProperty");
45-
72+
throw new ArgumentException("Wrong expression used, property access expression looks like obj.Property or Class.StaticProperty", nameof(expression));
4673
}
4774

4875
MemberExpression outerMemberExpression = (MemberExpression)memberExpression;

Telerik.JustMock/IPropertyExpressionBuilder.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
JustMock Lite
3-
Copyright © 2022 Progress Software Corporation
3+
Copyright © 2022,2025 Progress Software Corporation
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -22,19 +22,39 @@ namespace Telerik.JustMock
2222
{
2323
#if !PORTABLE
2424
/// <summary>
25-
/// Defines methods for setting and getting property values through an expression.
25+
/// Defines methods for building LINQ expressions that represent property get and set operations.
26+
/// This interface is used to facilitate setting up expectations and verifications for property
27+
/// access. It provides a strongly-typed approach to creating expressions that can be used
28+
/// to intercept, verify, and emulate property behavior during testing.
2629
/// </summary>
2730
public interface IPropertyExpressionBuilder<T>
2831
{
2932
/// <summary>
30-
/// Builds and expresison for setting the vlaue of a property.
33+
/// Builds an expression for property set arrangement with a specific value.
34+
/// This method creates an expression that represents assigning the specified value to the property,
35+
/// which can be used to verify that a property was set to a particular value or to arrange
36+
/// behavior when such an assignment occurs.
3137
/// </summary>
32-
/// <typeparam name="value">The value that should be set to the property.</typeparam>
38+
/// <param name="value">The exact value to match when the property is set.</param>
39+
/// <returns>An Action expression representing the property set operation.</returns>
3340
Expression<Action> Set(T value);
3441

3542
/// <summary>
36-
/// Builds and expresison for getting the vlaue of a property.
43+
/// Builds an expression for property set arrangement using a lambda.
44+
/// This method allows for more complex matching logic when arranging property set operations,
45+
/// such as matching ranges of values or applying custom validation criteria.
3746
/// </summary>
47+
/// <param name="expression">A lambda expression that produces the value to match when the property is set.</param>
48+
/// <returns>An Action expression representing the property set operation with the specified matching logic.</returns>
49+
Expression<Action> Set(Expression<Func<T>> expression);
50+
51+
/// <summary>
52+
/// Builds an expression for property get arrangement.
53+
/// This method creates an expression that represents retrieving the value of the property,
54+
/// which can be used to arrange behavior when the property is accessed, such as returning
55+
/// specific values or throwing exceptions.
56+
/// </summary>
57+
/// <returns>A Func expression representing the property get operation.</returns>
3858
Expression<Func<T>> Get();
3959
}
4060
#endif

Telerik.JustMock/Mock.Arrange.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
JustMock Lite
3-
Copyright © 2010-2015,2018 Progress Software Corporation
3+
Copyright © 2010-2015,2018,2025 Progress Software Corporation
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -158,13 +158,14 @@ public static ActionExpectation ArrangeSet(Action action)
158158
if (Mock.IsOnDemandEnabled)
159159
{
160160
var sb = new StringBuilder();
161-
sb.AppendLine("ArrangeSet(Action) is not avaiable with OnDemand option enabled.");
162-
sb.AppendLine("Please use Mock.ArrangeSet<OwnerTypeOfProperty>(Action). Or Mock.Arrange with appropriate expression for property set.");
163-
sb.AppendLine("-------------");
164-
sb.AppendLine("Example 1:");
165-
sb.AppendLine("Mock.ArrangeSet<TypeOfMockObject>(() => mockObject.SomeProperty = 5);");
166-
sb.AppendLine("Example 2:");
167-
sb.AppendLine("Mock.Arrange(Expr.Property(() => mockObject.SomeProperty).Set(5));");
161+
sb.AppendLine("ArrangeSet(Action) is not compatible with the OnDemand feature.");
162+
sb.AppendLine("Please use one of these alternatives:");
163+
sb.AppendLine(" 1. Mock.ArrangeSet<OwnerTypeOfProperty>(Action)");
164+
sb.AppendLine(" 2. Mock.Arrange(Expression) with a property set expression");
165+
sb.AppendLine();
166+
sb.AppendLine("Examples:");
167+
sb.AppendLine(" Mock.ArrangeSet<MockObject>(() => mockObject.SomeProperty = 5);");
168+
sb.AppendLine(" Mock.Arrange(Expr.Property(() => mockObject.SomeProperty).Set(5));");
168169

169170
throw new MockException(sb.ToString());
170171
}

Telerik.JustMock/PropertyExpressionBuilder.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
JustMock Lite
3-
Copyright © 2022 Progress Software Corporation
3+
Copyright © 2022,2025 Progress Software Corporation
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -34,22 +34,24 @@ public PropertyExpressionBuilder(Expression propertyExpression)
3434
this.propertyExpression = propertyExpression;
3535
}
3636

37-
/// <summary>
38-
/// Builds and expresison for setting the vlaue of a property.
39-
/// </summary>
40-
/// <typeparam name="value">The value that should be set to the property.</typeparam>
4137
public Expression<Action> Set(T value)
4238
{
4339
return ProfilerInterceptor.GuardInternal(() =>
4440
{
4541
return Expression.Lambda<Action>(
46-
Expression.Assign(this.propertyExpression, Expression.Constant(value)));
42+
Expression.Assign(this.propertyExpression, Expression.Constant(value, typeof(T))));
43+
});
44+
}
45+
46+
public Expression<Action> Set(Expression<Func<T>> expression)
47+
{
48+
return ProfilerInterceptor.GuardInternal(() =>
49+
{
50+
return Expression.Lambda<Action>(
51+
Expression.Assign(this.propertyExpression, expression.Body));
4752
});
4853
}
4954

50-
/// <summary>
51-
/// Builds and expresison for getting the vlaue of a property.
52-
/// </summary>
5355
public Expression<Func<T>> Get()
5456
{
5557
return ProfilerInterceptor.GuardInternal(() =>

0 commit comments

Comments
 (0)