Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
611b33b
chore: remove useless code
alexgarzao Oct 26, 2025
e324603
feat: testgen building end-to-end tests
alexgarzao Oct 26, 2025
2cdca99
chore: turn public GenValidations api
alexgarzao Oct 26, 2025
c2142d2
feat: testgen bulding validation code tests
alexgarzao Oct 26, 2025
f6bdb38
test: add generated validation code test files
alexgarzao Oct 26, 2025
581fa9a
chore: makefile rule to build generated tests and move to the correct
alexgarzao Oct 26, 2025
98b323a
chore: add DO NOT EDIT to all templates
alexgarzao Oct 26, 2025
5591942
chore: fix DO NOT EDIT header
alexgarzao Oct 26, 2025
47d14f6
chore: better func name
alexgarzao Oct 26, 2025
64050fa
doc: initial testgen readme
alexgarzao Oct 27, 2025
2ee054c
chore: remove useless code
alexgarzao Oct 27, 2025
abc9fe5
feat: testgen generating tests to check function validate output
alexgarzao Oct 27, 2025
f06c1cb
test: commit tests generated by testgen
alexgarzao Oct 27, 2025
7bb3ad6
Merge branch 'main' into 93-testgen-function-code-tests
alexgarzao Oct 28, 2025
e0325e6
chore: remove use slice[n] to avoid panic
alexgarzao Oct 28, 2025
4f9fa12
chore: better way to chain calls in the makefile
alexgarzao Oct 28, 2025
427754d
chore: use bitfield to exclude tests to be generated
alexgarzao Oct 29, 2025
b205a3a
chore: add govalidator tag to generated cmp perf tests
alexgarzao Oct 29, 2025
8a8c8f8
feat: generate perf cmp tests in testgen
alexgarzao Oct 29, 2025
c09649e
chore: add generated perf tests
alexgarzao Oct 29, 2025
8b5e2b3
Merge branch 'main' into 93-testgen-generating-cmp-perf-tests
alexgarzao Oct 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ build: clean

testgen:
@echo "Generating tests"
cd testgen/ && rm -f generated_*.go && go run *.go && mv generated_endtoend_*tests.go ../tests/endtoend/ && mv generated_validation_*_test.go ../internal/codegenerator/ && mv generated_function_code_*_test.go ../internal/codegenerator/
cd testgen/ && rm -f generated_*.go && go run *.go && mv generated_endtoend_*tests.go ../tests/endtoend/ && mv generated_validation_*_test.go ../internal/codegenerator/ && mv generated_function_code_*_test.go ../internal/codegenerator/ && mv generated_cmp_perf_*.go ../tests/cmpbenchtests/generated_tests/

endtoendtests: build
@echo "Running endtoend tests"
Expand All @@ -41,7 +41,7 @@ endtoendtests: build

cmpbenchtests: build
@echo "Running cmp bench tests"
rm -f tests/cmpbenchtests/generated_tests/*
rm -f tests/cmpbenchtests/generated_tests/valid*.go && rm -f tests/cmpbenchtests/generated_tests/types.go
cd tests/cmpbenchtests; go run .
$(VALIDGEN_BIN) tests/cmpbenchtests/generated_tests
go clean -testcache
Expand Down
48 changes: 48 additions & 0 deletions testgen/cmp_perf_no_pointer_tests.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Code generated by TestGen. DO NOT EDIT.

package benchtests

import (
"testing"

"github.com/go-playground/validator/v10"
)

{{range .Tests}}
type ValidGen{{.TestName}}Struct struct {
Field {{.FieldType}} `valid:"{{.ValidGenTag}}"`
}

type Validator{{.TestName}}Struct struct {
Field {{.FieldType}} `validate:"{{.ValidatorTag}}"`
}
{{end}}

{{range .Tests}}
func BenchmarkValidGen{{.TestName}}(b *testing.B) {
data := &ValidGen{{.TestName}}Struct{
Field: {{.ValidInput}},
}

for b.Loop() {
if err := ValidGen{{.TestName}}StructValidate(data); len(err) > 0 {
b.FailNow()
}
}
}

func BenchmarkValidator{{.TestName}}(b *testing.B) {
var validate *validator.Validate

validate = validator.New(validator.WithRequiredStructEnabled())
data := &Validator{{.TestName}}Struct{
Field: {{.ValidInput}},
}

for b.Loop() {
if err := validate.Struct(data); err != nil {
b.FailNow()
}
}
}
{{end}}
52 changes: 52 additions & 0 deletions testgen/cmp_perf_pointer_tests.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Code generated by TestGen. DO NOT EDIT.

package benchtests

import (
"testing"

"github.com/go-playground/validator/v10"
)

{{range .Tests}}
type ValidGen{{.TestName}}Struct struct {
Field {{.FieldType}} `valid:"{{.ValidGenTag}}"`
}

type Validator{{.TestName}}Struct struct {
Field {{.FieldType}} `validate:"{{.ValidatorTag}}"`
}
{{end}}

{{range .Tests}}
func BenchmarkValidGen{{.TestName}}(b *testing.B) {
var validInput {{.BasicType}} = {{.ValidInput}}
data := &ValidGen{{.TestName}}Struct{
Field: &validInput,
}

for b.Loop() {
if err := ValidGen{{.TestName}}StructValidate(data); len(err) > 0 {
b.FailNow()
}
}
}

func BenchmarkValidator{{.TestName}}(b *testing.B) {
var validate *validator.Validate

validate = validator.New(validator.WithRequiredStructEnabled())

var validInput {{.BasicType}} = {{.ValidInput}}

data := &Validator{{.TestName}}Struct{
Field: &validInput,
}

for b.Loop() {
if err := validate.Struct(data); err != nil {
b.FailNow()
}
}
}
{{end}}
124 changes: 124 additions & 0 deletions testgen/generate_cmp_perf_tests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package main

import (
"bytes"
"fmt"
"go/format"
"log"
"os"
"strings"
"text/template"

"github.com/opencodeco/validgen/internal/common"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)

type CmpBenchTests struct {
Tests []CmpBenchTest
}

type CmpBenchTest struct {
TestName string
FieldType string
BasicType string
ValidGenTag string
ValidatorTag string
ValidInput string
}

func generateComparativePerformanceTests() {
generateComparativePerformanceTest("cmp_perf_no_pointer_tests.tpl", "generated_cmp_perf_no_pointer_test.go", false)
generateComparativePerformanceTest("cmp_perf_pointer_tests.tpl", "generated_cmp_perf_pointer_test.go", true)
}

func generateComparativePerformanceTest(tpl, dest string, pointer bool) {
log.Printf("Generating comparative performance tests file: tpl[%s] dest[%s] pointer[%v]\n", tpl, dest, pointer)

benchTests := CmpBenchTests{}

for _, typeVal := range typesValidation {
if typeVal.validatorTag == "" {
log.Printf("Skipping tag %s: go-validator tag not defined\n", typeVal.tag)
continue
}

for _, testCase := range typeVal.testCases {
if testCase.excludeIf&cmpBenchTests != 0 {
log.Printf("Skipping test: tag %s type %s\n", typeVal.tag, testCase.typeClass)
continue
}
if testCase.excludeIf&noPointer != 0 && !pointer {
log.Printf("Skipping no pointer: tag %s type %s\n", typeVal.tag, testCase.typeClass)
continue
}

normalizedType := testCase.typeClass
if pointer {
normalizedType = "*" + normalizedType
}

fTypes := common.HelperFromNormalizedToBasicTypes(normalizedType)
sNames := common.HelperFromNormalizedToStringNames(normalizedType)

for i := range fTypes {
validGenTag := typeVal.tag
if typeVal.argsCount != common.ZeroValue {
validGenTag += "=" + testCase.validation
}
goValidatorTag := typeVal.validatorTag
if typeVal.argsCount != common.ZeroValue {
goValidatorTag += "=" + testCase.validation
}
testName := cases.Title(language.Und).String(typeVal.tag) + sNames[i]

basicType, _ := strings.CutPrefix(fTypes[i], "*")

benchTests.Tests = append(benchTests.Tests, CmpBenchTest{
TestName: testName,
FieldType: fTypes[i],
BasicType: basicType,
ValidGenTag: validGenTag,
ValidatorTag: goValidatorTag,
ValidInput: strings.ReplaceAll(testCase.validCase, "{{.BasicType}}", basicType),
})
}
}
}

log.Printf("%d test cases were generated\n", len(benchTests.Tests))

if err := benchTests.GenerateFile(tpl, dest); err != nil {
log.Fatalf("error generating comparative performance tests file %s", err)
}

log.Println("Generating done")
}

func (cbt *CmpBenchTests) GenerateFile(tplFile, output string) error {
tpl, err := os.ReadFile(tplFile)
if err != nil {
return fmt.Errorf("error reading %s: %s", tplFile, err)
}

tmpl, err := template.New("BenchTest").Parse(string(tpl))
if err != nil {
return fmt.Errorf("error parsing template %s: %s", tplFile, err)
}

code := new(bytes.Buffer)
if err := tmpl.Execute(code, cbt); err != nil {
return err
}

formattedCode, err := format.Source(code.Bytes())
if err != nil {
return err
}

if err := os.WriteFile(output, formattedCode, 0644); err != nil {
return err
}

return nil
}
11 changes: 3 additions & 8 deletions testgen/generate_function_code_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,9 @@ func generateFunctionCodeTestsFile(tpl, dest string, pointer bool) {
}

for _, toGenerate := range typeValidation.testCases {
// Default ("") gen no pointer and pointer test.
if toGenerate.generateFor != "" {
if toGenerate.generateFor == "pointer" && !pointer {
continue
}
if toGenerate.generateFor == "nopointer" && pointer {
continue
}
if toGenerate.excludeIf&noPointer != 0 && !pointer {
log.Printf("Skipping no pointer: tag %s type %s\n", typeValidation.tag, toGenerate.typeClass)
continue
}

normalizedType := toGenerate.typeClass
Expand Down
1 change: 1 addition & 0 deletions testgen/generate_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ func main() {
generateValidationTypesEndToEndTests()
generateValidationCodeUnitTests()
generateFunctionCodeUnitTests()
generateComparativePerformanceTests()

fmt.Println("Generating done")
}
11 changes: 3 additions & 8 deletions testgen/generate_validation_code_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,9 @@ func generateValidationCodeTestsFile(tpl, dest string, pointer bool) {

for _, typeValidation := range typesValidation {
for _, toGenerate := range typeValidation.testCases {
// Default ("") gen no pointer and pointer test.
if toGenerate.generateFor != "" {
if toGenerate.generateFor == "pointer" && !pointer {
continue
}
if toGenerate.generateFor == "nopointer" && pointer {
continue
}
if toGenerate.excludeIf&noPointer != 0 && !pointer {
log.Printf("Skipping no pointer: tag %s type %s\n", typeValidation.tag, toGenerate.typeClass)
continue
}

normalizedType := toGenerate.typeClass
Expand Down
12 changes: 4 additions & 8 deletions testgen/generate_validation_types_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,11 @@ func generateValidationTypesTestsFile(tpl, dest string, pointer bool) {
StructName: structName,
})
for _, toGenerate := range testCase.testCases {
// Default ("") gen no pointer and pointer test.
if toGenerate.generateFor != "" {
if toGenerate.generateFor == "pointer" && !pointer {
continue
}
if toGenerate.generateFor == "nopointer" && pointer {
continue
}
if toGenerate.excludeIf&noPointer != 0 && !pointer {
log.Printf("Skipping no pointer: tag %s type %s\n", testCase.tag, toGenerate.typeClass)
continue
}

normalizedType := toGenerate.typeClass
if pointer {
normalizedType = "*" + normalizedType
Expand Down
Loading
Loading