Skip to content

feat(mock): Add comprehensive enum field support in mock generator #30

@SebastienMelki

Description

@SebastienMelki

Feature Description

The mock generator currently has a TODO comment for enum fields. This feature will add full support for generating mock data for enum fields, including both single and repeated enum fields.

Current State

When encountering enum fields, the generator outputs:

// TODO: Handle field FieldName of type EnumKind

Proposed Solution

1. Implement Enum Field Generation

Add a new case in generateMockFieldAssignments for protoreflect.EnumKind:

case protoreflect.EnumKind:
    enumType := field.Enum.GoIdent
    if field.Desc.IsList() {
        gf.P(varName, ".", fieldName, " = []", enumType, "{")
        for i := 0; i < defaultListSize; i++ {
            gf.P("selectEnumValue(\"", fieldPath, "\", ", 
                field.Enum.Values[0].GoIdent, ", ",
                "[]", enumType, "{")
            for _, val := range field.Enum.Values {
                gf.P(val.GoIdent, ",")
            }
            gf.P("}),")
        }
        gf.P("}")
    } else {
        gf.P(varName, ".", fieldName, " = selectEnumValue(\"", fieldPath, "\", ",
            field.Enum.Values[0].GoIdent, ", ",
            "[]", enumType, "{")
        for _, val := range field.Enum.Values {
            gf.P(val.GoIdent, ",")
        }
        gf.P("})")
    }

2. Add Enum Selection Helper

Create a helper function to select enum values intelligently:

// selectEnumValue selects an enum value from examples or available values
func selectEnumValue[T ~int32](fieldPath string, defaultValue T, availableValues []T) T {
    // First try to use example from fieldExamples
    if examples, ok := fieldExamples[fieldPath]; ok && len(examples) > 0 {
        example := examples[rand.Intn(len(examples))]
        // Try to match example string to enum value name
        for _, val := range availableValues {
            if enumName(val) == example {
                return val
            }
        }
        // Try parsing as integer
        if v, err := strconv.Atoi(example); err == nil {
            return T(v)
        }
    }
    
    // Randomly select from available values
    if len(availableValues) > 0 {
        return availableValues[rand.Intn(len(availableValues))]
    }
    
    return defaultValue
}

3. Handle Enum Examples in Field Collection

Update collectMessageFieldExamples to extract enum value names as examples:

if field.Desc.Kind() == protoreflect.EnumKind {
    // Add enum value names as examples
    for _, val := range field.Enum.Values {
        examples = append(examples, string(val.Desc.Name()))
    }
}

4. Support for Proto Enum Options

Consider enum options like deprecated values:

  • Skip deprecated enum values by default
  • Add configuration to include/exclude specific values
  • Respect custom enum annotations if present

Implementation Considerations

  1. Type Safety: Use generics where possible for enum handling
  2. Value Distribution: Ensure good distribution across enum values
  3. Zero Values: Handle enums with explicit zero values properly
  4. Unknown Values: Skip "UNKNOWN" or "UNSPECIFIED" values unless no other options

Testing Requirements

  • Proto files with various enum types (simple, with zero value, deprecated values)
  • Test repeated enum fields
  • Verify correct enum type usage in generated code
  • Test enums with custom value assignments

Files Affected

  • internal/httpgen/mock_generator.go - Add enum case and helper
  • internal/httpgen/mock_generator.go - Update generateMockHelpers
  • internal/httpgen/testdata/proto/*.proto - Add enum test cases
  • internal/httpgen/testdata/golden/*_http_mock.pb.go - Update golden files

Success Criteria

  • Single enum fields generate valid values
  • Repeated enum fields generate slices with valid values
  • Enum values are randomly distributed
  • Generated code compiles without errors
  • Respects enum constraints (deprecated, custom options)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions