<commit_before>/*
 * Copyright (c) 2014, Yawning Angel <yawning at torproject dot org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package obfs4

import (
	"bytes"
	"testing"

	"git.torproject.org/pluggable-transports/obfs4.git/common/ntor"
	"git.torproject.org/pluggable-transports/obfs4.git/common/replayfilter"
)

func TestHandshakeNtorClient(t *testing.T) {
	// Generate the server node id and id keypair, and ephemeral session keys.
	nodeID, _ := ntor.NewNodeID([]byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"))
	idKeypair, _ := ntor.NewKeypair(false)
	serverFilter, _ := replayfilter.New(replayTTL)
	clientKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("client: ntor.NewKeypair failed: %s", err)
	}
	serverKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("server: ntor.NewKeypair failed: %s", err)
	}

	// Test client handshake padding.
	for l := clientMinPadLength; l <= clientMaxPadLength; l++ {
		// Generate the client state and override the pad length.
		clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
		clientHs.padLen = l

		// Generate what the client will send to the server.
		clientBlob, err := clientHs.generateHandshake()
		if err != nil {
			t.Fatalf("[%d:0] clientHandshake.generateHandshake() failed: %s", l, err)
		}
		if len(clientBlob) > maxHandshakeLength {
			t.Fatalf("[%d:0] Generated client body is oversized: %d", l, len(clientBlob))
		}
		if len(clientBlob) < clientMinHandshakeLength {
			t.Fatalf("[%d:0] Generated client body is undersized: %d", l, len(clientBlob))
		}
		if len(clientBlob) != clientMinHandshakeLength+l {
			t.Fatalf("[%d:0] Generated client body incorrect size: %d", l, len(clientBlob))
		}

		// Generate the server state and override the pad length.
		serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
		serverHs.padLen = serverMinPadLength

		// Parse the client handshake message.
		serverSeed, err := serverHs.parseClientHandshake(serverFilter, clientBlob)
		if err != nil {
			t.Fatalf("[%d:0] serverHandshake.parseClientHandshake() failed: %s", l, err)
		}

		// Genrate what the server will send to the client.
		serverBlob, err := serverHs.generateHandshake()
		if err != nil {
			t.Fatal("[%d:0]: serverHandshake.generateHandshake() failed: %s", l, err)
		}

		// Parse the server handshake message.
		clientHs.serverRepresentative = nil
		n, clientSeed, err := clientHs.parseServerHandshake(serverBlob)
		if err != nil {
			t.Fatalf("[%d:0] clientHandshake.parseServerHandshake() failed: %s", l, err)
		}
		if n != len(serverBlob) {
			t.Fatalf("[%d:0] clientHandshake.parseServerHandshake() has bytes remaining: %d", l, n)
		}

		// Ensure the derived shared secret is the same.
		if 0 != bytes.Compare(clientSeed, serverSeed) {
			t.Fatalf("[%d:0] client/server seed mismatch", l)
		}
	}

	// Test oversized client padding.
	clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
	if err != nil {
		t.Fatalf("newClientHandshake failed: %s", err)
	}
	clientHs.padLen = clientMaxPadLength + 1
	clientBlob, err := clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced oversize) failed: %s", err)
	}
	serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (oversized)")
	}

	// Test undersized client padding.
	clientHs.padLen = clientMinPadLength - 1
	clientBlob, err = clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced undersize) failed: %s", err)
	}
	serverHs = newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (undersized)")
	}
}

func TestHandshakeNtorServer(t *testing.T) {
	// Generate the server node id and id keypair, and ephemeral session keys.
	nodeID, _ := ntor.NewNodeID([]byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"))
	idKeypair, _ := ntor.NewKeypair(false)
	serverFilter, _ := replayfilter.New(replayTTL)
	clientKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("client: ntor.NewKeypair failed: %s", err)
	}
	serverKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("server: ntor.NewKeypair failed: %s", err)
	}

	// Test server handshake padding.
	for l := serverMinPadLength; l <= serverMaxPadLength+inlineSeedFrameLength; l++ {
		// Generate the client state and override the pad length.
		clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
		clientHs.padLen = clientMinPadLength

		// Generate what the client will send to the server.
		clientBlob, err := clientHs.generateHandshake()
		if err != nil {
			t.Fatalf("[%d:1] clientHandshake.generateHandshake() failed: %s", l, err)
		}
		if len(clientBlob) > maxHandshakeLength {
			t.Fatalf("[%d:1] Generated client body is oversized: %d", l, len(clientBlob))
		}

		// Generate the server state and override the pad length.
		serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
		serverHs.padLen = l

		// Parse the client handshake message.
		serverSeed, err := serverHs.parseClientHandshake(serverFilter, clientBlob)
		if err != nil {
			t.Fatalf("[%d:1] serverHandshake.parseClientHandshake() failed: %s", l, err)
		}

		// Genrate what the server will send to the client.
		serverBlob, err := serverHs.generateHandshake()
		if err != nil {
			t.Fatal("[%d:1]: serverHandshake.generateHandshake() failed: %s", l, err)
		}

		// Parse the server handshake message.
		n, clientSeed, err := clientHs.parseServerHandshake(serverBlob)
		if err != nil {
			t.Fatalf("[%d:1] clientHandshake.parseServerHandshake() failed: %s", l, err)
		}
		if n != len(serverBlob) {
			t.Fatalf("[%d:1] clientHandshake.parseServerHandshake() has bytes remaining: %d", l, n)
		}

		// Ensure the derived shared secret is the same.
		if 0 != bytes.Compare(clientSeed, serverSeed) {
			t.Fatalf("[%d:1] client/server seed mismatch", l)
		}
	}

	// Test oversized client padding.
	clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
	if err != nil {
		t.Fatalf("newClientHandshake failed: %s", err)
	}
	clientHs.padLen = clientMaxPadLength + 1
	clientBlob, err := clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced oversize) failed: %s", err)
	}
	serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (oversized)")
	}

	// Test undersized client padding.
	clientHs.padLen = clientMinPadLength - 1
	clientBlob, err = clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced undersize) failed: %s", err)
	}
	serverHs = newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (undersized)")
	}

	// Test oversized server padding.
	//
	// NB: serverMaxPadLength isn't the real maxPadLength that triggers client
	// rejection, because the implementation is written with the asusmption
	// that the PRNG_SEED is also inlined with the response.  Thus the client
	// actually accepts longer padding.  The server handshake test and this
	// test adjust around that.
	clientHs.padLen = clientMinPadLength
	clientBlob, err = clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() failed: %s", err)
	}
	serverHs = newServerHandshake(nodeID, idKeypair, serverKeypair)
	serverHs.padLen = serverMaxPadLength + inlineSeedFrameLength + 1
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err != nil {
		t.Fatalf("serverHandshake.parseClientHandshake() failed: %s", err)
	}
	serverBlob, err := serverHs.generateHandshake()
	if err != nil {
		t.Fatal("serverHandshake.generateHandshake() (forced oversize) failed: %s", err)
	}
	_, _, err = clientHs.parseServerHandshake(serverBlob)
	if err == nil {
		t.Fatalf("clientHandshake.parseServerHandshake() succeded (oversized)")
	}
}
<commit_msg>Fix minor issues pointed out by "go vet".<commit_after>/*
 * Copyright (c) 2014, Yawning Angel <yawning at torproject dot org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package obfs4

import (
	"bytes"
	"testing"

	"git.torproject.org/pluggable-transports/obfs4.git/common/ntor"
	"git.torproject.org/pluggable-transports/obfs4.git/common/replayfilter"
)

func TestHandshakeNtorClient(t *testing.T) {
	// Generate the server node id and id keypair, and ephemeral session keys.
	nodeID, _ := ntor.NewNodeID([]byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"))
	idKeypair, _ := ntor.NewKeypair(false)
	serverFilter, _ := replayfilter.New(replayTTL)
	clientKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("client: ntor.NewKeypair failed: %s", err)
	}
	serverKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("server: ntor.NewKeypair failed: %s", err)
	}

	// Test client handshake padding.
	for l := clientMinPadLength; l <= clientMaxPadLength; l++ {
		// Generate the client state and override the pad length.
		clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
		clientHs.padLen = l

		// Generate what the client will send to the server.
		clientBlob, err := clientHs.generateHandshake()
		if err != nil {
			t.Fatalf("[%d:0] clientHandshake.generateHandshake() failed: %s", l, err)
		}
		if len(clientBlob) > maxHandshakeLength {
			t.Fatalf("[%d:0] Generated client body is oversized: %d", l, len(clientBlob))
		}
		if len(clientBlob) < clientMinHandshakeLength {
			t.Fatalf("[%d:0] Generated client body is undersized: %d", l, len(clientBlob))
		}
		if len(clientBlob) != clientMinHandshakeLength+l {
			t.Fatalf("[%d:0] Generated client body incorrect size: %d", l, len(clientBlob))
		}

		// Generate the server state and override the pad length.
		serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
		serverHs.padLen = serverMinPadLength

		// Parse the client handshake message.
		serverSeed, err := serverHs.parseClientHandshake(serverFilter, clientBlob)
		if err != nil {
			t.Fatalf("[%d:0] serverHandshake.parseClientHandshake() failed: %s", l, err)
		}

		// Genrate what the server will send to the client.
		serverBlob, err := serverHs.generateHandshake()
		if err != nil {
			t.Fatalf("[%d:0]: serverHandshake.generateHandshake() failed: %s", l, err)
		}

		// Parse the server handshake message.
		clientHs.serverRepresentative = nil
		n, clientSeed, err := clientHs.parseServerHandshake(serverBlob)
		if err != nil {
			t.Fatalf("[%d:0] clientHandshake.parseServerHandshake() failed: %s", l, err)
		}
		if n != len(serverBlob) {
			t.Fatalf("[%d:0] clientHandshake.parseServerHandshake() has bytes remaining: %d", l, n)
		}

		// Ensure the derived shared secret is the same.
		if 0 != bytes.Compare(clientSeed, serverSeed) {
			t.Fatalf("[%d:0] client/server seed mismatch", l)
		}
	}

	// Test oversized client padding.
	clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
	if err != nil {
		t.Fatalf("newClientHandshake failed: %s", err)
	}
	clientHs.padLen = clientMaxPadLength + 1
	clientBlob, err := clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced oversize) failed: %s", err)
	}
	serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (oversized)")
	}

	// Test undersized client padding.
	clientHs.padLen = clientMinPadLength - 1
	clientBlob, err = clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced undersize) failed: %s", err)
	}
	serverHs = newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (undersized)")
	}
}

func TestHandshakeNtorServer(t *testing.T) {
	// Generate the server node id and id keypair, and ephemeral session keys.
	nodeID, _ := ntor.NewNodeID([]byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"))
	idKeypair, _ := ntor.NewKeypair(false)
	serverFilter, _ := replayfilter.New(replayTTL)
	clientKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("client: ntor.NewKeypair failed: %s", err)
	}
	serverKeypair, err := ntor.NewKeypair(true)
	if err != nil {
		t.Fatalf("server: ntor.NewKeypair failed: %s", err)
	}

	// Test server handshake padding.
	for l := serverMinPadLength; l <= serverMaxPadLength+inlineSeedFrameLength; l++ {
		// Generate the client state and override the pad length.
		clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
		clientHs.padLen = clientMinPadLength

		// Generate what the client will send to the server.
		clientBlob, err := clientHs.generateHandshake()
		if err != nil {
			t.Fatalf("[%d:1] clientHandshake.generateHandshake() failed: %s", l, err)
		}
		if len(clientBlob) > maxHandshakeLength {
			t.Fatalf("[%d:1] Generated client body is oversized: %d", l, len(clientBlob))
		}

		// Generate the server state and override the pad length.
		serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
		serverHs.padLen = l

		// Parse the client handshake message.
		serverSeed, err := serverHs.parseClientHandshake(serverFilter, clientBlob)
		if err != nil {
			t.Fatalf("[%d:1] serverHandshake.parseClientHandshake() failed: %s", l, err)
		}

		// Genrate what the server will send to the client.
		serverBlob, err := serverHs.generateHandshake()
		if err != nil {
			t.Fatalf("[%d:1]: serverHandshake.generateHandshake() failed: %s", l, err)
		}

		// Parse the server handshake message.
		n, clientSeed, err := clientHs.parseServerHandshake(serverBlob)
		if err != nil {
			t.Fatalf("[%d:1] clientHandshake.parseServerHandshake() failed: %s", l, err)
		}
		if n != len(serverBlob) {
			t.Fatalf("[%d:1] clientHandshake.parseServerHandshake() has bytes remaining: %d", l, n)
		}

		// Ensure the derived shared secret is the same.
		if 0 != bytes.Compare(clientSeed, serverSeed) {
			t.Fatalf("[%d:1] client/server seed mismatch", l)
		}
	}

	// Test oversized client padding.
	clientHs := newClientHandshake(nodeID, idKeypair.Public(), clientKeypair)
	if err != nil {
		t.Fatalf("newClientHandshake failed: %s", err)
	}
	clientHs.padLen = clientMaxPadLength + 1
	clientBlob, err := clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced oversize) failed: %s", err)
	}
	serverHs := newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (oversized)")
	}

	// Test undersized client padding.
	clientHs.padLen = clientMinPadLength - 1
	clientBlob, err = clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() (forced undersize) failed: %s", err)
	}
	serverHs = newServerHandshake(nodeID, idKeypair, serverKeypair)
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err == nil {
		t.Fatalf("serverHandshake.parseClientHandshake() succeded (undersized)")
	}

	// Test oversized server padding.
	//
	// NB: serverMaxPadLength isn't the real maxPadLength that triggers client
	// rejection, because the implementation is written with the asusmption
	// that the PRNG_SEED is also inlined with the response.  Thus the client
	// actually accepts longer padding.  The server handshake test and this
	// test adjust around that.
	clientHs.padLen = clientMinPadLength
	clientBlob, err = clientHs.generateHandshake()
	if err != nil {
		t.Fatalf("clientHandshake.generateHandshake() failed: %s", err)
	}
	serverHs = newServerHandshake(nodeID, idKeypair, serverKeypair)
	serverHs.padLen = serverMaxPadLength + inlineSeedFrameLength + 1
	_, err = serverHs.parseClientHandshake(serverFilter, clientBlob)
	if err != nil {
		t.Fatalf("serverHandshake.parseClientHandshake() failed: %s", err)
	}
	serverBlob, err := serverHs.generateHandshake()
	if err != nil {
		t.Fatalf("serverHandshake.generateHandshake() (forced oversize) failed: %s", err)
	}
	_, _, err = clientHs.parseServerHandshake(serverBlob)
	if err == nil {
		t.Fatalf("clientHandshake.parseServerHandshake() succeded (oversized)")
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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.

package view

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/google/shenzhen-go/dev/dom"
	"github.com/google/shenzhen-go/dev/model"
)

type fakeGraphController struct{}

func (c fakeGraphController) Graph() *model.Graph          { return nil }
func (c fakeGraphController) GainFocus()                   {}
func (c fakeGraphController) LoseFocus()                   {}
func (c fakeGraphController) Nodes(f func(NodeController)) { f(fakeNodeController{}) }

func (c fakeGraphController) Node(name string) NodeController {
	if name != "Node 1" {
		return nil
	}
	return fakeNodeController{}
}

func (c fakeGraphController) NumNodes() int                         { return 1 }
func (c fakeGraphController) Channel(name string) ChannelController { return nil }
func (c fakeGraphController) Channels(f func(ChannelController))    {}
func (c fakeGraphController) NumChannels() int                      { return 0 }

func (c fakeGraphController) CreateChannel(...PinController) (ChannelController, error) {
	return nil, nil
}

func (c fakeGraphController) CreateNode(ctx context.Context, partType string) (NodeController, error) {
	return nil, nil
}

func (c fakeGraphController) Save(ctx context.Context) error           { return nil }
func (c fakeGraphController) SaveProperties(ctx context.Context) error { return nil }

type fakeNodeController struct{}

func (f fakeNodeController) Name() string             { return "Node 1" }
func (f fakeNodeController) Position() (x, y float64) { return 150, 150 }

func (f fakeNodeController) Pins(x func(PinController)) {
	x(fakePinController("input"))
	x(fakePinController("output"))
	x(fakePinController("output 2"))
}

func (f fakeNodeController) GainFocus() {}
func (f fakeNodeController) LoseFocus() {}

func (f fakeNodeController) Delete(context.Context) error                        { return nil }
func (f fakeNodeController) Save(context.Context) error                          { return nil }
func (f fakeNodeController) SetPosition(context.Context, float64, float64) error { return nil }
func (f fakeNodeController) ShowMetadataSubpanel()                               {}
func (f fakeNodeController) ShowPartSubpanel(string)                             {}

type fakePinController string

func (f fakePinController) Name() string  { return string(f) }
func (f fakePinController) Type() string  { return "int" }
func (f fakePinController) IsInput() bool { return f == "input" }

func (f fakePinController) Attach(ctx context.Context, cc ChannelController) error { return nil }
func (f fakePinController) Detach(ctx context.Context) error                       { return nil }

func TestGraphRefreshFromEmpty(t *testing.T) {
	doc := dom.MakeFakeDocument()
	v := &View{
		doc:     doc,
		diagram: doc.MakeSVGElement("svg"),
	}
	v.graph = &Graph{
		view: v,
		gc:   fakeGraphController{},
		doc:  doc,
	}
	v.graph.makeElements(doc, v.diagram)
	v.graph.refresh()

	if v.graph.Channels == nil {
		t.Fatal("v.graph.Channels = nil, want non-nil map")
	}
	if v.graph.Nodes == nil {
		t.Fatal("v.graph.Nodes = nil, want non-nil map")
	}
	node1 := v.graph.Nodes["Node 1"]
	if node1 == nil {
		t.Fatal("v.graph.Nodes[Node 1] = nil, want non-nil node")
	}
	if got, want := len(node1.Inputs), 1; got != want {
		t.Errorf("len(Nodes[Node 1].Inputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.Outputs), 2; got != want {
		t.Errorf("len(Nodes[Node 1].Outputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.AllPins), 3; got != want {
		t.Errorf("len(Nodes[Node 1].AllPins) = %d, want %d", got, want)
	}

	// Was checking "wholeText" property before, but this is with the fakes - how did that ever pass?
	if got, want := node1.TextBox.TextNode.Get("nodeValue").String(), "Node 1"; got != want {
		t.Errorf("Node 1 text = %q, want %q", got, want)
	}
}
<commit_msg>Down to only one direct use of model from view.<commit_after>// Copyright 2017 Google Inc.
//
// 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.

package view

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/google/shenzhen-go/dev/dom"
)

type fakeGraphController struct{}

func (c fakeGraphController) GainFocus()                   {}
func (c fakeGraphController) LoseFocus()                   {}
func (c fakeGraphController) Nodes(f func(NodeController)) { f(fakeNodeController{}) }

func (c fakeGraphController) Node(name string) NodeController {
	if name != "Node 1" {
		return nil
	}
	return fakeNodeController{}
}

func (c fakeGraphController) NumNodes() int                         { return 1 }
func (c fakeGraphController) Channel(name string) ChannelController { return nil }
func (c fakeGraphController) Channels(f func(ChannelController))    {}
func (c fakeGraphController) NumChannels() int                      { return 0 }

func (c fakeGraphController) CreateChannel(...PinController) (ChannelController, error) {
	return nil, nil
}

func (c fakeGraphController) CreateNode(ctx context.Context, partType string) (NodeController, error) {
	return nil, nil
}

func (c fakeGraphController) Save(ctx context.Context) error           { return nil }
func (c fakeGraphController) SaveProperties(ctx context.Context) error { return nil }

type fakeNodeController struct{}

func (f fakeNodeController) Name() string             { return "Node 1" }
func (f fakeNodeController) Position() (x, y float64) { return 150, 150 }

func (f fakeNodeController) Pins(x func(PinController)) {
	x(fakePinController("input"))
	x(fakePinController("output"))
	x(fakePinController("output 2"))
}

func (f fakeNodeController) GainFocus() {}
func (f fakeNodeController) LoseFocus() {}

func (f fakeNodeController) Delete(context.Context) error                        { return nil }
func (f fakeNodeController) Save(context.Context) error                          { return nil }
func (f fakeNodeController) SetPosition(context.Context, float64, float64) error { return nil }
func (f fakeNodeController) ShowMetadataSubpanel()                               {}
func (f fakeNodeController) ShowPartSubpanel(string)                             {}

type fakePinController string

func (f fakePinController) Name() string  { return string(f) }
func (f fakePinController) Type() string  { return "int" }
func (f fakePinController) IsInput() bool { return f == "input" }

func (f fakePinController) Attach(ctx context.Context, cc ChannelController) error { return nil }
func (f fakePinController) Detach(ctx context.Context) error                       { return nil }

func TestGraphRefreshFromEmpty(t *testing.T) {
	doc := dom.MakeFakeDocument()
	v := &View{
		doc:     doc,
		diagram: doc.MakeSVGElement("svg"),
	}
	v.graph = &Graph{
		view: v,
		gc:   fakeGraphController{},
		doc:  doc,
	}
	v.graph.makeElements(doc, v.diagram)
	v.graph.refresh()

	if v.graph.Channels == nil {
		t.Fatal("v.graph.Channels = nil, want non-nil map")
	}
	if v.graph.Nodes == nil {
		t.Fatal("v.graph.Nodes = nil, want non-nil map")
	}
	node1 := v.graph.Nodes["Node 1"]
	if node1 == nil {
		t.Fatal("v.graph.Nodes[Node 1] = nil, want non-nil node")
	}
	if got, want := len(node1.Inputs), 1; got != want {
		t.Errorf("len(Nodes[Node 1].Inputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.Outputs), 2; got != want {
		t.Errorf("len(Nodes[Node 1].Outputs) = %d, want %d", got, want)
	}
	if got, want := len(node1.AllPins), 3; got != want {
		t.Errorf("len(Nodes[Node 1].AllPins) = %d, want %d", got, want)
	}

	// Was checking "wholeText" property before, but this is with the fakes - how did that ever pass?
	if got, want := node1.TextBox.TextNode.Get("nodeValue").String(), "Node 1"; got != want {
		t.Errorf("Node 1 text = %q, want %q", got, want)
	}
}
<|endoftext|>


<commit_before>package drivers

import (
	"database/sql"
	"reflect"
	"errors"
	"strconv"
	"strings"
)

type GoedbSQLDriver struct{
	db     *sql.DB
	tables map[string]GoedbTable
}

func init(){

}

func (sqld *GoedbSQLDriver) Open(driver string, params string) error{
	db, err := sql.Open(driver, params)
	if err != nil {
		return err
	}

	err = db.Ping() // Send a ping to make sure the database connection is alive.
	if err != nil {
		db.Close()
		return err
	}

	sqld.db = db
	if sqld.tables == nil {
		sqld.tables = make(map[string]GoedbTable)
	}

	if driver == "sqlite3" {
		sqld.db.Exec("PRAGMA foreign_keys = ON")
	}
	return nil

}

func (sqld *GoedbSQLDriver) Close() error{
	if sqld.db == nil {
		return errors.New("DB is closed")
	}
	return sqld.db.Close()
}

func (sqld *GoedbSQLDriver) Migrate(i interface{}) (error){
	sqld.DropTable(i)
	table := parseModel(i)
	sqld.tables[table.Name] = table
	sqltab := getSQLTableModel(table)
	_, err := sqld.db.Exec(sqltab)
	return err
}

func (sqld *GoedbSQLDriver) Model(i interface{}) (GoedbTable, error){
	var q GoedbTable
	if q, ok := sqld.tables[getType(i).Name()]; ok{
		return q, nil
	}
	return q, errors.New("Model not found")
}

func (sqld *GoedbSQLDriver) Insert(i interface{})(GoedbResult, error){
	var result sql.Result
	var goedbres GoedbResult

	model,err := sqld.Model(i)
	if err != nil {
		return goedbres, err
	}
	columns, values := getColumnsAndValues(model, i)
	sql := "INSERT INTO "+model.Name +" ("+columns+") values("+values+")"
	result, err = sqld.db.Exec(sql)
	if err != nil {
		return goedbres, err
	}

	goedbres.NumRecordsAffected, _ = result.RowsAffected()
	return goedbres, nil
}

func (sqld *GoedbSQLDriver) Remove(i interface{})(GoedbResult, error){
	var result sql.Result
	var goedbres GoedbResult

	model,err := sqld.Model(i)
	if err != nil {
		return goedbres, err
	}

	pkc, pkv, err := getPKs(model, i)
	if err != nil {
		return goedbres, err
	}

	sql := "DELETE FROM "+model.Name +" WHERE "+pkc+ "=" + pkv
	result, err = sqld.db.Exec(sql)
	if err != nil {
		return goedbres, err
	}

	goedbres.NumRecordsAffected, _ = result.RowsAffected()
	return goedbres, err
}

func (sqld *GoedbSQLDriver) First(i interface{}, where string) (error){
	model,err := sqld.Model(i)
	if err != nil {
		return err
	}

	var sql string
	if where == "" {
		pkc, pkv, err := getPKs(model, i)
		if err != nil {
			return errors.New("Error getting primary key")
		}
		sql = "SELECT * FROM " + model.Name + " WHERE " + pkc + "=" + pkv
	}else{
		sql = "SELECT * FROM " + model.Name + " WHERE " + where
	}

	rows, err := sqld.db.Query(sql)
	if err != nil{
		return err
	}
	defer rows.Close()

	valuePtrs := structToSliceOfFieldAddress(i)

	if !rows.Next() {
		return errors.New("Record not found")
	}

	rows.Scan(valuePtrs...)
	return nil
}

func (sqld *GoedbSQLDriver) Find(i interface{}, where string) error{
	model,err := sqld.Model(i)
	if err != nil {
		return err
	}

	var sql string

	if where == "" {
		sql = "SELECT * FROM " + model.Name
	}else{
		sql = "SELECT * FROM " + model.Name + " WHERE " + where
	}

	rows, err := sqld.db.Query(sql)
	if err != nil {
		return err
	}

	slicePtr := reflect.ValueOf(i)
	slice := reflect.Indirect(slicePtr)

	slType := getType(i)

	if !rows.Next() {
		return errors.New("Records not found")
	}

	for {
		ptr := reflect.New(slType)

		valuePtrs := structToSliceOfFieldAddress(ptr)
		rows.Scan(valuePtrs...)

		slice.Set(reflect.Append(slice, ptr.Elem()))

		if !rows.Next() { break }
	}

	return nil
}

func (sqld *GoedbSQLDriver) DropTable(i interface{}) error{
	typ := getType(i)
	name := typ.Name()

	_, err := sqld.db.Exec("DROP TABLE "+name)
	if err != nil {
		return err
	}
	delete(sqld.tables, name)
	return nil
}

/* ======================================
	    Support functions
   ====================================== */

func getType(i interface{}) (reflect.Type){
	typ := reflect.TypeOf(i)

	// if a pointer to a struct is passed, get the type of the dereferenced object
	if typ.Kind() == reflect.Ptr{
		typ = typ.Elem()
	}

	if typ.Kind() == reflect.Slice{
		typ = typ.Elem()
	}

	return typ
}

func getSQLColumnModel(value GoedbColumn) (string, string, string, error){
	var pksFound string
	var constraints string
	column := value.Title

	switch value.Ctype {
	case "char":
		column += " CHARACTER"
	case  "int8", "int16", "int32", "int",  "uint8", "uint16", "uint32", "uint":
		column += " INTEGER"
	case "int64", "uint64":
		column += " BIGINT"
	case "float32", "float64":
		column += " FLOAT"
	case "bool":
		column += " BOOLEAN"
	case "string":
		column += " VARCHAR"
	default:
		return "","","",errors.New("Type unkown")
	}

	if value.Unique {
		column += " UNIQUE"
	}

	if value.Autoinc {
		column += " AUTOINCREMENT"
	}

	if value.Pk {
		pksFound += value.Title+","
	}

	if value.Fk {
		constraints += ", FOREIGN KEY ("+value.Title +") REFERENCES "+value.Fkref +" ON DELETE CASCADE"
	}
	column += ","

	return column, pksFound, constraints, nil
}

func getSQLTableModel(table GoedbTable) (string){
	columns := ""
	pksFound := ""
	constraints := ""

	for _, value := range table.Columns {
		columnModel, pksColModel, constModel, err := getSQLColumnModel(value)
		if err != nil {
			continue
		}
		columns += columnModel
		pksFound += pksColModel
		constraints += constModel

	}
	if len(pksFound) > 0 {
		pksFound = pksFound[:len(pksFound)-1]
		constraints += ", PRIMARY KEY ("+ pksFound +")"
	}

	lastColumnIndex := len(columns)
	return "CREATE TABLE "+table.Name +" (" +columns[:lastColumnIndex-1] + constraints+")"
}

func getPKs(gt GoedbTable, obj interface{}) (string, string, error){
	val := reflect.ValueOf(obj)

	if val.Kind() == reflect.Ptr{
		val = val.Elem()
	}

	for i:=0;i<len(gt.Columns);i++ {
		v := val.Field(i)
		if gt.Columns[i].Pk {
			switch gt.Columns[i].Ctype {
			case  "int8", "int16", "int32", "int",  "uint8", "uint16", "uint32", "uint", "int64", "uint64":
				return gt.Columns[i].Title, strconv.FormatInt(v.Int(), 10), nil
			case "float32", "float64":
				return gt.Columns[i].Title, strconv.FormatFloat(v.Float(), 'f', 6, 64), nil
			case "bool":
				if v.Bool() {
					return gt.Columns[i].Title, "1", nil
				}else{
					return gt.Columns[i].Title, "0", nil
				}
			case "string","char":
				return gt.Columns[i].Title, "'"+v.String()+"'", nil
			}
		}
	}

	return "", "", errors.New("No PK found")
}

func structToSliceOfFieldAddress(s interface{}) []interface{} {

	var fieldArr reflect.Value
	if _, ok  := s.(reflect.Value); ok{
		fieldArr = s.(reflect.Value)
	}else{
		fieldArr = reflect.ValueOf(s).Elem()
	}

	if fieldArr.Kind() == reflect.Ptr{
		fieldArr = fieldArr.Elem()
	}

	fieldAddrArr := make([]interface{}, fieldArr.NumField())

	for i := 0; i < fieldArr.NumField(); i++ {
		f := fieldArr.Field(i)
		fieldAddrArr[i] = f.Addr().Interface()
	}

	return fieldAddrArr
}

func getColumnsAndValues(gt GoedbTable, obj interface{}) (string, string){
	strCols := ""
	strValues := ""

	val := reflect.ValueOf(obj)

	if val.Kind() == reflect.Ptr{
		val = val.Elem()
	}

	for i:=0;i<len(gt.Columns);i++ {
		v := val.Field(i)
		switch gt.Columns[i].Ctype {
		case  "int8", "int16", "int32", "int",  "uint8", "uint16", "uint32", "uint", "int64", "uint64":
			strValues += strconv.FormatInt(v.Int(), 10)+","
		case "float32", "float64":
			strValues += strconv.FormatFloat(v.Float(), 'f', 6, 64)+","
		case "bool":
			if v.Bool() {
				strValues += "1,"
			}else{
				strValues += "0,"
			}
		case "string","char":
			strValues += "'"+v.String()+"',"
		}
		strCols += gt.Columns[i].Title + ","

	}

	return strCols[:len(strCols)-1], strValues[:len(strValues)-1]
}

func parseModel(model interface{}) (GoedbTable){
	typ := reflect.TypeOf(model)

	// if a pointer to a struct is passed, get the type of the dereferenced object
	if typ.Kind() == reflect.Ptr{
		typ = typ.Elem()
	}

	table := GoedbTable{}
	table.Name = typ.Name()
	table.Columns = make([]GoedbColumn, 0)

	for i:=0;i<typ.NumField();i++ {
		tablecol := GoedbColumn{}
		tablecol.Title = typ.Field(i).Name
		tablecol.Ctype = typ.Field(i).Type.Name()

		if tag, ok := typ.Field(i).Tag.Lookup("goedb"); ok {
			params := strings.Split(tag, ",")
			for _, val := range params {
				switch val {
				case "pk":
					tablecol.Pk = true
				case "autoincrement":
					tablecol.Autoinc = true
				case "unique":
					tablecol.Unique = true
				default:
					if strings.Contains(val, "fk=") {
						tablecol.Fk = true
						tablecol.Fkref = strings.Split(val, "=")[1]
					}
				}
			}
		}
		table.Columns = append(table.Columns, tablecol)
	}

	return table
}<commit_msg>Minor refactoring<commit_after>package drivers

import (
	"database/sql"
	"reflect"
	"errors"
	"strconv"
	"strings"
)

type GoedbSQLDriver struct{
	db     *sql.DB
	tables map[string]GoedbTable
}

func init(){

}

func (sqld *GoedbSQLDriver) Open(driver string, params string) error{
	db, err := sql.Open(driver, params)
	if err != nil {
		return err
	}

	err = db.Ping() // Send a ping to make sure the database connection is alive.
	if err != nil {
		db.Close()
		return err
	}

	sqld.db = db
	if sqld.tables == nil {
		sqld.tables = make(map[string]GoedbTable)
	}

	if driver == "sqlite3" {
		sqld.db.Exec("PRAGMA foreign_keys = ON")
	}
	return nil

}

func (sqld *GoedbSQLDriver) Close() error{
	if sqld.db == nil {
		return errors.New("DB is closed")
	}
	return sqld.db.Close()
}

func (sqld *GoedbSQLDriver) Migrate(i interface{}) (error){
	sqld.DropTable(i)
	table := parseModel(i)
	sqld.tables[table.Name] = table
	sqltab := getSQLTableModel(table)
	_, err := sqld.db.Exec(sqltab)
	return err
}

func (sqld *GoedbSQLDriver) Model(i interface{}) (GoedbTable, error){
	var q GoedbTable
	if q, ok := sqld.tables[getType(i).Name()]; ok{
		return q, nil
	}
	return q, errors.New("Model not found")
}

func (sqld *GoedbSQLDriver) Insert(i interface{})(GoedbResult, error){
	var result sql.Result
	var goedbres GoedbResult

	model,err := sqld.Model(i)
	if err != nil {
		return goedbres, err
	}
	columns, values := getColumnsAndValues(model, i)
	sql := "INSERT INTO "+model.Name +" ("+columns+") values("+values+")"
	result, err = sqld.db.Exec(sql)
	if err != nil {
		return goedbres, err
	}

	goedbres.NumRecordsAffected, _ = result.RowsAffected()
	return goedbres, nil
}

func (sqld *GoedbSQLDriver) Remove(i interface{})(GoedbResult, error){
	var result sql.Result
	var goedbres GoedbResult

	model,err := sqld.Model(i)
	if err != nil {
		return goedbres, err
	}

	pkc, pkv, err := getPKs(model, i)
	if err != nil {
		return goedbres, err
	}

	sql := "DELETE FROM "+model.Name +" WHERE "+pkc+ "=" + pkv
	result, err = sqld.db.Exec(sql)
	if err != nil {
		return goedbres, err
	}

	goedbres.NumRecordsAffected, _ = result.RowsAffected()
	return goedbres, err
}

func (sqld *GoedbSQLDriver) First(i interface{}, where string) (error){
	model,err := sqld.Model(i)
	if err != nil {
		return err
	}

	var sql string
	if where == "" {
		pkc, pkv, err := getPKs(model, i)
		if err != nil {
			return errors.New("Error getting primary key")
		}
		sql = "SELECT * FROM " + model.Name + " WHERE " + pkc + "=" + pkv
	}else{
		sql = "SELECT * FROM " + model.Name + " WHERE " + where
	}

	rows, err := sqld.db.Query(sql)
	if err != nil{
		return err
	}
	defer rows.Close()

	valuePtrs := structToSliceOfFieldAddress(i)

	if !rows.Next() {
		return errors.New("Record not found")
	}

	rows.Scan(valuePtrs...)
	return nil
}

func (sqld *GoedbSQLDriver) Find(resultEntitySlice interface{}, where string) error{
	model,err := sqld.Model(resultEntitySlice)
	if err != nil {
		return err
	}

	var sqlQuery string

	if where != "" {
		where = " WHERE "+ where
	}

	sqlQuery = "SELECT * FROM " + model.Name + where
	rows, err := sqld.db.Query(sqlQuery)
	if err != nil {
		return err
	}

	//Creates a new pointer with the same type that resultEntitySlice
	slicePtr := reflect.ValueOf(resultEntitySlice)
	//it gets the value of the slice pointer
	slice := reflect.Indirect(slicePtr)

	entityType := getType(resultEntitySlice)

	if !rows.Next() {
		return errors.New("Records not found")
	}

	for {
		entityPtr := reflect.New(entityType)

		entityFieldsAsSlice := structToSliceOfFieldAddress(entityPtr)
		rows.Scan(entityFieldsAsSlice...)

		slice.Set(reflect.Append(slice, entityPtr.Elem()))

		if !rows.Next() { break }
	}

	return nil
}

func (sqld *GoedbSQLDriver) DropTable(i interface{}) error{
	typ := getType(i)
	name := typ.Name()

	_, err := sqld.db.Exec("DROP TABLE "+name)
	if err != nil {
		return err
	}
	delete(sqld.tables, name)
	return nil
}

/* ======================================
	    Support functions
   ====================================== */

func getType(i interface{}) (reflect.Type){
	typ := reflect.TypeOf(i)

	// if a pointer to a struct is passed, get the type of the dereferenced object
	if typ.Kind() == reflect.Ptr{
		typ = typ.Elem()
	}

	if typ.Kind() == reflect.Slice{
		typ = typ.Elem()
	}

	return typ
}

func getSQLColumnModel(value GoedbColumn) (string, string, string, error){
	var pksFound string
	var constraints string
	column := value.Title

	switch value.Ctype {
	case "char":
		column += " CHARACTER"
	case  "int8", "int16", "int32", "int",  "uint8", "uint16", "uint32", "uint":
		column += " INTEGER"
	case "int64", "uint64":
		column += " BIGINT"
	case "float32", "float64":
		column += " FLOAT"
	case "bool":
		column += " BOOLEAN"
	case "string":
		column += " VARCHAR"
	default:
		return "","","",errors.New("Type unkown")
	}

	if value.Unique {
		column += " UNIQUE"
	}

	if value.Autoinc {
		column += " AUTOINCREMENT"
	}

	if value.Pk {
		pksFound += value.Title+","
	}

	if value.Fk {
		constraints += ", FOREIGN KEY ("+value.Title +") REFERENCES "+value.Fkref +" ON DELETE CASCADE"
	}
	column += ","

	return column, pksFound, constraints, nil
}

func getSQLTableModel(table GoedbTable) (string){
	columns := ""
	pksFound := ""
	constraints := ""

	for _, value := range table.Columns {
		columnModel, pksColModel, constModel, err := getSQLColumnModel(value)
		if err != nil {
			continue
		}
		columns += columnModel
		pksFound += pksColModel
		constraints += constModel
	}

	if len(pksFound) > 0 {
		pksFound = pksFound[:len(pksFound)-1]
		constraints += ", PRIMARY KEY ("+ pksFound +")"
	}

	lastColumnIndex := len(columns)
	return "CREATE TABLE "+table.Name +" (" +columns[:lastColumnIndex-1] + constraints+")"
}

func getPKs(gt GoedbTable, obj interface{}) (string, string, error){
	val := reflect.ValueOf(obj)

	if val.Kind() == reflect.Ptr{
		val = val.Elem()
	}

	for i:=0;i<len(gt.Columns);i++ {
		v := val.Field(i)
		if gt.Columns[i].Pk {
			switch gt.Columns[i].Ctype {
			case  "int8", "int16", "int32", "int",  "uint8", "uint16", "uint32", "uint", "int64", "uint64":
				return gt.Columns[i].Title, strconv.FormatInt(v.Int(), 10), nil
			case "float32", "float64":
				return gt.Columns[i].Title, strconv.FormatFloat(v.Float(), 'f', 6, 64), nil
			case "bool":
				if v.Bool() {
					return gt.Columns[i].Title, "1", nil
				}else{
					return gt.Columns[i].Title, "0", nil
				}
			case "string","char":
				return gt.Columns[i].Title, "'"+v.String()+"'", nil
			}
		}
	}

	return "", "", errors.New("No PK found")
}

/*
	Returns a slice with the addresses of each struct field,
	so any modification on the slide will modify the source struct fields
 */
func structToSliceOfFieldAddress(structPtr interface{}) []interface{} {

	var fieldArr reflect.Value
	if _, ok  := structPtr.(reflect.Value); ok{
		fieldArr = structPtr.(reflect.Value)
	}else{
		fieldArr = reflect.ValueOf(structPtr).Elem()
	}

	if fieldArr.Kind() == reflect.Ptr{
		fieldArr = fieldArr.Elem()
	}

	fieldAddrArr := make([]interface{}, fieldArr.NumField())

	for i := 0; i < fieldArr.NumField(); i++ {
		f := fieldArr.Field(i)
		fieldAddrArr[i] = f.Addr().Interface()
	}

	return fieldAddrArr
}

/*
	Returns columns names and values for inserting values
 */
func getColumnsAndValues(gt GoedbTable, obj interface{}) (string, string){
	strCols := ""
	strValues := ""

	val := reflect.ValueOf(obj)

	if val.Kind() == reflect.Ptr{
		val = val.Elem()
	}

	for i:=0;i<len(gt.Columns);i++ {
		v := val.Field(i)
		switch gt.Columns[i].Ctype {
		case  "int8", "int16", "int32", "int",  "uint8", "uint16", "uint32", "uint", "int64", "uint64":
			strValues += strconv.FormatInt(v.Int(), 10)+","
		case "float32", "float64":
			strValues += strconv.FormatFloat(v.Float(), 'f', 6, 64)+","
		case "bool":
			if v.Bool() {
				strValues += "1,"
			}else{
				strValues += "0,"
			}
		case "string","char":
			strValues += "'"+v.String()+"',"
		}
		strCols += gt.Columns[i].Title + ","
	}

	return strCols[:len(strCols)-1], strValues[:len(strValues)-1]
}

func parseModel(model interface{}) (GoedbTable){
	typ := reflect.TypeOf(model)

	// if a pointer to a struct is passed, get the type of the dereferenced object
	if typ.Kind() == reflect.Ptr{
		typ = typ.Elem()
	}

	table := GoedbTable{}
	table.Name = typ.Name()
	table.Columns = make([]GoedbColumn, 0)

	for i:=0;i<typ.NumField();i++ {
		tablecol := GoedbColumn{}
		tablecol.Title = typ.Field(i).Name
		tablecol.Ctype = typ.Field(i).Type.Name()

		if tag, ok := typ.Field(i).Tag.Lookup("goedb"); ok {
			params := strings.Split(tag, ",")
			for _, val := range params {
				switch val {
				case "pk":
					tablecol.Pk = true
				case "autoincrement":
					tablecol.Autoinc = true
				case "unique":
					tablecol.Unique = true
				default:
					if strings.Contains(val, "fk=") {
						tablecol.Fk = true
						tablecol.Fkref = strings.Split(val, "=")[1]
					}
				}
			}
		}
		table.Columns = append(table.Columns, tablecol)
	}

	return table
}<|endoftext|>


<commit_before>package terraform

import (
	"bytes"
	"fmt"
	"sort"
	"sync"

	"github.com/hashicorp/terraform/config"
)

// StateV1 is used to represent the state of Terraform files before
// 0.3. It is automatically upgraded to a modern State representation
// on start.
type StateV1 struct {
	Outputs   map[string]string
	Resources map[string]*ResourceState
	Tainted   map[string]struct{}

	once sync.Once
}

func (s *State) init() {
	s.once.Do(func() {
		if s.Resources == nil {
			s.Resources = make(map[string]*ResourceState)
		}

		if s.Tainted == nil {
			s.Tainted = make(map[string]struct{})
		}
	})
}

func (s *State) deepcopy() *State {
	result := new(State)
	result.init()
	if s != nil {
		for k, v := range s.Resources {
			result.Resources[k] = v
		}
		for k, v := range s.Tainted {
			result.Tainted[k] = v
		}
	}

	return result
}

// prune is a helper that removes any empty IDs from the state
// and cleans it up in general.
func (s *State) prune() {
	for k, v := range s.Resources {
		if v.ID == "" {
			delete(s.Resources, k)
		}
	}
}

// Orphans returns a list of keys of resources that are in the State
// but aren't present in the configuration itself. Hence, these keys
// represent the state of resources that are orphans.
func (s *State) Orphans(c *config.Config) []string {
	keys := make(map[string]struct{})
	for k, _ := range s.Resources {
		keys[k] = struct{}{}
	}

	for _, r := range c.Resources {
		delete(keys, r.Id())

		// Mark all the counts as not orphans.
		for i := 0; i < r.Count; i++ {
			delete(keys, fmt.Sprintf("%s.%d", r.Id(), i))
		}
	}

	result := make([]string, 0, len(keys))
	for k, _ := range keys {
		result = append(result, k)
	}

	return result
}

func (s *State) String() string {
	if len(s.Resources) == 0 {
		return "<no state>"
	}

	var buf bytes.Buffer

	names := make([]string, 0, len(s.Resources))
	for name, _ := range s.Resources {
		names = append(names, name)
	}
	sort.Strings(names)

	for _, k := range names {
		rs := s.Resources[k]
		id := rs.ID
		if id == "" {
			id = "<not created>"
		}

		taintStr := ""
		if _, ok := s.Tainted[k]; ok {
			taintStr = " (tainted)"
		}

		buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr))
		buf.WriteString(fmt.Sprintf("  ID = %s\n", id))

		attrKeys := make([]string, 0, len(rs.Attributes))
		for ak, _ := range rs.Attributes {
			if ak == "id" {
				continue
			}

			attrKeys = append(attrKeys, ak)
		}
		sort.Strings(attrKeys)

		for _, ak := range attrKeys {
			av := rs.Attributes[ak]
			buf.WriteString(fmt.Sprintf("  %s = %s\n", ak, av))
		}

		if len(rs.Dependencies) > 0 {
			buf.WriteString(fmt.Sprintf("\n  Dependencies:\n"))
			for _, dep := range rs.Dependencies {
				buf.WriteString(fmt.Sprintf("    %s\n", dep.ID))
			}
		}
	}

	if len(s.Outputs) > 0 {
		buf.WriteString("\nOutputs:\n\n")

		ks := make([]string, 0, len(s.Outputs))
		for k, _ := range s.Outputs {
			ks = append(ks, k)
		}
		sort.Strings(ks)

		for _, k := range ks {
			v := s.Outputs[k]
			buf.WriteString(fmt.Sprintf("%s = %s\n", k, v))
		}
	}

	return buf.String()
}

// sensitiveState is used to store sensitive state information
// that should not be serialized. This is only used temporarily
// and is restored into the state.
type sensitiveState struct {
	ConnInfo map[string]map[string]string

	once sync.Once
}

func (s *sensitiveState) init() {
	s.once.Do(func() {
		s.ConnInfo = make(map[string]map[string]string)
	})
}

// The format byte is prefixed into the state file format so that we have
// the ability in the future to change the file format if we want for any
// reason.
const stateFormatMagic = "tfstate"
const stateFormatVersion byte = 1

/// ResourceState holds the state of a resource that is used so that
// a provider can find and manage an existing resource as well as for
// storing attributes that are uesd to populate variables of child
// resources.
//
// Attributes has attributes about the created resource that are
// queryable in interpolation: "${type.id.attr}"
//
// Extra is just extra data that a provider can return that we store
// for later, but is not exposed in any way to the user.
type ResourceStateV1 struct {
	// This is filled in and managed by Terraform, and is the resource
	// type itself such as "mycloud_instance". If a resource provider sets
	// this value, it won't be persisted.
	Type string

	// The attributes below are all meant to be filled in by the
	// resource providers themselves. Documentation for each are above
	// each element.

	// A unique ID for this resource. This is opaque to Terraform
	// and is only meant as a lookup mechanism for the providers.
	ID string

	// Attributes are basic information about the resource. Any keys here
	// are accessible in variable format within Terraform configurations:
	// ${resourcetype.name.attribute}.
	Attributes map[string]string

	// ConnInfo is used for the providers to export information which is
	// used to connect to the resource for provisioning. For example,
	// this could contain SSH or WinRM credentials.
	ConnInfo map[string]string

	// Extra information that the provider can store about a resource.
	// This data is opaque, never shown to the user, and is sent back to
	// the provider as-is for whatever purpose appropriate.
	Extra map[string]interface{}

	// Dependencies are a list of things that this resource relies on
	// existing to remain intact. For example: an AWS instance might
	// depend on a subnet (which itself might depend on a VPC, and so
	// on).
	//
	// Terraform uses this information to build valid destruction
	// orders and to warn the user if they're destroying a resource that
	// another resource depends on.
	//
	// Things can be put into this list that may not be managed by
	// Terraform. If Terraform doesn't find a matching ID in the
	// overall state, then it assumes it isn't managed and doesn't
	// worry about it.
	Dependencies []ResourceDependency
}

// MergeDiff takes a ResourceDiff and merges the attributes into
// this resource state in order to generate a new state. This new
// state can be used to provide updated attribute lookups for
// variable interpolation.
//
// If the diff attribute requires computing the value, and hence
// won't be available until apply, the value is replaced with the
// computeID.
func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState {
	var result ResourceState
	if s != nil {
		result = *s
	}

	result.Attributes = make(map[string]string)
	if s != nil {
		for k, v := range s.Attributes {
			result.Attributes[k] = v
		}
	}
	if d != nil {
		for k, diff := range d.Attributes {
			if diff.NewRemoved {
				delete(result.Attributes, k)
				continue
			}
			if diff.NewComputed {
				result.Attributes[k] = config.UnknownVariableValue
				continue
			}

			result.Attributes[k] = diff.New
		}
	}

	return &result
}

func (s *ResourceState) GoString() string {
	return fmt.Sprintf("*%#v", *s)
}

// ResourceDependency maps a resource to another resource that it
// depends on to remain intact and uncorrupted.
type ResourceDependency struct {
	// ID of the resource that we depend on. This ID should map
	// directly to another ResourceState's ID.
	ID string
}
<commit_msg>Renaming to suffix V1 to old state structs<commit_after>package terraform

import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"
	"io"
	"sort"
	"sync"

	"github.com/hashicorp/terraform/config"
)

// The format byte is prefixed into the state file format so that we have
// the ability in the future to change the file format if we want for any
// reason.
const (
	stateFormatMagic        = "tfstate"
	stateFormatVersion byte = 1
)

// StateV1 is used to represent the state of Terraform files before
// 0.3. It is automatically upgraded to a modern State representation
// on start.
type StateV1 struct {
	Outputs   map[string]string
	Resources map[string]*ResourceState
	Tainted   map[string]struct{}

	once sync.Once
}

func (s *StateV1) init() {
	s.once.Do(func() {
		if s.Resources == nil {
			s.Resources = make(map[string]*ResourceState)
		}

		if s.Tainted == nil {
			s.Tainted = make(map[string]struct{})
		}
	})
}

func (s *StateV1) deepcopy() *State {
	result := new(State)
	result.init()
	if s != nil {
		for k, v := range s.Resources {
			result.Resources[k] = v
		}
		for k, v := range s.Tainted {
			result.Tainted[k] = v
		}
	}

	return result
}

// prune is a helper that removes any empty IDs from the state
// and cleans it up in general.
func (s *StateV1) prune() {
	for k, v := range s.Resources {
		if v.ID == "" {
			delete(s.Resources, k)
		}
	}
}

// Orphans returns a list of keys of resources that are in the State
// but aren't present in the configuration itself. Hence, these keys
// represent the state of resources that are orphans.
func (s *StateV1) Orphans(c *config.Config) []string {
	keys := make(map[string]struct{})
	for k, _ := range s.Resources {
		keys[k] = struct{}{}
	}

	for _, r := range c.Resources {
		delete(keys, r.Id())

		// Mark all the counts as not orphans.
		for i := 0; i < r.Count; i++ {
			delete(keys, fmt.Sprintf("%s.%d", r.Id(), i))
		}
	}

	result := make([]string, 0, len(keys))
	for k, _ := range keys {
		result = append(result, k)
	}

	return result
}

func (s *StateV1) String() string {
	if len(s.Resources) == 0 {
		return "<no state>"
	}

	var buf bytes.Buffer

	names := make([]string, 0, len(s.Resources))
	for name, _ := range s.Resources {
		names = append(names, name)
	}
	sort.Strings(names)

	for _, k := range names {
		rs := s.Resources[k]
		id := rs.ID
		if id == "" {
			id = "<not created>"
		}

		taintStr := ""
		if _, ok := s.Tainted[k]; ok {
			taintStr = " (tainted)"
		}

		buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr))
		buf.WriteString(fmt.Sprintf("  ID = %s\n", id))

		attrKeys := make([]string, 0, len(rs.Attributes))
		for ak, _ := range rs.Attributes {
			if ak == "id" {
				continue
			}

			attrKeys = append(attrKeys, ak)
		}
		sort.Strings(attrKeys)

		for _, ak := range attrKeys {
			av := rs.Attributes[ak]
			buf.WriteString(fmt.Sprintf("  %s = %s\n", ak, av))
		}

		if len(rs.Dependencies) > 0 {
			buf.WriteString(fmt.Sprintf("\n  Dependencies:\n"))
			for _, dep := range rs.Dependencies {
				buf.WriteString(fmt.Sprintf("    %s\n", dep.ID))
			}
		}
	}

	if len(s.Outputs) > 0 {
		buf.WriteString("\nOutputs:\n\n")

		ks := make([]string, 0, len(s.Outputs))
		for k, _ := range s.Outputs {
			ks = append(ks, k)
		}
		sort.Strings(ks)

		for _, k := range ks {
			v := s.Outputs[k]
			buf.WriteString(fmt.Sprintf("%s = %s\n", k, v))
		}
	}

	return buf.String()
}

/// ResourceState holds the state of a resource that is used so that
// a provider can find and manage an existing resource as well as for
// storing attributes that are uesd to populate variables of child
// resources.
//
// Attributes has attributes about the created resource that are
// queryable in interpolation: "${type.id.attr}"
//
// Extra is just extra data that a provider can return that we store
// for later, but is not exposed in any way to the user.
type ResourceStateV1 struct {
	// This is filled in and managed by Terraform, and is the resource
	// type itself such as "mycloud_instance". If a resource provider sets
	// this value, it won't be persisted.
	Type string

	// The attributes below are all meant to be filled in by the
	// resource providers themselves. Documentation for each are above
	// each element.

	// A unique ID for this resource. This is opaque to Terraform
	// and is only meant as a lookup mechanism for the providers.
	ID string

	// Attributes are basic information about the resource. Any keys here
	// are accessible in variable format within Terraform configurations:
	// ${resourcetype.name.attribute}.
	Attributes map[string]string

	// ConnInfo is used for the providers to export information which is
	// used to connect to the resource for provisioning. For example,
	// this could contain SSH or WinRM credentials.
	ConnInfo map[string]string

	// Extra information that the provider can store about a resource.
	// This data is opaque, never shown to the user, and is sent back to
	// the provider as-is for whatever purpose appropriate.
	Extra map[string]interface{}

	// Dependencies are a list of things that this resource relies on
	// existing to remain intact. For example: an AWS instance might
	// depend on a subnet (which itself might depend on a VPC, and so
	// on).
	//
	// Terraform uses this information to build valid destruction
	// orders and to warn the user if they're destroying a resource that
	// another resource depends on.
	//
	// Things can be put into this list that may not be managed by
	// Terraform. If Terraform doesn't find a matching ID in the
	// overall state, then it assumes it isn't managed and doesn't
	// worry about it.
	Dependencies []ResourceDependency
}

// MergeDiff takes a ResourceDiff and merges the attributes into
// this resource state in order to generate a new state. This new
// state can be used to provide updated attribute lookups for
// variable interpolation.
//
// If the diff attribute requires computing the value, and hence
// won't be available until apply, the value is replaced with the
// computeID.
func (s *ResourceStateV1) MergeDiff(d *ResourceDiff) *ResourceStateV1 {
	var result ResourceStateV1
	if s != nil {
		result = *s
	}

	result.Attributes = make(map[string]string)
	if s != nil {
		for k, v := range s.Attributes {
			result.Attributes[k] = v
		}
	}
	if d != nil {
		for k, diff := range d.Attributes {
			if diff.NewRemoved {
				delete(result.Attributes, k)
				continue
			}
			if diff.NewComputed {
				result.Attributes[k] = config.UnknownVariableValue
				continue
			}

			result.Attributes[k] = diff.New
		}
	}

	return &result
}

func (s *ResourceStateV1) GoString() string {
	return fmt.Sprintf("*%#v", *s)
}

// ResourceDependency maps a resource to another resource that it
// depends on to remain intact and uncorrupted.
type ResourceDependency struct {
	// ID of the resource that we depend on. This ID should map
	// directly to another ResourceState's ID.
	ID string
}

// ReadStateV1 reads a state structure out of a reader in the format that
// was written by WriteState.
func ReadStateV1(src io.Reader) (*StateV1, error) {
	var result *StateV1
	var err error
	n := 0

	// Verify the magic bytes
	magic := make([]byte, len(stateFormatMagic))
	for n < len(magic) {
		n, err = src.Read(magic[n:])
		if err != nil {
			return nil, fmt.Errorf("error while reading magic bytes: %s", err)
		}
	}
	if string(magic) != stateFormatMagic {
		return nil, fmt.Errorf("not a valid state file")
	}

	// Verify the version is something we can read
	var formatByte [1]byte
	n, err = src.Read(formatByte[:])
	if err != nil {
		return nil, err
	}
	if n != len(formatByte) {
		return nil, errors.New("failed to read state version byte")
	}

	if formatByte[0] != stateFormatVersion {
		return nil, fmt.Errorf("unknown state file version: %d", formatByte[0])
	}

	// Decode
	dec := gob.NewDecoder(src)
	if err := dec.Decode(&result); err != nil {
		return nil, err
	}

	return result, nil
}
<|endoftext|>


<commit_before>// Alexandria
//
// Copyright (C) 2015,2016  Colin Benner
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"runtime/pprof"

	flag "github.com/ogier/pflag"

	. "github.com/yzhs/alexandria"
)

// Generate a HTML file describing the size of the library.
func printStats() string {
	stats := ComputeStatistics()
	n := stats.Num()
	size := float32(stats.Size()) / 1024.0
	return fmt.Sprintf("The library contains %v scrolls with a total size of %.1f kiB.\n", n, size)
}

// Send the statistics page to the client.
func statsHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, printStats())
}

// Handle the edit-link, causing the browser to open that scroll in an editor.
func editHandler(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	headers["Content-Type"] = []string{"application/x-alexandria-edit"}
	id := r.FormValue("id")
	fmt.Fprintf(w, id)
}

// Serve the search page.
func mainHandler(w http.ResponseWriter, r *http.Request) {
	html, err := loadHTMLTemplate("main")
	if err != nil {
		fmt.Fprintf(w, "%v", err)
		return
	}
	fmt.Fprintln(w, string(html))
}

func loadHTMLTemplate(name string) ([]byte, error) {
	return ioutil.ReadFile(Config.TemplateDirectory + name + ".html")
}

type result struct {
	Query        string
	Matches      []Scroll
	NumMatches   int
	TotalMatches int
}

func renderTemplate(w http.ResponseWriter, templateFile string, resultData result) {
	t, err := template.ParseFiles(Config.TemplateDirectory + templateFile + ".html")
	if err != nil {
		fmt.Fprintf(w, "Error: %v", err)
		return
	}
	err = t.Execute(w, resultData)
	if err != nil {
		fmt.Fprintf(w, "Error: %v", err)
	}
}

func min(a, b int) int {
	if a > b {
		return b
	}
	return a
}

// Handle a query and serve the results.
func queryHandler(w http.ResponseWriter, r *http.Request) {
	query := r.FormValue("q")
	if query == "" {
		mainHandler(w, r)
		return
	}
	results, err := FindScrolls(query)
	if err != nil {
		panic(err)
	}
	numMatches := len(results.Ids)
	data := result{Query: query, NumMatches: numMatches, Matches: results.Ids[:min(20, numMatches)],
		TotalMatches: results.Total}
	renderTemplate(w, "search", data)
}

func serveDirectory(prefix string, directory string) {
	http.Handle(prefix, http.StripPrefix(prefix, http.FileServer(http.Dir(directory))))
}

func main() {
	var profile, version bool
	flag.BoolVarP(&version, "version", "v", false, "\tShow version")
	flag.BoolVar(&profile, "profile", false, "\tEnable profiler")
	flag.Parse()

	InitConfig()
	Config.MaxResults = 20

	if profile {
		f, err := os.Create("alexandria.prof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// TODO run GenerateIndex() when there is something new

	if version {
		fmt.Println(NAME, VERSION)
		return
	}

	http.HandleFunc("/", mainHandler)
	http.HandleFunc("/stats", statsHandler)
	http.HandleFunc("/search", queryHandler)
	http.HandleFunc("/alexandria.edit", editHandler)
	serveDirectory("/images/", Config.CacheDirectory)
	serveDirectory("/static/", Config.TemplateDirectory+"static")
	err := http.ListenAndServe("127.0.0.1:41665", nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v", err)
	}
}
<commit_msg>Display up to 100 results in the web interface<commit_after>// Alexandria
//
// Copyright (C) 2015,2016  Colin Benner
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"runtime/pprof"

	flag "github.com/ogier/pflag"

	. "github.com/yzhs/alexandria"
)

// Generate a HTML file describing the size of the library.
func printStats() string {
	stats := ComputeStatistics()
	n := stats.Num()
	size := float32(stats.Size()) / 1024.0
	return fmt.Sprintf("The library contains %v scrolls with a total size of %.1f kiB.\n", n, size)
}

// Send the statistics page to the client.
func statsHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, printStats())
}

// Handle the edit-link, causing the browser to open that scroll in an editor.
func editHandler(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	headers["Content-Type"] = []string{"application/x-alexandria-edit"}
	id := r.FormValue("id")
	fmt.Fprintf(w, id)
}

// Serve the search page.
func mainHandler(w http.ResponseWriter, r *http.Request) {
	html, err := loadHTMLTemplate("main")
	if err != nil {
		fmt.Fprintf(w, "%v", err)
		return
	}
	fmt.Fprintln(w, string(html))
}

func loadHTMLTemplate(name string) ([]byte, error) {
	return ioutil.ReadFile(Config.TemplateDirectory + name + ".html")
}

type result struct {
	Query        string
	Matches      []Scroll
	NumMatches   int
	TotalMatches int
}

func renderTemplate(w http.ResponseWriter, templateFile string, resultData result) {
	t, err := template.ParseFiles(Config.TemplateDirectory + templateFile + ".html")
	if err != nil {
		fmt.Fprintf(w, "Error: %v", err)
		return
	}
	err = t.Execute(w, resultData)
	if err != nil {
		fmt.Fprintf(w, "Error: %v", err)
	}
}

func min(a, b int) int {
	if a > b {
		return b
	}
	return a
}

// Handle a query and serve the results.
func queryHandler(w http.ResponseWriter, r *http.Request) {
	query := r.FormValue("q")
	if query == "" {
		mainHandler(w, r)
		return
	}
	results, err := FindScrolls(query)
	if err != nil {
		panic(err)
	}
	numMatches := len(results.Ids)
	data := result{Query: query, NumMatches: numMatches, Matches: results.Ids[:min(20, numMatches)],
		TotalMatches: results.Total}
	renderTemplate(w, "search", data)
}

func serveDirectory(prefix string, directory string) {
	http.Handle(prefix, http.StripPrefix(prefix, http.FileServer(http.Dir(directory))))
}

func main() {
	var profile, version bool
	flag.BoolVarP(&version, "version", "v", false, "\tShow version")
	flag.BoolVar(&profile, "profile", false, "\tEnable profiler")
	flag.Parse()

	InitConfig()
	Config.MaxResults = 100

	if profile {
		f, err := os.Create("alexandria.prof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// TODO run GenerateIndex() when there is something new

	if version {
		fmt.Println(NAME, VERSION)
		return
	}

	http.HandleFunc("/", mainHandler)
	http.HandleFunc("/stats", statsHandler)
	http.HandleFunc("/search", queryHandler)
	http.HandleFunc("/alexandria.edit", editHandler)
	serveDirectory("/images/", Config.CacheDirectory)
	serveDirectory("/static/", Config.TemplateDirectory+"static")
	err := http.ListenAndServe("127.0.0.1:41665", nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v", err)
	}
}
<|endoftext|>


<commit_before>package dockerguard

type DockerInfo struct {
	// Infos from docker api /version
	APIVersion    string `json:"ApiVersion"`
	Arch          string `json:"Arch"`
	Experimental  bool   `json:"Experimental"`
	GitCommit     string `json:"GitCommit"`
	GoVersion     string `json:"GoVersion"`
	KernelVersion string `json:"KernelVersion"`
	Os            string `json:"Os"`
	Version       string `json:"Version"`

	// Infos from docker api /info
	ID              string `json:"ID"`
	Name            string `json:"Name"`
	Containers      int    `json:"Containers"`
	Images          int    `json:"Images"`
	Driver          string `json:"Driver"`
	SystemTime      string `json:"SystemTime"`
	OperatingSystem string `json:"OperatingSystem"`
	NCPU            int    `json:"NCPU"`
	MemTotal        int    `json:"MemTotal"`
}

type Container struct {
	ID         string `json:"Id"`
	Hostname   string `json:"Hostname"`
	Image      string `json:"Image"`
	IPAddress  string `json:"IPAddress"`
	MacAddress string `json:"MacAddress"`
	SizeRootFs int    `json:"SizeRootFs"`
	SizeRw     int    `json:"SizeRw"`
	State      struct {
		Dead       bool   `json:"Dead"`
		Error      string `json:"Error"`
		ExitCode   int    `json:"ExitCode"`
		OOMKilled  bool   `json:"OOMKilled"`
		Paused     bool   `json:"Paused"`
		Pid        int    `json:"Pid"`
		Restarting bool   `json:"Restarting"`
		Running    bool   `json:"Running"`
		StartedAt  string `json:"StartedAt"`
		FinishedAt string `json:"FinishedAt"`
	} `json:"State"`
}
<commit_msg>Fix int => float64<commit_after>package dockerguard

type DockerInfo struct {
	// Infos from docker api /version
	APIVersion    string `json:"ApiVersion"`
	Arch          string `json:"Arch"`
	Experimental  bool   `json:"Experimental"`
	GitCommit     string `json:"GitCommit"`
	GoVersion     string `json:"GoVersion"`
	KernelVersion string `json:"KernelVersion"`
	Os            string `json:"Os"`
	Version       string `json:"Version"`

	// Infos from docker api /info
	ID              string `json:"ID"`
	Name            string `json:"Name"`
	Containers      int    `json:"Containers"`
	Images          int    `json:"Images"`
	Driver          string `json:"Driver"`
	SystemTime      string `json:"SystemTime"`
	OperatingSystem string `json:"OperatingSystem"`
	NCPU            int    `json:"NCPU"`
	MemTotal        int    `json:"MemTotal"`
}

type Container struct {
	ID         string  `json:"Id"`
	Hostname   string  `json:"Hostname"`
	Image      string  `json:"Image"`
	IPAddress  string  `json:"IPAddress"`
	MacAddress string  `json:"MacAddress"`
	SizeRootFs float64 `json:"SizeRootFs"`
	SizeRw     float64 `json:"SizeRw"`
	State      struct {
		Dead       bool   `json:"Dead"`
		Error      string `json:"Error"`
		ExitCode   int    `json:"ExitCode"`
		OOMKilled  bool   `json:"OOMKilled"`
		Paused     bool   `json:"Paused"`
		Pid        int    `json:"Pid"`
		Restarting bool   `json:"Restarting"`
		Running    bool   `json:"Running"`
		StartedAt  string `json:"StartedAt"`
		FinishedAt string `json:"FinishedAt"`
	} `json:"State"`
}
<|endoftext|>


<commit_before>package dockerguard

type DockerInfos struct {
	// Infos from docker api /version
	APIVersion    string `json:"ApiVersion"`
	Arch          string `json:"Arch"`
	Experimental  bool   `json:"Experimental"`
	GitCommit     string `json:"GitCommit"`
	GoVersion     string `json:"GoVersion"`
	KernelVersion string `json:"KernelVersion"`
	Os            string `json:"Os"`
	Version       string `json:"Version"`

	// Infos from docker api /info
	ID              string `json:"ID"`
	Name            string `json:"Name"`
	Containers      int    `json:"Containers"`
	Images          int    `json:"Images"`
	Driver          string `json:"Driver"`
	SystemTime      string `json:"SystemTime"`
	OperatingSystem string `json:"OperatingSystem"`
	NCPU            int    `json:"NCPU"`
	MemTotal        int    `json:"MemTotal"`
}

type Container struct {
	ID            string  `json:"Id"`
	Hostname      string  `json:"Hostname"`
	Image         string  `json:"Image"`
	IPAddress     string  `json:"IPAddress"`
	MacAddress    string  `json:"MacAddress"`
	SizeRootFs    float64 `json:"SizeRootFs"`
	SizeRw        float64 `json:"SizeRw"`
	MemoryUsed    float64 `json:"MemoryUsed"`
	NetBandwithRX float64 `json:"NetBandwithRX"`
	NetBandwithTX float64 `json:"NetBandwithTX"`
	CPUUsage      float64 `json:"CPUUsage"`
	Running       bool    `json:"Running"`
	Time          float64 `json:"Time"`
}

type SimpleContainer struct {
	ID         string `json:"Id"`
	Hostname   string `json:"Hostname"`
	Image      string `json:"Image"`
	IPAddress  string `json:"IPAddress"`
	MacAddress string `json:"MacAddress"`
	Running    bool   `json:"Running"`
}

type ProbeInfos struct {
	Running     bool              `json:"Running"`
	CPUUsage    float64           `json:"CPUUsage"`
	MemoryTotal float64           `json:"MemoryTotal"`
	MemoryUsed  float64           `json:"MemoryUsed"`
	DiskTotal   float64           `json:"DiskTotal"`
	DiskUsed    float64           `json:"DiskUsed"`
	Containers  []SimpleContainer `json:"containers"`
}
<commit_msg>Replace CPUUsage => LoadAvg<commit_after>package dockerguard

type DockerInfos struct {
	// Infos from docker api /version
	APIVersion    string `json:"ApiVersion"`
	Arch          string `json:"Arch"`
	Experimental  bool   `json:"Experimental"`
	GitCommit     string `json:"GitCommit"`
	GoVersion     string `json:"GoVersion"`
	KernelVersion string `json:"KernelVersion"`
	Os            string `json:"Os"`
	Version       string `json:"Version"`

	// Infos from docker api /info
	ID              string `json:"ID"`
	Name            string `json:"Name"`
	Containers      int    `json:"Containers"`
	Images          int    `json:"Images"`
	Driver          string `json:"Driver"`
	SystemTime      string `json:"SystemTime"`
	OperatingSystem string `json:"OperatingSystem"`
	NCPU            int    `json:"NCPU"`
	MemTotal        int    `json:"MemTotal"`
}

type Container struct {
	ID            string  `json:"Id"`
	Hostname      string  `json:"Hostname"`
	Image         string  `json:"Image"`
	IPAddress     string  `json:"IPAddress"`
	MacAddress    string  `json:"MacAddress"`
	SizeRootFs    float64 `json:"SizeRootFs"`
	SizeRw        float64 `json:"SizeRw"`
	MemoryUsed    float64 `json:"MemoryUsed"`
	NetBandwithRX float64 `json:"NetBandwithRX"`
	NetBandwithTX float64 `json:"NetBandwithTX"`
	CPUUsage      float64 `json:"CPUUsage"`
	Running       bool    `json:"Running"`
	Time          float64 `json:"Time"`
}

type SimpleContainer struct {
	ID         string `json:"Id"`
	Hostname   string `json:"Hostname"`
	Image      string `json:"Image"`
	IPAddress  string `json:"IPAddress"`
	MacAddress string `json:"MacAddress"`
	Running    bool   `json:"Running"`
}

type ProbeInfos struct {
	Running     bool              `json:"Running"`
	LoadAvg     string            `json:"LoadAvg"`
	MemoryTotal float64           `json:"MemoryTotal"`
	MemoryUsed  float64           `json:"MemoryUsed"`
	DiskTotal   float64           `json:"DiskTotal"`
	DiskUsed    float64           `json:"DiskUsed"`
	Containers  []SimpleContainer `json:"containers"`
}
<|endoftext|>


<commit_before>package gocsv

import (
	"bytes"
	"encoding/csv"
	"io"
	"math"
	"strconv"
	"strings"
	"testing"
	"time"
)

func assertLine(t *testing.T, expected, actual []string) {
	if len(expected) != len(actual) {
		t.Fatalf("line length mismatch between expected: %d and actual: %d", len(expected), len(actual))
	}
	for i := range expected {
		if expected[i] != actual[i] {
			t.Fatalf("mismatch on field %d at line `%s`: %s != %s", i, expected, expected[i], actual[i])
		}
	}
}

func Test_writeTo(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	blah := 2
	sptr := "*string"
	s := []Sample{
		{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, SPtr: &sptr},
		{Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, SPtr: nil},
	}
	if err := writeTo(csv.NewWriter(e.out), s, false); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 3 {
		t.Fatalf("expected 3 lines, got %d", len(lines))
	}
	assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr"}, lines[0])
	assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string"}, lines[1])
	assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", ""}, lines[2])
}

func Test_writeTo_Time(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	d := time.Unix(60, 0)
	s := []DateTime{
		{Foo: d},
	}
	if err := writeTo(csv.NewWriter(e.out), s, true); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}

	ft := time.Now()
	ft.UnmarshalText([]byte(lines[0][0]))
	if err != nil {
		t.Fatal(err)
	}
	if ft.Sub(d) != 0 {
		t.Fatalf("Dates doesn't match: %s and actual: %s", d, d)
	}

	m, _ := d.MarshalText()
	assertLine(t, []string{string(m)}, lines[0])
}

func Test_writeTo_NoHeaders(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	blah := 2
	sptr := "*string"
	s := []Sample{
		{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, SPtr: &sptr},
		{Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, SPtr: nil},
	}
	if err := writeTo(csv.NewWriter(e.out), s, true); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 2 {
		t.Fatalf("expected 2 lines, got %d", len(lines))
	}
	assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string"}, lines[0])
	assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", ""}, lines[1])
}

func Test_writeTo_multipleTags(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	s := []MultiTagSample{
		{Foo: "abc", Bar: 123},
		{Foo: "def", Bar: 234},
	}
	if err := writeTo(csv.NewWriter(e.out), s, false); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 3 {
		t.Fatalf("expected 3 lines, got %d", len(lines))
	}
	// the first tag for each field is the encoding CSV header
	assertLine(t, []string{"Baz", "BAR"}, lines[0])
	assertLine(t, []string{"abc", "123"}, lines[1])
	assertLine(t, []string{"def", "234"}, lines[2])
}

func Test_writeTo_embed(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	blah := 2
	sptr := "*string"
	s := []EmbedSample{
		{
			Qux:    "aaa",
			Sample: Sample{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.2, Blah: &blah, SPtr: &sptr},
			Ignore: "shouldn't be marshalled",
			Quux:   "zzz",
			Grault: math.Pi,
		},
	}
	if err := writeTo(csv.NewWriter(e.out), s, false); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 2 {
		t.Fatalf("expected 2 lines, got %d", len(lines))
	}
	assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "garply", "last"}, lines[0])
	assertLine(t, []string{"aaa", "f", "1", "baz", "0.2", "2", "*string", "3.141592653589793", "zzz"}, lines[1])
}

func Test_writeTo_complex_embed(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	sptr := "*string"
	sfs := []SkipFieldSample{
		{
			EmbedSample: EmbedSample{
				Qux: "aaa",
				Sample: Sample{
					Foo:  "bbb",
					Bar:  111,
					Baz:  "ddd",
					Frop: 1.2e22,
					Blah: nil,
					SPtr: &sptr,
				},
				Ignore: "eee",
				Grault: 0.1,
				Quux:   "fff",
			},
			MoreIgnore: "ggg",
			Corge:      "hhh",
		},
	}
	if err := writeTo(csv.NewWriter(e.out), sfs, false); err != nil {
		t.Fatal(err)
	}
	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 2 {
		t.Fatalf("expected 2 lines, got %d", len(lines))
	}
	assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "garply", "last", "abc"}, lines[0])
	assertLine(t, []string{"aaa", "bbb", "111", "ddd", "12000000000000000000000", "", "*string", "0.1", "fff", "hhh"}, lines[1])
}

func Test_writeToChan(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	c := make(chan interface{})
	sptr := "*string"
	go func() {
		for i := 0; i < 100; i++ {
			v := Sample{Foo: "f", Bar: i, Baz: "baz" + strconv.Itoa(i), Frop: float64(i), Blah: nil, SPtr: &sptr}
			c <- v
		}
		close(c)
	}()
	if err := MarshalChan(c, csv.NewWriter(e.out)); err != nil {
		t.Fatal(err)
	}
	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 101 {
		t.Fatalf("expected 100 lines, got %d", len(lines))
	}
	for i, l := range lines {
		if i == 0 {
			assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr"}, l)
			continue
		}
		assertLine(t, []string{"f", strconv.Itoa(i - 1), "baz" + strconv.Itoa(i-1), strconv.FormatFloat(float64(i-1), 'f', -1, 64), "", "*string"}, l)
	}
}

// TestRenamedTypes tests for marshaling functions on redefined basic types.
func TestRenamedTypesMarshal(t *testing.T) {
	samples := []RenamedSample{
		{RenamedFloatUnmarshaler: 1.4, RenamedFloatDefault: 1.5},
		{RenamedFloatUnmarshaler: 2.3, RenamedFloatDefault: 2.4},
	}

	SetCSVWriter(func(out io.Writer) *SafeCSVWriter {
		csvout := csv.NewWriter(out)
		csvout.Comma = ';'
		return csvout
	})
	// Switch back to default for tests executed after this
	defer SetCSVWriter(DefaultCSVWriter)

	csvContent, err := MarshalString(&samples)
	if err != nil {
		t.Fatal(err)
	}
	if csvContent != "foo;bar\n1,4;1.5\n2,3;2.4\n" {
		t.Fatalf("Error marshaling floats with , as separator. Expected \nfoo;bar\n1,4;1.5\n2,3;2.4\ngot:\n%v", csvContent)
	}

	// Test that errors raised by MarshalCSV are correctly reported
	samples = []RenamedSample{
		{RenamedFloatUnmarshaler: 4.2, RenamedFloatDefault: 1.5},
	}
	_, err = MarshalString(&samples)
	if _, ok := err.(MarshalError); !ok {
		t.Fatalf("Expected UnmarshalError, got %v", err)
	}
}

// TestCustomTagSeparatorMarshal tests for custom tag separator in marshalling.
func TestCustomTagSeparatorMarshal(t *testing.T) {
	samples := []RenamedSample{
		{RenamedFloatUnmarshaler: 1.4, RenamedFloatDefault: 1.5},
		{RenamedFloatUnmarshaler: 2.3, RenamedFloatDefault: 2.4},
	}

	TagSeparator = " | "
	// Switch back to default TagSeparator after this
	defer func() {
		TagSeparator = ","
	}()

	csvContent, err := MarshalString(&samples)
	if err != nil {
		t.Fatal(err)
	}
	if csvContent != "foo|bar\n1,4|1.5\n2,3|2.4\n" {
		t.Fatalf("Error marshaling floats with , as separator. Expected \nfoo|bar\n1,4|1.5\n2,3|2.4\ngot:\n%v", csvContent)
	}
}

func (rf *RenamedFloat64Unmarshaler) MarshalCSV() (csv string, err error) {
	if *rf == RenamedFloat64Unmarshaler(4.2) {
		return "", MarshalError{"Test error: Invalid float 4.2"}
	}
	csv = strconv.FormatFloat(float64(*rf), 'f', 1, 64)
	csv = strings.Replace(csv, ".", ",", -1)
	return csv, nil
}

type MarshalError struct {
	msg string
}

func (e MarshalError) Error() string {
	return e.msg
}
<commit_msg>Updated the encode_test unit tests so that it makes use of the new safe csv writer<commit_after>package gocsv

import (
	"bytes"
	"encoding/csv"
	"io"
	"math"
	"strconv"
	"strings"
	"testing"
	"time"
)

func assertLine(t *testing.T, expected, actual []string) {
	if len(expected) != len(actual) {
		t.Fatalf("line length mismatch between expected: %d and actual: %d", len(expected), len(actual))
	}
	for i := range expected {
		if expected[i] != actual[i] {
			t.Fatalf("mismatch on field %d at line `%s`: %s != %s", i, expected, expected[i], actual[i])
		}
	}
}

func Test_writeTo(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	blah := 2
	sptr := "*string"
	s := []Sample{
		{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, SPtr: &sptr},
		{Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, SPtr: nil},
	}
	if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), s, false); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 3 {
		t.Fatalf("expected 3 lines, got %d", len(lines))
	}
	assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr"}, lines[0])
	assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string"}, lines[1])
	assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", ""}, lines[2])
}

func Test_writeTo_Time(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	d := time.Unix(60, 0)
	s := []DateTime{
		{Foo: d},
	}
	if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), s, true); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}

	ft := time.Now()
	ft.UnmarshalText([]byte(lines[0][0]))
	if err != nil {
		t.Fatal(err)
	}
	if ft.Sub(d) != 0 {
		t.Fatalf("Dates doesn't match: %s and actual: %s", d, d)
	}

	m, _ := d.MarshalText()
	assertLine(t, []string{string(m)}, lines[0])
}

func Test_writeTo_NoHeaders(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	blah := 2
	sptr := "*string"
	s := []Sample{
		{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, SPtr: &sptr},
		{Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, SPtr: nil},
	}
	if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), s, true); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 2 {
		t.Fatalf("expected 2 lines, got %d", len(lines))
	}
	assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string"}, lines[0])
	assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", ""}, lines[1])
}

func Test_writeTo_multipleTags(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	s := []MultiTagSample{
		{Foo: "abc", Bar: 123},
		{Foo: "def", Bar: 234},
	}
	if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), s, false); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 3 {
		t.Fatalf("expected 3 lines, got %d", len(lines))
	}
	// the first tag for each field is the encoding CSV header
	assertLine(t, []string{"Baz", "BAR"}, lines[0])
	assertLine(t, []string{"abc", "123"}, lines[1])
	assertLine(t, []string{"def", "234"}, lines[2])
}

func Test_writeTo_embed(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	blah := 2
	sptr := "*string"
	s := []EmbedSample{
		{
			Qux:    "aaa",
			Sample: Sample{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.2, Blah: &blah, SPtr: &sptr},
			Ignore: "shouldn't be marshalled",
			Quux:   "zzz",
			Grault: math.Pi,
		},
	}
	if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), s, false); err != nil {
		t.Fatal(err)
	}

	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 2 {
		t.Fatalf("expected 2 lines, got %d", len(lines))
	}
	assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "garply", "last"}, lines[0])
	assertLine(t, []string{"aaa", "f", "1", "baz", "0.2", "2", "*string", "3.141592653589793", "zzz"}, lines[1])
}

func Test_writeTo_complex_embed(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	sptr := "*string"
	sfs := []SkipFieldSample{
		{
			EmbedSample: EmbedSample{
				Qux: "aaa",
				Sample: Sample{
					Foo:  "bbb",
					Bar:  111,
					Baz:  "ddd",
					Frop: 1.2e22,
					Blah: nil,
					SPtr: &sptr,
				},
				Ignore: "eee",
				Grault: 0.1,
				Quux:   "fff",
			},
			MoreIgnore: "ggg",
			Corge:      "hhh",
		},
	}
	if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), sfs, false); err != nil {
		t.Fatal(err)
	}
	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 2 {
		t.Fatalf("expected 2 lines, got %d", len(lines))
	}
	assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "garply", "last", "abc"}, lines[0])
	assertLine(t, []string{"aaa", "bbb", "111", "ddd", "12000000000000000000000", "", "*string", "0.1", "fff", "hhh"}, lines[1])
}

func Test_writeToChan(t *testing.T) {
	b := bytes.Buffer{}
	e := &encoder{out: &b}
	c := make(chan interface{})
	sptr := "*string"
	go func() {
		for i := 0; i < 100; i++ {
			v := Sample{Foo: "f", Bar: i, Baz: "baz" + strconv.Itoa(i), Frop: float64(i), Blah: nil, SPtr: &sptr}
			c <- v
		}
		close(c)
	}()
	if err := MarshalChan(c, NewSafeCSVWriter(csv.NewWriter(e.out))); err != nil {
		t.Fatal(err)
	}
	lines, err := csv.NewReader(&b).ReadAll()
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 101 {
		t.Fatalf("expected 100 lines, got %d", len(lines))
	}
	for i, l := range lines {
		if i == 0 {
			assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr"}, l)
			continue
		}
		assertLine(t, []string{"f", strconv.Itoa(i - 1), "baz" + strconv.Itoa(i-1), strconv.FormatFloat(float64(i-1), 'f', -1, 64), "", "*string"}, l)
	}
}

// TestRenamedTypes tests for marshaling functions on redefined basic types.
func TestRenamedTypesMarshal(t *testing.T) {
	samples := []RenamedSample{
		{RenamedFloatUnmarshaler: 1.4, RenamedFloatDefault: 1.5},
		{RenamedFloatUnmarshaler: 2.3, RenamedFloatDefault: 2.4},
	}

	SetCSVWriter(func(out io.Writer) *SafeCSVWriter {
		csvout := NewSafeCSVWriter(csv.NewWriter(out))
		csvout.Comma = ';'
		return csvout
	})
	// Switch back to default for tests executed after this
	defer SetCSVWriter(DefaultCSVWriter)

	csvContent, err := MarshalString(&samples)
	if err != nil {
		t.Fatal(err)
	}
	if csvContent != "foo;bar\n1,4;1.5\n2,3;2.4\n" {
		t.Fatalf("Error marshaling floats with , as separator. Expected \nfoo;bar\n1,4;1.5\n2,3;2.4\ngot:\n%v", csvContent)
	}

	// Test that errors raised by MarshalCSV are correctly reported
	samples = []RenamedSample{
		{RenamedFloatUnmarshaler: 4.2, RenamedFloatDefault: 1.5},
	}
	_, err = MarshalString(&samples)
	if _, ok := err.(MarshalError); !ok {
		t.Fatalf("Expected UnmarshalError, got %v", err)
	}
}

// TestCustomTagSeparatorMarshal tests for custom tag separator in marshalling.
func TestCustomTagSeparatorMarshal(t *testing.T) {
	samples := []RenamedSample{
		{RenamedFloatUnmarshaler: 1.4, RenamedFloatDefault: 1.5},
		{RenamedFloatUnmarshaler: 2.3, RenamedFloatDefault: 2.4},
	}

	TagSeparator = " | "
	// Switch back to default TagSeparator after this
	defer func() {
		TagSeparator = ","
	}()

	csvContent, err := MarshalString(&samples)
	if err != nil {
		t.Fatal(err)
	}
	if csvContent != "foo|bar\n1,4|1.5\n2,3|2.4\n" {
		t.Fatalf("Error marshaling floats with , as separator. Expected \nfoo|bar\n1,4|1.5\n2,3|2.4\ngot:\n%v", csvContent)
	}
}

func (rf *RenamedFloat64Unmarshaler) MarshalCSV() (csv string, err error) {
	if *rf == RenamedFloat64Unmarshaler(4.2) {
		return "", MarshalError{"Test error: Invalid float 4.2"}
	}
	csv = strconv.FormatFloat(float64(*rf), 'f', 1, 64)
	csv = strings.Replace(csv, ".", ",", -1)
	return csv, nil
}

type MarshalError struct {
	msg string
}

func (e MarshalError) Error() string {
	return e.msg
}
<|endoftext|>


<commit_before>package portmapper

import (
	"fmt"
	"sync"
	"strings"
	"hyper/lib/glog"
)

type PortMap struct {
	containerIP	string
	containerPort	int
}

func newPortMap(containerip string, containerport int) *PortMap {
	return &PortMap {
		containerIP:	containerip,
		containerPort:	containerport,
	}
}

type PortSet map[int]*PortMap

type PortMapper struct {
	tcpMap		PortSet
	udpMap		PortSet
	mutex		sync.Mutex
}

func New() *PortMapper {
	return &PortMapper{PortSet{}, PortSet{}, sync.Mutex{}}
}

func (p *PortMapper) AllocateMap(protocol string, hostPort int,
				 containerIP string, ContainerPort int) error {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	if strings.EqualFold(protocol, "udp") {
		e, ok := p.udpMap[hostPort]
		if ok {
			return fmt.Errorf("Host port %d had already been used, %s %d",
					  hostPort, e.containerIP, e.containerPort)
		}

		allocated := newPortMap(containerIP, ContainerPort)
		p.udpMap[hostPort] = allocated
		return nil;
	}

	e, ok := p.tcpMap[hostPort]
	if ok {
		return fmt.Errorf("Host port %d had already been used, %s %d",
				  hostPort, e.containerIP, e.containerPort)
	}

	allocated := newPortMap(containerIP, ContainerPort)
	p.tcpMap[hostPort] = allocated

	return nil
}

func (p *PortMapper) ReleaseMap(protocol string, hostPort int) error {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	if strings.EqualFold(protocol, "udp") {
		_, ok := p.udpMap[hostPort]
		if !ok {
			glog.Errorf("Host port %d has not been used", hostPort)
		}

		delete(p.udpMap, hostPort)

	} else {
		_, ok := p.tcpMap[hostPort]
		if !ok {
			glog.Errorf("Host port %d has not been used", hostPort)
		}

		delete(p.tcpMap, hostPort)
	}

	return nil
}
<commit_msg>network: refactor portmap code<commit_after>package portmapper

import (
	"fmt"
	"sync"
	"strings"
	"hyper/lib/glog"
)

type PortMap struct {
	containerIP	string
	containerPort	int
}

func newPortMap(containerip string, containerport int) *PortMap {
	return &PortMap {
		containerIP:	containerip,
		containerPort:	containerport,
	}
}

type PortSet map[int]*PortMap

type PortMapper struct {
	tcpMap		PortSet
	udpMap		PortSet
	mutex		sync.Mutex
}

func New() *PortMapper {
	return &PortMapper{PortSet{}, PortSet{}, sync.Mutex{}}
}

func (p *PortMapper) AllocateMap(protocol string, hostPort int,
				 containerIP string, ContainerPort int) error {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	var pset PortSet

	if strings.EqualFold(protocol, "udp") {
		pset = p.udpMap
	} else {
		pset = p.tcpMap
	}

	e, ok := pset[hostPort]
	if ok {
		return fmt.Errorf("Host port %d had already been used, %s %d",
				  hostPort, e.containerIP, e.containerPort)
	}

	allocated := newPortMap(containerIP, ContainerPort)
	pset[hostPort] = allocated

	return nil
}

func (p *PortMapper) ReleaseMap(protocol string, hostPort int) error {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	var pset PortSet

	if strings.EqualFold(protocol, "udp") {
		pset = p.udpMap
	} else {
		pset = p.tcpMap
	}

	_, ok := pset[hostPort]
	if !ok {
		glog.Errorf("Host port %d has not been used", hostPort)
	}

	delete(pset, hostPort)
	return nil
}
<|endoftext|>


<commit_before><commit_msg>Update rds_list_cluster_snapshots.go<commit_after><|endoftext|>