Repository: go-gorm/gorm
Pull request #5836 (2022-11-04 13:17:27)

fix logger path bug
<!--
Make sure these boxes checked before submitting your pull request.

For significant changes, please open an issue to make an agreement on an implementation design/plan first before starting it.
-->

- [x] Do only one thing
- [x] Non breaking API changes
- [x] Tested

### What did this pull request do?

To fix logger path bug.

### User Case Description

before:

``` shell
➜  app go run .
2022/11/04 21:10:29 /Users/kvii/go/pkg/mod/gorm.io/gorm@v1.24.1/callbacks.go:134
[0.004ms] [rows:0] SELECT 1
```

after:

``` shell
➜  app go run .
2022/11/04 20:58:48 /Users/kvii/workspace/qs/gormt/app/main.go:14
[0.005ms] [rows:0] SELECT 1
```


Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 16903ed..b88bf67 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -9,3 +9,12 @@ linters:
     - prealloc
     - unconvert
     - unparam
+    - goimports
+    - whitespace
+
+linters-settings:
+  whitespace:
+    multi-func: true
+  goimports:
+    local-prefixes: gorm.io/gorm
+
diff --git a/utils/utils.go b/utils/utils.go
index 90b4c8e..2d87f4c 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -3,8 +3,8 @@ package utils
 import (
 	"database/sql/driver"
 	"fmt"
+	"path/filepath"
 	"reflect"
-	"regexp"
 	"runtime"
 	"strconv"
 	"strings"
@@ -16,7 +16,18 @@ var gormSourceDir string
 func init() {
 	_, file, _, _ := runtime.Caller(0)
 	// compatible solution to get gorm source directory with various operating systems
-	gormSourceDir = regexp.MustCompile(`gorm.utils.utils\.go`).ReplaceAllString(file, "")
+	gormSourceDir = sourceDir(file)
+}
+
+func sourceDir(file string) string {
+	dir := filepath.Dir(file)
+	dir = filepath.Dir(dir)
+
+	s := filepath.Dir(dir)
+	if filepath.Base(s) != "gorm.io" {
+		s = dir
+	}
+	return s + string(filepath.Separator)
 }
 
 // FileWithLineNum return the file name and line number of the current file


Test patch:
diff --git a/utils/utils_test.go b/utils/utils_test.go
index 27dfee1..71eef96 100644
--- a/utils/utils_test.go
+++ b/utils/utils_test.go
@@ -1,8 +1,13 @@
 package utils
 
 import (
+	"database/sql"
+	"database/sql/driver"
+	"errors"
+	"math"
 	"strings"
 	"testing"
+	"time"
 )
 
 func TestIsValidDBNameChar(t *testing.T) {
@@ -13,6 +18,29 @@ func TestIsValidDBNameChar(t *testing.T) {
 	}
 }
 
+func TestCheckTruth(t *testing.T) {
+	checkTruthTests := []struct {
+		v   string
+		out bool
+	}{
+		{"123", true},
+		{"true", true},
+		{"", false},
+		{"false", false},
+		{"False", false},
+		{"FALSE", false},
+		{"\u0046alse", false},
+	}
+
+	for _, test := range checkTruthTests {
+		t.Run(test.v, func(t *testing.T) {
+			if out := CheckTruth(test.v); out != test.out {
+				t.Errorf("CheckTruth(%s) want: %t, got: %t", test.v, test.out, out)
+			}
+		})
+	}
+}
+
 func TestToStringKey(t *testing.T) {
 	cases := []struct {
 		values []interface{}
@@ -29,3 +57,81 @@ func TestToStringKey(t *testing.T) {
 		}
 	}
 }
+
+func TestContains(t *testing.T) {
+	containsTests := []struct {
+		name  string
+		elems []string
+		elem  string
+		out   bool
+	}{
+		{"exists", []string{"1", "2", "3"}, "1", true},
+		{"not exists", []string{"1", "2", "3"}, "4", false},
+	}
+	for _, test := range containsTests {
+		t.Run(test.name, func(t *testing.T) {
+			if out := Contains(test.elems, test.elem); test.out != out {
+				t.Errorf("Contains(%v, %s) want: %t, got: %t", test.elems, test.elem, test.out, out)
+			}
+		})
+	}
+}
+
+type ModifyAt sql.NullTime
+
+// Value return a Unix time.
+func (n ModifyAt) Value() (driver.Value, error) {
+	if !n.Valid {
+		return nil, nil
+	}
+	return n.Time.Unix(), nil
+}
+
+func TestAssertEqual(t *testing.T) {
+	now := time.Now()
+	assertEqualTests := []struct {
+		name     string
+		src, dst interface{}
+		out      bool
+	}{
+		{"error equal", errors.New("1"), errors.New("1"), true},
+		{"error not equal", errors.New("1"), errors.New("2"), false},
+		{"driver.Valuer equal", ModifyAt{Time: now, Valid: true}, ModifyAt{Time: now, Valid: true}, true},
+		{"driver.Valuer not equal", ModifyAt{Time: now, Valid: true}, ModifyAt{Time: now.Add(time.Second), Valid: true}, false},
+	}
+	for _, test := range assertEqualTests {
+		t.Run(test.name, func(t *testing.T) {
+			if out := AssertEqual(test.src, test.dst); test.out != out {
+				t.Errorf("AssertEqual(%v, %v) want: %t, got: %t", test.src, test.dst, test.out, out)
+			}
+		})
+	}
+}
+
+func TestToString(t *testing.T) {
+	tests := []struct {
+		name string
+		in   interface{}
+		out  string
+	}{
+		{"int", math.MaxInt64, "9223372036854775807"},
+		{"int8", int8(math.MaxInt8), "127"},
+		{"int16", int16(math.MaxInt16), "32767"},
+		{"int32", int32(math.MaxInt32), "2147483647"},
+		{"int64", int64(math.MaxInt64), "9223372036854775807"},
+		{"uint", uint(math.MaxUint64), "18446744073709551615"},
+		{"uint8", uint8(math.MaxUint8), "255"},
+		{"uint16", uint16(math.MaxUint16), "65535"},
+		{"uint32", uint32(math.MaxUint32), "4294967295"},
+		{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
+		{"string", "abc", "abc"},
+		{"other", true, ""},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			if out := ToString(test.in); test.out != out {
+				t.Fatalf("ToString(%v) want: %s, got: %s", test.in, test.out, out)
+			}
+		})
+	}
+}
diff --git a/utils/utils_unix_test.go b/utils/utils_unix_test.go
new file mode 100644
index 0000000..da97aa2
--- /dev/null
+++ b/utils/utils_unix_test.go
@@ -0,0 +1,33 @@
+package utils
+
+import "testing"
+
+func TestSourceDir(t *testing.T) {
+	cases := []struct {
+		file string
+		want string
+	}{
+		{
+			file: "/Users/name/go/pkg/mod/gorm.io/gorm@v1.2.3/utils/utils.go",
+			want: "/Users/name/go/pkg/mod/gorm.io/",
+		},
+		{
+			file: "/go/work/proj/gorm/utils/utils.go",
+			want: "/go/work/proj/gorm/",
+		},
+		{
+			file: "/go/work/proj/gorm_alias/utils/utils.go",
+			want: "/go/work/proj/gorm_alias/",
+		},
+		{
+			file: "/go/work/proj/my.gorm.io/gorm@v1.2.3/utils/utils.go",
+			want: "/go/work/proj/my.gorm.io/gorm@v1.2.3/",
+		},
+	}
+	for _, c := range cases {
+		s := sourceDir(c.file)
+		if s != c.want {
+			t.Fatalf("%s: expected %s, got %s", c.file, c.want, s)
+		}
+	}
+}
diff --git a/utils/utils_windows_test.go b/utils/utils_windows_test.go
new file mode 100644
index 0000000..d1734e0
--- /dev/null
+++ b/utils/utils_windows_test.go
@@ -0,0 +1,33 @@
+package utils
+
+import "testing"
+
+func TestSourceDir(t *testing.T) {
+	cases := []struct {
+		file string
+		want string
+	}{
+		{
+			file: `C:\Users\name\go\pkg\mod\gorm.io\gorm@v1.20.8\utils\utils.go`,
+			want: `C:\Users\name\go\pkg\mod\gorm.io`,
+		},
+		{
+			file: `C:\go\work\proj\gorm\utils\utils.go`,
+			want: `C:\go\work\proj\gorm`,
+		},
+		{
+			file: `C:\go\work\proj\gorm_alias\utils\utils.go`,
+			want: `C:\go\work\proj\gorm_alias`,
+		},
+		{
+			file: `C:\go\work\proj\my.gorm.io\gorm\utils\utils.go`,
+			want: `C:\go\work\proj\my.gorm.io\gorm`,
+		},
+	}
+	for _, c := range cases {
+		s := sourceDir(c.file)
+		if s != c.want {
+			t.Fatalf("%s: expected %s, got %s", c.file, c.want, s)
+		}
+	}
+}