Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"sync/atomic"
"time"

"github.com/tableauio/loader/pkg/udiff"
"github.com/tableauio/tableau/format"
"github.com/tableauio/tableau/load"
"github.com/tableauio/tableau/store"
Expand Down Expand Up @@ -143,7 +144,7 @@ func (h *Hub) Store(dir string, format format.Format, options ...store.Option) e
return nil
}

// mutableCheck checks if the messagers are mutable or not.
// mutableCheck checks if the messagers are mutated or not.
func (h *Hub) mutableCheck() {
interval := h.opts.MutableCheck.Interval
if interval == 0 {
Expand All @@ -166,7 +167,7 @@ func (h *Hub) mutableCheck() {
}

func (h *Hub) onMutateDefault(name string, original, current proto.Message) {
text, _ := UnifiedDiff(original, current)
text, _ := udiff.UnifiedDiff(original, current)
fmt.Fprintf(os.Stderr,
"==== %s DIFF BEGIN ====\n%s==== %s DIFF END ====\n",
name, text, name)
Expand Down
24 changes: 0 additions & 24 deletions cmd/protoc-gen-go-tableau-loader/embed/templates/util.pc.go.tpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import (
"errors"

"github.com/pmezard/go-difflib/difflib"
"github.com/tableauio/tableau/store"
"google.golang.org/protobuf/proto"
)

var ErrNotFound = errors.New("not found")
Expand All @@ -22,23 +18,3 @@ func GetMessager[T Messager](messagerMap MessagerMap) T {
messager, _ := messagerMap[t.Name()].(T)
return messager
}

// UnifiedDiff generates the proto message delta as a unified diff.
func UnifiedDiff(original, current proto.Message) (string, error) {
originalText, err := store.MarshalToText(original, true)
if err != nil {
return "", err
}
currentText, err := store.MarshalToText(current, true)
if err != nil {
return "", err
}
diff := difflib.UnifiedDiff{
A: difflib.SplitLines(string(originalText)),
B: difflib.SplitLines(string(currentText)),
FromFile: "Original",
ToFile: "Current",
Context: 3,
}
return difflib.GetUnifiedDiffString(diff)
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ module github.com/tableauio/loader
go 1.21

require (
github.com/aymanbagabas/go-udiff v0.2.0
github.com/iancoleman/strcase v0.3.0
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/testify v1.10.0
github.com/tableauio/tableau v0.15.1
golang.org/x/exp v0.0.0-20230418202329-0354be287a23
google.golang.org/protobuf v1.34.2
)

Expand All @@ -18,6 +17,7 @@ require (
github.com/emirpasic/gods v1.18.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/protocolbuffers/txtpbfmt v0.0.0-20240820135758-21b1d9897dc7 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.4 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307 h1:C735MoY/X+UOx6SECmHk5pVOj51h839Ph13pEoY8UmU=
github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM=
Expand Down Expand Up @@ -56,8 +58,6 @@ go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20230418202329-0354be287a23 h1:4NKENAGIctmZYLK9W+X1kDK8ObBFqOSCJM6WE7CvkJY=
golang.org/x/exp v0.0.0-20230418202329-0354be287a23/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
Expand Down
2 changes: 1 addition & 1 deletion internal/options/options.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package options

import (
"slices"
"strings"

"github.com/tableauio/tableau/proto/tableaupb"
"golang.org/x/exp/slices"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
Expand Down
20 changes: 20 additions & 0 deletions pkg/udiff/udiff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package udiff

import (
"github.com/aymanbagabas/go-udiff"
"github.com/tableauio/tableau/store"
"google.golang.org/protobuf/proto"
)

// UnifiedDiff generates the proto message delta as a unified diff.
func UnifiedDiff(original, current proto.Message) (string, error) {
originalText, err := store.MarshalToText(original, true)
if err != nil {
return "", err
}
currentText, err := store.MarshalToText(current, true)
if err != nil {
return "", err
}
return udiff.Unified("Original", "Current", string(originalText), string(currentText)), nil
}
100 changes: 100 additions & 0 deletions pkg/udiff/udiff_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package udiff

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/wrapperspb"
)

func TestUnifiedDiff_NoDifference(t *testing.T) {
original := wrapperspb.String("hello")
current := wrapperspb.String("hello")

diff, err := UnifiedDiff(original, current)
require.NoError(t, err)
assert.Empty(t, diff)
}

func TestUnifiedDiff_WithDifference(t *testing.T) {
original := wrapperspb.String("hello")
current := wrapperspb.String("world")

diff, err := UnifiedDiff(original, current)
require.NoError(t, err)
assert.NotEmpty(t, diff)

// Assert full unified diff lines
assert.Contains(t, diff, "--- Original")
assert.Contains(t, diff, "+++ Current")
assert.Contains(t, diff, `-value: "hello"`)
assert.Contains(t, diff, `+value: "world"`)
}

func TestUnifiedDiff_NilMessages(t *testing.T) {
original := wrapperspb.String("")
current := wrapperspb.String("")

diff, err := UnifiedDiff(original, current)
require.NoError(t, err)
assert.Empty(t, diff)
}

func TestUnifiedDiff_ComplexMessage(t *testing.T) {
original, err := structpb.NewStruct(map[string]any{
"name": "Alice",
"age": 30,
"active": true,
"score": 99.5,
"address": map[string]any{"city": "Shanghai", "zip": "200000"},
"tags": []any{"admin", "vip"},
})
require.NoError(t, err)

current, err := structpb.NewStruct(map[string]any{
"name": "Bob",
"age": 25,
"active": false,
"score": 88.0,
"address": map[string]any{"city": "Beijing", "zip": "100000"},
"tags": []any{"user"},
})
require.NoError(t, err)

diff, err := UnifiedDiff(original, current)
require.NoError(t, err)
assert.NotEmpty(t, diff)

// Assert changed fields with full unified diff lines
assert.Contains(t, diff, "- bool_value: true")
assert.Contains(t, diff, "+ bool_value: false")
assert.Contains(t, diff, `- string_value: "Shanghai"`)
assert.Contains(t, diff, `+ string_value: "Beijing"`)
assert.Contains(t, diff, `- string_value: "200000"`)
assert.Contains(t, diff, `+ string_value: "100000"`)
assert.Contains(t, diff, "- number_value: 30")
assert.Contains(t, diff, "+ number_value: 25")
assert.Contains(t, diff, `- string_value: "Alice"`)
assert.Contains(t, diff, `+ string_value: "Bob"`)
assert.Contains(t, diff, "- number_value: 99.5")
assert.Contains(t, diff, "+ number_value: 88")
assert.Contains(t, diff, `- string_value: "admin"`)
assert.Contains(t, diff, `- string_value: "vip"`)
assert.Contains(t, diff, `+ string_value: "user"`)

// Assert unchanged fields (keys) are not in diff lines (no +/- prefix)
assert.NotContains(t, diff, `- key: "active"`)
assert.NotContains(t, diff, `+ key: "active"`)
assert.NotContains(t, diff, `- key: "address"`)
assert.NotContains(t, diff, `+ key: "address"`)
assert.NotContains(t, diff, `- key: "age"`)
assert.NotContains(t, diff, `+ key: "age"`)
assert.NotContains(t, diff, `- key: "name"`)
assert.NotContains(t, diff, `+ key: "name"`)
assert.NotContains(t, diff, `- key: "score"`)
assert.NotContains(t, diff, `+ key: "score"`)
assert.NotContains(t, diff, `- key: "tags"`)
assert.NotContains(t, diff, `+ key: "tags"`)
}
5 changes: 3 additions & 2 deletions test/go-tableau-loader/protoconf/loader/hub.pc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 0 additions & 24 deletions test/go-tableau-loader/protoconf/loader/util.pc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading