+ Сценарий: Добавление сгенерированных функций в test-файл

Этот коммит содержится в:
Softonik 2025-06-05 02:06:15 +03:00
родитель 4e3e82b79e
коммит 6f2a5fef98
6 изменённых файлов: 293 добавлений и 0 удалений

99
pkg/formatters/ast/ast.go Обычный файл
Просмотреть файл

@ -0,0 +1,99 @@
package ast
import (
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
"errors"
)
type ASTer struct {
pkg string
fname string
fset *token.FileSet
node *ast.File
}
func NewASTer() (*ASTer, error) {
a := &ASTer{}
pkg, err := получитьИмяGoПакетаВЭтойДире()
if err != nil {
return nil, err
}
a.pkg = pkg
err = a.найтиТестовыйФайл()
if err != nil {
return nil, err
}
return a, nil
}
func (a *ASTer) ДобавитьТестовуюФункцию(func_name string) error {
return a.добавитьвФайлФункцию(func_name)
}
func (a *ASTer) найтиТестовыйФайл() error {
a.сгенеритьИмяФайла()
_, err := os.Stat(a.fname)
return err
}
func (a *ASTer) сгенеритьИмяФайла() {
a.fname = a.pkg + "_test.go"
}
func (a *ASTer) добавитьвФайлФункцию(func_name string) error {
err := a.спарситьФайлиДобавитьФункцию(func_name)
if err != nil {
return err
}
return a.перезаписатьФайл()
}
func (a *ASTer) спарситьФайлиДобавитьФункцию(func_name string) error {
err := a.спарситьФайл()
if err != nil {
return err
}
fun := a.пустаяФункция(func_name)
a.node.Decls = append(a.node.Decls, fun)
return nil
}
func (a *ASTer) спарситьФайл() error {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, a.fname, nil, parser.ParseComments)
a.fset = fset
a.node = node
return err
}
func (a *ASTer) пустаяФункция(func_name string) *ast.FuncDecl {
return &ast.FuncDecl{
Name: ast.NewIdent(func_name),
Type: &ast.FuncType{
Params: &ast.FieldList{},
Results: &ast.FieldList{},
},
Body: &ast.BlockStmt{},
}
}
func (a *ASTer) перезаписатьФайл() error {
err := переименоватьФайлСоВременем(a.fname)
if err != nil {
return errors.Join(err, errors.New("cant backup orig file"))
}
f, err := os.Create(a.fname)
if err != nil {
return errors.Join(err, errors.New("cant rewrite orig file"))
}
defer f.Close()
return format.Node(f, a.fset, a.node)
}

68
pkg/formatters/ast/ast_test.go Обычный файл
Просмотреть файл

@ -0,0 +1,68 @@
package ast
import (
"os"
"path/filepath"
"git.golang1.ru/softonik/godog"
"git.golang1.ru/softonik/godog/pkg/lib"
. "git.golang1.ru/softonik/godog_and_gomega"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/format"
)
type testData struct {
tempdir string
}
var (
t *testData
)
func resetTestData() {
t = &testData{}
}
func beforeSuite() {
CharactersAroundMismatchToInclude = 20
}
func afterSuite() {
}
func beforeScenario() {
resetTestData()
createTempDir()
}
func afterScenario() {
rmTempDir()
}
func createTempDir() {
dir := filepath.Clean(os.TempDir())
tempDir, err := os.MkdirTemp(dir, "test-")
Ok(err)
t.tempdir = tempDir
err = os.Chdir(t.tempdir)
Ok(err)
}
func rmTempDir() {
err := os.RemoveAll(t.tempdir)
Ok(err)
}
// -----------------------
func файл(fname string, content *godog.DocString) {
err := lib.WriteFile(fname, content.Content)
Ok(err)
}
func добавленаТестоваяФункция(func_name string) {
err := ДобавитьТестовуюФункцию(func_name)
Ok(err)
}
func файлДолженСодержать(fname string, content *godog.DocString) {
cont, err := lib.ReadFile(fname)
Ok(err)
Ω(cont).To(Be(content.Content))
}

18
pkg/formatters/ast/features/app.feature Обычный файл
Просмотреть файл

@ -0,0 +1,18 @@
# language: ru
Функционал: AST-редактир go-файлов
Сгенерированные функции автоматически добавляются в тест-файл текущего пакета
Сценарий: Добавление сгенерированных функций в тест-файл
Дано Файл "mypkg_test.go":
```
package mypkg
```
Когда Добавлена тестовая функция "ПриветМир"
То Файл "mypkg_test.go" должен содержать:
```
package mypkg
func ПриветМир() {
}
```

10
pkg/formatters/ast/global.go Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
package ast
func ДобавитьТестовуюФункцию(f string) error {
a, err := NewASTer()
if err != nil {
return err
}
return a.ДобавитьТестовуюФункцию(f)
}

50
pkg/formatters/ast/helpers.go Обычный файл
Просмотреть файл

@ -0,0 +1,50 @@
package ast
import (
"fmt"
"go/parser"
"go/token"
"os"
"path/filepath"
"time"
"errors"
)
func получитьИмяGoПакетаВЭтойДире() (pkg_name string, err_ret error) {
err_ret = errors.New("not found")
filepath.WalkDir(".", func(path string, info os.DirEntry, err error) error {
if err != nil {
return err
}
if !info.IsDir() && filepath.Ext(path) == ".go" {
pkg, err := получитьИмяGoПакетаФайла(path)
if err != nil {
return err
}
pkg_name = pkg
err_ret = nil
return filepath.SkipDir
}
return nil
})
return
}
func получитьИмяGoПакетаФайла(fname string) (string, error) {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, fname, nil, parser.PackageClauseOnly)
if err != nil {
return "", err
}
return node.Name.Name, nil
}
func переименоватьФайлСоВременем(fname string) error {
currentTime := time.Now()
timestamp := currentTime.Format("20060102_150405")
new_fname := fmt.Sprintf("%v_%v", fname, timestamp)
return os.Rename(fname, new_fname)
}

48
pkg/formatters/ast/init_test.go Обычный файл
Просмотреть файл

@ -0,0 +1,48 @@
package ast
import (
"context"
"os"
"testing"
"git.golang1.ru/softonik/godog"
"git.golang1.ru/softonik/godog/colors"
. "git.golang1.ru/softonik/godog_and_gomega"
)
func InitializeScenario(ctx *godog.ScenarioContext) {
ctx.Step(`^Файл "([^"]*)":$`, файл)
ctx.Step(`^Добавлена тестовая функция "([^"]*)"$`, добавленаТестоваяФункция)
ctx.Step(`^Файл "([^"]*)" должен содержать:$`, файлДолженСодержать)
// -----------------------
ctx.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
beforeScenario()
return ctx, nil
})
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
afterScenario()
return ctx, nil
})
InitializeGomegaForGodog(ctx)
}
func InitializeSuite(tsc *godog.TestSuiteContext) {
tsc.BeforeSuite(beforeSuite)
tsc.AfterSuite(afterSuite)
}
func TestMain(m *testing.M) {
var opts = godog.Options{
Output: colors.Colored(os.Stdout),
Strict: true,
StopOnFailure: true,
}
r := godog.TestSuite{
Name: "app",
TestSuiteInitializer: InitializeSuite,
ScenarioInitializer: InitializeScenario,
Options: &opts,
}.Run()
os.Exit(r)
}