package sh3d
import (
"archive/zip"
"bytes"
"strings"
"testing"
)
func archive(t *testing.T, files map[string]string) *bytes.Reader {
t.Helper()
var buf bytes.Buffer
zw := zip.NewWriter(&buf)
for name, body := range files {
w, err := zw.Create(name)
if err != nil {
t.Fatal(err)
}
if _, err := w.Write([]byte(body)); err != nil {
t.Fatal(err)
}
}
if err := zw.Close(); err != nil {
t.Fatal(err)
}
return bytes.NewReader(buf.Bytes())
}
func read(t *testing.T, homeXML string) (*Home, error) {
t.Helper()
r := archive(t, map[string]string{"Home": "serialised java", "Home.xml": homeXML, "0": "model"})
return Read(r, r.Size())
}
const flat = `
`
func TestReadGeometry(t *testing.T) {
h, err := read(t, flat)
if err != nil {
t.Fatal(err)
}
if len(h.Walls) != 1 || h.Walls[0].YEnd != 285 || h.Walls[0].Thickness != 7.62 {
t.Errorf("walls = %+v", h.Walls)
}
if len(h.Rooms) != 1 {
t.Fatalf("rooms = %+v, want one: a polyline's points are not a room's", h.Rooms)
}
if r := h.Rooms[0]; r.Name != "Kitchen" || len(r.Points) != 3 || r.NameXOffset != 5 || r.NameYOffset != -10 {
t.Errorf("room = %+v", r)
}
byName := map[string]Piece{}
for _, p := range h.Furniture {
byName[p.Name] = p
}
if len(h.Furniture) != 5 {
t.Errorf("furniture = %d pieces, want door, window, chair, shelf and lamp", len(h.Furniture))
}
if _, ok := byName["Hidden"]; ok {
t.Error("an invisible piece was read")
}
if _, ok := byName["Desk set"]; ok {
t.Error("a furniture group was read as a piece rather than flattened")
}
if c := byName["Chair"]; c.Level != "l1" || c.X != 117.5 {
t.Errorf("chair = %+v, want the group's level and its own coordinates", c)
}
if d := byName["Door"]; !d.DoorOrWindow || d.WallThickness != 0.517 || d.WallDistance != 0.069 || d.Angle != 1.5707964 {
t.Errorf("door = %+v", d)
}
if w := byName["Window"]; !w.DoorOrWindow || w.WallThickness != 1 || w.WallDistance != 0 || w.Elevation != 87 {
t.Errorf("window = %+v, want the defaults SweetHome3D leaves out", w)
}
if s := byName["Shelf"]; s.DoorOrWindow || s.Width != 100 {
t.Errorf("shelf = %+v", s)
}
}
func TestFirstLevel(t *testing.T) {
h, err := read(t, `
`)
if err != nil {
t.Fatal(err)
}
f := h.FirstLevel()
if len(f.Levels) != 1 || f.Levels[0].ID != "a" {
t.Fatalf("first level = %+v, want the lowest elevation, then the lowest index", f.Levels)
}
if len(f.Walls) != 1 || f.Walls[0].XEnd != 2 || len(f.Rooms) != 0 || len(f.Furniture) != 1 {
t.Errorf("first level holds %d walls, %d rooms, %d pieces", len(f.Walls), len(f.Rooms), len(f.Furniture))
}
flatHome, err := read(t, flat)
if err != nil {
t.Fatal(err)
}
if flatHome.FirstLevel() != flatHome {
t.Error("a home without levels should come back whole")
}
}
func TestReadRejects(t *testing.T) {
cases := []struct {
name string
file *bytes.Reader
want string
}{
{"not a zip", bytes.NewReader([]byte(`{"width": 800}`)), "not a ZIP"},
{"old file", archive(t, map[string]string{"Home": "serialised java"}), "5.3"},
{"wrong root", archive(t, map[string]string{"Home.xml": ""}), "not "},
{"empty", archive(t, map[string]string{"Home.xml": ""}), "empty"},
{"malformed number", archive(t, map[string]string{"Home.xml": ""}), "xStart"},
{"not finite", archive(t, map[string]string{"Home.xml": ""}), "finite"},
{"broken xml", archive(t, map[string]string{"Home.xml": ""
r := archive(t, map[string]string{"Home.xml": big})
if r.Size() > 1<<20 {
t.Fatalf("test archive is %d bytes, expected it to compress", r.Size())
}
if _, err := Read(r, r.Size()); err == nil || !strings.Contains(err.Error(), "allowed") {
t.Errorf("err = %v, want the size cap", err)
}
}