<commit_before>// +build integração

package testes

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"testing"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/docker/ctx"
	"github.com/docker/libcompose/project"
	"github.com/docker/libcompose/project/options"
	"github.com/rafaeljusto/atiradorfrequente/núcleo/protocolo"
	"github.com/rafaeljusto/atiradorfrequente/testes"
	"github.com/registrobr/gostk/errors"
)

var endereçoServidor string

func TestCriaçãoDeFrequência(t *testing.T) {
	cenários := []struct {
		descrição          string
		requisição         *http.Request
		códigoHTTPEsperado int
		cabeçalhoEsperado  func(corpo []byte) (http.Header, error)
		corpoEsperado      func(corpo []byte) ([]byte, error)
	}{
		{
			descrição: "deve criar corretamente uma frequência",
			requisição: func() *http.Request {
				frequênciaPedido := protocolo.FrequênciaPedido{
					Calibre:           "calibre .380",
					ArmaUtilizada:     "arma do clube",
					NúmeroSérie:       "za785671",
					GuiaDeTráfego:     762556223,
					QuantidadeMunição: 50,
					DataInício:        time.Now().Add(-30 * time.Minute),
					DataTérmino:       time.Now().Add(-10 * time.Minute),
				}

				corpo, err := json.Marshal(frequênciaPedido)
				if err != nil {
					t.Fatalf("Erro ao gerar os dados da requisição. Detalhes: %s", err)
				}

				url := fmt.Sprintf("http://%s/frequencia/380308", endereçoServidor)
				r, err := http.NewRequest("POST", url, bytes.NewReader(corpo))
				if err != nil {
					t.Fatalf("Erro ao gerar a requisição. Detalhes: %s", err)
				}

				return r
			}(),
			códigoHTTPEsperado: http.StatusCreated,
			cabeçalhoEsperado: func(corpo []byte) (http.Header, error) {
				var frequênciaPendenteResposta protocolo.FrequênciaPendenteResposta
				if err := json.Unmarshal(corpo, &frequênciaPendenteResposta); err != nil {
					return nil, errors.Errorf("Erro ao interpretar o corpo da resposta. Detalhes: %s", err)
				}

				return http.Header{
					"Content-Type": []string{"application/json; charset=utf-8"},
					"Location":     []string{"/frequencia/380308/" + frequênciaPendenteResposta.NúmeroControle.String()},
				}, nil
			},
			corpoEsperado: func(corpo []byte) ([]byte, error) {
				var frequênciaPendenteResposta protocolo.FrequênciaPendenteResposta
				if err := json.Unmarshal(corpo, &frequênciaPendenteResposta); err != nil {
					return nil, errors.Errorf("Erro ao interpretar o corpo da resposta. Detalhes: %s", err)
				}

				corpoEsperado, err := json.Marshal(frequênciaPendenteResposta)
				if err != nil {
					return nil, errors.Errorf("Erro ao gerar os dados da resposta. Detalhes: %s", err)
				}

				return bytes.TrimSpace(corpoEsperado), nil
			},
		},
		{
			descrição: "deve detectar quando campos obrigatórios não foram preenchidos",
			requisição: func() *http.Request {
				url := fmt.Sprintf("http://%s/frequencia/380308", endereçoServidor)
				r, err := http.NewRequest("POST", url, nil)
				if err != nil {
					t.Fatalf("Erro ao gerar a requisição. Detalhes: %s", err)
				}

				return r
			}(),
			códigoHTTPEsperado: http.StatusBadRequest,
			cabeçalhoEsperado: func(corpo []byte) (http.Header, error) {
				return http.Header{
					"Content-Type": []string{"application/json; charset=utf-8"},
				}, nil
			},
			corpoEsperado: func(corpo []byte) ([]byte, error) {
				mensagens := protocolo.NovasMensagens(
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoCampoNãoPreenchido, "calibre", ""),
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoCampoNãoPreenchido, "armaUtilizada", ""),
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoCampoNãoPreenchido, "quantidadeMunicao", "0"),
				)

				corpoEsperado, err := json.Marshal(mensagens)
				if err != nil {
					return nil, errors.Errorf("Erro ao gerar os dados da resposta. Detalhes: %s", err)
				}

				return bytes.TrimSpace(corpoEsperado), nil
			},
		},
	}

	for _, cenário := range cenários {
		t.Run(cenário.descrição, func(t *testing.T) {
			var cliente http.Client

			resposta, err := cliente.Do(cenário.requisição)
			if err != nil {
				t.Fatalf("Erro inesperado ao enviar a requisição. Detalhes: %s", err)
			}
			defer resposta.Body.Close()

			corpo, err := ioutil.ReadAll(resposta.Body)
			if err != nil {
				t.Fatalf("Erro inesperado ao ler o corpo da resposta. Detalhes: %s", err)
			}

			var verificadorResultado testes.VerificadorResultados

			verificadorResultado.DefinirEsperado(cenário.códigoHTTPEsperado, nil)
			if err = verificadorResultado.VerificaResultado(resposta.StatusCode, nil); err != nil {
				t.Error(err)
			}

			if cenário.cabeçalhoEsperado != nil {
				cabeçalhoEsperado, err := cenário.cabeçalhoEsperado(corpo)
				if err != nil {
					t.Fatal(err)
				}

				// copia campos variáveis da resposta definitiva para não causar
				// problemas. Infelizmente não temos como prever os valores destes
				// campos na resposta esperada.

				if data := resposta.Header.Get("Date"); data != "" {
					cabeçalhoEsperado.Set("Date", data)
				}
				if tamanhoConteúdo := resposta.Header.Get("Content-Length"); tamanhoConteúdo != "" {
					cabeçalhoEsperado.Set("Content-Length", tamanhoConteúdo)
				}

				verificadorResultado.DefinirEsperado(cabeçalhoEsperado, nil)
				if err = verificadorResultado.VerificaResultado(resposta.Header, nil); err != nil {
					t.Error(err)
				}
			}

			if cenário.corpoEsperado != nil {
				corpoEsperado, err := cenário.corpoEsperado(corpo)
				if err != nil {
					t.Fatal(err)
				}

				if corpoEsperado == nil && corpo != nil {
					t.Errorf("Corpo inesperado na resposta.\n%s", string(corpo))

				} else if corpoEsperado != nil && corpo == nil {
					t.Error("Corpo inexistente na resposta")

				} else {
					corpo = bytes.TrimSpace(corpo)
					verificadorResultado.DefinirEsperado(string(corpoEsperado), nil)
					if err = verificadorResultado.VerificaResultado(string(corpo), nil); err != nil {
						t.Error(err)
					}
				}
			}
		})
	}
}

func TestMain(m *testing.M) {
	flag.Parse()

	código := 0
	defer func() {
		os.Exit(código)
	}()

	// descarta os logs da biblioteca de containers
	logrus.SetOutput(ioutil.Discard)

	projeto, err := docker.NewProject(&ctx.Context{
		Context: project.Context{
			ComposeFiles: []string{"docker-compose.yml"},
			ProjectName:  "atiradorfrequente",
		},
	}, nil)

	if err != nil {
		fmt.Printf("Erro ao inicializar o projeto para testes. Detalhes: %s\n", err)
		código = 1
		return
	}

	defer func() {
		err = projeto.Down(context.Background(), options.Down{
			RemoveVolume:  true,
			RemoveImages:  options.ImageType("all"),
			RemoveOrphans: true,
		})

		if err != nil {
			fmt.Printf("Erro ao finalizar o projeto de testes. Detalhes: %s\n", err)
		}
	}()

	err = projeto.Up(context.Background(), options.Up{
		Create: options.Create{
			ForceRecreate: true,
			ForceBuild:    true,
		},
	})

	if err != nil {
		fmt.Printf("Erro ao executar o projeto para testes. Detalhes: %s\n", err)
		código = 2
		return
	}

	abortarInício := make(chan bool)
	servidorRodando := make(chan bool)

	go func() {
		for {
			select {
			case <-time.Tick(100 * time.Millisecond):
				break
			case <-abortarInício:
				return
			}

			if endereçoServidor == "" {
				endereçoServidor, err = projeto.Port(context.Background(), 1, "tcp", "restaf", "80")
				if err != nil || endereçoServidor == " " {
					continue
				}
			}

			url := fmt.Sprintf("http://%s/ping", endereçoServidor)
			if resposta, err := http.Get(url); err != nil || resposta.StatusCode != http.StatusNoContent {
				continue
			}

			close(servidorRodando)
			return
		}
	}()

	select {
	case <-servidorRodando:
		código = m.Run()

	case <-time.Tick(20 * time.Second):
		close(abortarInício)
		fmt.Println("Tempo esgotado aguardando o servidor iniciar")
		código = 3
	}
}
<commit_msg>Aumenta a cobertura do teste de integração<commit_after>// +build integração

package testes

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"testing"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/docker/ctx"
	"github.com/docker/libcompose/project"
	"github.com/docker/libcompose/project/options"
	"github.com/rafaeljusto/atiradorfrequente/núcleo/protocolo"
	"github.com/rafaeljusto/atiradorfrequente/testes"
	"github.com/registrobr/gostk/errors"
)

var endereçoServidor string

func TestCriaçãoDeFrequência(t *testing.T) {
	cenários := []struct {
		descrição          string
		requisição         *http.Request
		códigoHTTPEsperado int
		cabeçalhoEsperado  func(corpo []byte) (http.Header, error)
		corpoEsperado      func(corpo []byte) ([]byte, error)
	}{
		{
			descrição: "deve criar corretamente uma frequência",
			requisição: func() *http.Request {
				frequênciaPedido := protocolo.FrequênciaPedido{
					Calibre:           "calibre .380",
					ArmaUtilizada:     "arma do clube",
					NúmeroSérie:       "za785671",
					GuiaDeTráfego:     762556223,
					QuantidadeMunição: 50,
					DataInício:        time.Now().Add(-30 * time.Minute),
					DataTérmino:       time.Now().Add(-10 * time.Minute),
				}

				corpo, err := json.Marshal(frequênciaPedido)
				if err != nil {
					t.Fatalf("Erro ao gerar os dados da requisição. Detalhes: %s", err)
				}

				url := fmt.Sprintf("http://%s/frequencia/380308", endereçoServidor)
				r, err := http.NewRequest("POST", url, bytes.NewReader(corpo))
				if err != nil {
					t.Fatalf("Erro ao gerar a requisição. Detalhes: %s", err)
				}

				return r
			}(),
			códigoHTTPEsperado: http.StatusCreated,
			cabeçalhoEsperado: func(corpo []byte) (http.Header, error) {
				var frequênciaPendenteResposta protocolo.FrequênciaPendenteResposta
				if err := json.Unmarshal(corpo, &frequênciaPendenteResposta); err != nil {
					return nil, errors.Errorf("Erro ao interpretar o corpo da resposta. Detalhes: %s", err)
				}

				return http.Header{
					"Content-Type": []string{"application/json; charset=utf-8"},
					"Location":     []string{"/frequencia/380308/" + frequênciaPendenteResposta.NúmeroControle.String()},
				}, nil
			},
			corpoEsperado: func(corpo []byte) ([]byte, error) {
				var frequênciaPendenteResposta protocolo.FrequênciaPendenteResposta
				if err := json.Unmarshal(corpo, &frequênciaPendenteResposta); err != nil {
					return nil, errors.Errorf("Erro ao interpretar o corpo da resposta. Detalhes: %s", err)
				}

				corpoEsperado, err := json.Marshal(frequênciaPendenteResposta)
				if err != nil {
					return nil, errors.Errorf("Erro ao gerar os dados da resposta. Detalhes: %s", err)
				}

				return bytes.TrimSpace(corpoEsperado), nil
			},
		},
		{
			descrição: "deve detectar quando campos obrigatórios não foram preenchidos",
			requisição: func() *http.Request {
				url := fmt.Sprintf("http://%s/frequencia/380308", endereçoServidor)
				r, err := http.NewRequest("POST", url, nil)
				if err != nil {
					t.Fatalf("Erro ao gerar a requisição. Detalhes: %s", err)
				}

				return r
			}(),
			códigoHTTPEsperado: http.StatusBadRequest,
			cabeçalhoEsperado: func(corpo []byte) (http.Header, error) {
				return http.Header{
					"Content-Type": []string{"application/json; charset=utf-8"},
				}, nil
			},
			corpoEsperado: func(corpo []byte) ([]byte, error) {
				mensagens := protocolo.NovasMensagens(
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoCampoNãoPreenchido, "calibre", ""),
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoCampoNãoPreenchido, "armaUtilizada", ""),
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoCampoNãoPreenchido, "quantidadeMunicao", "0"),
				)

				corpoEsperado, err := json.Marshal(mensagens)
				if err != nil {
					return nil, errors.Errorf("Erro ao gerar os dados da resposta. Detalhes: %s", err)
				}

				return bytes.TrimSpace(corpoEsperado), nil
			},
		},
		{
			descrição: "deve detectar campos com dados inválidos",
			requisição: func() *http.Request {
				frequênciaPedido := protocolo.FrequênciaPedido{
					Calibre:           "calibre .380",
					ArmaUtilizada:     "arma do clube",
					NúmeroSérie:       "785671", // formato inválido
					GuiaDeTráfego:     762556223,
					QuantidadeMunição: 50,
					DataInício:        time.Now().Add(-30 * time.Minute),
					DataTérmino:       time.Now().Add(-40 * time.Minute), // término antes do inicio
				}

				corpo, err := json.Marshal(frequênciaPedido)
				if err != nil {
					t.Fatalf("Erro ao gerar os dados da requisição. Detalhes: %s", err)
				}

				url := fmt.Sprintf("http://%s/frequencia/380308", endereçoServidor)
				r, err := http.NewRequest("POST", url, bytes.NewReader(corpo))
				if err != nil {
					t.Fatalf("Erro ao gerar a requisição. Detalhes: %s", err)
				}

				return r
			}(),
			códigoHTTPEsperado: http.StatusBadRequest,
			cabeçalhoEsperado: func(corpo []byte) (http.Header, error) {
				return http.Header{
					"Content-Type": []string{"application/json; charset=utf-8"},
				}, nil
			},
			corpoEsperado: func(corpo []byte) ([]byte, error) {
				mensagens := protocolo.NovasMensagens(
					protocolo.NovaMensagemComCampo(protocolo.MensagemCódigoNúmeroSérieInválido, "", "785671"),
					protocolo.NovaMensagem(protocolo.MensagemCódigoDatasPeríodoIncorreto),
				)

				corpoEsperado, err := json.Marshal(mensagens)
				if err != nil {
					return nil, errors.Errorf("Erro ao gerar os dados da resposta. Detalhes: %s", err)
				}

				return bytes.TrimSpace(corpoEsperado), nil
			},
		},
	}

	for _, cenário := range cenários {
		t.Run(cenário.descrição, func(t *testing.T) {
			var cliente http.Client

			resposta, err := cliente.Do(cenário.requisição)
			if err != nil {
				t.Fatalf("Erro inesperado ao enviar a requisição. Detalhes: %s", err)
			}
			defer resposta.Body.Close()

			corpo, err := ioutil.ReadAll(resposta.Body)
			if err != nil {
				t.Fatalf("Erro inesperado ao ler o corpo da resposta. Detalhes: %s", err)
			}

			var verificadorResultado testes.VerificadorResultados

			verificadorResultado.DefinirEsperado(cenário.códigoHTTPEsperado, nil)
			if err = verificadorResultado.VerificaResultado(resposta.StatusCode, nil); err != nil {
				t.Error(err)
			}

			if cenário.cabeçalhoEsperado != nil {
				cabeçalhoEsperado, err := cenário.cabeçalhoEsperado(corpo)
				if err != nil {
					t.Fatal(err)
				}

				// copia campos variáveis da resposta definitiva para não causar
				// problemas. Infelizmente não temos como prever os valores destes
				// campos na resposta esperada.

				if data := resposta.Header.Get("Date"); data != "" {
					cabeçalhoEsperado.Set("Date", data)
				}
				if tamanhoConteúdo := resposta.Header.Get("Content-Length"); tamanhoConteúdo != "" {
					cabeçalhoEsperado.Set("Content-Length", tamanhoConteúdo)
				}

				verificadorResultado.DefinirEsperado(cabeçalhoEsperado, nil)
				if err = verificadorResultado.VerificaResultado(resposta.Header, nil); err != nil {
					t.Error(err)
				}
			}

			if cenário.corpoEsperado != nil {
				corpoEsperado, err := cenário.corpoEsperado(corpo)
				if err != nil {
					t.Fatal(err)
				}
				corpo = bytes.TrimSpace(corpo)

				if corpoEsperado == nil && corpo != nil {
					t.Errorf("Corpo inesperado na resposta.\n%s", string(corpo))

				} else if corpoEsperado != nil && corpo == nil {
					t.Error("Corpo inexistente na resposta")

				} else {
					verificadorResultado.DefinirEsperado(string(corpoEsperado), nil)
					if err = verificadorResultado.VerificaResultado(string(corpo), nil); err != nil {
						t.Error(err)
					}
				}
			}
		})
	}
}

func TestCriaçãoFrequênciaConfirmação(t *testing.T) {
	cenários := []struct {
		descrição          string
		requisição         *http.Request
		códigoHTTPEsperado int
		cabeçalhoEsperado  func(corpo []byte) (http.Header, error)
		corpoEsperado      func(corpo []byte) ([]byte, error)
	}{
		{
			descrição: "deve confirmar corretamente uma frequência",
			requisição: func() *http.Request {
				frequênciaConfirmaçãoPedido := protocolo.FrequênciaConfirmaçãoPedido{
					Imagem: "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAATElEQVR4XpWPCwoAIAhDswPrWTyxMcKEBn2EwYPG0yQi2st0gJllO5kHRlUNBIwsrkzjbnN3AdPqc5lXV/gMNqYt7cn9Vvr+NT0k7xkVBY1RndW3lwAAAABJRU5ErkJggg==",
				}

				corpo, err := json.Marshal(frequênciaConfirmaçãoPedido)
				if err != nil {
					t.Fatalf("Erro ao gerar os dados da requisição. Detalhes: %s", err)
				}

				url := fmt.Sprintf("http://%s/frequencia/380308/1-1234", endereçoServidor)
				r, err := http.NewRequest("PUT", url, bytes.NewReader(corpo))
				if err != nil {
					t.Fatalf("Erro ao gerar a requisição. Detalhes: %s", err)
				}

				return r
			}(),
			códigoHTTPEsperado: http.StatusNoContent,
			cabeçalhoEsperado: func(corpo []byte) (http.Header, error) {
				return make(http.Header), nil
			},
			corpoEsperado: func(corpo []byte) ([]byte, error) {
				return nil, nil
			},
		},
	}

	for _, cenário := range cenários {
		t.Run(cenário.descrição, func(t *testing.T) {
			var cliente http.Client

			resposta, err := cliente.Do(cenário.requisição)
			if err != nil {
				t.Fatalf("Erro inesperado ao enviar a requisição. Detalhes: %s", err)
			}
			defer resposta.Body.Close()

			corpo, err := ioutil.ReadAll(resposta.Body)
			if err != nil {
				t.Fatalf("Erro inesperado ao ler o corpo da resposta. Detalhes: %s", err)
			}

			var verificadorResultado testes.VerificadorResultados

			verificadorResultado.DefinirEsperado(cenário.códigoHTTPEsperado, nil)
			if err = verificadorResultado.VerificaResultado(resposta.StatusCode, nil); err != nil {
				t.Error(err)
			}

			if cenário.cabeçalhoEsperado != nil {
				cabeçalhoEsperado, err := cenário.cabeçalhoEsperado(corpo)
				if err != nil {
					t.Fatal(err)
				}

				// copia campos variáveis da resposta definitiva para não causar
				// problemas. Infelizmente não temos como prever os valores destes
				// campos na resposta esperada.

				if data := resposta.Header.Get("Date"); data != "" {
					cabeçalhoEsperado.Set("Date", data)
				}
				if tamanhoConteúdo := resposta.Header.Get("Content-Length"); tamanhoConteúdo != "" {
					cabeçalhoEsperado.Set("Content-Length", tamanhoConteúdo)
				}

				verificadorResultado.DefinirEsperado(cabeçalhoEsperado, nil)
				if err = verificadorResultado.VerificaResultado(resposta.Header, nil); err != nil {
					t.Error(err)
				}
			}

			if cenário.corpoEsperado != nil {
				corpoEsperado, err := cenário.corpoEsperado(corpo)
				if err != nil {
					t.Fatal(err)
				}
				corpo = bytes.TrimSpace(corpo)

				if corpoEsperado == nil && corpo != nil {
					t.Errorf("Corpo inesperado na resposta.\n%s", string(corpo))

				} else if corpoEsperado != nil && corpo == nil {
					t.Error("Corpo inexistente na resposta")

				} else {
					verificadorResultado.DefinirEsperado(string(corpoEsperado), nil)
					if err = verificadorResultado.VerificaResultado(string(corpo), nil); err != nil {
						t.Error(err)
					}
				}
			}
		})
	}
}

func TestMain(m *testing.M) {
	flag.Parse()

	código := 0
	defer func() {
		os.Exit(código)
	}()

	// descarta os logs da biblioteca de containers
	logrus.SetOutput(ioutil.Discard)

	projeto, err := docker.NewProject(&ctx.Context{
		Context: project.Context{
			ComposeFiles: []string{"docker-compose.yml"},
			ProjectName:  "atiradorfrequente",
		},
	}, nil)

	if err != nil {
		fmt.Printf("Erro ao inicializar o projeto para testes. Detalhes: %s\n", err)
		código = 1
		return
	}

	defer func() {
		err = projeto.Down(context.Background(), options.Down{
			RemoveVolume:  true,
			RemoveImages:  options.ImageType("all"),
			RemoveOrphans: true,
		})

		if err != nil {
			fmt.Printf("Erro ao finalizar o projeto de testes. Detalhes: %s\n", err)
		}
	}()

	err = projeto.Up(context.Background(), options.Up{
		Create: options.Create{
			ForceRecreate: true,
			ForceBuild:    true,
		},
	})

	if err != nil {
		fmt.Printf("Erro ao executar o projeto para testes. Detalhes: %s\n", err)
		código = 2
		return
	}

	abortarInício := make(chan bool)
	servidorRodando := make(chan bool)

	go func() {
		for {
			select {
			case <-time.Tick(100 * time.Millisecond):
				break
			case <-abortarInício:
				return
			}

			if endereçoServidor == "" {
				endereçoServidor, err = projeto.Port(context.Background(), 1, "tcp", "restaf", "80")
				if err != nil || endereçoServidor == " " {
					continue
				}
			}

			url := fmt.Sprintf("http://%s/ping", endereçoServidor)
			if resposta, err := http.Get(url); err != nil || resposta.StatusCode != http.StatusNoContent {
				continue
			}

			close(servidorRodando)
			return
		}
	}()

	select {
	case <-servidorRodando:
		código = m.Run()

	case <-time.Tick(20 * time.Second):
		close(abortarInício)
		fmt.Println("Tempo esgotado aguardando o servidor iniciar")
		código = 3
	}
}
<|endoftext|>


<commit_before>package cephfs

import (
	"io"
	"os"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestFileOpen(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileOpen.txt"

	// idempotent open for read and write
	t.Run("create", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NotNil(t, f1)
		err = f1.Close()
		assert.NoError(t, err)
		assert.NoError(t, mount.Unlink(fname))
	})

	t.Run("errorMissing", func(t *testing.T) {
		// try to open a file we know should not exist
		f2, err := mount.Open(".nope", os.O_RDONLY, 0666)
		assert.Error(t, err)
		assert.Nil(t, f2)
	})

	t.Run("existsInMount", func(t *testing.T) {
		useMount(t)

		f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NotNil(t, f1)
		err = f1.Close()
		assert.NoError(t, err)
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		s, err := os.Stat(path.Join(CephMountDir, fname))
		assert.NoError(t, err)
		assert.EqualValues(t, 0, s.Size())
	})

	t.Run("idempotentClose", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NotNil(t, f1)
		assert.NoError(t, f1.Close())
		assert.NoError(t, f1.Close()) // call close again. it should not fail
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()
	})

	t.Run("uninitializedFileClose", func(t *testing.T) {
		f := &File{}
		err := f.Close()
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})

	t.Run("invalidFdClose", func(t *testing.T) {
		f := &File{mount, 1980}
		err := f.Close()
		assert.Error(t, err)
	})

	t.Run("openInvalidMount", func(t *testing.T) {
		m := &MountInfo{}
		_, err := m.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.Error(t, err)
	})
}

func TestFileReadWrite(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileReadWrite.txt"

	t.Run("writeAndRead", func(t *testing.T) {
		// idempotent open for read and write
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		n, err := f1.Write([]byte("yello world!"))
		assert.NoError(t, err)
		assert.EqualValues(t, 12, n)
		err = f1.Close()
		assert.NoError(t, err)
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		buf := make([]byte, 1024)
		f2, err := mount.Open(fname, os.O_RDONLY, 0)
		n, err = f2.Read(buf)
		assert.NoError(t, err)
		assert.EqualValues(t, 12, n)
		assert.Equal(t, "yello world!", string(buf[:n]))
	})

	t.Run("openForWriteOnly", func(t *testing.T) {
		buf := make([]byte, 32)
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.Read(buf)
		assert.Error(t, err)
	})

	t.Run("openForReadOnly", func(t *testing.T) {
		// "touch" the file
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NoError(t, f1.Close())

		f1, err = mount.Open(fname, os.O_RDONLY, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.Write([]byte("yo"))
		assert.Error(t, err)
	})

	t.Run("uninitializedFile", func(t *testing.T) {
		f := &File{}
		b := []byte("testme")
		_, err := f.Write(b)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
		_, err = f.Read(b)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})
}

func TestFileReadWriteAt(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileReadWriteAt.txt"

	t.Run("writeAtAndReadAt", func(t *testing.T) {
		// idempotent open for read and write
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		n, err := f1.WriteAt([]byte("foo"), 0)
		assert.NoError(t, err)
		assert.EqualValues(t, 3, n)
		n, err = f1.WriteAt([]byte("bar"), 6)
		assert.NoError(t, err)
		assert.EqualValues(t, 3, n)
		err = f1.Close()
		assert.NoError(t, err)
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		buf := make([]byte, 4)
		f2, err := mount.Open(fname, os.O_RDONLY, 0)
		n, err = f2.ReadAt(buf, 0)
		assert.NoError(t, err)
		assert.EqualValues(t, 4, n)
		assert.Equal(t, "foo", string(buf[:3]))
		assert.EqualValues(t, 0, string(buf[3]))
		n, err = f2.ReadAt(buf, 6)
		assert.NoError(t, err)
		assert.EqualValues(t, 3, n)
		assert.Equal(t, "bar", string(buf[:3]))
	})

	t.Run("openForWriteOnly", func(t *testing.T) {
		buf := make([]byte, 32)
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.ReadAt(buf, 0)
		assert.Error(t, err)
	})

	t.Run("openForReadOnly", func(t *testing.T) {
		// "touch" the file
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NoError(t, f1.Close())

		f1, err = mount.Open(fname, os.O_RDONLY, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.WriteAt([]byte("yo"), 0)
		assert.Error(t, err)
	})

	t.Run("uninitializedFile", func(t *testing.T) {
		f := &File{}
		b := []byte("testme")
		_, err := f.WriteAt(b, 0)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
		_, err = f.ReadAt(b, 0)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})
}

func TestFileInterfaces(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileInterfaces.txt"

	t.Run("ioWriter", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		var w io.Writer = f1
		_, err = w.Write([]byte("foo"))
		assert.NoError(t, err)
	})

	t.Run("ioReader", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		_, err = f1.Write([]byte("foo"))
		assert.NoError(t, err)
		assert.NoError(t, f1.Close())

		f1, err = mount.Open(fname, os.O_RDONLY, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		var r io.Reader = f1
		buf := make([]byte, 32)
		_, err = r.Read(buf)
		assert.NoError(t, err)
		n, err := r.Read(buf)
		assert.Equal(t, 0, n)
		assert.Equal(t, io.EOF, err)
	})
}

func TestFileSeek(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileSeek.txt"

	t.Run("validSeek", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		o, err := f1.Seek(8, SeekSet)
		assert.NoError(t, err)
		assert.EqualValues(t, 8, o)

		n, err := f1.Write([]byte("flimflam"))
		assert.NoError(t, err)
		assert.EqualValues(t, 8, n)
	})

	t.Run("invalidWhence", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		o, err := f1.Seek(8, 1776)
		assert.Error(t, err)
		assert.EqualValues(t, 0, o)
	})

	t.Run("invalidSeek", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		o, err := f1.Seek(-22, SeekSet)
		assert.Error(t, err)
		assert.EqualValues(t, 0, o)
	})

	t.Run("uninitializedFile", func(t *testing.T) {
		f := &File{}
		_, err := f.Seek(0, SeekSet)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})
}
<commit_msg>cephfs: add a test to ensure behavior of mixed use of Read + ReadAt<commit_after>package cephfs

import (
	"io"
	"os"
	"path"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestFileOpen(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileOpen.txt"

	// idempotent open for read and write
	t.Run("create", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NotNil(t, f1)
		err = f1.Close()
		assert.NoError(t, err)
		assert.NoError(t, mount.Unlink(fname))
	})

	t.Run("errorMissing", func(t *testing.T) {
		// try to open a file we know should not exist
		f2, err := mount.Open(".nope", os.O_RDONLY, 0666)
		assert.Error(t, err)
		assert.Nil(t, f2)
	})

	t.Run("existsInMount", func(t *testing.T) {
		useMount(t)

		f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NotNil(t, f1)
		err = f1.Close()
		assert.NoError(t, err)
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		s, err := os.Stat(path.Join(CephMountDir, fname))
		assert.NoError(t, err)
		assert.EqualValues(t, 0, s.Size())
	})

	t.Run("idempotentClose", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NotNil(t, f1)
		assert.NoError(t, f1.Close())
		assert.NoError(t, f1.Close()) // call close again. it should not fail
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()
	})

	t.Run("uninitializedFileClose", func(t *testing.T) {
		f := &File{}
		err := f.Close()
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})

	t.Run("invalidFdClose", func(t *testing.T) {
		f := &File{mount, 1980}
		err := f.Close()
		assert.Error(t, err)
	})

	t.Run("openInvalidMount", func(t *testing.T) {
		m := &MountInfo{}
		_, err := m.Open(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
		assert.Error(t, err)
	})
}

func TestFileReadWrite(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileReadWrite.txt"

	t.Run("writeAndRead", func(t *testing.T) {
		// idempotent open for read and write
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		n, err := f1.Write([]byte("yello world!"))
		assert.NoError(t, err)
		assert.EqualValues(t, 12, n)
		err = f1.Close()
		assert.NoError(t, err)
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		buf := make([]byte, 1024)
		f2, err := mount.Open(fname, os.O_RDONLY, 0)
		n, err = f2.Read(buf)
		assert.NoError(t, err)
		assert.EqualValues(t, 12, n)
		assert.Equal(t, "yello world!", string(buf[:n]))
	})

	t.Run("openForWriteOnly", func(t *testing.T) {
		buf := make([]byte, 32)
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.Read(buf)
		assert.Error(t, err)
	})

	t.Run("openForReadOnly", func(t *testing.T) {
		// "touch" the file
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NoError(t, f1.Close())

		f1, err = mount.Open(fname, os.O_RDONLY, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.Write([]byte("yo"))
		assert.Error(t, err)
	})

	t.Run("uninitializedFile", func(t *testing.T) {
		f := &File{}
		b := []byte("testme")
		_, err := f.Write(b)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
		_, err = f.Read(b)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})
}

func TestFileReadWriteAt(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileReadWriteAt.txt"

	t.Run("writeAtAndReadAt", func(t *testing.T) {
		// idempotent open for read and write
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		n, err := f1.WriteAt([]byte("foo"), 0)
		assert.NoError(t, err)
		assert.EqualValues(t, 3, n)
		n, err = f1.WriteAt([]byte("bar"), 6)
		assert.NoError(t, err)
		assert.EqualValues(t, 3, n)
		err = f1.Close()
		assert.NoError(t, err)
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		buf := make([]byte, 4)
		f2, err := mount.Open(fname, os.O_RDONLY, 0)
		n, err = f2.ReadAt(buf, 0)
		assert.NoError(t, err)
		assert.EqualValues(t, 4, n)
		assert.Equal(t, "foo", string(buf[:3]))
		assert.EqualValues(t, 0, string(buf[3]))
		n, err = f2.ReadAt(buf, 6)
		assert.NoError(t, err)
		assert.EqualValues(t, 3, n)
		assert.Equal(t, "bar", string(buf[:3]))
	})

	t.Run("openForWriteOnly", func(t *testing.T) {
		buf := make([]byte, 32)
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.ReadAt(buf, 0)
		assert.Error(t, err)
	})

	t.Run("openForReadOnly", func(t *testing.T) {
		// "touch" the file
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		assert.NoError(t, f1.Close())

		f1, err = mount.Open(fname, os.O_RDONLY, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		_, err = f1.WriteAt([]byte("yo"), 0)
		assert.Error(t, err)
	})

	t.Run("uninitializedFile", func(t *testing.T) {
		f := &File{}
		b := []byte("testme")
		_, err := f.WriteAt(b, 0)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
		_, err = f.ReadAt(b, 0)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})
}

func TestFileInterfaces(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileInterfaces.txt"

	t.Run("ioWriter", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		var w io.Writer = f1
		_, err = w.Write([]byte("foo"))
		assert.NoError(t, err)
	})

	t.Run("ioReader", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		_, err = f1.Write([]byte("foo"))
		assert.NoError(t, err)
		assert.NoError(t, f1.Close())

		f1, err = mount.Open(fname, os.O_RDONLY, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		var r io.Reader = f1
		buf := make([]byte, 32)
		_, err = r.Read(buf)
		assert.NoError(t, err)
		n, err := r.Read(buf)
		assert.Equal(t, 0, n)
		assert.Equal(t, io.EOF, err)
	})
}

func TestFileSeek(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestFileSeek.txt"

	t.Run("validSeek", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		o, err := f1.Seek(8, SeekSet)
		assert.NoError(t, err)
		assert.EqualValues(t, 8, o)

		n, err := f1.Write([]byte("flimflam"))
		assert.NoError(t, err)
		assert.EqualValues(t, 8, n)
	})

	t.Run("invalidWhence", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		o, err := f1.Seek(8, 1776)
		assert.Error(t, err)
		assert.EqualValues(t, 0, o)
	})

	t.Run("invalidSeek", func(t *testing.T) {
		f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
		assert.NoError(t, err)
		defer func() { assert.NoError(t, f1.Close()) }()
		defer func() { assert.NoError(t, mount.Unlink(fname)) }()

		o, err := f1.Seek(-22, SeekSet)
		assert.Error(t, err)
		assert.EqualValues(t, 0, o)
	})

	t.Run("uninitializedFile", func(t *testing.T) {
		f := &File{}
		_, err := f.Seek(0, SeekSet)
		assert.Error(t, err)
		assert.Equal(t, ErrNotConnected, err)
	})
}

func TestMixedReadReadAt(t *testing.T) {
	mount := fsConnect(t)
	defer fsDisconnect(t, mount)
	fname := "TestMixedReadReadAt.txt"

	f1, err := mount.Open(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	assert.NoError(t, err)
	_, err = f1.Write([]byte("abc def ghi wow!"))
	assert.NoError(t, err)
	assert.NoError(t, f1.Close())
	defer func() { assert.NoError(t, mount.Unlink(fname)) }()

	buf := make([]byte, 4)
	f2, err := mount.Open(fname, os.O_RDONLY, 0)
	n, err := f2.ReadAt(buf, 0)
	assert.NoError(t, err)
	assert.Equal(t, 4, n)
	assert.Equal(t, "abc ", string(buf))

	n, err = f2.Read(buf)
	assert.NoError(t, err)
	assert.Equal(t, 4, n)
	assert.Equal(t, "abc ", string(buf))

	n, err = f2.Read(buf)
	assert.NoError(t, err)
	assert.Equal(t, 4, n)
	assert.Equal(t, "def ", string(buf))

	n, err = f2.ReadAt(buf, 0)
	assert.NoError(t, err)
	assert.Equal(t, 4, n)
	assert.Equal(t, "abc ", string(buf))

	n, err = f2.ReadAt(buf, 12)
	assert.NoError(t, err)
	assert.Equal(t, 4, n)
	assert.Equal(t, "wow!", string(buf))

	n, err = f2.Read(buf)
	assert.NoError(t, err)
	assert.Equal(t, 4, n)
	assert.Equal(t, "ghi ", string(buf))

	assert.NoError(t, f1.Close())
}
<|endoftext|>


<commit_before>package pgx

import (
	"bytes"
	"database/sql/driver"
	"fmt"
	"reflect"

	"github.com/jackc/pgx/pgtype"
)

// PostgreSQL oids for common types
const (
	BoolOid             = 16
	ByteaOid            = 17
	CharOid             = 18
	NameOid             = 19
	Int8Oid             = 20
	Int2Oid             = 21
	Int4Oid             = 23
	TextOid             = 25
	OidOid              = 26
	TidOid              = 27
	XidOid              = 28
	CidOid              = 29
	JsonOid             = 114
	CidrOid             = 650
	CidrArrayOid        = 651
	Float4Oid           = 700
	Float8Oid           = 701
	UnknownOid          = 705
	InetOid             = 869
	BoolArrayOid        = 1000
	Int2ArrayOid        = 1005
	Int4ArrayOid        = 1007
	TextArrayOid        = 1009
	ByteaArrayOid       = 1001
	VarcharArrayOid     = 1015
	Int8ArrayOid        = 1016
	Float4ArrayOid      = 1021
	Float8ArrayOid      = 1022
	AclitemOid          = 1033
	AclitemArrayOid     = 1034
	InetArrayOid        = 1041
	VarcharOid          = 1043
	DateOid             = 1082
	TimestampOid        = 1114
	TimestampArrayOid   = 1115
	DateArrayOid        = 1182
	TimestampTzOid      = 1184
	TimestampTzArrayOid = 1185
	RecordOid           = 2249
	UuidOid             = 2950
	JsonbOid            = 3802
)

// PostgreSQL format codes
const (
	TextFormatCode   = 0
	BinaryFormatCode = 1
)

const maxUint = ^uint(0)
const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1

// SerializationError occurs on failure to encode or decode a value
type SerializationError string

func (e SerializationError) Error() string {
	return string(e)
}

func encodePreparedStatementArgument(wbuf *WriteBuf, oid pgtype.Oid, arg interface{}) error {
	if arg == nil {
		wbuf.WriteInt32(-1)
		return nil
	}

	switch arg := arg.(type) {
	case pgtype.BinaryEncoder:
		buf := &bytes.Buffer{}
		null, err := arg.EncodeBinary(wbuf.conn.ConnInfo, buf)
		if err != nil {
			return err
		}
		if null {
			wbuf.WriteInt32(-1)
		} else {
			wbuf.WriteInt32(int32(buf.Len()))
			wbuf.WriteBytes(buf.Bytes())
		}
		return nil
	case pgtype.TextEncoder:
		buf := &bytes.Buffer{}
		null, err := arg.EncodeText(wbuf.conn.ConnInfo, buf)
		if err != nil {
			return err
		}
		if null {
			wbuf.WriteInt32(-1)
		} else {
			wbuf.WriteInt32(int32(buf.Len()))
			wbuf.WriteBytes(buf.Bytes())
		}
		return nil
	case driver.Valuer:
		v, err := arg.Value()
		if err != nil {
			return err
		}
		return encodePreparedStatementArgument(wbuf, oid, v)
	case string:
		return encodeString(wbuf, oid, arg)
	case []byte:
		return encodeByteSlice(wbuf, oid, arg)
	}

	refVal := reflect.ValueOf(arg)

	if refVal.Kind() == reflect.Ptr {
		if refVal.IsNil() {
			wbuf.WriteInt32(-1)
			return nil
		}
		arg = refVal.Elem().Interface()
		return encodePreparedStatementArgument(wbuf, oid, arg)
	}

	if dt, ok := wbuf.conn.ConnInfo.DataTypeForOid(oid); ok {
		value := dt.Value
		err := value.Set(arg)
		if err != nil {
			return err
		}

		buf := &bytes.Buffer{}
		null, err := value.(pgtype.BinaryEncoder).EncodeBinary(wbuf.conn.ConnInfo, buf)
		if err != nil {
			return err
		}
		if null {
			wbuf.WriteInt32(-1)
		} else {
			wbuf.WriteInt32(int32(buf.Len()))
			wbuf.WriteBytes(buf.Bytes())
		}
		return nil
	}

	if strippedArg, ok := stripNamedType(&refVal); ok {
		return encodePreparedStatementArgument(wbuf, oid, strippedArg)
	}
	return SerializationError(fmt.Sprintf("Cannot encode %T into oid %v - %T must implement Encoder or be converted to a string", arg, oid, arg))
}

// chooseParameterFormatCode determines the correct format code for an
// argument to a prepared statement. It defaults to TextFormatCode if no
// determination can be made.
func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid pgtype.Oid, arg interface{}) int16 {
	switch arg.(type) {
	case pgtype.BinaryEncoder:
		return BinaryFormatCode
	case string, *string, pgtype.TextEncoder:
		return TextFormatCode
	}

	if dt, ok := ci.DataTypeForOid(oid); ok {
		if _, ok := dt.Value.(pgtype.BinaryEncoder); ok {
			return BinaryFormatCode
		}
	}

	return TextFormatCode
}

func stripNamedType(val *reflect.Value) (interface{}, bool) {
	switch val.Kind() {
	case reflect.Int:
		convVal := int(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int8:
		convVal := int8(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int16:
		convVal := int16(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int32:
		convVal := int32(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int64:
		convVal := int64(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint:
		convVal := uint(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint8:
		convVal := uint8(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint16:
		convVal := uint16(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint32:
		convVal := uint32(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint64:
		convVal := uint64(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.String:
		convVal := val.String()
		return convVal, reflect.TypeOf(convVal) != val.Type()
	}

	return nil, false
}

func decodeText(vr *ValueReader) string {
	if vr.Len() == -1 {
		vr.Fatal(ProtocolError("Cannot decode null into string"))
		return ""
	}

	if vr.Type().FormatCode == BinaryFormatCode {
		vr.Fatal(ProtocolError("cannot decode binary value into string"))
		return ""
	}

	return vr.ReadString(vr.Len())
}

func encodeString(w *WriteBuf, oid pgtype.Oid, value string) error {
	w.WriteInt32(int32(len(value)))
	w.WriteBytes([]byte(value))
	return nil
}

func decodeBytea(vr *ValueReader) []byte {
	if vr.Len() == -1 {
		return nil
	}

	if vr.Type().DataType != ByteaOid {
		vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into []byte", vr.Type().DataType)))
		return nil
	}

	if vr.Type().FormatCode != BinaryFormatCode {
		vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
		return nil
	}

	return vr.ReadBytes(vr.Len())
}

func encodeByteSlice(w *WriteBuf, oid pgtype.Oid, value []byte) error {
	w.WriteInt32(int32(len(value)))
	w.WriteBytes(value)

	return nil
}
<commit_msg>Remove unused code<commit_after>package pgx

import (
	"bytes"
	"database/sql/driver"
	"fmt"
	"reflect"

	"github.com/jackc/pgx/pgtype"
)

// PostgreSQL oids for common types
const (
	BoolOid             = 16
	ByteaOid            = 17
	CharOid             = 18
	NameOid             = 19
	Int8Oid             = 20
	Int2Oid             = 21
	Int4Oid             = 23
	TextOid             = 25
	OidOid              = 26
	TidOid              = 27
	XidOid              = 28
	CidOid              = 29
	JsonOid             = 114
	CidrOid             = 650
	CidrArrayOid        = 651
	Float4Oid           = 700
	Float8Oid           = 701
	UnknownOid          = 705
	InetOid             = 869
	BoolArrayOid        = 1000
	Int2ArrayOid        = 1005
	Int4ArrayOid        = 1007
	TextArrayOid        = 1009
	ByteaArrayOid       = 1001
	VarcharArrayOid     = 1015
	Int8ArrayOid        = 1016
	Float4ArrayOid      = 1021
	Float8ArrayOid      = 1022
	AclitemOid          = 1033
	AclitemArrayOid     = 1034
	InetArrayOid        = 1041
	VarcharOid          = 1043
	DateOid             = 1082
	TimestampOid        = 1114
	TimestampArrayOid   = 1115
	DateArrayOid        = 1182
	TimestampTzOid      = 1184
	TimestampTzArrayOid = 1185
	RecordOid           = 2249
	UuidOid             = 2950
	JsonbOid            = 3802
)

// PostgreSQL format codes
const (
	TextFormatCode   = 0
	BinaryFormatCode = 1
)

const maxUint = ^uint(0)
const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1

// SerializationError occurs on failure to encode or decode a value
type SerializationError string

func (e SerializationError) Error() string {
	return string(e)
}

func encodePreparedStatementArgument(wbuf *WriteBuf, oid pgtype.Oid, arg interface{}) error {
	if arg == nil {
		wbuf.WriteInt32(-1)
		return nil
	}

	switch arg := arg.(type) {
	case pgtype.BinaryEncoder:
		buf := &bytes.Buffer{}
		null, err := arg.EncodeBinary(wbuf.conn.ConnInfo, buf)
		if err != nil {
			return err
		}
		if null {
			wbuf.WriteInt32(-1)
		} else {
			wbuf.WriteInt32(int32(buf.Len()))
			wbuf.WriteBytes(buf.Bytes())
		}
		return nil
	case pgtype.TextEncoder:
		buf := &bytes.Buffer{}
		null, err := arg.EncodeText(wbuf.conn.ConnInfo, buf)
		if err != nil {
			return err
		}
		if null {
			wbuf.WriteInt32(-1)
		} else {
			wbuf.WriteInt32(int32(buf.Len()))
			wbuf.WriteBytes(buf.Bytes())
		}
		return nil
	case driver.Valuer:
		v, err := arg.Value()
		if err != nil {
			return err
		}
		return encodePreparedStatementArgument(wbuf, oid, v)
	case string:
		wbuf.WriteInt32(int32(len(arg)))
		wbuf.WriteBytes([]byte(arg))
		return nil
	case []byte:
		wbuf.WriteInt32(int32(len(arg)))
		wbuf.WriteBytes(arg)
		return nil
	}

	refVal := reflect.ValueOf(arg)

	if refVal.Kind() == reflect.Ptr {
		if refVal.IsNil() {
			wbuf.WriteInt32(-1)
			return nil
		}
		arg = refVal.Elem().Interface()
		return encodePreparedStatementArgument(wbuf, oid, arg)
	}

	if dt, ok := wbuf.conn.ConnInfo.DataTypeForOid(oid); ok {
		value := dt.Value
		err := value.Set(arg)
		if err != nil {
			return err
		}

		buf := &bytes.Buffer{}
		null, err := value.(pgtype.BinaryEncoder).EncodeBinary(wbuf.conn.ConnInfo, buf)
		if err != nil {
			return err
		}
		if null {
			wbuf.WriteInt32(-1)
		} else {
			wbuf.WriteInt32(int32(buf.Len()))
			wbuf.WriteBytes(buf.Bytes())
		}
		return nil
	}

	if strippedArg, ok := stripNamedType(&refVal); ok {
		return encodePreparedStatementArgument(wbuf, oid, strippedArg)
	}
	return SerializationError(fmt.Sprintf("Cannot encode %T into oid %v - %T must implement Encoder or be converted to a string", arg, oid, arg))
}

// chooseParameterFormatCode determines the correct format code for an
// argument to a prepared statement. It defaults to TextFormatCode if no
// determination can be made.
func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid pgtype.Oid, arg interface{}) int16 {
	switch arg.(type) {
	case pgtype.BinaryEncoder:
		return BinaryFormatCode
	case string, *string, pgtype.TextEncoder:
		return TextFormatCode
	}

	if dt, ok := ci.DataTypeForOid(oid); ok {
		if _, ok := dt.Value.(pgtype.BinaryEncoder); ok {
			return BinaryFormatCode
		}
	}

	return TextFormatCode
}

func stripNamedType(val *reflect.Value) (interface{}, bool) {
	switch val.Kind() {
	case reflect.Int:
		convVal := int(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int8:
		convVal := int8(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int16:
		convVal := int16(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int32:
		convVal := int32(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Int64:
		convVal := int64(val.Int())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint:
		convVal := uint(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint8:
		convVal := uint8(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint16:
		convVal := uint16(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint32:
		convVal := uint32(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.Uint64:
		convVal := uint64(val.Uint())
		return convVal, reflect.TypeOf(convVal) != val.Type()
	case reflect.String:
		convVal := val.String()
		return convVal, reflect.TypeOf(convVal) != val.Type()
	}

	return nil, false
}

func decodeBytea(vr *ValueReader) []byte {
	if vr.Len() == -1 {
		return nil
	}

	if vr.Type().DataType != ByteaOid {
		vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into []byte", vr.Type().DataType)))
		return nil
	}

	if vr.Type().FormatCode != BinaryFormatCode {
		vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
		return nil
	}

	return vr.ReadBytes(vr.Len())
}
<|endoftext|>


<commit_before>package config

import "sync"

//Values provides storage of arbitrary interface{} values referenced by type Key.
//The zero value for Values is not in a valid state, thus Values should be
//created with NewValues().
//Values is safe for use by multiple goroutines.
type Values struct {
	lock *sync.RWMutex
	root *node
}

//NewValues creates an empty *Values.
func NewValues() *Values {
	return &Values{
		lock: &sync.RWMutex{},
		root: newNode(),
	}
}

func newValues(root *node) *Values {
	return &Values{
		lock: &sync.RWMutex{},
		root: root,
	}
}

//Merge merges all associations in other into v starting at key.
//To merge other in v at root, use an empty Key for key.
func (v *Values) Merge(key Key, other *Values) bool {
	v.lock.Lock()
	defer v.lock.Unlock()

	changed := false
	other.EachKeyValue(func(otherKey Key, value interface{}) {
		actualKey := key.Append(otherKey)
		changed = v.put(actualKey, value) || changed
	})
	return changed
}

//EachKeyValue calls visitor with each set Key value association in v.
func (v *Values) EachKeyValue(visitor func(key Key, value interface{})) {
	v.lock.RLock()
	defer v.lock.RUnlock()

	v.root.eachKeyValue(nil, visitor)
}

//Equal determines whether or not v and other contain the exact same set of
//Keys and associated values.
//Comparison on a value by value basis is done with the == operator.
func (v *Values) Equal(other *Values) bool {
	v.lock.RLock()
	defer v.lock.RUnlock()
	other.lock.RLock()
	defer other.lock.RUnlock()

	return v.root.equal(other.root)
}

//Put adds the key, value association to v.
//changed indicates whether or not this operation changes the set of associations
//in any way.
func (v *Values) Put(key Key, value interface{}) (changed bool) {
	v.lock.Lock()
	defer v.lock.Unlock()

	return v.put(key, value)
}

func (v *Values) put(key Key, value interface{}) bool {
	return v.root.put(key, value)
}

//IsEmpty determines whether or not any associated exist in v.
func (v *Values) IsEmpty() bool {
	v.lock.RLock()
	defer v.lock.RUnlock()

	return v.root.isEmpty()
}

//Get returns the value associated with key or nil if the association does not
//exist.
func (v *Values) Get(key Key) (value interface{}) {
	value, _ = v.GetOk(key)
	return value
}

//GetOk return the value associated with key.
//The return value ok indicates whether or not any value is actually stored at key.
func (v *Values) GetOk(key Key) (value interface{}, ok bool) {
	v.lock.RLock()
	defer v.lock.RUnlock()

	_, found, _ := v.root.findDescendent(nil, key, false, false)
	if found == nil {
		return nil, false
	}
	if found.isSet() {
		return found.value, true
	}
	return newValues(found.clone()), true
}

//Clone creates a new Values with all associations copied into the result.
//The individual values are shallow copied into the result.
func (v *Values) Clone() *Values {
	v.lock.RLock()
	defer v.lock.RUnlock()

	return newValues(v.root)
}

//Remove deletes the association stored at key if one exists.
//v is the removed value or nil if nothing was returned, and ok indicated any value
//was actually removed.
func (v *Values) Remove(key Key) (value interface{}, ok bool) {
	v.lock.Lock()
	defer v.lock.Unlock()

	if key.IsEmpty() {
		if v.root.isSet() {
			result := v.root.value
			v.root = newNode()
			return result, true
		}
		return nil, false
	}

	parent, found, _ := v.root.findDescendent(nil, key, false, false)
	if found == nil {
		return nil, false
	}
	var result interface{}
	if found.isSet() {
		result = found.value
	} else {
		result = newValues(found)
	}
	if parent != nil {
		delete(parent.children, key[key.Len()-1])
	}
	return result, true
}

//node is the internal node type for a Values tree.
//It stores the value stored at its location in the tree and links to children node.
type node struct {
	//value is the value stored at this location in the tree.
	//It may be nil.
	//It is determined to be set by the isSet() method.
	value interface{}

	//children holds the references to this node's child nodes.
	//The keys in children are the parts to the larger Key that references a value.
	children map[string]*node
}

func newNodeValue(value interface{}) *node {
	n := newNode()
	n.value = value
	n.children = nil
	return n
}

func newNode() *node {
	return &node{
		value:    nil,
		children: map[string]*node{},
	}
}

func (n *node) isEmpty() bool {
	return !n.isSet() && len(n.children) == 0
}

func (n *node) isSet() bool {
	return n.children == nil
}

func (n *node) put(key Key, value interface{}) bool {
	if key.IsEmpty() {
		return n.setValue(value)
	}
	child, changed := n.findChild(key[0], true)
	remainingKey := key[1:]
	return child.put(remainingKey, value) || changed
}

func (n *node) setValue(value interface{}) bool {
	if values, ok := value.(*Values); ok {
		return n.setValues(values)
	}
	changed := false
	if n.isSet() {
		changed = value != n.value
	} else {
		changed = true
	}
	n.value = value
	n.children = nil
	return changed
}

func (n *node) setValues(values *Values) bool {
	if values.IsEmpty() {
		if n.isEmpty() {
			return false
		}
		n.value = nil
		n.children = nil
		return true
	}
	changed := false
	values.EachKeyValue(func(key Key, value interface{}) {
		changed = n.put(key, value) || changed
	})
	return changed
}

func (n *node) clone() *node {
	return &node{
		value:    n.value,
		children: n.cloneChildren(),
	}
}

func (n *node) cloneChildren() map[string]*node {
	if n.children == nil {
		return nil
	}
	result := map[string]*node{}
	for key, child := range n.children {
		result[key] = child.clone()
	}
	return result
}

func (n *node) eachKeyValue(key Key, visitor func(key Key, value interface{})) {
	if n.isSet() {
		visitor(key, n.value)
		return
	}
	for keyPart, childNode := range n.children {
		childNode.eachKeyValue(append(NewKey(key...), keyPart), visitor)
	}
}

func (n *node) equal(other *node) bool {
	if n.value != other.value {
		return false
	}
	return n.childrenEqual(other)
}

func (n *node) childrenEqual(other *node) bool {
	if len(n.children) != len(other.children) {
		return false
	}
	for keyPart, child := range n.children {
		otherChild, ok := other.children[keyPart]
		if !ok || !child.equal(otherChild) {
			return false
		}
	}
	return true
}

func (n *node) findDescendent(parent *node, key Key, canChange, hasChanged bool) (*node, *node, bool) {
	if key.IsEmpty() {
		return parent, n, hasChanged
	}
	child, changed := n.findChild(key[0], canChange)
	if child == nil {
		return parent, nil, changed
	}
	return child.findDescendent(n, key[1:], canChange, changed || hasChanged)
}

func (n *node) findChild(keyPart string, canChange bool) (*node, bool) {
	changed := false
	if n.isSet() {
		if !canChange {
			return nil, false
		}
		n.value, changed = nil, true
		n.children = map[string]*node{}
	}
	child, ok := n.children[keyPart]
	if !ok {
		if !canChange {
			return nil, false
		}
		n.children[keyPart] = newNode()
		child = n.children[keyPart]
		changed = true
	}
	return child, changed
}
<commit_msg>Updates documentation for the *node type.<commit_after>package config

import "sync"

//Values provides storage of arbitrary interface{} values referenced by type Key.
//The zero value for Values is not in a valid state, thus Values should be
//created with NewValues().
//Values is safe for use by multiple goroutines.
type Values struct {
	lock *sync.RWMutex
	root *node
}

//NewValues creates an empty *Values.
func NewValues() *Values {
	return &Values{
		lock: &sync.RWMutex{},
		root: newNode(),
	}
}

func newValues(root *node) *Values {
	return &Values{
		lock: &sync.RWMutex{},
		root: root,
	}
}

//Merge merges all associations in other into v starting at key.
//To merge other in v at root, use an empty Key for key.
func (v *Values) Merge(key Key, other *Values) bool {
	v.lock.Lock()
	defer v.lock.Unlock()

	changed := false
	other.EachKeyValue(func(otherKey Key, value interface{}) {
		actualKey := key.Append(otherKey)
		changed = v.put(actualKey, value) || changed
	})
	return changed
}

//EachKeyValue calls visitor with each set Key value association in v.
func (v *Values) EachKeyValue(visitor func(key Key, value interface{})) {
	v.lock.RLock()
	defer v.lock.RUnlock()

	v.root.eachKeyValue(nil, visitor)
}

//Equal determines whether or not v and other contain the exact same set of
//Keys and associated values.
//Comparison on a value by value basis is done with the == operator.
func (v *Values) Equal(other *Values) bool {
	v.lock.RLock()
	defer v.lock.RUnlock()
	other.lock.RLock()
	defer other.lock.RUnlock()

	return v.root.equal(other.root)
}

//Put adds the key, value association to v.
//changed indicates whether or not this operation changes the set of associations
//in any way.
func (v *Values) Put(key Key, value interface{}) (changed bool) {
	v.lock.Lock()
	defer v.lock.Unlock()

	return v.put(key, value)
}

func (v *Values) put(key Key, value interface{}) bool {
	return v.root.put(key, value)
}

//IsEmpty determines whether or not any associated exist in v.
func (v *Values) IsEmpty() bool {
	v.lock.RLock()
	defer v.lock.RUnlock()

	return v.root.isEmpty()
}

//Get returns the value associated with key or nil if the association does not
//exist.
func (v *Values) Get(key Key) (value interface{}) {
	value, _ = v.GetOk(key)
	return value
}

//GetOk return the value associated with key.
//The return value ok indicates whether or not any value is actually stored at key.
func (v *Values) GetOk(key Key) (value interface{}, ok bool) {
	v.lock.RLock()
	defer v.lock.RUnlock()

	_, found, _ := v.root.findDescendent(nil, key, false, false)
	if found == nil {
		return nil, false
	}
	if found.isSet() {
		return found.value, true
	}
	return newValues(found.clone()), true
}

//Clone creates a new Values with all associations copied into the result.
//The individual values are shallow copied into the result.
func (v *Values) Clone() *Values {
	v.lock.RLock()
	defer v.lock.RUnlock()

	return newValues(v.root)
}

//Remove deletes the association stored at key if one exists.
//v is the removed value or nil if nothing was returned, and ok indicated any value
//was actually removed.
func (v *Values) Remove(key Key) (value interface{}, ok bool) {
	v.lock.Lock()
	defer v.lock.Unlock()

	if key.IsEmpty() {
		if v.root.isSet() {
			result := v.root.value
			v.root = newNode()
			return result, true
		}
		return nil, false
	}

	parent, found, _ := v.root.findDescendent(nil, key, false, false)
	if found == nil {
		return nil, false
	}
	var result interface{}
	if found.isSet() {
		result = found.value
	} else {
		result = newValues(found)
	}
	if parent != nil {
		delete(parent.children, key[key.Len()-1])
	}
	return result, true
}

//node is the internal node type for a Values tree.
//It stores the value stored at its location in the tree and links to children node.
type node struct {
	//value is the value stored at this location in the tree.
	//It may be nil.
	//It is determined to be set by the isSet() method.
	value interface{}

	//children holds the references to this node's child nodes.
	//The keys in children are the parts to the larger Key that references a value.
	children map[string]*node
}

//newNodeValues creates a *node to value set to value and children set to nil.
func newNodeValue(value interface{}) *node {
	n := newNode()
	n.value = value
	n.children = nil
	return n
}

//newNode creates a *node with nil value and empty children.
func newNode() *node {
	return &node{
		value:    nil,
		children: map[string]*node{},
	}
}

//isEmpty determines whether or not n is empty.
//true if not n.isSet() and length of n.children is 0, false otherwise.
func (n *node) isEmpty() bool {
	return !n.isSet() && len(n.children) == 0
}

//isSet determines whether or not n is set (n.values can assumed to be keyed).
//true if n.children is nil, false otherwise.
func (n *node) isSet() bool {
	return n.children == nil
}

//put puts value at key within n's subtree or at n if key is empty.
func (n *node) put(key Key, value interface{}) bool {
	if key.IsEmpty() {
		return n.setValue(value)
	}
	child, changed := n.findChild(key[0], true)
	remainingKey := key[1:]
	return child.put(remainingKey, value) || changed
}

//setValue sets n value to value.
//if value is a *Values, then n.setValues(values.(*Values)) is used.
func (n *node) setValue(value interface{}) bool {
	if values, ok := value.(*Values); ok {
		return n.setValues(values)
	}
	changed := false
	if n.isSet() {
		changed = value != n.value
	} else {
		changed = true
	}
	n.value = value
	n.children = nil
	return changed
}

//setValues calls n.put() for each key, value in values.
func (n *node) setValues(values *Values) bool {
	if values.IsEmpty() {
		if n.isEmpty() {
			return false
		}
		n.value = nil
		n.children = nil
		return true
	}
	changed := false
	values.EachKeyValue(func(key Key, value interface{}) {
		changed = n.put(key, value) || changed
	})
	return changed
}

//clone returns a cloned n with a shallow copy of n.value and n.children cloned
//via n.cloneChildren().
func (n *node) clone() *node {
	return &node{
		value:    n.value,
		children: n.cloneChildren(),
	}
}

//cloneChildren returns a new map matching n.children by calling *node.clone()
//on each child in n.children.
func (n *node) cloneChildren() map[string]*node {
	if n.children == nil {
		return nil
	}
	result := map[string]*node{}
	for key, child := range n.children {
		result[key] = child.clone()
	}
	return result
}

//eachKeyValues calls visitor for each set value in n's subtree.
//key is a Key onto which to append all descdendent keys.
func (n *node) eachKeyValue(key Key, visitor func(key Key, value interface{})) {
	if n.isSet() {
		visitor(key, n.value)
		return
	}
	for keyPart, childNode := range n.children {
		childNode.eachKeyValue(append(NewKey(key...), keyPart), visitor)
	}
}

//equal determines if n and other are equal by n.value == other.value and n.childrenEqual(other)
func (n *node) equal(other *node) bool {
	return n.value == other.value && n.childrenEqual(other)
}

//childrenEqual determines if n and other's children have the same set of keys
//and all associated child nodes are equal via *node.equal().
func (n *node) childrenEqual(other *node) bool {
	if len(n.children) != len(other.children) {
		return false
	}
	for keyPart, child := range n.children {
		otherChild, ok := other.children[keyPart]
		if !ok || !child.equal(otherChild) {
			return false
		}
	}
	return true
}

//findDescendent finds a desired descendent (node at any lower level) and its possible
//parent.
//The parameter parent should be n's parent. This must be ensured by the caller.
func (n *node) findDescendent(parent *node, key Key, canChange, hasChanged bool) (foundParent *node, found *node, changed bool) {
	//if there is no more key to look into, then return parent, n, and hasChanged.
	if key.IsEmpty() {
		return parent, n, hasChanged
	}
	//find the child at the next part in key, possibly creating or changing with canChange.
	child, changed := n.findChild(key[0], canChange)
	if child == nil {
		return parent, nil, changed
	}
	//recurse into children.
	return child.findDescendent(n, key[1:], canChange, changed || hasChanged)
}

//findChild find a child node of n at keyPart.
//canChange tells findChild if it can modify n.children to modify n.value and or n.children.
//Essentially, canChange being true performs a put, and false performs a get or lookup.
func (n *node) findChild(keyPart string, canChange bool) (*node, bool) {
	changed := false
	if n.isSet() {
		if !canChange {
			return nil, false
		}
		n.value, changed = nil, true
		n.children = map[string]*node{}
	}
	child, ok := n.children[keyPart]
	if !ok {
		if !canChange {
			return nil, false
		}
		n.children[keyPart] = newNode()
		child = n.children[keyPart]
		changed = true
	}
	return child, changed
}
<|endoftext|>


<commit_before>package testrouter

import (
	"net/http"
	"testing"

	"github.com/Nivl/go-rest-tools/network/http/httperr"
	"github.com/Nivl/go-rest-tools/router"
	"github.com/Nivl/go-rest-tools/router/mockrouter"
	"github.com/Nivl/go-rest-tools/storage/db/mockdb"
	"github.com/stretchr/testify/assert"
)

// ConflictTestParams represents the params needed by ConflictTest
type ConflictTestParams struct {
	Handler           router.RouteHandler
	HandlerParams     interface{}
	StructConflicting string
	FieldConflicting  string
}

// ConflictTest test a handler and expects a 409
func ConflictTest(t *testing.T, p *ConflictTestParams) {
	// Mock the database & add expectations
	mockDB := new(mockdb.DB)
	mockDB.ExpectInsertConflict(p.StructConflicting, p.FieldConflicting)

	// Mock the request & add expectations
	req := new(mockrouter.HTTPRequest)
	req.On("Params").Return(p.HandlerParams)

	// call the handler
	err := p.Handler(req, &router.Dependencies{DB: mockDB})

	// Assert everything
	assert.Error(t, err)
	mockDB.AssertExpectations(t)
	req.AssertExpectations(t)

	httpErr := httperr.Convert(err)
	assert.Equal(t, http.StatusConflict, httpErr.Code())
	assert.Equal(t, p.FieldConflicting, httpErr.Field())
}
<commit_msg>test(router): Add rename ConflictTest to ConflictInsertTest and add ConflictUpdateTest<commit_after>package testrouter

import (
	"net/http"
	"testing"

	"github.com/Nivl/go-rest-tools/network/http/httperr"
	"github.com/Nivl/go-rest-tools/router"
	"github.com/Nivl/go-rest-tools/router/mockrouter"
	"github.com/Nivl/go-rest-tools/storage/db"
	"github.com/Nivl/go-rest-tools/storage/db/mockdb"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

// ConflictTestParams represents the params needed by ConflictTest
type ConflictTestParams struct {
	Handler           router.RouteHandler
	HandlerParams     interface{}
	StructConflicting string
	FieldConflicting  string
}

// ConflictInsertTest test an handler and expects a 409 on an insert statement
func ConflictInsertTest(t *testing.T, p *ConflictTestParams) {
	// Mock the database & add expectations
	mockDB := new(mockdb.DB)
	mockDB.ExpectInsertConflict(p.StructConflicting, p.FieldConflicting)

	// Mock the request & add expectations
	req := new(mockrouter.HTTPRequest)
	req.On("Params").Return(p.HandlerParams)

	// call the handler
	err := p.Handler(req, &router.Dependencies{DB: mockDB})

	// Assert everything
	assert.Error(t, err)
	mockDB.AssertExpectations(t)
	req.AssertExpectations(t)

	httpErr := httperr.Convert(err)
	assert.Equal(t, http.StatusConflict, httpErr.Code())
	assert.Equal(t, p.FieldConflicting, httpErr.Field())
}

// ConflictUpdateTest test am handler and expects a 409 on an update statement
func ConflictUpdateTest(t *testing.T, p *ConflictTestParams) {
	// Mock the database & add expectations
	mockDB := new(mockdb.DB)
	mockDB.ExpectGet(p.StructConflicting, func(args mock.Arguments) {
		obj := args.Get(0).(db.Model)
		obj.SetID("e9b51718-383b-42be-8720-0c8d7a99e978")
	})
	mockDB.ExpectUpdateConflict(p.StructConflicting, p.FieldConflicting)

	// Mock the request & add expectations
	req := new(mockrouter.HTTPRequest)
	req.On("Params").Return(p.HandlerParams)

	// call the handler
	err := p.Handler(req, &router.Dependencies{DB: mockDB})

	// Assert everything
	assert.Error(t, err)
	mockDB.AssertExpectations(t)
	req.AssertExpectations(t)

	httpErr := httperr.Convert(err)
	assert.Equal(t, http.StatusConflict, httpErr.Code())
	assert.Equal(t, p.FieldConflicting, httpErr.Field())
}
<|endoftext|>


<commit_before>package rpm

import (
	"math"
	"regexp"
	"strings"
	"unicode"
)

// alphanumPattern is a regular expression to match all sequences of numeric
// characters or alphanumeric characters.
var alphanumPattern = regexp.MustCompile("([a-zA-Z]+)|([0-9]+)")

// VersionCompare compares the version details of two packages. Versions are
// compared by Epoch, Version and Release in descending order of precedence.
//
// If a is more recent than b, 1 is returned. If a is less recent than b, -1 is
// returned. If a and b are equal, 0 is returned.
//
// This function does not consider if the two packages have the same name or if
// either package has been made obsolete by the other.
func VersionCompare(a PackageVersion, b PackageVersion) int {
	// compare nils
	if a == nil && b == nil {
		return 0
	} else if a == nil {
		return -1
	} else if b == nil {
		return 1
	}

	// compare epoch
	ae := a.Epoch()
	be := b.Epoch()
	if ae != be {
		if ae > be {
			return 1
		} else {
			return -1
		}
	}

	// compare version
	if rc := rpmvercmp(a.Version(), b.Version()); rc != 0 {
		return rc
	}

	// compare release
	return rpmvercmp(a.Release(), b.Release())
}

// rpmcmpver compares two version or release strings.
//
// For the original C implementation, see:
// https://github.com/rpm-software-management/rpm/blob/master/lib/rpmvercmp.c#L16
func rpmvercmp(a, b string) int {
	// shortcut for equality
	if a == b {
		return 0
	}

	// get alpha/numeric segements
	segsa := alphanumPattern.FindAllString(a, -1)
	segsb := alphanumPattern.FindAllString(b, -1)
	segs := int(math.Min(float64(len(segsa)), float64(len(segsb))))

	// TODO: handle tildes in rpmvercmp

	// compare each segment
	for i := 0; i < segs; i++ {
		a := segsa[i]
		b := segsb[i]

		if unicode.IsNumber([]rune(a)[0]) {
			// numbers are always greater than alphas
			if !unicode.IsNumber([]rune(b)[0]) {
				// a is numeric, b is alpha
				return 1
			}

			// trim leading zeros
			a = strings.TrimLeft(a, "0")
			b = strings.TrimLeft(b, "0")

			// longest string wins without further comparison
			if len(a) > len(b) {
				return 1
			} else if len(b) > len(a) {
				return -1
			}

		} else if unicode.IsNumber([]rune(b)[0]) {
			// a is alpha, b is numeric
			return -1
		}

		// string compare
		if a < b {
			return -1
		} else if a > b {
			return 1
		}
	}

	// segments were all the same but separators must have been different
	if len(segsa) == len(segsb) {
		return 0
	}

	// whoever has the most segments wins
	if len(segsa) > len(segsb) {
		return 1
	} else {
		return -1
	}
}
<commit_msg>Added LatestPackage()<commit_after>package rpm

import (
	"math"
	"regexp"
	"strings"
	"unicode"
)

// alphanumPattern is a regular expression to match all sequences of numeric
// characters or alphanumeric characters.
var alphanumPattern = regexp.MustCompile("([a-zA-Z]+)|([0-9]+)")

// VersionCompare compares the version details of two packages. Versions are
// compared by Epoch, Version and Release in descending order of precedence.
//
// If a is more recent than b, 1 is returned. If a is less recent than b, -1 is
// returned. If a and b are equal, 0 is returned.
//
// This function does not consider if the two packages have the same name or if
// either package has been made obsolete by the other.
func VersionCompare(a PackageVersion, b PackageVersion) int {
	// compare nils
	if a == nil && b == nil {
		return 0
	} else if a == nil {
		return -1
	} else if b == nil {
		return 1
	}

	// compare epoch
	ae := a.Epoch()
	be := b.Epoch()
	if ae != be {
		if ae > be {
			return 1
		} else {
			return -1
		}
	}

	// compare version
	if rc := rpmvercmp(a.Version(), b.Version()); rc != 0 {
		return rc
	}

	// compare release
	return rpmvercmp(a.Release(), b.Release())
}

// LatestPackage returns the package with the highest version in the given slice
// of PackageVersions.
func LatestPackage(v ...PackageVersion) PackageVersion {
	var latest PackageVersion
	for _, p := range v {
		if 1 == VersionCompare(p, latest) {
			latest = p
		}
	}

	return latest
}

// rpmcmpver compares two version or release strings.
//
// For the original C implementation, see:
// https://github.com/rpm-software-management/rpm/blob/master/lib/rpmvercmp.c#L16
func rpmvercmp(a, b string) int {
	// shortcut for equality
	if a == b {
		return 0
	}

	// get alpha/numeric segements
	segsa := alphanumPattern.FindAllString(a, -1)
	segsb := alphanumPattern.FindAllString(b, -1)
	segs := int(math.Min(float64(len(segsa)), float64(len(segsb))))

	// TODO: handle tildes in rpmvercmp

	// compare each segment
	for i := 0; i < segs; i++ {
		a := segsa[i]
		b := segsb[i]

		if unicode.IsNumber([]rune(a)[0]) {
			// numbers are always greater than alphas
			if !unicode.IsNumber([]rune(b)[0]) {
				// a is numeric, b is alpha
				return 1
			}

			// trim leading zeros
			a = strings.TrimLeft(a, "0")
			b = strings.TrimLeft(b, "0")

			// longest string wins without further comparison
			if len(a) > len(b) {
				return 1
			} else if len(b) > len(a) {
				return -1
			}

		} else if unicode.IsNumber([]rune(b)[0]) {
			// a is alpha, b is numeric
			return -1
		}

		// string compare
		if a < b {
			return -1
		} else if a > b {
			return 1
		}
	}

	// segments were all the same but separators must have been different
	if len(segsa) == len(segsb) {
		return 0
	}

	// whoever has the most segments wins
	if len(segsa) > len(segsb) {
		return 1
	} else {
		return -1
	}
}
<|endoftext|>


<commit_before>package walgo

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
)

const (
	jsonTagName  = "json"
	walgoTagName = "walgo"
	skipValue    = "skip"
)

// VarifyBody reads the body from the HTTP request and tries to decode it as
// JSON. It also checks for the presence of all the values in the given
// interface type. If the parsed body matches the interface the next function
// is called.
func VerifyBody(w http.ResponseWriter, r *http.Request, v interface{}, next func()) {
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	valid, err := verifyData(data, v)
	if err != nil || !valid {
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	next()
}

func verifyData(data []byte, v interface{}) (ok bool, err error) {
	if reflect.Indirect(reflect.ValueOf(v)).Type().Kind() == reflect.Struct {
		tmp := make(map[string]interface{})
		err = json.Unmarshal(data, &tmp)
		if err != nil {
			return false, err
		}

		t := reflect.Indirect(reflect.ValueOf(v)).Type()
		for i := 0; i < t.NumField(); i++ {
			f := t.Field(i)

			if !skipFieldTagPresent(f) && (!fieldJsonTagPresent(f, tmp) && !fieldNamePresent(f, tmp)) {
				return false, fmt.Errorf("Field not found: %s", f.Name)
			}
		}

		err = json.Unmarshal(data, &v)
		if err != nil {
			return false, err
		}

		return true, nil
	}

	return false, fmt.Errorf("Value is not a struct: %s", reflect.TypeOf(v).Kind().String())
}

func fieldNamePresent(f reflect.StructField, t map[string]interface{}) bool {
	_, ok := t[f.Name]
	return ok
}

func fieldJsonTagPresent(f reflect.StructField, t map[string]interface{}) bool {
	jsonTag := f.Tag.Get(jsonTagName)
	if "" != jsonTag {
		splitTag := strings.Split(jsonTag, ",")

		_, ok := t[splitTag[0]]
		return ok
	}

	return false
}

func skipFieldTagPresent(f reflect.StructField) bool {
	walgoTag := f.Tag.Get(walgoTagName)
	if skipValue == walgoTag {
		return true
	}

	return false
}
<commit_msg>Added tag to enforce non-default values. A bit messy - but should work.<commit_after>package walgo

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
)

const (
	jsonTagName  = "json"
	walgoTagName = "walgo"
	skipValue    = "skip"
	noDefault    = "nodefault"
)

// VarifyBody reads the body from the HTTP request and tries to decode it as
// JSON. It also checks for the presence of all the values in the given
// interface type. If the parsed body matches the interface the next function
// is called.
func VerifyBody(w http.ResponseWriter, r *http.Request, v interface{}, next func()) {
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	valid, err := verifyData(data, v)
	if err != nil || !valid {
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	next()
}

func verifyData(data []byte, v interface{}) (ok bool, err error) {
	if reflect.Indirect(reflect.ValueOf(v)).Type().Kind() == reflect.Struct {
		tmp := make(map[string]interface{})
		err = json.Unmarshal(data, &tmp)
		if err != nil {
			return false, err
		}

		t := reflect.Indirect(reflect.ValueOf(v)).Type()
		for i := 0; i < t.NumField(); i++ {
			f := t.Field(i)

			if !skipFieldTagPresent(f) && (!fieldJsonTagPresent(f, tmp) && !fieldNamePresent(f, tmp)) {
				return false, fmt.Errorf("Field not found: %s", f.Name)
			}

			if noDefaultFieldTagPresent(f) {
				if isZero(getFieldValue(f, tmp)) {
					return false, fmt.Errorf("Field not allowed to have default value: %s", f.Name)
				}
			}
		}

		err = json.Unmarshal(data, &v)
		if err != nil {
			return false, err
		}

		return true, nil
	}

	return false, fmt.Errorf("Value is not a struct: %s", reflect.TypeOf(v).Kind().String())
}

func getFieldValue(f reflect.StructField, t map[string]interface{}) reflect.Value {
	name, found := fieldJsonTag(f, t)
	if !found && fieldNamePresent(f, t) {
		return reflect.ValueOf(t[f.Name])
	}

	return reflect.ValueOf(t[name])
}

func fieldNamePresent(f reflect.StructField, t map[string]interface{}) bool {
	_, ok := t[f.Name]
	if !ok {
		ok = jsonFieldNamePresent(f, t)
	}
	return ok
}

func jsonFieldNamePresent(f reflect.StructField, t map[string]interface{}) bool {
	if name, found := fieldJsonTag(f, t); found {
		_, ok := t[name]
		return ok
	}

	return false
}

func fieldJsonTagPresent(f reflect.StructField, t map[string]interface{}) bool {
	_, ok := fieldJsonTag(f, t)
	return ok
}

func fieldJsonTag(f reflect.StructField, t map[string]interface{}) (name string, found bool) {
	jsonTag := f.Tag.Get(jsonTagName)
	if "" != jsonTag {
		name = strings.Split(jsonTag, ",")[0]
		_, found = t[name]
		return name, found
	}

	return "", false
}

func skipFieldTagPresent(f reflect.StructField) bool {
	walgoTag := f.Tag.Get(walgoTagName)
	if skipValue == walgoTag {
		return true
	}

	return false
}

func noDefaultFieldTagPresent(f reflect.StructField) bool {
	walgoTag := f.Tag.Get(walgoTagName)
	if noDefault == walgoTag {
		return true
	}

	return false
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Func, reflect.Map, reflect.Slice:
		return v.IsNil()
	case reflect.Array:
		z := true
		for i := 0; i < v.Len(); i++ {
			z = z && isZero(v.Index(i))
		}
		return z
	case reflect.Struct:
		z := true
		for i := 0; i < v.NumField(); i++ {
			z = z && isZero(v.Field(i))
		}
		return z
	}
	// Compare other types directly:
	z := reflect.Zero(v.Type())
	return v.Interface() == z.Interface()
}
<|endoftext|>