diff --git a/encoder.go b/encoder.go index b92ef42..39c84f7 100644 --- a/encoder.go +++ b/encoder.go @@ -36,7 +36,16 @@ func newXMLEncoder(w io.Writer, floatPresicion int) *xmlEncoder { // AddRelationship adds a relationship to the encoded model. // Duplicated relationships will be removed before encoding. func (enc *xmlEncoder) AddRelationship(r spec.Relationship) { - enc.relationships = append(enc.relationships, Relationship(r)) + hasRelationship := false + for _, relationship := range enc.relationships { + if relationship.Path == r.Path { + hasRelationship = true + break + } + } + if !hasRelationship { + enc.relationships = append(enc.relationships, Relationship(r)) + } } // FloatPresicion returns the float presicion to use diff --git a/encoder_test.go b/encoder_test.go index 98a2510..a0b8b2e 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -8,12 +8,14 @@ import ( "encoding/xml" "errors" "image/color" + "path/filepath" "reflect" "strconv" "testing" "github.com/go-test/deep" "github.com/hpinc/go3mf/spec" + "github.com/hpinc/go3mf/utils" "github.com/stretchr/testify/mock" ) @@ -309,3 +311,62 @@ func TestEncoder_Encode_Roundtrip(t *testing.T) { }) } } + +func TestEncoder_Relationship(t *testing.T) { + type request struct { + fileName string + } + type response struct { + relationships []Relationship + } + + tests := []struct { + name string + request request + response response + }{ /*Verfy if a file rels is not update in case of relationship exists*/ + {"file_with_texture_rel_but_no_texture", + request{fileName: "super_boogoku_tiny.3mf"}, + response{relationships: []Relationship{ + {ID: "rel2", Type: "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture", Path: "/Thumbnails/super_boo.png"}, + {ID: "rel3", Type: "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture", Path: "/Thumbnails/goku_ss.png"}, + }}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + utils.WithProjectDirAndTestTempDirRemoveAtEnd( + filepath.Join("testdata"), func(testFileDir string, testTempDir string) { + testFile := filepath.Join(testFileDir, tt.request.fileName) + outputFile := filepath.Join(testTempDir, "SW3DBUG-2700_changed.3mf") + var model Model + r, err := OpenReader(testFile) + if err != nil { + t.Errorf("TestEncoder_Relationship() error = %v", err) + } + r.Decode(&model) + defer r.Close() + w, err := CreateWriter(outputFile) + if err != nil { + t.Errorf("TestEncoder_Relationship() error = %v", err) + } + w.Encode(&model) + defer w.Close() + + var modelUpdated Model + r, err = OpenReader(outputFile) + if err != nil { + t.Errorf("TestEncoder_Relationship() error = %v", err) + } + r.Decode(&modelUpdated) + defer r.Close() + + if diff := deep.Equal(modelUpdated.Relationships, tt.response.relationships); diff != nil { + t.Errorf("TestEncoder_Relationship() = %v", diff) + } + }) + + }) + } + +} diff --git a/testdata/super_boogoku_tiny.3mf b/testdata/super_boogoku_tiny.3mf new file mode 100644 index 0000000..10b31ae Binary files /dev/null and b/testdata/super_boogoku_tiny.3mf differ diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..8988e19 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,39 @@ +package utils + +import ( + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" +) + +func GetRootProjectDir() (string, error) { + _, filename, _, _ := runtime.Caller(0) + dir := filepath.Join(path.Dir(filename), "..") + err := os.Chdir(dir) + return dir, err +} + +func WithRootProjectDir(callback func(string)) { + dir, err := GetRootProjectDir() + if err != nil { + panic(err) + } + callback(dir) +} + +func WithProjectDirAndTestTempDirRemoveAtEnd(fileFolder string, callback func(testFileDir string, testTempDir string)) { + dir, err := GetRootProjectDir() + if err != nil { + panic(err) + } + testTempDir, err := ioutil.TempDir("", "testcase") + if err != nil { + panic(err) + } + defer os.RemoveAll(testTempDir) + defer os.Remove(testTempDir) + + callback(filepath.Join(dir, fileFolder), testTempDir) +}