Skip to content

Invalid Property Setter Expectations are Not Handled Correctly #392

@JasonBock

Description

@JasonBock

To Reproduce

public interface IInterfaceProperty
{
	int GetAndSetData { get; set; }
}

[Test]
public static void Invalid()
{
	using var context = new RockContext();
	var expectations = context.Create<IInterfacePropertyCreateExpectations>();
	expectations.Properties.Setters.SetData(3);

	var mock = expectations.Instance();
	mock.SetData = 4;
}

Expected behavior
This should fail with an ExpectationException.

Actual behavior

Rocks.Exceptions.VerificationException : The following verification failure(s) occurred: Mock type: Rocks.Analysis.IntegrationTests.InterfacePropertyTestTypes.IInterfacePropertyCreateExpectations+Mock, member: Void set_SetData(Int32), message: The expected call count is incorrect. Expected: 1, received: 0.

Additional context
The problem is that the generated code seems incorrect. Currently, it does this:

set
{
    if (this.Expectations.handlers4 is not null)
    {
        var @foundMatch = false;
        foreach (var @handler in this.Expectations.handlers4)
        {
            if (@handler.value.IsValid(value!))
            {
                @handler.CallCount++;
                @foundMatch = true;
                @handler.Callback?.Invoke(value!);
                
                if (!@foundMatch)
                {
                    this.Expectations.WasExceptionThrown = true;
                    throw new global::Rocks.Exceptions.ExpectationException(
                        $"""
                        No handlers match for {this.GetType().GetMemberDescription(4)}
                            value: {@value.FormatValue()}
                        """);
                }
                
                @handler.RaiseEvents(this);
                break;
            }
        }
    }
    else
    {
        this.Expectations.WasExceptionThrown = true;
        throw new global::Rocks.Exceptions.ExpectationException(
            $"""
            No handlers were found for {this.GetType().GetMemberDescription(4)}
                value: {@value.FormatValue()}
            """);
    }
}

What I think it should do is move the if within the foreach outside of it:

set
{
    if (this.Expectations.handlers4 is not null)
    {
        var @foundMatch = false;
        foreach (var @handler in this.Expectations.handlers4)
        {
            if (@handler.value.IsValid(value!))
            {
                @handler.CallCount++;
                @foundMatch = true;
                @handler.Callback?.Invoke(value!);
                @handler.RaiseEvents(this);
                break;
            }
        }

        if (!@foundMatch)
        {
            this.Expectations.WasExceptionThrown = true;
            throw new global::Rocks.Exceptions.ExpectationException(
                $"""
                No handlers match for {this.GetType().GetMemberDescription(4)}
                    value: {@value.FormatValue()}
                """);
        }
    }
    else
    {
        this.Expectations.WasExceptionThrown = true;
        throw new global::Rocks.Exceptions.ExpectationException(
            $"""
            No handlers were found for {this.GetType().GetMemberDescription(4)}
                value: {@value.FormatValue()}
            """);
    }
}

This way, it will throw ExpectationException when there no match was found.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions