/*
NAME
  rtmp_test.go

DESCRIPTION
  See Readme.md

AUTHOR
  Saxon Nelson-Milton <saxon@ausocean.org>

LICENSE
  rtmp_test.go is Copyright (C) 2017 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 rtmp

import (
	"testing"
	"unsafe"
)

const (
	arrStart = 0
	arrEnd   = 5
	arrSize  = 6
	inc      = 3
	dec      = 3
)

const (
	byteSize  = 1
	int32Size = 4
	int64Size = 8
)

var (
	byteArr  = [arrSize]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
	int32Arr = [arrSize]int32{1, 2, 3, 4, 5, 6}
	int64Arr = [arrSize]int64{1, 2, 3, 4, 5, 6}
	errMsg   = "Obtained: %v, but wanted: %v"
)

// TODO: write test for realloc
// TODO: write test for memmove
// TODO: write test for allocate

func TestMemcmp(t *testing.T) {
	slice1 := []byte("ABCDEFG")
	slice2 := []byte("ABCDEFG")
	slice3 := []byte("ABCDJFG")

	if memcmp(unsafe.Pointer(&slice1[0]), unsafe.Pointer(&slice2[0]), 7) != 0 {
		t.Errorf("Should have got 0!")
	}

	if memcmp(unsafe.Pointer(&slice1[0]), unsafe.Pointer(&slice3[0]), 7) == 0 {
		t.Errorf("Should not have got 0!")
	}
}

func TestMemset(t *testing.T) {
	size := 10
	setNum := 5
	testVal := byte('A')
	mem := allocate(uintptr(size))
	memset((*byte)(mem), int(testVal), setNum)
	for i := 0; i < size; i++ {
		if i > setNum-1 {
			testVal = byte(0)
		}
		if *indxBytePtr(mem, i) != testVal {
			t.Errorf("mem doesn't match expected values at: %v", i)
		}
	}
}

func TestGoStrToCStr(t *testing.T) {
	goStr := "string\000"
	bStr := goStrToCStr(goStr)

	testData := []byte{'s', 't', 'r', 'i', 'n', 'g', '\000'}

	for i := 0; i < len(goStr); i++ {
		val := *indxBytePtr(unsafe.Pointer(bStr), i)
		testVal := testData[i]
		if val != testVal {
			t.Errorf("Wanted: %v, but got: %v", testVal, val)
		}
	}
}

func TestStrdup(t *testing.T) {
	goStr := "string\000"
	bStr := goStrToCStr(goStr)

	testData := []byte{'s', 't', 'r', 'i', 'n', 'g', '\000'}

	newStr := strdup(bStr)

	for i := 0; i < len(goStr); i++ {
		val := *indxBytePtr(unsafe.Pointer(newStr), i)
		testVal := testData[i]
		if val != testVal {
			t.Errorf("Wanted: %v, but got: %v", testVal, val)
		}
	}
}

func TestStrlen(t *testing.T) {
	goStr := "string\000"
	bStr := goStrToCStr(goStr)
	eLength := 6
	oLength := strlen(bStr)
	if oLength != int32(eLength) {
		t.Errorf("Wanted: %v, but got: %v", eLength, oLength)
	}
}

func TestStrchr(t *testing.T) {
	goStr := "string\000"
	bStr := goStrToCStr(goStr)
	// First try to find something that is in the string
	ePtr := uintptr(incBytePtr(unsafe.Pointer(bStr), 2))
	obtainedPtr := uintptr(unsafe.Pointer(strchr(bStr, 'r')))
	if ePtr != obtainedPtr {
		t.Errorf("wanted: %v, but got: %v", ePtr, obtainedPtr)
	}
	// Now try something that isn't actually in the string
	obtainedPtr2 := strchr(bStr, 'k')
	ePtr2 := (*byte)(nil)
	if ePtr2 != obtainedPtr2 {
		t.Errorf("wanted: %v, but got: %v", ePtr, obtainedPtr)
	}
}

func TestIncPtr(t *testing.T) {
	// Test how it deals with bytes
	bytePtr := unsafe.Pointer(&byteArr[arrStart])
	valueByte := *(*byte)(incPtr(bytePtr, inc, byteSize))
	if valueByte != byteArr[inc] {
		t.Errorf(errMsg, valueByte, byteArr[inc])
	}

	// Test how it deals with int32s
	int32Ptr := unsafe.Pointer(&int32Arr[arrStart])
	valueInt32 := *(*int32)(incPtr(int32Ptr, inc, int32Size))
	if valueInt32 != int32Arr[inc] {
		t.Errorf(errMsg, valueInt32, int32Arr[inc])
	}

	// Test how it deals with int64
	int64Ptr := unsafe.Pointer(&int64Arr[arrStart])
	valueInt64 := *(*int64)(incPtr(int64Ptr, inc, int64Size))
	if valueInt64 != int64Arr[inc] {
		t.Errorf(errMsg, valueInt64, int64Arr[inc])
	}
}

func TestDecPtr(t *testing.T) {
	// Test how it deals with bytes
	bytePtr := unsafe.Pointer(&byteArr[arrEnd])
	valueByte := *(*byte)(decPtr(bytePtr, dec, byteSize))
	if valueByte != byteArr[arrEnd-dec] {
		t.Errorf(errMsg, valueByte, byteArr[inc])
	}

	// Test how it deals with ints
	int32Ptr := unsafe.Pointer(&int32Arr[arrEnd])
	valueInt32 := *(*int32)(decPtr(int32Ptr, dec, int32Size))
	if valueInt32 != int32Arr[arrEnd-inc] {
		t.Errorf(errMsg, valueInt32, int32Arr[inc])
	}

	// Test how it deals with int64
	int64Ptr := unsafe.Pointer(&int64Arr[arrEnd])
	valueInt64 := *(*int64)(decPtr(int64Ptr, dec, int64Size))
	if valueInt64 != int64Arr[arrEnd-dec] {
		t.Errorf(errMsg, valueInt64, int64Arr[inc])
	}
}

func TestIndxBytePtr(t *testing.T) {
	// Test how it deals with bytes
	bytePtr := unsafe.Pointer(&byteArr[arrStart])
	valueByte := indxBytePtr(bytePtr, inc)
	if *valueByte != byteArr[inc] {
		t.Errorf(errMsg, valueByte, byteArr[inc])
	}
}

func TestIndxInt32Ptr(t *testing.T) {
	// Test how it deals with int32s
	int32Ptr := unsafe.Pointer(&int32Arr[arrStart])
	valueInt32 := indxInt32Ptr(int32Ptr, inc)
	if *valueInt32 != int32Arr[inc] {
		t.Errorf(errMsg, valueInt32, int32Arr[inc])
	}
}

func TestIndxInt64Ptr(t *testing.T) {
	// Test how it deals with int64
	int64Ptr := unsafe.Pointer(&int64Arr[arrStart])
	valueInt64 := indxInt64Ptr(int64Ptr, inc)
	if *valueInt64 != int64Arr[inc] {
		t.Errorf(errMsg, valueInt64, int64Arr[inc])
	}
}

/*
func TestPtrToSlice(t *testing.T){
}
*/