diff --git a/README.md b/README.md
index e6ca62908..4a7fb3d2d 100644
--- a/README.md
+++ b/README.md
@@ -68,6 +68,7 @@ This project exists thanks to all the people who contribute, to participate in t
+
## Group
diff --git a/README_zh.md b/README_zh.md
index d1e3ea87b..dae6bcb4c 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -66,6 +66,7 @@ Laravel!
+
## 群组
diff --git a/foundation/application.go b/foundation/application.go
index c162d31d5..f2ae8c556 100644
--- a/foundation/application.go
+++ b/foundation/application.go
@@ -18,6 +18,8 @@ var (
App foundation.Application
)
+var flagEnv = flag.String("env", ".env", "custom .env path")
+
func init() {
setEnv()
@@ -46,6 +48,7 @@ func (app *Application) Boot() {
app.registerConfiguredServiceProviders()
app.bootConfiguredServiceProviders()
app.registerCommands([]consolecontract.Command{
+ console.NewTestMakeCommand(),
console.NewPackageMakeCommand(),
console.NewVendorPublishCommand(app.publishes, app.publishGroups),
})
@@ -183,16 +186,32 @@ func setEnv() {
}
}
- var env *string
- if !flag.Parsed() && support.Env != support.EnvTest {
- env = flag.String("env", ".env", "custom .env path")
- flag.Parse()
- } else {
- testEnv := ".env"
- env = &testEnv
+ env := getEnvPath()
+ if support.Env == support.EnvTest {
+ var (
+ relativePath string
+ envExist bool
+ testEnv = env
+ )
+
+ for i := 0; i < 50; i++ {
+ if _, err := os.Stat(testEnv); err == nil {
+ envExist = true
+
+ break
+ } else {
+ testEnv = filepath.Join("../", testEnv)
+ relativePath = filepath.Join("../", relativePath)
+ }
+ }
+
+ if envExist {
+ env = testEnv
+ support.RelativePath = relativePath
+ }
}
- support.EnvPath = *env
+ support.EnvPath = env
}
func setRootPath() {
@@ -206,3 +225,34 @@ func setRootPath() {
support.RootPath = rootPath
}
+
+func getEnvPath() string {
+ envPath := ".env"
+ args := os.Args
+ for index, arg := range args {
+ if strings.HasPrefix(arg, "--env=") {
+ path := strings.TrimPrefix(arg, "--env=")
+
+ if path != "" {
+ envPath = path
+ break
+ }
+ }
+ if strings.HasPrefix(arg, "-env=") {
+ path := strings.TrimPrefix(arg, "-env=")
+
+ if path != "" {
+ envPath = path
+ break
+ }
+ }
+ if arg == "--env" || arg == "-env" {
+ if len(args) >= index+1 && !strings.HasPrefix(args[index+1], "-") {
+ envPath = args[index+1]
+ break
+ }
+ }
+ }
+
+ return envPath
+}
diff --git a/foundation/console/stubs.go b/foundation/console/stubs.go
new file mode 100644
index 000000000..3bcaffd10
--- /dev/null
+++ b/foundation/console/stubs.go
@@ -0,0 +1,38 @@
+package console
+
+type Stubs struct {
+}
+
+func (r Stubs) Test() string {
+ return `package DummyPackage
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/suite"
+
+ "goravel/tests"
+)
+
+type DummyTestSuite struct {
+ suite.Suite
+ tests.TestCase
+}
+
+func TestDummyTestSuite(t *testing.T) {
+ suite.Run(t, new(DummyTestSuite))
+}
+
+// SetupTest will run before each test in the suite.
+func (s *UserTestSuite) SetupTest() {
+}
+
+// TearDownTest will run after each test in the suite.
+func (s *UserTestSuite) TearDownTest() {
+}
+
+func (s *UserTestSuite) TestIndex() {
+ // TODO
+}
+`
+}
diff --git a/foundation/console/test_make_command.go b/foundation/console/test_make_command.go
new file mode 100644
index 000000000..72c3746fd
--- /dev/null
+++ b/foundation/console/test_make_command.go
@@ -0,0 +1,99 @@
+package console
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/gookit/color"
+
+ "github.com/goravel/framework/contracts/console"
+ "github.com/goravel/framework/contracts/console/command"
+ "github.com/goravel/framework/support/file"
+ "github.com/goravel/framework/support/str"
+)
+
+type TestMakeCommand struct {
+}
+
+func NewTestMakeCommand() *TestMakeCommand {
+ return &TestMakeCommand{}
+}
+
+// Signature The name and signature of the console command.
+func (receiver *TestMakeCommand) Signature() string {
+ return "make:test"
+}
+
+// Description The console command description.
+func (receiver *TestMakeCommand) Description() string {
+ return "Create a new test class"
+}
+
+// Extend The console command extend.
+func (receiver *TestMakeCommand) Extend() command.Extend {
+ return command.Extend{
+ Category: "make",
+ }
+}
+
+// Handle Execute the console command.
+func (receiver *TestMakeCommand) Handle(ctx console.Context) error {
+ name := ctx.Argument(0)
+ if name == "" {
+ return errors.New("Not enough arguments (missing: name) ")
+ }
+
+ stub := receiver.getStub()
+
+ if err := file.Create(receiver.getPath(name), receiver.populateStub(stub, name)); err != nil {
+ return err
+ }
+
+ color.Greenln("Test created successfully")
+
+ return nil
+}
+
+func (receiver *TestMakeCommand) getStub() string {
+ return Stubs{}.Test()
+}
+
+// populateStub Populate the place-holders in the command stub.
+func (receiver *TestMakeCommand) populateStub(stub string, name string) string {
+ controllerName, packageName, _ := receiver.parseName(name)
+
+ stub = strings.ReplaceAll(stub, "DummyTest", str.Case2Camel(controllerName))
+ stub = strings.ReplaceAll(stub, "DummyPackage", packageName)
+
+ return stub
+}
+
+// getPath Get the full path to the command.
+func (receiver *TestMakeCommand) getPath(name string) string {
+ pwd, _ := os.Getwd()
+
+ controllerName, _, folderPath := receiver.parseName(name)
+
+ return filepath.Join(pwd, "tests", folderPath, str.Camel2Case(controllerName)+".go")
+}
+
+// parseName Parse the name to get the controller name, package name and folder path.
+func (receiver *TestMakeCommand) parseName(name string) (string, string, string) {
+ name = strings.TrimSuffix(name, ".go")
+
+ segments := strings.Split(name, "/")
+
+ controllerName := segments[len(segments)-1]
+
+ packageName := "tests"
+ folderPath := ""
+
+ if len(segments) > 1 {
+ folderPath = filepath.Join(segments[:len(segments)-1]...)
+ packageName = segments[len(segments)-2]
+ }
+
+ return controllerName, packageName, folderPath
+}
diff --git a/foundation/console/test_make_command_test.go b/foundation/console/test_make_command_test.go
new file mode 100644
index 000000000..1ede35b7c
--- /dev/null
+++ b/foundation/console/test_make_command_test.go
@@ -0,0 +1,32 @@
+package console
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ consolemocks "github.com/goravel/framework/contracts/console/mocks"
+ "github.com/goravel/framework/support/file"
+)
+
+func TestTestMakeCommand(t *testing.T) {
+ testMakeCommand := &TestMakeCommand{}
+ mockContext := &consolemocks.Context{}
+ mockContext.On("Argument", 0).Return("").Once()
+ err := testMakeCommand.Handle(mockContext)
+ assert.EqualError(t, err, "Not enough arguments (missing: name) ")
+
+ mockContext.On("Argument", 0).Return("UserTest").Once()
+ err = testMakeCommand.Handle(mockContext)
+ assert.Nil(t, err)
+ assert.True(t, file.Exists("tests/user_test.go"))
+
+ mockContext.On("Argument", 0).Return("user/UserTest").Once()
+ err = testMakeCommand.Handle(mockContext)
+ assert.Nil(t, err)
+ assert.True(t, file.Exists("tests/user/user_test.go"))
+ assert.True(t, file.Contain("tests/user/user_test.go", "package user"))
+ assert.True(t, file.Contain("tests/user/user_test.go", "type UserTestSuite struct"))
+ assert.True(t, file.Contain("tests/user/user_test.go", "func (s *UserTestSuite) SetupTest() {"))
+ assert.Nil(t, file.Remove("tests"))
+}
diff --git a/log/logger/daily.go b/log/logger/daily.go
index ae750a38a..f7d77bfe9 100644
--- a/log/logger/daily.go
+++ b/log/logger/daily.go
@@ -12,6 +12,7 @@ import (
"github.com/goravel/framework/contracts/config"
"github.com/goravel/framework/log/formatter"
+ "github.com/goravel/framework/support"
)
type Daily struct {
@@ -33,6 +34,7 @@ func (daily *Daily) Handle(channel string) (logrus.Hook, error) {
ext := filepath.Ext(logPath)
logPath = strings.ReplaceAll(logPath, ext, "")
+ logPath = filepath.Join(support.RelativePath, logPath)
writer, err := rotatelogs.New(
logPath+"-%Y-%m-%d"+ext,
diff --git a/log/logger/single.go b/log/logger/single.go
index 8f86faffb..347c62695 100644
--- a/log/logger/single.go
+++ b/log/logger/single.go
@@ -2,12 +2,14 @@ package logger
import (
"errors"
+ "path/filepath"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"github.com/goravel/framework/contracts/config"
"github.com/goravel/framework/log/formatter"
+ "github.com/goravel/framework/support"
)
type Single struct {
@@ -26,6 +28,7 @@ func (single *Single) Handle(channel string) (logrus.Hook, error) {
return nil, errors.New("error log path")
}
+ logPath = filepath.Join(support.RelativePath, logPath)
levels := getLevels(single.config.GetString(channel + ".level"))
pathMap := lfshook.PathMap{}
for _, level := range levels {
diff --git a/support/constant.go b/support/constant.go
index 5aed24277..5f6035ea8 100644
--- a/support/constant.go
+++ b/support/constant.go
@@ -9,7 +9,8 @@ const (
)
var (
- Env = EnvRuntime
- EnvPath = ".env"
- RootPath string
+ Env = EnvRuntime
+ EnvPath string
+ RelativePath string
+ RootPath string
)
diff --git a/testing/test_case.go b/testing/test_case.go
new file mode 100644
index 000000000..374f5a8ed
--- /dev/null
+++ b/testing/test_case.go
@@ -0,0 +1,4 @@
+package testing
+
+type TestCase struct {
+}