ebml-go/unmarshal_test.go
2024-09-18 18:10:46 +02:00

688 lines
19 KiB
Go

// Copyright 2019 The ebml-go authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ebml
import (
"bytes"
"errors"
"fmt"
"io"
"reflect"
"testing"
"time"
"git.gammaspectra.live/WeebDataHoarder/ebml-go/internal/errs"
)
func ExampleUnmarshal() {
TestBinary := []byte{
0x1a, 0x45, 0xdf, 0xa3, // EBML
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // 0x10
0x42, 0x82, 0x85, 0x77, 0x65, 0x62, 0x6d, 0x00, // EBMLDocType = webm
0x42, 0x87, 0x81, 0x02, // DocTypeVersion = 2
0x42, 0x85, 0x81, 0x02, // DocTypeReadVersion = 2
}
type TestEBML struct {
Header struct {
DocType string `ebml:"EBMLDocType"`
DocTypeVersion uint64 `ebml:"EBMLDocTypeVersion"`
DocTypeReadVersion uint64 `ebml:"EBMLDocTypeReadVersion"`
} `ebml:"EBML"`
}
r := bytes.NewReader(TestBinary)
var ret TestEBML
if err := Unmarshal(r, &ret); err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Println(ret)
// Output: {{webm 2 2}}
}
func TestUnmarshal_MultipleUnknownSize(t *testing.T) {
b := []byte{
0x18, 0x53, 0x80, 0x67, // Segment
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x1F, 0x43, 0xB6, 0x75, // Cluster
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x42, 0x87, 0x81, 0x01,
0x1F, 0x43, 0xB6, 0x75, // Cluster
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x42, 0x87, 0x81, 0x02,
}
type Cluster struct {
DocTypeVersion uint64 `ebml:"EBMLDocTypeVersion"`
}
type Segment struct {
Cluster []Cluster `ebml:"Cluster"`
}
type TestEBML struct {
Segment Segment `ebml:"Segment"`
}
expected := TestEBML{
Segment: Segment{
Cluster: []Cluster{{0x01}, {0x02}},
},
}
var ret TestEBML
if err := Unmarshal(bytes.NewReader(b), &ret); err != nil {
t.Fatalf("Unexpected error: '%v'\n", err)
}
if !reflect.DeepEqual(expected, ret) {
t.Errorf("Expected result: %v, got: %v", expected, ret)
}
}
func TestUnmarshal_Convert(t *testing.T) {
cases := map[string]struct {
b []byte
expected interface{}
}{
"UInt64ToUInt64": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion uint64 `ebml:"EBMLDocTypeVersion"`
}{2},
},
"UInt64ToUInt32": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion uint32 `ebml:"EBMLDocTypeVersion"`
}{2},
},
"UInt64ToUInt16": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion uint16 `ebml:"EBMLDocTypeVersion"`
}{2},
},
"UInt64ToUInt8": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion uint8 `ebml:"EBMLDocTypeVersion"`
}{2},
},
"UInt64ToUInt": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion uint `ebml:"EBMLDocTypeVersion"`
}{2},
},
"Int64ToInt64": {
[]byte{0xFB, 0x81, 0xFF},
struct {
ReferenceBlock int64 `ebml:"ReferenceBlock"`
}{-1},
},
"Int64ToInt32": {
[]byte{0xFB, 0x81, 0xFF},
struct {
ReferenceBlock int32 `ebml:"ReferenceBlock"`
}{-1},
},
"Int64ToInt16": {
[]byte{0xFB, 0x81, 0xFF},
struct {
ReferenceBlock int16 `ebml:"ReferenceBlock"`
}{-1},
},
"Int64ToInt8": {
[]byte{0xFB, 0x81, 0xFF},
struct {
ReferenceBlock int8 `ebml:"ReferenceBlock"`
}{-1},
},
"Int64ToInt": {
[]byte{0xFB, 0x81, 0xFF},
struct {
ReferenceBlock int `ebml:"ReferenceBlock"`
}{-1},
},
"Float64ToFloat64": {
[]byte{0x44, 0x89, 0x84, 0x00, 0x00, 0x00, 0x00},
struct {
Duration float64 `ebml:"Duration"`
}{0.0},
},
"Float64ToFloat32": {
[]byte{0x44, 0x89, 0x84, 0x00, 0x00, 0x00, 0x00},
struct {
Duration float32 `ebml:"Duration"`
}{0.0},
},
"UInt64ToUInt64Slice": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion []uint64 `ebml:"EBMLDocTypeVersion"`
}{[]uint64{2}},
},
"UInt64ToUInt32Slice": {
[]byte{0x42, 0x87, 0x81, 0x02},
struct {
DocTypeVersion []uint32 `ebml:"EBMLDocTypeVersion"`
}{[]uint32{2}},
},
"Int64ToInt32Slice": {
[]byte{0xFB, 0x81, 0xFF},
struct {
ReferenceBlock []int32 `ebml:"ReferenceBlock"`
}{[]int32{-1}},
},
"Float64ToFloat32Slice": {
[]byte{0x44, 0x89, 0x84, 0x00, 0x00, 0x00, 0x00},
struct {
Duration []float32 `ebml:"Duration"`
}{[]float32{0.0}},
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
ret := reflect.New(reflect.ValueOf(c.expected).Type())
if err := Unmarshal(bytes.NewReader(c.b), ret.Interface()); err != nil {
t.Fatalf("Unexpected error: '%v'\n", err)
}
if !reflect.DeepEqual(c.expected, ret.Elem().Interface()) {
t.Errorf("Expected convert result: %v, got %v",
c.expected, ret.Elem().Interface())
}
})
}
}
func TestUnmarshal_OptionError(t *testing.T) {
errExpected := errors.New("an error")
err := Unmarshal(&bytes.Buffer{}, &struct{}{},
func(*UnmarshalOptions) error {
return errExpected
},
)
if err != errExpected {
t.Errorf("Expected error against failing UnmarshalOption: '%v', got: '%v'", errExpected, err)
}
}
func TestUnmarshal_WithElementReadHooks(t *testing.T) {
TestBinary := []byte{
0x18, 0x53, 0x80, 0x67, 0xa6, // Segment
0x1c, 0x53, 0xbb, 0x6b, 0x80, // Cues (empty)
0x16, 0x54, 0xae, 0x6b, 0x9c, // Tracks
0xae, 0x8c, // TrackEntry[0]
0x53, 0x6e, 0x86, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x00, // Name=Video
0xd7, 0x81, 0x01, // TrackNumber=1
0xae, 0x8c, // TrackEntry[1]
0x53, 0x6e, 0x86, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x00, // Name=Audio
0xd7, 0x81, 0x02, // TrackNumber=2
}
type TestEBML struct {
Segment struct {
Tracks struct {
TrackEntry []struct {
Name string `ebml:"Name,omitempty"`
TrackNumber uint64 `ebml:"TrackNumber"`
} `ebml:"TrackEntry"`
} `ebml:"Tracks"`
} `ebml:"Segment"`
}
r := bytes.NewReader(TestBinary)
var ret TestEBML
m := make(map[string][]*Element)
hook := withElementMap(m)
if err := Unmarshal(r, &ret, WithElementReadHooks(hook)); err != nil {
t.Errorf("Unexpected error: '%v'", err)
}
// Verify positions of elements
expected := map[string][]uint64{
"Segment": {0},
"Segment.Tracks": {10},
"Segment.Tracks.TrackEntry": {15, 29},
"Segment.Tracks.TrackEntry.Name": {17, 31},
"Segment.Tracks.TrackEntry.TrackNumber": {26, 40},
}
posMap := elementPositionMap(m)
if !reflect.DeepEqual(expected, posMap) {
t.Errorf("Unexpected read hook positions, \nexpected: %v, \n got: %v", expected, posMap)
}
checkTarget := "Segment.Tracks.TrackEntry.Name"
switch {
case len(m[checkTarget]) != 2:
t.Fatalf("%s read hook should be called twice, but called %d times",
checkTarget, len(m[checkTarget]))
case m[checkTarget][0].Type != ElementName:
t.Fatalf("ElementType of %s should be %s, got %s",
checkTarget, ElementName, m[checkTarget][0].Type)
}
switch v, ok := m[checkTarget][0].Value.(string); {
case !ok:
t.Errorf("Invalid type of data: %T", v)
case v != "Video":
t.Errorf("The value should be Video, got %s", v)
}
}
func TestUnmarshal_Chan(t *testing.T) {
TestBinary := []byte{
0x18, 0x53, 0x80, 0x67, 0x8f, // Segment
0x16, 0x54, 0xae, 0x6b, 0x8a, // Tracks
0xae, 0x83, // TrackEntry[0]
0xd7, 0x81, 0x01, // TrackNumber=1
0xae, 0x83, // TrackEntry[0]
0xd7, 0x81, 0x02, // TrackNumber=2
}
type TestEBML struct {
Segment struct {
Tracks struct {
TrackEntry struct {
TrackNumber chan uint64 `ebml:"TrackNumber"`
} `ebml:"TrackEntry"`
} `ebml:"Tracks"`
} `ebml:"Segment"`
}
var ret TestEBML
ch := make(chan uint64, 100)
ret.Segment.Tracks.TrackEntry.TrackNumber = ch
done := make(chan struct{})
go func() {
select {
case <-time.After(5 * time.Second):
panic("test timeout")
case <-done:
}
}()
if err := Unmarshal(bytes.NewReader(TestBinary), &ret); err != nil {
t.Errorf("Unexpected error: '%v'", err)
}
close(done)
if len(ch) != 2 {
t.Fatalf("Element chan should be sent twice, but sent %d times", len(ch))
}
if v := <-ch; v != 1 {
t.Errorf("First value should be 1, got %d", v)
}
if v := <-ch; v != 2 {
t.Errorf("Second value should be 2, got %d", v)
}
}
func TestUnmarshal_Tag(t *testing.T) {
var tagged struct {
DocCustomNamedType string `ebml:"EBMLDocType"`
}
var untagged struct {
EBMLDocType string
}
b := []byte{0x42, 0x82, 0x85, 0x68, 0x6F, 0x67, 0x65, 0x00}
if err := Unmarshal(bytes.NewBuffer(b), &tagged); err != nil {
t.Fatalf("Unexpected error: '%v'", err)
}
if err := Unmarshal(bytes.NewBuffer(b), &untagged); err != nil {
t.Fatalf("Unexpected error: '%v'", err)
}
if tagged.DocCustomNamedType != untagged.EBMLDocType {
t.Errorf("Unmarshal result to tagged and and untagged struct must be same, tagged: %v, untagged: %v", tagged, untagged)
}
}
func TestUnmarshal_Map(t *testing.T) {
b := []byte{
0x1A, 0x45, 0xDF, 0xA3, 0x8C,
0x42, 0x82, 0x85, 0x68, 0x6F, 0x67, 0x65, 0x00,
0xEC, 0x82, 0x00, 0x00,
0x18, 0x53, 0x80, 0x67, 0xFF,
0x1F, 0x43, 0xB6, 0x75, 0x80,
0x1F, 0x43, 0xB6, 0x75, 0x80,
0x1F, 0x43, 0xB6, 0x75, 0x80,
}
expected := map[string]interface{}{
"EBML": map[string]interface{}{
"EBMLDocType": "hoge",
"Void": []uint8{0, 0},
},
"Segment": map[string]interface{}{
"Cluster": []interface{}{
map[string]interface{}{},
map[string]interface{}{},
map[string]interface{}{},
},
},
}
t.Run("AllocatedMap", func(t *testing.T) {
ret := make(map[string]interface{})
if err := Unmarshal(bytes.NewBuffer(b), &ret); err != nil {
t.Fatalf("Unexpected error: '%v'", err)
}
if !reflect.DeepEqual(expected, ret) {
t.Errorf("Unmarshal to map differs from expected:\n%#+v\ngot:\n%#+v", expected, ret)
}
})
t.Run("NilMap", func(t *testing.T) {
var ret map[string]interface{}
if err := Unmarshal(bytes.NewBuffer(b), &ret); err != nil {
t.Fatalf("Unexpected error: '%v'", err)
}
if !reflect.DeepEqual(expected, ret) {
t.Errorf("Unmarshal to map differs from expected:\n%#+v\ngot:\n%#+v", expected, ret)
}
})
}
func TestUnmarshal_IgnoreUnknown(t *testing.T) {
b := []byte{
0x1A, 0x45, 0xDF, 0xA3, 0x8A,
0x42, 0x82, 0x85, 0x68, 0x6F, 0x67, 0x65, 0x00,
0x81, 0x81, // 0x81 is not defined in Matroska v4
0x18, 0x53, 0x80, 0x67, 0xFF,
0x1F, 0x43, 0xB6, 0x75, 0x80,
0x1F, 0x43, 0xB6, 0x75, 0x80,
}
expected := map[string]interface{}{
"EBML": map[string]interface{}{
"EBMLDocType": "hoge",
},
"Segment": map[string]interface{}{
"Cluster": []interface{}{
map[string]interface{}{},
map[string]interface{}{},
},
},
}
ret := make(map[string]interface{})
if err := Unmarshal(bytes.NewBuffer(b), &ret, WithIgnoreUnknown(true)); err != nil {
t.Fatalf("Unexpected error: '%v'", err)
}
if !reflect.DeepEqual(expected, ret) {
t.Errorf("Unmarshal with IgnoreUnknown differs from expected:\n%#+v\ngot:\n%#+v", expected, ret)
}
}
func TestUnmarshal_Error(t *testing.T) {
type TestEBML struct {
Header struct {
} `ebml:"EBML"`
}
t.Run("NilValue", func(t *testing.T) {
if err := Unmarshal(bytes.NewBuffer([]byte{}), nil); !errs.Is(err, ErrIndefiniteType) {
t.Errorf("Expected error: '%v', got: '%v'", ErrIndefiniteType, err)
}
})
t.Run("NonPtr", func(t *testing.T) {
if err := Unmarshal(bytes.NewBuffer([]byte{}), struct{}{}); !errs.Is(err, ErrIncompatibleType) {
t.Errorf("Expected error: '%v', got: '%v'", ErrIncompatibleType, err)
}
})
t.Run("UnknownElementName", func(t *testing.T) {
input := &struct {
Header struct {
} `ebml:"Unknown"`
}{}
if err := Unmarshal(bytes.NewBuffer([]byte{}), input); !errs.Is(err, ErrUnknownElementName) {
t.Errorf("Expected error: '%v', got: '%v'", ErrUnknownElementName, err)
}
})
t.Run("InvalidTag", func(t *testing.T) {
input := &struct {
Header struct {
} `ebml:"EBML,ivalid"`
}{}
if err := Unmarshal(bytes.NewBuffer([]byte{}), input); !errs.Is(err, ErrInvalidTag) {
t.Errorf("Expected error: '%v', got: '%v'", ErrInvalidTag, err)
}
})
t.Run("UnknownElement", func(t *testing.T) {
input := &TestEBML{}
b := []byte{0x81}
if err := Unmarshal(bytes.NewBuffer(b), input); !errs.Is(err, ErrUnknownElement) {
t.Errorf("Expected error: '%v', got: '%v'", ErrUnknownElement, err)
}
})
t.Run("NonStaticUnknownElementWithIgnoreUnknown", func(t *testing.T) {
input := &TestEBML{}
b := []byte{0x81, 0xFF}
if err := Unmarshal(
bytes.NewBuffer(b), input, WithIgnoreUnknown(true),
); err != nil {
t.Errorf("Unexpected error: '%v'", err)
}
})
t.Run("ShortUnknownElementWithIgnoreUnknown", func(t *testing.T) {
input := &TestEBML{}
b := []byte{0x81, 0x85, 0x00}
if err := Unmarshal(
bytes.NewBuffer(b), input, WithIgnoreUnknown(true),
); err != nil {
t.Errorf("Unexpected error: '%v'", err)
}
})
t.Run("Short", func(t *testing.T) {
TestBinaries := map[string][]byte{
"ElementID": {0x1a, 0x45, 0xdf},
"DataSize": {0x42, 0x86, 0x40},
"UInt(0)": {0x42, 0x86, 0x84},
"UInt": {0x42, 0x86, 0x84, 0x00},
"Float(0)": {0x44, 0x89, 0x84},
"Float": {0x44, 0x89, 0x84, 0x00},
"String(0)": {0x42, 0x82, 0x84},
"String": {0x42, 0x82, 0x84, 0x00},
}
for name, b := range TestBinaries {
t.Run(name, func(t *testing.T) {
var val TestEBML
if err := Unmarshal(bytes.NewBuffer(b), &val); !errs.Is(err, io.ErrUnexpectedEOF) {
t.Errorf("Expected error: '%v', got: '%v'", io.ErrUnexpectedEOF, err)
}
})
}
})
t.Run("ErrorPropagation", func(t *testing.T) {
TestBinaries := map[string][]byte{
"UInt": {0x42, 0x86, 0x84, 0x00, 0x00, 0x00, 0x00},
"Float": {0x44, 0x89, 0x84, 0x00, 0x00, 0x00, 0x00},
"String": {0x42, 0x82, 0x84, 0x00, 0x00, 0x00, 0x00},
"Block": {0xA3, 0x85, 0x81, 0x00, 0x00, 0x00, 0x00},
"BlockXiph": {0xA3, 0x88, 0x81, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00},
"BlockFixed": {0xA3, 0x87, 0x81, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00},
"BlockEBML": {0xA3, 0x88, 0x98, 0x00, 0x00, 0x06, 0x01, 0x81, 0x00, 0x00},
}
for name, b := range TestBinaries {
t.Run(name, func(t *testing.T) {
for i := 1; i < len(b)-1; i++ {
var val TestEBML
r := &delayedBrokenReader{b: b, limit: i}
if err := Unmarshal(r, &val); !errs.Is(err, io.ErrClosedPipe) {
t.Errorf("Error is not propagated from Reader, limit: %d, expected: '%v', got: '%v'", i, io.ErrClosedPipe, err)
}
}
})
}
})
t.Run("Incompatible", func(t *testing.T) {
cases := map[string]struct {
b []byte
ret interface{}
err error
}{
"UInt64ToInt64": {
b: []byte{0x42, 0x87, 0x81, 0x02},
ret: &struct {
DocTypeVersion int64 `ebml:"EBMLDocTypeVersion"`
}{},
err: ErrIncompatibleType,
},
"Int64ToUInt64": {
b: []byte{0xFB, 0x81, 0xFF},
ret: &struct {
ReferenceBlock uint64 `ebml:"ReferenceBlock"`
}{},
err: ErrIncompatibleType,
},
"Float64ToInt64": {
b: []byte{0x44, 0x89, 0x84, 0x00, 0x00, 0x00, 0x00},
ret: &struct {
Duration int64 `ebml:"Duration"`
}{},
err: ErrIncompatibleType,
},
"StringToInt64": {
b: []byte{0x42, 0x82, 0x85, 0x77, 0x65, 0x62, 0x6d, 0x00},
ret: &struct {
EBMLDocType int64 `ebml:"EBMLDocType"`
}{},
err: ErrIncompatibleType,
},
"UInt64ToInt64Slice": {
b: []byte{0x42, 0x87, 0x81, 0x02},
ret: &struct {
DocTypeVersion []int64 `ebml:"EBMLDocTypeVersion"`
}{},
err: ErrIncompatibleType,
},
"Int64ToUInt64Slice": {
b: []byte{0xFB, 0x81, 0xFF},
ret: &struct {
ReferenceBlock []uint64 `ebml:"ReferenceBlock"`
}{},
err: ErrIncompatibleType,
},
"Float64ToInt64Slice": {
b: []byte{0x44, 0x89, 0x84, 0x00, 0x00, 0x00, 0x00},
ret: &struct {
Duration []int64 `ebml:"Duration"`
}{},
err: ErrIncompatibleType,
},
"StringToInt64Slice": {
b: []byte{0x42, 0x82, 0x85, 0x77, 0x65, 0x62, 0x6d, 0x00},
ret: &struct {
EBMLDocType []int64 `ebml:"EBMLDocType"`
}{},
err: ErrIncompatibleType,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
if err := Unmarshal(bytes.NewBuffer(c.b), c.ret); !errs.Is(err, c.err) {
t.Errorf("Expected error: '%v', got: '%v'", c.err, err)
}
})
}
})
}
func ExampleUnmarshal_partial() {
TestBinary := []byte{
0x1a, 0x45, 0xdf, 0xa3, 0x84, // EBML
0x42, 0x87, 0x81, 0x02, // DocTypeVersion = 2
0x18, 0x53, 0x80, 0x67, 0xFF, // Segment
0x16, 0x54, 0xae, 0x6b, 0x85, // Tracks
0xae, 0x83, // TrackEntry[0]
0xd7, 0x81, 0x01, // TrackNumber=1
0x1F, 0x43, 0xB6, 0x75, 0xFF, // Cluster
0xE7, 0x81, 0x00, // Timecode
0xA3, 0x86, 0x81, 0x00, 0x00, 0x88, 0xAA, 0xCC, // SimpleBlock
}
type TestHeader struct {
Header map[string]interface{} `ebml:"EBML"`
Segment struct {
Tracks map[string]interface{} `ebml:"Tracks,stop"` // Stop unmarshalling after reading this element
}
}
type TestClusters struct {
Cluster []struct {
Timecode uint64
SimpleBlock []Block
}
}
r := bytes.NewReader(TestBinary)
var header TestHeader
if err := Unmarshal(r, &header); !errs.Is(err, ErrReadStopped) {
panic("Unmarshal failed")
}
fmt.Printf("First unmarshal: %v\n", header)
var clusters TestClusters
if err := Unmarshal(r, &clusters); err != nil {
panic("Unmarshal failed")
}
fmt.Printf("Second unmarshal: %v\n", clusters)
// Output:
// First unmarshal: {map[EBMLDocTypeVersion:2] {map[TrackEntry:map[TrackNumber:1]]}}
// Second unmarshal: {[{0 [{1 0 true true 0 false [[170 204]]}]}]}
}
func BenchmarkUnmarshal(b *testing.B) {
TestBinary := []byte{
0x1a, 0x45, 0xdf, 0xa3, // EBML
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // 0x10
0x42, 0x82, 0x85, 0x77, 0x65, 0x62, 0x6d, 0x00, // DocType = webm
0x42, 0x87, 0x81, 0x02, // DocTypeVersion = 2
0x42, 0x85, 0x81, 0x02, // DocTypeReadVersion = 2
0x18, 0x53, 0x80, 0x67, 0xFF, // Segment
0x1F, 0x43, 0xB6, 0x75, 0xFF, // Cluster
0xE7, 0x81, 0x00, // Timecode
0xA3, 0x86, 0x81, 0x00, 0x00, 0x88, 0xAA, 0xCC, // SimpleBlock
0xA3, 0x86, 0x81, 0x00, 0x10, 0x88, 0xAA, 0xCC, // SimpleBlock
0xA3, 0x86, 0x81, 0x00, 0x20, 0x88, 0xAA, 0xCC, // SimpleBlock
0x1F, 0x43, 0xB6, 0x75, 0xFF, // Cluster
0xE7, 0x81, 0x10, // Timecode
0xA3, 0x86, 0x81, 0x00, 0x00, 0x88, 0xAA, 0xCC, // SimpleBlock
0xA3, 0x86, 0x81, 0x00, 0x10, 0x88, 0xAA, 0xCC, // SimpleBlock
0xA3, 0x86, 0x81, 0x00, 0x20, 0x88, 0xAA, 0xCC, // SimpleBlock
}
type TestEBML struct {
Header struct {
DocType string `ebml:"EBMLDocType"`
DocTypeVersion uint64 `ebml:"EBMLDocTypeVersion"`
DocTypeReadVersion uint64 `ebml:"EBMLDocTypeReadVersion"`
} `ebml:"EBML"`
Segment []struct {
Cluster struct {
Timecode uint64
SimpleBlock []Block
}
}
}
var ret TestEBML
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := Unmarshal(bytes.NewReader(TestBinary), &ret); err != nil {
b.Fatalf("Unexpected error: '%v'", err)
}
}
}