Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ed8e415
feat: add bootstrap files needed to create repo tests
manicar2093 Aug 8, 2025
c894282
feat: add goption.go in testfunc to not repeat GetValue() string in t…
manicar2093 Aug 14, 2025
b396a2f
test: add fixtures for test creation
manicar2093 Aug 14, 2025
8f84782
feat: add suite test on repo creation
manicar2093 Aug 23, 2025
c95c0e2
feat: add repository testing
manicar2093 Aug 29, 2025
ed6030d
feat: add succeed and curly braces in needed places
manicar2093 Sep 4, 2025
8321093
chore: remove unused imports to repo testing
manicar2093 Sep 4, 2025
f69401a
test: add changes to test to match changes on imports and curly braces
manicar2093 Sep 4, 2025
408e2ba
feat: add partial update generator and move it to models generation
manicar2093 Sep 4, 2025
74df0b8
feat: add changes into controller due partial update model
manicar2093 Sep 4, 2025
9cbb110
feat: remove unused imports due partial update struct was move to models
manicar2093 Sep 4, 2025
d27a57a
feat: add correct name to partial update struct generator
manicar2093 Sep 4, 2025
16ee316
chore: change logs in generators removing used packages names
manicar2093 Sep 4, 2025
f6fbe02
feat: add ginkgo to go tools
manicar2093 Sep 4, 2025
fe1d2e6
fix: change test data to correct snake case going from data_32 to data32
manicar2093 Sep 5, 2025
3a08f57
feat: add bool and enum handling on repo testing and generators
manicar2093 Sep 5, 2025
1e4665d
docs: add readme documentation marking Create CRUD testing task :D
manicar2093 Sep 5, 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
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,19 @@ Now the only thing to notice is all dates are handled as UTC and show as Local w
- [X] Create models
- [X] Create migrations with Prisma
- [X] Create CRUD repository
- [ ] Create CRUD testing
- [X] Create CRUD testing
- [X] Create all at once: controller, model, migration and repository
- [ ] Create API documentation
- [ ] Create auth implementation
- [X] Add CRUD HTML templates
- [ ] Add CRUD HTML testing
- [ ] Add API testing

## Known Issues

- On PartialUpdateById test bool and enums (and it optional variations) has no random validations. This is due bool just has 2 possible values and enums can have from 1 to many. This makes it hard to randomize tests.
- On command when writing an attribute called data_32 snake case is not well converted. This can cause problems with Gorm ORM due gorm will transform it to data32 and model will be data_32. Horrible, but avoidable if not use _ in attributes declaration

## License

This project is licensed under the MIT License - see the LICENSE file for details.
32 changes: 29 additions & 3 deletions bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import (
"embed"
"errors"
"fmt"
"github.com/charmbracelet/log"
"github.com/manicar2093/gomancer/deps"
"github.com/manicar2093/gomancer/domain"
"net/url"
"os"
"path"
"strings"
"text/template"

"github.com/charmbracelet/log"
"github.com/manicar2093/gomancer/deps"
"github.com/manicar2093/gomancer/domain"
)

//go:embed templates/*
Expand Down Expand Up @@ -42,6 +43,10 @@ var (
".env",
"env_file",
},
{
".env.test",
"env_test_file",
},
{
"package.json",
"package_json",
Expand Down Expand Up @@ -124,6 +129,27 @@ var (
"generators.go",
"pkg_generators_generators",
},
{
"db.go",
"pkg_generators_db",
},
{
"slices.go",
"pkg_generators_slices",
},
},
},
{
string(domain.PkgTestfuncPackagePath),
[]fileWithContent{
{
"db.go",
"pkg_testfunc_db",
},
{
"goption.go",
"pkg_testfunc_goption",
},
},
},
{
Expand Down
103 changes: 100 additions & 3 deletions bootstrap/bootstrap_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package bootstrap_test

import (
"os"
"path"

"github.com/manicar2093/gomancer/bootstrap"
"github.com/manicar2093/gomancer/testmatchers"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"os"
"path"
)

var _ = Describe("Main", Ordered, func() {
Expand Down Expand Up @@ -41,11 +42,20 @@ var _ = Describe("Main", Ordered, func() {
content := `DATABASE_URL="postgresql://development:development@localhost:5432/test_dev?sslmode=disable"
ENVIRONMENT=dev
PORT=3000
SESSION_SECRET_KEY=session_secret_key
SESSION_SECRET_KEY=session_secret_key_dev
`
Expect(dirWithPath(".env")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates .env.test file", func() {
content := `DATABASE_URL="postgresql://development:development@localhost:5432/test_test?sslmode=disable"
ENVIRONMENT=test
PORT=3000
SESSION_SECRET_KEY=session_secret_key_test
`
Expect(dirWithPath(".env.test")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates package.json file", func() {
content := `{
"devDependencies": {
Expand Down Expand Up @@ -220,6 +230,85 @@ func decode(t testingI, args map[string]any, holder any) {
Expect(dirWithPath("pkg/generators/generators.go")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates pkg/generators/db.go file", func() {
content := `package generators

import (
connections "test/core/connections"
errors "errors"
gorm "gorm.io/gorm"
)

func CreateOrFail(t testingI, dbConn *connections.ConnWrapper, data any) {
res := dbConn.Create(data)
if res.Error != nil {
t.Fatal(res.Error)
}
}

func FirstOrFail[T any](t testingI, dbConn *connections.ConnWrapper, conds ...any) *T {
var dest T
if res := dbConn.First(&dest, conds...); res.Error != nil {
t.Fatal(res.Error)
}

return &dest
}

func NotFoundOrFail[T any](t testingI, dbConn *connections.ConnWrapper, conds ...any) {
var dest T
if res := dbConn.First(&dest, conds...); res.Error != nil {
if !errors.Is(res.Error, gorm.ErrRecordNotFound) {
t.Fatal(res.Error)
}
}
}
`
Expect(dirWithPath("pkg/generators/db.go")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates pkg/generators/slices.go file", func() {
content := `package generators

func Slice[T any](generator func() T, count int) []T {
ret := make([]T, count)
for i := 0; i < count; i++ {
ret[i] = generator()
}
return ret
}
`
Expect(dirWithPath("pkg/generators/slices.go")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates pkg/testfunc/db.go file", func() {
content := `// Package testfunc contains utility functions to run tests with ease
package testfunc

import (
core "test/core"
connections "test/core/connections"
converters "test/core/converters"
)

func GetTestingGormDB() *connections.ConnWrapper {
conf := converters.Must(core.ParseConfig[connections.DatabaseConnectionConfig]())
return connections.GetGormConnection(conf)
}
`
Expect(dirWithPath("pkg/testfunc/db.go")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates pkg/testfunc/goption.go file", func() {
content := `package testfunc

const (
GetValueMethod = "GetValue()"
)
`
Expect(dirWithPath("pkg/testfunc/goption.go")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})

It("creates pkg/config/config.go file", func() {
content := `// Package config contains a struct with all your API configs
package config
Expand Down Expand Up @@ -305,6 +394,7 @@ tool (
github.com/a-h/templ/cmd/templ
github.com/air-verse/air
github.com/templui/templui/cmd/templui
github.com/onsi/ginkgo/v2/ginkgo
)
`
Expect(dirWithPath("go.mod")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
Expand Down Expand Up @@ -340,6 +430,13 @@ tasks:
deps: [build]
cmds:
- ./.bin/service/server
test:
desc: Run migrations, all tests and reset migrations using .env.test environment file
dotenv: ['.env.test']
cmds:
- npx prisma migrate dev --skip-seed
- go tool ginkgo run -v ./...
- npx prisma migrate reset --force
`
Expect(dirWithPath("Taskfile.yml")).Should(testmatchers.BeAnExistingFileAndEqualString(content))
})
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/templates/env_file.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{ define "env_file" }}DATABASE_URL="postgresql://development:development@localhost:5432/{{.ProjectName}}_{{.DevEnvironment}}?sslmode=disable"
ENVIRONMENT={{.DevEnvironment}}
PORT=3000
SESSION_SECRET_KEY=session_secret_key
SESSION_SECRET_KEY=session_secret_key_{{.DevEnvironment}}
{{end}}
5 changes: 5 additions & 0 deletions bootstrap/templates/env_test_file.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{ define "env_test_file" }}DATABASE_URL="postgresql://development:development@localhost:5432/{{.ProjectName}}_{{.TestEnvironment}}?sslmode=disable"
ENVIRONMENT={{.TestEnvironment}}
PORT=3000
SESSION_SECRET_KEY=session_secret_key_{{.TestEnvironment}}
{{end}}
1 change: 1 addition & 0 deletions bootstrap/templates/go.mod.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ tool (
{{"\t"}}github.com/a-h/templ/cmd/templ
{{"\t"}}github.com/air-verse/air
{{"\t"}}github.com/templui/templui/cmd/templui
{{"\t"}}github.com/onsi/ginkgo/v2/ginkgo
)
{{ end }}
33 changes: 33 additions & 0 deletions bootstrap/templates/pkg_generators_db.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{{ define "pkg_generators_db" }}package generators

import (
{{.GoDeps.Project.Core.Connections.GenerateImportString}}
{{.GoDeps.Std.Errors.GenerateImportString}}
{{.GoDeps.Gorm.GenerateImportString}}
)

func CreateOrFail(t testingI, dbConn *connections.ConnWrapper, data any) {
res := dbConn.Create(data)
if res.Error != nil {
t.Fatal(res.Error)
}
}

func FirstOrFail[T any](t testingI, dbConn *connections.ConnWrapper, conds ...any) *T {
var dest T
if res := dbConn.First(&dest, conds...); res.Error != nil {
t.Fatal(res.Error)
}

return &dest
}

func NotFoundOrFail[T any](t testingI, dbConn *connections.ConnWrapper, conds ...any) {
var dest T
if res := dbConn.First(&dest, conds...); res.Error != nil {
if !errors.Is(res.Error, gorm.ErrRecordNotFound) {
t.Fatal(res.Error)
}
}
}
{{ end }}
10 changes: 10 additions & 0 deletions bootstrap/templates/pkg_generators_slices.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{{ define "pkg_generators_slices" }}package generators

func Slice[T any](generator func() T, count int) []T {
ret := make([]T, count)
for i := 0; i < count; i++ {
ret[i] = generator()
}
return ret
}
{{ end }}
14 changes: 14 additions & 0 deletions bootstrap/templates/pkg_testfunc_db.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{ define "pkg_testfunc_db" }}// Package testfunc contains utility functions to run tests with ease
package testfunc

import (
{{.GoDeps.Project.Core.GenerateImportString}}
{{.GoDeps.Project.Core.Connections.GenerateImportString}}
{{.GoDeps.Project.Core.Converters.GenerateImportString}}
)

func GetTestingGormDB() *connections.ConnWrapper {
conf := converters.Must(core.ParseConfig[connections.DatabaseConnectionConfig]())
return connections.GetGormConnection(conf)
}
{{ end }}
6 changes: 6 additions & 0 deletions bootstrap/templates/pkg_testfunc_goption.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{ define "pkg_testfunc_goption" }}package testfunc

const (
GetValueMethod = "GetValue()"
)
{{ end }}
7 changes: 7 additions & 0 deletions bootstrap/templates/taskfile.yml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@ tasks:
deps: [build]
cmds:
- ./.bin/service/server
test:
desc: Run migrations, all tests and reset migrations using .env.test environment file
dotenv: ['.env.test']
cmds:
- npx prisma migrate dev --skip-seed
- go tool ginkgo run -v ./...
- npx prisma migrate reset --force
{{ end }}
5 changes: 3 additions & 2 deletions cmd/gen.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cmd

import (
"os"

"github.com/charmbracelet/log"
"github.com/manicar2093/gomancer/controllers/echoimpl"
"github.com/manicar2093/gomancer/deps"
Expand All @@ -10,7 +12,6 @@ import (
"github.com/manicar2093/gomancer/parser"
"github.com/manicar2093/gomancer/repositories/gormimpl"
"github.com/spf13/cobra"
"os"
)

var GenCmd = &cobra.Command{
Expand Down Expand Up @@ -70,7 +71,7 @@ gomancer gen Client name:string dob:time:optional status:enum/active/deactivated
log.Error(err)
return
}
if err := gormimpl.GenerateRepository(input, goDeps); err != nil {
if err := gormimpl.GenerateRepository(input, goDeps, inCreation); err != nil {
log.Error(err)
return
}
Expand Down
2 changes: 1 addition & 1 deletion controllers/echoimpl/fixtures/rest_controller.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (c *PostTestController) GetAllPaginatedHandler(ctx echo.Context) error {
}

func (c *PostTestController) PartialUpdateByIdHandler(ctx echo.Context) error {
req := posttests.PartialUpdateByIdInput{}
req := models.PostTestPartialUpdateByIdInput{}
if err := core.BindAndValidate(ctx, &req); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion controllers/echoimpl/fixtures/web_controller.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (c *PostTestWebController) GetAllPaginatedHandler(ctx echo.Context) error {
}

func (c *PostTestWebController) PartialUpdateByIdHandler(ctx echo.Context) error {
req := posttests.PartialUpdateByIdInput{}
req := models.PostTestPartialUpdateByIdInput{}
if err := core.BindAndValidate(ctx, &req); err != nil {
return err
}
Expand Down
Loading
Loading