How to exclude certain enumerations from all enumeration types
Asked Answered
L

1

4

I am trying to exclude certain enumeration values such as Unknown and Uninitialized from the set of values for any enumeration type.

I can see that Enums are generated in a round robin fashion using the EnumGenerator from the set of all possible Enum values for a given Enum type.

Based on that code, my first thought is to build an ISpecimenBuilder that checks for Type.IsEnum and does a context.Resolve(request) until Resolve returns a value that is not on the excluded list.

The problem is this gives me a recursion error. After inspecting the source code I understand why - if a builder handles a request and calls another Resolve again with the same request you will end up in an infinite loop.

But as EnumGenerator is not extensible, and I can't figure out how to intercept the build chain I am stumped as to how to solve this.

Listed answered 13/1, 2017 at 6:20 Comment(0)
C
7

You can create a custom Specimen Builder that uses the existing EnumGenerator but skips the values you don't need. In this specimen I use the specimen.ToString() method intentionally in order not to be linked to any particular enum type:

public class ExcludeUnknownEnumGenerator : ISpecimenBuilder
{
    private readonly EnumGenerator _enumGenerator = new EnumGenerator();

    public object Create(object request, ISpecimenContext context)
    {
        var enumType = request as Type;
        if (enumType == null || !enumType.IsEnum)
        {
            return new NoSpecimen();
        }

        var namesEnumerator = Enum.GetNames(enumType).GetEnumerator();
        while (namesEnumerator.MoveNext())
        {
            var specimen = _enumGenerator.Create(request, context);
            if (specimen.ToString() != "Unknown" &&
                specimen.ToString() != "Uninitialized")
            {
                return specimen;
            }
        }

        throw new ObjectCreationException(
            "AutoFixture was unable to create a value for " +
            enumType.FullName +
            " since it is an enum containing either no values or " +
            "ignored values only ('Unknown' and 'Uninitialized'). " +
            "Please add at least one valid value to the enum.");
    }
}

public enum EnumWithUnknown
{
    Known,
    Unknown,
    Wellknown,
    Uninitialized
}

The following code shows enum values without the Unknown and Uninitialized states:

var fixture = new Fixture();
fixture.Customizations.Insert(0, new ExcludeUnknownEnumGenerator());

Console.Out.WriteLine("result = {0}", fixture.Create<EnumWithUnknown>());
Console.Out.WriteLine("result = {0}", fixture.Create<EnumWithUnknown>());
Console.Out.WriteLine("result = {0}", fixture.Create<EnumWithUnknown>());
Console.Out.WriteLine("result = {0}", fixture.Create<EnumWithUnknown>());

*** ConsoleOutput ***

result = Known
result = Wellknown
result = Known
result = Wellknown
Classicize answered 16/1, 2017 at 9:25 Comment(3)
Wouldn't it be easier to decorate the existing EnumGenerator?Girosol
I do call the EnumGenerator class in the Create method. When you say 'easier', do you mean shrinking the Create method somehow?Classicize
Please accept my apologies; I didn't read the code thoroughly enough before I wrote that comment.Girosol

© 2022 - 2024 — McMap. All rights reserved.