378 lines
7.1 KiB
Go
378 lines
7.1 KiB
Go
|
package conf
|
||
|
|
||
|
import (
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
const sampleForParsing = `Key1=Value
|
||
|
Test=Xd
|
||
|
What=1294; This be a comment.
|
||
|
; This be another comment.
|
||
|
|
||
|
|
||
|
Multi=Line\
|
||
|
String!
|
||
|
Key\=With\=Equal=Indeed!
|
||
|
ShouldNotOutput=
|
||
|
=ShouldNotOutput
|
||
|
ShouldNotOutput
|
||
|
|
||
|
Can=Contain\;Semicolons!
|
||
|
EqualSign=Can also = not = be = escaped!
|
||
|
|
||
|
ThisShouldComeUp=Yup`
|
||
|
|
||
|
func TestParse(t *testing.T) {
|
||
|
kvs := Parse([]byte(sampleForParsing))
|
||
|
t.Log("Result:")
|
||
|
for _, v := range kvs {
|
||
|
t.Logf(" %s - %s\n", v.Field, v.Value)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkParseWithSample(b *testing.B) {
|
||
|
sp := []byte(sampleForParsing)
|
||
|
b.ResetTimer()
|
||
|
for n := 0; n < b.N; n++ {
|
||
|
Parse(sp)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
escapeOriginal = `;aqsdwe103====aa\a\\aa!a;a
|
||
|
|
||
|
xd|`
|
||
|
escapeExpected = `\;aqsdwe103\=\=\=\=aa\\a\\\\aa!a\;a\
|
||
|
\
|
||
|
xd|`
|
||
|
)
|
||
|
|
||
|
func TestEscape(t *testing.T) {
|
||
|
escaped := Escape(escapeOriginal)
|
||
|
if escaped != escapeExpected {
|
||
|
t.Fatalf("Expected Escape to return '%s', got '%s' instead.", escapeExpected, escaped)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkEscape(b *testing.B) {
|
||
|
for n := 0; n < b.N; n++ {
|
||
|
Escape(escapeOriginal)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const sampleForUnmarshaling = `
|
||
|
; Welcome to hell.
|
||
|
; As we have to try every single possible value a struct can have, all of this is required.
|
||
|
; Fuck.
|
||
|
TestInt=1510591
|
||
|
TestInt8=-100
|
||
|
TestInt16=-12844
|
||
|
TestInt32=-3211
|
||
|
TestInt64=410491
|
||
|
|
||
|
TestUint=284129419
|
||
|
TestUint8=255
|
||
|
TestUint16=65535
|
||
|
TestUint32=151529;Can't remember the max value. Won't bother googling.
|
||
|
TestUint64=24148999
|
||
|
|
||
|
TestFloat32=24.1123
|
||
|
TestFloat64=110.134141223
|
||
|
|
||
|
TestBool=1
|
||
|
|
||
|
TestString=How much wood would a woodchuck chuck if a woodchuck could chuck wood?
|
||
|
TestEmpty=
|
||
|
`
|
||
|
|
||
|
type sampleTest struct {
|
||
|
TestInt int
|
||
|
TestInt8 int8
|
||
|
TestInt16 int16
|
||
|
TestInt32 int32
|
||
|
TestInt64 int64
|
||
|
|
||
|
TestUint uint
|
||
|
TestUint8 uint8
|
||
|
TestUint16 uint16
|
||
|
TestUint32 uint32
|
||
|
TestUint64 uint64
|
||
|
|
||
|
TestFloat32 float32
|
||
|
TestFloat64 float64
|
||
|
|
||
|
TestBool bool
|
||
|
|
||
|
TestString string
|
||
|
TestEmpty string
|
||
|
}
|
||
|
|
||
|
func (si sampleTest) check(t *testing.T) {
|
||
|
if true &&
|
||
|
si.TestInt == 1510591 &&
|
||
|
si.TestInt8 == -100 &&
|
||
|
si.TestInt16 == -12844 &&
|
||
|
si.TestInt32 == -3211 &&
|
||
|
si.TestInt64 == 410491 &&
|
||
|
|
||
|
si.TestUint == 284129419 &&
|
||
|
si.TestUint8 == 255 &&
|
||
|
si.TestUint16 == 65535 &&
|
||
|
si.TestUint32 == 151529 &&
|
||
|
si.TestUint64 == 24148999 &&
|
||
|
|
||
|
si.TestFloat32 == 24.1123 &&
|
||
|
si.TestFloat64 == 110.134141223 &&
|
||
|
|
||
|
si.TestBool == true &&
|
||
|
|
||
|
si.TestString == "How much wood would a woodchuck chuck if a woodchuck could chuck wood?" &&
|
||
|
si.TestEmpty == "" {
|
||
|
t.Log("It surprisingly worked.")
|
||
|
} else {
|
||
|
t.Log("Nope.")
|
||
|
t.Fatalf("%#v", si)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestLoad(t *testing.T) {
|
||
|
// Prepare file
|
||
|
err := ioutil.WriteFile("test.conf", []byte(sampleForUnmarshaling), 0644)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer os.Remove("test.conf")
|
||
|
|
||
|
// Prepare struct
|
||
|
si := sampleTest{}
|
||
|
|
||
|
// Load
|
||
|
err = Load(&si, "test.conf")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// Check for all values to be valid.
|
||
|
si.check(t)
|
||
|
}
|
||
|
|
||
|
func TestLoadShouldErrNotAStruct(t *testing.T) {
|
||
|
if err := Load(2, "test.conf"); err != ErrNotAStruct {
|
||
|
t.Fatalf("Should have panicked with ErrNotAStruct, got error '%s' instead.", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestLoadShouldErrNoFile(t *testing.T) {
|
||
|
si := sampleTest{}
|
||
|
if err := Load(&si, "test.conf"); err != ErrNoFile {
|
||
|
t.Fatalf("Should have panicked with ErrNoFile, got error '%s' instead.", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestMustLoadShouldPanic(t *testing.T) {
|
||
|
defer func() {
|
||
|
c := recover()
|
||
|
if c == nil {
|
||
|
t.Fatal("MustLoad with wrong values didn't panic!")
|
||
|
}
|
||
|
}()
|
||
|
MustLoad(2, "test.conf")
|
||
|
}
|
||
|
|
||
|
func TestFailBool(t *testing.T) {
|
||
|
// Prepare file
|
||
|
err := ioutil.WriteFile("test.conf", []byte(`TestBool=Lolno.`), 0644)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer os.Remove("test.conf")
|
||
|
|
||
|
// Prepare struct
|
||
|
si := sampleTest{}
|
||
|
|
||
|
// Load
|
||
|
err = Load(&si, "test.conf")
|
||
|
if err == nil {
|
||
|
t.Fatal("Should have returned an error, didn't")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFailInt(t *testing.T) {
|
||
|
// Prepare file
|
||
|
err := ioutil.WriteFile("test.conf", []byte(`TestInt=10934104912049120491204912031301293102`), 0644)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer os.Remove("test.conf")
|
||
|
|
||
|
// Prepare struct
|
||
|
si := sampleTest{}
|
||
|
|
||
|
// Load
|
||
|
err = Load(&si, "test.conf")
|
||
|
if err == nil {
|
||
|
t.Fatal("Should have returned an error, didn't")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFailFloat(t *testing.T) {
|
||
|
// Prepare file
|
||
|
err := ioutil.WriteFile("test.conf", []byte(`TestFloat32=2931.23111aaddfffeep`), 0644)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer os.Remove("test.conf")
|
||
|
|
||
|
// Prepare struct
|
||
|
si := sampleTest{}
|
||
|
|
||
|
// Load
|
||
|
err = Load(&si, "test.conf")
|
||
|
if err == nil {
|
||
|
t.Fatal("Should have returned an error, didn't")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFailUint(t *testing.T) {
|
||
|
// Prepare file
|
||
|
err := ioutil.WriteFile("test.conf", []byte(`TestUint8=asd`), 0644)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer os.Remove("test.conf")
|
||
|
|
||
|
// Prepare struct
|
||
|
si := sampleTest{}
|
||
|
|
||
|
// Load
|
||
|
err = Load(&si, "test.conf")
|
||
|
if err == nil {
|
||
|
t.Fatal("Should have returned an error, didn't")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestLoadRaw(t *testing.T) {
|
||
|
si := sampleTest{}
|
||
|
|
||
|
LoadRaw(&si, []byte(sampleForUnmarshaling))
|
||
|
si.check(t)
|
||
|
}
|
||
|
|
||
|
func TestMustLoadRawShouldPanic(t *testing.T) {
|
||
|
defer func() {
|
||
|
c := recover()
|
||
|
if c == nil {
|
||
|
t.Fatal("MustLoad with wrong values didn't panic!")
|
||
|
}
|
||
|
}()
|
||
|
MustLoadRaw(2, []byte("a"))
|
||
|
}
|
||
|
|
||
|
func BenchmarkLoadRaw(b *testing.B) {
|
||
|
si := &sampleTest{}
|
||
|
data := []byte(sampleForUnmarshaling)
|
||
|
b.ResetTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
LoadRaw(si, data)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type exportTypeTest struct {
|
||
|
Name string
|
||
|
Age int `description:"The age of the patient.\nDescriptions can be multi-line."`
|
||
|
}
|
||
|
|
||
|
const expectedExportType = `Name=Jack
|
||
|
; The age of the patient.
|
||
|
; Descriptions can be multi-line.
|
||
|
Age=19
|
||
|
`
|
||
|
|
||
|
func TestMustExportRaw(t *testing.T) {
|
||
|
defer func() {
|
||
|
c := recover()
|
||
|
if c != nil {
|
||
|
t.Fatal(c)
|
||
|
}
|
||
|
}()
|
||
|
e := &exportTypeTest{
|
||
|
Name: "Jack",
|
||
|
Age: 19,
|
||
|
}
|
||
|
data := MustExportRaw(e)
|
||
|
if string(data) != expectedExportType {
|
||
|
t.Fatalf("Expected '%s', got '%s'", expectedExportType, string(data))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestMustExportShouldPanic(t *testing.T) {
|
||
|
defer func() {
|
||
|
c := recover()
|
||
|
if c == nil {
|
||
|
t.Fatal(c)
|
||
|
}
|
||
|
}()
|
||
|
MustExport(2, "a.conf")
|
||
|
}
|
||
|
|
||
|
func TestMustExportRawShouldPanic(t *testing.T) {
|
||
|
defer func() {
|
||
|
c := recover()
|
||
|
if c == nil {
|
||
|
t.Fatal(c)
|
||
|
}
|
||
|
}()
|
||
|
MustExportRaw(2)
|
||
|
}
|
||
|
|
||
|
type exportWithInvalidType struct {
|
||
|
InvalidType []byte
|
||
|
Name string
|
||
|
}
|
||
|
|
||
|
func TestExport(t *testing.T) {
|
||
|
err := Export(exportWithInvalidType{
|
||
|
InvalidType: []byte("well"),
|
||
|
Name: "xd",
|
||
|
}, "test.conf")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
os.Remove("test.conf")
|
||
|
}
|
||
|
|
||
|
func TestFullChain(t *testing.T) {
|
||
|
initial := exportTypeTest{
|
||
|
Name: "Pisellone",
|
||
|
Age: 133337,
|
||
|
}
|
||
|
c := MustExportRaw(initial)
|
||
|
secondary := exportTypeTest{}
|
||
|
MustLoadRaw(&secondary, c)
|
||
|
if !reflect.DeepEqual(initial, secondary) {
|
||
|
t.Fatalf("Initial struct %#v is not the same as the derivate %#v.", initial, secondary)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCRLF(t *testing.T) {
|
||
|
const w = "Key1=Nice\r\nKey2=Meme"
|
||
|
vals := Parse([]byte(w))
|
||
|
for _, i := range vals {
|
||
|
switch i.Field {
|
||
|
case "Key1":
|
||
|
if i.Value != "Nice" {
|
||
|
t.Fatalf("Expected '%s', got '%s'", "Nice", i.Value)
|
||
|
}
|
||
|
case "Key2":
|
||
|
if i.Value != "Meme" {
|
||
|
t.Fatalf("Expected '%s', got '%s'", "Meme", i.Value)
|
||
|
}
|
||
|
default:
|
||
|
t.Fatalf("Unexpected key '%s'", i.Field)
|
||
|
}
|
||
|
}
|
||
|
}
|