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

package docker

import (
	"bytes"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/exec"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"github.com/globocom/tsuru/router"
	_ "github.com/globocom/tsuru/router/nginx"
	_ "github.com/globocom/tsuru/router/testing"
	"io"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

func init() {
	provision.Register("docker", &DockerProvisioner{})
}

var execut exec.Executor

func executor() exec.Executor {
	if execut == nil {
		execut = exec.OsExecutor{}
	}
	return execut
}

func (p *DockerProvisioner) router() (router.Router, error) {
	r, err := config.GetString("router")
	if err != nil {
		return nil, err
	}
	return router.Get(r)
}

type DockerProvisioner struct{}

func (p *DockerProvisioner) setup(ip, framework string) error {
	formulasPath, err := config.GetString("docker:formulas-path")
	if err != nil {
		return err
	}
	log.Printf("Creating hooks dir for %s", ip)
	args := []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo mkdir -p /var/lib/tsuru/hooks"}
	err = executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on creating hooks dir for %s", ip)
		log.Print(err)
		return err
	}
	log.Printf("Permissons on hooks dir for %s", ip)
	args = []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo chown -R ubuntu /var/lib/tsuru/hooks"}
	err = executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on permissions for %s", ip)
		log.Print(err)
		return err
	}
	log.Printf("coping hooks to %s", ip)
	output := bytes.Buffer{}
	args = []string{"-q", "-o", "StrictHostKeyChecking no", "-r", formulasPath + "/" + framework + "/hooks", "ubuntu@" + ip + ":/var/lib/tsuru"}
	err = executor().Execute("scp", args, nil, &output, &output)
	if err != nil {
		log.Printf("error on execute scp with the args: %#v", args)
		log.Print(output.String())
		log.Print(err)
		return err
	}
	return nil
}

func (p *DockerProvisioner) install(ip string) error {
	log.Printf("executing the install hook for %s", ip)
	args := []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo /var/lib/tsuru/hooks/install"}
	err := executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on install for %s", ip)
		log.Print(err)
		return err
	}
	return nil
}

func (p *DockerProvisioner) start(ip string) error {
	args := []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo /var/lib/tsuru/hooks/start"}
	err := executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on start for %s", ip)
		log.Print(err)
		return err
	}
	return nil
}

// Provision creates a container and install its dependencies
func (p *DockerProvisioner) Provision(app provision.App) error {
	go func(p *DockerProvisioner, app provision.App) {
		c := container{name: app.GetName()}
		log.Printf("creating container %s", c.name)
		u := provision.Unit{
			Name:       app.GetName(),
			AppName:    app.GetName(),
			Type:       app.GetPlatform(),
			Machine:    0,
			InstanceId: app.GetName(),
			Status:     provision.StatusCreating,
			Ip:         "",
		}
		log.Printf("inserting container unit %s in the database", app.GetName())
		if err := collection().Insert(u); err != nil {
			log.Print(err)
			return
		}
		id, err := c.create(app.GetPlatform(), repository.GetReadOnlyUrl(app.GetName()))
		if err != nil {
			log.Printf("error on create container %s", app.GetName())
			log.Print(err)
			return
		}
		c.id = id
		u.InstanceId = id
		if err := c.start(); err != nil {
			log.Printf("error on start container %s", app.GetName())
			log.Print(err)
			return
		}
		ip, err := c.ip() // handle this error
		u.Ip = ip
		u.Status = provision.StatusInstalling
		if err := collection().Update(bson.M{"name": u.Name}, u); err != nil {
			log.Print(err)
			return
		}
		if err := p.setup(ip, app.GetPlatform()); err != nil {
			log.Printf("error on setup container %s", app.GetName())
			log.Print(err)
			return
		}
		if err := p.install(ip); err != nil {
			log.Printf("error on install container %s", app.GetName())
			log.Print(err)
			return
		}
		log.Printf("running provisioning start() for container %s", c.id)
		if err := p.start(ip); err != nil {
			log.Printf("error on start app for container %s", app.GetName())
			log.Print(err)
			return
		}
		r, err := p.router()
		if err != nil {
			log.Print(err)
			return
		}
		err = r.AddRoute(app.GetName(), ip)
		if err != nil {
			log.Printf("error on add route for %s with ip %s", app.GetName(), ip)
			log.Print(err)
		}
		u.Status = provision.StatusStarted
		if err := collection().Update(bson.M{"name": u.Name}, u); err != nil {
			log.Print(err)
			return
		}
		log.Printf("Successfuly updated unit: %s", app.GetName())
	}(p, app)
	return nil
}

func (p *DockerProvisioner) Restart(app provision.App) error {
	var buf bytes.Buffer
	err := p.ExecuteCommand(&buf, &buf, app, "/var/lib/tsuru/hooks/restart")
	if err != nil {
		msg := fmt.Sprintf("Failed to restart the app (%s): %s", err, buf.String())
		app.Log(msg, "tsuru-provisioner")
		return &provision.Error{Reason: buf.String(), Err: err}
	}
	return nil
}

func (p *DockerProvisioner) Deploy(app provision.App, w io.Writer) error {
	c := newContainer(app)
	img := image{Name: app.GetName()}
	_, err := img.commit(c.id)
	return err
}

func (p *DockerProvisioner) Destroy(app provision.App) error {
	units := app.ProvisionUnits()
	for _, u := range units {
		go func(u provision.AppUnit) {
			c := container{
				name: app.GetName(),
				// TODO: get actual c.id
				id: u.GetInstanceId(),
			}
			log.Printf("stoping container %s", u.GetInstanceId())
			if err := c.stop(); err != nil {
				log.Print("Could not stop container. Trying to remove it anyway.")
				log.Print(err.Error())
			}

			log.Printf("removing container %s", u.GetInstanceId())
			if err := c.remove(); err != nil {
				log.Print("Could not remove container. Aborting...")
				log.Print(err.Error())
				return
			}

			log.Printf("removing container %s from the database", u.GetName())
			if err := collection().Remove(bson.M{"name": u.GetName()}); err != nil {
				log.Printf("Could not remove container from database. Error %s", err.Error())
			}
			log.Print("Units successfuly removed.")
		}(u)
	}
	img := &image{Name: app.GetName()}
	log.Printf("removing image %s from the database", app.GetName())
	if err := img.remove(); err != nil {
		return err
	}
	return nil
}

func (*DockerProvisioner) Addr(app provision.App) (string, error) {
	units := app.ProvisionUnits()
	return units[0].GetIp(), nil
}

func (*DockerProvisioner) AddUnits(app provision.App, units uint) ([]provision.Unit, error) {
	return []provision.Unit{}, nil
}

func (*DockerProvisioner) RemoveUnit(app provision.App, unitName string) error {
	return nil
}

func (*DockerProvisioner) InstallDeps(app provision.App, w io.Writer) error {
	return nil
}

func (*DockerProvisioner) ExecuteCommand(stdout, stderr io.Writer, app provision.App, cmd string, args ...string) error {
	arguments := []string{"-l", "ubuntu", "-q", "-o", "StrictHostKeyChecking no"}
	arguments = append(arguments, app.ProvisionUnits()[0].GetIp())
	arguments = append(arguments, cmd)
	arguments = append(arguments, args...)
	err := executor().Execute("ssh", arguments, nil, stdout, stderr)
	if err != nil {
		return err
	}
	return nil
}

func (p *DockerProvisioner) CollectStatus() ([]provision.Unit, error) {
	var units []provision.Unit
	err := collection().Find(nil).All(&units)
	if err != nil {
		return []provision.Unit{}, err
	}
	return units, nil
}

func collection() *mgo.Collection {
	name, err := config.GetString("docker:collection")
	if err != nil {
		log.Fatalf("FATAL: %s.", err)
	}
	conn, err := db.Conn()
	if err != nil {
		log.Printf("Failed to connect to the database: %s", err)
	}
	return conn.Collection(name)
}

func imagesCollection() *mgo.Collection {
	nameIndex := mgo.Index{Key: []string{"name"}, Unique: true}
	conn, err := db.Conn()
	if err != nil {
		log.Printf("Failed to connect to the database: %s", err)
	}
	c := conn.Collection("docker_image")
	c.EnsureIndex(nameIndex)
	return c
}
<commit_msg>provision/docker/provisioner: passing function argument to generate cmds for container creation<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/exec"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/router"
	_ "github.com/globocom/tsuru/router/nginx"
	_ "github.com/globocom/tsuru/router/testing"
	"io"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

func init() {
	provision.Register("docker", &DockerProvisioner{})
}

var execut exec.Executor

func executor() exec.Executor {
	if execut == nil {
		execut = exec.OsExecutor{}
	}
	return execut
}

func (p *DockerProvisioner) router() (router.Router, error) {
	r, err := config.GetString("router")
	if err != nil {
		return nil, err
	}
	return router.Get(r)
}

type DockerProvisioner struct{}

func (p *DockerProvisioner) setup(ip, framework string) error {
	formulasPath, err := config.GetString("docker:formulas-path")
	if err != nil {
		return err
	}
	log.Printf("Creating hooks dir for %s", ip)
	args := []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo mkdir -p /var/lib/tsuru/hooks"}
	err = executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on creating hooks dir for %s", ip)
		log.Print(err)
		return err
	}
	log.Printf("Permissons on hooks dir for %s", ip)
	args = []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo chown -R ubuntu /var/lib/tsuru/hooks"}
	err = executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on permissions for %s", ip)
		log.Print(err)
		return err
	}
	log.Printf("coping hooks to %s", ip)
	output := bytes.Buffer{}
	args = []string{"-q", "-o", "StrictHostKeyChecking no", "-r", formulasPath + "/" + framework + "/hooks", "ubuntu@" + ip + ":/var/lib/tsuru"}
	err = executor().Execute("scp", args, nil, &output, &output)
	if err != nil {
		log.Printf("error on execute scp with the args: %#v", args)
		log.Print(output.String())
		log.Print(err)
		return err
	}
	return nil
}

func (p *DockerProvisioner) install(ip string) error {
	log.Printf("executing the install hook for %s", ip)
	args := []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo /var/lib/tsuru/hooks/install"}
	err := executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on install for %s", ip)
		log.Print(err)
		return err
	}
	return nil
}

func (p *DockerProvisioner) start(ip string) error {
	args := []string{"-q", "-o", "StrictHostKeyChecking no", "-l", "ubuntu", ip, "sudo /var/lib/tsuru/hooks/start"}
	err := executor().Execute("ssh", args, nil, nil, nil)
	if err != nil {
		log.Printf("error on start for %s", ip)
		log.Print(err)
		return err
	}
	return nil
}

// Provision creates a container and install its dependencies
func (p *DockerProvisioner) Provision(app provision.App) error {
	go func(p *DockerProvisioner, app provision.App) {
		c := container{name: app.GetName()}
		log.Printf("creating container %s", c.name)
		u := provision.Unit{
			Name:       app.GetName(),
			AppName:    app.GetName(),
			Type:       app.GetPlatform(),
			Machine:    0,
			InstanceId: app.GetName(),
			Status:     provision.StatusCreating,
			Ip:         "",
		}
		log.Printf("inserting container unit %s in the database", app.GetName())
		if err := collection().Insert(u); err != nil {
			log.Print(err)
			return
		}
		id, err := c.create(app, deployContainerCmd)
		if err != nil {
			log.Printf("error on create container %s", app.GetName())
			log.Print(err)
			return
		}
		c.id = id
		u.InstanceId = id
		if err := c.start(); err != nil {
			log.Printf("error on start container %s", app.GetName())
			log.Print(err)
			return
		}
		ip, err := c.ip() // handle this error
		u.Ip = ip
		u.Status = provision.StatusInstalling
		if err := collection().Update(bson.M{"name": u.Name}, u); err != nil {
			log.Print(err)
			return
		}
		if err := p.setup(ip, app.GetPlatform()); err != nil {
			log.Printf("error on setup container %s", app.GetName())
			log.Print(err)
			return
		}
		if err := p.install(ip); err != nil {
			log.Printf("error on install container %s", app.GetName())
			log.Print(err)
			return
		}
		log.Printf("running provisioning start() for container %s", c.id)
		if err := p.start(ip); err != nil {
			log.Printf("error on start app for container %s", app.GetName())
			log.Print(err)
			return
		}
		r, err := p.router()
		if err != nil {
			log.Print(err)
			return
		}
		err = r.AddRoute(app.GetName(), ip)
		if err != nil {
			log.Printf("error on add route for %s with ip %s", app.GetName(), ip)
			log.Print(err)
		}
		u.Status = provision.StatusStarted
		if err := collection().Update(bson.M{"name": u.Name}, u); err != nil {
			log.Print(err)
			return
		}
		log.Printf("Successfuly updated unit: %s", app.GetName())
	}(p, app)
	return nil
}

func (p *DockerProvisioner) Restart(app provision.App) error {
	var buf bytes.Buffer
	err := p.ExecuteCommand(&buf, &buf, app, "/var/lib/tsuru/hooks/restart")
	if err != nil {
		msg := fmt.Sprintf("Failed to restart the app (%s): %s", err, buf.String())
		app.Log(msg, "tsuru-provisioner")
		return &provision.Error{Reason: buf.String(), Err: err}
	}
	return nil
}

func (p *DockerProvisioner) Deploy(app provision.App, w io.Writer) error {
	c := newContainer(app, deployContainerCmd)
	img := image{Name: app.GetName()}
	_, err := img.commit(c.id)
	return err
}

func (p *DockerProvisioner) Destroy(app provision.App) error {
	units := app.ProvisionUnits()
	for _, u := range units {
		go func(u provision.AppUnit) {
			c := container{
				name: app.GetName(),
				// TODO: get actual c.id
				id: u.GetInstanceId(),
			}
			log.Printf("stoping container %s", u.GetInstanceId())
			if err := c.stop(); err != nil {
				log.Print("Could not stop container. Trying to remove it anyway.")
				log.Print(err.Error())
			}

			log.Printf("removing container %s", u.GetInstanceId())
			if err := c.remove(); err != nil {
				log.Print("Could not remove container. Aborting...")
				log.Print(err.Error())
				return
			}

			log.Printf("removing container %s from the database", u.GetName())
			if err := collection().Remove(bson.M{"name": u.GetName()}); err != nil {
				log.Printf("Could not remove container from database. Error %s", err.Error())
			}
			log.Print("Units successfuly removed.")
		}(u)
	}
	img := &image{Name: app.GetName()}
	log.Printf("removing image %s from the database", app.GetName())
	if err := img.remove(); err != nil {
		return err
	}
	return nil
}

func (*DockerProvisioner) Addr(app provision.App) (string, error) {
	units := app.ProvisionUnits()
	return units[0].GetIp(), nil
}

func (*DockerProvisioner) AddUnits(app provision.App, units uint) ([]provision.Unit, error) {
	return []provision.Unit{}, nil
}

func (*DockerProvisioner) RemoveUnit(app provision.App, unitName string) error {
	return nil
}

func (*DockerProvisioner) InstallDeps(app provision.App, w io.Writer) error {
	return nil
}

func (*DockerProvisioner) ExecuteCommand(stdout, stderr io.Writer, app provision.App, cmd string, args ...string) error {
	arguments := []string{"-l", "ubuntu", "-q", "-o", "StrictHostKeyChecking no"}
	arguments = append(arguments, app.ProvisionUnits()[0].GetIp())
	arguments = append(arguments, cmd)
	arguments = append(arguments, args...)
	err := executor().Execute("ssh", arguments, nil, stdout, stderr)
	if err != nil {
		return err
	}
	return nil
}

func (p *DockerProvisioner) CollectStatus() ([]provision.Unit, error) {
	var units []provision.Unit
	err := collection().Find(nil).All(&units)
	if err != nil {
		return []provision.Unit{}, err
	}
	return units, nil
}

func collection() *mgo.Collection {
	name, err := config.GetString("docker:collection")
	if err != nil {
		log.Fatalf("FATAL: %s.", err)
	}
	conn, err := db.Conn()
	if err != nil {
		log.Printf("Failed to connect to the database: %s", err)
	}
	return conn.Collection(name)
}

func imagesCollection() *mgo.Collection {
	nameIndex := mgo.Index{Key: []string{"name"}, Unique: true}
	conn, err := db.Conn()
	if err != nil {
		log.Printf("Failed to connect to the database: %s", err)
	}
	c := conn.Collection("docker_image")
	c.EnsureIndex(nameIndex)
	return c
}
<|endoftext|>


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

package swarm

import (
	"github.com/docker/docker/api/types/swarm"
	"github.com/fsouza/go-dockerclient"
	"github.com/fsouza/go-dockerclient/testing"
	"github.com/tsuru/tsuru/action"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/app/image"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/check.v1"
	"net/http"
)

func (s *S) TestActionUpdateServicesForward(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:   cli,
		app:      a,
		newImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{},
	}
	processes, err := updateServices.Forward(action.FWContext{Params: []interface{}{args}})
	c.Assert(err, check.IsNil)
	c.Assert(processes, check.DeepEquals, []string{"web"})
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec python myapp.py",
	})
}

func (s *S) TestActionUpdateServicesForwardUpdateExisting(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	_, err = cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"oldcmd"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-web",
			},
		},
	})
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:   cli,
		app:      a,
		newImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{},
	}
	processes, err := updateServices.Forward(action.FWContext{Params: []interface{}{args}})
	c.Assert(err, check.IsNil)
	c.Assert(processes, check.DeepEquals, []string{"web"})
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec python myapp.py",
	})
}

func (s *S) TestActionUpdateServicesForwardFailureInMiddle(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	_, err = cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"original-web"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-web",
			},
		},
	})
	c.Assert(err, check.IsNil)
	srvWorker, err := cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"original-worker"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-worker",
			},
		},
	})
	c.Assert(err, check.IsNil)
	oldImg := "app:v1"
	err = image.SaveImageCustomData(oldImg, map[string]interface{}{
		"processes": map[string]interface{}{
			"web":    "old1",
			"worker": "old2",
		},
	})
	c.Assert(err, check.IsNil)
	newImg := "app:v2"
	err = image.SaveImageCustomData(newImg, map[string]interface{}{
		"processes": map[string]interface{}{
			"web":    "new1",
			"worker": "new2",
		},
	})
	c.Assert(err, check.IsNil)
	srv.CustomHandler("/services/"+srvWorker.ID, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("bad error"))
	}))
	imgData := &image.ImageMetadata{
		Processes: map[string]string{"web": "", "worker": ""},
	}
	args := &pipelineArgs{
		client:         cli,
		app:            a,
		newImage:       newImg,
		newImgData:     imgData,
		currentImage:   oldImg,
		currentImgData: imgData,
	}
	processes, err := updateServices.Forward(action.FWContext{Params: []interface{}{args}})
	c.Assert(err, check.ErrorMatches, ".*bad error")
	c.Assert(processes, check.IsNil)
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec old1",
	})
	service, err = cli.InspectService("myapp-worker")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"original-worker",
	})
}

func (s *S) TestActionUpdateServicesBackward(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:       cli,
		app:          a,
		currentImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
	}
	updateServices.Backward(action.BWContext{
		FWResult: []string{"web"},
		Params:   []interface{}{args},
	})
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec python myapp.py",
	})
}

func (s *S) TestActionUpdateServicesBackwardNotInCurrent(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	_, err = cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"original-web"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-web",
			},
		},
	})
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:       cli,
		app:          a,
		currentImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{},
	}
	updateServices.Backward(action.BWContext{
		FWResult: []string{"web"},
		Params:   []interface{}{args},
	})
	_, err = cli.InspectService("myapp-web")
	c.Assert(err, check.ErrorMatches, "No such service.*")
}
<commit_msg>provision/swarm: fix import ordering<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package swarm

import (
	"net/http"

	"github.com/docker/docker/api/types/swarm"
	"github.com/fsouza/go-dockerclient"
	"github.com/fsouza/go-dockerclient/testing"
	"github.com/tsuru/tsuru/action"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/app/image"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/check.v1"
)

func (s *S) TestActionUpdateServicesForward(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:   cli,
		app:      a,
		newImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{},
	}
	processes, err := updateServices.Forward(action.FWContext{Params: []interface{}{args}})
	c.Assert(err, check.IsNil)
	c.Assert(processes, check.DeepEquals, []string{"web"})
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec python myapp.py",
	})
}

func (s *S) TestActionUpdateServicesForwardUpdateExisting(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	_, err = cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"oldcmd"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-web",
			},
		},
	})
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:   cli,
		app:      a,
		newImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{},
	}
	processes, err := updateServices.Forward(action.FWContext{Params: []interface{}{args}})
	c.Assert(err, check.IsNil)
	c.Assert(processes, check.DeepEquals, []string{"web"})
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec python myapp.py",
	})
}

func (s *S) TestActionUpdateServicesForwardFailureInMiddle(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	_, err = cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"original-web"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-web",
			},
		},
	})
	c.Assert(err, check.IsNil)
	srvWorker, err := cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"original-worker"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-worker",
			},
		},
	})
	c.Assert(err, check.IsNil)
	oldImg := "app:v1"
	err = image.SaveImageCustomData(oldImg, map[string]interface{}{
		"processes": map[string]interface{}{
			"web":    "old1",
			"worker": "old2",
		},
	})
	c.Assert(err, check.IsNil)
	newImg := "app:v2"
	err = image.SaveImageCustomData(newImg, map[string]interface{}{
		"processes": map[string]interface{}{
			"web":    "new1",
			"worker": "new2",
		},
	})
	c.Assert(err, check.IsNil)
	srv.CustomHandler("/services/"+srvWorker.ID, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("bad error"))
	}))
	imgData := &image.ImageMetadata{
		Processes: map[string]string{"web": "", "worker": ""},
	}
	args := &pipelineArgs{
		client:         cli,
		app:            a,
		newImage:       newImg,
		newImgData:     imgData,
		currentImage:   oldImg,
		currentImgData: imgData,
	}
	processes, err := updateServices.Forward(action.FWContext{Params: []interface{}{args}})
	c.Assert(err, check.ErrorMatches, ".*bad error")
	c.Assert(processes, check.IsNil)
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec old1",
	})
	service, err = cli.InspectService("myapp-worker")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"original-worker",
	})
}

func (s *S) TestActionUpdateServicesBackward(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:       cli,
		app:          a,
		currentImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
	}
	updateServices.Backward(action.BWContext{
		FWResult: []string{"web"},
		Params:   []interface{}{args},
	})
	service, err := cli.InspectService("myapp-web")
	c.Assert(err, check.IsNil)
	c.Assert(service.Spec.TaskTemplate.ContainerSpec.Command, check.DeepEquals, []string{
		"/bin/sh", "-lc", "[ -d /home/application/current ] && cd /home/application/current; exec python myapp.py",
	})
}

func (s *S) TestActionUpdateServicesBackwardNotInCurrent(c *check.C) {
	srv, err := testing.NewServer("127.0.0.1:0", nil, nil)
	c.Assert(err, check.IsNil)
	metadata := map[string]string{"m1": "v1", "pool": "p1"}
	opts := provision.AddNodeOptions{
		Address:  srv.URL(),
		Metadata: metadata,
	}
	err = s.p.AddNode(opts)
	c.Assert(err, check.IsNil)
	cli, err := chooseDBSwarmNode()
	c.Assert(err, check.IsNil)
	a := &app.App{Name: "myapp", Platform: "whitespace", TeamOwner: s.team.Name}
	err = app.CreateApp(a, s.user)
	c.Assert(err, check.IsNil)
	_, err = cli.CreateService(docker.CreateServiceOptions{
		ServiceSpec: swarm.ServiceSpec{
			TaskTemplate: swarm.TaskSpec{
				ContainerSpec: swarm.ContainerSpec{
					Command: []string{"original-web"},
				},
			},
			Annotations: swarm.Annotations{
				Name: "myapp-web",
			},
		},
	})
	c.Assert(err, check.IsNil)
	imgName := "app:v1"
	err = image.SaveImageCustomData(imgName, map[string]interface{}{
		"processes": map[string]interface{}{
			"web": "python myapp.py",
		},
	})
	c.Assert(err, check.IsNil)
	args := &pipelineArgs{
		client:       cli,
		app:          a,
		currentImage: imgName,
		newImgData: &image.ImageMetadata{
			Processes: map[string]string{"web": ""},
		},
		currentImgData: &image.ImageMetadata{},
	}
	updateServices.Backward(action.BWContext{
		FWResult: []string{"web"},
		Params:   []interface{}{args},
	})
	_, err = cli.InspectService("myapp-web")
	c.Assert(err, check.ErrorMatches, "No such service.*")
}
<|endoftext|>


<commit_before>// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// 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 sqlite3

import (
	"context"
	"database/sql"
	"strings"

	"github.com/matrix-org/dendrite/internal"
	"github.com/matrix-org/dendrite/internal/eventutil"
	"github.com/matrix-org/dendrite/internal/sqlutil"
	"github.com/matrix-org/dendrite/syncapi/storage/tables"
	"github.com/matrix-org/dendrite/syncapi/types"
)

func NewSqliteNotificationDataTable(db *sql.DB, streamID *StreamIDStatements) (tables.NotificationData, error) {
	_, err := db.Exec(notificationDataSchema)
	if err != nil {
		return nil, err
	}
	r := &notificationDataStatements{
		streamIDStatements: streamID,
		db:                 db,
	}
	return r, sqlutil.StatementList{
		{&r.upsertRoomUnreadCounts, upsertRoomUnreadNotificationCountsSQL},
		{&r.selectMaxID, selectMaxNotificationIDSQL},
		// {&r.selectUserUnreadCountsForRooms, selectUserUnreadNotificationsForRooms}, // used at runtime
	}.Prepare(db)
}

type notificationDataStatements struct {
	db                     *sql.DB
	streamIDStatements     *StreamIDStatements
	upsertRoomUnreadCounts *sql.Stmt
	selectMaxID            *sql.Stmt
	//selectUserUnreadCountsForRooms *sql.Stmt
}

const notificationDataSchema = `
CREATE TABLE IF NOT EXISTS syncapi_notification_data (
	id INTEGER PRIMARY KEY,
	user_id TEXT NOT NULL,
	room_id TEXT NOT NULL,
	notification_count BIGINT NOT NULL DEFAULT 0,
	highlight_count BIGINT NOT NULL DEFAULT 0,
	CONSTRAINT syncapi_notifications_unique UNIQUE (user_id, room_id)
);`

const upsertRoomUnreadNotificationCountsSQL = `INSERT INTO syncapi_notification_data
  (user_id, room_id, notification_count, highlight_count)
  VALUES ($1, $2, $3, $4)
  ON CONFLICT (user_id, room_id)
  DO UPDATE SET id = $5, notification_count = $6, highlight_count = $7`

const selectUserUnreadNotificationsForRooms = `SELECT room_id, notification_count, highlight_count
	FROM syncapi_notification_data
	WHERE user_id = $1 AND
	      room_id IN ($2)`

const selectMaxNotificationIDSQL = `SELECT CASE COUNT(*) WHEN 0 THEN 0 ELSE MAX(id) END FROM syncapi_notification_data`

func (r *notificationDataStatements) UpsertRoomUnreadCounts(ctx context.Context, txn *sql.Tx, userID, roomID string, notificationCount, highlightCount int) (pos types.StreamPosition, err error) {
	pos, err = r.streamIDStatements.nextNotificationID(ctx, nil)
	if err != nil {
		return
	}
	_, err = r.upsertRoomUnreadCounts.ExecContext(ctx, userID, roomID, notificationCount, highlightCount, pos, notificationCount, highlightCount)
	return
}

func (r *notificationDataStatements) SelectUserUnreadCountsForRooms(
	ctx context.Context, txn *sql.Tx, userID string, roomIDs []string,
) (map[string]*eventutil.NotificationData, error) {
	params := make([]interface{}, len(roomIDs)+1)
	params[0] = userID
	for i := range roomIDs {
		params[i+1] = roomIDs[i]
	}
	sql := strings.Replace(selectUserUnreadNotificationsForRooms, "($1)", sqlutil.QueryVariadic(len(params)), 1)
	rows, err := r.db.QueryContext(ctx, sql, params)
	if err != nil {
		return nil, err
	}
	defer internal.CloseAndLogIfError(ctx, rows, "SelectUserUnreadCountsForRooms: rows.close() failed")

	roomCounts := map[string]*eventutil.NotificationData{}
	var roomID string
	var notificationCount, highlightCount int
	for rows.Next() {
		if err = rows.Scan(&roomID, &notificationCount, &highlightCount); err != nil {
			return nil, err
		}

		roomCounts[roomID] = &eventutil.NotificationData{
			RoomID:                  roomID,
			UnreadNotificationCount: notificationCount,
			UnreadHighlightCount:    highlightCount,
		}
	}
	return roomCounts, rows.Err()
}

func (r *notificationDataStatements) SelectMaxID(ctx context.Context, txn *sql.Tx) (int64, error) {
	var id int64
	err := sqlutil.TxStmt(txn, r.selectMaxID).QueryRowContext(ctx).Scan(&id)
	return id, err
}
<commit_msg>Fix for `sql: converting argument $1 type: unsupported type []interfa… (#2743)<commit_after>// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// 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 sqlite3

import (
	"context"
	"database/sql"
	"strings"

	"github.com/matrix-org/dendrite/internal"
	"github.com/matrix-org/dendrite/internal/eventutil"
	"github.com/matrix-org/dendrite/internal/sqlutil"
	"github.com/matrix-org/dendrite/syncapi/storage/tables"
	"github.com/matrix-org/dendrite/syncapi/types"
)

func NewSqliteNotificationDataTable(db *sql.DB, streamID *StreamIDStatements) (tables.NotificationData, error) {
	_, err := db.Exec(notificationDataSchema)
	if err != nil {
		return nil, err
	}
	r := &notificationDataStatements{
		streamIDStatements: streamID,
		db:                 db,
	}
	return r, sqlutil.StatementList{
		{&r.upsertRoomUnreadCounts, upsertRoomUnreadNotificationCountsSQL},
		{&r.selectMaxID, selectMaxNotificationIDSQL},
		// {&r.selectUserUnreadCountsForRooms, selectUserUnreadNotificationsForRooms}, // used at runtime
	}.Prepare(db)
}

type notificationDataStatements struct {
	db                     *sql.DB
	streamIDStatements     *StreamIDStatements
	upsertRoomUnreadCounts *sql.Stmt
	selectMaxID            *sql.Stmt
	//selectUserUnreadCountsForRooms *sql.Stmt
}

const notificationDataSchema = `
CREATE TABLE IF NOT EXISTS syncapi_notification_data (
	id INTEGER PRIMARY KEY,
	user_id TEXT NOT NULL,
	room_id TEXT NOT NULL,
	notification_count BIGINT NOT NULL DEFAULT 0,
	highlight_count BIGINT NOT NULL DEFAULT 0,
	CONSTRAINT syncapi_notifications_unique UNIQUE (user_id, room_id)
);`

const upsertRoomUnreadNotificationCountsSQL = `INSERT INTO syncapi_notification_data
  (user_id, room_id, notification_count, highlight_count)
  VALUES ($1, $2, $3, $4)
  ON CONFLICT (user_id, room_id)
  DO UPDATE SET id = $5, notification_count = $6, highlight_count = $7`

const selectUserUnreadNotificationsForRooms = `SELECT room_id, notification_count, highlight_count
	FROM syncapi_notification_data
	WHERE user_id = $1 AND
	      room_id IN ($2)`

const selectMaxNotificationIDSQL = `SELECT CASE COUNT(*) WHEN 0 THEN 0 ELSE MAX(id) END FROM syncapi_notification_data`

func (r *notificationDataStatements) UpsertRoomUnreadCounts(ctx context.Context, txn *sql.Tx, userID, roomID string, notificationCount, highlightCount int) (pos types.StreamPosition, err error) {
	pos, err = r.streamIDStatements.nextNotificationID(ctx, nil)
	if err != nil {
		return
	}
	_, err = r.upsertRoomUnreadCounts.ExecContext(ctx, userID, roomID, notificationCount, highlightCount, pos, notificationCount, highlightCount)
	return
}

func (r *notificationDataStatements) SelectUserUnreadCountsForRooms(
	ctx context.Context, txn *sql.Tx, userID string, roomIDs []string,
) (map[string]*eventutil.NotificationData, error) {
	params := make([]interface{}, len(roomIDs)+1)
	params[0] = userID
	for i := range roomIDs {
		params[i+1] = roomIDs[i]
	}
	sql := strings.Replace(selectUserUnreadNotificationsForRooms, "($2)", sqlutil.QueryVariadicOffset(len(roomIDs), 1), 1)
	rows, err := r.db.QueryContext(ctx, sql, params...)
	if err != nil {
		return nil, err
	}
	defer internal.CloseAndLogIfError(ctx, rows, "SelectUserUnreadCountsForRooms: rows.close() failed")

	roomCounts := map[string]*eventutil.NotificationData{}
	var roomID string
	var notificationCount, highlightCount int
	for rows.Next() {
		if err = rows.Scan(&roomID, &notificationCount, &highlightCount); err != nil {
			return nil, err
		}

		roomCounts[roomID] = &eventutil.NotificationData{
			RoomID:                  roomID,
			UnreadNotificationCount: notificationCount,
			UnreadHighlightCount:    highlightCount,
		}
	}
	return roomCounts, rows.Err()
}

func (r *notificationDataStatements) SelectMaxID(ctx context.Context, txn *sql.Tx) (int64, error) {
	var id int64
	err := sqlutil.TxStmt(txn, r.selectMaxID).QueryRowContext(ctx).Scan(&id)
	return id, err
}
<|endoftext|>


<commit_before>package bind

import (
	"bufio"
	"github.com/devigned/veil/cgo"
	"github.com/devigned/veil/core"
	"os"
	"path"
	"regexp"
	"strings"
	"text/template"
	"unicode"
)

const (
	HEADER_FILE_NAME = "output.h"
	PYTHON_FILE_NAME = "generated.py"
	PYTHON_TEMPLATE  = `import os
import sys
import cffi as _cffi_backend

_PY3 = sys.version_info[0] == 3

ffi = _cffi_backend.FFI()
ffi.cdef("""{{.CDef}}""")

class _CffiHelper(object):

    here = os.path.dirname(os.path.abspath(__file__))
    lib = ffi.dlopen(os.path.join(here, "output"))

    @staticmethod
    def error_string(err):
        ptr = ffi.cast("void *", err)
        return _CffiHelper.lib.cgo_error_to_string(ptr)

    @staticmethod
    def c2py_string(s):
        pystr = ffi.string(s)
        _CffiHelper.lib.cgo_cfree(s)
        if _PY3:
            pystr = pystr.decode('utf-8')
        return pystr

# Globally defined functions
{{range $_, $func := .Funcs}}
def {{$func.Name}}({{$func.PrintArgs}}):
    {{range $_, $func := .Funcs}}

    {{end}}
    pass

{{end}}

`
)

var (
	startCGoDefine  = regexp.MustCompile(`^#define GO_CGO_PROLOGUE_H`)
	sizeOfRemove    = regexp.MustCompile(`_check_for_64_bit_pointer_matching_GoInt`)
	complexRemove   = regexp.MustCompile(`_Complex`)
	endif           = regexp.MustCompile(`^#endif`)
	endOfCGoDefine  = regexp.MustCompile(`^#ifdef __cplusplus`)
	extern          = regexp.MustCompile(`^extern`)
	sizeTypeReplace = regexp.MustCompile(`__SIZE_TYPE__`)
	removeFilters   = []*regexp.Regexp{sizeOfRemove, complexRemove}
	replaceFilters  = map[string]*regexp.Regexp{"size_t": sizeTypeReplace}
)

var pythonTemplate *template.Template

func init() {
	replacedTabsTemplate := removeTabs(PYTHON_TEMPLATE)
	if tmpl, err := template.New("codeTemplate").Parse(replacedTabsTemplate); err != nil {
		panic(err)

	} else {
		pythonTemplate = tmpl
	}
}

func removeTabs(src string) string {
	return strings.Replace(src, "\t", "  ", -1)
}

// Py3Binder contains the data for generating a python 3 binding
type Py3Binder struct {
	pkg *cgo.Package
}

type PyTemplateData struct {
	CDef  string
	Funcs []*PyFunc
}

type PyFunc struct {
	Name      string
	Arguments []string
}

func (p PyFunc) PrintArgs() string {
	return strings.Join(p.Arguments, ", ")
}

// NewPy3Binder creates a new Binder for Python 3
func NewPy3Binder(pkg *cgo.Package) Bindable {
	return &Py3Binder{
		pkg: pkg,
	}
}

// Bind is the Python 3 implementation of Bind
func (p Py3Binder) Bind(outDir string) error {
	headerPath := path.Join(outDir, HEADER_FILE_NAME)
	cdefText, err := p.cDefText(headerPath)
	if err != nil {
		return core.NewSystemErrorF("Failed to generate Python CDefs: %v", err)
	}

	data := PyTemplateData{
		CDef:  strings.Join(cdefText, "\n"),
		Funcs: p.Funcs(),
	}

	f, err := os.Create(path.Join(outDir, PYTHON_FILE_NAME))
	if err != nil {
		return core.NewSystemErrorF("Unable to create %s", path.Join(outDir, PYTHON_FILE_NAME))
	}

	defer f.Close()

	w := bufio.NewWriter(f)
	pythonTemplate.Execute(w, data)
	w.Flush()

	return nil
}

func (p Py3Binder) Funcs() []*PyFunc {
	funcs := make([]*PyFunc, len(p.pkg.Funcs()))

	for idx, f := range p.pkg.Funcs() {

		argNames := make([]string, f.Signature().Params().Len())
		for i := 0; i < f.Signature().Params().Len(); i++ {
			param := f.Signature().Params().At(i)
			argNames[i] = ToSnake(param.Name())
		}

		funcs[idx] = &PyFunc{
			Name:      ToSnake(f.Name()),
			Arguments: argNames,
		}
	}
	return funcs
}

func (p Py3Binder) cDefText(headerPath string) ([]string, error) {
	if file, err := os.Open(headerPath); err == nil {
		defer file.Close()

		filteredHeaders := []string{}
		recording := false

		// create a new scanner and read the file line by line
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			text := scanner.Text()

			if recording {
				if endif.MatchString(text) || endOfCGoDefine.MatchString(text) {
					recording = false
					continue
				}

				matched := false
				for _, filter := range removeFilters {
					if filter.MatchString(text) {
						matched = true
						break
					}
				}

				if !matched {
					for key, value := range replaceFilters {
						if value.MatchString(text) {
							text = value.ReplaceAllString(text, key)
						}
					}
					text = removeTabs(text)
					filteredHeaders = append(filteredHeaders, text)
				}
			}

			if !recording && (startCGoDefine.MatchString(text) || extern.MatchString(text)) {
				recording = true
			}
		}

		// check for errors
		if err = scanner.Err(); err != nil {
			return nil, core.NewSystemError(err)
		}

		return filteredHeaders, nil

	} else {
		return nil, core.NewSystemError(err)
	}
}

// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
// via: https://gist.github.com/elwinar/14e1e897fdbe4d3432e1
func ToSnake(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}
<commit_msg>python formatting and calling cgo<commit_after>package bind

import (
	"bufio"
	"github.com/devigned/veil/cgo"
	"github.com/devigned/veil/core"
	"go/types"
	"log"
	"os"
	"os/exec"
	"path"
	"regexp"
	"strings"
	"text/template"
	"unicode"
)

const (
	HEADER_FILE_NAME = "output.h"
	PYTHON_FILE_NAME = "generated.py"
	PYTHON_TEMPLATE  = `import os
import sys
import cffi as _cffi_backend

_PY3 = sys.version_info[0] == 3

ffi = _cffi_backend.FFI()
ffi.cdef("""{{.CDef}}""")

class _CffiHelper(object):

    here = os.path.dirname(os.path.abspath(__file__))
    lib = ffi.dlopen(os.path.join(here, "output"))

    @staticmethod
    def error_string(err):
        ptr = ffi.cast("void *", err)
        return _CffiHelper.lib.cgo_error_to_string(ptr)

    @staticmethod
    def c2py_string(s):
        pystr = ffi.string(s)
        _CffiHelper.lib.cgo_cfree(s)
        if _PY3:
            pystr = pystr.decode('utf-8')
        return pystr

# Globally defined functions
{{range $_, $func := .Funcs}}
def {{$func.Name}}({{$func.PrintArgs}}):
    {{ range $_, $inTrx := $func.InputTransforms -}}
      {{ $inTrx }}
    {{ end -}}
    return _CffiHelper.lib.{{$func.Call}}

{{end}}

`
)

var (
	startCGoDefine  = regexp.MustCompile(`^#define GO_CGO_PROLOGUE_H`)
	sizeOfRemove    = regexp.MustCompile(`_check_for_64_bit_pointer_matching_GoInt`)
	complexRemove   = regexp.MustCompile(`_Complex`)
	endif           = regexp.MustCompile(`^#endif`)
	endOfCGoDefine  = regexp.MustCompile(`^#ifdef __cplusplus`)
	extern          = regexp.MustCompile(`^extern`)
	sizeTypeReplace = regexp.MustCompile(`__SIZE_TYPE__`)
	removeFilters   = []*regexp.Regexp{sizeOfRemove, complexRemove}
	replaceFilters  = map[string]*regexp.Regexp{"size_t": sizeTypeReplace}
)

var pythonTemplate *template.Template

func init() {
	replacedTabsTemplate := removeTabs(PYTHON_TEMPLATE)
	if tmpl, err := template.New("codeTemplate").Parse(replacedTabsTemplate); err != nil {
		panic(err)

	} else {
		pythonTemplate = tmpl
	}
}

func removeTabs(src string) string {
	return strings.Replace(src, "\t", "  ", -1)
}

// Py3Binder contains the data for generating a python 3 binding
type Py3Binder struct {
	pkg *cgo.Package
}

type PyTemplateData struct {
	CDef  string
	Funcs []*PyFunc
}

type PyParam struct {
	underlying     *types.Var
	InputTransform string
}

func NewPyParam(v *types.Var) *PyParam {
	return &PyParam{underlying: v}
}

func (p PyParam) HasInputTransform() bool {
	return p.InputTransform != ""
}

func (p PyParam) Name() string {
	return ToSnake(p.underlying.Name())
}

type PyFunc struct {
	fun    cgo.Func
	Name   string
	Params []*PyParam
}

func (f PyFunc) InputTransforms() []string {
	// TODO: add input transformations
	return []string{}
}

func (f PyFunc) Call() string {
	return f.fun.CGoName() + "(" + f.PrintArgs() + ")"
}

func (f PyFunc) PrintArgs() string {
	names := make([]string, len(f.Params))
	for i := 0; i < len(names); i++ {
		names[i] = f.Params[i].Name()
	}
	return strings.Join(names, ", ")
}

// NewPy3Binder creates a new Binder for Python 3
func NewPy3Binder(pkg *cgo.Package) Bindable {
	return &Py3Binder{
		pkg: pkg,
	}
}

// Bind is the Python 3 implementation of Bind
func (p Py3Binder) Bind(outDir string) error {
	headerPath := path.Join(outDir, HEADER_FILE_NAME)
	cdefText, err := p.cDefText(headerPath)
	if err != nil {
		return core.NewSystemErrorF("Failed to generate Python CDefs: %v", err)
	}

	data := PyTemplateData{
		CDef:  strings.Join(cdefText, "\n"),
		Funcs: p.Funcs(),
	}

	pythonFilePath := path.Join(outDir, PYTHON_FILE_NAME)
	f, err := os.Create(pythonFilePath)
	if err != nil {
		return core.NewSystemErrorF("Unable to create %s", path.Join(outDir, PYTHON_FILE_NAME))
	}

	w := bufio.NewWriter(f)
	pythonTemplate.Execute(w, data)
	w.Flush()
	f.Close()

	PyFormat(pythonFilePath)

	return nil
}

func (p Py3Binder) Funcs() []*PyFunc {
	funcs := make([]*PyFunc, len(p.pkg.Funcs()))

	for idx, f := range p.pkg.Funcs() {

		pyParams := make([]*PyParam, f.Signature().Params().Len())
		for i := 0; i < f.Signature().Params().Len(); i++ {
			param := f.Signature().Params().At(i)
			pyParams[i] = NewPyParam(param)
		}

		funcs[idx] = &PyFunc{
			fun:    f,
			Name:   ToSnake(f.Name()),
			Params: pyParams,
		}
	}
	return funcs
}

func (p Py3Binder) cDefText(headerPath string) ([]string, error) {
	if file, err := os.Open(headerPath); err == nil {
		defer file.Close()

		filteredHeaders := []string{}
		recording := false

		// create a new scanner and read the file line by line
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			text := scanner.Text()

			if recording {
				if endif.MatchString(text) || endOfCGoDefine.MatchString(text) {
					recording = false
					continue
				}

				matched := false
				for _, filter := range removeFilters {
					if filter.MatchString(text) {
						matched = true
						break
					}
				}

				if !matched {
					for key, value := range replaceFilters {
						if value.MatchString(text) {
							text = value.ReplaceAllString(text, key)
						}
					}
					text = removeTabs(text)
					filteredHeaders = append(filteredHeaders, text)
				}
			}

			if !recording && (startCGoDefine.MatchString(text) || extern.MatchString(text)) {
				recording = true
			}
		}

		// check for errors
		if err = scanner.Err(); err != nil {
			return nil, core.NewSystemError(err)
		}

		return filteredHeaders, nil

	} else {
		return nil, core.NewSystemError(err)
	}
}

// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
// via: https://gist.github.com/elwinar/14e1e897fdbe4d3432e1
func ToSnake(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}

func PyFormat(path string) {
	which := exec.Command("which", "yapf")
	if err := which.Run(); err == nil {
		cmd := exec.Command("yapf", "-i", "--style={based_on_style: pep8, column_limit: 100}", path)
		err = cmd.Run()
	} else {
		log.Println("To format your Python code run `pip install yapf`")
	}
}
<|endoftext|>


<commit_before>package stringUtils

import "testing"

func TestAbbreviate(t *testing.T) {
	if Abbreviate("", 4) != "" {
		t.Errorf("fail test abbreviate 1")
	}
	if Abbreviate("abcdefg", 6) != "abc..." {
		t.Errorf("fail test abbreviate 2")
	}
	if Abbreviate("abcdefg", 7) != "abcdefg" {
		t.Errorf("fail test abbreviate 2")
	}
	if Abbreviate("abcdefg", 8) != "abcdefg" {
		t.Errorf("fail test abbreviate 3")
	}
	if Abbreviate("abcdefg", 4) != "a..." {
		t.Errorf("fail test abbreviate 4")
	}
}

func TestAbbreviateWithOffset(t *testing.T) {
	if AbbreviateWithOffset("", 0, 4) != "" {
		t.Errorf("fail test abbreviate 1")
	}
	if AbbreviateWithOffset("abcdefghijklmno", -1, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 2")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 0, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 3")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 1, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 4")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 4, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 5")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 5, 10) != "...fghi..." {
		t.Errorf("fail test abbreviate 5")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 6, 10) != "...ghij..." {
		t.Errorf("fail test abbreviate 6")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 8, 10) != "...ijklmno" {
		t.Errorf("fail test abbreviate 7")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 10, 10) != "...ijklmno" {
		t.Errorf("fail test abbreviate 8")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 12, 10) != "...ijklmno" {
		t.Errorf("fail test abbreviate 9")
	}
	if AbbreviateWithOffset("abcdefghij", 0, 3) != "abcdefghij" {
		t.Errorf("fail test abbreviate 10")
	}
	if AbbreviateWithOffset("abcdefghij", 5, 6) != "abcdefghij" {
		t.Errorf("fail test abbreviate 11")
	}
}

func TestAppendIfMissing(t *testing.T) {
	if AppendIfMissing("abc", "") != "abc" {
		t.Errorf("fail test AppendIfMissing 1")
	}
	if AppendIfMissing("", "xyz") != "" {
		t.Errorf("fail test AppendIfMissing 2")
	}
	if AppendIfMissing("abc", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissing 3")
	}
	if AppendIfMissing("abcxyz", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissing 4")
	}
	if AppendIfMissing("abcXYZ", "xyz") != "abcXYZxyz" {
		t.Errorf("fail test AppendIfMissing 5")
	}
}

func TestAppendIfMissingIgnoreCase(t *testing.T) {
	if AppendIfMissingIgnoreCase("abc", "") != "abc" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 1")
	}
	if AppendIfMissingIgnoreCase("", "xyz") != "" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 2")
	}
	if AppendIfMissingIgnoreCase("abc", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 3")
	}
	if AppendIfMissingIgnoreCase("abcxyz", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 4")
	}
	if AppendIfMissingIgnoreCase("abcXYZ", "xyz") != "abcXYZ" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 5")
	}
}

func TestCapitalize(t *testing.T) {
	if Capitalize("") != "" {
		t.Errorf("fail test capitalize 1")
	}
	if Capitalize("cat") != "Cat" {
		t.Errorf("fail test capitalize 2")
	}
	if Capitalize("cAt") != "CAt" {
		t.Errorf("fail test capitalize 3")
	}
}

func TestChomp(t *testing.T) {
	if Chomp("") != "" {
		t.Errorf("fail test chomp 1")
	}
	if Chomp("abc \r") != "abc " {
		t.Errorf("fail test chomp 2")
	}
	if Chomp("abc\n") != "abc" {
		t.Errorf("fail test chomp 3")
	}
	if Chomp("abc\r\n") != "abc" {
		t.Errorf("fail test chomp 4")
	}
	if Chomp("abc\r\n\r\n") != "abc\r\n" {
		t.Errorf("fail test chomp 5")
	}
	if Chomp("abc\n\r") != "abc\n" {
		t.Errorf("fail test chomp 6")
	}
	if Chomp("abc\n\rabc") != "abc\n\rabc" {
		t.Errorf("fail test chomp 7")
	}
	if Chomp("\r") != "" {
		t.Errorf("fail test chomp 8")
	}
	if Chomp("\n") != "" {
		t.Errorf("fail test chomp 9")
	}
	if Chomp("\r\n") != "" {
		t.Errorf("fail test chomp 10")
	}
}

func TestChop(t *testing.T) {
	if Chop("") != "" {
		t.Errorf("fail test chop 1")
	}
	if Chop("abc \r") != "abc " {
		t.Errorf("fail test chop 2")
	}
	if Chop("abc\n") != "abc" {
		t.Errorf("fail test chop 3")
	}
	if Chop("abc\r\n") != "abc" {
		t.Errorf("fail test chop 4")
	}
	if Chop("abc\r\n\r\n") != "abc\r\n" {
		t.Errorf("fail test chop 5")
	}
	if Chop("abc\n\r") != "abc\n" {
		t.Errorf("fail test chop 6")
	}
	if Chop("abc\n\rabc") != "abc\n\rab" {
		t.Errorf("fail test chop 7")
	}
	if Chop("\r") != "" {
		t.Errorf("fail test chop 8")
	}
	if Chop("\n") != "" {
		t.Errorf("fail test chop 9")
	}
	if Chop("\r\n") != "" {
		t.Errorf("fail test chop 10")
	}
}

func TestIsAllLowerCase(t *testing.T) {
	if IsAllLowerCase("") != false {
		t.Errorf("fail test IsAllLowerCase 1")
	}
	if IsAllLowerCase("  ") != false {
		t.Errorf("fail test IsAllLowerCase 2")
	}
	if IsAllLowerCase("abc") != true {
		t.Errorf("fail test IsAllLowerCase 3")
	}
	if IsAllLowerCase("abC") != false {
		t.Errorf("fail test IsAllLowerCase 4")
	}
	if IsAllLowerCase("ab c") != false {
		t.Errorf("fail test IsAllLowerCase 5")
	}
	if IsAllLowerCase("ab1c") != false {
		t.Errorf("fail test IsAllLowerCase 6")
	}
	if IsAllLowerCase("ab/c") != false {
		t.Errorf("fail test IsAllLowerCase 7")
	}
}

func TestIsAllUpperCase(t *testing.T) {
	if IsAllUpperCase("") != false {
		t.Errorf("fail test IsAllUpperCase 1")
	}
	if IsAllUpperCase("  ") != false {
		t.Errorf("fail test IsAllUpperCase 2")
	}
	if IsAllUpperCase("ABC") != true {
		t.Errorf("fail test IsAllUpperCase 3")
	}
	if IsAllUpperCase("aBC") != false {
		t.Errorf("fail test IsAllUpperCase 4")
	}
	if IsAllUpperCase("A C") != false {
		t.Errorf("fail test IsAllUpperCase 5")
	}
	if IsAllUpperCase("A1C") != false {
		t.Errorf("fail test IsAllUpperCase 6")
	}
	if IsAllUpperCase("A/C") != false {
		t.Errorf("fail test IsAllUpperCase 7")
	}
}

func TestOverlay(t *testing.T) {
	if Overlay("", "abc", 0, 0) != "abc" {
		t.Errorf("fail test Overlay 1")
	}
	if Overlay("abcdef", "", 2, 4) != "abef" {
		t.Errorf("fail test Overlay 2")
	}
	if Overlay("abcdef", "", 4, 2) != "abef" {
		t.Errorf("fail test Overlay 3")
	}
	if Overlay("abcdef", "zzzz", 2, 4) != "abzzzzef" {
		t.Errorf("fail test Overlay 4")
	}
	if Overlay("abcdef", "zzzz", 4, 2) != "abzzzzef" {
		t.Errorf("fail test Overlay 5")
	}
	if Overlay("abcdef", "zzzz", -1, 4) != "zzzzef" {
		t.Errorf("fail test Overlay 6")
	}
	if Overlay("abcdef", "zzzz", 2, 8) != "abzzzz" {
		t.Errorf("fail test Overlay 7")
	}
	if Overlay("abcdef", "zzzz", -2, -3) != "zzzzabcdef" {
		t.Errorf("fail test Overlay 8")
	}
	if Overlay("abcdef", "zzzz", 8, 10) != "abcdefzzzz" {
		t.Errorf("fail test Overlay 9")
	}
}

func TestRemove(t *testing.T) {
	if Remove("", "abc") != "" {
		t.Errorf("fail test Remove 1")
	}
	if Remove("queued", "u") != "qeed" {
		t.Errorf("fail test Remove 2")
	}
	if Remove("queued", "z") != "queued" {
		t.Errorf("fail test Remove 3")
	}
}

func TestRepeat(t *testing.T) {
	if Repeat("a", 3) != "aaa" {
		t.Errorf("fail test Repeat 1")
	}
	if Repeat("abc", 3) != "abcabcabc" {
		t.Errorf("fail test Repeat 2")
	}
}

func TestRepeatWithSeparator(t *testing.T) {
	if RepeatWithSeparator("a", ",", 3) != "a,a,a" {
		t.Errorf("fail test RepeatWithSeparator 1")
	}
	if RepeatWithSeparator("abc", "-", 3) != "abc-abc-abc" {
		t.Errorf("fail test RepeatWithSeparator 2")
	}
}

func TestStrip(t *testing.T) {
	if Strip("   abc   ") != "abc" {
		t.Errorf("fail test Strip 1")
	}
	if Strip("  . a  bc :    ") != ". a  bc :" {
		t.Errorf("fail test Strip 2")
	}
	if Strip("abc") != "abc" {
		t.Errorf("fail test Strip 3")
	}
}

func TestSubstrings(t *testing.T) {
	if SubstringBefore("abc.def.ghi", ".") != "abc" {
		t.Errorf("fail test SubstringBefore 1")
	}
	if SubstringBefore("abc.def", "g") != "abc.def" {
		t.Errorf("fail test SubstringBefore 2")
	}
	if SubstringBeforeLast("abc.def.ghi", ".") != "abc.def" {
		t.Errorf("fail test SubstringBeforeLast 1")
	}
	if SubstringAfter("abc.def.ghi", ".") != "def.ghi" {
		t.Errorf("fail test SubstringAfter 1")
	}
	if SubstringAfter("abc.def", "g") != "abc.def" {
		t.Errorf("fail test SubstringAfter 2")
	}
	if SubstringAfterLast("abc.def.ghi", ".") != "ghi" {
		t.Errorf("fail test SubstringAfterLast 1")
	}
}

func TestSwapCase(t *testing.T) {
	if SwapCase("abc.def") != "ABC.DEF" {
		t.Errorf("fail test SwapCase 1")
	}
	if SwapCase("aBc.dEf") != "AbC.DeF" {
		t.Errorf("fail test SwapCase 2")
	}
	if SwapCase(" ABC.def ") != " abc.DEF " {
		t.Errorf("fail test SwapCase 3")
	}
}

func TestUncapitalize(t *testing.T) {
	if Uncapitalize("AbcDef") != "abcDef" {
		t.Errorf("fail test Uncapitalize 1")
	}
	if Uncapitalize("abcDef") != "abcDef" {
		t.Errorf("fail test Uncapitalize 2")
	}
	if Uncapitalize("世界") != "世界" {
		t.Errorf("fail test Uncapitalize 3")
	}
}
<commit_msg>test: EndsWith<commit_after>package stringUtils

import "testing"

func TestAbbreviate(t *testing.T) {
	if Abbreviate("", 4) != "" {
		t.Errorf("fail test abbreviate 1")
	}
	if Abbreviate("abcdefg", 6) != "abc..." {
		t.Errorf("fail test abbreviate 2")
	}
	if Abbreviate("abcdefg", 7) != "abcdefg" {
		t.Errorf("fail test abbreviate 2")
	}
	if Abbreviate("abcdefg", 8) != "abcdefg" {
		t.Errorf("fail test abbreviate 3")
	}
	if Abbreviate("abcdefg", 4) != "a..." {
		t.Errorf("fail test abbreviate 4")
	}
}

func TestAbbreviateWithOffset(t *testing.T) {
	if AbbreviateWithOffset("", 0, 4) != "" {
		t.Errorf("fail test abbreviate 1")
	}
	if AbbreviateWithOffset("abcdefghijklmno", -1, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 2")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 0, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 3")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 1, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 4")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 4, 10) != "abcdefg..." {
		t.Errorf("fail test abbreviate 5")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 5, 10) != "...fghi..." {
		t.Errorf("fail test abbreviate 5")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 6, 10) != "...ghij..." {
		t.Errorf("fail test abbreviate 6")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 8, 10) != "...ijklmno" {
		t.Errorf("fail test abbreviate 7")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 10, 10) != "...ijklmno" {
		t.Errorf("fail test abbreviate 8")
	}
	if AbbreviateWithOffset("abcdefghijklmno", 12, 10) != "...ijklmno" {
		t.Errorf("fail test abbreviate 9")
	}
	if AbbreviateWithOffset("abcdefghij", 0, 3) != "abcdefghij" {
		t.Errorf("fail test abbreviate 10")
	}
	if AbbreviateWithOffset("abcdefghij", 5, 6) != "abcdefghij" {
		t.Errorf("fail test abbreviate 11")
	}
}

func TestAppendIfMissing(t *testing.T) {
	if AppendIfMissing("abc", "") != "abc" {
		t.Errorf("fail test AppendIfMissing 1")
	}
	if AppendIfMissing("", "xyz") != "" {
		t.Errorf("fail test AppendIfMissing 2")
	}
	if AppendIfMissing("abc", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissing 3")
	}
	if AppendIfMissing("abcxyz", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissing 4")
	}
	if AppendIfMissing("abcXYZ", "xyz") != "abcXYZxyz" {
		t.Errorf("fail test AppendIfMissing 5")
	}
}

func TestAppendIfMissingIgnoreCase(t *testing.T) {
	if AppendIfMissingIgnoreCase("abc", "") != "abc" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 1")
	}
	if AppendIfMissingIgnoreCase("", "xyz") != "" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 2")
	}
	if AppendIfMissingIgnoreCase("abc", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 3")
	}
	if AppendIfMissingIgnoreCase("abcxyz", "xyz") != "abcxyz" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 4")
	}
	if AppendIfMissingIgnoreCase("abcXYZ", "xyz") != "abcXYZ" {
		t.Errorf("fail test AppendIfMissingIgnoreCase 5")
	}
}

func TestCapitalize(t *testing.T) {
	if Capitalize("") != "" {
		t.Errorf("fail test capitalize 1")
	}
	if Capitalize("cat") != "Cat" {
		t.Errorf("fail test capitalize 2")
	}
	if Capitalize("cAt") != "CAt" {
		t.Errorf("fail test capitalize 3")
	}
}

func TestChomp(t *testing.T) {
	if Chomp("") != "" {
		t.Errorf("fail test chomp 1")
	}
	if Chomp("abc \r") != "abc " {
		t.Errorf("fail test chomp 2")
	}
	if Chomp("abc\n") != "abc" {
		t.Errorf("fail test chomp 3")
	}
	if Chomp("abc\r\n") != "abc" {
		t.Errorf("fail test chomp 4")
	}
	if Chomp("abc\r\n\r\n") != "abc\r\n" {
		t.Errorf("fail test chomp 5")
	}
	if Chomp("abc\n\r") != "abc\n" {
		t.Errorf("fail test chomp 6")
	}
	if Chomp("abc\n\rabc") != "abc\n\rabc" {
		t.Errorf("fail test chomp 7")
	}
	if Chomp("\r") != "" {
		t.Errorf("fail test chomp 8")
	}
	if Chomp("\n") != "" {
		t.Errorf("fail test chomp 9")
	}
	if Chomp("\r\n") != "" {
		t.Errorf("fail test chomp 10")
	}
}

func TestChop(t *testing.T) {
	if Chop("") != "" {
		t.Errorf("fail test chop 1")
	}
	if Chop("abc \r") != "abc " {
		t.Errorf("fail test chop 2")
	}
	if Chop("abc\n") != "abc" {
		t.Errorf("fail test chop 3")
	}
	if Chop("abc\r\n") != "abc" {
		t.Errorf("fail test chop 4")
	}
	if Chop("abc\r\n\r\n") != "abc\r\n" {
		t.Errorf("fail test chop 5")
	}
	if Chop("abc\n\r") != "abc\n" {
		t.Errorf("fail test chop 6")
	}
	if Chop("abc\n\rabc") != "abc\n\rab" {
		t.Errorf("fail test chop 7")
	}
	if Chop("\r") != "" {
		t.Errorf("fail test chop 8")
	}
	if Chop("\n") != "" {
		t.Errorf("fail test chop 9")
	}
	if Chop("\r\n") != "" {
		t.Errorf("fail test chop 10")
	}
}

func TestEndsWith(t *testing.T) {
	if EndsWith("foobar", "bazz") != false {
		t.Errorf("fail test EndsWith 1")
	}
	if EndsWith("foobar", "BAR") != false {
		t.Errorf("fail test EndsWith 2")
	}
	if EndsWith("foobar", "bar") != true {
		t.Errorf("fail test EndsWith 3")
	}
}

func TestIsAllLowerCase(t *testing.T) {
	if IsAllLowerCase("") != false {
		t.Errorf("fail test IsAllLowerCase 1")
	}
	if IsAllLowerCase("  ") != false {
		t.Errorf("fail test IsAllLowerCase 2")
	}
	if IsAllLowerCase("abc") != true {
		t.Errorf("fail test IsAllLowerCase 3")
	}
	if IsAllLowerCase("abC") != false {
		t.Errorf("fail test IsAllLowerCase 4")
	}
	if IsAllLowerCase("ab c") != false {
		t.Errorf("fail test IsAllLowerCase 5")
	}
	if IsAllLowerCase("ab1c") != false {
		t.Errorf("fail test IsAllLowerCase 6")
	}
	if IsAllLowerCase("ab/c") != false {
		t.Errorf("fail test IsAllLowerCase 7")
	}
}

func TestIsAllUpperCase(t *testing.T) {
	if IsAllUpperCase("") != false {
		t.Errorf("fail test IsAllUpperCase 1")
	}
	if IsAllUpperCase("  ") != false {
		t.Errorf("fail test IsAllUpperCase 2")
	}
	if IsAllUpperCase("ABC") != true {
		t.Errorf("fail test IsAllUpperCase 3")
	}
	if IsAllUpperCase("aBC") != false {
		t.Errorf("fail test IsAllUpperCase 4")
	}
	if IsAllUpperCase("A C") != false {
		t.Errorf("fail test IsAllUpperCase 5")
	}
	if IsAllUpperCase("A1C") != false {
		t.Errorf("fail test IsAllUpperCase 6")
	}
	if IsAllUpperCase("A/C") != false {
		t.Errorf("fail test IsAllUpperCase 7")
	}
}

func TestOverlay(t *testing.T) {
	if Overlay("", "abc", 0, 0) != "abc" {
		t.Errorf("fail test Overlay 1")
	}
	if Overlay("abcdef", "", 2, 4) != "abef" {
		t.Errorf("fail test Overlay 2")
	}
	if Overlay("abcdef", "", 4, 2) != "abef" {
		t.Errorf("fail test Overlay 3")
	}
	if Overlay("abcdef", "zzzz", 2, 4) != "abzzzzef" {
		t.Errorf("fail test Overlay 4")
	}
	if Overlay("abcdef", "zzzz", 4, 2) != "abzzzzef" {
		t.Errorf("fail test Overlay 5")
	}
	if Overlay("abcdef", "zzzz", -1, 4) != "zzzzef" {
		t.Errorf("fail test Overlay 6")
	}
	if Overlay("abcdef", "zzzz", 2, 8) != "abzzzz" {
		t.Errorf("fail test Overlay 7")
	}
	if Overlay("abcdef", "zzzz", -2, -3) != "zzzzabcdef" {
		t.Errorf("fail test Overlay 8")
	}
	if Overlay("abcdef", "zzzz", 8, 10) != "abcdefzzzz" {
		t.Errorf("fail test Overlay 9")
	}
}

func TestRemove(t *testing.T) {
	if Remove("", "abc") != "" {
		t.Errorf("fail test Remove 1")
	}
	if Remove("queued", "u") != "qeed" {
		t.Errorf("fail test Remove 2")
	}
	if Remove("queued", "z") != "queued" {
		t.Errorf("fail test Remove 3")
	}
}

func TestRepeat(t *testing.T) {
	if Repeat("a", 3) != "aaa" {
		t.Errorf("fail test Repeat 1")
	}
	if Repeat("abc", 3) != "abcabcabc" {
		t.Errorf("fail test Repeat 2")
	}
}

func TestRepeatWithSeparator(t *testing.T) {
	if RepeatWithSeparator("a", ",", 3) != "a,a,a" {
		t.Errorf("fail test RepeatWithSeparator 1")
	}
	if RepeatWithSeparator("abc", "-", 3) != "abc-abc-abc" {
		t.Errorf("fail test RepeatWithSeparator 2")
	}
}

func TestStrip(t *testing.T) {
	if Strip("   abc   ") != "abc" {
		t.Errorf("fail test Strip 1")
	}
	if Strip("  . a  bc :    ") != ". a  bc :" {
		t.Errorf("fail test Strip 2")
	}
	if Strip("abc") != "abc" {
		t.Errorf("fail test Strip 3")
	}
}

func TestSubstrings(t *testing.T) {
	if SubstringBefore("abc.def.ghi", ".") != "abc" {
		t.Errorf("fail test SubstringBefore 1")
	}
	if SubstringBefore("abc.def", "g") != "abc.def" {
		t.Errorf("fail test SubstringBefore 2")
	}
	if SubstringBeforeLast("abc.def.ghi", ".") != "abc.def" {
		t.Errorf("fail test SubstringBeforeLast 1")
	}
	if SubstringAfter("abc.def.ghi", ".") != "def.ghi" {
		t.Errorf("fail test SubstringAfter 1")
	}
	if SubstringAfter("abc.def", "g") != "abc.def" {
		t.Errorf("fail test SubstringAfter 2")
	}
	if SubstringAfterLast("abc.def.ghi", ".") != "ghi" {
		t.Errorf("fail test SubstringAfterLast 1")
	}
}

func TestSwapCase(t *testing.T) {
	if SwapCase("abc.def") != "ABC.DEF" {
		t.Errorf("fail test SwapCase 1")
	}
	if SwapCase("aBc.dEf") != "AbC.DeF" {
		t.Errorf("fail test SwapCase 2")
	}
	if SwapCase(" ABC.def ") != " abc.DEF " {
		t.Errorf("fail test SwapCase 3")
	}
}

func TestUncapitalize(t *testing.T) {
	if Uncapitalize("AbcDef") != "abcDef" {
		t.Errorf("fail test Uncapitalize 1")
	}
	if Uncapitalize("abcDef") != "abcDef" {
		t.Errorf("fail test Uncapitalize 2")
	}
	if Uncapitalize("世界") != "世界" {
		t.Errorf("fail test Uncapitalize 3")
	}
}
<|endoftext|>


<commit_before>package bitvector

import "testing"

// Length of the BitVector
// for the benchmarking portion
const VECTOR_LEN = 1024

func assert( t *testing.T, value bool, format string, args ...interface{} ) {
    if !value {
		t.Errorf(format,args...)
    }
}

func TestAllocationSize(t *testing.T) {
	// test single byte allocation
    for i := 1; i <= 8; i++ {
		v := New(i)
		assert(t, len(v.bits)==1, "wrong allocation size for iteration %d", i)
	}
    // test double byte allocation
    for i := 9; i <= 16; i++ {
		v := New(i)
		assert(t, len(v.bits)==2, "wrong allocation size for iteration %d", i)
	}

    // test array growth
    v := New(1)
    v.Set(1,true)
    assert(t,len(v.bits)==1, "weird allocation after set")
    v.Set(7,true)
    assert(t,len(v.bits)==1, "weird allocation after set")
    v.Set(8,true)
    assert(t,len(v.bits)==2, "weird allocation after set (should have grown to 16)")
    w := New(1)
    w.Set(17,true)
    assert(t,len(w.bits)==3, "didn't grow correctly (should have grown to 3 bytes)")
}

func TestSetGet(t *testing.T) {
	v := New(8)
    w := New(16)
    v.Set(0,true)
    assert(t,v.Get(0),"didn't set correctly")
    assert(t,v.GetInt(0)==1,"didn't set correctly")
    for i := 1; i < 8; i++ {
		assert(t,!v.Get(i),"should be 0")
		assert(t,v.GetInt(i)==0,"GetInt should be 0")
	}

    // set all bits in w
    for i := 0; i < 16; i++ {
        w.Set(i,true)
    }
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
}

func TestNot(t *testing.T) {
	w := New(16)
	w.Not()
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
	w.Not()
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,!w.Get(i),"should be 0")
		assert(t,w.GetInt(i)==0,"GetInt should be 0")
    }
	w.Not()
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
}

func TestNotPackage(t *testing.T) {
    v := New(16)
    w := Not(v)
    assert(t,v!=w,"v and w are the same")
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
    z := Not(w)
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,!z.Get(i),"should be 0")
		assert(t,z.GetInt(i)==0,"GetInt should be 0")
    }
}

func TestCopy(t *testing.T) {
	v := New(16)
	w := v.Copy()
	assert(t,v!=w,"same object?")
	assert(t,len(v.bits)==len(w.bits),"different byte allocations!")

}

func TestEqual(t *testing.T) {
	v := New(16)
	w := New(8)
	assert(t,v.Equal(w),"%s should be equal to %s", v, w)
}

func BenchmarkAllocation(b *testing.B) {
    for i := 0; i < b.N; i++ {
		New(VECTOR_LEN)
    }
}

func BenchmarkNot(b *testing.B) {
	v := New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Not()
	}
}

func BenchmarkNotManual(b *testing.B) {
	v := New(VECTOR_LEN)
    for i := 0; i < b.N; i++ {
		for j := 0; j < VECTOR_LEN; j++ {
			v.Set(j,true)
		}
    }
}

func BenchmarkSetTrue(b *testing.B) {
	v := New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Set(0,true)
	}
}

func BenchmarkSetFalse(b *testing.B) {
	v := New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Set(0,false)
	}
}
<commit_msg>Finished unit test for bitvector.<commit_after>package bitvector

import "testing"

// Length of the BitVector
// for the benchmarking portion
const VECTOR_LEN = 1024

func assert( t *testing.T, value bool, format string, args ...interface{} ) {
    if !value {
		t.Errorf(format,args...)
    }
}

func TestAllocationSize(t *testing.T) {
	// test single byte allocation
    for i := 1; i <= 8; i++ {
		v := New(i)
		assert(t, len(v.bits)==1, "wrong allocation size for iteration %d", i)
	}
    // test double byte allocation
    for i := 9; i <= 16; i++ {
		v := New(i)
		assert(t, len(v.bits)==2, "wrong allocation size for iteration %d", i)
	}

    // test array growth
    v := New(1)
    v.Set(1,true)
    assert(t,len(v.bits)==1, "weird allocation after set")
    v.Set(7,true)
    assert(t,len(v.bits)==1, "weird allocation after set")
    v.Set(8,true)
    assert(t,len(v.bits)==2, "weird allocation after set (should have grown to 16)")
    w := New(1)
    w.Set(17,true)
    assert(t,len(w.bits)==3, "didn't grow correctly (should have grown to 3 bytes)")
}

func TestSetGet(t *testing.T) {
	v := New(8)
    w := New(16)
    v.Set(0,true)
    assert(t,v.Get(0),"didn't set correctly")
    assert(t,v.GetInt(0)==1,"didn't set correctly")
    for i := 1; i < 8; i++ {
		assert(t,!v.Get(i),"should be 0")
		assert(t,v.GetInt(i)==0,"GetInt should be 0")
	}

    // set all bits in w
    for i := 0; i < 16; i++ {
        w.Set(i,true)
    }
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
}

func TestNot(t *testing.T) {
	w := New(16)
	w.Not()
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
	w.Not()
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,!w.Get(i),"should be 0")
		assert(t,w.GetInt(i)==0,"GetInt should be 0")
    }
	w.Not()
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
}

func TestNotPackage(t *testing.T) {
    v := New(16)
    w := Not(v)
    assert(t,v!=w,"v and w are the same")
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,w.Get(i),"should be 1")
		assert(t,w.GetInt(i)==1,"GetInt should be 1")
    }
    z := Not(w)
    // and check...
    for i := 0; i < 16; i++ {
        assert(t,!z.Get(i),"should be 0")
		assert(t,z.GetInt(i)==0,"GetInt should be 0")
    }
}

func TestCopy(t *testing.T) {
	v := New(16)
	w := v.Copy()
	assert(t,v!=w,"same object?")
	assert(t,len(v.bits)==len(w.bits),"different byte allocations!")

}

func TestEqual(t *testing.T) {
	v := New(16)
	w := New(8)
	assert(t,v.Equal(w),"%s should be equal to %s", v, w)
	assert(t,w.Equal(v),"%s should be equal to %s", v, w)
    w.Not();
	assert(t,!v.Equal(w),"%s should not be equal to %s", v, w)
	assert(t,!w.Equal(v),"%s should not be equal to %s", v, w)
}

func TestOr(t *testing.T) {
	v, w, z := New(8), New(8), New(8)
	z.Not()
	for i := 0; i < 8; i++ {
		if i % 2 == 0 {
			v.Set(i,true)
		} else {
			w.Set(i,true)
		}
    }
	v.Or(w)
	assert(t,v.Equal(z),"v should all be ones: %s",v)
}

func TestAnd(t *testing.T) {
	v, w, z := New(8), New(8), New(8)
	for i := 0; i < 8; i++ {
		if i % 2 == 0 {
			v.Set(i,true)
		} else {
			w.Set(i,true)
		}
    }
	v.And(w)
	assert(t,v.Equal(z),"v should all be zeros: %s",v)
	z.Not()
	v.And(z)
	assert(t,v.Equal(v),"v should be itself: %s",v)
	v.And(v)
	assert(t,v.Equal(v),"v should be itself: %s",v)
}

func BenchmarkEqual(b *testing.B) {
    v, w := New(VECTOR_LEN), New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Equal(w)
	}
}

func BenchmarkAllocation(b *testing.B) {
    for i := 0; i < b.N; i++ {
		New(VECTOR_LEN)
    }
}

func BenchmarkNot(b *testing.B) {
	v := New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Not()
	}
}

func BenchmarkNotManual(b *testing.B) {
	v := New(VECTOR_LEN)
    for i := 0; i < b.N; i++ {
		for j := 0; j < VECTOR_LEN; j++ {
			v.Set(j,true)
		}
    }
}

func BenchmarkSetTrue(b *testing.B) {
	v := New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Set(0,true)
	}
}

func BenchmarkSetFalse(b *testing.B) {
	v := New(VECTOR_LEN)
	for i := 0; i < b.N; i++ {
		v.Set(0,false)
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package main_test

import (
	"testing"

	"sigs.k8s.io/kustomize/pkg/kusttest"
	"sigs.k8s.io/kustomize/plugin"
)

func TestPrefixSuffixTransformer(t *testing.T) {
	tc := plugin.NewEnvForTest(t).Set()
	defer tc.Reset()

	tc.BuildGoPlugin(
		"builtin", "", "PrefixSuffixTransformer")

	th := kusttest_test.NewKustTestPluginHarness(t, "/app")
	rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
  name: notImportantHere
prefix: baked-
suffix: -pie
fieldSpecs:
  - path: metadata/name
`, `
apiVersion: v1
kind: Service
metadata:
  name: apple
spec:
  ports:
  - port: 7002
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crd
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm
`)

	th.AssertActualEqualsExpected(rm, `
apiVersion: v1
kind: Service
metadata:
  name: baked-apple-pie
spec:
  ports:
  - port: 7002
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crd
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: baked-cm-pie
`)
}
<commit_msg>Add test for regression<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package main_test

import (
	"testing"

	"sigs.k8s.io/kustomize/pkg/kusttest"
	"sigs.k8s.io/kustomize/plugin"
)

func TestPrefixSuffixTransformer(t *testing.T) {
	tc := plugin.NewEnvForTest(t).Set()
	defer tc.Reset()

	tc.BuildGoPlugin(
		"builtin", "", "PrefixSuffixTransformer")

	th := kusttest_test.NewKustTestPluginHarness(t, "/app")
	rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
  name: notImportantHere
prefix: baked-
suffix: -pie
fieldSpecs:
  - path: metadata/name
`, `
apiVersion: v1
kind: Service
metadata:
  name: apple
spec:
  ports:
  - port: 7002
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crd
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm
`)

	th.AssertActualEqualsExpected(rm, `
apiVersion: v1
kind: Service
metadata:
  name: baked-apple-pie
spec:
  ports:
  - port: 7002
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crd
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: baked-cm-pie
`)

  rm = th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
  name: notImportantHere
prefix: test-
fieldSpecs:
  - kind: Deployment
    path: metadata/name
  - kind: Deployment
    path: spec/template/spec/containers/name
`, `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment
spec:
  template:
    spec:
      containers:
      - image: myapp
        name: main
        ---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crd
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm
`)

	th.AssertActualEqualsExpected(rm, `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
spec:
  template:
    spec:
      containers:
      - image: myapp
        name: test-main
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crd
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-cm
`)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path"
	"strconv"
	"text/template"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/sessions"
	"github.com/jmoiron/sqlx"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

var (
	db    *sqlx.DB
	store *sessions.CookieStore
)

type user struct {
	ID          int       `db:"id"`
	AccountName string    `db:"account_name"`
	Passhash    string    `db:"passhash"`
	Authority   int       `db:"authority"`
	DelFlg      int       `db:"del_flg"`
	CreatedAt   time.Time `db:"created_at"`
}

type post struct {
	ID        int       `db:"id"`
	UserID    int       `db:"user_id"`
	Imgdata   []byte    `db:"imagdata"`
	Body      string    `db:"body"`
	Mime      string    `db:"mime"`
	CreatedAt time.Time `db:"created_at"`
}

type comment struct {
	ID        int       `db:"id"`
	PostID    int       `db:"post_id"`
	UserID    int       `db:"user_id"`
	Comment   string    `db:"comment"`
	CreatedAt time.Time `db:"created_at"`
}

func getSessionUser() user {
	return user{}
}

func getTemplPath(filename string) string {
	return path.Join("templates", filename)
}

func getIndex(c web.C, w http.ResponseWriter, r *http.Request) {
	// fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
	_ = getSessionUser()

	posts := []post{}

	err := db.Select(&posts, "SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC")
	if err != nil {
		fmt.Println(err)
		return
	}

	template.Must(template.ParseFiles(
		getTemplPath("layout.html"),
		getTemplPath("index.html"),
		getTemplPath("posts.html"),
		getTemplPath("post.html")),
	).Execute(w, struct{ Posts []post }{posts})
}

func main() {
	host := os.Getenv("ISUCONP_DB_HOST")
	if host == "" {
		host = "localhost"
	}
	port := os.Getenv("ISUCONP_DB_PORT")
	if port == "" {
		port = "3306"
	}
	_, err := strconv.Atoi(port)
	if err != nil {
		log.Fatalf("Failed to read DB port number from an environment variable ISUCONP_DB_PORT.\nError: %s", err.Error())
	}
	user := os.Getenv("ISUCONP_DB_USER")
	if user == "" {
		user = "root"
	}
	password := os.Getenv("ISUCONP_DB_PASSWORD")
	dbname := os.Getenv("ISUCONP_DB_NAME")
	if dbname == "" {
		dbname = "isucon5q"
	}

	dsn := fmt.Sprintf(
		"%s:%s@tcp(%s:%s)/%s?parseTime=true&loc=Local",
		user,
		password,
		host,
		port,
		dbname,
	)

	db, err = sqlx.Open("mysql", dsn)
	if err != nil {
		log.Fatalf("Failed to connect to DB: %s.", err.Error())
	}
	defer db.Close()

	goji.Get("/", getIndex)
	goji.Serve()
}
<commit_msg>ログイン成功した<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"text/template"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/sessions"
	"github.com/jmoiron/sqlx"
	"github.com/zenazn/goji"
)

var (
	db    *sqlx.DB
	store *sessions.CookieStore
)

type user struct {
	ID          int       `db:"id"`
	AccountName string    `db:"account_name"`
	Passhash    string    `db:"passhash"`
	Authority   int       `db:"authority"`
	DelFlg      int       `db:"del_flg"`
	CreatedAt   time.Time `db:"created_at"`
}

type post struct {
	ID        int       `db:"id"`
	UserID    int       `db:"user_id"`
	Imgdata   []byte    `db:"imagdata"`
	Body      string    `db:"body"`
	Mime      string    `db:"mime"`
	CreatedAt time.Time `db:"created_at"`
}

type comment struct {
	ID        int       `db:"id"`
	PostID    int       `db:"post_id"`
	UserID    int       `db:"user_id"`
	Comment   string    `db:"comment"`
	CreatedAt time.Time `db:"created_at"`
}

func init() {
	store = sessions.NewCookieStore([]byte("Iscogram"))
}

func getSession(r *http.Request) *sessions.Session {
	session, err := store.Get(r, "isuconp-go.session")
	if err != nil {
		fmt.Println(err)
		return nil
	}
	return session
}

func getSessionUser(r *http.Request) *user {
	session := getSession(r)
	uid, ok := session.Values["user_id"]
	if !ok || uid == nil {
		return nil
	}

	u := &user{}

	err := db.Get(&u, "SELECT * FROM `users` WHERE `id` = ?", uid)
	if err != nil {
		fmt.Println(err)
		return nil
	}

	return u
}

func tryLogin(accountName, password string) *user {
	u := user{}
	err := db.Get(&u, "SELECT * FROM users WHERE account_name = ? AND del_flg = 0", accountName)
	if err != nil {
		fmt.Println(err)
		return nil
	}

	if &u != nil && calculatePasshash(u.AccountName, password) == u.Passhash {
		return &u
	} else if &u == nil {
		return nil
	} else {
		return nil
	}

	return &u
}

func digest(src string) string {
	fmt.Println(src)
	// TODO: escape
	out, err := exec.Command("/bin/bash", "-c", `printf "%s" "`+src+`" | openssl dgst -sha512 | sed 's/^.*= //'`).Output()
	if err != nil {
		fmt.Println(err)
		return ""
	}

	fmt.Println(strings.TrimSuffix(string(out), "\n"))
	return strings.TrimSuffix(string(out), "\n")
}

func calculateSalt(accountName string) string {
	return digest(accountName)
}

func calculatePasshash(accountName, password string) string {
	return digest(password + ":" + calculateSalt(accountName))
}

func getTemplPath(filename string) string {
	return path.Join("templates", filename)
}

func getIndex(w http.ResponseWriter, r *http.Request) {
	// fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
	_ = getSessionUser(r)

	posts := []post{}

	err := db.Select(&posts, "SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC")
	if err != nil {
		fmt.Println(err)
		return
	}

	template.Must(template.ParseFiles(
		getTemplPath("layout.html"),
		getTemplPath("index.html"),
		getTemplPath("posts.html"),
		getTemplPath("post.html")),
	).Execute(w, struct{ Posts []post }{posts})
}

func postLogin(w http.ResponseWriter, r *http.Request) {
	if getSessionUser(r) != nil {
		w.Header().Set("Location", "/")
		w.WriteHeader(http.StatusFound)
		return
	}

	u := tryLogin(r.FormValue("account_name"), r.FormValue("password"))

	if u != nil {
		session := getSession(r)
		session.Values["user_id"] = u.ID
		session.Save(r, w)

		w.Header().Set("Location", "/")
		w.WriteHeader(http.StatusFound)
	} else {
		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusFound)
	}
}

func main() {
	host := os.Getenv("ISUCONP_DB_HOST")
	if host == "" {
		host = "localhost"
	}
	port := os.Getenv("ISUCONP_DB_PORT")
	if port == "" {
		port = "3306"
	}
	_, err := strconv.Atoi(port)
	if err != nil {
		log.Fatalf("Failed to read DB port number from an environment variable ISUCONP_DB_PORT.\nError: %s", err.Error())
	}
	user := os.Getenv("ISUCONP_DB_USER")
	if user == "" {
		user = "root"
	}
	password := os.Getenv("ISUCONP_DB_PASSWORD")
	dbname := os.Getenv("ISUCONP_DB_NAME")
	if dbname == "" {
		dbname = "isucon5q"
	}

	dsn := fmt.Sprintf(
		"%s:%s@tcp(%s:%s)/%s?parseTime=true&loc=Local",
		user,
		password,
		host,
		port,
		dbname,
	)

	db, err = sqlx.Open("mysql", dsn)
	if err != nil {
		log.Fatalf("Failed to connect to DB: %s.", err.Error())
	}
	defer db.Close()

	goji.Get("/", getIndex)
	goji.Post("/login", postLogin)
	goji.Serve()
}
<|endoftext|>


<commit_before>// 在这里写你的事件

package main

import (
	"fmt"
	"math"
	"strings"

	"github.com/ying32/govcl/vcl/types/colors"

	"github.com/ying32/govcl/vcl"
	"github.com/ying32/govcl/vcl/types"
)

//::private::
type TForm1Fields struct {
}

// 这个例了是改的原来网上一个Delphi的TListBox自绘的，
// 原地址： https://blog.csdn.net/nhconch/article/details/205127

func (f *TForm1) OnFormCreate(sender vcl.IObject) {
	f.ScreenCenter()

	// 这里为显示，手动设置，一般可以设计器时设置
	f.LstLeft.SetStyle(types.LbOwnerDrawFixed)
	f.LstLeft.SetCtl3D(false)
	f.LstLeft.SetItemHeight(90)
	f.LstLeft.Items().Add("第一项")
	f.LstLeft.Items().Add("第二项")
	f.LstLeft.Items().Add("第三项")
	f.LstLeft.Items().Add("第四项")

	f.LstRight.SetStyle(types.LbOwnerDrawFixed)
	f.LstRight.SetCtl3D(false)
	f.LstRight.SetItemHeight(53)
	for i := int32(0); i < 20; i++ {
		f.LstRight.Items().Add(fmt.Sprintf("ListBox Item of %d\nSecond of %d\nThird of %d", i, i, i))
	}

}

func (f *TForm1) OnFormShow(object vcl.IObject) {
	f.LstLeft.SetItemIndex(0)
	f.LstLeft.Repaint()

	f.LstRight.SetItemIndex(0)
	f.LstRight.Repaint()
}

func (f *TForm1) OnFormDestroy(sender vcl.IObject) {

}

func (f *TForm1) OnLstLeftDrawItem(control vcl.IWinControl, index int32, aRect types.TRect, state types.TOwnerDrawState) {
	r := types.TRect{}
	canvas := f.LstLeft.Canvas()
	brush := canvas.Brush()
	pen := canvas.Pen()
	font := canvas.Font()

	brush.SetColor(colors.ClWhite)
	canvas.FillRect(aRect)
	if state.In(types.OdSelected) {
		pen.SetColor(0xFFB2B5)
	} else {
		pen.SetColor(colors.ClSilver)
	}
	brush.SetStyle(types.BsClear)

	r = types.TRect{Left: aRect.Left + 3, Top: aRect.Top + 3, Right: aRect.Right - 3, Bottom: aRect.Bottom - 3}
	canvas.RoundRect(r.Left, r.Top, r.Right, r.Bottom, 10, 10)

	if state.In(types.OdSelected) {
		pic := f.Image1.Picture()
		canvas.Draw(r.Left+(r.Right-r.Left-pic.Width())/2, r.Top+2, pic.Graphic())
	} else {
		pic := f.Image2.Picture()
		canvas.Draw(r.Left+(r.Right-r.Left-pic.Width())/2, r.Top+2, pic.Graphic())
	}
	r.Top = r.Bottom - int32(math.Abs(float64(font.Height()))) - 4
	brush.SetStyle(types.BsSolid)
	if state.In(types.OdSelected) {
		brush.SetColor(0xFFB2B5)
	} else {
		brush.SetColor(colors.ClSilver)
	}
	canvas.FillRect(r)
	font.SetColor(colors.ClBlack)
	r.Top += 2
	canvas.TextRect3(&r, f.LstLeft.Items().S(index), types.NewSet(types.TfVerticalCenter, types.TfCenter, types.TfWordEllipsis))
	if state.In(types.OdFocused) {
		canvas.DrawFocusRect(aRect)
	}

}

func (f *TForm1) OnLstRightDrawItem(control vcl.IWinControl, index int32, aRect types.TRect, state types.TOwnerDrawState) {
	canvas := f.LstRight.Canvas()
	brush := canvas.Brush()
	pen := canvas.Pen()
	font := canvas.Font()

	font.SetColor(colors.ClBlack)
	brush.SetColor(colors.ClWhite)
	canvas.FillRect(aRect)

	brush.SetColor(types.TColor(0x00FFF7F7))
	pen.SetColor(types.TColor(0x00131315))
	canvas.RoundRect(aRect.Left+3, aRect.Top+3, aRect.Right-2, aRect.Bottom-2, 8, 8)
	canvas.RoundRect(aRect.Left+3, aRect.Top+3, aRect.Right-3, aRect.Bottom-3, 5, 5)
	if state.In(types.OdSelected) {
		brush.SetColor(types.TColor(0x00FFB2B5))
		canvas.RoundRect(aRect.Left+3, aRect.Top+3, aRect.Right-3, aRect.Bottom-3, 5, 5)
		font.SetColor(colors.ClBlue)
		if state.In(types.OdFocused) {
			canvas.DrawFocusRect(aRect)
		}
	}

	idx := 0
	if index%2 != 0 {
		idx = 1
	}
	f.ImageList1.Draw(canvas, aRect.Left+7, aRect.Top+(f.LstRight.ItemHeight()-f.ImageList1.Height())/2, int32(idx), true)

	sArr := strings.Split(f.LstRight.Items().S(index), "\n")
	if len(sArr) == 3 {
		canvas.TextOut(aRect.Left+32+10, aRect.Top+4, sArr[0])
		canvas.TextOut(aRect.Left+32+10, aRect.Top+18, sArr[1])
		canvas.TextOut(aRect.Left+32+10, aRect.Top+32, sArr[2])
	}

	/*
		var
		    strTemp: String;
		begin

		    //画出图标
		    ImageList1.Draw(lsbRight.Canvas, Rect.Left + 7,
		            Rect.top + (lsbRight.ItemHeight - ImageList1.Height) div 2, Index, true);
		    //分别绘出三行文字
		    strTemp := lsbRight.Items.Strings[Index];
		    lsbRight.Canvas.TextOut(Rect.Left + 32 + 10, Rect.Top + 4
		                            , Copy(strTemp, 1, Pos(#13, strTemp)-1));
		    strTemp := Copy(strTemp, Pos(#13, strTemp)+1, Length(strTemp));
		    lsbRight.Canvas.TextOut(Rect.Left + 32 + 10, Rect.Top + 18,
		                            Copy(strTemp, 1, Pos(#13, strTemp)-1));
		    lsbRight.Canvas.TextOut(Rect.Left + 32 + 10, Rect.Top + 32,
		                            Copy(strTemp, Pos(#13, strTemp)+1, Length(strTemp)));

	*/
}
<commit_msg>Update listboxcustomdraw2 example.<commit_after>// 在这里写你的事件

package main

import (
	"fmt"
	"math"
	"strings"

	"github.com/ying32/govcl/vcl/types/colors"

	"github.com/ying32/govcl/vcl"
	"github.com/ying32/govcl/vcl/types"
)

//::private::
type TForm1Fields struct {
}

// 这个例了是改的原来网上一个Delphi的TListBox自绘的，
// 原地址： https://blog.csdn.net/nhconch/article/details/205127

func (f *TForm1) OnFormCreate(sender vcl.IObject) {
	f.ScreenCenter()

	// 这里为显示，手动设置，一般可以设计器时设置
	f.LstLeft.SetStyle(types.LbOwnerDrawFixed)
	f.LstLeft.SetCtl3D(false)
	f.LstLeft.SetItemHeight(90)
	f.LstLeft.Items().Add("第一项")
	f.LstLeft.Items().Add("第二项")
	f.LstLeft.Items().Add("第三项")
	f.LstLeft.Items().Add("第四项")

	f.LstRight.SetStyle(types.LbOwnerDrawFixed)
	f.LstRight.SetCtl3D(false)
	f.LstRight.SetItemHeight(53)
	for i := int32(0); i < 20; i++ {
		f.LstRight.Items().Add(fmt.Sprintf("ListBox Item of %d\nSecond of %d\nThird of %d", i, i, i))
	}

}

func (f *TForm1) OnFormShow(object vcl.IObject) {
	f.LstLeft.SetItemIndex(0)
	f.LstLeft.Repaint()

	f.LstRight.SetItemIndex(0)
	f.LstRight.Repaint()
}

func (f *TForm1) OnFormDestroy(sender vcl.IObject) {

}

func (f *TForm1) OnLstLeftDrawItem(control vcl.IWinControl, index int32, aRect types.TRect, state types.TOwnerDrawState) {
	r := types.TRect{}
	canvas := f.LstLeft.Canvas()
	brush := canvas.Brush()
	pen := canvas.Pen()
	font := canvas.Font()

	//设置填充的背景颜色并填充背景
	brush.SetColor(colors.ClWhite)
	canvas.FillRect(aRect)

	//绘制圆角矩形
	if state.In(types.OdSelected) {
		pen.SetColor(0xFFB2B5) //选中项的圆角矩形颜色
	} else {
		pen.SetColor(colors.ClSilver) //未选中项的圆角矩形颜色
	}
	brush.SetStyle(types.BsClear)

	r = types.TRect{Left: aRect.Left + 3, Top: aRect.Top + 3, Right: aRect.Right - 3, Bottom: aRect.Bottom - 3}
	canvas.RoundRect(r.Left, r.Top, r.Right, r.Bottom, 10, 10)

	//画出图标
	if state.In(types.OdSelected) {
		pic := f.Image1.Picture()
		canvas.Draw(r.Left+(r.Right-r.Left-pic.Width())/2, r.Top+2, pic.Graphic()) //选中项的图像
	} else {
		pic := f.Image2.Picture()
		canvas.Draw(r.Left+(r.Right-r.Left-pic.Width())/2, r.Top+2, pic.Graphic()) //未选中项的图像
	}

	//填充文字区背景
	r.Top = r.Bottom - int32(math.Abs(float64(font.Height()))) - 4
	brush.SetStyle(types.BsSolid)
	if state.In(types.OdSelected) {
		brush.SetColor(0xFFB2B5) //选中项的背景颜色
	} else {
		brush.SetColor(colors.ClSilver) //未选中项的背景颜色
	}
	canvas.FillRect(r)

	//输出文字，仅支持单行
	font.SetColor(colors.ClBlack)

	//计算文字顶点位置， 水平，垂直居中，文字超出绘制圆点
	r.Top += 2
	canvas.TextRect3(&r, f.LstLeft.Items().S(index), types.NewSet(types.TfVerticalCenter, types.TfCenter, types.TfWordEllipsis))

	//画焦点虚框，当系统再绘制时，变成XOR运算，从而达到擦除焦点虚框的目的
	if state.In(types.OdFocused) {
		canvas.DrawFocusRect(aRect)
	}

}

func (f *TForm1) OnLstRightDrawItem(control vcl.IWinControl, index int32, aRect types.TRect, state types.TOwnerDrawState) {
	canvas := f.LstRight.Canvas()
	brush := canvas.Brush()
	pen := canvas.Pen()
	font := canvas.Font()

	//文字颜色
	font.SetColor(colors.ClBlack)

	//设置背景颜色并填充背景
	brush.SetColor(colors.ClWhite)
	canvas.FillRect(aRect)

	//设置圆角矩形颜色并画出圆角矩形
	brush.SetColor(types.TColor(0x00FFF7F7))
	pen.SetColor(types.TColor(0x00131315))
	canvas.RoundRect(aRect.Left+3, aRect.Top+3, aRect.Right-2, aRect.Bottom-2, 8, 8)

	//以不同的宽度和高度再画一次，实现立体效果
	canvas.RoundRect(aRect.Left+3, aRect.Top+3, aRect.Right-3, aRect.Bottom-3, 5, 5)

	//如果是当前选中项
	if state.In(types.OdSelected) {
		//以不同的背景色画出选中项的圆角矩形
		brush.SetColor(types.TColor(0x00FFB2B5))
		canvas.RoundRect(aRect.Left+3, aRect.Top+3, aRect.Right-3, aRect.Bottom-3, 5, 5)

		//选中项的文字颜色
		font.SetColor(colors.ClBlue)

		//如果当前项拥有焦点，画焦点虚框，当系统再绘制时变成XOR运算从而达到擦除焦点虚框的目的
		if state.In(types.OdFocused) {
			canvas.DrawFocusRect(aRect)
		}
	}

	idx := 0
	if index%2 != 0 {
		idx = 1
	}
	//画出图标
	f.ImageList1.Draw(canvas, aRect.Left+7, aRect.Top+(f.LstRight.ItemHeight()-f.ImageList1.Height())/2, int32(idx), true)

	//分别绘出三行文字
	sArr := strings.Split(f.LstRight.Items().S(index), "\n")
	if len(sArr) == 3 {
		canvas.TextOut(aRect.Left+32+10, aRect.Top+4, sArr[0])
		canvas.TextOut(aRect.Left+32+10, aRect.Top+18, sArr[1])
		canvas.TextOut(aRect.Left+32+10, aRect.Top+32, sArr[2])
	}
}
<|endoftext|>