av/stream/mts/psi/psi_test.go

376 lines
8.6 KiB
Go

/*
NAME
psi_test.go
DESCRIPTION
See Readme.md
AUTHOR
Saxon Milton <saxon@ausocean.org>
LICENSE
psi_test.go is Copyright (C) 2018 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package psi
import (
"bytes"
"testing"
)
// Some common manifestations of PSI
var (
// standardPat is a minimal PAT.
standardPat = PSI{
Pf: 0x00,
Tid: 0x00,
Ssi: true,
Pb: false,
Sl: 0x0d,
Tss: &TSS{
Tide: 0x01,
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PAT{
Pn: 0x01,
Pmpid: 0x1000,
},
},
}
// standardPmt is a minimal PMT, without time and location descriptors.
standardPmt = PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: 0x12,
Tss: &TSS{
Tide: 0x01,
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100, // wrong
Pil: 0,
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
}
// standardPmtTimeLocation is a standard PMT with time and location
// descriptors, but time and location fields zeroed out.
standardPmtWithMeta = PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: 0x3e,
Tss: &TSS{
Tide: 0x01,
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100,
Pil: PmtTimeLocationPil,
Pd: []Desc{
{
Dt: TimeDescTag,
Dl: TimeDataSize,
Dd: make([]byte, TimeDataSize),
},
{
Dt: LocationDescTag,
Dl: LocationDataSize,
Dd: make([]byte, LocationDataSize),
},
},
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
}
)
// Times as ints for testing
const (
tstTime1 = 1235367435 // 0x49a2360b
tstTime2 = 1735357535 // 0x676f745f
)
// GPS string for testing
// TODO: make these realistic
const (
locationTstStr1 = "$GPGGA,123519,4807.038,N,01131.0"
locationTstStr2 = "$GPGGA,183710,4902.048,N,02171.0"
)
// err message
const (
errCmp = "Incorrect output, for: %v \nwant: %v, \ngot: %v"
)
// Test time to bytes test Data
var (
timeSlice = []byte{
0x00, 0x00, 0x00, 0x00, 0x49, 0xA2, 0x36, 0x0B,
}
)
// Parts to construct bytes of pmt with time and bytes
var (
pmtWithMetaHead = []byte{
0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a,
TimeDescTag, // Descriptor tag for timestamp
TimeDataSize, // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x74, 0x5f, // Timestamp data
LocationDescTag, // Descriptor tag for location
LocationDataSize, // Length of bytes to follow
}
pmtWithMetaTail = []byte{
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}
)
var (
// Bytes representing pmt with tstTime1
pmtTimeBytes1 = []byte{
0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a,
TimeDescTag, // Descriptor tag
TimeDataSize, // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x49, 0xa2, 0x36, 0x0b, // timestamp
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}
// Bytes representing pmt with tstTime 2
pmtTimeBytes2 = []byte{
0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a,
TimeDescTag, // Descriptor tag
TimeDataSize, // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x74, 0x5f, // timestamp
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}
// Bytes representing pmt with time1 and location1
pmtWithMetaTst1 = buildPmtWithMeta(locationTstStr1)
// bytes representing pmt with with time1 and location 2
pmtWithMetaTst2 = buildPmtWithMeta(locationTstStr2)
)
// bytesTests contains data for testing the Bytes() funcs for the PSI data struct
var bytesTests = []struct {
name string
input PSI
want []byte
}{
// Pat test
{
name: "pat Bytes()",
input: standardPat,
want: StandardPatBytes,
},
// Pmt test data no descriptor
{
name: "pmt to Bytes() without descriptors",
input: standardPmt,
want: StandardPmtBytes,
},
// Pmt with time descriptor
{
name: "pmt to Bytes() with time descriptor",
input: PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: 0x12,
Tss: &TSS{
Tide: 0x01,
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100, // wrong
Pil: 10,
Pd: []Desc{
{
Dt: TimeDescTag,
Dl: TimeDataSize,
Dd: TimeBytes(tstTime1),
},
},
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
},
want: pmtTimeBytes1,
},
// Pmt with time and location
{
name: "pmt Bytes() with time and location",
input: PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: 0x12,
Tss: &TSS{
Tide: 0x01,
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100, // wrong
Pil: 10,
Pd: []Desc{
{
Dt: TimeDescTag,
Dl: TimeDataSize,
Dd: TimeBytes(tstTime2),
},
{
Dt: LocationDescTag,
Dl: LocationDataSize,
Dd: []byte(locationTstStr1),
},
},
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
},
want: buildPmtWithMeta(locationTstStr1),
},
}
// TestBytes ensures that the Bytes() funcs are working correctly to take PSI
// structs and convert them to byte slices
func TestBytes(t *testing.T) {
for _, test := range bytesTests {
got := test.input.Bytes()
if !bytes.Equal(got, addPadding(addCrc(test.want))) {
t.Errorf("unexpected error for test %v: got:%v want:%v", test.name, got,
test.want)
}
}
}
// TestTimestampToBytes is a quick sanity check of the int64 time to []byte func
func TestTimestampToBytes(t *testing.T) {
tb := TimeBytes(tstTime1)
if !bytes.Equal(timeSlice, tb) {
t.Errorf(errCmp, "testTimeStampToBytes", timeSlice, tb)
}
}
// TestTimeUpdate checks to see if we can correctly update the timstamp in pmt
func TestTimeUpdate(t *testing.T) {
cpy := make([]byte, len(pmtTimeBytes1))
copy(cpy, pmtTimeBytes1)
cpy = addCrc(cpy)
err := UpdateTime(cpy, tstTime2)
cpy = cpy[:len(cpy)-4]
if err != nil {
t.Errorf("Update time returned err: %v", err)
}
if !bytes.Equal(pmtTimeBytes2, cpy) {
t.Errorf(errCmp, "TestTimeUpdate", pmtTimeBytes2, cpy)
}
}
// TestTimeGet tsts to see if we can correctly get the timestamp from a pmt
func TestTimeGet(t *testing.T) {
s, err := TimeFrom(pmtTimeBytes1)
if err != nil {
t.Errorf("Getting timestamp failed with err: %v", err)
}
if s != tstTime1 {
t.Errorf(errCmp, "TestTimeGet", tstTime1, s)
}
}
// TestLocationGet checks that we can correctly get location data from a pmt table
func TestLocationGet(t *testing.T) {
pb := standardPmtWithMeta.Bytes()
err := UpdateLocation(pb, locationTstStr1)
if err != nil {
t.Errorf("Error for TestLocationGet UpdateLocation(pb, locationTstStr1): %v", err)
}
g, err := LocationFrom(pb)
if err != nil {
t.Errorf("Error for TestLocationGet LocationOf(pb): %v", err)
}
if g != locationTstStr1 {
t.Errorf(errCmp, "TestLocationGet", locationTstStr1, g)
}
}
// TestLocationUpdate checks to see if we can update the location string in a pmt correctly
func TestLocationUpdate(t *testing.T) {
cpy := make([]byte, len(pmtWithMetaTst1))
copy(cpy, pmtWithMetaTst1)
cpy = addCrc(cpy)
err := UpdateLocation(cpy, locationTstStr2)
cpy = cpy[:len(cpy)-4]
if err != nil {
t.Errorf("Update time returned err: %v", err)
}
if !bytes.Equal(pmtWithMetaTst2, cpy) {
t.Errorf(errCmp, "TestLocationUpdate", pmtWithMetaTst2, cpy)
}
}
func TestTrim(t *testing.T) {
test := []byte{0xa3, 0x01, 0x03, 0x00, 0xde}
want := []byte{0xa3, 0x01, 0x03}
got := trimTo(test, 0x00)
if !bytes.Equal(got, want) {
t.Errorf(errCmp, "TestTrim", want, got)
}
}
// buildPmtTimeLocationBytes is a helper function to help construct the byte slices
// for pmts with time and location, as the location data field is 32 bytes, i.e. quite large
// to type out
func buildPmtWithMeta(tstStr string) []byte {
dst := make([]byte, len(pmtWithMetaHead)+32+len(pmtWithMetaTail))
copy(dst, pmtWithMetaHead)
copy(dst[len(pmtWithMetaHead):], tstStr)
copy(dst[len(pmtWithMetaHead)+32:], pmtWithMetaTail)
return dst
}