| package plist |
| |
| import ( |
| "bytes" |
| "fmt" |
| "reflect" |
| "testing" |
| ) |
| |
| func BenchmarkXMLDecode(b *testing.B) { |
| for i := 0; i < b.N; i++ { |
| b.StopTimer() |
| var bval interface{} |
| buf := bytes.NewReader([]byte(plistValueTreeAsXML)) |
| b.StartTimer() |
| decoder := NewDecoder(buf) |
| decoder.Decode(bval) |
| b.StopTimer() |
| } |
| } |
| |
| func BenchmarkBplistDecode(b *testing.B) { |
| for i := 0; i < b.N; i++ { |
| b.StopTimer() |
| var bval interface{} |
| buf := bytes.NewReader(plistValueTreeAsBplist) |
| b.StartTimer() |
| decoder := NewDecoder(buf) |
| decoder.Decode(bval) |
| b.StopTimer() |
| } |
| } |
| |
| func TestLaxDecode(t *testing.T) { |
| var laxTestDataStringsOnlyAsXML = `{B=1;D="2013-11-27 00:34:00 +0000";I64=1;F64="3.0";U64=2;}` |
| d := LaxTestData{} |
| buf := bytes.NewReader([]byte(laxTestDataStringsOnlyAsXML)) |
| decoder := NewDecoder(buf) |
| decoder.lax = true |
| err := decoder.Decode(&d) |
| if err != nil { |
| t.Error(err.Error()) |
| } |
| |
| if d != laxTestData { |
| t.Logf("Expected: %#v", laxTestData) |
| t.Logf("Received: %#v", d) |
| t.Fail() |
| } |
| } |
| |
| func TestIllegalLaxDecode(t *testing.T) { |
| i := int64(0) |
| u := uint64(0) |
| f := float64(0) |
| b := false |
| plists := []struct { |
| pl string |
| d interface{} |
| }{ |
| {"<string>abc</string>", &i}, |
| {"<string>abc</string>", &u}, |
| {"<string>def</string>", &f}, |
| {"<string>ghi</string>", &b}, |
| {"<string>jkl</string>", []byte{0x00}}, |
| } |
| |
| for _, plist := range plists { |
| buf := bytes.NewReader([]byte(plist.pl)) |
| decoder := NewDecoder(buf) |
| decoder.lax = true |
| err := decoder.Decode(plist.d) |
| t.Logf("Error: %v", err) |
| if err == nil { |
| t.Error("Expected error, received nothing.") |
| } |
| } |
| } |
| |
| func TestIllegalDecode(t *testing.T) { |
| i := int64(0) |
| b := false |
| plists := []struct { |
| pl string |
| d interface{} |
| }{ |
| {"<string>abc</string>", &i}, |
| {"<data>ABC=</data>", &i}, |
| {"<real>34.1</real>", &i}, |
| {"<true>def</true>", &i}, |
| {"<date>2010-01-01T00:00:00Z</date>", &i}, |
| {"<integer>0</integer>", &b}, |
| {"<array><integer>0</integer></array>", &b}, |
| {"<dict><key>a</key><integer>0</integer></dict>", &b}, |
| {"<array><true/><true/><true/></array>", &[1]int{1}}, |
| {"<data>SGVsbG8=</data>", &[3]byte{}}, |
| } |
| |
| for _, plist := range plists { |
| buf := bytes.NewReader([]byte(plist.pl)) |
| decoder := NewDecoder(buf) |
| err := decoder.Decode(plist.d) |
| t.Logf("Error: %v", err) |
| if err == nil { |
| t.Error("Expected error, received nothing.") |
| } |
| } |
| } |
| |
| func TestDecode(t *testing.T) { |
| for _, test := range tests { |
| subtest(t, test.Name, func(t *testing.T) { |
| expVal := test.DecodeValue |
| if expVal == nil { |
| expVal = test.Value |
| } |
| |
| expReflect := reflect.ValueOf(expVal) |
| if !expReflect.IsValid() || isEmptyInterface(expReflect) { |
| return |
| } |
| if expReflect.Kind() == reflect.Ptr || expReflect.Kind() == reflect.Interface { |
| // Unbox pointer for comparison's sake |
| expReflect = expReflect.Elem() |
| } |
| expVal = expReflect.Interface() |
| |
| results := make(map[int]interface{}) |
| for fmt, doc := range test.Documents { |
| if test.SkipDecode[fmt] { |
| return |
| } |
| subtest(t, FormatNames[fmt], func(t *testing.T) { |
| val := reflect.New(expReflect.Type()).Interface() |
| _, err := Unmarshal(doc, val) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| valReflect := reflect.ValueOf(val) |
| if valReflect.Kind() == reflect.Ptr || valReflect.Kind() == reflect.Interface { |
| // Unbox pointer for comparison's sake |
| valReflect = valReflect.Elem() |
| val = valReflect.Interface() |
| } |
| |
| results[fmt] = val |
| if !reflect.DeepEqual(expVal, val) { |
| t.Logf("Expected: %#v\n", expVal) |
| t.Logf("Received: %#v\n", val) |
| t.Fail() |
| } |
| }) |
| } |
| |
| if results[BinaryFormat] != nil && results[XMLFormat] != nil { |
| if !reflect.DeepEqual(results[BinaryFormat], results[XMLFormat]) { |
| t.Log("Binary and XML decoding yielded different values.") |
| t.Log("Binary:", results[BinaryFormat]) |
| t.Log("XML :", results[XMLFormat]) |
| t.Fail() |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestInterfaceDecode(t *testing.T) { |
| var xval interface{} |
| buf := bytes.NewReader([]byte{98, 112, 108, 105, 115, 116, 48, 48, 214, 1, 13, 17, 21, 25, 27, 2, 14, 18, 22, 26, 28, 88, 105, 110, 116, 97, 114, 114, 97, 121, 170, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 1, 16, 8, 16, 16, 16, 32, 16, 64, 16, 2, 16, 9, 16, 17, 16, 33, 16, 65, 86, 102, 108, 111, 97, 116, 115, 162, 15, 16, 34, 66, 0, 0, 0, 35, 64, 80, 0, 0, 0, 0, 0, 0, 88, 98, 111, 111, 108, 101, 97, 110, 115, 162, 19, 20, 9, 8, 87, 115, 116, 114, 105, 110, 103, 115, 162, 23, 24, 92, 72, 101, 108, 108, 111, 44, 32, 65, 83, 67, 73, 73, 105, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 78, 22, 117, 76, 84, 100, 97, 116, 97, 68, 1, 2, 3, 4, 84, 100, 97, 116, 101, 51, 65, 184, 69, 117, 120, 0, 0, 0, 8, 21, 30, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 68, 71, 76, 85, 94, 97, 98, 99, 107, 110, 123, 142, 147, 152, 157, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166}) |
| decoder := NewDecoder(buf) |
| err := decoder.Decode(&xval) |
| if err != nil { |
| t.Log("Error:", err) |
| t.Fail() |
| } |
| } |
| |
| func TestFormatDetection(t *testing.T) { |
| type formatTest struct { |
| expectedFormat int |
| data []byte |
| } |
| plists := []formatTest{ |
| {BinaryFormat, []byte{98, 112, 108, 105, 115, 116, 48, 48, 85, 72, 101, 108, 108, 111, 8, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14}}, |
| {XMLFormat, []byte(`<string><*I3></string>`)}, |
| {InvalidFormat, []byte(`bplist00`)}, // Looks like a binary property list, and bplist does not have fallbacks(!) |
| {OpenStepFormat, []byte(`(1,2,3,4,5)`)}, |
| {OpenStepFormat, []byte(`<abab>`)}, |
| {GNUStepFormat, []byte(`(1,2,<*I3>)`)}, |
| {InvalidFormat, []byte{0x00}}, // This isn't a valid property list of any sort. |
| } |
| |
| for i, fmttest := range plists { |
| fmt, err := Unmarshal(fmttest.data, nil) |
| if fmt != fmttest.expectedFormat { |
| t.Errorf("plist %d: Wanted %s, received %s.", i, FormatNames[fmttest.expectedFormat], FormatNames[fmt]) |
| } |
| if err != nil { |
| t.Logf("plist %d: Error: %v", i, err) |
| } |
| } |
| } |
| |
| func ExampleDecoder_Decode() { |
| type sparseBundleHeader struct { |
| InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"` |
| BandSize uint64 `plist:"band-size"` |
| BackingStoreVersion int `plist:"bundle-backingstore-version"` |
| DiskImageBundleType string `plist:"diskimage-bundle-type"` |
| Size uint64 `plist:"size"` |
| } |
| |
| buf := bytes.NewReader([]byte(`<?xml version="1.0" encoding="UTF-8"?> |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| <plist version="1.0"> |
| <dict> |
| <key>CFBundleInfoDictionaryVersion</key> |
| <string>6.0</string> |
| <key>band-size</key> |
| <integer>8388608</integer> |
| <key>bundle-backingstore-version</key> |
| <integer>1</integer> |
| <key>diskimage-bundle-type</key> |
| <string>com.apple.diskimage.sparsebundle</string> |
| <key>size</key> |
| <integer>4398046511104</integer> |
| </dict> |
| </plist>`)) |
| |
| var data sparseBundleHeader |
| decoder := NewDecoder(buf) |
| err := decoder.Decode(&data) |
| if err != nil { |
| fmt.Println(err) |
| } |
| fmt.Println(data) |
| |
| // Output: {6.0 8388608 1 com.apple.diskimage.sparsebundle 4398046511104} |
| } |