diff --git a/decode_test.go b/decode_test.go
index bd171a1..617ce25 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -8,6 +8,8 @@ import (
"log"
"net/http"
"net/http/httptest"
+ "os"
+ "os/exec"
"path/filepath"
"reflect"
"testing"
@@ -513,3 +515,52 @@ func TestDecodeTagSkip(t *testing.T) {
t.Error("field decoded when it was tagged as -")
}
}
+
+// test parity with plutil -lint on macOS
+var xmlParityTestFailures = map[string]struct{}{
+ "empty-plist.plist": {},
+ "invalid-before-plist.plist": {},
+ "invalid-data.plist": {},
+ "invalid-middle.plist": {},
+ "invalid-start.plist": {},
+ "no-dict-end.plist": {},
+ "no-plist-end.plist": {},
+ "unescaped-plist.plist": {},
+ "unescaped-xml.plist": {},
+}
+
+func TestXMLPlutilParity(t *testing.T) {
+ type data struct {
+ Key string `plist:"key"`
+ }
+ tests, err := os.ReadDir("testdata/xml/")
+ if err != nil {
+ t.Fatalf("could not open testdata/xml: %v", err)
+ }
+
+ plutil, _ := exec.LookPath("plutil")
+
+ for _, test := range tests {
+ testPath := filepath.Join("testdata/xml/", test.Name())
+ buf, err := os.ReadFile(testPath)
+ if err != nil {
+ t.Errorf("could not read test %s: %v", test.Name(), err)
+ continue
+ }
+ v := new(data)
+ err = Unmarshal(buf, v)
+
+ _, check := xmlParityTestFailures[test.Name()]
+ if plutil != "" {
+ check = exec.Command(plutil, "-lint", testPath).Run() != nil
+ }
+
+ if check && err == nil {
+ t.Errorf("expected error for test %s but got: nil", test.Name())
+ } else if !check && err != nil {
+ t.Errorf("expected no error for test %s but got: %v", test.Name(), err)
+ } else if !check && v.Key != "val" {
+ t.Errorf("expected key=val for test %s but got: key=%s", test.Name(), v.Key)
+ }
+ }
+}
diff --git a/testdata/xml/empty-doctype.plist b/testdata/xml/empty-doctype.plist
new file mode 100644
index 0000000..aa4a935
--- /dev/null
+++ b/testdata/xml/empty-doctype.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/empty-plist.plist b/testdata/xml/empty-plist.plist
new file mode 100644
index 0000000..8b232f6
--- /dev/null
+++ b/testdata/xml/empty-plist.plist
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/testdata/xml/empty-xml.plist b/testdata/xml/empty-xml.plist
new file mode 100644
index 0000000..05a26d1
--- /dev/null
+++ b/testdata/xml/empty-xml.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/invalid-before-plist.plist b/testdata/xml/invalid-before-plist.plist
new file mode 100644
index 0000000..ad9bd75
--- /dev/null
+++ b/testdata/xml/invalid-before-plist.plist
@@ -0,0 +1,9 @@
+
+
+invalid
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/invalid-data.plist b/testdata/xml/invalid-data.plist
new file mode 100644
index 0000000..7bb255e
--- /dev/null
+++ b/testdata/xml/invalid-data.plist
@@ -0,0 +1,9 @@
+
+
+
+
+ key
+ val
+invalid
+
+
diff --git a/testdata/xml/invalid-end.plist b/testdata/xml/invalid-end.plist
new file mode 100644
index 0000000..bafbc0c
--- /dev/null
+++ b/testdata/xml/invalid-end.plist
@@ -0,0 +1,9 @@
+
+
+
+
+ key
+ val
+
+
+invalid
diff --git a/testdata/xml/invalid-middle.plist b/testdata/xml/invalid-middle.plist
new file mode 100644
index 0000000..ed4abab
--- /dev/null
+++ b/testdata/xml/invalid-middle.plist
@@ -0,0 +1,9 @@
+
+invalid
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/invalid-start.plist b/testdata/xml/invalid-start.plist
new file mode 100644
index 0000000..8ac26f5
--- /dev/null
+++ b/testdata/xml/invalid-start.plist
@@ -0,0 +1,8 @@
+invalid
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/malformed-xml.plist b/testdata/xml/malformed-xml.plist
new file mode 100644
index 0000000..539ffb2
--- /dev/null
+++ b/testdata/xml/malformed-xml.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/no-both.plist b/testdata/xml/no-both.plist
new file mode 100644
index 0000000..4fa7ef5
--- /dev/null
+++ b/testdata/xml/no-both.plist
@@ -0,0 +1,6 @@
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/no-dict-end.plist b/testdata/xml/no-dict-end.plist
new file mode 100644
index 0000000..508e45c
--- /dev/null
+++ b/testdata/xml/no-dict-end.plist
@@ -0,0 +1,7 @@
+
+
+
+
+ key
+ val
+
diff --git a/testdata/xml/no-doctype.plist b/testdata/xml/no-doctype.plist
new file mode 100644
index 0000000..f8134b4
--- /dev/null
+++ b/testdata/xml/no-doctype.plist
@@ -0,0 +1,7 @@
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/no-plist-end.plist b/testdata/xml/no-plist-end.plist
new file mode 100644
index 0000000..d34f609
--- /dev/null
+++ b/testdata/xml/no-plist-end.plist
@@ -0,0 +1,7 @@
+
+
+
+
+ key
+ val
+
diff --git a/testdata/xml/no-plist-version.plist b/testdata/xml/no-plist-version.plist
new file mode 100644
index 0000000..6ef5b11
--- /dev/null
+++ b/testdata/xml/no-plist-version.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/no-xml-tag.plist b/testdata/xml/no-xml-tag.plist
new file mode 100644
index 0000000..80047b0
--- /dev/null
+++ b/testdata/xml/no-xml-tag.plist
@@ -0,0 +1,7 @@
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/swapped.plist b/testdata/xml/swapped.plist
new file mode 100644
index 0000000..0304264
--- /dev/null
+++ b/testdata/xml/swapped.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/unescaped-plist.plist b/testdata/xml/unescaped-plist.plist
new file mode 100644
index 0000000..d45ca28
--- /dev/null
+++ b/testdata/xml/unescaped-plist.plist
@@ -0,0 +1,8 @@
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/unescaped-xml.plist b/testdata/xml/unescaped-xml.plist
new file mode 100644
index 0000000..116dfe4
--- /dev/null
+++ b/testdata/xml/unescaped-xml.plist
@@ -0,0 +1,8 @@
+
+
+
+ key
+ val
+
+
diff --git a/testdata/xml/valid.plist b/testdata/xml/valid.plist
new file mode 100644
index 0000000..96f10ba
--- /dev/null
+++ b/testdata/xml/valid.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ key
+ val
+
+