<commit_before>package sio_test

import (
	//"fmt"
	"io"
	"os"
	"reflect"
	"testing"

	"github.com/go-hep/sio"
)

type RunHeader struct {
	RunNbr   int32
	Detector string
	Descr    string
	SubDets  []string
	//Params   Parameters

	Ints   []int64
	Floats []float64
}

func TestStreamOpen(t *testing.T) {
	const fname = "testdata/runhdr.sio"
	f, err := sio.Open(fname)
	if err != nil {
		t.Fatalf("could not open [%s]: %v", fname)
	}
	defer f.Close()

	if f.Name() != fname {
		t.Fatalf("sio.Stream.Name: expected [%s]. got [%s]", fname, f.Name())
	}

	if f.FileName() != fname {
		t.Fatalf("sio.Stream.FileName: expected [%s]. got [%s]", fname, f.FileName())
	}

	fi, err := f.Mode()
	if err != nil {
		t.Fatalf("could not retrieve stream mode: %v", err)
	}

	if !fi.IsRegular() {
		t.Fatalf("sio.Stream.Mode: expected regular file")
	}

	if f.CurPos() != 0 {
		t.Fatalf("expected pos=%v. got=%v", 0, f.CurPos())
	}
}

func TestStreamCreate(t *testing.T) {
	const fname = "testdata/out.sio"
	defer os.RemoveAll(fname)

	f, err := sio.Create(fname)
	if err != nil {
		t.Fatalf("could not create [%s]: %v", fname, err)
	}

	if f.Name() != fname {
		t.Fatalf("sio.Stream.Name: expected [%s]. got [%s]", fname, f.Name())
	}

	if f.FileName() != fname {
		t.Fatalf("sio.Stream.FileName: expected [%s]. got [%s]", fname, f.FileName())
	}

	fi, err := f.Mode()
	if err != nil {
		t.Fatalf("could not retrieve stream mode: %v", err)
	}

	if !fi.IsRegular() {
		t.Fatalf("sio.Stream.Mode: expected regular file")
	}

	if f.CurPos() != 0 {
		t.Fatalf("expected pos=%v. got=%v", 0, f.CurPos())
	}
}

func TestReadRunHeader(t *testing.T) {
	testReadStream(t, "testdata/runhdr.sio")
}

func TestReadRunHeaderCompr(t *testing.T) {
	testReadStream(t, "testdata/runhdr-compr.sio")
}

func TestWriteRunHeader(t *testing.T) {
	const fname = "testdata/out.sio"
	defer os.RemoveAll(fname)
	testWriteStream(t, fname)
}

func TestReadWrite(t *testing.T) {
	const fname = "testdata/rw.sio"
	defer os.RemoveAll(fname)
	testWriteStream(t, fname)
	testReadStream(t, fname)
}

func testReadStream(t *testing.T, fname string) {

	f, err := sio.Open(fname)
	if err != nil {
		t.Fatalf("could not open [%s]: %v", fname)
	}
	defer f.Close()

	runhdr := RunHeader{
		RunNbr:   42,
		Detector: "---",
		Descr:    "---",
		SubDets:  []string{},
		Floats:   []float64{},
		Ints:     []int64{},
	}

	rec := f.Record("RioRunHeader")
	if !f.HasRecord("RioRunHeader") {
		t.Fatalf("expected stream to have LCRunHeader record")
	}
	if rec.Unpack() {
		t.Fatalf("expected record to NOT unpack by default")
	}
	if rec.Name() != "RioRunHeader" {
		t.Fatalf("expected record name=[%s]. got=[%s]", "RioRunHeader", rec.Name())
	}

	rec.SetUnpack(true)
	if !rec.Unpack() {
		t.Fatalf("expected record to unpack now")
	}

	err = rec.Connect("RunHeader", &runhdr)
	if err != nil {
		t.Fatalf("error connecting [RunHeader]: %v", err)
	}

	for nrecs := 0; nrecs < 100; nrecs++ {
		//fmt.Printf("::: irec=%d, fname=%q\n", nrecs, fname)
		rec, err := f.ReadRecord()
		if err != nil {
			if err == io.EOF && nrecs == 10 {
				break
			}
			t.Fatalf("error reading record: %v (nrecs=%d)", err, nrecs)
		}

		if rec == nil {
			t.Fatalf("got nil record! (nrecs=%d)", nrecs)
		}

		if rec.Name() != "RioRunHeader" {
			t.Fatalf("expected record name=[%s]. got=[%s]. (nrecs=%d)",
				"RioRunHeader",
				rec.Name(),
				nrecs,
			)
		}

		if int(runhdr.RunNbr) != nrecs {
			t.Fatalf("expected runnbr=%d. got=%d.", nrecs, runhdr.RunNbr)
		}
		if runhdr.Detector != "MyDetector" {
			t.Fatalf("expected detector=[%s]. got=[%s]. (nrecs=%d)",
				"MyDetector",
				runhdr.Detector,
				nrecs,
			)
		}
		if runhdr.Descr != "dummy run number" {
			t.Fatalf("expected descr=[%s]. got=[%s]. (nrecs=%d)",
				"dummy run number",
				runhdr.Descr,
				nrecs,
			)
		}
		subdets := []string{"subdet 0", "subdet 1"}
		if !reflect.DeepEqual(runhdr.SubDets, subdets) {
			t.Fatalf("expected subdets=%v. got=%v (nrecs=%d)",
				subdets,
				runhdr.SubDets,
				nrecs,
			)
		}

		floats := []float64{
			float64(nrecs) + 100,
			float64(nrecs) + 200,
			float64(nrecs) + 300,
		}
		if !reflect.DeepEqual(runhdr.Floats, floats) {
			t.Fatalf("expected floats=%v. got=%v (nrecs=%d)",
				floats,
				runhdr.Floats,
				nrecs,
			)
		}

		ints := []int64{
			int64(nrecs) + 100,
			int64(nrecs) + 200,
			int64(nrecs) + 300,
		}
		if !reflect.DeepEqual(runhdr.Ints, ints) {
			t.Fatalf("expected ints=%v. got=%v (nrecs=%d)",
				floats,
				runhdr.Floats,
				nrecs,
			)
		}
	}
}

func testWriteStream(t *testing.T, fname string) {
	f, err := sio.Create(fname)
	if err != nil {
		t.Fatalf("could not create [%s]: %v", fname, err)
	}

	defer f.Close()

	var runhdr RunHeader
	runhdr.RunNbr = 42

	rec := f.Record("RioRunHeader")
	if rec == nil {
		t.Fatalf("could not create record [RioRunHeader]")
	}
	rec.SetUnpack(true)
	if !rec.Unpack() {
		t.Fatalf("expected record to unpack now")
	}

	err = rec.Connect("RunHeader", &runhdr)
	if err != nil {
		t.Fatalf("error connecting [RunHeader]: %v", err)
	}

	for irec := 0; irec < 10; irec++ {
		runhdr = RunHeader{
			RunNbr:   int32(irec),
			Detector: "MyDetector",
			Descr:    "dummy run number",
			SubDets:  []string{"subdet 0", "subdet 1"},
			Floats: []float64{
				float64(irec) + 100,
				float64(irec) + 200,
				float64(irec) + 300,
			},
			Ints: []int64{
				int64(irec) + 100,
				int64(irec) + 200,
				int64(irec) + 300,
			},
		}
		err = f.WriteRecord(rec)
		if err != nil {
			t.Fatalf("error writing record: %v (irec=%d)", err, irec)
		}

		err = f.Sync()
		if err != nil {
			t.Fatalf("error flushing record: %v (irec=%d)", err, irec)
		}
	}
}
<commit_msg>test: add printout of error<commit_after>package sio_test

import (
	//"fmt"
	"io"
	"os"
	"reflect"
	"testing"

	"github.com/go-hep/sio"
)

type RunHeader struct {
	RunNbr   int32
	Detector string
	Descr    string
	SubDets  []string
	//Params   Parameters

	Ints   []int64
	Floats []float64
}

func TestStreamOpen(t *testing.T) {
	const fname = "testdata/runhdr.sio"
	f, err := sio.Open(fname)
	if err != nil {
		t.Fatalf("could not open [%s]: %v", fname, err)
	}
	defer f.Close()

	if f.Name() != fname {
		t.Fatalf("sio.Stream.Name: expected [%s]. got [%s]", fname, f.Name())
	}

	if f.FileName() != fname {
		t.Fatalf("sio.Stream.FileName: expected [%s]. got [%s]", fname, f.FileName())
	}

	fi, err := f.Mode()
	if err != nil {
		t.Fatalf("could not retrieve stream mode: %v", err)
	}

	if !fi.IsRegular() {
		t.Fatalf("sio.Stream.Mode: expected regular file")
	}

	if f.CurPos() != 0 {
		t.Fatalf("expected pos=%v. got=%v", 0, f.CurPos())
	}
}

func TestStreamCreate(t *testing.T) {
	const fname = "testdata/out.sio"
	defer os.RemoveAll(fname)

	f, err := sio.Create(fname)
	if err != nil {
		t.Fatalf("could not create [%s]: %v", fname, err)
	}

	if f.Name() != fname {
		t.Fatalf("sio.Stream.Name: expected [%s]. got [%s]", fname, f.Name())
	}

	if f.FileName() != fname {
		t.Fatalf("sio.Stream.FileName: expected [%s]. got [%s]", fname, f.FileName())
	}

	fi, err := f.Mode()
	if err != nil {
		t.Fatalf("could not retrieve stream mode: %v", err)
	}

	if !fi.IsRegular() {
		t.Fatalf("sio.Stream.Mode: expected regular file")
	}

	if f.CurPos() != 0 {
		t.Fatalf("expected pos=%v. got=%v", 0, f.CurPos())
	}
}

func TestReadRunHeader(t *testing.T) {
	testReadStream(t, "testdata/runhdr.sio")
}

func TestReadRunHeaderCompr(t *testing.T) {
	testReadStream(t, "testdata/runhdr-compr.sio")
}

func TestWriteRunHeader(t *testing.T) {
	const fname = "testdata/out.sio"
	defer os.RemoveAll(fname)
	testWriteStream(t, fname)
}

func TestReadWrite(t *testing.T) {
	const fname = "testdata/rw.sio"
	defer os.RemoveAll(fname)
	testWriteStream(t, fname)
	testReadStream(t, fname)
}

func testReadStream(t *testing.T, fname string) {

	f, err := sio.Open(fname)
	if err != nil {
		t.Fatalf("could not open [%s]: %v", fname, err)
	}
	defer f.Close()

	runhdr := RunHeader{
		RunNbr:   42,
		Detector: "---",
		Descr:    "---",
		SubDets:  []string{},
		Floats:   []float64{},
		Ints:     []int64{},
	}

	rec := f.Record("RioRunHeader")
	if !f.HasRecord("RioRunHeader") {
		t.Fatalf("expected stream to have LCRunHeader record")
	}
	if rec.Unpack() {
		t.Fatalf("expected record to NOT unpack by default")
	}
	if rec.Name() != "RioRunHeader" {
		t.Fatalf("expected record name=[%s]. got=[%s]", "RioRunHeader", rec.Name())
	}

	rec.SetUnpack(true)
	if !rec.Unpack() {
		t.Fatalf("expected record to unpack now")
	}

	err = rec.Connect("RunHeader", &runhdr)
	if err != nil {
		t.Fatalf("error connecting [RunHeader]: %v", err)
	}

	for nrecs := 0; nrecs < 100; nrecs++ {
		//fmt.Printf("::: irec=%d, fname=%q\n", nrecs, fname)
		rec, err := f.ReadRecord()
		if err != nil {
			if err == io.EOF && nrecs == 10 {
				break
			}
			t.Fatalf("error reading record: %v (nrecs=%d)", err, nrecs)
		}

		if rec == nil {
			t.Fatalf("got nil record! (nrecs=%d)", nrecs)
		}

		if rec.Name() != "RioRunHeader" {
			t.Fatalf("expected record name=[%s]. got=[%s]. (nrecs=%d)",
				"RioRunHeader",
				rec.Name(),
				nrecs,
			)
		}

		if int(runhdr.RunNbr) != nrecs {
			t.Fatalf("expected runnbr=%d. got=%d.", nrecs, runhdr.RunNbr)
		}
		if runhdr.Detector != "MyDetector" {
			t.Fatalf("expected detector=[%s]. got=[%s]. (nrecs=%d)",
				"MyDetector",
				runhdr.Detector,
				nrecs,
			)
		}
		if runhdr.Descr != "dummy run number" {
			t.Fatalf("expected descr=[%s]. got=[%s]. (nrecs=%d)",
				"dummy run number",
				runhdr.Descr,
				nrecs,
			)
		}
		subdets := []string{"subdet 0", "subdet 1"}
		if !reflect.DeepEqual(runhdr.SubDets, subdets) {
			t.Fatalf("expected subdets=%v. got=%v (nrecs=%d)",
				subdets,
				runhdr.SubDets,
				nrecs,
			)
		}

		floats := []float64{
			float64(nrecs) + 100,
			float64(nrecs) + 200,
			float64(nrecs) + 300,
		}
		if !reflect.DeepEqual(runhdr.Floats, floats) {
			t.Fatalf("expected floats=%v. got=%v (nrecs=%d)",
				floats,
				runhdr.Floats,
				nrecs,
			)
		}

		ints := []int64{
			int64(nrecs) + 100,
			int64(nrecs) + 200,
			int64(nrecs) + 300,
		}
		if !reflect.DeepEqual(runhdr.Ints, ints) {
			t.Fatalf("expected ints=%v. got=%v (nrecs=%d)",
				floats,
				runhdr.Floats,
				nrecs,
			)
		}
	}
}

func testWriteStream(t *testing.T, fname string) {
	f, err := sio.Create(fname)
	if err != nil {
		t.Fatalf("could not create [%s]: %v", fname, err)
	}

	defer f.Close()

	var runhdr RunHeader
	runhdr.RunNbr = 42

	rec := f.Record("RioRunHeader")
	if rec == nil {
		t.Fatalf("could not create record [RioRunHeader]")
	}
	rec.SetUnpack(true)
	if !rec.Unpack() {
		t.Fatalf("expected record to unpack now")
	}

	err = rec.Connect("RunHeader", &runhdr)
	if err != nil {
		t.Fatalf("error connecting [RunHeader]: %v", err)
	}

	for irec := 0; irec < 10; irec++ {
		runhdr = RunHeader{
			RunNbr:   int32(irec),
			Detector: "MyDetector",
			Descr:    "dummy run number",
			SubDets:  []string{"subdet 0", "subdet 1"},
			Floats: []float64{
				float64(irec) + 100,
				float64(irec) + 200,
				float64(irec) + 300,
			},
			Ints: []int64{
				int64(irec) + 100,
				int64(irec) + 200,
				int64(irec) + 300,
			},
		}
		err = f.WriteRecord(rec)
		if err != nil {
			t.Fatalf("error writing record: %v (irec=%d)", err, irec)
		}

		err = f.Sync()
		if err != nil {
			t.Fatalf("error flushing record: %v (irec=%d)", err, irec)
		}
	}
}
<|endoftext|>


<commit_before>package vld

import (
	"regexp"
	"testing"
)

func ptrStr(val string) *string {
	return &val
}

type testString struct {
	name    string
	s       *stringVld
	wantErr bool
}

func Test_String_Required(t *testing.T) {
	testStringRequired(t, "String", []testString{
		{"1", String(""), true},
		{"2", String("x"), false},
	})
	testStringRequired(t, "StrPtr", []testString{
		{"1", StrPtr(nil), true},
		{"2", StrPtr(ptrStr("x")), false},
	})
}

func testStringRequired(t *testing.T, detail string, tests []testString) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Required().Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Required() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testStringLength struct {
	name    string
	s       *stringVld
	length  int
	wantErr bool
}

func Test_String_GT(t *testing.T) {
	testStringGT(t, "String", []testStringLength{
		{"1", String("a"), 0, false},           // test zero length
		{"2", String(""), 10, false},           // not required
		{"3", String("").Required(), 10, true}, // required
		{"4", String("a"), 1, true},            // greater than 1
		{"5", String("ab"), 1, false},
	})

	testStringGT(t, "StrPtr", []testStringLength{
		{"1", StrPtr(ptrStr("a")), 0, false},    // test zero length
		{"2", StrPtr(nil), 10, false},           // not required
		{"3", StrPtr(nil).Required(), 10, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, true},     // greater than 1
		{"5", StrPtr(ptrStr("ab")), 1, false},
	})
}

func testStringGT(t *testing.T, detail string, tests []testStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.GT(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.GT() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_GTE(t *testing.T) {
	testStringGTE(t, "String", []testStringLength{
		{"1", String("a"), 0, false},           // test zero length
		{"2", String(""), 10, false},           // not required
		{"3", String("").Required(), 10, true}, // required
		{"4", String("a"), 1, false},           // equal 1
		{"5", String("ab"), 1, false},
		{"6", String("ab"), 10, true},
	})

	testStringGTE(t, "StrPtr", []testStringLength{
		{"1", StrPtr(ptrStr("a")), 0, false},    // test zero length
		{"2", StrPtr(nil), 10, false},           // not required
		{"3", StrPtr(nil).Required(), 10, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, false},    // equal 1
		{"5", StrPtr(ptrStr("ab")), 1, false},
		{"6", StrPtr(ptrStr("ab")), 10, true},
	})
}

func testStringGTE(t *testing.T, detail string, tests []testStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.GTE(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.GTE() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_LT(t *testing.T) {
	testStringLT(t, "String", []testStringLength{
		{"1", String("a"), 0, true},           // test zero length
		{"2", String(""), 0, false},           // not required
		{"3", String("").Required(), 0, true}, // required
		{"4", String("a"), 1, true},           // equal
		{"5", String("a"), 2, false},          // smaller than 2
		{"6", String("ab"), 1, true},
	})

	testStringLT(t, "StrPtr", []testStringLength{
		{"1", StrPtr(ptrStr("a")), 0, true},    // test zero length
		{"2", StrPtr(nil), 0, false},           // not required
		{"3", StrPtr(nil).Required(), 0, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, true},    // equal
		{"5", StrPtr(ptrStr("a")), 2, false},   // smaller than 2
		{"6", StrPtr(ptrStr("ab")), 1, true},
	})
}

func testStringLT(t *testing.T, detail string, tests []testStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.LT(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.LT() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_LTE(t *testing.T) {
	testStringLTE(t, "String", []testStringLength{
		{"1", String("a"), 0, true},           // test zero length
		{"2", String(""), 0, false},           // not required
		{"3", String("").Required(), 0, true}, // required
		{"4", String("a"), 1, false},          // equal
		{"5", String("a"), 2, false},          // smaller than 2
		{"6", String("ab"), 1, true},
	})

	testStringLTE(t, "StrPtr", []testStringLength{
		{"1", StrPtr(ptrStr("a")), 0, true},    // test zero length
		{"2", StrPtr(nil), 0, false},           // not required
		{"3", StrPtr(nil).Required(), 0, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, false},   // equal
		{"5", StrPtr(ptrStr("a")), 2, false},   // smaller than 2
		{"6", StrPtr(ptrStr("ab")), 1, true},
	})
}

func testStringLTE(t *testing.T, detail string, tests []testStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.LTE(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.LTE() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testStringMinMax struct {
	name    string
	s       *stringVld
	min     int
	max     int
	wantErr bool
}

func Test_String_Length(t *testing.T) {
	testStringLength(t, "String", []testStringMinMax{
		{"1", String("a"), 0, 0, true},            // test zero
		{"2", String(""), 5, 10, false},           // not required
		{"3", String("").Required(), 5, 10, true}, // required
		{"4", String("a"), 1, 3, false},           // equal min
		{"5", String("ab"), 1, 3, false},          // mid
		{"6", String("abc"), 1, 3, false},         // equal min
		{"7", String("abc"), 1, 2, true},          // upper
		{"8", String("abc"), 4, 5, true},          // smaller
	})

	testStringLength(t, "StrPtr", []testStringMinMax{
		{"1", StrPtr(ptrStr("a")), 0, 0, true},     // test zero
		{"2", StrPtr(nil), 5, 10, false},           // not required
		{"3", StrPtr(nil).Required(), 5, 10, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, 3, false},    // equal min
		{"5", StrPtr(ptrStr("ab")), 1, 3, false},   // mid
		{"6", StrPtr(ptrStr("abc")), 1, 3, false},  // equal min
		{"7", StrPtr(ptrStr("abc")), 1, 2, true},   // upper
		{"8", StrPtr(ptrStr("abc")), 4, 5, true},   // smaller
	})
}

func testStringLength(t *testing.T, detail string, tests []testStringMinMax) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Length(tt.min, tt.max).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Length() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_Len(t *testing.T) {
	testStringLen(t, "String", []testStringLength{
		{"1", String("a"), 0, true},           // test zero
		{"2", String(""), 5, false},           // not required
		{"3", String("").Required(), 5, true}, // required
		{"4", String("ab"), 2, false},         // equal
		{"5", String("ab"), 3, true},          // different
	})
	testStringLen(t, "StrPtr", []testStringLength{
		{"1", StrPtr(ptrStr("a")), 0, true},    // test zero
		{"2", StrPtr(nil), 5, false},           // not required
		{"3", StrPtr(nil).Required(), 5, true}, // required
		{"4", StrPtr(ptrStr("ab")), 2, false},  // equal
		{"5", StrPtr(ptrStr("ab")), 3, true},   // different
	})
}

func testStringLen(t *testing.T, detail string, tests []testStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Len(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Len() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testStringMatch struct {
	name    string
	s       *stringVld
	pattern string
	wantErr bool
}

func Test_String_Match(t *testing.T) {
	testStringMatch(t, "String", []testStringMatch{
		{"1", String(""), "[a-z]", false},           // not required
		{"2", String("").Required(), "[a-z]", true}, // required
		{"3", String("ab"), "[a-z]", false},         // match
		{"4", String("ab"), "[0-9]", true},          // not match
	})
	testStringMatch(t, "StrPtr", []testStringMatch{
		{"1", StrPtr(nil), "[a-z]", false},           // not required
		{"2", StrPtr(nil).Required(), "[a-z]", true}, // required
		{"3", StrPtr(ptrStr("ab")), "[a-z]", false},  // match
		{"4", StrPtr(ptrStr("ab")), "[0-9]", true},   // not match
	})
}

func testStringMatch(t *testing.T, detail string, tests []testStringMatch) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Match(regexp.MustCompile(tt.pattern)).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Match() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testStringOneOf struct {
	name    string
	s       *stringVld
	values  []string
	wantErr bool
}

func Test_String_OneOf(t *testing.T) {
	testStringOneOf(t, "String", []testStringOneOf{
		{"1", String(""), []string{"ab"}, false},           // not required
		{"2", String("").Required(), []string{"ab"}, true}, // required
		{"3", String("ab"), []string{"ab"}, false},         // one
		{"4", String("ab"), []string{"abc"}, true},         // not match
		{"5", String("ab"), []string{"de", "fg"}, true},    // not match
	})
	testStringOneOf(t, "StrPtr", []testStringOneOf{
		{"1", StrPtr(nil), []string{"ab"}, false},               // not required
		{"2", StrPtr(nil).Required(), []string{"ab"}, true},     // required
		{"3", StrPtr(ptrStr("ab")), []string{"ab"}, false},      // one
		{"4", StrPtr(ptrStr("ab")), []string{"abc"}, true},      // not match
		{"5", StrPtr(ptrStr("ab")), []string{"de", "fg"}, true}, // not match
	})
}

func testStringOneOf(t *testing.T, detail string, tests []testStringOneOf) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.OneOf(tt.values).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.OneOf() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_IsEmail(t *testing.T) {
	testStringIsEmail(t, "String", []testString{
		{"1", String(""), false},            // not required
		{"2", String("").Required(), true},  // required
		{"3", String("foo@bah.com"), false}, // match
		{"4", String("not email"), true},    // not match
	})
	testStringIsEmail(t, "StrPtr", []testString{
		{"1", StrPtr(nil), false},                   // not required
		{"2", StrPtr(nil).Required(), true},         // required
		{"3", StrPtr(ptrStr("foo@bah.com")), false}, // match
		{"4", StrPtr(ptrStr("not email")), true},    // not match
	})
}

func testStringIsEmail(t *testing.T, detail string, tests []testString) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.IsEmail().Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.IsEmail() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}
<commit_msg>fix test<commit_after>package vld

import (
	"regexp"
	"testing"
)

func ptrStr(val string) *string {
	return &val
}

type testString struct {
	name    string
	s       *stringVld
	wantErr bool
}

func Test_String_Required(t *testing.T) {
	testStringRequired(t, "String", []testString{
		{"1", String(""), true},
		{"2", String("x"), false},
	})
	testStringRequired(t, "StrPtr", []testString{
		{"1", StrPtr(nil), true},
		{"2", StrPtr(ptrStr("x")), false},
	})
}

func testStringRequired(t *testing.T, detail string, tests []testString) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Required().Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Required() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testValueStringLength struct {
	name    string
	s       *stringVld
	length  int
	wantErr bool
}

func Test_String_GT(t *testing.T) {
	testStringGT(t, "String", []testValueStringLength{
		{"1", String("a"), 0, false},           // test zero length
		{"2", String(""), 10, false},           // not required
		{"3", String("").Required(), 10, true}, // required
		{"4", String("a"), 1, true},            // greater than 1
		{"5", String("ab"), 1, false},
	})

	testStringGT(t, "StrPtr", []testValueStringLength{
		{"1", StrPtr(ptrStr("a")), 0, false},    // test zero length
		{"2", StrPtr(nil), 10, false},           // not required
		{"3", StrPtr(nil).Required(), 10, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, true},     // greater than 1
		{"5", StrPtr(ptrStr("ab")), 1, false},
	})
}

func testStringGT(t *testing.T, detail string, tests []testValueStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.GT(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.GT() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_GTE(t *testing.T) {
	testStringGTE(t, "String", []testValueStringLength{
		{"1", String("a"), 0, false},           // test zero length
		{"2", String(""), 10, false},           // not required
		{"3", String("").Required(), 10, true}, // required
		{"4", String("a"), 1, false},           // equal 1
		{"5", String("ab"), 1, false},
		{"6", String("ab"), 10, true},
	})

	testStringGTE(t, "StrPtr", []testValueStringLength{
		{"1", StrPtr(ptrStr("a")), 0, false},    // test zero length
		{"2", StrPtr(nil), 10, false},           // not required
		{"3", StrPtr(nil).Required(), 10, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, false},    // equal 1
		{"5", StrPtr(ptrStr("ab")), 1, false},
		{"6", StrPtr(ptrStr("ab")), 10, true},
	})
}

func testStringGTE(t *testing.T, detail string, tests []testValueStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.GTE(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.GTE() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_LT(t *testing.T) {
	testStringLT(t, "String", []testValueStringLength{
		{"1", String("a"), 0, true},           // test zero length
		{"2", String(""), 0, false},           // not required
		{"3", String("").Required(), 0, true}, // required
		{"4", String("a"), 1, true},           // equal
		{"5", String("a"), 2, false},          // smaller than 2
		{"6", String("ab"), 1, true},
	})

	testStringLT(t, "StrPtr", []testValueStringLength{
		{"1", StrPtr(ptrStr("a")), 0, true},    // test zero length
		{"2", StrPtr(nil), 0, false},           // not required
		{"3", StrPtr(nil).Required(), 0, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, true},    // equal
		{"5", StrPtr(ptrStr("a")), 2, false},   // smaller than 2
		{"6", StrPtr(ptrStr("ab")), 1, true},
	})
}

func testStringLT(t *testing.T, detail string, tests []testValueStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.LT(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.LT() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_LTE(t *testing.T) {
	testStringLTE(t, "String", []testValueStringLength{
		{"1", String("a"), 0, true},           // test zero length
		{"2", String(""), 0, false},           // not required
		{"3", String("").Required(), 0, true}, // required
		{"4", String("a"), 1, false},          // equal
		{"5", String("a"), 2, false},          // smaller than 2
		{"6", String("ab"), 1, true},
	})

	testStringLTE(t, "StrPtr", []testValueStringLength{
		{"1", StrPtr(ptrStr("a")), 0, true},    // test zero length
		{"2", StrPtr(nil), 0, false},           // not required
		{"3", StrPtr(nil).Required(), 0, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, false},   // equal
		{"5", StrPtr(ptrStr("a")), 2, false},   // smaller than 2
		{"6", StrPtr(ptrStr("ab")), 1, true},
	})
}

func testStringLTE(t *testing.T, detail string, tests []testValueStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.LTE(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.LTE() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testValueStringMinMax struct {
	name    string
	s       *stringVld
	min     int
	max     int
	wantErr bool
}

func Test_String_Length(t *testing.T) {
	testStringLength(t, "String", []testValueStringMinMax{
		{"1", String("a"), 0, 0, true},            // test zero
		{"2", String(""), 5, 10, false},           // not required
		{"3", String("").Required(), 5, 10, true}, // required
		{"4", String("a"), 1, 3, false},           // equal min
		{"5", String("ab"), 1, 3, false},          // mid
		{"6", String("abc"), 1, 3, false},         // equal min
		{"7", String("abc"), 1, 2, true},          // upper
		{"8", String("abc"), 4, 5, true},          // smaller
	})

	testStringLength(t, "StrPtr", []testValueStringMinMax{
		{"1", StrPtr(ptrStr("a")), 0, 0, true},     // test zero
		{"2", StrPtr(nil), 5, 10, false},           // not required
		{"3", StrPtr(nil).Required(), 5, 10, true}, // required
		{"4", StrPtr(ptrStr("a")), 1, 3, false},    // equal min
		{"5", StrPtr(ptrStr("ab")), 1, 3, false},   // mid
		{"6", StrPtr(ptrStr("abc")), 1, 3, false},  // equal min
		{"7", StrPtr(ptrStr("abc")), 1, 2, true},   // upper
		{"8", StrPtr(ptrStr("abc")), 4, 5, true},   // smaller
	})
}

func testStringLength(t *testing.T, detail string, tests []testValueStringMinMax) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Length(tt.min, tt.max).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Length() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_Len(t *testing.T) {
	testStringLen(t, "String", []testValueStringLength{
		{"1", String("a"), 0, true},           // test zero
		{"2", String(""), 5, false},           // not required
		{"3", String("").Required(), 5, true}, // required
		{"4", String("ab"), 2, false},         // equal
		{"5", String("ab"), 3, true},          // different
	})
	testStringLen(t, "StrPtr", []testValueStringLength{
		{"1", StrPtr(ptrStr("a")), 0, true},    // test zero
		{"2", StrPtr(nil), 5, false},           // not required
		{"3", StrPtr(nil).Required(), 5, true}, // required
		{"4", StrPtr(ptrStr("ab")), 2, false},  // equal
		{"5", StrPtr(ptrStr("ab")), 3, true},   // different
	})
}

func testStringLen(t *testing.T, detail string, tests []testValueStringLength) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Len(tt.length).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Len() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testValueStringMatch struct {
	name    string
	s       *stringVld
	pattern string
	wantErr bool
}

func Test_String_Match(t *testing.T) {
	testStringMatch(t, "String", []testValueStringMatch{
		{"1", String(""), "[a-z]", false},           // not required
		{"2", String("").Required(), "[a-z]", true}, // required
		{"3", String("ab"), "[a-z]", false},         // match
		{"4", String("ab"), "[0-9]", true},          // not match
	})
	testStringMatch(t, "StrPtr", []testValueStringMatch{
		{"1", StrPtr(nil), "[a-z]", false},           // not required
		{"2", StrPtr(nil).Required(), "[a-z]", true}, // required
		{"3", StrPtr(ptrStr("ab")), "[a-z]", false},  // match
		{"4", StrPtr(ptrStr("ab")), "[0-9]", true},   // not match
	})
}

func testStringMatch(t *testing.T, detail string, tests []testValueStringMatch) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.Match(regexp.MustCompile(tt.pattern)).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.Match() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

type testValueStringOneOf struct {
	name    string
	s       *stringVld
	values  []string
	wantErr bool
}

func Test_String_OneOf(t *testing.T) {
	testStringOneOf(t, "String", []testValueStringOneOf{
		{"1", String(""), []string{"ab"}, false},           // not required
		{"2", String("").Required(), []string{"ab"}, true}, // required
		{"3", String("ab"), []string{"ab"}, false},         // one
		{"4", String("ab"), []string{"abc"}, true},         // not match
		{"5", String("ab"), []string{"de", "fg"}, true},    // not match
	})
	testStringOneOf(t, "StrPtr", []testValueStringOneOf{
		{"1", StrPtr(nil), []string{"ab"}, false},               // not required
		{"2", StrPtr(nil).Required(), []string{"ab"}, true},     // required
		{"3", StrPtr(ptrStr("ab")), []string{"ab"}, false},      // one
		{"4", StrPtr(ptrStr("ab")), []string{"abc"}, true},      // not match
		{"5", StrPtr(ptrStr("ab")), []string{"de", "fg"}, true}, // not match
	})
}

func testStringOneOf(t *testing.T, detail string, tests []testValueStringOneOf) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.OneOf(tt.values).Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.OneOf() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}

func Test_String_IsEmail(t *testing.T) {
	testStringIsEmail(t, "String", []testString{
		{"1", String(""), false},            // not required
		{"2", String("").Required(), true},  // required
		{"3", String("foo@bah.com"), false}, // match
		{"4", String("not email"), true},    // not match
	})
	testStringIsEmail(t, "StrPtr", []testString{
		{"1", StrPtr(nil), false},                   // not required
		{"2", StrPtr(nil).Required(), true},         // required
		{"3", StrPtr(ptrStr("foo@bah.com")), false}, // match
		{"4", StrPtr(ptrStr("not email")), true},    // not match
	})
}

func testStringIsEmail(t *testing.T, detail string, tests []testString) {
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.s.IsEmail().Error(); (err != nil) != tt.wantErr {
				t.Errorf("%v.IsEmail() error = %v, wantErr %v", detail, err, tt.wantErr)
			}
		})
	}
}
<|endoftext|>


<commit_before>package slices

import (
	"fmt"
	"reflect"
	"testing"
)

// https://golang.org/cmd/go/#hdr-Description_of_testing_flags
// go test -v -bench string_test.go -benchtime 2s

var ()

func TestIsEmpty(t *testing.T) {

	if err := expect(IsEmpty([]string{}), true); err != nil {
		t.Error(err)
	}

	if err := expect(IsEmpty([]string{""}), true); err != nil {
		t.Error(err)
	}

	if err := expect(IsEmpty([]string{"a", "b", "c"}), false); err != nil {
		t.Error(err)
	}
}

func TestConcat(t *testing.T) {

	if err := expect(Concat([]string{}), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Concat([]string{""}), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Concat([]string{"a", "b", "c"}), "abc"); err != nil {
		t.Error(err)
	}
}

func TestJoin(t *testing.T) {

	if err := expect(Join([]string{}, "-"), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Join([]string{""}, "-"), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Join([]string{"a", "b", "c"}, "-"), "a-b-c"); err != nil {
		t.Error(err)
	}
}

func TestCut(t *testing.T) {

	if err := expect(Cut([]string{}, 0, -1), []string{}); err != nil {
		t.Error(err)
	}

	if err := expectNot(Cut([]string{}, 0, -1), []string{""}); err != nil {
		t.Error(err)
	}

	if err := expect(Cut([]string{""}, 0, -1), []string{""}); err != nil {
		t.Error(err)
	}
}

func TestIsSameArray(t *testing.T) {
	slc1 := []string{"same elements,", "different arrays"}
	if slc2 := Cut(slc1, 0, -1); IsSameArray(slc2, slc1) {
		t.Error(errExpected(false, slc2, slc1))
	}
}

func TestDuplicate(t *testing.T) {
	slc1 := []string{"same elements,", "different arrays"}
	if slc2 := Copy(slc1); IsSameArray(slc2, slc1) {
		t.Error(errExpected(false, slc2, slc1))
	}
}

func TestEquals(t *testing.T) {

	slc1 := []string{"same", "elements"}
	slc2 := []string{"same", "elements"}

	if err := expect(Equals(slc1, slc2)); err != nil {
		t.Error(err)
	}
}

func TestPop(t *testing.T) {

	slcBefore := []string{"just enough", "too much"}
	popped, slcAfter := Pop(slcBefore)

	if err := expect(popped, "too much"); err != nil {
		t.Error(err)
	}

	if err := expect(slcAfter, []string{"just enough"}); err != nil {
		t.Error(err)
	}
}

func TestShift(t *testing.T) {

	slcBefore := []string{"next", "enqueued"}
	shifted, slcAfter := Shift(slcBefore)

	if err := expect(shifted, "next"); err != nil {
		t.Error(err)
	}

	if err := expect(slcAfter, []string{"enqueued"}); err != nil {
		t.Error(err)
	}
}

func TestUnshift(t *testing.T) {
	if err := expect(Unshift([]string{"queue"}, "enqueued"), []string{"enqueued", "queue"}); err != nil {
		t.Error(err)
	}
}

// Ridiculously faster
func BenchmarkQueuePushShift(b *testing.B) {

	slc := []string{"deeporange50", "deeporange500", "deeporange900", "deeporangeA100", "deeporangeA200", "deeporangeA400", "deeporangea700", "deeporange-50", "deeporange:500", "deeporange_900", "deeporange A100", "deeporange-A200", "deeporange:A400", "deeporange_A700", "deeporange000", "deeporange1000", "deeporangeA000", "deeporangeA300", "deeporangeA1000", "deeporange:000", "deeporange-1000", "deeporange_A000", "deeporange A300", "deeporange-A1000", "deeporange"}

	for i := 0; i < b.N; i++ {
		slc = append(slc, "next")
		slc = slc[1:]
	}
}

// Ridiculously slower
func BenchmarkQueueUnshiftPop(b *testing.B) {

	slc := []string{"deeporange50", "deeporange500", "deeporange900", "deeporangeA100", "deeporangeA200", "deeporangeA400", "deeporangea700", "deeporange-50", "deeporange:500", "deeporange_900", "deeporange A100", "deeporange-A200", "deeporange:A400", "deeporange_A700", "deeporange000", "deeporange1000", "deeporangeA000", "deeporangeA300", "deeporangeA1000", "deeporange:000", "deeporange-1000", "deeporange_A000", "deeporange A300", "deeporange-A1000", "deeporange"}
	iEnd := len(slc) - 1

	for i := 0; i < b.N; i++ {
		slc = append([]string{"next"}, slc...)
		slc = slc[:iEnd]
	}
}

func expect(args ...interface{}) error {
	switch len(args) {
	case 0:
		return fmt.Errorf("Not enough arguments to expect. Args passed: %v", args)
	case 1:
		args = append(args, []interface{}{true}...) // this is nuts, Go
		fallthrough
	default:
		return _expect(true, args...)
	}
}

func expectNot(args ...interface{}) error {
	switch len(args) {
	case 0:
		return fmt.Errorf("Not enough arguments to expect. Args passed: %v", args)
	case 1:
		args = append(args, []interface{}{false}...) // this is nuts, Go
		fallthrough
	default:
		return _expect(false, args...)
	}
}

func _expect(boolWanted bool, args ...interface{}) error {

	result := args[0]
	expected := args[1]

	if boolReceived := _areEqual(result, expected); boolReceived != boolWanted {
		return errExpected(boolWanted, args...)
	}
	return nil
}

func _areEqual(result interface{}, expected interface{}) bool {
	return reflect.DeepEqual(result, expected)
}

func errExpected(boolWanted bool, args ...interface{}) error {

	condition := "to equal"
	if boolWanted == false {
		condition = "not to equal"
	}

	result := args[0]
	expected := args[1]

	switch len(args) {
	case 2:
		return fmt.Errorf("Expected '%v' %v '%v'", result, condition, expected)
	default:
		return fmt.Errorf("%v: Expected '%v' %v '%v'", args[2], result, condition, expected)
	}
}
<commit_msg>Fix expectNot(). Cleanup<commit_after>package slices

import (
	"fmt"
	"reflect"
	"testing"
)

// https://golang.org/cmd/go/#hdr-Description_of_testing_flags
// go test -v -bench string_test.go -benchtime 2s

var ()

func TestIsEmpty(t *testing.T) {

	if err := expect(IsEmpty([]string{}), true); err != nil {
		t.Error(err)
	}

	if err := expect(IsEmpty([]string{""}), true); err != nil {
		t.Error(err)
	}

	if err := expect(IsEmpty([]string{"a", "b", "c"}), false); err != nil {
		t.Error(err)
	}
}

func TestConcat(t *testing.T) {

	if err := expect(Concat([]string{}), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Concat([]string{""}), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Concat([]string{"a", "b", "c"}), "abc"); err != nil {
		t.Error(err)
	}
}

func TestJoin(t *testing.T) {

	if err := expect(Join([]string{}, "-"), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Join([]string{""}, "-"), ""); err != nil {
		t.Error(err)
	}

	if err := expect(Join([]string{"a", "b", "c"}, "-"), "a-b-c"); err != nil {
		t.Error(err)
	}
}

func TestCut(t *testing.T) {

	if err := expect(Cut([]string{}, 0, -1), []string{}); err != nil {
		t.Error(err)
	}

	if err := expectNot(Cut([]string{}, 0, -1), []string{""}); err != nil {
		t.Error(err)
	}

	if err := expect(Cut([]string{""}, 0, -1), []string{""}); err != nil {
		t.Error(err)
	}
}

func TestIsSameArray(t *testing.T) {
	slc1 := []string{"same elements,", "different arrays"}
	if slc2 := Cut(slc1, 0, -1); IsSameArray(slc2, slc1) {
		t.Error(errExpected(false, slc2, slc1))
	}
}

func TestDuplicate(t *testing.T) {
	slc1 := []string{"same elements,", "different arrays"}
	if slc2 := Copy(slc1); IsSameArray(slc2, slc1) {
		t.Error(errExpected(false, slc2, slc1))
	}
}

func TestEquals(t *testing.T) {

	slc1 := []string{"same", "elements"}
	slc2 := []string{"same", "elements"}

	if err := expect(Equals(slc1, slc2)); err != nil {
		t.Error(err)
	}
}

func TestPop(t *testing.T) {

	slcBefore := []string{"just enough", "too much"}
	popped, slcAfter := Pop(slcBefore)

	if err := expect(popped, "too much"); err != nil {
		t.Error(err)
	}

	if err := expect(slcAfter, []string{"just enough"}); err != nil {
		t.Error(err)
	}
}

func TestShift(t *testing.T) {

	slcBefore := []string{"next", "enqueued"}
	shifted, slcAfter := Shift(slcBefore)

	if err := expect(shifted, "next"); err != nil {
		t.Error(err)
	}

	if err := expect(slcAfter, []string{"enqueued"}); err != nil {
		t.Error(err)
	}
}

func TestUnshift(t *testing.T) {
	if err := expect(Unshift([]string{"queue"}, "enqueued"), []string{"enqueued", "queue"}); err != nil {
		t.Error(err)
	}
}

// Ridiculously faster
func BenchmarkQueuePushShift(b *testing.B) {

	slc := []string{"deeporange50", "deeporange500", "deeporange900", "deeporangeA100", "deeporangeA200", "deeporangeA400", "deeporangea700", "deeporange-50", "deeporange:500", "deeporange_900", "deeporange A100", "deeporange-A200", "deeporange:A400", "deeporange_A700", "deeporange000", "deeporange1000", "deeporangeA000", "deeporangeA300", "deeporangeA1000", "deeporange:000", "deeporange-1000", "deeporange_A000", "deeporange A300", "deeporange-A1000", "deeporange"}

	for i := 0; i < b.N; i++ {
		slc = append(slc, "next")
		slc = slc[1:]
	}
}

// Ridiculously slower
func BenchmarkQueueUnshiftPop(b *testing.B) {

	slc := []string{"deeporange50", "deeporange500", "deeporange900", "deeporangeA100", "deeporangeA200", "deeporangeA400", "deeporangea700", "deeporange-50", "deeporange:500", "deeporange_900", "deeporange A100", "deeporange-A200", "deeporange:A400", "deeporange_A700", "deeporange000", "deeporange1000", "deeporangeA000", "deeporangeA300", "deeporangeA1000", "deeporange:000", "deeporange-1000", "deeporange_A000", "deeporange A300", "deeporange-A1000", "deeporange"}
	iEnd := len(slc) - 1

	for i := 0; i < b.N; i++ {
		slc = append([]string{"next"}, slc...)
		slc = slc[:iEnd]
	}
}

func expect(args ...interface{}) error {
	switch len(args) {
	case 0:
		return fmt.Errorf("Not enough arguments to expect(). Args passed: %v", args)
	case 1:
		return expect(args[0], true)
	default:
		return _expect(true, args...)
	}
}

func expectNot(args ...interface{}) error {
	switch len(args) {
	case 0:
		return fmt.Errorf("Not enough arguments to expect(). Args passed: %v", args)
	case 1:
		return expectNot(args[0], true)
	default:
		return _expect(false, args...)
	}
}

func _expect(boolWanted bool, args ...interface{}) error {

	result := args[0]
	expected := args[1]

	if boolReceived := _areEqual(result, expected); boolReceived != boolWanted {
		return errExpected(boolWanted, args...)
	}
	return nil
}

func _areEqual(result interface{}, expected interface{}) bool {
	return reflect.DeepEqual(result, expected)
}

func errExpected(boolWanted bool, args ...interface{}) error {

	condition := "to equal"
	if boolWanted == false {
		condition = "not to equal"
	}

	result := args[0]
	expected := args[1]

	switch len(args) {
	case 2:
		return fmt.Errorf("Expected '%v' %v '%v'", result, condition, expected)
	default:
		return fmt.Errorf("%v: Expected '%v' %v '%v'", args[2], result, condition, expected)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Goutils Author. All Rights Reserved.
//
// -------------------------------------------------------------------

package goutils

import (
	"reflect"
	"testing"
	"unsafe"
)

///  /*
///   * basic types
///   */
///  typedef signed char             int8;
///  typedef unsigned char           uint8;
///  typedef signed short            int16;
///  typedef unsigned short          uint16;
///  typedef signed int              int32;
///  typedef unsigned int            uint32;
///  typedef signed long long int    int64;
///  typedef unsigned long long int  uint64;
///  typedef float                   float32;
///  typedef double                  float64;
///
///  #ifdef _64BIT
///  typedef uint64          uintptr;
///  typedef int64           intptr;
///  typedef int64           intgo; // Go's int
///  typedef uint64          uintgo; // Go's uint
///  #else
///  typedef uint32          uintptr;
///  typedef int32           intptr;
///  typedef int32           intgo; // Go's int
///  typedef uint32          uintgo; // Go's uint
///  #endif
///
///  /*
///   * defined types
///   */
///  typedef uint8           bool;
///  typedef uint8           byte;//

// byte
// output:uint8
func TestByte(t *testing.T) {
	var b byte = '0'
	t.Logf("ByteTest output:%v", reflect.TypeOf(b).Kind())
}

// rune
// output:int32
func TestRune(t *testing.T) {
	var r rune = 0
	t.Logf("RuneTest output:%v", reflect.TypeOf(r).Kind())
}

// string
//
// struct String
// {
//    byte* str;
//    intgo len;
// };
//
// output:&{5311546 12} true
func TestString(t *testing.T) {
	var str string = "Hello world!"

	p := (*struct {
		str  uintptr
		_len int
	})(unsafe.Pointer(&str))

	src_str := (*string)(unsafe.Pointer(p))

	t.Logf("TestString output:%v %v", p, *src_str == str)
}

// slice
//
// struct  Slice
// {					  // must not move anything
//    byte*   array;      // actual data
//    uintgo  len;        // number of elements
//    uintgo  cap;        // allocated number of elements
// };
//
// output:&{842350536768 5 10}
func TestSlice(t *testing.T) {
	var slice []int32 = make([]int32, 5, 10)

	p := (*struct {
		array uintptr
		_len  int
		_cap  int
	})(unsafe.Pointer(&slice))

	t.Logf("TestSlice output:%v", p)
}

// interface
//
// $GOROOT/src/pkg/runtime/type.h
/// struct Type
/// {
///     uintptr size;
///     uint32 hash;
///     uint8 _unused;
///     uint8 align;
///     uint8 fieldAlign;
///     uint8 kind;
///     Alg *alg;
///     void *gc;
///     String *string;
///     UncommonType *x;
///     Type *ptrto;
/// };

// $GOROOT/src/pkg/runtime/runtime.h
/// struct Iface
/// {
///     Itab*   tab;
///     void*   data;
///
/// };
///
/// struct Eface
/// {
///     Type*   type;
///     void*   data;
///
/// };
///
/// struct  Itab
/// {
///     InterfaceType*  inter;
///     Type*   type;
///     Itab*   link;
///     int32   bad;
///     int32   unused;
///     void    (*fun[])(void);
///
/// };
// output:&{5143520 842351144400}
func TestInterface(t *testing.T) {
	var i interface{} = "Hello world!"

	p := (*struct {
		tab  uintptr
		data uintptr
	})(unsafe.Pointer(&i))

	t.Logf("TestInterface output:%v", p)
}
<commit_msg>struct map<commit_after>// Copyright 2016 The Goutils Author. All Rights Reserved.
//
// -------------------------------------------------------------------

package goutils

import (
	"reflect"
	"testing"
	"unsafe"
)

///  /*
///   * basic types
///   */
///  typedef signed char             int8;
///  typedef unsigned char           uint8;
///  typedef signed short            int16;
///  typedef unsigned short          uint16;
///  typedef signed int              int32;
///  typedef unsigned int            uint32;
///  typedef signed long long int    int64;
///  typedef unsigned long long int  uint64;
///  typedef float                   float32;
///  typedef double                  float64;
///
///  #ifdef _64BIT
///  typedef uint64          uintptr;
///  typedef int64           intptr;
///  typedef int64           intgo; // Go's int
///  typedef uint64          uintgo; // Go's uint
///  #else
///  typedef uint32          uintptr;
///  typedef int32           intptr;
///  typedef int32           intgo; // Go's int
///  typedef uint32          uintgo; // Go's uint
///  #endif
///
///  /*
///   * defined types
///   */
///  typedef uint8           bool;
///  typedef uint8           byte;//

// byte
// output:uint8
func TestByte(t *testing.T) {
	var b byte = '0'
	t.Logf("ByteTest output:%v", reflect.TypeOf(b).Kind())
}

// rune
// output:int32
func TestRune(t *testing.T) {
	var r rune = 0
	t.Logf("RuneTest output:%v", reflect.TypeOf(r).Kind())
}

// string
//
// struct String
// {
//    byte* str;
//    intgo len;
// };
//
// output:&{5311546 12} true
func TestString(t *testing.T) {
	var str string = "Hello world!"

	p := (*struct {
		str  uintptr
		_len int
	})(unsafe.Pointer(&str))

	src_str := (*string)(unsafe.Pointer(p))

	t.Logf("TestString output:%v %v", p, *src_str == str)
}

// slice
//
// struct  Slice
// {					  // must not move anything
//    byte*   array;      // actual data
//    uintgo  len;        // number of elements
//    uintgo  cap;        // allocated number of elements
// };
//
// output:&{842350536768 5 10}
func TestSlice(t *testing.T) {
	var slice []int32 = make([]int32, 5, 10)

	p := (*struct {
		array uintptr
		_len  int
		_cap  int
	})(unsafe.Pointer(&slice))

	t.Logf("TestSlice output:%v", p)
}

// interface
//
// $GOROOT/src/pkg/runtime/type.h
/// struct Type
/// {
///     uintptr size;
///     uint32 hash;
///     uint8 _unused;
///     uint8 align;
///     uint8 fieldAlign;
///     uint8 kind;
///     Alg *alg;
///     void *gc;
///     String *string;
///     UncommonType *x;
///     Type *ptrto;
/// };

// $GOROOT/src/pkg/runtime/runtime.h
/// struct Iface
/// {
///     Itab*   tab;
///     void*   data;
///
/// };
///
/// struct Eface
/// {
///     Type*   type;
///     void*   data;
///
/// };
///
/// struct  Itab
/// {
///     InterfaceType*  inter;
///     Type*   type;
///     Itab*   link;
///     int32   bad;
///     int32   unused;
///     void    (*fun[])(void);
///
/// };
// output:&{5143520 842351144400}
func TestInterface(t *testing.T) {
	var i interface{} = "Hello world!"

	p := (*struct {
		tab  uintptr
		data uintptr
	})(unsafe.Pointer(&i))

	t.Logf("TestInterface output:%v", p)
}

// map
//
// $GOROOT/src/pkg/runtime/hashmap.c
/// struct Hmap
/// {
///     uintgo  count;
///     uint32  flags;
///     uint32  hash0;
///     uint8   B;
///     uint8   keysize;
///     uint8   valuesize;
///     uint16  bucketsize;
///
///     byte    *buckets;
///     byte    *oldbuckets;
///     uintptr nevacuate;
///
/// };
//
// output:&{842350537056 0 0 0 0 0 0 0 0 0}
func TestMap(t *testing.T) {
	var m = make(map[string]int32, 10)

	m["hello_world"] = 123456

	p := (*struct {
		count      int
		flags      uint32
		hash0      uint32
		B          uint8
		keysize    uint8
		valuesize  uint8
		bucketsize uint16

		buckets    uintptr
		oldbuckets uintptr
		nevacuate  uintptr
	})(unsafe.Pointer(&m))

	t.Logf("output: %v", p)
}
<|endoftext|>


<commit_before>package quotas_test

import (
	"net/http"
	"net/http/httptest"
	"time"

	testapi "github.com/cloudfoundry/cli/cf/api/fakes"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/net"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testnet "github.com/cloudfoundry/cli/testhelpers/net"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/cf/api/quotas"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CloudControllerQuotaRepository", func() {
	var (
		testServer  *httptest.Server
		testHandler *testnet.TestHandler
		configRepo  core_config.ReadWriter
		repo        CloudControllerQuotaRepository
	)

	BeforeEach(func() {
		configRepo = testconfig.NewRepositoryWithDefaults()
		gateway := net.NewCloudControllerGateway(configRepo, time.Now, &testterm.FakeUI{})
		repo = NewCloudControllerQuotaRepository(configRepo, gateway)
	})

	AfterEach(func() {
		testServer.Close()
	})

	setupTestServer := func(reqs ...testnet.TestRequest) {
		testServer, testHandler = testnet.NewServer(reqs)
		configRepo.SetApiEndpoint(testServer.URL)
	}

	Describe("FindByName", func() {
		BeforeEach(func() {
			setupTestServer(firstQuotaRequest, secondQuotaRequest)
		})

		It("Finds Quota definitions by name", func() {
			quota, err := repo.FindByName("my-remote-quota")

			Expect(err).NotTo(HaveOccurred())
			Expect(testHandler).To(HaveAllRequestsCalled())
			Expect(quota).To(Equal(models.QuotaFields{
				Guid:                    "my-quota-guid",
				Name:                    "my-remote-quota",
				MemoryLimit:             1024,
				InstanceMemoryLimit:     -1,
				RoutesLimit:             123,
				ServicesLimit:           321,
				NonBasicServicesAllowed: true,
			}))
		})
	})

	Describe("FindAll", func() {
		BeforeEach(func() {
			setupTestServer(firstQuotaRequest, secondQuotaRequest)
		})

		It("finds all Quota definitions", func() {
			quotas, err := repo.FindAll()

			Expect(err).NotTo(HaveOccurred())
			Expect(testHandler).To(HaveAllRequestsCalled())
			Expect(len(quotas)).To(Equal(3))
			Expect(quotas[0].Guid).To(Equal("my-quota-guid"))
			Expect(quotas[0].Name).To(Equal("my-remote-quota"))
			Expect(quotas[0].MemoryLimit).To(Equal(int64(1024)))
			Expect(quotas[0].RoutesLimit).To(Equal(123))
			Expect(quotas[0].ServicesLimit).To(Equal(321))

			Expect(quotas[1].Guid).To(Equal("my-quota-guid2"))
			Expect(quotas[2].Guid).To(Equal("my-quota-guid3"))
		})
	})

	Describe("AssignQuotaToOrg", func() {
		It("sets the quota for an organization", func() {
			req := testapi.NewCloudControllerTestRequest(testnet.TestRequest{
				Method:   "PUT",
				Path:     "/v2/organizations/my-org-guid",
				Matcher:  testnet.RequestBodyMatcher(`{"quota_definition_guid":"my-quota-guid"}`),
				Response: testnet.TestResponse{Status: http.StatusCreated},
			})

			setupTestServer(req)

			err := repo.AssignQuotaToOrg("my-org-guid", "my-quota-guid")
			Expect(testHandler).To(HaveAllRequestsCalled())
			Expect(err).NotTo(HaveOccurred())
		})
	})

	Describe("Create", func() {
		It("creates a new quota with the given name", func() {
			req := testapi.NewCloudControllerTestRequest(testnet.TestRequest{
				Method: "POST",
				Path:   "/v2/quota_definitions",
				Matcher: testnet.RequestBodyMatcher(`{
					"name": "not-so-strict",
					"non_basic_services_allowed": false,
					"total_services": 1,
					"total_routes": 12,
					"memory_limit": 123,
					"instance_memory_limit": 0
				}`),
				Response: testnet.TestResponse{Status: http.StatusCreated},
			})
			setupTestServer(req)

			quota := models.QuotaFields{
				Name:          "not-so-strict",
				ServicesLimit: 1,
				RoutesLimit:   12,
				MemoryLimit:   123,
			}
			err := repo.Create(quota)
			Expect(err).NotTo(HaveOccurred())
			Expect(testHandler).To(HaveAllRequestsCalled())
		})
	})

	Describe("Update", func() {
		It("updates an existing quota", func() {
			setupTestServer(testapi.NewCloudControllerTestRequest(testnet.TestRequest{
				Method: "PUT",
				Path:   "/v2/quota_definitions/my-quota-guid",
				Matcher: testnet.RequestBodyMatcher(`{
					"guid": "my-quota-guid",
					"non_basic_services_allowed": false,
					"name": "amazing-quota",
					"total_services": 1,
					"total_routes": 12,
					"memory_limit": 123,
					"instance_memory_limit": 0
				}`),
			}))

			quota := models.QuotaFields{
				Guid:          "my-quota-guid",
				Name:          "amazing-quota",
				ServicesLimit: 1,
				RoutesLimit:   12,
				MemoryLimit:   123,
			}

			err := repo.Update(quota)
			Expect(err).NotTo(HaveOccurred())
			Expect(testHandler).To(HaveAllRequestsCalled())
		})
	})

	Describe("Delete", func() {
		It("deletes the quota with the given name", func() {
			req := testapi.NewCloudControllerTestRequest(testnet.TestRequest{
				Method:   "DELETE",
				Path:     "/v2/quota_definitions/my-quota-guid",
				Response: testnet.TestResponse{Status: http.StatusNoContent},
			})
			setupTestServer(req)

			err := repo.Delete("my-quota-guid")
			Expect(err).NotTo(HaveOccurred())
			Expect(testHandler).To(HaveAllRequestsCalled())
		})
	})
})

var firstQuotaRequest = testapi.NewCloudControllerTestRequest(testnet.TestRequest{
	Method: "GET",
	Path:   "/v2/quota_definitions",
	Response: testnet.TestResponse{
		Status: http.StatusOK,
		Body: `{
		"next_url": "/v2/quota_definitions?page=2",
		"resources": [
			{
			  "metadata": { "guid": "my-quota-guid" },
			  "entity": {
			  	"name": "my-remote-quota",
			  	"memory_limit": 1024,
          "instance_memory_limit": -1,
			  	"total_routes": 123,
			  	"total_services": 321,
			  	"non_basic_services_allowed": true
			  }
			}
		]}`,
	},
})

var secondQuotaRequest = testapi.NewCloudControllerTestRequest(testnet.TestRequest{
	Method: "GET",
	Path:   "/v2/quota_definitions?page=2",
	Response: testnet.TestResponse{
		Status: http.StatusOK,
		Body: `{
		"resources": [
			{
			  "metadata": { "guid": "my-quota-guid2" },
			  "entity": { "name": "my-remote-quota2", "memory_limit": 1024 }
			},
			{
			  "metadata": { "guid": "my-quota-guid3" },
			  "entity": { "name": "my-remote-quota3", "memory_limit": 1024 }
			}
		]}`,
	},
})
<commit_msg>Make quotas_test test work in Go 1.6<commit_after>package quotas_test

import (
	"net/http"
	"time"

	"github.com/cloudfoundry/cli/cf/api/quotas"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/net"

	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	"github.com/onsi/gomega/ghttp"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CloudControllerQuotaRepository", func() {
	var (
		ccServer   *ghttp.Server
		configRepo core_config.ReadWriter
		repo       quotas.CloudControllerQuotaRepository
	)

	BeforeEach(func() {
		ccServer = ghttp.NewServer()
		configRepo = testconfig.NewRepositoryWithDefaults()
		configRepo.SetApiEndpoint(ccServer.URL())
		gateway := net.NewCloudControllerGateway(configRepo, time.Now, &testterm.FakeUI{})
		repo = quotas.NewCloudControllerQuotaRepository(configRepo, gateway)
	})

	AfterEach(func() {
		ccServer.Close()
	})

	Describe("FindByName", func() {
		BeforeEach(func() {
			ccServer.AppendHandlers(
				ghttp.CombineHandlers(
					ghttp.VerifyRequest("GET", "/v2/quota_definitions"),
					ghttp.RespondWith(http.StatusOK, `{
						"next_url": "/v2/quota_definitions?page=2",
						"resources": [
							{
								"metadata": { "guid": "my-quota-guid" },
								"entity": {
									"name": "my-remote-quota",
									"memory_limit": 1024,
									"instance_memory_limit": -1,
									"total_routes": 123,
									"total_services": 321,
									"non_basic_services_allowed": true
								}
							}
						]
					}`),
				),
				ghttp.CombineHandlers(
					ghttp.VerifyRequest("GET", "/v2/quota_definitions", "page=2"),
					ghttp.RespondWith(http.StatusOK, `{
						"resources": [
							{
								"metadata": { "guid": "my-quota-guid2" },
								"entity": { "name": "my-remote-quota2", "memory_limit": 1024 }
							},
							{
								"metadata": { "guid": "my-quota-guid3" },
								"entity": { "name": "my-remote-quota3", "memory_limit": 1024 }
							}
						]
					}`),
				),
			)
		})

		It("Finds Quota definitions by name", func() {
			quota, err := repo.FindByName("my-remote-quota")
			Expect(err).NotTo(HaveOccurred())
			Expect(ccServer.ReceivedRequests()).To(HaveLen(2))
			Expect(quota).To(Equal(models.QuotaFields{
				Guid:                    "my-quota-guid",
				Name:                    "my-remote-quota",
				MemoryLimit:             1024,
				InstanceMemoryLimit:     -1,
				RoutesLimit:             123,
				ServicesLimit:           321,
				NonBasicServicesAllowed: true,
			}))
		})
	})

	Describe("FindAll", func() {
		BeforeEach(func() {
			ccServer.AppendHandlers(
				ghttp.CombineHandlers(
					ghttp.VerifyRequest("GET", "/v2/quota_definitions"),
					ghttp.RespondWith(http.StatusOK, `{
						"next_url": "/v2/quota_definitions?page=2",
						"resources": [
							{
								"metadata": { "guid": "my-quota-guid" },
								"entity": {
									"name": "my-remote-quota",
									"memory_limit": 1024,
									"instance_memory_limit": -1,
									"total_routes": 123,
									"total_services": 321,
									"non_basic_services_allowed": true
								}
							}
						]
					}`),
				),
				ghttp.CombineHandlers(
					ghttp.VerifyRequest("GET", "/v2/quota_definitions", "page=2"),
					ghttp.RespondWith(http.StatusOK, `{
						"resources": [
							{
								"metadata": { "guid": "my-quota-guid2" },
								"entity": { "name": "my-remote-quota2", "memory_limit": 1024 }
							},
							{
								"metadata": { "guid": "my-quota-guid3" },
								"entity": { "name": "my-remote-quota3", "memory_limit": 1024 }
							}
						]
					}`),
				),
			)
		})

		It("finds all Quota definitions", func() {
			quotas, err := repo.FindAll()
			Expect(err).NotTo(HaveOccurred())

			Expect(ccServer.ReceivedRequests()).To(HaveLen(2))
			Expect(quotas).To(HaveLen(3))
			Expect(quotas[0].Guid).To(Equal("my-quota-guid"))
			Expect(quotas[0].Name).To(Equal("my-remote-quota"))
			Expect(quotas[0].MemoryLimit).To(Equal(int64(1024)))
			Expect(quotas[0].RoutesLimit).To(Equal(123))
			Expect(quotas[0].ServicesLimit).To(Equal(321))

			Expect(quotas[1].Guid).To(Equal("my-quota-guid2"))
			Expect(quotas[2].Guid).To(Equal("my-quota-guid3"))
		})
	})

	Describe("AssignQuotaToOrg", func() {
		BeforeEach(func() {
			ccServer.AppendHandlers(
				ghttp.VerifyRequest("PUT", "/v2/organizations/my-org-guid"),
				ghttp.VerifyJSON(`{"quota_definition_guid":"my-quota-guid"}`),
				ghttp.RespondWith(http.StatusCreated, nil),
			)
		})

		It("sets the quota for an organization", func() {
			err := repo.AssignQuotaToOrg("my-org-guid", "my-quota-guid")
			Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
			Expect(err).NotTo(HaveOccurred())
		})
	})

	Describe("Create", func() {
		BeforeEach(func() {
			ccServer.AppendHandlers(
				ghttp.VerifyRequest("POST", "/v2/quota_definitions"),
				ghttp.VerifyJSON(`{
					"name": "not-so-strict",
					"non_basic_services_allowed": false,
					"total_services": 1,
					"total_routes": 12,
					"memory_limit": 123,
					"instance_memory_limit": 0
				}`),
				ghttp.RespondWith(http.StatusCreated, nil),
			)
		})

		It("creates a new quota with the given name", func() {
			quota := models.QuotaFields{
				Name:          "not-so-strict",
				ServicesLimit: 1,
				RoutesLimit:   12,
				MemoryLimit:   123,
			}
			err := repo.Create(quota)
			Expect(err).NotTo(HaveOccurred())
			Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
		})
	})

	Describe("Update", func() {
		BeforeEach(func() {
			ccServer.AppendHandlers(
				ghttp.VerifyRequest("PUT", "/v2/quota_definitions/my-quota-guid"),
				ghttp.VerifyJSON(`{
					"guid": "my-quota-guid",
					"non_basic_services_allowed": false,
					"name": "amazing-quota",
					"total_services": 1,
					"total_routes": 12,
					"memory_limit": 123,
					"instance_memory_limit": 0
				}`),
				ghttp.RespondWith(http.StatusOK, nil),
			)
		})

		It("updates an existing quota", func() {
			quota := models.QuotaFields{
				Guid:          "my-quota-guid",
				Name:          "amazing-quota",
				ServicesLimit: 1,
				RoutesLimit:   12,
				MemoryLimit:   123,
			}

			err := repo.Update(quota)
			Expect(err).NotTo(HaveOccurred())
			Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
		})
	})

	Describe("Delete", func() {
		BeforeEach(func() {
			ccServer.AppendHandlers(
				ghttp.VerifyRequest("DELETE", "/v2/quota_definitions/my-quota-guid"),
				ghttp.RespondWith(http.StatusNoContent, nil),
			)
		})

		It("deletes the quota with the given name", func() {
			err := repo.Delete("my-quota-guid")
			Expect(err).NotTo(HaveOccurred())
			Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
		})
	})
})
<|endoftext|>


<commit_before>// Package json provides a json codec
package json

import (
	"encoding/json"
	"io"

	"github.com/micro/go-micro/codec"
)

type Codec struct {
	Conn    io.ReadWriteCloser
	Encoder *json.Encoder
	Decoder *json.Decoder
}

func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error {
	return nil
}

func (c *Codec) ReadBody(b interface{}) error {
	return c.Decoder.Decode(b)
}

func (c *Codec) Write(m *codec.Message, b interface{}) error {
	return c.Encoder.Encode(b)
}

func (c *Codec) Close() error {
	return c.Conn.Close()
}

func (c *Codec) String() string {
	return "json"
}

func NewCodec(c io.ReadWriteCloser) codec.Codec {
	return &Codec{
		Conn:    c,
		Decoder: json.NewDecoder(c),
		Encoder: json.NewEncoder(c),
	}
}
<commit_msg>Don't process nil<commit_after>// Package json provides a json codec
package json

import (
	"encoding/json"
	"io"

	"github.com/micro/go-micro/codec"
)

type Codec struct {
	Conn    io.ReadWriteCloser
	Encoder *json.Encoder
	Decoder *json.Decoder
}

func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error {
	return nil
}

func (c *Codec) ReadBody(b interface{}) error {
	if b == nil {
		return nil
	}
	return c.Decoder.Decode(b)
}

func (c *Codec) Write(m *codec.Message, b interface{}) error {
	if b == nil {
		return nil
	}
	return c.Encoder.Encode(b)
}

func (c *Codec) Close() error {
	return c.Conn.Close()
}

func (c *Codec) String() string {
	return "json"
}

func NewCodec(c io.ReadWriteCloser) codec.Codec {
	return &Codec{
		Conn:    c,
		Decoder: json.NewDecoder(c),
		Encoder: json.NewEncoder(c),
	}
}
<|endoftext|>


<commit_before>package symmetric

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

var (
	ErrBadKey  = fmt.Errorf("invalid key")
	ErrPadding = fmt.Errorf("invalid padding")
)

var (
	devRandom   *os.File
	SecureLevel = 0
)

func init() {
	var err error

	devRandom, err = os.Open("/dev/random")
	if err != nil {
		fmt.Fprintf(os.Stderr, "*** failed to open /dev/random")
		fmt.Fprintf(os.Stderr, "    long-term key generation not recommended")
	} else {
		SecureLevel = 1
	}
}

// Random returns a byte slice containing size random bytes.
func Random(size int) (b []byte, err error) {
	b = make([]byte, size)
	_, err = io.ReadFull(rand.Reader, b)
	return
}

// GenerateKey returns a key suitable for AES-256 cryptography.
func GenerateKey() (key []byte, err error) {
	return Random(KeySize)
}

// Generates a long-term (LT) key. It uses the `/dev/random`
// device, and will typically be much slower than GenerateKey.
func GenerateLTKey() (key []byte, err error) {
	if devRandom == nil {
		err = DegradedError
		return
	}
	key = make([]byte, KeySize)

	_, err = io.ReadFull(devRandom, key)
	return
}

// GenerateIV returns an initialisation vector suitable for
// AES-CBC encryption.
func GenerateIV() (iv []byte, err error) {
	return Random(aes.BlockSize)
}

// Implement the standard padding scheme for block ciphers.
func PadBuffer(m []byte) (p []byte, err error) {
	mLen := len(m)

	p = make([]byte, mLen)
	copy(p, m)

	if len(p) != mLen {
		return p, ErrPadding
	}

	padding := aes.BlockSize - mLen%aes.BlockSize

	p = append(p, 0x80)
	for i := 1; i < padding; i++ {
		p = append(p, 0x0)
	}
	return
}

// Unpad data padded with the standard padding scheme.
func UnpadBuffer(p []byte) (m []byte, err error) {
	m = p
	var pLen int
	origLen := len(m)

	for pLen = origLen - 1; pLen >= 0; pLen-- {
		if m[pLen] == 0x80 {
			break
		}

		if m[pLen] != 0x0 || (origLen-pLen) > aes.BlockSize {
			err = ErrPadding
			return
		}
	}
	m = m[:pLen]
	return
}

// Encrypt encrypts a message, prepending the IV to the beginning.
func Encrypt(key []byte, msg []byte) (ct []byte, err error) {
	c, err := aes.NewCipher(key)
	if err != nil {
		return
	}

	iv, err := GenerateIV()
	if err != nil {
		return
	}

	padded, err := PadBuffer(msg)
	if err != nil {
		return
	}

	cbc := cipher.NewCBCEncrypter(c, iv)
	cbc.CryptBlocks(padded, padded) // encrypt in-place
	ct = iv
	ct = append(ct, padded...)

	return
}

var ErrInvalidIV = fmt.Errorf("invalid IV")

// Decrypt takes an encrypted messages and decrypts it.
func Decrypt(key []byte, ct []byte) (msg []byte, err error) {
	c, err := aes.NewCipher(key)
	if err != nil {
		return
	}

	// Copy the ciphertext to prevent it from being modified.
	tmp_ct := make([]byte, len(ct))
	copy(tmp_ct, ct)
	iv := tmp_ct[:aes.BlockSize]
	if len(iv) != aes.BlockSize {
		return msg, ErrInvalidIV
	}
	msg = tmp_ct[aes.BlockSize:]

	cbc := cipher.NewCBCDecrypter(c, iv)
	cbc.CryptBlocks(msg, msg)
	msg, err = UnpadBuffer(msg)
	return
}

// Read a key from a file
func ReadKeyFromFile(filename string) (key []byte, err error) {
	key, err = ioutil.ReadFile(filename)
	if err != nil {
		return
	} else if len(key) != KeySize {
		err = ErrBadKey
	}
	return
}

// Zeroise wipes out the data in a slice before deleting the array.
func Zeroise(data *[]byte) (n int) {
	dLen := len(*data)

	for n = 0; n < dLen; n++ {
		(*data)[n] = 0x0
	}

	*data = make([]byte, 0)
	return
}

// Scrub writes random data to the variable the given number of
// rounds, then zeroises it.
func Scrub(data []byte, rounds int) (err error) {
	dLen := len(data)

	var n int
	for r := 0; r < rounds; r++ {
		for i := 0; i < dLen; i++ {
			n, err = io.ReadFull(rand.Reader, data)
			if err != nil {
				return
			} else if n != dLen {
				err = fmt.Errorf("[scrub] invalid random read size %d", n)
				return
			}
		}
	}
	if dLen != Zeroise(&data) {
		err = fmt.Errorf("zeroise failed")
	}
	return
}
<commit_msg>Update padding function with advice from Karl J. Smith.<commit_after>package symmetric

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

var (
	ErrBadKey  = fmt.Errorf("invalid key")
	ErrPadding = fmt.Errorf("invalid padding")
)

var (
	devRandom   *os.File
	SecureLevel = 0
)

func init() {
	var err error

	devRandom, err = os.Open("/dev/random")
	if err != nil {
		fmt.Fprintf(os.Stderr, "*** failed to open /dev/random")
		fmt.Fprintf(os.Stderr, "    long-term key generation not recommended")
	} else {
		SecureLevel = 1
	}
}

// Random returns a byte slice containing size random bytes.
func Random(size int) (b []byte, err error) {
	b = make([]byte, size)
	_, err = io.ReadFull(rand.Reader, b)
	return
}

// GenerateKey returns a key suitable for AES-256 cryptography.
func GenerateKey() (key []byte, err error) {
	return Random(KeySize)
}

// Generates a long-term (LT) key. It uses the `/dev/random`
// device, and will typically be much slower than GenerateKey.
func GenerateLTKey() (key []byte, err error) {
	if devRandom == nil {
		err = DegradedError
		return
	}
	key = make([]byte, KeySize)

	_, err = io.ReadFull(devRandom, key)
	return
}

// GenerateIV returns an initialisation vector suitable for
// AES-CBC encryption.
func GenerateIV() (iv []byte, err error) {
	return Random(aes.BlockSize)
}

// Implement the standard padding scheme for block ciphers.
func PadBuffer(m []byte) (p []byte, err error) {
	mLen := len(m)

        padding := aes.BlockSize - mLen%aes.BlockSize
        p = make([]byte, mLen, aes.BlockSize*(mLen+padding))
        copy(p, m)
	p = append(p, 0x80)
	for i := 1; i < padding; i++ {
		p = append(p, 0x0)
	}
	return
}

// Unpad data padded with the standard padding scheme.
func UnpadBuffer(p []byte) (m []byte, err error) {
	m = p
	var pLen int
	origLen := len(m)

	for pLen = origLen - 1; pLen >= 0; pLen-- {
		if m[pLen] == 0x80 {
			break
		}

		if m[pLen] != 0x0 || (origLen-pLen) > aes.BlockSize {
			err = ErrPadding
			return
		}
	}
	m = m[:pLen]
	return
}

// Encrypt encrypts a message, prepending the IV to the beginning.
func Encrypt(key []byte, msg []byte) (ct []byte, err error) {
	c, err := aes.NewCipher(key)
	if err != nil {
		return
	}

	iv, err := GenerateIV()
	if err != nil {
		return
	}

	padded, err := PadBuffer(msg)
	if err != nil {
		return
	}

	cbc := cipher.NewCBCEncrypter(c, iv)
	cbc.CryptBlocks(padded, padded) // encrypt in-place
	ct = iv
	ct = append(ct, padded...)

	return
}

var ErrInvalidIV = fmt.Errorf("invalid IV")

// Decrypt takes an encrypted messages and decrypts it.
func Decrypt(key []byte, ct []byte) (msg []byte, err error) {
	c, err := aes.NewCipher(key)
	if err != nil {
		return
	}

	// Copy the ciphertext to prevent it from being modified.
	tmp_ct := make([]byte, len(ct))
	copy(tmp_ct, ct)
	iv := tmp_ct[:aes.BlockSize]
	if len(iv) != aes.BlockSize {
		return msg, ErrInvalidIV
	}
	msg = tmp_ct[aes.BlockSize:]

	cbc := cipher.NewCBCDecrypter(c, iv)
	cbc.CryptBlocks(msg, msg)
	msg, err = UnpadBuffer(msg)
	return
}

// Read a key from a file
func ReadKeyFromFile(filename string) (key []byte, err error) {
	key, err = ioutil.ReadFile(filename)
	if err != nil {
		return
	} else if len(key) != KeySize {
		err = ErrBadKey
	}
	return
}

// Zeroise wipes out the data in a slice before deleting the array.
func Zeroise(data *[]byte) (n int) {
	dLen := len(*data)

	for n = 0; n < dLen; n++ {
		(*data)[n] = 0x0
	}

	*data = make([]byte, 0)
	return
}

// Scrub writes random data to the variable the given number of
// rounds, then zeroises it.
func Scrub(data []byte, rounds int) (err error) {
	dLen := len(data)

	var n int
	for r := 0; r < rounds; r++ {
		for i := 0; i < dLen; i++ {
			n, err = io.ReadFull(rand.Reader, data)
			if err != nil {
				return
			} else if n != dLen {
				err = fmt.Errorf("[scrub] invalid random read size %d", n)
				return
			}
		}
	}
	if dLen != Zeroise(&data) {
		err = fmt.Errorf("zeroise failed")
	}
	return
}
<|endoftext|>


<commit_before>package keys

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

// Source represents one or a chain of sources
type Source interface {
	Get(ctx context.Context) ([]byte, error)
}

// Sources defines a chain of sources
type Sources []Source

// Get iterates sources and returns the first successfully resolved
func (sources Sources) Get(ctx context.Context) ([]byte, error) {
	for _, source := range sources {
		bts, err := source.Get(ctx)
		if err == nil {
			return bts, nil
		}
	}
	return nil, ErrNoSourcesResolved
}

// HTTPSource defines a source with a URL to resolve over HTTP
type HTTPSource string

// Get retrieves data from the URL over HTTP
func (source HTTPSource) Get(ctx context.Context) ([]byte, error) {
	if source == "" {
		return nil, ErrEmptyURL
	}
	req, err := http.NewRequest(http.MethodGet, string(source), nil)
	if err != nil {
		return nil, ErrGetKeySource{err}
	}
	req = req.WithContext(ctx)
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, ErrGetKeySource{err}
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		return nil, ErrGetKeySource{fmt.Sprintf("got status code %d got %d", http.StatusOK, res.StatusCode)}
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, ErrReadResponse{err}
	}
	return body, nil
}

// FileSource defines a path to a file on disk
type FileSource string

// Get retrieves data from the path to a file on disk
func (source FileSource) Get(ctx context.Context) ([]byte, error) {
	if source == "" {
		return nil, ErrEmptyFilePath
	}
	f, err := os.Open(string(source))
	if err != nil {
		return nil, ErrGetKeySource{err}
	}
	content, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, ErrReadResponse{err}
	}
	return content, nil
}

// StringSource defines the source as a string
type StringSource string

// Get converts the string to a byte slice
func (source StringSource) Get(ctx context.Context) ([]byte, error) {
	return []byte(source), nil
}
<commit_msg>feat: add a 10 second timeout for the http key source<commit_after>package keys

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

// Source represents one or a chain of sources
type Source interface {
	Get(ctx context.Context) ([]byte, error)
}

// Sources defines a chain of sources
type Sources []Source

// Get iterates sources and returns the first successfully resolved
func (sources Sources) Get(ctx context.Context) ([]byte, error) {
	for _, source := range sources {
		bts, err := source.Get(ctx)
		if err == nil {
			return bts, nil
		}
	}
	return nil, ErrNoSourcesResolved
}

const (
	httpTimeout = 10 * time.Second
)

// HTTPSource defines a source with a URL to resolve over HTTP
type HTTPSource string

// Get retrieves data from the URL over HTTP
func (source HTTPSource) Get(ctx context.Context) ([]byte, error) {
	if source == "" {
		return nil, ErrEmptyURL
	}
	req, err := http.NewRequest(http.MethodGet, string(source), nil)
	if err != nil {
		return nil, ErrGetKeySource{err}
	}
	req = req.WithContext(ctx)
	client := &http.Client{
		Timeout: httpTimeout,
	}
	res, err := client.Do(req)
	if err != nil {
		return nil, ErrGetKeySource{err}
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		return nil, ErrGetKeySource{fmt.Sprintf("got status code %d got %d", http.StatusOK, res.StatusCode)}
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, ErrReadResponse{err}
	}
	return body, nil
}

// FileSource defines a path to a file on disk
type FileSource string

// Get retrieves data from the path to a file on disk
func (source FileSource) Get(ctx context.Context) ([]byte, error) {
	if source == "" {
		return nil, ErrEmptyFilePath
	}
	f, err := os.Open(string(source))
	if err != nil {
		return nil, ErrGetKeySource{err}
	}
	content, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, ErrReadResponse{err}
	}
	return content, nil
}

// StringSource defines the source as a string
type StringSource string

// Get converts the string to a byte slice
func (source StringSource) Get(ctx context.Context) ([]byte, error) {
	return []byte(source), nil
}
<|endoftext|>


<commit_before>// +build coprocess

package main

import (
	"strings"

	"github.com/Sirupsen/logrus"

	"github.com/TykTechnologies/tyk/apidef"
	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/coprocess"

	"errors"
	"io/ioutil"
	"net/http"
)

var (
	// EnableCoProcess will be overridden by config.Global.EnableCoProcess.
	EnableCoProcess = false

	// GlobalDispatcher will be implemented by the current CoProcess driver.
	GlobalDispatcher coprocess.Dispatcher
)

// CoProcessMiddleware is the basic CP middleware struct.
type CoProcessMiddleware struct {
	BaseMiddleware
	HookType         coprocess.HookType
	HookName         string
	MiddlewareDriver apidef.MiddlewareDriver
}

func (mw *CoProcessMiddleware) Name() string {
	return "CoProcessMiddleware"
}

// CreateCoProcessMiddleware initializes a new CP middleware, takes hook type (pre, post, etc.), hook name ("my_hook") and driver ("python").
func CreateCoProcessMiddleware(hookName string, hookType coprocess.HookType, mwDriver apidef.MiddlewareDriver, baseMid BaseMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		BaseMiddleware:   baseMid,
		HookType:         hookType,
		HookName:         hookName,
		MiddlewareDriver: mwDriver,
	}

	return createMiddleware(dMiddleware)
}

func doCoprocessReload() {
	if GlobalDispatcher != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Info("Reloading middlewares")
		GlobalDispatcher.Reload()
	}

}

// CoProcessor represents a CoProcess during the request.
type CoProcessor struct {
	HookType   coprocess.HookType
	Middleware *CoProcessMiddleware
}

// ObjectFromRequest constructs a CoProcessObject from a given http.Request.
func (c *CoProcessor) ObjectFromRequest(r *http.Request) *coprocess.Object {
	var body string
	if r.Body == nil {
		body = ""
	} else {
		defer r.Body.Close()
		originalBody, _ := ioutil.ReadAll(r.Body)
		body = string(originalBody)
	}

	miniRequestObject := &coprocess.MiniRequestObject{
		Headers:        ProtoMap(r.Header),
		SetHeaders:     map[string]string{},
		DeleteHeaders:  []string{},
		Body:           body,
		Url:            r.URL.Path,
		Params:         ProtoMap(r.URL.Query()),
		AddParams:      map[string]string{},
		ExtendedParams: ProtoMap(nil),
		DeleteParams:   []string{},
		ReturnOverrides: &coprocess.ReturnOverrides{
			ResponseCode: -1,
		},
	}

	object := &coprocess.Object{
		Request:  miniRequestObject,
		HookName: c.Middleware.HookName,
	}

	// If a middleware is set, take its HookType, otherwise override it with CoProcessor.HookType
	if c.Middleware != nil && c.HookType == 0 {
		c.HookType = c.Middleware.HookType
	}

	object.HookType = c.HookType

	object.Metadata = make(map[string]string)
	object.Spec = make(map[string]string)

	// Append spec data:
	if c.Middleware != nil {
		object.Spec = map[string]string{
			"OrgID": c.Middleware.Spec.OrgID,
			"APIID": c.Middleware.Spec.APIID,
		}
	}

	// Encode the session object (if not a pre-process & not a custom key check):
	if c.HookType != coprocess.HookType_Pre && c.HookType != coprocess.HookType_CustomKeyCheck {
		session := ctxGetSession(r)
		if session != nil {
			object.Session = ProtoSessionState(session)
		}
	}

	return object
}

// ObjectPostProcess does CoProcessObject post-processing (adding/removing headers or params, etc.).
func (c *CoProcessor) ObjectPostProcess(object *coprocess.Object, r *http.Request) {
	r.ContentLength = int64(len(object.Request.Body))
	r.Body = ioutil.NopCloser(strings.NewReader(object.Request.Body))

	for _, dh := range object.Request.DeleteHeaders {
		r.Header.Del(dh)
	}

	for h, v := range object.Request.SetHeaders {
		r.Header.Set(h, v)
	}

	values := r.URL.Query()
	for _, k := range object.Request.DeleteParams {
		values.Del(k)
	}

	for p, v := range object.Request.AddParams {
		values.Set(p, v)
	}

	r.URL.Path = object.Request.Url
	r.URL.RawQuery = values.Encode()
}

// CoProcessInit creates a new CoProcessDispatcher, it will be called when Tyk starts.
func CoProcessInit() error {
	var err error
	if config.Global.CoProcessOptions.EnableCoProcess {
		GlobalDispatcher, err = NewCoProcessDispatcher()
		EnableCoProcess = true
	}
	return err
}

// EnabledForSpec checks if this middleware should be enabled for a given API.
func (m *CoProcessMiddleware) EnabledForSpec() bool {
	// This flag is true when Tyk has been compiled with CP support and when the configuration enables it.
	enableCoProcess := config.Global.CoProcessOptions.EnableCoProcess && EnableCoProcess
	// This flag indicates if the current spec specifies any CP custom middleware.
	var usesCoProcessMiddleware bool

	supportedDrivers := []apidef.MiddlewareDriver{apidef.PythonDriver, apidef.LuaDriver, apidef.GrpcDriver}

	for _, driver := range supportedDrivers {
		if m.Spec.CustomMiddleware.Driver == driver && CoProcessName == driver {
			usesCoProcessMiddleware = true
			break
		}
	}

	if usesCoProcessMiddleware && enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Debug("Enabling CP middleware.")
		return true
	}

	if usesCoProcessMiddleware && !enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("Your API specifies a CP custom middleware, either Tyk wasn't build with CP support or CP is not enabled in your Tyk configuration file!")
	}

	if !usesCoProcessMiddleware && m.Spec.CustomMiddleware.Driver != "" {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("CP Driver not supported: ", m.Spec.CustomMiddleware.Driver)
	}

	return false
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	log.WithFields(logrus.Fields{
		"prefix": "coprocess",
	}).Debug("CoProcess Request, HookType: ", m.HookType)

	if !EnableCoProcess {
		return nil, 200
	}

	var extractor IdExtractor
	if m.Spec.EnableCoProcessAuth && m.Spec.CustomMiddleware.IdExtractor.Extractor != nil {
		extractor = m.Spec.CustomMiddleware.IdExtractor.Extractor.(IdExtractor)
	}

	var returnOverrides ReturnOverrides
	var sessionID string

	if m.HookType == coprocess.HookType_CustomKeyCheck && extractor != nil {
		sessionID, returnOverrides = extractor.ExtractAndCheck(r)

		if returnOverrides.ResponseCode != 0 {
			if returnOverrides.ResponseError == "" {
				return nil, returnOverrides.ResponseCode
			}
			err := errors.New(returnOverrides.ResponseError)
			return err, returnOverrides.ResponseCode
		}
	}

	// It's also possible to override the HookType:
	coProcessor := CoProcessor{
		Middleware: m,
		// HookType: coprocess.PreHook,
	}

	object := coProcessor.ObjectFromRequest(r)

	returnObject, err := coProcessor.Dispatch(object)
	if err != nil {
		if m.HookType == coprocess.HookType_CustomKeyCheck {
			return errors.New("Key not authorised"), 403
		} else {
			return errors.New("Middleware error"), 500
		}
	}

	coProcessor.ObjectPostProcess(returnObject, r)

	token := returnObject.Metadata["token"]

	// The CP middleware indicates this is a bad auth:
	if returnObject.Request.ReturnOverrides.ResponseCode > 400 {

		logEntry := getLogEntryForRequest(r, token, nil)
		logEntry.Info("Attempted access with invalid key.")

		// Fire Authfailed Event
		AuthFailed(m, r, token)

		// Report in health check
		reportHealthValue(m.Spec, KeyFailure, "1")

		errorMsg := "Key not authorised"
		if returnObject.Request.ReturnOverrides.ResponseError != "" {
			errorMsg = returnObject.Request.ReturnOverrides.ResponseError
		}

		return errors.New(errorMsg), int(returnObject.Request.ReturnOverrides.ResponseCode)
	}

	if returnObject.Request.ReturnOverrides.ResponseCode > 0 {
		for h, v := range returnObject.Request.ReturnOverrides.Headers {
			w.Header().Set(h, v)
		}
		w.WriteHeader(int(returnObject.Request.ReturnOverrides.ResponseCode))
		w.Write([]byte(returnObject.Request.ReturnOverrides.ResponseError))
		return nil, mwStatusRespond
	}

	// Is this a CP authentication middleware?
	if m.Spec.EnableCoProcessAuth && m.HookType == coprocess.HookType_CustomKeyCheck {
		// The CP middleware didn't setup a session:
		if returnObject.Session == nil {
			return errors.New("Key not authorised"), 403
		}

		returnedSession := TykSessionState(returnObject.Session)

		if extractor == nil {
			sessionLifetime := returnedSession.Lifetime(m.Spec.SessionLifetime)
			// This API is not using the ID extractor, but we've got a session:
			m.Spec.SessionManager.UpdateSession(token, returnedSession, sessionLifetime)
			ctxSetSession(r, returnedSession)
			ctxSetAuthToken(r, token)
		} else {
			// The CP middleware did setup a session, we should pass it to the ID extractor (caching):
			extractor.PostProcess(r, returnedSession, sessionID)
		}
	}

	return nil, 200
}
<commit_msg>Add support for API `config_data` to Coprocess middleware<commit_after>// +build coprocess

package main

import (
	"encoding/json"
	"strings"

	"github.com/Sirupsen/logrus"

	"github.com/TykTechnologies/tyk/apidef"
	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/coprocess"

	"errors"
	"io/ioutil"
	"net/http"
)

var (
	// EnableCoProcess will be overridden by config.Global.EnableCoProcess.
	EnableCoProcess = false

	// GlobalDispatcher will be implemented by the current CoProcess driver.
	GlobalDispatcher coprocess.Dispatcher
)

// CoProcessMiddleware is the basic CP middleware struct.
type CoProcessMiddleware struct {
	BaseMiddleware
	HookType         coprocess.HookType
	HookName         string
	MiddlewareDriver apidef.MiddlewareDriver
}

func (mw *CoProcessMiddleware) Name() string {
	return "CoProcessMiddleware"
}

// CreateCoProcessMiddleware initializes a new CP middleware, takes hook type (pre, post, etc.), hook name ("my_hook") and driver ("python").
func CreateCoProcessMiddleware(hookName string, hookType coprocess.HookType, mwDriver apidef.MiddlewareDriver, baseMid BaseMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		BaseMiddleware:   baseMid,
		HookType:         hookType,
		HookName:         hookName,
		MiddlewareDriver: mwDriver,
	}

	return createMiddleware(dMiddleware)
}

func doCoprocessReload() {
	if GlobalDispatcher != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Info("Reloading middlewares")
		GlobalDispatcher.Reload()
	}

}

// CoProcessor represents a CoProcess during the request.
type CoProcessor struct {
	HookType   coprocess.HookType
	Middleware *CoProcessMiddleware
}

// ObjectFromRequest constructs a CoProcessObject from a given http.Request.
func (c *CoProcessor) ObjectFromRequest(r *http.Request) *coprocess.Object {
	var body string
	if r.Body == nil {
		body = ""
	} else {
		defer r.Body.Close()
		originalBody, _ := ioutil.ReadAll(r.Body)
		body = string(originalBody)
	}

	miniRequestObject := &coprocess.MiniRequestObject{
		Headers:        ProtoMap(r.Header),
		SetHeaders:     map[string]string{},
		DeleteHeaders:  []string{},
		Body:           body,
		Url:            r.URL.Path,
		Params:         ProtoMap(r.URL.Query()),
		AddParams:      map[string]string{},
		ExtendedParams: ProtoMap(nil),
		DeleteParams:   []string{},
		ReturnOverrides: &coprocess.ReturnOverrides{
			ResponseCode: -1,
		},
	}

	object := &coprocess.Object{
		Request:  miniRequestObject,
		HookName: c.Middleware.HookName,
	}

	// If a middleware is set, take its HookType, otherwise override it with CoProcessor.HookType
	if c.Middleware != nil && c.HookType == 0 {
		c.HookType = c.Middleware.HookType
	}

	object.HookType = c.HookType

	object.Metadata = make(map[string]string)
	object.Spec = make(map[string]string)

	// Append spec data:
	if c.Middleware != nil {
		configDataAsJson := []byte("{}")
		if len(c.Middleware.Spec.ConfigData) > 0 {
			configDataAsJson, _ = json.Marshal(c.Middleware.Spec.ConfigData)
		}

		object.Spec = map[string]string{
			"OrgID":       c.Middleware.Spec.OrgID,
			"APIID":       c.Middleware.Spec.APIID,
			"config_data": string(configDataAsJson),
		}
	}

	// Encode the session object (if not a pre-process & not a custom key check):
	if c.HookType != coprocess.HookType_Pre && c.HookType != coprocess.HookType_CustomKeyCheck {
		session := ctxGetSession(r)
		if session != nil {
			object.Session = ProtoSessionState(session)
		}
	}

	return object
}

// ObjectPostProcess does CoProcessObject post-processing (adding/removing headers or params, etc.).
func (c *CoProcessor) ObjectPostProcess(object *coprocess.Object, r *http.Request) {
	r.ContentLength = int64(len(object.Request.Body))
	r.Body = ioutil.NopCloser(strings.NewReader(object.Request.Body))

	for _, dh := range object.Request.DeleteHeaders {
		r.Header.Del(dh)
	}

	for h, v := range object.Request.SetHeaders {
		r.Header.Set(h, v)
	}

	values := r.URL.Query()
	for _, k := range object.Request.DeleteParams {
		values.Del(k)
	}

	for p, v := range object.Request.AddParams {
		values.Set(p, v)
	}

	r.URL.Path = object.Request.Url
	r.URL.RawQuery = values.Encode()
}

// CoProcessInit creates a new CoProcessDispatcher, it will be called when Tyk starts.
func CoProcessInit() error {
	var err error
	if config.Global.CoProcessOptions.EnableCoProcess {
		GlobalDispatcher, err = NewCoProcessDispatcher()
		EnableCoProcess = true
	}
	return err
}

// EnabledForSpec checks if this middleware should be enabled for a given API.
func (m *CoProcessMiddleware) EnabledForSpec() bool {
	// This flag is true when Tyk has been compiled with CP support and when the configuration enables it.
	enableCoProcess := config.Global.CoProcessOptions.EnableCoProcess && EnableCoProcess
	// This flag indicates if the current spec specifies any CP custom middleware.
	var usesCoProcessMiddleware bool

	supportedDrivers := []apidef.MiddlewareDriver{apidef.PythonDriver, apidef.LuaDriver, apidef.GrpcDriver}

	for _, driver := range supportedDrivers {
		if m.Spec.CustomMiddleware.Driver == driver && CoProcessName == driver {
			usesCoProcessMiddleware = true
			break
		}
	}

	if usesCoProcessMiddleware && enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Debug("Enabling CP middleware.")
		return true
	}

	if usesCoProcessMiddleware && !enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("Your API specifies a CP custom middleware, either Tyk wasn't build with CP support or CP is not enabled in your Tyk configuration file!")
	}

	if !usesCoProcessMiddleware && m.Spec.CustomMiddleware.Driver != "" {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("CP Driver not supported: ", m.Spec.CustomMiddleware.Driver)
	}

	return false
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	log.WithFields(logrus.Fields{
		"prefix": "coprocess",
	}).Debug("CoProcess Request, HookType: ", m.HookType)

	if !EnableCoProcess {
		return nil, 200
	}

	var extractor IdExtractor
	if m.Spec.EnableCoProcessAuth && m.Spec.CustomMiddleware.IdExtractor.Extractor != nil {
		extractor = m.Spec.CustomMiddleware.IdExtractor.Extractor.(IdExtractor)
	}

	var returnOverrides ReturnOverrides
	var sessionID string

	if m.HookType == coprocess.HookType_CustomKeyCheck && extractor != nil {
		sessionID, returnOverrides = extractor.ExtractAndCheck(r)

		if returnOverrides.ResponseCode != 0 {
			if returnOverrides.ResponseError == "" {
				return nil, returnOverrides.ResponseCode
			}
			err := errors.New(returnOverrides.ResponseError)
			return err, returnOverrides.ResponseCode
		}
	}

	// It's also possible to override the HookType:
	coProcessor := CoProcessor{
		Middleware: m,
		// HookType: coprocess.PreHook,
	}

	object := coProcessor.ObjectFromRequest(r)

	returnObject, err := coProcessor.Dispatch(object)
	if err != nil {
		if m.HookType == coprocess.HookType_CustomKeyCheck {
			return errors.New("Key not authorised"), 403
		} else {
			return errors.New("Middleware error"), 500
		}
	}

	coProcessor.ObjectPostProcess(returnObject, r)

	token := returnObject.Metadata["token"]

	// The CP middleware indicates this is a bad auth:
	if returnObject.Request.ReturnOverrides.ResponseCode > 400 {

		logEntry := getLogEntryForRequest(r, token, nil)
		logEntry.Info("Attempted access with invalid key.")

		// Fire Authfailed Event
		AuthFailed(m, r, token)

		// Report in health check
		reportHealthValue(m.Spec, KeyFailure, "1")

		errorMsg := "Key not authorised"
		if returnObject.Request.ReturnOverrides.ResponseError != "" {
			errorMsg = returnObject.Request.ReturnOverrides.ResponseError
		}

		return errors.New(errorMsg), int(returnObject.Request.ReturnOverrides.ResponseCode)
	}

	if returnObject.Request.ReturnOverrides.ResponseCode > 0 {
		for h, v := range returnObject.Request.ReturnOverrides.Headers {
			w.Header().Set(h, v)
		}
		w.WriteHeader(int(returnObject.Request.ReturnOverrides.ResponseCode))
		w.Write([]byte(returnObject.Request.ReturnOverrides.ResponseError))
		return nil, mwStatusRespond
	}

	// Is this a CP authentication middleware?
	if m.Spec.EnableCoProcessAuth && m.HookType == coprocess.HookType_CustomKeyCheck {
		// The CP middleware didn't setup a session:
		if returnObject.Session == nil {
			return errors.New("Key not authorised"), 403
		}

		returnedSession := TykSessionState(returnObject.Session)

		if extractor == nil {
			sessionLifetime := returnedSession.Lifetime(m.Spec.SessionLifetime)
			// This API is not using the ID extractor, but we've got a session:
			m.Spec.SessionManager.UpdateSession(token, returnedSession, sessionLifetime)
			ctxSetSession(r, returnedSession)
			ctxSetAuthToken(r, token)
		} else {
			// The CP middleware did setup a session, we should pass it to the ID extractor (caching):
			extractor.PostProcess(r, returnedSession, sessionID)
		}
	}

	return nil, 200
}
<|endoftext|>