Skip to content

Commit 3de3f51

Browse files
authored
feat(tests): Merge pull request #5 from Patch2PDF/tests
Tests
2 parents b46dc26 + 91b90f4 commit 3de3f51

8 files changed

Lines changed: 522 additions & 5 deletions

File tree

.github/workflows/pr-check.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55

66
permissions:
77
contents: read
8+
pull-requests: write
89

910
jobs:
1011
Format:
@@ -81,4 +82,9 @@ jobs:
8182

8283
- name: Test
8384
run: |
84-
go test -v ./...
85+
go test -coverprofile=cover.out ./tests/... -coverpkg=./pkg/...,.,./internal/...
86+
87+
- name: Coverage Report
88+
uses: Jannik-Hm/go-test-coverage-report@v1.1
89+
with:
90+
coverprofile: cover.out

pkg/MeshTypes/mesh.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package MeshTypes
22

3+
import (
4+
"fmt"
5+
)
6+
37
type Mesh struct {
48
Triangles []*Triangle
59
}
@@ -31,8 +35,13 @@ func (obj *Mesh) RotateAndTranslate(translationMatrix Matrix) {
3135
}
3236

3337
func (obj *Mesh) calculateBoundingBox() Vector {
34-
min := Vector{}
35-
max := Vector{}
38+
// init with first triangle to prohibit 0 values being min or max
39+
if len(obj.Triangles) == 0 || obj.Triangles[0] == nil || obj.Triangles[0].V0 == nil {
40+
return Vector{}
41+
}
42+
min := obj.Triangles[0].V0.Position
43+
max := obj.Triangles[0].V0.Position
44+
3645
for _, triangle := range obj.Triangles {
3746
min = triangle.V0.Position.Min(&min)
3847
max = triangle.V0.Position.Max(&max)
@@ -50,8 +59,11 @@ func (obj *Mesh) calculateBoundingBox() Vector {
5059
}
5160
}
5261

53-
func (obj *Mesh) ScaleToDimensions(desiredSize *Vector) {
62+
func (obj *Mesh) ScaleToDimensions(desiredSize *Vector) error {
5463
actual := obj.calculateBoundingBox()
64+
if actual.X == 0 && actual.Y == 0 && actual.Z == 0 {
65+
return fmt.Errorf("invalid Mesh with 0 dimension")
66+
}
5567
scaling := desiredSize.Div(actual)
5668
scaledVectors := make(map[*Vertex]struct{})
5769
for _, triangle := range obj.Triangles {
@@ -68,4 +80,5 @@ func (obj *Mesh) ScaleToDimensions(desiredSize *Vector) {
6880
scaledVectors[triangle.V2] = struct{}{}
6981
}
7082
}
83+
return nil
7184
}

pkg/file_handlers/3ds.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ func Load3DS(fileData *[]byte, desiredSize *MeshTypes.Vector) (*MeshTypes.Mesh,
9191
mesh := &MeshTypes.Mesh{Triangles: triangles}
9292

9393
if desiredSize != nil {
94-
mesh.ScaleToDimensions(desiredSize)
94+
err := mesh.ScaleToDimensions(desiredSize)
95+
if err != nil {
96+
return nil, err
97+
}
9598
}
9699

97100
return mesh, nil

tests/MeshTypes/matrix_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package MeshTypes_Test
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/Patch2PDF/GDTF-Mesh-Reader/pkg/MeshTypes"
8+
)
9+
10+
func TestIdentityMatrix(t *testing.T) {
11+
want := MeshTypes.Matrix{
12+
X00: 1, X01: 0, X02: 0, X03: 0,
13+
X10: 0, X11: 1, X12: 0, X13: 0,
14+
X20: 0, X21: 0, X22: 1, X23: 0,
15+
X30: 0, X31: 0, X32: 0, X33: 1,
16+
}
17+
if !reflect.DeepEqual(MeshTypes.IdentityMatrix(), want) {
18+
t.Errorf(`IdentityMatrix() Output does not match`)
19+
}
20+
}
21+
22+
func TestMatrixMul(t *testing.T) {
23+
a := MeshTypes.Matrix{
24+
X00: 1, X01: 2, X02: 3, X03: 4,
25+
X10: 5, X11: 6, X12: 7, X13: 8,
26+
X20: 9, X21: 10, X22: 11, X23: 12,
27+
X30: 13, X31: 14, X32: 15, X33: 16,
28+
}
29+
b := MeshTypes.Matrix{
30+
X00: 17, X01: 18, X02: 19, X03: 20,
31+
X10: 21, X11: 22, X12: 23, X13: 24,
32+
X20: 25, X21: 26, X22: 27, X23: 28,
33+
X30: 29, X31: 30, X32: 31, X33: 32,
34+
}
35+
want := MeshTypes.Matrix{
36+
X00: 250, X01: 260, X02: 270, X03: 280,
37+
X10: 618, X11: 644, X12: 670, X13: 696,
38+
X20: 986, X21: 1028, X22: 1070, X23: 1112,
39+
X30: 1354, X31: 1412, X32: 1470, X33: 1528,
40+
}
41+
if !reflect.DeepEqual(a.Mul(b), want) {
42+
t.Errorf(`Matrix Multiplication Output does not match`)
43+
}
44+
}
45+
46+
func TestMulPosition(t *testing.T) {
47+
a := MeshTypes.Matrix{
48+
X00: 1, X01: 2, X02: 3, X03: 4,
49+
X10: 5, X11: 6, X12: 7, X13: 8,
50+
X20: 9, X21: 10, X22: 11, X23: 12,
51+
X30: 13, X31: 14, X32: 15, X33: 16,
52+
}
53+
b := MeshTypes.Vector{
54+
X: 17,
55+
Y: 18,
56+
Z: 19,
57+
}
58+
want := MeshTypes.Vector{
59+
X: 114,
60+
Y: 334,
61+
Z: 554,
62+
}
63+
64+
if !reflect.DeepEqual(a.MulPosition(b), want) {
65+
t.Errorf(`Matrix Vector Multiplication Output does not match`)
66+
}
67+
}

tests/MeshTypes/mesh_test.go

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package MeshTypes_Test
2+
3+
import (
4+
"math/rand"
5+
"reflect"
6+
"testing"
7+
8+
"github.com/Patch2PDF/GDTF-Mesh-Reader/pkg/MeshTypes"
9+
)
10+
11+
func RandomTriangle() *MeshTypes.Triangle {
12+
return &MeshTypes.Triangle{
13+
V0: RandomVertex(),
14+
V1: RandomVertex(),
15+
V2: RandomVertex(),
16+
}
17+
}
18+
19+
func RandomVertex() *MeshTypes.Vertex {
20+
normal := RandomVector()
21+
return &MeshTypes.Vertex{
22+
Position: RandomVector(),
23+
Normal: &normal,
24+
}
25+
}
26+
27+
func RandomVector() MeshTypes.Vector {
28+
return MeshTypes.Vector{
29+
X: rand.Float64(),
30+
Y: rand.Float64(),
31+
Z: rand.Float64(),
32+
}
33+
}
34+
35+
func TestAddTriangle(t *testing.T) {
36+
a := MeshTypes.Mesh{
37+
Triangles: []*MeshTypes.Triangle{RandomTriangle()},
38+
}
39+
b := RandomTriangle()
40+
copy := a.Copy()
41+
copy.AddTriangle(b)
42+
if !reflect.DeepEqual(copy, MeshTypes.Mesh{Triangles: []*MeshTypes.Triangle{a.Triangles[0], b}}) {
43+
t.Errorf("Mesh AddTriangle() Output does not match expected")
44+
}
45+
}
46+
47+
func TestMeshCopy(t *testing.T) {
48+
a := MeshTypes.Mesh{
49+
Triangles: []*MeshTypes.Triangle{RandomTriangle()},
50+
}
51+
copy := a.Copy()
52+
if !(reflect.DeepEqual(a, copy) && &a != &copy) {
53+
t.Errorf("Mesh Copy() Output does not match expected")
54+
}
55+
}
56+
57+
func TestAddMesh(t *testing.T) {
58+
a := MeshTypes.Mesh{
59+
Triangles: []*MeshTypes.Triangle{RandomTriangle()},
60+
}
61+
b := MeshTypes.Mesh{
62+
Triangles: []*MeshTypes.Triangle{RandomTriangle()},
63+
}
64+
copy := a.Copy()
65+
result := copy.Add(&b)
66+
if !reflect.DeepEqual(*result, MeshTypes.Mesh{Triangles: []*MeshTypes.Triangle{a.Triangles[0], b.Triangles[0]}}) {
67+
t.Errorf("Mesh Add() Output does not match expected")
68+
}
69+
}
70+
71+
func TestRotateAndTranslate(t *testing.T) {
72+
a := MeshTypes.Mesh{
73+
Triangles: []*MeshTypes.Triangle{RandomTriangle()},
74+
}
75+
translationMatrix := MeshTypes.Matrix{
76+
X00: 1, X01: -1, X02: 5, X03: -20,
77+
X10: 1, X11: 2, X12: -3, X13: 10,
78+
X20: 1, X21: 5, X22: 3, X23: -5,
79+
X30: 1, X31: 6, X32: -6, X33: 4,
80+
}
81+
result := a.Copy()
82+
result.RotateAndTranslate(translationMatrix)
83+
want := a.Copy()
84+
for _, triangle := range want.Triangles {
85+
triangle.V0.Position = translationMatrix.MulPosition(triangle.V0.Position) // safe to use as func is tested in another place
86+
triangle.V1.Position = translationMatrix.MulPosition(triangle.V1.Position)
87+
triangle.V2.Position = translationMatrix.MulPosition(triangle.V2.Position)
88+
}
89+
if !reflect.DeepEqual(result, want) {
90+
t.Errorf("Mesh RotateAndTranslate() Output does not match expected")
91+
}
92+
}
93+
94+
func TestScaleToDimensions(t *testing.T) {
95+
a := MeshTypes.Mesh{
96+
Triangles: []*MeshTypes.Triangle{
97+
{
98+
V0: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: -1, Y: 1, Z: -1}},
99+
V1: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 1, Y: -3, Z: 1}},
100+
V2: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 1, Y: 1, Z: 0}},
101+
},
102+
},
103+
}
104+
desiredSize := MeshTypes.Vector{
105+
X: 4, Y: 4, Z: 8,
106+
}
107+
result := a.Copy()
108+
result.ScaleToDimensions(&desiredSize)
109+
want := MeshTypes.Mesh{
110+
Triangles: []*MeshTypes.Triangle{
111+
{
112+
V0: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: -2, Y: 1, Z: -4}},
113+
V1: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 2, Y: -3, Z: 4}},
114+
V2: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 2, Y: 1, Z: 0}},
115+
},
116+
},
117+
}
118+
if !reflect.DeepEqual(result, want) {
119+
t.Errorf("Mesh ScaleToDimensions() Output does not match expected")
120+
}
121+
}
122+
123+
func TestScaleToDimensionsEmptyMesh(t *testing.T) {
124+
a := MeshTypes.Mesh{
125+
Triangles: []*MeshTypes.Triangle{},
126+
}
127+
desiredSize := MeshTypes.Vector{
128+
X: 4, Y: 4, Z: 8,
129+
}
130+
err := a.ScaleToDimensions(&desiredSize)
131+
if err == nil {
132+
t.Errorf("Mesh ScaleToDimensions() did not return error on faulty mesh")
133+
}
134+
}
135+
136+
func TestScaleToDimensionsNullTriangle(t *testing.T) {
137+
a := MeshTypes.Mesh{
138+
Triangles: []*MeshTypes.Triangle{nil},
139+
}
140+
desiredSize := MeshTypes.Vector{
141+
X: 4, Y: 4, Z: 8,
142+
}
143+
err := a.ScaleToDimensions(&desiredSize)
144+
if err == nil {
145+
t.Errorf("Mesh ScaleToDimensions() did not return error on faulty mesh")
146+
}
147+
}
148+
149+
func TestScaleToDimensionsNullVertex(t *testing.T) {
150+
a := MeshTypes.Mesh{
151+
Triangles: []*MeshTypes.Triangle{
152+
{
153+
V0: nil,
154+
V1: nil,
155+
V2: nil,
156+
},
157+
},
158+
}
159+
desiredSize := MeshTypes.Vector{
160+
X: 4, Y: 4, Z: 8,
161+
}
162+
err := a.ScaleToDimensions(&desiredSize)
163+
if err == nil {
164+
t.Errorf("Mesh ScaleToDimensions() did not return error on faulty mesh")
165+
}
166+
}
167+
168+
func TestScaleToDimensions0Size(t *testing.T) {
169+
a := MeshTypes.Mesh{
170+
Triangles: []*MeshTypes.Triangle{
171+
{
172+
V0: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 0, Y: 0, Z: 0}},
173+
V1: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 0, Y: 0, Z: 0}},
174+
V2: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 0, Y: 0, Z: 0}},
175+
},
176+
},
177+
}
178+
desiredSize := MeshTypes.Vector{
179+
X: 4, Y: 4, Z: 8,
180+
}
181+
err := a.ScaleToDimensions(&desiredSize)
182+
if err == nil {
183+
t.Errorf("Mesh ScaleToDimensions() did not return error on faulty mesh")
184+
}
185+
}
186+
187+
func TestScaleToDimensionsSameVertex(t *testing.T) {
188+
triangle := MeshTypes.Triangle{
189+
V0: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 0, Y: 0, Z: 0}},
190+
V1: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 0, Y: 0, Z: 0}},
191+
V2: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 0, Y: 0, Z: 0}},
192+
}
193+
a := MeshTypes.Mesh{
194+
Triangles: []*MeshTypes.Triangle{
195+
&triangle,
196+
{
197+
V0: triangle.V0,
198+
V1: triangle.V1,
199+
V2: triangle.V2,
200+
},
201+
},
202+
}
203+
desiredSize := MeshTypes.Vector{
204+
X: 4, Y: 4, Z: 8,
205+
}
206+
err := a.ScaleToDimensions(&desiredSize)
207+
if err == nil {
208+
t.Errorf("Mesh ScaleToDimensions() did not return error on faulty mesh")
209+
}
210+
}

tests/MeshTypes/triangle_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package MeshTypes_Test
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/Patch2PDF/GDTF-Mesh-Reader/pkg/MeshTypes"
8+
)
9+
10+
func TestTriangleNormal(t *testing.T) {
11+
a := MeshTypes.Triangle{
12+
V0: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 1, Y: 4, Z: 3}, Normal: &MeshTypes.Vector{X: 4, Y: 5, Z: 6}},
13+
V1: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 4, Y: 8, Z: 10}, Normal: &MeshTypes.Vector{X: 10, Y: 11, Z: 12}},
14+
V2: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 13, Y: 14, Z: 15}, Normal: &MeshTypes.Vector{X: 16, Y: 17, Z: 18}},
15+
}
16+
want := MeshTypes.Vector{X: -0.39436910666014113, Y: 0.8604416872584897, Z: -0.3226656327219336}
17+
result := a.Normal()
18+
if !reflect.DeepEqual(result, want) {
19+
t.Error("Triangle Normal() returned value does not match expected value")
20+
}
21+
}
22+
23+
func TestTriangleCopy(t *testing.T) {
24+
a := MeshTypes.Triangle{
25+
V0: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 1, Y: 2, Z: 3}, Normal: &MeshTypes.Vector{X: 4, Y: 5, Z: 6}},
26+
V1: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 7, Y: 8, Z: 9}, Normal: &MeshTypes.Vector{X: 10, Y: 11, Z: 12}},
27+
V2: &MeshTypes.Vertex{Position: MeshTypes.Vector{X: 13, Y: 14, Z: 15}, Normal: &MeshTypes.Vector{X: 16, Y: 17, Z: 18}},
28+
}
29+
copy := a.Copy()
30+
if !(reflect.DeepEqual(copy, a) && a.V0 != copy.V0 && a.V1 != copy.V1 && a.V2 != copy.V2) {
31+
t.Error("Triangle Copy() returned value does not match expected value")
32+
}
33+
}

0 commit comments

Comments
 (0)