<commit_before>package main

import (
	"flag"
	"fmt"
	"time"

	"cloud.google.com/go/compute/metadata"

	"github.com/gofrs/flock"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/pkg/apis/clientauthentication"
	clientauthv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
	"k8s.io/klog"
)

const (
	modeTPM      = "tpm"
	modeVMID     = "vmid"
	modeAltToken = "alt-token"
)

var (
	mode = flag.String("mode", modeTPM, "Plugin mode, one of ['tpm', 'vmid', 'alt-token'].")
	// VMID token flags.
	audience = flag.String("audience", "", "Audience field of for the VM ID token. Must be a URI.")
	// TPM flags.
	cacheDir = flag.String("cache-dir", "/var/lib/kubelet/pki", "Path to directory to store key and certificate.")
	tpmPath  = flag.String("tpm-path", "/dev/tpm0", "path to a TPM character device or socket.")

	altTokenURL  = flag.String("alt-token-url", "", "URL to token endpoint.")
	altTokenBody = flag.String("alt-token-body", "", "Body of token request.")

	flockPath = flag.String("flock-path", "/tmp/gke-exec-auth-plugin.lock", "Path to filesystem lock file.")

	scheme       = runtime.NewScheme()
	codecs       = serializer.NewCodecFactory(scheme)
	groupVersion = schema.GroupVersion{
		Group:   "client.authentication.k8s.io",
		Version: "v1alpha1",
	}
)

func init() {
	metav1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
	clientauthv1alpha1.AddToScheme(scheme)
	clientauthentication.AddToScheme(scheme)

	// Override the default in klog. There's verbosity flag for suppressing output.
	flag.Set("logtostderr", "true")
}

func main() {
	flag.Parse()

	var key, cert []byte
	var token string
	var err error

	// Lock the process, this prevents parallel gke-exec-auth-plugin
	// invocations from making redundant CSR requests.
	fileLock := flock.New(*flockPath)
	err = fileLock.Lock()
	if err != nil {
		klog.Exit(err)
	}
	defer fileLock.Unlock()

	switch *mode {
	case modeVMID:
		if *audience == "" {
			klog.Exit("--audience must be set")
		}
		token, err = metadata.Get(fmt.Sprintf("instance/service-accounts/default/identity?audience=%s&format=full", *audience))
		if err != nil {
			klog.Exit(err)
		}
		token = "vmid-" + token
	case modeTPM:
		key, cert, err = getKeyCert(*cacheDir, requestCertificate)
		if err != nil {
			klog.Exit(err)
		}
	case modeAltToken:
		if *altTokenURL == "" {
			klog.Exit("--alt-token-url must be set")
		}
		if *altTokenBody == "" {
			klog.Exit("--alt-token-body must be set")
		}
		tok, err := newAltTokenSource(*altTokenURL, *altTokenBody).Token()
		if err != nil {
			klog.Exit(err)
		}
		token = tok.AccessToken
	default:
		klog.Exitf("unrecognized --mode value %q, want one of [%q, %q]", *mode, modeVMID, modeTPM)
	}

	if err := writeResponse(token, key, cert); err != nil {
		klog.Exit(err)
	}
}

func writeResponse(token string, key, cert []byte) error {
	resp := &clientauthentication.ExecCredential{
		Status: &clientauthentication.ExecCredentialStatus{
			// Make Kubelet poke us every hour, we'll cache the cert for longer.
			ExpirationTimestamp:   &metav1.Time{time.Now().Add(responseExpiry)},
			Token:                 token,
			ClientCertificateData: string(cert),
			ClientKeyData:         string(key),
		},
	}
	data, err := runtime.Encode(codecs.LegacyCodec(groupVersion), resp)
	if err != nil {
		return err
	}
	fmt.Print(string(data))
	return nil
}
<commit_msg>Moved lock. Changed flock path. Addressing PR feedback.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"cloud.google.com/go/compute/metadata"
	"github.com/gofrs/flock"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/pkg/apis/clientauthentication"
	clientauthv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
	"k8s.io/klog"
)

const (
	modeTPM      = "tpm"
	modeVMID     = "vmid"
	modeAltToken = "alt-token"
	flockName    = "gke-exec-auth-plugin.lock"
)

var (
	mode = flag.String("mode", modeTPM, "Plugin mode, one of ['tpm', 'vmid', 'alt-token'].")
	// VMID token flags.
	audience = flag.String("audience", "", "Audience field of for the VM ID token. Must be a URI.")
	// TPM flags.
	cacheDir = flag.String("cache-dir", "/var/lib/kubelet/pki", "Path to directory to store key and certificate.")
	tpmPath  = flag.String("tpm-path", "/dev/tpm0", "path to a TPM character device or socket.")

	altTokenURL  = flag.String("alt-token-url", "", "URL to token endpoint.")
	altTokenBody = flag.String("alt-token-body", "", "Body of token request.")

	scheme       = runtime.NewScheme()
	codecs       = serializer.NewCodecFactory(scheme)
	groupVersion = schema.GroupVersion{
		Group:   "client.authentication.k8s.io",
		Version: "v1alpha1",
	}
)

func init() {
	metav1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
	clientauthv1alpha1.AddToScheme(scheme)
	clientauthentication.AddToScheme(scheme)

	// Override the default in klog. There's verbosity flag for suppressing output.
	flag.Set("logtostderr", "true")
}

func main() {
	flag.Parse()

	var key, cert []byte
	var token string
	var err error

	switch *mode {
	case modeVMID:
		if *audience == "" {
			klog.Exit("--audience must be set")
		}
		token, err = metadata.Get(fmt.Sprintf("instance/service-accounts/default/identity?audience=%s&format=full", *audience))
		if err != nil {
			klog.Exit(err)
		}
		token = "vmid-" + token
	case modeTPM:
		// Lock around certificate reading and CSRs. Prevents parallel
		// invocations creating duplicate CSRs if there is no cert yet.
		fileLock := flock.New(filepath.Join(os.TempDir(), flockName))
		err = fileLock.Lock()
		if err != nil {
			klog.Exit(err)
		}
		defer fileLock.Unlock()

		key, cert, err = getKeyCert(*cacheDir, requestCertificate)
		if err != nil {
			klog.Exit(err)
		}
	case modeAltToken:
		if *altTokenURL == "" {
			klog.Exit("--alt-token-url must be set")
		}
		if *altTokenBody == "" {
			klog.Exit("--alt-token-body must be set")
		}
		tok, err := newAltTokenSource(*altTokenURL, *altTokenBody).Token()
		if err != nil {
			klog.Exit(err)
		}
		token = tok.AccessToken
	default:
		klog.Exitf("unrecognized --mode value %q, want one of [%q, %q]", *mode, modeVMID, modeTPM)
	}

	if err := writeResponse(token, key, cert); err != nil {
		klog.Exit(err)
	}
}

func writeResponse(token string, key, cert []byte) error {
	resp := &clientauthentication.ExecCredential{
		Status: &clientauthentication.ExecCredentialStatus{
			// Make Kubelet poke us every hour, we'll cache the cert for longer.
			ExpirationTimestamp:   &metav1.Time{time.Now().Add(responseExpiry)},
			Token:                 token,
			ClientCertificateData: string(cert),
			ClientKeyData:         string(key),
		},
	}
	data, err := runtime.Encode(codecs.LegacyCodec(groupVersion), resp)
	if err != nil {
		return err
	}
	fmt.Print(string(data))
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Implements php/composer-install buildpack.
// The composer-install buildpack installs the composer dependency manager.
package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
	"github.com/buildpacks/libcnb"
)

const (
	composerLayer    = "composer"
	composerJSON     = "composer.json"
	composerSetup    = "composer-setup"
	composerVer      = "2.1.3"
	versionKey       = "version"
	composerSigURL   = "https://composer.github.io/installer.sig"
	composerSetupURL = "https://getcomposer.org/installer"
)

func main() {
	gcp.Main(detectFn, buildFn)
}

func detectFn(ctx *gcp.Context) (gcp.DetectResult, error) {
	if !ctx.FileExists(composerJSON) {
		return gcp.OptOutFileNotFound(composerJSON), nil
	}
	return gcp.OptInFileFound(composerJSON), nil
}

func buildFn(ctx *gcp.Context) error {
	l := ctx.Layer(composerLayer, gcp.BuildLayer, gcp.CacheLayer)

	ctx.AddBOMEntry(libcnb.BOMEntry{
		Name:     composerLayer,
		Metadata: map[string]interface{}{"version": composerVer},
		Build:    true,
	})

	// Check the metadata in the cache layer to determine if we need to proceed.
	metaVersion := ctx.GetMetadata(l, versionKey)
	if composerVer == metaVersion {
		ctx.CacheHit(composerLayer)
		ctx.Logf("composer binary cache hit, skipping installation.")
		return nil
	}
	ctx.CacheMiss(composerLayer)
	ctx.ClearLayer(l)

	// download the installer
	installer, err := ioutil.TempFile(l.Path, fmt.Sprintf("%s-*.php", composerSetup))
	if err != nil {
		return fmt.Errorf("creating temp file: %w", err)
	}
	defer os.Remove(installer.Name())

	fetchCmd := fmt.Sprintf("curl --fail --show-error --silent --location --retry 3 --output %s %s", installer.Name(), composerSetupURL)
	ctx.Exec([]string{"bash", "-c", fetchCmd}, gcp.WithUserAttribution)

	// verify the installer hash
	expectedSHACmd := fmt.Sprintf("curl --fail --show-error --silent --location --retry 3 %s", composerSigURL)
	expectedSHA := ctx.Exec([]string{"bash", "-c", expectedSHACmd}).Stdout
	actualSHACmd := fmt.Sprintf("php -r \"echo hash_file('sha384', '%s');\"", installer.Name())
	actualSHA := ctx.Exec([]string{"bash", "-c", actualSHACmd}).Stdout
	if actualSHA != expectedSHA {
		return fmt.Errorf("invalid composer installer found at %q: checksum for composer installer, %q, does not match expected checksum of %q", composerSetupURL, actualSHA, expectedSHA)
	}

	// run the installer
	ctx.Logf("Installing Composer v%s", composerVer)
	clBin := filepath.Join(l.Path, "bin")
	ctx.MkdirAll(clBin, 0755)
	installCmd := fmt.Sprintf("php %s --install-dir %s --filename composer --version %s", installer.Name(), clBin, composerVer)
	ctx.Exec([]string{"bash", "-c", installCmd})

	ctx.SetMetadata(l, versionKey, composerVer)
	return nil
}
<commit_msg>Using os.CreateTemp rather than ioutil.TempFile.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Implements php/composer-install buildpack.
// The composer-install buildpack installs the composer dependency manager.
package main

import (
	"fmt"
	"os"
	"path/filepath"

	gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
	"github.com/buildpacks/libcnb"
)

const (
	composerLayer    = "composer"
	composerJSON     = "composer.json"
	composerSetup    = "composer-setup"
	composerVer      = "2.1.3"
	versionKey       = "version"
	composerSigURL   = "https://composer.github.io/installer.sig"
	composerSetupURL = "https://getcomposer.org/installer"
)

func main() {
	gcp.Main(detectFn, buildFn)
}

func detectFn(ctx *gcp.Context) (gcp.DetectResult, error) {
	if !ctx.FileExists(composerJSON) {
		return gcp.OptOutFileNotFound(composerJSON), nil
	}
	return gcp.OptInFileFound(composerJSON), nil
}

func buildFn(ctx *gcp.Context) error {
	l := ctx.Layer(composerLayer, gcp.BuildLayer, gcp.CacheLayer)

	ctx.AddBOMEntry(libcnb.BOMEntry{
		Name:     composerLayer,
		Metadata: map[string]interface{}{"version": composerVer},
		Build:    true,
	})

	// Check the metadata in the cache layer to determine if we need to proceed.
	metaVersion := ctx.GetMetadata(l, versionKey)
	if composerVer == metaVersion {
		ctx.CacheHit(composerLayer)
		ctx.Logf("composer binary cache hit, skipping installation.")
		return nil
	}
	ctx.CacheMiss(composerLayer)
	ctx.ClearLayer(l)

	// download the installer
	installer, err := os.CreateTemp(l.Path, fmt.Sprintf("%s-*.php", composerSetup))
	if err != nil {
		return fmt.Errorf("creating temp file: %w", err)
	}
	defer os.Remove(installer.Name())

	fetchCmd := fmt.Sprintf("curl --fail --show-error --silent --location --retry 3 --output %s %s", installer.Name(), composerSetupURL)
	ctx.Exec([]string{"bash", "-c", fetchCmd}, gcp.WithUserAttribution)

	// verify the installer hash
	expectedSHACmd := fmt.Sprintf("curl --fail --show-error --silent --location --retry 3 %s", composerSigURL)
	expectedSHA := ctx.Exec([]string{"bash", "-c", expectedSHACmd}).Stdout
	actualSHACmd := fmt.Sprintf("php -r \"echo hash_file('sha384', '%s');\"", installer.Name())
	actualSHA := ctx.Exec([]string{"bash", "-c", actualSHACmd}).Stdout
	if actualSHA != expectedSHA {
		return fmt.Errorf("invalid composer installer found at %q: checksum for composer installer, %q, does not match expected checksum of %q", composerSetupURL, actualSHA, expectedSHA)
	}

	// run the installer
	ctx.Logf("Installing Composer v%s", composerVer)
	clBin := filepath.Join(l.Path, "bin")
	ctx.MkdirAll(clBin, 0755)
	installCmd := fmt.Sprintf("php %s --install-dir %s --filename composer --version %s", installer.Name(), clBin, composerVer)
	ctx.Exec([]string{"bash", "-c", installCmd})

	ctx.SetMetadata(l, versionKey, composerVer)
	return nil
}
<|endoftext|>


<commit_before>package data

import (
	"errors"
	"github.com/HouzuoGuo/tiedot/gommap"
	"github.com/bouk/monkey"
	"os"
	"reflect"
	"testing"
)

const tmp = "/tmp/tiedot_test_file"

func TestOpenFlushClose(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	tmpFile, err := OpenDataFile(tmp, 999)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
		return
	}
	defer tmpFile.Close()
	if tmpFile.Path != tmp {
		t.Fatal("Name not set")
	}
	if tmpFile.Used != 0 {
		t.Fatal("Incorrect Used")
	}
	if tmpFile.Growth != 999 {
		t.Fatal("Growth not set")
	}
	if tmpFile.Fh == nil || tmpFile.Buf == nil {
		t.Fatal("Not mmapped")
	}
	if err := tmpFile.Close(); err != nil {
		t.Fatalf("Failed to close: %v", err)
	}
}
func TestFindingAppendAndClear(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	// Open
	tmpFile, err := OpenDataFile(tmp, 1024)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
		return
	}
	if tmpFile.Used != 0 {
		t.Fatal("Incorrect Used", tmpFile.Used)
	}
	// Write something
	tmpFile.Buf[500] = 1
	tmpFile.Close()

	// Re-open
	tmpFile, err = OpenDataFile(tmp, 1024)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
	}
	if tmpFile.Used != 501 {
		t.Fatal("Incorrect Used")
	}

	// Write something again
	for i := 750; i < 800; i++ {
		tmpFile.Buf[i] = byte('a')
	}
	tmpFile.Close()

	// Re-open again
	tmpFile, err = OpenDataFile(tmp, 1024)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
	}
	if tmpFile.Used != 800 {
		t.Fatal("Incorrect Append", tmpFile.Used)
	}
	// Clear the file and test size
	if err = tmpFile.Clear(); err != nil {
		t.Fatal(err)
	}
	if !(len(tmpFile.Buf) == 1024 && tmpFile.Buf[750] == 0 && tmpFile.Growth == 1024 && tmpFile.Size == 1024 && tmpFile.Used == 0) {
		t.Fatal("Did not clear", len(tmpFile.Buf), tmpFile.Growth, tmpFile.Size, tmpFile.Used)
	}
	// Can still write to the buffer?
	tmpFile.Buf[999] = 1
	tmpFile.Close()
}
func TestFileGrow(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	// Open and write something
	tmpFile, err := OpenDataFile(tmp, 4)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
		return
	}
	tmpFile.Buf[2] = 1
	tmpFile.Used = 3
	if tmpFile.Size != 4 {
		t.Fatal("Incorrect Size", tmpFile.Size)
	}
	tmpFile.EnsureSize(8)
	if tmpFile.Size != 12 { // 3 times file growth = 12 bytes
		t.Fatalf("Incorrect Size")
	}
	if tmpFile.Used != 3 { // Used should not change
		t.Fatalf("Incorrect Used")
	}
	if len(tmpFile.Buf) != 12 {
		t.Fatal("Did not remap")
	}
	if tmpFile.Growth != 4 {
		t.Fatalf("Incorrect Growth")
	}
	// Can write to the new (now larger) region
	tmpFile.Buf[10] = 1
	tmpFile.Buf[11] = 1
	tmpFile.Close()
}
func TestCloseErr(t *testing.T) {
	err := "Error close file"
	var d *DataFile
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.PatchInstanceMethod(reflect.TypeOf(d), "Close", func(_ *DataFile) error {
		return errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when close file ")
	}
	patch.Unpatch()
}
func TestTruncateError(t *testing.T) {
	err := "error truncate"
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(os.Truncate, func(name string, size int64) error {
		return errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when call truncate function")
	}
	patch.Unpatch()
}
func TestFileOpenError(t *testing.T) {
	err := "error open file"
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(os.OpenFile, func(name string, flag int, perm os.FileMode) (*os.File, error) {
		return nil, errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when call new open file")
	}
	patch.Unpatch()
}
func TestFillEmptyByteFileError(t *testing.T) {
	err := "error fill empty byte new file"
	var f *os.File
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.PatchInstanceMethod(reflect.TypeOf(f), "Seek", func(_ *os.File, offset int64, whence int) (int64, error) {
		return 0, errors.New(err)
	})

	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when fill empty byte new file")
	}
	patch.Unpatch()
}
func TestMapErrorWhanCallClose(t *testing.T) {
	err := "error create descriptor to mmap"
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(gommap.Map, func(f *os.File) (gommap.MMap, error) {
		return nil, errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when call  mmap")
	}
	patch.Unpatch()
}
<commit_msg>add tests file in data<commit_after>package data

import (
	"errors"
	"github.com/HouzuoGuo/tiedot/gommap"
	"github.com/bouk/monkey"
	"os"
	"reflect"
	"testing"
)

const tmp = "/tmp/tiedot_test_file"

func TestOpenFlushClose(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	tmpFile, err := OpenDataFile(tmp, 999)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
		return
	}
	defer tmpFile.Close()
	if tmpFile.Path != tmp {
		t.Fatal("Name not set")
	}
	if tmpFile.Used != 0 {
		t.Fatal("Incorrect Used")
	}
	if tmpFile.Growth != 999 {
		t.Fatal("Growth not set")
	}
	if tmpFile.Fh == nil || tmpFile.Buf == nil {
		t.Fatal("Not mmapped")
	}
	if err := tmpFile.Close(); err != nil {
		t.Fatalf("Failed to close: %v", err)
	}
}
func TestFindingAppendAndClear(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	// Open
	tmpFile, err := OpenDataFile(tmp, 1024)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
		return
	}
	if tmpFile.Used != 0 {
		t.Fatal("Incorrect Used", tmpFile.Used)
	}
	// Write something
	tmpFile.Buf[500] = 1
	tmpFile.Close()

	// Re-open
	tmpFile, err = OpenDataFile(tmp, 1024)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
	}
	if tmpFile.Used != 501 {
		t.Fatal("Incorrect Used")
	}

	// Write something again
	for i := 750; i < 800; i++ {
		tmpFile.Buf[i] = byte('a')
	}
	tmpFile.Close()

	// Re-open again
	tmpFile, err = OpenDataFile(tmp, 1024)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
	}
	if tmpFile.Used != 800 {
		t.Fatal("Incorrect Append", tmpFile.Used)
	}
	// Clear the file and test size
	if err = tmpFile.Clear(); err != nil {
		t.Fatal(err)
	}
	if !(len(tmpFile.Buf) == 1024 && tmpFile.Buf[750] == 0 && tmpFile.Growth == 1024 && tmpFile.Size == 1024 && tmpFile.Used == 0) {
		t.Fatal("Did not clear", len(tmpFile.Buf), tmpFile.Growth, tmpFile.Size, tmpFile.Used)
	}
	// Can still write to the buffer?
	tmpFile.Buf[999] = 1
	tmpFile.Close()
}
func TestFileGrow(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	// Open and write something
	tmpFile, err := OpenDataFile(tmp, 4)
	if err != nil {
		t.Fatalf("Failed to open: %v", err)
		return
	}
	tmpFile.Buf[2] = 1
	tmpFile.Used = 3
	if tmpFile.Size != 4 {
		t.Fatal("Incorrect Size", tmpFile.Size)
	}
	tmpFile.EnsureSize(8)
	if tmpFile.Size != 12 { // 3 times file growth = 12 bytes
		t.Fatalf("Incorrect Size")
	}
	if tmpFile.Used != 3 { // Used should not change
		t.Fatalf("Incorrect Used")
	}
	if len(tmpFile.Buf) != 12 {
		t.Fatal("Did not remap")
	}
	if tmpFile.Growth != 4 {
		t.Fatalf("Incorrect Growth")
	}
	// Can write to the new (now larger) region
	tmpFile.Buf[10] = 1
	tmpFile.Buf[11] = 1
	tmpFile.Close()
}
func TestCloseErr(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	err := "Error close file"
	var d *DataFile
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.PatchInstanceMethod(reflect.TypeOf(d), "Close", func(_ *DataFile) error {
		return errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when close file ")
	}
	patch.Unpatch()
}
func TestTruncateError(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	err := "error truncate"
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(os.Truncate, func(name string, size int64) error {
		return errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when call truncate function")
	}
	patch.Unpatch()
}
func TestFileOpenError(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	err := "error open file"
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(os.OpenFile, func(name string, flag int, perm os.FileMode) (*os.File, error) {
		return nil, errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when call new open file")
	}
	patch.Unpatch()
}
func TestFillEmptyByteFileError(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	err := "error fill empty byte new file"
	var f *os.File
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.PatchInstanceMethod(reflect.TypeOf(f), "Seek", func(_ *os.File, offset int64, whence int) (int64, error) {
		return 0, errors.New(err)
	})

	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when fill empty byte new file")
	}
	patch.Unpatch()
}
func TestMapErrorWhanCallClose(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	err := "error create descriptor to mmap"
	tmpFile, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(gommap.Map, func(f *os.File) (gommap.MMap, error) {
		return nil, errors.New(err)
	})
	if tmpFile.Clear().Error() != err {
		t.Error("Expected error when call  mmap")
	}
	patch.Unpatch()
}
func TestOpenDataFileErrAfterOpen(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error after open file"
	patch := monkey.Patch(os.OpenFile, func(name string, flag int, perm os.FileMode) (*os.File, error) {
		return nil, errors.New(errMessage)
	})
	defer patch.Unpatch()

	if _, err := OpenDataFile(tmp, 1024);err.Error() != errMessage {
		t.Error("Expected error when call OpenDataFile")
	}
}
func TestOpenDataSeekErr(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error after call Seek"
	var fh *os.File
	patch := monkey.PatchInstanceMethod(reflect.TypeOf(fh), "Seek", func(_ *os.File, offset int64, whence int) (ret int64, err error)  {
		return 0, errors.New(errMessage)
	})
	defer patch.Unpatch()
	if _, err := OpenDataFile(tmp, 1024);err.Error() != errMessage {
		t.Error("Expected error when call Seek struct file ")
	}
}
func TestFileSmallerThanGrowth(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error not ensure size file"
	var d *DataFile
	var fh *os.File
	patchSeek := monkey.PatchInstanceMethod(reflect.TypeOf(fh), "Seek", func(_ *os.File, offset int64, whence int) (ret int64, err error)  {
		return 10, nil
	})
	defer patchSeek.Unpatch()

	patch := monkey.PatchInstanceMethod(reflect.TypeOf(d), "EnsureSize", func(_ *DataFile, more int) (err error)  {
		return errors.New(errMessage)
	})
	defer patch.Unpatch()

	if _, err := OpenDataFile(tmp, 1024);err.Error() != errMessage {
		t.Error("Expected error when call EnsureSize function")
	}
}
func TestOverWriteWithZeroErrorFileWrite(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error write"
	var fh *os.File
	fd, _ := OpenDataFile(tmp, 1024)
	patchWrite := monkey.PatchInstanceMethod(reflect.TypeOf(fh), "Write", func(_ *os.File, b []byte) (n int, err error)  {
		return 0, errors.New(errMessage)
	})
	defer patchWrite.Unpatch()
	fd.Clear()
}
func TestEnsureSizeUnmapErr(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error unmap"
	var m *gommap.MMap

	patch := monkey.PatchInstanceMethod(reflect.TypeOf(m), "Unmap", func(_ *gommap.MMap) (err error)  {
		return errors.New(errMessage)
	})
	defer patch.Unpatch()

	fd, _ := OpenDataFile(tmp, 1024)
	fd.Used = 2000

	if fd.EnsureSize(0).Error() != errMessage {
		t.Error("Expected error unmap in inner function EnsureSize")
	}
}
func TestEnsureSizeOverwriteWithZeroErr(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error Overwrite"
	var fh *os.File
	patch := monkey.PatchInstanceMethod(reflect.TypeOf(fh), "Seek", func(_ *os.File, offset int64, whence int) (ret int64, err error)  {
		return 0, errors.New(errMessage)
	})
	defer patch.Unpatch()

	fd, _ := OpenDataFile(tmp, 1024)
	fd.Used = 2000

	if fd.EnsureSize(0).Error() != errMessage {
		t.Error("Expected error `overWriteWithZero` in inner function `EnsureSize`")
	}
}
func TestEnsureSizeMapErr(t *testing.T) {
	os.Remove(tmp)
	defer os.Remove(tmp)
	errMessage := "error map bufer"
	fd, _ := OpenDataFile(tmp, 1024)
	patch := monkey.Patch(gommap.Map, func(f *os.File) (gommap.MMap, error) {
		return nil, errors.New(errMessage)
	})
	defer patch.Unpatch()
	fd.Size = 500
	if fd.EnsureSize(1200).Error() != errMessage {
		t.Error("Expected error `gommap.Map` in inner function `EnsureSize`")
	}
}<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package log implements a simple logging package. It defines a type, Logger,
// with methods for formatting output. It also has a predefined 'standard'
// Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and
// Panic[f|ln], which are easier to use than creating a Logger manually.
// That logger writes to standard error and prints the date and time
// of each logged message.
// The Fatal functions call os.Exit(1) after writing the log message.
// The Panic functions call panic after writing the log message.
package log

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"sync"
	"time"
)

// These flags define which text to prefix to each log entry generated by the Logger.
const (
	// Bits or'ed together to control what's printed.
	// There is no control over the order they appear (the order listed
	// here) or the format they present (as described in the comments).
	// The prefix is followed by a colon only when Llongfile or Lshortfile
	// is specified.
	// For example, flags Ldate | Ltime (or LstdFlags) produce,
	//	2009/01/23 01:23:23 message
	// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
	//	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
	Ltime                         // the time in the local time zone: 01:23:23
	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile                     // full file name and line number: /a/b/c/d.go:23
	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
	LstdFlags     = Ldate | Ltime // initial values for the standard logger
)

// A Logger represents an active logging object that generates lines of
// output to an io.Writer.  Each logging operation makes a single call to
// the Writer's Write method.  A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
	mu     sync.Mutex // ensures atomic writes; protects the following fields
	prefix string     // prefix to write at beginning of each line
	flag   int        // properties
	out    io.Writer  // destination for output
	buf    []byte     // for accumulating text to write
}

// New creates a new Logger.   The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) *Logger {
	return &Logger{out: out, prefix: prefix, flag: flag}
}

// SetOutput sets the output destination for the logger.
func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.out = w
}

var std = New(os.Stderr, "", LstdFlags)

// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
func itoa(buf *[]byte, i int, wid int) {
	// Assemble decimal in reverse order.
	var b [20]byte
	bp := len(b) - 1
	for i >= 10 || wid > 1 {
		wid--
		q := i / 10
		b[bp] = byte('0' + i - q*10)
		bp--
		i = q
	}
	// i < 10
	b[bp] = byte('0' + i)
	*buf = append(*buf, b[bp:]...)
}

func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
	*buf = append(*buf, l.prefix...)
	if l.flag&LUTC != 0 {
		t = t.UTC()
	}
	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
		if l.flag&Ldate != 0 {
			year, month, day := t.Date()
			itoa(buf, year, 4)
			*buf = append(*buf, '/')
			itoa(buf, int(month), 2)
			*buf = append(*buf, '/')
			itoa(buf, day, 2)
			*buf = append(*buf, ' ')
		}
		if l.flag&(Ltime|Lmicroseconds) != 0 {
			hour, min, sec := t.Clock()
			itoa(buf, hour, 2)
			*buf = append(*buf, ':')
			itoa(buf, min, 2)
			*buf = append(*buf, ':')
			itoa(buf, sec, 2)
			if l.flag&Lmicroseconds != 0 {
				*buf = append(*buf, '.')
				itoa(buf, t.Nanosecond()/1e3, 6)
			}
			*buf = append(*buf, ' ')
		}
	}
	if l.flag&(Lshortfile|Llongfile) != 0 {
		if l.flag&Lshortfile != 0 {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		*buf = append(*buf, file...)
		*buf = append(*buf, ':')
		itoa(buf, line, -1)
		*buf = append(*buf, ": "...)
	}
}

// Output writes the output for a logging event.  The string s contains
// the text to print after the prefix specified by the flags of the
// Logger.  A newline is appended if the last character of s is not
// already a newline.  Calldepth is used to recover the PC and is
// provided for generality, although at the moment on all pre-defined
// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) error {
	now := time.Now() // get this early.
	var file string
	var line int
	l.mu.Lock()
	defer l.mu.Unlock()
	if l.flag&(Lshortfile|Llongfile) != 0 {
		// release lock while getting caller info - it's expensive.
		l.mu.Unlock()
		var ok bool
		_, file, line, ok = runtime.Caller(calldepth)
		if !ok {
			file = "???"
			line = 0
		}
		l.mu.Lock()
	}
	l.buf = l.buf[:0]
	l.formatHeader(&l.buf, now, file, line)
	l.buf = append(l.buf, s...)
	if len(s) == 0 || s[len(s)-1] != '\n' {
		l.buf = append(l.buf, '\n')
	}
	_, err := l.out.Write(l.buf)
	return err
}

// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Printf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
}

// Print calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }

// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
func (l *Logger) Fatal(v ...interface{}) {
	l.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
func (l *Logger) Fatalln(v ...interface{}) {
	l.Output(2, fmt.Sprintln(v...))
	os.Exit(1)
}

// Panic is equivalent to l.Print() followed by a call to panic().
func (l *Logger) Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	l.Output(2, s)
	panic(s)
}

// Panicf is equivalent to l.Printf() followed by a call to panic().
func (l *Logger) Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	l.Output(2, s)
	panic(s)
}

// Panicln is equivalent to l.Println() followed by a call to panic().
func (l *Logger) Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	l.Output(2, s)
	panic(s)
}

// Flags returns the output flags for the logger.
func (l *Logger) Flags() int {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.flag
}

// SetFlags sets the output flags for the logger.
func (l *Logger) SetFlags(flag int) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.flag = flag
}

// Prefix returns the output prefix for the logger.
func (l *Logger) Prefix() string {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.prefix
}

// SetPrefix sets the output prefix for the logger.
func (l *Logger) SetPrefix(prefix string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.prefix = prefix
}

// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
	std.mu.Lock()
	defer std.mu.Unlock()
	std.out = w
}

// Flags returns the output flags for the standard logger.
func Flags() int {
	return std.Flags()
}

// SetFlags sets the output flags for the standard logger.
func SetFlags(flag int) {
	std.SetFlags(flag)
}

// Prefix returns the output prefix for the standard logger.
func Prefix() string {
	return std.Prefix()
}

// SetPrefix sets the output prefix for the standard logger.
func SetPrefix(prefix string) {
	std.SetPrefix(prefix)
}

// These functions write to the standard logger.

// Print calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Print.
func Print(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
}

// Printf calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Printf.
func Printf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
}

// Println calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Println.
func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

// Fatal is equivalent to Print() followed by a call to os.Exit(1).
func Fatal(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalf is equivalent to Printf() followed by a call to os.Exit(1).
func Fatalf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Fatalln is equivalent to Println() followed by a call to os.Exit(1).
func Fatalln(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
	os.Exit(1)
}

// Panic is equivalent to Print() followed by a call to panic().
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	std.Output(2, s)
	panic(s)
}

// Panicf is equivalent to Printf() followed by a call to panic().
func Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	std.Output(2, s)
	panic(s)
}

// Panicln is equivalent to Println() followed by a call to panic().
func Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	std.Output(2, s)
	panic(s)
}

// Output writes the output for a logging event.  The string s contains
// the text to print after the prefix specified by the flags of the
// Logger.  A newline is appended if the last character of s is not
// already a newline.  Calldepth is the count of the number of
// frames to skip when computing the file name and line number
// if Llongfile or Lshortfile is set; a value of 1 will print the details
// for the caller of Output.
func Output(calldepth int, s string) error {
	return std.Output(calldepth+1, s) // +1 for this frame.
}
<commit_msg>Display prefix after flag output<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package log implements a simple logging package. It defines a type, Logger,
// with methods for formatting output. It also has a predefined 'standard'
// Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and
// Panic[f|ln], which are easier to use than creating a Logger manually.
// That logger writes to standard error and prints the date and time
// of each logged message.
// The Fatal functions call os.Exit(1) after writing the log message.
// The Panic functions call panic after writing the log message.
package log

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"sync"
	"time"
)

// These flags define which text to prefix to each log entry generated by the Logger.
const (
	// Bits or'ed together to control what's printed.
	// There is no control over the order they appear (the order listed
	// here) or the format they present (as described in the comments).
	// The prefix is followed by a colon only when Llongfile or Lshortfile
	// is specified.
	// For example, flags Ldate | Ltime (or LstdFlags) produce,
	//	2009/01/23 01:23:23 message
	// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
	//	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
	Ltime                         // the time in the local time zone: 01:23:23
	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile                     // full file name and line number: /a/b/c/d.go:23
	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
	LstdFlags     = Ldate | Ltime // initial values for the standard logger
	Lbefore                       // Display flag output before prefix
)

// A Logger represents an active logging object that generates lines of
// output to an io.Writer.  Each logging operation makes a single call to
// the Writer's Write method.  A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
	mu     sync.Mutex // ensures atomic writes; protects the following fields
	prefix string     // prefix to write at beginning of each line
	flag   int        // properties
	out    io.Writer  // destination for output
	buf    []byte     // for accumulating text to write
}

// New creates a new Logger.   The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) *Logger {
	return &Logger{out: out, prefix: prefix, flag: flag}
}

// SetOutput sets the output destination for the logger.
func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.out = w
}

var std = New(os.Stderr, "", LstdFlags)

// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
func itoa(buf *[]byte, i int, wid int) {
	// Assemble decimal in reverse order.
	var b [20]byte
	bp := len(b) - 1
	for i >= 10 || wid > 1 {
		wid--
		q := i / 10
		b[bp] = byte('0' + i - q*10)
		bp--
		i = q
	}
	// i < 10
	b[bp] = byte('0' + i)
	*buf = append(*buf, b[bp:]...)
}

func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
        if l.flag&Lbefore != 0 {
            *buf = formatFlags(&buf, t, file, line)
	    *buf = append(*buf, l.prefix...)
        } else {
	    *buf = append(*buf, l.prefix...)
            *buf = formatFlags(&buf, t, file, line)
        }
}

func (l *Logger) formatFlags(buf *[]byte, t time.Time, file string, line int) buf *[] {
	if l.flag&LUTC != 0 {
		t = t.UTC()
	}
	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
		if l.flag&Ldate != 0 {
			year, month, day := t.Date()
			itoa(buf, year, 4)
			*buf = append(*buf, '/')
			itoa(buf, int(month), 2)
			*buf = append(*buf, '/')
			itoa(buf, day, 2)
			*buf = append(*buf, ' ')
		}
		if l.flag&(Ltime|Lmicroseconds) != 0 {
			hour, min, sec := t.Clock()
			itoa(buf, hour, 2)
			*buf = append(*buf, ':')
			itoa(buf, min, 2)
			*buf = append(*buf, ':')
			itoa(buf, sec, 2)
			if l.flag&Lmicroseconds != 0 {
				*buf = append(*buf, '.')
				itoa(buf, t.Nanosecond()/1e3, 6)
			}
			*buf = append(*buf, ' ')
		}
	}
	if l.flag&(Lshortfile|Llongfile) != 0 {
		if l.flag&Lshortfile != 0 {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		*buf = append(*buf, file...)
		*buf = append(*buf, ':')
		itoa(buf, line, -1)
		*buf = append(*buf, ": "...)
	}
}

// Output writes the output for a logging event.  The string s contains
// the text to print after the prefix specified by the flags of the
// Logger.  A newline is appended if the last character of s is not
// already a newline.  Calldepth is used to recover the PC and is
// provided for generality, although at the moment on all pre-defined
// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) error {
	now := time.Now() // get this early.
	var file string
	var line int
	l.mu.Lock()
	defer l.mu.Unlock()
	if l.flag&(Lshortfile|Llongfile) != 0 {
		// release lock while getting caller info - it's expensive.
		l.mu.Unlock()
		var ok bool
		_, file, line, ok = runtime.Caller(calldepth)
		if !ok {
			file = "???"
			line = 0
		}
		l.mu.Lock()
	}
	l.buf = l.buf[:0]
	l.formatHeader(&l.buf, now, file, line)
	l.buf = append(l.buf, s...)
	if len(s) == 0 || s[len(s)-1] != '\n' {
		l.buf = append(l.buf, '\n')
	}
	_, err := l.out.Write(l.buf)
	return err
}

// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Printf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
}

// Print calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }

// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
func (l *Logger) Fatal(v ...interface{}) {
	l.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
func (l *Logger) Fatalln(v ...interface{}) {
	l.Output(2, fmt.Sprintln(v...))
	os.Exit(1)
}

// Panic is equivalent to l.Print() followed by a call to panic().
func (l *Logger) Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	l.Output(2, s)
	panic(s)
}

// Panicf is equivalent to l.Printf() followed by a call to panic().
func (l *Logger) Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	l.Output(2, s)
	panic(s)
}

// Panicln is equivalent to l.Println() followed by a call to panic().
func (l *Logger) Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	l.Output(2, s)
	panic(s)
}

// Flags returns the output flags for the logger.
func (l *Logger) Flags() int {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.flag
}

// SetFlags sets the output flags for the logger.
func (l *Logger) SetFlags(flag int) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.flag = flag
}

// Prefix returns the output prefix for the logger.
func (l *Logger) Prefix() string {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.prefix
}

// SetPrefix sets the output prefix for the logger.
func (l *Logger) SetPrefix(prefix string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.prefix = prefix
}

// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
	std.mu.Lock()
	defer std.mu.Unlock()
	std.out = w
}

// Flags returns the output flags for the standard logger.
func Flags() int {
	return std.Flags()
}

// SetFlags sets the output flags for the standard logger.
func SetFlags(flag int) {
	std.SetFlags(flag)
}

// Prefix returns the output prefix for the standard logger.
func Prefix() string {
	return std.Prefix()
}

// SetPrefix sets the output prefix for the standard logger.
func SetPrefix(prefix string) {
	std.SetPrefix(prefix)
}

// These functions write to the standard logger.

// Print calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Print.
func Print(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
}

// Printf calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Printf.
func Printf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
}

// Println calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Println.
func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

// Fatal is equivalent to Print() followed by a call to os.Exit(1).
func Fatal(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalf is equivalent to Printf() followed by a call to os.Exit(1).
func Fatalf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Fatalln is equivalent to Println() followed by a call to os.Exit(1).
func Fatalln(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
	os.Exit(1)
}

// Panic is equivalent to Print() followed by a call to panic().
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	std.Output(2, s)
	panic(s)
}

// Panicf is equivalent to Printf() followed by a call to panic().
func Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	std.Output(2, s)
	panic(s)
}

// Panicln is equivalent to Println() followed by a call to panic().
func Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	std.Output(2, s)
	panic(s)
}

// Output writes the output for a logging event.  The string s contains
// the text to print after the prefix specified by the flags of the
// Logger.  A newline is appended if the last character of s is not
// already a newline.  Calldepth is the count of the number of
// frames to skip when computing the file name and line number
// if Llongfile or Lshortfile is set; a value of 1 will print the details
// for the caller of Output.
func Output(calldepth int, s string) error {
	return std.Output(calldepth+1, s) // +1 for this frame.
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package table

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/aclements/go-gg/generic"
)

// GroupID identifies a group. GroupIDs form a tree, rooted at
// RootGroupID (which is also the zero GroupID).
type GroupID struct {
	*groupNode
}

// RootGroupID is the root of the GroupID tree.
var RootGroupID = GroupID{}

type groupNode struct {
	parent GroupID
	label  interface{}
}

// String returns the path to GroupID g in the form "/l1/l2/l3". If g
// is RootGroupID, it returns "/". Each level in the group is formed
// by formatting the label using fmt's "%v" verb. Note that this is
// purely diagnostic; this string may not uniquely identify g.
func (g GroupID) String() string {
	if g == RootGroupID {
		return "/"
	}
	parts := []string{}
	for p := g; p != RootGroupID; p = p.parent {
		part := fmt.Sprintf("/%v", p.label)
		parts = append(parts, part)
	}
	for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
		parts[i], parts[j] = parts[j], parts[i]
	}
	return strings.Join(parts, "")
}

// Extend returns a new GroupID that is a child of GroupID g. The
// returned GroupID will not be equal to any existing GroupID (even if
// label is not unique among g's children). The label is primarily
// diagnostic; the table package uses it only when printing tables,
// but callers may store semantic information in group labels.
func (g GroupID) Extend(label interface{}) GroupID {
	return GroupID{&groupNode{g, label}}
}

// Parent returns the parent of g. The parent of RootGroupID is
// RootGroupID.
func (g GroupID) Parent() GroupID {
	if g == RootGroupID {
		return RootGroupID
	}
	return g.parent
}

// Label returns the label of g.
func (g GroupID) Label() interface{} {
	return g.label
}

// GroupBy sub-divides all groups such that all of the rows in each
// group have equal values for all of the named columns. The relative
// order of rows with equal values for the named columns is
// maintained. Grouped-by columns become constant columns within each
// group.
func GroupBy(g Grouping, cols ...string) Grouping {
	// TODO: This would generate much less garbage if we grouped
	// all of cols in one pass.

	if len(cols) == 0 {
		return g
	}

	out := Grouping(new(Table))
	for _, gid := range g.Tables() {
		t := g.Table(gid)

		if cv, ok := t.Const(cols[0]); ok {
			// Grouping by a constant is trivial.
			subgid := gid.Extend(cv)
			out = out.AddTable(subgid, t)
			continue
		}

		c := t.MustColumn(cols[0])

		// Create an index on c.
		type subgroupInfo struct {
			gid GroupID
			val interface{}
		}
		subgroups := []subgroupInfo{}
		gidkey := make(map[interface{}]GroupID)
		rowsMap := make(map[GroupID][]int)
		seq := reflect.ValueOf(c)
		for i := 0; i < seq.Len(); i++ {
			x := seq.Index(i).Interface()
			subgid, ok := gidkey[x]
			if !ok {
				subgid = gid.Extend(x)
				subgroups = append(subgroups, subgroupInfo{subgid, x})
				gidkey[x] = subgid
				rowsMap[subgid] = []int{}
			}
			rowsMap[subgid] = append(rowsMap[subgid], i)
		}

		// Split this group in all columns.
		for _, subgroup := range subgroups {
			// Construct this new group.
			rows := rowsMap[subgroup.gid]
			subtable := new(Table)
			for _, name := range t.Columns() {
				if name == cols[0] {
					// Promote the group-by column
					// to a constant.
					subtable = subtable.AddConst(name, subgroup.val)
					continue
				}
				seq := t.Column(name)
				seq = generic.MultiIndex(seq, rows)
				subtable = subtable.Add(name, seq)
			}
			out = out.AddTable(subgroup.gid, subtable)
		}
	}

	return GroupBy(out, cols[1:]...)
}

// Ungroup concatenates adjacent Tables in g that share a group parent
// into a Table identified by the parent, undoing the effects of the
// most recent GroupBy operation.
func Ungroup(g Grouping) Grouping {
	groups := g.Tables()
	if len(groups) == 0 || len(groups) == 1 && groups[0] == RootGroupID {
		return g
	}

	out := Grouping(new(Table))
	runGid := groups[0].Parent()
	runTabs := []*Table{}
	for _, gid := range groups {
		if gid.Parent() != runGid {
			// Flush the run.
			out = out.AddTable(runGid, concatRows(runTabs...))

			runGid = gid.Parent()
			runTabs = runTabs[:0]
		}
		runTabs = append(runTabs, g.Table(gid))
	}
	// Flush the last run.
	out = out.AddTable(runGid, concatRows(runTabs...))

	return out
}

// Flatten concatenates all of the groups in g into a single Table.
// This is equivalent to repeatedly Ungrouping g.
func Flatten(g Grouping) *Table {
	groups := g.Tables()
	switch len(groups) {
	case 0:
		return new(Table)

	case 1:
		return g.Table(groups[0])
	}

	tabs := make([]*Table, len(groups))
	for i, gid := range groups {
		tabs[i] = g.Table(gid)
	}

	return concatRows(tabs...)
}

// concatRows concatenates the rows of tabs into a single Table. All
// Tables in tabs must all have the same column set.
func concatRows(tabs ...*Table) *Table {
	// TODO: Consider making this public. It would have to check
	// the columns, and we would probably also want a concatCols.

	switch len(tabs) {
	case 0:
		return new(Table)

	case 1:
		return tabs[0]
	}

	// Construct each column.
	out := new(Table)
	seqs := make([]generic.Slice, len(tabs))
	for _, col := range tabs[0].Columns() {
		seqs = seqs[:0]
		for _, tab := range tabs {
			seqs = append(seqs, tab.Column(col))
		}
		out = out.Add(col, generic.Concat(seqs...))
	}

	return out
}
<commit_msg>table: keep constants constant during GroupBy<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package table

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/aclements/go-gg/generic"
)

// GroupID identifies a group. GroupIDs form a tree, rooted at
// RootGroupID (which is also the zero GroupID).
type GroupID struct {
	*groupNode
}

// RootGroupID is the root of the GroupID tree.
var RootGroupID = GroupID{}

type groupNode struct {
	parent GroupID
	label  interface{}
}

// String returns the path to GroupID g in the form "/l1/l2/l3". If g
// is RootGroupID, it returns "/". Each level in the group is formed
// by formatting the label using fmt's "%v" verb. Note that this is
// purely diagnostic; this string may not uniquely identify g.
func (g GroupID) String() string {
	if g == RootGroupID {
		return "/"
	}
	parts := []string{}
	for p := g; p != RootGroupID; p = p.parent {
		part := fmt.Sprintf("/%v", p.label)
		parts = append(parts, part)
	}
	for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
		parts[i], parts[j] = parts[j], parts[i]
	}
	return strings.Join(parts, "")
}

// Extend returns a new GroupID that is a child of GroupID g. The
// returned GroupID will not be equal to any existing GroupID (even if
// label is not unique among g's children). The label is primarily
// diagnostic; the table package uses it only when printing tables,
// but callers may store semantic information in group labels.
func (g GroupID) Extend(label interface{}) GroupID {
	return GroupID{&groupNode{g, label}}
}

// Parent returns the parent of g. The parent of RootGroupID is
// RootGroupID.
func (g GroupID) Parent() GroupID {
	if g == RootGroupID {
		return RootGroupID
	}
	return g.parent
}

// Label returns the label of g.
func (g GroupID) Label() interface{} {
	return g.label
}

// GroupBy sub-divides all groups such that all of the rows in each
// group have equal values for all of the named columns. The relative
// order of rows with equal values for the named columns is
// maintained. Grouped-by columns become constant columns within each
// group.
func GroupBy(g Grouping, cols ...string) Grouping {
	// TODO: This would generate much less garbage if we grouped
	// all of cols in one pass.

	if len(cols) == 0 {
		return g
	}

	out := Grouping(new(Table))
	for _, gid := range g.Tables() {
		t := g.Table(gid)

		if cv, ok := t.Const(cols[0]); ok {
			// Grouping by a constant is trivial.
			subgid := gid.Extend(cv)
			out = out.AddTable(subgid, t)
			continue
		}

		c := t.MustColumn(cols[0])

		// Create an index on c.
		type subgroupInfo struct {
			gid GroupID
			val interface{}
		}
		subgroups := []subgroupInfo{}
		gidkey := make(map[interface{}]GroupID)
		rowsMap := make(map[GroupID][]int)
		seq := reflect.ValueOf(c)
		for i := 0; i < seq.Len(); i++ {
			x := seq.Index(i).Interface()
			subgid, ok := gidkey[x]
			if !ok {
				subgid = gid.Extend(x)
				subgroups = append(subgroups, subgroupInfo{subgid, x})
				gidkey[x] = subgid
				rowsMap[subgid] = []int{}
			}
			rowsMap[subgid] = append(rowsMap[subgid], i)
		}

		// Split this group in all columns.
		for _, subgroup := range subgroups {
			// Construct this new group.
			rows := rowsMap[subgroup.gid]
			subtable := new(Table)
			for _, name := range t.Columns() {
				if name == cols[0] {
					// Promote the group-by column
					// to a constant.
					subtable = subtable.AddConst(name, subgroup.val)
					continue
				}
				if cv, ok := t.Const(name); ok {
					// Keep constants constant.
					subtable = subtable.AddConst(name, cv)
					continue
				}
				seq := t.Column(name)
				seq = generic.MultiIndex(seq, rows)
				subtable = subtable.Add(name, seq)
			}
			out = out.AddTable(subgroup.gid, subtable)
		}
	}

	return GroupBy(out, cols[1:]...)
}

// Ungroup concatenates adjacent Tables in g that share a group parent
// into a Table identified by the parent, undoing the effects of the
// most recent GroupBy operation.
func Ungroup(g Grouping) Grouping {
	groups := g.Tables()
	if len(groups) == 0 || len(groups) == 1 && groups[0] == RootGroupID {
		return g
	}

	out := Grouping(new(Table))
	runGid := groups[0].Parent()
	runTabs := []*Table{}
	for _, gid := range groups {
		if gid.Parent() != runGid {
			// Flush the run.
			out = out.AddTable(runGid, concatRows(runTabs...))

			runGid = gid.Parent()
			runTabs = runTabs[:0]
		}
		runTabs = append(runTabs, g.Table(gid))
	}
	// Flush the last run.
	out = out.AddTable(runGid, concatRows(runTabs...))

	return out
}

// Flatten concatenates all of the groups in g into a single Table.
// This is equivalent to repeatedly Ungrouping g.
func Flatten(g Grouping) *Table {
	groups := g.Tables()
	switch len(groups) {
	case 0:
		return new(Table)

	case 1:
		return g.Table(groups[0])
	}

	tabs := make([]*Table, len(groups))
	for i, gid := range groups {
		tabs[i] = g.Table(gid)
	}

	return concatRows(tabs...)
}

// concatRows concatenates the rows of tabs into a single Table. All
// Tables in tabs must all have the same column set.
func concatRows(tabs ...*Table) *Table {
	// TODO: Consider making this public. It would have to check
	// the columns, and we would probably also want a concatCols.

	switch len(tabs) {
	case 0:
		return new(Table)

	case 1:
		return tabs[0]
	}

	// Construct each column.
	out := new(Table)
	seqs := make([]generic.Slice, len(tabs))
	for _, col := range tabs[0].Columns() {
		seqs = seqs[:0]
		for _, tab := range tabs {
			seqs = append(seqs, tab.Column(col))
		}
		out = out.Add(col, generic.Concat(seqs...))
	}

	return out
}
<|endoftext|>


<commit_before>package controllers

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/mux"
)

func TestGetTables(t *testing.T) {
	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
	}{
		{"Get tables without custom where clause", "/tables", "GET", http.StatusOK},
		{"Get tables with custom where clause", "/tables?c.relname=$eq.test", "GET", http.StatusOK},
		{"Get tables with custom order clause", "/tables?_order=c.relname", "GET", http.StatusOK},
		{"Get tables with custom where clause and pagination", "/tables?c.relname=$eq.test&_page=1&_page_size=20", "GET", http.StatusOK},
		{"Get tables with COUNT clause", "/tables?_count=*", "GET", http.StatusOK},
		{"Get tables with custom where invalid clause", "/tables?0c.relname=$eq.test", "GET", http.StatusBadRequest},
		{"Get tables with ORDER BY and invalid column", "/tables?_order=0c.relname", "GET", http.StatusBadRequest},
		{"Get tables with noexistent column", "/tables?c.rolooo=$eq.test", "GET", http.StatusBadRequest},
	}

	router := mux.NewRouter()
	router.HandleFunc("/tables", GetTables).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetTables")
	}
}

func TestGetTablesByDatabaseAndSchema(t *testing.T) {
	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
	}{
		{"Get tables by database and schema without custom where clause", "/prest/public", "GET", http.StatusOK},
		{"Get tables by database and schema with custom where clause", "/prest/public?t.tablename=$eq.test", "GET", http.StatusOK},
		{"Get tables by database and schema with order clause", "/prest/public?t.tablename=$eq.test&_order=t.tablename", "GET", http.StatusOK},
		{"Get tables by database and schema with custom where clause and pagination", "/prest/public?t.tablename=$eq.test&_page=1&_page_size=20", "GET", http.StatusOK},
		// errors
		{"Get tables by database and schema with custom where invalid clause", "/prest/public?0t.tablename=$eq.test", "GET", http.StatusBadRequest},
		{"Get tables by databases and schema with custom where and pagination invalid", "/prest/public?t.tablename=$eq.test&_page=A&_page_size=20", "GET", http.StatusBadRequest},
		{"Get tables by databases and schema with ORDER BY and column invalid", "/prest/public?_order=0t.tablename", "GET", http.StatusBadRequest},
		{"Get tables by databases with noexistent column", "/prest/public?t.taababa=$eq.test", "GET", http.StatusBadRequest},
	}

	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}", GetTablesByDatabaseAndSchema).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetTablesByDatabaseAndSchema")
	}
}

func TestSelectFromTables(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", SelectFromTables).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
		body        string
	}{
		{"execute select in a table with array", "/prest/public/testarray", "GET", http.StatusOK, "[{\"id\":100,\"data\":[\"Gohan\",\"Goten\"]}]"},
		{"execute select in a table without custom where clause", "/prest/public/test", "GET", http.StatusOK, ""},
		{"execute select in a table with count all fields *", "/prest/public/test?_count=*", "GET", http.StatusOK, ""},
		{"execute select in a table with count function", "/prest/public/test?_count=name", "GET", http.StatusOK, ""},
		{"execute select in a table with custom where clause", "/prest/public/test?name=$eq.nuveo", "GET", http.StatusOK, ""},
		{"execute select in a table with custom join clause", "/prest/public/test?_join=inner:test8:test8.nameforjoin:$eq:test.name", "GET", http.StatusOK, ""},
		{"execute select in a table with order clause empty", "/prest/public/test?_order=", "GET", http.StatusOK, ""},
		{"execute select in a table with custom where clause and pagination", "/prest/public/test?name=$eq.nuveo&_page=1&_page_size=20", "GET", http.StatusOK, ""},
		{"execute select in a table with select fields", "/prest/public/test5?_select=celphone,name", "GET", http.StatusOK, ""},
		{"execute select in a table with select *", "/prest/public/test5?_select=*", "GET", http.StatusOK, ""},

		{"execute select in a table with group by clause", "/prest/public/test_group_by_table?_select=age,sum:salary&_groupby=age", "GET", http.StatusOK, "[{\"age\":20,\"sum\":1350}, \n {\"age\":19,\"sum\":7997}]"},

		{"execute select in a view without custom where clause", "/prest/public/view_test", "GET", http.StatusOK, ""},
		{"execute select in a view with count all fields *", "/prest/public/view_test?_count=*", "GET", http.StatusOK, ""},
		{"execute select in a view with count function", "/prest/public/view_test?_count=player", "GET", http.StatusOK, ""},
		{"execute select in a view with order function", "/prest/public/view_test?_order=-player", "GET", http.StatusOK, ""},
		{"execute select in a view with custom where clause", "/prest/public/view_test?player=$eq.gopher", "GET", http.StatusOK, ""},
		{"execute select in a view with custom join clause", "/prest/public/view_test?_join=inner:test2:test2.name:eq:view_test.player", "GET", http.StatusOK, ""},
		{"execute select in a view with custom where clause and pagination", "/prest/public/view_test?player=$eq.gopher&_page=1&_page_size=20", "GET", http.StatusOK, ""},
		{"execute select in a view with select fields", "/prest/public/view_test?_select=player", "GET", http.StatusOK, ""},

		// errors
		{"execute select in a table with invalid join clause", "/prest/public/test?_join=inner:test2:test2.name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with order clause and column invalid", "/prest/public/test?_order=0name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid pagination clause", "/prest/public/test?name=$eq.nuveo&_page=A", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid count clause", "/prest/public/test?_count=0name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid order clause", "/prest/public/test?_order=0name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid fields using group by clause", "/prest/public/test_group_by_table?_select=pa,sum:pum&_groupby=pa", "GET", http.StatusBadRequest, ""},

		{"execute select in a view with an other column", "/prest/public/view_test?_select=celphone", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with where and column invalid", "/prest/public/view_test?0celphone=$eq.888888", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with custom join clause invalid", "/prest/public/view_test?_join=inner:test2.name:eq:view_test.player", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with custom where clause and pagination invalid", "/prest/public/view_test?player=$eq.gopher&_page=A&_page_size=20", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with order by and column invalid", "/prest/public/view_test?_order=0celphone", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with count column invalid", "/prest/public/view_test?_count=0celphone", "GET", http.StatusBadRequest, ""},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		if tc.body != "" {
			doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "SelectFromTables", tc.body)
			continue
		}
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "SelectFromTables")
	}
}

func TestInsertInTables(t *testing.T) {
	m := make(map[string]interface{})
	m["name"] = "prest"

	mJSON := make(map[string]interface{})
	mJSON["name"] = "prest"
	mJSON["data"] = `{"term": "name", "subterm": ["names", "of", "subterms"], "obj": {"emp": "nuveo"}}`

	mARRAY := make(map[string]interface{})
	mARRAY["data"] = []string{"value 1", "value 2", "value 3"}

	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", InsertInTables).Methods("POST")
	server := httptest.NewServer(router)
	defer server.Close()

	var testCases = []struct {
		description string
		url         string
		request     map[string]interface{}
		status      int
	}{
		{"execute insert in a table with array field", "/prest/public/testarray", mARRAY, http.StatusOK},
		{"execute insert in a table with jsonb field", "/prest/public/testjson", mJSON, http.StatusOK},
		{"execute insert in a table without custom where clause", "/prest/public/test", m, http.StatusOK},
		{"execute insert in a table with invalid database", "/0prest/public/test", m, http.StatusBadRequest},
		{"execute insert in a table with invalid schema", "/prest/0public/test", m, http.StatusBadRequest},
		{"execute insert in a table with invalid table", "/prest/public/0test", m, http.StatusBadRequest},
		{"execute insert in a table with invalid body", "/prest/public/test", nil, http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, tc.request, "POST", tc.status, "InsertInTables")
	}
}

func TestDeleteFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", DeleteFromTable).Methods("DELETE")
	server := httptest.NewServer(router)
	defer server.Close()

	var testCases = []struct {
		description string
		url         string
		request     map[string]interface{}
		status      int
	}{
		{"execute delete in a table without custom where clause", "/prest/public/test", nil, http.StatusOK},
		{"excute delete in a table with where clause", "/prest/public/test?name=$eq.nuveo", nil, http.StatusOK},
		{"execute delete in a table with invalid database", "/0prest/public/test", nil, http.StatusBadRequest},
		{"execute delete in a table with invalid schema", "/prest/0public/test", nil, http.StatusBadRequest},
		{"execute delete in a table with invalid table", "/prest/public/0test", nil, http.StatusBadRequest},
		{"execute delete in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", nil, http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, tc.request, "DELETE", tc.status, "DeleteFromTable")
	}
}

func TestUpdateFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", UpdateTable).Methods("PUT", "PATCH")
	server := httptest.NewServer(router)
	defer server.Close()

	m := make(map[string]interface{}, 0)
	m["name"] = "prest"

	var testCases = []struct {
		description string
		url         string
		request     map[string]interface{}
		status      int
	}{
		{"execute update in a table without custom where clause", "/prest/public/test", m, http.StatusOK},
		{"excute update in a table with where clause", "/prest/public/test?name=$eq.nuveo", m, http.StatusOK},
		{"execute update in a table with invalid database", "/0prest/public/test", m, http.StatusBadRequest},
		{"execute update in a table with invalid schema", "/prest/0public/test", m, http.StatusBadRequest},
		{"execute update in a table with invalid table", "/prest/public/0test", m, http.StatusBadRequest},
		{"execute update in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", m, http.StatusBadRequest},
		{"execute update in a table with invalid body", "/prest/public/test?name=$eq.nuveo", nil, http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, tc.request, "PUT", tc.status, "UpdateTable")
		doRequest(t, server.URL+tc.url, tc.request, "PATCH", tc.status, "UpdateTable")
	}
}
<commit_msg>Add support to HAVING clause (#177)<commit_after>package controllers

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/mux"
)

func TestGetTables(t *testing.T) {
	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
	}{
		{"Get tables without custom where clause", "/tables", "GET", http.StatusOK},
		{"Get tables with custom where clause", "/tables?c.relname=$eq.test", "GET", http.StatusOK},
		{"Get tables with custom order clause", "/tables?_order=c.relname", "GET", http.StatusOK},
		{"Get tables with custom where clause and pagination", "/tables?c.relname=$eq.test&_page=1&_page_size=20", "GET", http.StatusOK},
		{"Get tables with COUNT clause", "/tables?_count=*", "GET", http.StatusOK},
		{"Get tables with custom where invalid clause", "/tables?0c.relname=$eq.test", "GET", http.StatusBadRequest},
		{"Get tables with ORDER BY and invalid column", "/tables?_order=0c.relname", "GET", http.StatusBadRequest},
		{"Get tables with noexistent column", "/tables?c.rolooo=$eq.test", "GET", http.StatusBadRequest},
	}

	router := mux.NewRouter()
	router.HandleFunc("/tables", GetTables).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetTables")
	}
}

func TestGetTablesByDatabaseAndSchema(t *testing.T) {
	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
	}{
		{"Get tables by database and schema without custom where clause", "/prest/public", "GET", http.StatusOK},
		{"Get tables by database and schema with custom where clause", "/prest/public?t.tablename=$eq.test", "GET", http.StatusOK},
		{"Get tables by database and schema with order clause", "/prest/public?t.tablename=$eq.test&_order=t.tablename", "GET", http.StatusOK},
		{"Get tables by database and schema with custom where clause and pagination", "/prest/public?t.tablename=$eq.test&_page=1&_page_size=20", "GET", http.StatusOK},
		// errors
		{"Get tables by database and schema with custom where invalid clause", "/prest/public?0t.tablename=$eq.test", "GET", http.StatusBadRequest},
		{"Get tables by databases and schema with custom where and pagination invalid", "/prest/public?t.tablename=$eq.test&_page=A&_page_size=20", "GET", http.StatusBadRequest},
		{"Get tables by databases and schema with ORDER BY and column invalid", "/prest/public?_order=0t.tablename", "GET", http.StatusBadRequest},
		{"Get tables by databases with noexistent column", "/prest/public?t.taababa=$eq.test", "GET", http.StatusBadRequest},
	}

	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}", GetTablesByDatabaseAndSchema).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetTablesByDatabaseAndSchema")
	}
}

func TestSelectFromTables(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", SelectFromTables).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
		body        string
	}{
		{"execute select in a table with array", "/prest/public/testarray", "GET", http.StatusOK, "[{\"id\":100,\"data\":[\"Gohan\",\"Goten\"]}]"},
		{"execute select in a table without custom where clause", "/prest/public/test", "GET", http.StatusOK, ""},
		{"execute select in a table with count all fields *", "/prest/public/test?_count=*", "GET", http.StatusOK, ""},
		{"execute select in a table with count function", "/prest/public/test?_count=name", "GET", http.StatusOK, ""},
		{"execute select in a table with custom where clause", "/prest/public/test?name=$eq.nuveo", "GET", http.StatusOK, ""},
		{"execute select in a table with custom join clause", "/prest/public/test?_join=inner:test8:test8.nameforjoin:$eq:test.name", "GET", http.StatusOK, ""},
		{"execute select in a table with order clause empty", "/prest/public/test?_order=", "GET", http.StatusOK, ""},
		{"execute select in a table with custom where clause and pagination", "/prest/public/test?name=$eq.nuveo&_page=1&_page_size=20", "GET", http.StatusOK, ""},
		{"execute select in a table with select fields", "/prest/public/test5?_select=celphone,name", "GET", http.StatusOK, ""},
		{"execute select in a table with select *", "/prest/public/test5?_select=*", "GET", http.StatusOK, ""},

		{"execute select in a table with group by clause", "/prest/public/test_group_by_table?_select=age,sum:salary&_groupby=age", "GET", http.StatusOK, "[{\"age\":20,\"sum\":1350}, \n {\"age\":19,\"sum\":7997}]"},
		{"Execute select in a table with group by and having clause", "/prest/public/test_group_by_table?_select=age,sum:salary&_groupby=age->>having:sum:salary:$gt:3000", "GET", http.StatusOK, "[{\"age\":19,\"sum\":7997}]"},

		{"execute select in a view without custom where clause", "/prest/public/view_test", "GET", http.StatusOK, ""},
		{"execute select in a view with count all fields *", "/prest/public/view_test?_count=*", "GET", http.StatusOK, ""},
		{"execute select in a view with count function", "/prest/public/view_test?_count=player", "GET", http.StatusOK, ""},
		{"execute select in a view with order function", "/prest/public/view_test?_order=-player", "GET", http.StatusOK, ""},
		{"execute select in a view with custom where clause", "/prest/public/view_test?player=$eq.gopher", "GET", http.StatusOK, ""},
		{"execute select in a view with custom join clause", "/prest/public/view_test?_join=inner:test2:test2.name:eq:view_test.player", "GET", http.StatusOK, ""},
		{"execute select in a view with custom where clause and pagination", "/prest/public/view_test?player=$eq.gopher&_page=1&_page_size=20", "GET", http.StatusOK, ""},
		{"execute select in a view with select fields", "/prest/public/view_test?_select=player", "GET", http.StatusOK, ""},

		// errors
		{"execute select in a table with invalid join clause", "/prest/public/test?_join=inner:test2:test2.name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with order clause and column invalid", "/prest/public/test?_order=0name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid pagination clause", "/prest/public/test?name=$eq.nuveo&_page=A", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid count clause", "/prest/public/test?_count=0name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid order clause", "/prest/public/test?_order=0name", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid fields using group by clause", "/prest/public/test_group_by_table?_select=pa,sum:pum&_groupby=pa", "GET", http.StatusBadRequest, ""},
		{"execute select in a table with invalid fields using group by and having clause", "/prest/public/test_group_by_table?_select=pa,sum:pum&_groupby=pa->>having:sum:pmu:$eq:150", "GET", http.StatusBadRequest, ""},

		{"execute select in a view with an other column", "/prest/public/view_test?_select=celphone", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with where and column invalid", "/prest/public/view_test?0celphone=$eq.888888", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with custom join clause invalid", "/prest/public/view_test?_join=inner:test2.name:eq:view_test.player", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with custom where clause and pagination invalid", "/prest/public/view_test?player=$eq.gopher&_page=A&_page_size=20", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with order by and column invalid", "/prest/public/view_test?_order=0celphone", "GET", http.StatusBadRequest, ""},
		{"execute select in a view with count column invalid", "/prest/public/view_test?_count=0celphone", "GET", http.StatusBadRequest, ""},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		if tc.body != "" {
			doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "SelectFromTables", tc.body)
			continue
		}
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "SelectFromTables")
	}
}

func TestInsertInTables(t *testing.T) {
	m := make(map[string]interface{})
	m["name"] = "prest"

	mJSON := make(map[string]interface{})
	mJSON["name"] = "prest"
	mJSON["data"] = `{"term": "name", "subterm": ["names", "of", "subterms"], "obj": {"emp": "nuveo"}}`

	mARRAY := make(map[string]interface{})
	mARRAY["data"] = []string{"value 1", "value 2", "value 3"}

	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", InsertInTables).Methods("POST")
	server := httptest.NewServer(router)
	defer server.Close()

	var testCases = []struct {
		description string
		url         string
		request     map[string]interface{}
		status      int
	}{
		{"execute insert in a table with array field", "/prest/public/testarray", mARRAY, http.StatusOK},
		{"execute insert in a table with jsonb field", "/prest/public/testjson", mJSON, http.StatusOK},
		{"execute insert in a table without custom where clause", "/prest/public/test", m, http.StatusOK},
		{"execute insert in a table with invalid database", "/0prest/public/test", m, http.StatusBadRequest},
		{"execute insert in a table with invalid schema", "/prest/0public/test", m, http.StatusBadRequest},
		{"execute insert in a table with invalid table", "/prest/public/0test", m, http.StatusBadRequest},
		{"execute insert in a table with invalid body", "/prest/public/test", nil, http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, tc.request, "POST", tc.status, "InsertInTables")
	}
}

func TestDeleteFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", DeleteFromTable).Methods("DELETE")
	server := httptest.NewServer(router)
	defer server.Close()

	var testCases = []struct {
		description string
		url         string
		request     map[string]interface{}
		status      int
	}{
		{"execute delete in a table without custom where clause", "/prest/public/test", nil, http.StatusOK},
		{"excute delete in a table with where clause", "/prest/public/test?name=$eq.nuveo", nil, http.StatusOK},
		{"execute delete in a table with invalid database", "/0prest/public/test", nil, http.StatusBadRequest},
		{"execute delete in a table with invalid schema", "/prest/0public/test", nil, http.StatusBadRequest},
		{"execute delete in a table with invalid table", "/prest/public/0test", nil, http.StatusBadRequest},
		{"execute delete in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", nil, http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, tc.request, "DELETE", tc.status, "DeleteFromTable")
	}
}

func TestUpdateFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", UpdateTable).Methods("PUT", "PATCH")
	server := httptest.NewServer(router)
	defer server.Close()

	m := make(map[string]interface{}, 0)
	m["name"] = "prest"

	var testCases = []struct {
		description string
		url         string
		request     map[string]interface{}
		status      int
	}{
		{"execute update in a table without custom where clause", "/prest/public/test", m, http.StatusOK},
		{"excute update in a table with where clause", "/prest/public/test?name=$eq.nuveo", m, http.StatusOK},
		{"execute update in a table with invalid database", "/0prest/public/test", m, http.StatusBadRequest},
		{"execute update in a table with invalid schema", "/prest/0public/test", m, http.StatusBadRequest},
		{"execute update in a table with invalid table", "/prest/public/0test", m, http.StatusBadRequest},
		{"execute update in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", m, http.StatusBadRequest},
		{"execute update in a table with invalid body", "/prest/public/test?name=$eq.nuveo", nil, http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, tc.request, "PUT", tc.status, "UpdateTable")
		doRequest(t, server.URL+tc.url, tc.request, "PATCH", tc.status, "UpdateTable")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"unicode/utf8"
)

const version = "1.0.0"

// Defines a single panel
type Panel struct {
	timeout int64
	panel   string
}

// Do some basic logging for any error
func checkErr(error err) bool {
	if err != nil {
		log.Fatalln("Error encountered:", err)
		return true
	}
	return false
}

// Load a specified file into the panels slice
func loadFile(string fileName, queue chan *stringOut) {
	file, err := os.Open(filename)
	if checkErr(err) {
		return
	}

	stringOut <- "END"

}

func load(string fileName) {
	log.Println("Loading", fileName)
	lines := make(chan string, 100)

	go loadFile(fileName, lines)

	for {
		line := <-lines
		if line != "END" {
			runeValue, width := utf8.DecodeRuneInString(line[0:])

		} else {
			break
		}
	}

}

func main() {
	fmt.Println("Go ASCII Service version", version)

	go load("sw1.txt")

	sock, err := net.Listen("tcp", "21")

	if checkErr(err) {
		return
	}

	for {

	}
}
<commit_msg>Signed-off-by: Amrit Panesar <apanesar@4195tech.com><commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"unicode/utf8"
)

// http://semver.org/
const version = "0.1.0"

// Defines a single panel
type Panel struct {
	timeout int64
	panel   string
}

// Do some basic logging for any error
func checkErr(error err) bool {
	if err != nil {
		log.Fatalln("Error encountered:", err)
		return true
	}
	return false
}

// Load a specified file into the panels slice
func loadFile(string fileName, queue chan *stringOut) {
	file, err := os.Open(filename)
	if checkErr(err) {
		return
	}

	stringOut <- "END"

}

func load(string fileName) {
	log.Println("Loading", fileName)
	lines := make(chan string, 100)

	go loadFile(fileName, lines)

	for {
		line := <-lines
		if line != "END" {
			runeValue, width := utf8.DecodeRuneInString(line[0:])

		} else {
			break
		}
	}

}

func main() {
	fmt.Println("Go ASCII Service version", version)

	go load("sw1.txt")

	sock, err := net.Listen("tcp", "21")

	if checkErr(err) {
		return
	}

	for {

	}
}
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.
package parse

import (
	"bufio"
	"bytes"
	"fmt"
	"encoding/json"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"os"
	"strings"
	"testing"
)

type lexTest struct {
	name           string
	description    string
	data           string
	items          string
	expect         string
	collectedItems []item
}

type lexTests []lexTest

func (l lexTests) SearchByName(name string) *lexTest {
	for _, test := range l {
		if test.name == name {
			return &test
		}
	}
	return nil
}

var tests lexTests

var (
	tEOF = item{ElementType: itemEOF, Position: 0, Value: ""}
)

var spd = spew.ConfigState{Indent: "\t"}

func init() {
	log.SetLevel(log.LEVEL_DEBUG)
	log.SetTemplate("{{if .Date}}{{.Date}} {{end}}" +
		"{{if .Prefix}}{{.Prefix}} {{end}}" +
		"{{if .LogLabel}}{{.LogLabel}} {{end}}" +
		"{{if .FileName}}{{.FileName}}: {{end}}" +
		"{{if .FunctionName}}{{.FunctionName}}{{end}}" +
		"{{if .LineNumber}}#{{.LineNumber}}: {{end}}" +
		"{{if .Text}}{{.Text}}{{end}}")
	log.SetFlags(log.Lansi | log.LnoPrefix | log.LfunctionName |
		log.LlineNumber)
}

func parseTestData(t *testing.T, filepath string) ([]lexTest, error) {
	testData, err := os.Open(filepath)
	defer testData.Close()
	if err != nil {
		return nil, err
	}

	var lexTests []lexTest
	var curTest = new(lexTest)
	var buffer bytes.Buffer

	scanner := bufio.NewScanner(testData)

	for scanner.Scan() {
		switch scanner.Text() {
		case "#name":
			// buffer = bytes.NewBuffer(buffer.Bytes())
			// name starts a new section
			if buffer.Len() > 0 {
				// Apend the last section to the array and
				// reset
				curTest.expect = buffer.String()
				lexTests = append(lexTests, *curTest)
			}
			curTest = new(lexTest)
			buffer.Reset()
		case "#description":
			curTest.name = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#data":
			curTest.description = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#items":
			curTest.data = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#parse-expect":
			curTest.items = buffer.String()
			buffer.Reset()
		default:
			// Collect the text in between sections
			buffer.WriteString(fmt.Sprintln(scanner.Text()))
		}
	}

	if err := scanner.Err(); err != nil {
		t.Error(err)
	}

	if buffer.Len() > 0 {
		// Apend the last section to the array and
		curTest.expect = buffer.String()
		lexTests = append(lexTests, *curTest)
	}

	return lexTests, nil
}

// collect gathers the emitted items into a slice.
func collect(t *lexTest) (items []item) {
	l := lex(t.name, t.data)
	for {
		item := l.nextItem()
		items = append(items, item)
		if item.ElementType == itemEOF || item.ElementType == itemError {
			break
		}
	}
	return
}

func lexSectionTest(t *testing.T, testName string) []item {
	var err error
	if tests == nil {
		tests, err = parseTestData(t, "../testdata/test_lex_sections.dat")
		if err != nil {
			t.FailNow()
		}
	}
	test := tests.SearchByName(testName)
	if test != nil {
		log.Debugf("Test Name: \t%s\n", test.name)
		log.Debugf("Description: \t%s\n", test.description)
		log.Debugf("Test Input:\n-----------\n%s\n----------\n", test.data)
		items := collect(test)
		return items
	}
	return nil
}

// Unmarshals input into []items, the json input from test data does not include ElementType, so
// this is filled in manually. Returns error if there is a json parsing error.
func jsonToItems(input []byte) ([]item, error) {
	var exp []item
	err := json.Unmarshal(input, &exp)
	if err != nil {
		return nil, err
	}
	// Set the correct ElementType (int), this is not included in the json from the test data.
	for i, item := range exp {
		for j, elm := range elements {
			if item.ElementName == elm {
				exp[i].ElementType = itemElement(j)
			}
		}
	}
	return exp, nil
}

// Test equality between items and expected items from unmarshalled json data, field by field.
// Returns error in case of error during json unmarshalling, or mismatch between items and the
// expected output.
func equal(t *testing.T, items []item, testName string) []error {
	test := tests.SearchByName(testName)
	eItems, err := jsonToItems([]byte(test.items))
	if err != nil {
		t.Fatal("JSON error: ", err)
	}
	if len(items) != len(eItems) {
		t.Fatalf("Collected items is not the same length as eItems!\n" +
	                 "\nGot items (%d): -------------------------------\n\n%s\n" +
	                 "Expect items (%d): ------------------------------\n\n%s\n" +
	                 "-------------------------------------------------\n",
			 len(items), spd.Sdump(items), len(eItems), spd.Sdump(eItems))
	}
	for i, item := range items {
		if item.ElementType != eItems[i].ElementType {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\nLine:\t%d\nValue:\t%q\n\n" +
				 "Got ElementType:\t\t%s\nExpect ElementType:\t%s\n\n",
				 i, item.ElementName, item.Line, item.Value, item.ElementType,
				 eItems[i].ElementType)
		}
		if item.Line != eItems[i].Line {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\nValue:\t%q\n\n" +
			         "Got Line Number:\t%d\nExpect Line Number:\t%d\n\n",
				 i, item.ElementName, item.Value, item.Line, eItems[i].Line)
		}
		if item.Position != eItems[i].Position {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\nLine:\t%d\nValue:\t%q\n\n" +
				 "Got Position:\t\t%d\nExpect Position:\t%d\n\n",
				 i, item.ElementName, item.Line, item.Value, item.Position,
				 eItems[i].Position)
		}
		if item.Value != eItems[i].Value {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\n\n" +
			         "Got Value:\n\t%q\nExpect Value:\n\t%q\n\n",
				 i, item.ElementName, item.Value, eItems[i].Value)
		}
	}
	return nil
}

func TestSectionTitlePara(t *testing.T) {
	testName := "SectionTitlePara"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}

func TestSectionTitleParaNoBlankline(t *testing.T) {
	testName := "SectionTitleParaNoBlankline"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}

func TestSectionParaHeadPara(t *testing.T) {
	testName := "SectionParaHeadPara"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}

func TestSectionUnexpectedTitles(t *testing.T) {
	testName := "SectionUnexpectedTitles"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}
<commit_msg>lex_test.go: Disable debug output<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.
package parse

import (
	"bufio"
	"bytes"
	"fmt"
	"encoding/json"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"os"
	"strings"
	"testing"
)

type lexTest struct {
	name           string
	description    string
	data           string
	items          string
	expect         string
	collectedItems []item
}

type lexTests []lexTest

func (l lexTests) SearchByName(name string) *lexTest {
	for _, test := range l {
		if test.name == name {
			return &test
		}
	}
	return nil
}

var tests lexTests

var (
	tEOF = item{ElementType: itemEOF, Position: 0, Value: ""}
)

var spd = spew.ConfigState{Indent: "\t"}

func init() {
	// log.SetLevel(log.LEVEL_DEBUG)
	log.SetTemplate("{{if .Date}}{{.Date}} {{end}}" +
		"{{if .Prefix}}{{.Prefix}} {{end}}" +
		"{{if .LogLabel}}{{.LogLabel}} {{end}}" +
		"{{if .FileName}}{{.FileName}}: {{end}}" +
		"{{if .FunctionName}}{{.FunctionName}}{{end}}" +
		"{{if .LineNumber}}#{{.LineNumber}}: {{end}}" +
		"{{if .Text}}{{.Text}}{{end}}")
	log.SetFlags(log.Lansi | log.LnoPrefix | log.LfunctionName |
		log.LlineNumber)
}

func parseTestData(t *testing.T, filepath string) ([]lexTest, error) {
	testData, err := os.Open(filepath)
	defer testData.Close()
	if err != nil {
		return nil, err
	}

	var lexTests []lexTest
	var curTest = new(lexTest)
	var buffer bytes.Buffer

	scanner := bufio.NewScanner(testData)

	for scanner.Scan() {
		switch scanner.Text() {
		case "#name":
			// buffer = bytes.NewBuffer(buffer.Bytes())
			// name starts a new section
			if buffer.Len() > 0 {
				// Apend the last section to the array and
				// reset
				curTest.expect = buffer.String()
				lexTests = append(lexTests, *curTest)
			}
			curTest = new(lexTest)
			buffer.Reset()
		case "#description":
			curTest.name = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#data":
			curTest.description = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#items":
			curTest.data = strings.TrimRight(buffer.String(), "\n")
			buffer.Reset()
		case "#parse-expect":
			curTest.items = buffer.String()
			buffer.Reset()
		default:
			// Collect the text in between sections
			buffer.WriteString(fmt.Sprintln(scanner.Text()))
		}
	}

	if err := scanner.Err(); err != nil {
		t.Error(err)
	}

	if buffer.Len() > 0 {
		// Apend the last section to the array and
		curTest.expect = buffer.String()
		lexTests = append(lexTests, *curTest)
	}

	return lexTests, nil
}

// collect gathers the emitted items into a slice.
func collect(t *lexTest) (items []item) {
	l := lex(t.name, t.data)
	for {
		item := l.nextItem()
		items = append(items, item)
		if item.ElementType == itemEOF || item.ElementType == itemError {
			break
		}
	}
	return
}

func lexSectionTest(t *testing.T, testName string) []item {
	var err error
	if tests == nil {
		tests, err = parseTestData(t, "../testdata/test_lex_sections.dat")
		if err != nil {
			t.FailNow()
		}
	}
	test := tests.SearchByName(testName)
	if test != nil {
		log.Debugf("Test Name: \t%s\n", test.name)
		log.Debugf("Description: \t%s\n", test.description)
		log.Debugf("Test Input:\n-----------\n%s\n----------\n", test.data)
		items := collect(test)
		return items
	}
	return nil
}

// Unmarshals input into []items, the json input from test data does not include ElementType, so
// this is filled in manually. Returns error if there is a json parsing error.
func jsonToItems(input []byte) ([]item, error) {
	var exp []item
	err := json.Unmarshal(input, &exp)
	if err != nil {
		return nil, err
	}
	// Set the correct ElementType (int), this is not included in the json from the test data.
	for i, item := range exp {
		for j, elm := range elements {
			if item.ElementName == elm {
				exp[i].ElementType = itemElement(j)
			}
		}
	}
	return exp, nil
}

// Test equality between items and expected items from unmarshalled json data, field by field.
// Returns error in case of error during json unmarshalling, or mismatch between items and the
// expected output.
func equal(t *testing.T, items []item, testName string) []error {
	test := tests.SearchByName(testName)
	eItems, err := jsonToItems([]byte(test.items))
	if err != nil {
		t.Fatal("JSON error: ", err)
	}
	if len(items) != len(eItems) {
		t.Fatalf("Collected items is not the same length as eItems!\n" +
	                 "\nGot items (%d): -------------------------------\n\n%s\n" +
	                 "Expect items (%d): ------------------------------\n\n%s\n" +
	                 "-------------------------------------------------\n",
			 len(items), spd.Sdump(items), len(eItems), spd.Sdump(eItems))
	}
	for i, item := range items {
		if item.ElementType != eItems[i].ElementType {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\nLine:\t%d\nValue:\t%q\n\n" +
				 "Got ElementType:\t\t%s\nExpect ElementType:\t%s\n\n",
				 i, item.ElementName, item.Line, item.Value, item.ElementType,
				 eItems[i].ElementType)
		}
		if item.Line != eItems[i].Line {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\nValue:\t%q\n\n" +
			         "Got Line Number:\t%d\nExpect Line Number:\t%d\n\n",
				 i, item.ElementName, item.Value, item.Line, eItems[i].Line)
		}
		if item.Position != eItems[i].Position {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\nLine:\t%d\nValue:\t%q\n\n" +
				 "Got Position:\t\t%d\nExpect Position:\t%d\n\n",
				 i, item.ElementName, item.Line, item.Value, item.Position,
				 eItems[i].Position)
		}
		if item.Value != eItems[i].Value {
			t.Errorf("\n\nItem:\t%d\nElement Name:\t%s\n\n" +
			         "Got Value:\n\t%q\nExpect Value:\n\t%q\n\n",
				 i, item.ElementName, item.Value, eItems[i].Value)
		}
	}
	return nil
}

func TestSectionTitlePara(t *testing.T) {
	testName := "SectionTitlePara"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}

func TestSectionTitleParaNoBlankline(t *testing.T) {
	testName := "SectionTitleParaNoBlankline"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}

func TestSectionParaHeadPara(t *testing.T) {
	testName := "SectionParaHeadPara"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}

func TestSectionUnexpectedTitles(t *testing.T) {
	testName := "SectionUnexpectedTitles"
	items := lexSectionTest(t, testName)
	errors := equal(t, items, testName)
	if errors != nil {
		for err := range errors {
			t.Error(err)
		}
	}
}
<|endoftext|>


<commit_before>/*
Package pbf provides functions for parsing OSM PBF files.

The subpackage osmpbf contains the generated code for the OSM .proto files.
*/
package cache
<commit_msg>fixed package of pbf/doc.go<commit_after>/*
Package pbf provides functions for parsing OSM PBF files.

The subpackage osmpbf contains the generated code for the OSM .proto files.
*/
package pbf
<|endoftext|>