<commit_before>package commands

import (
	"bytes"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"testing"
)

func TestCleanSmallFile(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = bytes.NewBufferString("whatever\n")
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
		"size 9"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")
	prePushHookFile := filepath.Join(repo.Path, ".git", "hooks", "pre-push")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "cd", "29", "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411")
	cmd.After(func() {
		by, err := ioutil.ReadFile(file)
		if err != nil {
			t.Fatal(err)
		}

		contents := string(by)
		if contents != "whatever\n" {
			t.Fatalf("wrong contents: '%v'", contents)
		}

		by, err = ioutil.ReadFile(prePushHookFile)
		if err != nil {
			t.Fatal(err)
		}

		pattern := "git lfs push"
		if !bytes.Contains(by, []byte(pattern)) {
			t.Errorf("hook does not contain %s:\n%s", pattern, string(by))
		}
	})
}

func TestCleanBigFile(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = randomReader(1024)
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5\n" +
		"size 1024"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "7c", "d8", "7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5")
	cmd.After(func() {
		stat, err := os.Stat(file)
		if err != nil {
			t.Fatal(err)
		}

		if fileSize := stat.Size(); fileSize != 1024 {
			t.Fatalf("bad size: %d", fileSize)
		}
	})
}

func TestCleanPointerWithExtra(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = bytes.NewBufferString("version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5\n" +
		"size 1024\n\n" +
		"This is my test pointer.  There are many like it, but this one is mine.")
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:f39333aa7ce293ce27742843a1a1cd6e958eaf6b44cfca9039e6b461088df5ba\n" +
		"size 201"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "f3", "93", "f39333aa7ce293ce27742843a1a1cd6e958eaf6b44cfca9039e6b461088df5ba")
	cmd.After(func() {
		stat, err := os.Stat(file)
		if err != nil {
			t.Fatal(err)
		}

		if fileSize := stat.Size(); fileSize != 201 {
			t.Fatalf("bad size: %d", fileSize)
		}
	})
}

func TestCleanPointerWithWhitespaceAndExtra(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	head := bytes.NewBufferString("version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5\n" +
		"size 1024\n" +
		// extra white space to fill the initial buffer in DecodeFrom()
		"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")

	cmd := repo.Command("clean")
	cmd.Input = io.MultiReader(head, randomReader(1024))
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:494f6e07ed15b2e31ca60b31ed8c503bd7553dfd4a76ec73692f766bc67f0bec\n" +
		"size 1537"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "49", "4f", "494f6e07ed15b2e31ca60b31ed8c503bd7553dfd4a76ec73692f766bc67f0bec")
	cmd.After(func() {
		stat, err := os.Stat(file)
		if err != nil {
			t.Fatal(err)
		}

		if fileSize := stat.Size(); fileSize != 1537 {
			t.Fatalf("bad size: %d", fileSize)
		}
	})
}

func TestCleanPointer(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	versions := []string{
		"http://git-media.io/v/2",
		"https://hawser.github.com/spec/v1",
		"https://git-lfs.github.com/spec/v1",
	}

	for _, v := range versions {
		cmd := repo.Command("clean")
		cmd.Input = bytes.NewBufferString("version " + v + "\n" +
			"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
			"size 9\n")
		cmd.Output = "version " + v + "\n" +
			"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
			"size 9"

		path := filepath.Join(repo.Path, ".git", "lfs", "objects")

		cmd.Before(func() {
			_, err := os.Open(path)
			if _, ok := err.(*os.PathError); !ok {
				t.Errorf("'%s' should not exist before version %s", path, v)
			}
		})

		cmd.After(func() {
			dirs, err := ioutil.ReadDir(path)
			if _, ok := err.(*os.PathError); ok {
				return // it's ok if this dir does not exist
			}

			if err != nil {
				t.Errorf("Error for version %s: %s", v, err)
				return
			}

			if dirs == nil || len(dirs) == 0 {
				return
			}

			if len(dirs) == 1 && dirs[0].Name() == "logs" {
				return
			}

			for _, dir := range dirs {
				t.Logf("DIR: %v", dir.Name())
			}

			t.Errorf("objects were written to .git/lfs/objects")
		})
	}
}

func TestCleanWithCustomHook(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = bytes.NewBufferString("whatever\n")
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
		"size 9"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")
	prePushHookFile := filepath.Join(repo.Path, ".git", "hooks", "pre-push")
	customHook := []byte("test")

	cmd.Before(func() {
		err := ioutil.WriteFile(prePushHookFile, customHook, 0755)
		if err != nil {
			t.Fatal(err)
		}

		_, err = os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "cd", "29", "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411")
	cmd.After(func() {
		by, err := ioutil.ReadFile(file)
		if err != nil {
			t.Fatal(err)
		}

		contents := string(by)
		if contents != "whatever\n" {
			t.Fatalf("wrong contents: '%v'", contents)
		}

		by, err = ioutil.ReadFile(prePushHookFile)
		if err != nil {
			t.Fatal(err)
		}

		if string(by) != string(customHook) {
			t.Logf(string(by))
			t.Errorf("Hook does not contain custom hook")
		}
	})
}

func randomReader(n int64) io.Reader {
	return io.LimitReader(&randomDataMaker{rand.NewSource(42)}, n)
}

type randomDataMaker struct {
	src rand.Source
}

func (r *randomDataMaker) Read(p []byte) (n int, err error) {
	for i := range p {
		p[i] = byte(r.src.Int63() & 0xff)
	}
	return len(p), nil
}
<commit_msg>fix test<commit_after>package commands

import (
	"bytes"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"testing"
)

func TestCleanSmallFile(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = bytes.NewBufferString("whatever\n")
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
		"size 9"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")
	prePushHookFile := filepath.Join(repo.Path, ".git", "hooks", "pre-push")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "cd", "29", "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411")
	cmd.After(func() {
		by, err := ioutil.ReadFile(file)
		if err != nil {
			t.Fatal(err)
		}

		contents := string(by)
		if contents != "whatever\n" {
			t.Fatalf("wrong contents: '%v'", contents)
		}

		by, err = ioutil.ReadFile(prePushHookFile)
		if err != nil {
			t.Fatal(err)
		}

		pattern := "git lfs pre-push"
		if !bytes.Contains(by, []byte(pattern)) {
			t.Errorf("hook does not contain %s:\n%s", pattern, string(by))
		}
	})
}

func TestCleanBigFile(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = randomReader(1024)
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5\n" +
		"size 1024"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "7c", "d8", "7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5")
	cmd.After(func() {
		stat, err := os.Stat(file)
		if err != nil {
			t.Fatal(err)
		}

		if fileSize := stat.Size(); fileSize != 1024 {
			t.Fatalf("bad size: %d", fileSize)
		}
	})
}

func TestCleanPointerWithExtra(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = bytes.NewBufferString("version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5\n" +
		"size 1024\n\n" +
		"This is my test pointer.  There are many like it, but this one is mine.")
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:f39333aa7ce293ce27742843a1a1cd6e958eaf6b44cfca9039e6b461088df5ba\n" +
		"size 201"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "f3", "93", "f39333aa7ce293ce27742843a1a1cd6e958eaf6b44cfca9039e6b461088df5ba")
	cmd.After(func() {
		stat, err := os.Stat(file)
		if err != nil {
			t.Fatal(err)
		}

		if fileSize := stat.Size(); fileSize != 201 {
			t.Fatalf("bad size: %d", fileSize)
		}
	})
}

func TestCleanPointerWithWhitespaceAndExtra(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	head := bytes.NewBufferString("version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:7cd8be1d2cd0dd22cd9d229bb6b5785009a05e8b39d405615d882caac56562b5\n" +
		"size 1024\n" +
		// extra white space to fill the initial buffer in DecodeFrom()
		"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")

	cmd := repo.Command("clean")
	cmd.Input = io.MultiReader(head, randomReader(1024))
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:494f6e07ed15b2e31ca60b31ed8c503bd7553dfd4a76ec73692f766bc67f0bec\n" +
		"size 1537"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")

	cmd.Before(func() {
		_, err := os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "49", "4f", "494f6e07ed15b2e31ca60b31ed8c503bd7553dfd4a76ec73692f766bc67f0bec")
	cmd.After(func() {
		stat, err := os.Stat(file)
		if err != nil {
			t.Fatal(err)
		}

		if fileSize := stat.Size(); fileSize != 1537 {
			t.Fatalf("bad size: %d", fileSize)
		}
	})
}

func TestCleanPointer(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	versions := []string{
		"http://git-media.io/v/2",
		"https://hawser.github.com/spec/v1",
		"https://git-lfs.github.com/spec/v1",
	}

	for _, v := range versions {
		cmd := repo.Command("clean")
		cmd.Input = bytes.NewBufferString("version " + v + "\n" +
			"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
			"size 9\n")
		cmd.Output = "version " + v + "\n" +
			"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
			"size 9"

		path := filepath.Join(repo.Path, ".git", "lfs", "objects")

		cmd.Before(func() {
			_, err := os.Open(path)
			if _, ok := err.(*os.PathError); !ok {
				t.Errorf("'%s' should not exist before version %s", path, v)
			}
		})

		cmd.After(func() {
			dirs, err := ioutil.ReadDir(path)
			if _, ok := err.(*os.PathError); ok {
				return // it's ok if this dir does not exist
			}

			if err != nil {
				t.Errorf("Error for version %s: %s", v, err)
				return
			}

			if dirs == nil || len(dirs) == 0 {
				return
			}

			if len(dirs) == 1 && dirs[0].Name() == "logs" {
				return
			}

			for _, dir := range dirs {
				t.Logf("DIR: %v", dir.Name())
			}

			t.Errorf("objects were written to .git/lfs/objects")
		})
	}
}

func TestCleanWithCustomHook(t *testing.T) {
	repo := NewRepository(t, "empty")
	defer repo.Test()

	cmd := repo.Command("clean")
	cmd.Input = bytes.NewBufferString("whatever\n")
	cmd.Output = "version https://git-lfs.github.com/spec/v1\n" +
		"oid sha256:cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411\n" +
		"size 9"

	path := filepath.Join(repo.Path, ".git", "lfs", "objects")
	prePushHookFile := filepath.Join(repo.Path, ".git", "hooks", "pre-push")
	customHook := []byte("test")

	cmd.Before(func() {
		err := ioutil.WriteFile(prePushHookFile, customHook, 0755)
		if err != nil {
			t.Fatal(err)
		}

		_, err = os.Open(path)
		if _, ok := err.(*os.PathError); !ok {
			t.Fatalf("'%s' should not exist", path)
		}
	})

	file := filepath.Join(path, "cd", "29", "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411")
	cmd.After(func() {
		by, err := ioutil.ReadFile(file)
		if err != nil {
			t.Fatal(err)
		}

		contents := string(by)
		if contents != "whatever\n" {
			t.Fatalf("wrong contents: '%v'", contents)
		}

		by, err = ioutil.ReadFile(prePushHookFile)
		if err != nil {
			t.Fatal(err)
		}

		if string(by) != string(customHook) {
			t.Logf(string(by))
			t.Errorf("Hook does not contain custom hook")
		}
	})
}

func randomReader(n int64) io.Reader {
	return io.LimitReader(&randomDataMaker{rand.NewSource(42)}, n)
}

type randomDataMaker struct {
	src rand.Source
}

func (r *randomDataMaker) Read(p []byte) (n int, err error) {
	for i := range p {
		p[i] = byte(r.src.Int63() & 0xff)
	}
	return len(p), nil
}
<|endoftext|>


<commit_before>/*
Open Source Initiative OSI - The MIT License (MIT):Licensing

The MIT License (MIT)
Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package mapset

import "fmt"
import "strings"

type Set struct {
	set map[interface{}]bool
}

func NewSet() *Set {
	return &Set{make(map[interface{}]bool)}
}

func (set *Set) Add(i interface{}) bool {
	_, found := set.set[i]
	set.set[i] = true
	return !found //False if it existed already
}

func (set *Set) Contains(i interface{}) bool {
	_, found := set.set[i]
	return found //true if it existed already
}

func (set *Set) IsSubset(other *Set) bool {
	counter := 0
	for key, _ := range set.set {
		if other.Contains(key) {
			counter++
		}
	}
	return counter == set.Size()
}

func (set *Set) IsSuperset(other *Set) bool {
	counter := 0
	for key, _ := range other.set {
		if set.Contains(key) {
			counter++
		}
	}
	return counter == other.Size()
}

func (set *Set) Union(other *Set) *Set {
	if set != nil && other != nil {
		unionedSet := NewSet()

		for key, _ := range set.set {
			unionedSet.Add(key)
		}
		for key, _ := range other.set {
			unionedSet.Add(key)
		}
		return unionedSet
	}
	return nil
}

func (set *Set) Intersect(other *Set) *Set {
	if set != nil && other != nil {
		intersectedSet := NewSet()
		for key, _ := range set.set {
			if other.Contains(key) {
				intersectedSet.Add(key)
			}
		}
		for key, _ := range other.set {
			if set.Contains(key) {
				intersectedSet.Add(key)
			}
		}
		return intersectedSet
	}
	return nil
}

func (set *Set) Difference(other *Set) *Set {
	if set != nil && other != nil {
		differencedSet := NewSet()

		for key, _ := range set.set {
			differencedSet.Add(key)
		}

		for key, _ := range other.set {
			differencedSet.Add(key)
		}

		for key, _ := range other.set {
			differencedSet.Remove(key)
		}

		return differencedSet
	}
	return nil
}

func (set *Set) SymmetricDifference(other *Set) *Set {
	if set != nil && other != nil {
		aDiff := set.Difference(other)
		bDiff := other.Difference(set)

		symDifferencedSet := aDiff.Union(bDiff)

		return symDifferencedSet
	}
	return nil
}

func (set *Set) Clear() {
	set.set = make(map[interface{}]bool)
}

func (set *Set) Remove(i interface{}) {
	delete(set.set, i)
}

func (set *Set) Size() int {
	return len(set.set)
}

func (set *Set) String() string {
	items := make([]string, 0, len(set.set))

	for key := range set.set {
		items = append(items, fmt.Sprintf("%v", key))
	}
	return fmt.Sprintf("Set{%s}", strings.Join(items, ", "))
}
<commit_msg>Simplified Intersect method, only need to loop over one set to satisfy a proper intersection.  Thanks SaidinWot.  http://www.reddit.com/r/golang/comments/1hlijg/a_simple_set_type_for_the_go_language/<commit_after>/*
Open Source Initiative OSI - The MIT License (MIT):Licensing

The MIT License (MIT)
Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package mapset

import "fmt"
import "strings"

type Set struct {
	set map[interface{}]bool
}

func NewSet() *Set {
	return &Set{make(map[interface{}]bool)}
}

func (set *Set) Add(i interface{}) bool {
	_, found := set.set[i]
	set.set[i] = true
	return !found //False if it existed already
}

func (set *Set) Contains(i interface{}) bool {
	_, found := set.set[i]
	return found //true if it existed already
}

func (set *Set) IsSubset(other *Set) bool {
	counter := 0
	for key, _ := range set.set {
		if other.Contains(key) {
			counter++
		}
	}
	return counter == set.Size()
}

func (set *Set) IsSuperset(other *Set) bool {
	counter := 0
	for key, _ := range other.set {
		if set.Contains(key) {
			counter++
		}
	}
	return counter == other.Size()
}

func (set *Set) Union(other *Set) *Set {
	if set != nil && other != nil {
		unionedSet := NewSet()

		for key, _ := range set.set {
			unionedSet.Add(key)
		}
		for key, _ := range other.set {
			unionedSet.Add(key)
		}
		return unionedSet
	}
	return nil
}

func (set *Set) Intersect(other *Set) *Set {
	if set != nil && other != nil {
		intersectedSet := NewSet()
		for key, _ := range set.set {
			if other.Contains(key) {
				intersectedSet.Add(key)
			}
		}
		return intersectedSet
	}
	return nil
}

func (set *Set) Difference(other *Set) *Set {
	if set != nil && other != nil {
		differencedSet := NewSet()

		for key, _ := range set.set {
			differencedSet.Add(key)
		}

		for key, _ := range other.set {
			differencedSet.Add(key)
		}

		for key, _ := range other.set {
			differencedSet.Remove(key)
		}

		return differencedSet
	}
	return nil
}

func (set *Set) SymmetricDifference(other *Set) *Set {
	if set != nil && other != nil {
		aDiff := set.Difference(other)
		bDiff := other.Difference(set)

		symDifferencedSet := aDiff.Union(bDiff)

		return symDifferencedSet
	}
	return nil
}

func (set *Set) Clear() {
	set.set = make(map[interface{}]bool)
}

func (set *Set) Remove(i interface{}) {
	delete(set.set, i)
}

func (set *Set) Size() int {
	return len(set.set)
}

func (set *Set) String() string {
	items := make([]string, 0, len(set.set))

	for key := range set.set {
		items = append(items, fmt.Sprintf("%v", key))
	}
	return fmt.Sprintf("Set{%s}", strings.Join(items, ", "))
}
<|endoftext|>


<commit_before>package discrete

import (
	"sync"
)

// On one hand, using an interface{} as a key works on some levels.
// On the other hand, from experience, I can say that working with interface{} is a pain
// so I don't like it in an API. An alternate idea is to make Set an interface with a method that allows you to GRAB a map[interface{}]struct{} from
// the implementation, but that adds a lot of calls and needless operations, making the library slower
//
// Another point, using an interface{} may be pointless because a map key MUST have == and != defined, limiting the possible keys anyway (for instance, if you had a set of [3]floats I don't think it will do a deep
// comparison, making it rather pointless). Also, keying with a float will mean it does a strict == with the floats, possibly causing bad behavior. It may be best to just make it a map[int]struct{}. Thoughts?
type Set struct {
	data map[interface{}]struct{}
	id   uint64
}

// I highly doubt we have to worry about running out of IDs, but we could add a little reclaimID function if we're worried
var globalid uint64 = 0
var idMu sync.Mutex = sync.Mutex{}

// For cleanliness
var flag struct{} = struct{}{}

func NewSet() Set {
	idMu.Lock()
	defer idMu.Unlock()
	toReturn := Set{
		data: make(map[interface{}]struct{}, 0),
		id:   globalid,
	}

	globalID++
	return toReturn
}

// Reverts the set to the empty set without reallocating
func (s1 Set) Clear() Set {
	for el, _ := range s1.data {
		delete(s1.data, el)
	}

	return s1
}

// Ensures a perfect copy from s1 to dest (meaning the sets will be equal)
func (s1 Set) CopyTo(dest Set) Set {
	if s1.id == dest.id {
		return dest
	}

	if len(dest.data) > 0 {
		for el := range dest.data {
			delete(dest.data, el)
		}
	}

	for el := range s1.data {
		dest.data[el] = flag
	}

	return dest
}

func (s1 Set) Equal(s2 Set) bool {
	if s1.id == s2.id {
		return true
	} else if len(s1.data) != len(s2.data) {
		return false
	}

	for el := range s1.data {
		if _, ok := s2.data[el]; !ok {
			return false
		}
	}

	return true
}

func (dest Set) Union(s1, s2 Set) Set {
	if s1.id == s2.id {
		return s1.CopyTo(dest)
	}

	if s1.id != dest.id && s2.id != dest.id {
		dest.Clear()
	}

	if dest.id != s1.id {
		for el := range s1.data {
			dest.data[el] = flag
		}
	}

	if dest.id != s2.id {
		for el := range s2.data {
			dest.data[el] = flag
		}
	}

	return dest
}

func (dest Set) Intersection(s1, s2 Set) Set {
	var swap Set

	if s1.id == s2.id {
		return s1.CopyTo(dest)
	} else if s1.id == dest.id {
		swap = s2
	} else if s2.id == dest.id {
		swap = s1
	} else {
		dest.Clear()

		if len(s1.data) > len(s2.data) {
			s1, s2 = s2, s1
		}
		for el := range s1.data {
			if _, ok := s2.data[el]; ok {
				dest.data[el] = flag
			}
		}

		return dest
	}

	for el := range dest.data {
		if _, ok := swap.data[el]; !ok {
			delete(dest.data, el)
		}
	}

	return dest
}

func (dest Set) Diff(s1, s2 Set) Set {
	if s1.id == s2.id {
		return dest.Clear()
	} else if s2.id == dest.id {
		tmp := NewSet()

		return s1.Diff(tmp, s2).CopyTo(dest)
	} else if s1.id == dest.id {
		for el := range dest.data {
			if _, ok := s2.data[el]; ok {
				delete(dest.data, el)
			}
		}

	} else {
		dest.Clear()
		for el := range s1.data {
			if _, ok := s2.data[el]; !ok {
				dest.data[el] = flag
			}
		}
	}

	return dest
}

// Are Add/Remove necessary?
func (s1 Set) Add(element interface{}) {
	s1.data[element] = flag
}

func (s1 Set) Remove(element interface{}) {
	delete(s1.data, element)
}
<commit_msg>Mutex?<commit_after>package discrete

import (
	"sync"
)

// On one hand, using an interface{} as a key works on some levels.
// On the other hand, from experience, I can say that working with interface{} is a pain
// so I don't like it in an API. An alternate idea is to make Set an interface with a method that allows you to GRAB a map[interface{}]struct{} from
// the implementation, but that adds a lot of calls and needless operations, making the library slower
//
// Another point, using an interface{} may be pointless because a map key MUST have == and != defined, limiting the possible keys anyway (for instance, if you had a set of [3]floats I don't think it will do a deep
// comparison, making it rather pointless). Also, keying with a float will mean it does a strict == with the floats, possibly causing bad behavior. It may be best to just make it a map[int]struct{}. Thoughts?
type Set struct {
	data map[interface{}]struct{}
	id   uint64
}

// I highly doubt we have to worry about running out of IDs, but we could add a little reclaimID function if we're worried
var globalid uint64 = 0
var idMu sync.Mutex = sync.Mutex{}

// For cleanliness
var flag struct{} = struct{}{}

func NewSet() Set {
	idMu.Lock()
	defer idMu.Unlock()
	toReturn := Set{
		data: make(map[interface{}]struct{}, 0),
		id:   globalid,
	}

	globalid++
	return toReturn
}

// Reverts the set to the empty set without reallocating
func (s1 Set) Clear() Set {
	for el, _ := range s1.data {
		delete(s1.data, el)
	}

	return s1
}

// Ensures a perfect copy from s1 to dest (meaning the sets will be equal)
func (s1 Set) CopyTo(dest Set) Set {
	if s1.id == dest.id {
		return dest
	}

	if len(dest.data) > 0 {
		for el := range dest.data {
			delete(dest.data, el)
		}
	}

	for el := range s1.data {
		dest.data[el] = flag
	}

	return dest
}

func (s1 Set) Equal(s2 Set) bool {
	if s1.id == s2.id {
		return true
	} else if len(s1.data) != len(s2.data) {
		return false
	}

	for el := range s1.data {
		if _, ok := s2.data[el]; !ok {
			return false
		}
	}

	return true
}

func (dest Set) Union(s1, s2 Set) Set {
	if s1.id == s2.id {
		return s1.CopyTo(dest)
	}

	if s1.id != dest.id && s2.id != dest.id {
		dest.Clear()
	}

	if dest.id != s1.id {
		for el := range s1.data {
			dest.data[el] = flag
		}
	}

	if dest.id != s2.id {
		for el := range s2.data {
			dest.data[el] = flag
		}
	}

	return dest
}

func (dest Set) Intersection(s1, s2 Set) Set {
	var swap Set

	if s1.id == s2.id {
		return s1.CopyTo(dest)
	} else if s1.id == dest.id {
		swap = s2
	} else if s2.id == dest.id {
		swap = s1
	} else {
		dest.Clear()

		if len(s1.data) > len(s2.data) {
			s1, s2 = s2, s1
		}
		for el := range s1.data {
			if _, ok := s2.data[el]; ok {
				dest.data[el] = flag
			}
		}

		return dest
	}

	for el := range dest.data {
		if _, ok := swap.data[el]; !ok {
			delete(dest.data, el)
		}
	}

	return dest
}

func (dest Set) Diff(s1, s2 Set) Set {
	if s1.id == s2.id {
		return dest.Clear()
	} else if s2.id == dest.id {
		tmp := NewSet()

		return s1.Diff(tmp, s2).CopyTo(dest)
	} else if s1.id == dest.id {
		for el := range dest.data {
			if _, ok := s2.data[el]; ok {
				delete(dest.data, el)
			}
		}

	} else {
		dest.Clear()
		for el := range s1.data {
			if _, ok := s2.data[el]; !ok {
				dest.data[el] = flag
			}
		}
	}

	return dest
}

// Are Add/Remove necessary?
func (s1 Set) Add(element interface{}) {
	s1.data[element] = flag
}

func (s1 Set) Remove(element interface{}) {
	delete(s1.data, element)
}
<|endoftext|>


<commit_before>package views

import (
	"fmt"
	"html/template"
	"io"
	"time"
)

func datetime(t int64) string {
	return time.Unix(t, 0).Format(time.RFC3339)
}

func readable(t int64) string {
	n := time.Now()
	u := time.Unix(t, 0)
	d := n.Sub(u)

	if d.Hours() < 24 && n.Weekday() == u.Weekday() {
		if d.Hours() < 1 {
			return fmt.Sprintf("%d mintues ago", int(d.Minutes()))
		}
		return fmt.Sprintf("%d hours ago", int(d.Hours()))
	}

	if d.Hours() < 48 && n.Weekday() == u.Weekday()+1 {
		return u.Format("Yesterday at 15:04pm")
	}

	if n.Year() == u.Year() {
		return u.Format("02 Jan 15:04pm")
	}

	return u.Format("02 Jan 2006")
}

type Pair struct {
	Name string
	Hide bool
	Data interface{}
}

func pair(name string, show bool, data interface{}) *Pair {
	return &Pair{name, !show, data}
}

var Played interface {
	Execute(io.Writer, interface{}) error
}

func init() {
	var tmpl = template.Must(template.New("played").Funcs(template.FuncMap{
		"datetime": datetime,
		"readable": readable,
		"pair":     pair,
	}).Parse(played))
	tmpl = template.Must(tmpl.New("artistTab").Parse(artistTab))
	tmpl = template.Must(tmpl.New("trackTab").Parse(trackTab))

	Played = &wrappedTemplate{tmpl, "played"}
}

type wrappedTemplate struct {
	t *template.Template
	n string
}

func (w *wrappedTemplate) Execute(wr io.Writer, data interface{}) error {
	return w.t.ExecuteTemplate(wr, w.n, data)
}

const artistTab = `

    {{ range .Data }}

      {{.Artist}}
      {{.Count}} plays

    {{ end }}

`

const trackTab = `

    {{ range .Data }}

        {{.Artist}}
        {{.Track}}

      {{.Count}} plays

    {{ end }}

`

const played = `<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>{{.Title}}</title>
    <link rel="alternate" type="application/rss+xml" href="/feed" />

{{.Title}}

{{.TotalPlays}} plays

      {{ if .NowPlaying }}

        ♫
        {{.NowPlaying.Artist}}
        {{.NowPlaying.Track}}

      {{ end }}

Recently played

        {{ range .RecentlyPlayed }}

            {{.Artist}}
            {{.Track}}

          <time datetime="{{.Timestamp | datetime}}">{{.Timestamp | readable}}</time>

        {{ end }}

Top Artists

Overall

Year

Month

Week

        {{ template "artistTab" pair "tab-artists-overall" false .TopArtists.Overall }}
        {{ template "artistTab" pair "tab-artists-year"    false .TopArtists.Year    }}
        {{ template "artistTab" pair "tab-artists-month"   true  .TopArtists.Month   }}
        {{ template "artistTab" pair "tab-artists-week"    false .TopArtists.Week    }}

Top Tracks

Overall

Year

Month

Week

        {{ template "trackTab" pair "tab-tracks-overall" false .TopTracks.Overall }}
        {{ template "trackTab" pair "tab-tracks-year"    false .TopTracks.Year    }}
        {{ template "trackTab" pair "tab-tracks-month"   true  .TopTracks.Month   }}
        {{ template "trackTab" pair "tab-tracks-week"    false .TopTracks.Week    }}

`
<commit_msg>Fix small-width table cut-off problem<commit_after>package views

import (
	"fmt"
	"html/template"
	"io"
	"time"
)

func datetime(t int64) string {
	return time.Unix(t, 0).Format(time.RFC3339)
}

func readable(t int64) string {
	n := time.Now()
	u := time.Unix(t, 0)
	d := n.Sub(u)

	if d.Hours() < 24 && n.Weekday() == u.Weekday() {
		if d.Hours() < 1 {
			return fmt.Sprintf("%d mintues ago", int(d.Minutes()))
		}
		return fmt.Sprintf("%d hours ago", int(d.Hours()))
	}

	if d.Hours() < 48 && n.Weekday() == u.Weekday()+1 {
		return u.Format("Yesterday at 15:04pm")
	}

	if n.Year() == u.Year() {
		return u.Format("02 Jan 15:04pm")
	}

	return u.Format("02 Jan 2006")
}

type Pair struct {
	Name string
	Hide bool
	Data interface{}
}

func pair(name string, show bool, data interface{}) *Pair {
	return &Pair{name, !show, data}
}

var Played interface {
	Execute(io.Writer, interface{}) error
}

func init() {
	var tmpl = template.Must(template.New("played").Funcs(template.FuncMap{
		"datetime": datetime,
		"readable": readable,
		"pair":     pair,
	}).Parse(played))
	tmpl = template.Must(tmpl.New("artistTab").Parse(artistTab))
	tmpl = template.Must(tmpl.New("trackTab").Parse(trackTab))

	Played = &wrappedTemplate{tmpl, "played"}
}

type wrappedTemplate struct {
	t *template.Template
	n string
}

func (w *wrappedTemplate) Execute(wr io.Writer, data interface{}) error {
	return w.t.ExecuteTemplate(wr, w.n, data)
}

const artistTab = `

    {{ range .Data }}

      {{.Artist}}
      {{.Count}} plays

    {{ end }}

`

const trackTab = `

    {{ range .Data }}

        {{.Artist}}
        {{.Track}}

      {{.Count}} plays

    {{ end }}

`

const played = `<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>{{.Title}}</title>
    <link rel="alternate" type="application/rss+xml" href="/feed" />

{{.Title}}

{{.TotalPlays}} plays

      {{ if .NowPlaying }}

        ♫
        {{.NowPlaying.Artist}}
        {{.NowPlaying.Track}}

      {{ end }}

Recently played

        {{ range .RecentlyPlayed }}

            {{.Artist}}
            {{.Track}}

          <time datetime="{{.Timestamp | datetime}}">{{.Timestamp | readable}}</time>

        {{ end }}

Top Artists

Overall

Year

Month

Week

        {{ template "artistTab" pair "tab-artists-overall" false .TopArtists.Overall }}
        {{ template "artistTab" pair "tab-artists-year"    false .TopArtists.Year    }}
        {{ template "artistTab" pair "tab-artists-month"   true  .TopArtists.Month   }}
        {{ template "artistTab" pair "tab-artists-week"    false .TopArtists.Week    }}

Top Tracks

Overall

Year

Month

Week

        {{ template "trackTab" pair "tab-tracks-overall" false .TopTracks.Overall }}
        {{ template "trackTab" pair "tab-tracks-year"    false .TopTracks.Year    }}
        {{ template "trackTab" pair "tab-tracks-month"   true  .TopTracks.Month   }}
        {{ template "trackTab" pair "tab-tracks-week"    false .TopTracks.Week    }}

`
<|endoftext|>


<commit_before>package common_test

import (
	"bytes"
	"reflect"
	"testing"
	"time"

	"github.com/emersion/go-imap/common"
)

func TestParseDate(t *testing.T) {
	tests := []struct{
		dateStr string
		exp     time.Time
	}{
		{
			"21-Nov-1997 09:55:06 -0600",
			time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
		},
	}
	for _, test := range tests {
		date, err := common.ParseDate(test.dateStr)
		if err != nil {
			t.Errorf("Failed parsing %q: %v", test.dateStr, err)
			continue
		}
		if !date.Equal(test.exp) {
			t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
		}
	}
}

var bodySectionNameTests = []struct{
	raw string
	parsed *common.BodySectionName
	formatted string
}{
	{
		raw: "BODY[]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}},
	},
	{
		raw: "RFC822",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}},
		formatted: "BODY[]",
	},
	{
		raw: "BODY[HEADER]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier}},
	},
	{
		raw: "BODY.PEEK[]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}, Peek: true},
	},
	{
		raw: "BODY[TEXT]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.TextSpecifier}},
	},
	{
		raw: "RFC822.TEXT",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.TextSpecifier}},
		formatted: "BODY[TEXT]",
	},
	{
		raw: "RFC822.HEADER",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier}, Peek: true},
		formatted: "BODY.PEEK[HEADER]",
	},
	{
		raw: "BODY[]<0.512>",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}, Partial: []int{0, 512}},
	},
	{
		raw: "BODY[1.2.3]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Path: []int{1, 2, 3}}},
	},
	{
		raw: "BODY[1.2.3.HEADER]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier, Path: []int{1, 2, 3}}},
	},
	{
		raw: "BODY[5.MIME]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.MimeSpecifier, Path: []int{5}}},
	},
	{
		raw: "BODY[HEADER.FIELDS (From To)]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier, Fields: []string{"From", "To"}}},
	},
	{
		raw: "BODY[HEADER.FIELDS.NOT (Content-Id)]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier, Fields: []string{"Content-Id"}, NotFields: true}},
	},
}

func TestNewBodySectionName(t *testing.T) {
	for i, test := range bodySectionNameTests {
		bsn, err := common.NewBodySectionName(test.raw)
		if err != nil {
			t.Errorf("Cannot parse #%v: %v", i, err)
			continue
		}

		if !reflect.DeepEqual(bsn.BodyPartName, test.parsed.BodyPartName) {
			t.Errorf("Invalid body part name for #%v: %#+v", i, bsn.BodyPartName)
		} else if bsn.Peek != test.parsed.Peek {
			t.Errorf("Invalid peek value for #%v: %#+v", i, bsn.Peek)
		} else if !reflect.DeepEqual(bsn.Partial, test.parsed.Partial) {
			t.Errorf("Invalid partial for #%v: %#+v", i, bsn.Partial)
		}
	}
}

func TestBodySectionName_String(t *testing.T) {
	for i, test := range bodySectionNameTests {
		s := test.parsed.String()

		expected := test.formatted
		if expected == "" {
			expected = test.raw
		}

		if expected != s {
			t.Errorf("Invalid body section name for #%v: got %v but expected %v", i, s, expected)
		}
	}
}

var addrTests = []struct{
	fields []interface{}
	addr *common.Address
}{
	{
		fields: []interface{}{"The NSA", nil, "root", "nsa.gov"},
		addr: &common.Address{
			PersonalName: "The NSA",
			MailboxName: "root",
			HostName: "nsa.gov",
		},
	},
}

func TestAddress_Parse(t *testing.T) {
	for i, test := range addrTests {
		addr := &common.Address{}

		if err := addr.Parse(test.fields); err != nil {
			t.Error("Error parsing address:", err)
		} else if !reflect.DeepEqual(addr, test.addr) {
			t.Errorf("Invalid address for #%v: got %v but expected %v", i, addr, test.addr)
		}
	}
}

func TestAddress_Format(t *testing.T) {
	for i, test := range addrTests {
		fields := test.addr.Format()
		if !reflect.DeepEqual(fields, test.fields) {
			t.Errorf("Invalid address fields for #%v: got %v but expected %v", i, fields, test.fields)
		}
	}
}

func TestAddressList(t *testing.T) {
	fields := make([]interface{}, len(addrTests))
	addrs := make([]*common.Address, len(addrTests))
	for i, test := range addrTests {
		fields[i] = test.fields
		addrs[i] = test.addr
	}

	gotAddrs := common.ParseAddressList(fields)
	if !reflect.DeepEqual(gotAddrs, addrs) {
		t.Error("Invalid address list: got", gotAddrs, "but expected", addrs)
	}

	gotFields := common.FormatAddressList(addrs)
	if !reflect.DeepEqual(gotFields, fields) {
		t.Error("Invalid address list fields: got", gotFields, "but expected", fields)
	}
}

var paramsListTest = []struct{
	fields []interface{}
	params map[string]string
}{
	{
		fields: []interface{}{},
		params: map[string]string{},
	},
	{
		fields: []interface{}{"a", "b"},
		params: map[string]string{"a": "b"},
	},
	{
		fields: []interface{}{"cc", "dille", "cc dille", "CC DILLE"},
		params: map[string]string{"cc": "dille", "cc dille": "CC DILLE"},
	},
}

func TestParseParamList(t *testing.T) {
	for i, test := range paramsListTest {
		if params, err := common.ParseParamList(test.fields); err != nil {
			t.Errorf("Cannot parse params fields for #%v: %v", i, err)
		} else if !reflect.DeepEqual(params, test.params) {
			t.Errorf("Invalid params for #%v: got %v but expected %v", i, params, test.params)
		}
	}

	// Malformed params lists

	fields := []interface{}{"cc", []interface{}{"dille"}}
	if params, err := common.ParseParamList(fields); err == nil {
		t.Error("Parsed invalid params list:", params)
	}

	fields = []interface{}{"cc"}
	if params, err := common.ParseParamList(fields); err == nil {
		t.Error("Parsed invalid params list:", params)
	}
}

func TestFormatParamList(t *testing.T) {
	for i, test := range paramsListTest {
		fields := common.FormatParamList(test.params)

		if !reflect.DeepEqual(fields, test.fields) {
			t.Errorf("Invalid params fields for #%v: got %v but expected %v", i, fields, test.fields)
		}
	}
}

var bodyStructureTests = []struct{
	fields []interface{}
	bodyStructure *common.BodyStructure
}{
	{
		fields: []interface{}{"image", "jpeg", []interface{}{}, "<foo4%25foo1@bar.net>", "A picture of cat", "base64", "4242"},
		bodyStructure: &common.BodyStructure{
			MimeType: "image",
			MimeSubType: "jpeg",
			Params: map[string]string{},
			Id: "<foo4%25foo1@bar.net>",
			Description: "A picture of cat",
			Encoding: "base64",
			Size: 4242,
		},
	},
	{
		fields: []interface{}{"text", "plain", []interface{}{"charset", "utf-8"}, nil, nil, "us-ascii", "42", "2"},
		bodyStructure: &common.BodyStructure{
			MimeType: "text",
			MimeSubType: "plain",
			Params: map[string]string{"charset": "utf-8"},
			Encoding: "us-ascii",
			Size: 42,
			Lines: 2,
		},
	},
	{
		fields: []interface{}{
			"message", "rfc822", []interface{}{}, nil, nil, "us-ascii", "42",
			(&common.Envelope{}).Format(),
			(&common.BodyStructure{}).Format(),
			"67",
		},
		bodyStructure: &common.BodyStructure{
			MimeType: "message",
			MimeSubType: "rfc822",
			Params: map[string]string{},
			Encoding: "us-ascii",
			Size: 42,
			Lines: 67,
			Envelope: &common.Envelope{
				From: []*common.Address{},
				Sender: []*common.Address{},
				ReplyTo: []*common.Address{},
				To: []*common.Address{},
				Cc: []*common.Address{},
				Bcc: []*common.Address{},
			},
			BodyStructure: &common.BodyStructure{
				Params: map[string]string{},
			},
		},
	},
	{
		fields: []interface{}{"application", "pdf", []interface{}{}, nil, nil, "base64", "4242",
			"e0323a9039add2978bf5b49550572c7c", "attachment", []interface{}{"en-US"}, []interface{}{}},
		bodyStructure: &common.BodyStructure{
			MimeType: "application",
			MimeSubType: "pdf",
			Params: map[string]string{},
			Encoding: "base64",
			Size: 4242,
			Extended: true,
			Md5: "e0323a9039add2978bf5b49550572c7c",
			Disposition: "attachment",
			Language: []string{"en-US"},
			Location: []string{},
		},
	},
	{
		fields: []interface{}{
			[]interface{}{"text", "plain", []interface{}{}, nil, nil, "us-ascii", "87", "22"},
			[]interface{}{"text", "html", []interface{}{}, nil, nil, "us-ascii", "106", "36"},
			"alternative",
		},
		bodyStructure: &common.BodyStructure{
			MimeType: "multipart",
			MimeSubType: "alternative",
			Params: map[string]string{},
			Parts: []*common.BodyStructure{
				&common.BodyStructure{
					MimeType: "text",
					MimeSubType: "plain",
					Params: map[string]string{},
					Encoding: "us-ascii",
					Size: 87,
					Lines: 22,
				},
				&common.BodyStructure{
					MimeType: "text",
					MimeSubType: "html",
					Params: map[string]string{},
					Encoding: "us-ascii",
					Size: 106,
					Lines: 36,
				},
			},
		},
	},
	{
		fields: []interface{}{
			[]interface{}{"text", "plain", []interface{}{}, nil, nil, "us-ascii", "87", "22"},
			"alternative", []interface{}{"hello", "world"}, "inline", []interface{}{"en-US"}, []interface{}{},
		},
		bodyStructure: &common.BodyStructure{
			MimeType: "multipart",
			MimeSubType: "alternative",
			Params: map[string]string{"hello": "world"},
			Parts: []*common.BodyStructure{
				&common.BodyStructure{
					MimeType: "text",
					MimeSubType: "plain",
					Params: map[string]string{},
					Encoding: "us-ascii",
					Size: 87,
					Lines: 22,
				},
			},
			Extended: true,
			Disposition: "inline",
			Language: []string{"en-US"},
			Location: []string{},
		},
	},
}

func TestBodyStructure_Parse(t *testing.T) {
	for i, test := range bodyStructureTests {
		bs := &common.BodyStructure{}

		if err := bs.Parse(test.fields); err != nil {
			t.Errorf("Cannot parse #%v: %v", i, err)
		} else if !reflect.DeepEqual(bs, test.bodyStructure) {
			t.Errorf("Invalid body structure for #%v: got %v but expected %v", i, bs, test.bodyStructure)
		}
	}
}

func TestBodyStructure_Format(t *testing.T) {
	b := &bytes.Buffer{}
	w := common.NewWriter(b)

	formatFields := func(fields []interface{}) string {
		if _, err := w.WriteList(fields); err != nil {
			t.Fatalf("Cannot format %v: %v", fields, err)
		}

		s := b.String()
		b.Reset()
		return s
	}

	for i, test := range bodyStructureTests {
		fields := test.bodyStructure.Format()
		got := formatFields(fields)

		expected := formatFields(test.fields)

		if got != expected {
			t.Errorf("Invalid body structure fields for #%v: has %v but expected %v", i, got, expected)
		}
	}
}
<commit_msg>common: adds tests for BodySectionName.ExtractPartial()<commit_after>package common_test

import (
	"bytes"
	"reflect"
	"testing"
	"time"

	"github.com/emersion/go-imap/common"
)

func TestParseDate(t *testing.T) {
	tests := []struct{
		dateStr string
		exp     time.Time
	}{
		{
			"21-Nov-1997 09:55:06 -0600",
			time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
		},
	}
	for _, test := range tests {
		date, err := common.ParseDate(test.dateStr)
		if err != nil {
			t.Errorf("Failed parsing %q: %v", test.dateStr, err)
			continue
		}
		if !date.Equal(test.exp) {
			t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
		}
	}
}

var bodySectionNameTests = []struct{
	raw string
	parsed *common.BodySectionName
	formatted string
}{
	{
		raw: "BODY[]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}},
	},
	{
		raw: "RFC822",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}},
		formatted: "BODY[]",
	},
	{
		raw: "BODY[HEADER]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier}},
	},
	{
		raw: "BODY.PEEK[]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}, Peek: true},
	},
	{
		raw: "BODY[TEXT]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.TextSpecifier}},
	},
	{
		raw: "RFC822.TEXT",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.TextSpecifier}},
		formatted: "BODY[TEXT]",
	},
	{
		raw: "RFC822.HEADER",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier}, Peek: true},
		formatted: "BODY.PEEK[HEADER]",
	},
	{
		raw: "BODY[]<0.512>",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{}, Partial: []int{0, 512}},
	},
	{
		raw: "BODY[1.2.3]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Path: []int{1, 2, 3}}},
	},
	{
		raw: "BODY[1.2.3.HEADER]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier, Path: []int{1, 2, 3}}},
	},
	{
		raw: "BODY[5.MIME]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.MimeSpecifier, Path: []int{5}}},
	},
	{
		raw: "BODY[HEADER.FIELDS (From To)]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier, Fields: []string{"From", "To"}}},
	},
	{
		raw: "BODY[HEADER.FIELDS.NOT (Content-Id)]",
		parsed: &common.BodySectionName{BodyPartName: &common.BodyPartName{Specifier: common.HeaderSpecifier, Fields: []string{"Content-Id"}, NotFields: true}},
	},
}

func TestNewBodySectionName(t *testing.T) {
	for i, test := range bodySectionNameTests {
		bsn, err := common.NewBodySectionName(test.raw)
		if err != nil {
			t.Errorf("Cannot parse #%v: %v", i, err)
			continue
		}

		if !reflect.DeepEqual(bsn.BodyPartName, test.parsed.BodyPartName) {
			t.Errorf("Invalid body part name for #%v: %#+v", i, bsn.BodyPartName)
		} else if bsn.Peek != test.parsed.Peek {
			t.Errorf("Invalid peek value for #%v: %#+v", i, bsn.Peek)
		} else if !reflect.DeepEqual(bsn.Partial, test.parsed.Partial) {
			t.Errorf("Invalid partial for #%v: %#+v", i, bsn.Partial)
		}
	}
}

func TestBodySectionName_String(t *testing.T) {
	for i, test := range bodySectionNameTests {
		s := test.parsed.String()

		expected := test.formatted
		if expected == "" {
			expected = test.raw
		}

		if expected != s {
			t.Errorf("Invalid body section name for #%v: got %v but expected %v", i, s, expected)
		}
	}
}

func TestBodySectionName_ExtractPartial(t *testing.T) {
	tests := []struct{
		bsn string
		whole string
		partial string
	}{
		{
			bsn: "BODY[]",
			whole: "Hello World!",
			partial: "Hello World!",
		},
		{
			bsn: "BODY[]<6.5>",
			whole: "Hello World!",
			partial: "World",
		},
		{
			bsn: "BODY[]<6.1000>",
			whole: "Hello World!",
			partial: "World!",
		},
		{
			bsn: "BODY[]<0.1>",
			whole: "Hello World!",
			partial: "H",
		},
		{
			bsn: "BODY[]<1000.2000>",
			whole: "Hello World!",
			partial: "",
		},
	}

	for i, test := range tests {
		bsn, err := common.NewBodySectionName(test.bsn)
		if err != nil {
			t.Errorf("Cannot parse body section name #%v: %v", i, err)
			continue
		}

		partial := string(bsn.ExtractPartial([]byte(test.whole)))
		if partial != test.partial {
			t.Errorf("Invalid partial for #%v: got %v but expected %v", i, partial, test.partial)
		}
	}
}

var addrTests = []struct{
	fields []interface{}
	addr *common.Address
}{
	{
		fields: []interface{}{"The NSA", nil, "root", "nsa.gov"},
		addr: &common.Address{
			PersonalName: "The NSA",
			MailboxName: "root",
			HostName: "nsa.gov",
		},
	},
}

func TestAddress_Parse(t *testing.T) {
	for i, test := range addrTests {
		addr := &common.Address{}

		if err := addr.Parse(test.fields); err != nil {
			t.Error("Error parsing address:", err)
		} else if !reflect.DeepEqual(addr, test.addr) {
			t.Errorf("Invalid address for #%v: got %v but expected %v", i, addr, test.addr)
		}
	}
}

func TestAddress_Format(t *testing.T) {
	for i, test := range addrTests {
		fields := test.addr.Format()
		if !reflect.DeepEqual(fields, test.fields) {
			t.Errorf("Invalid address fields for #%v: got %v but expected %v", i, fields, test.fields)
		}
	}
}

func TestAddressList(t *testing.T) {
	fields := make([]interface{}, len(addrTests))
	addrs := make([]*common.Address, len(addrTests))
	for i, test := range addrTests {
		fields[i] = test.fields
		addrs[i] = test.addr
	}

	gotAddrs := common.ParseAddressList(fields)
	if !reflect.DeepEqual(gotAddrs, addrs) {
		t.Error("Invalid address list: got", gotAddrs, "but expected", addrs)
	}

	gotFields := common.FormatAddressList(addrs)
	if !reflect.DeepEqual(gotFields, fields) {
		t.Error("Invalid address list fields: got", gotFields, "but expected", fields)
	}
}

var paramsListTest = []struct{
	fields []interface{}
	params map[string]string
}{
	{
		fields: []interface{}{},
		params: map[string]string{},
	},
	{
		fields: []interface{}{"a", "b"},
		params: map[string]string{"a": "b"},
	},
	{
		fields: []interface{}{"cc", "dille", "cc dille", "CC DILLE"},
		params: map[string]string{"cc": "dille", "cc dille": "CC DILLE"},
	},
}

func TestParseParamList(t *testing.T) {
	for i, test := range paramsListTest {
		if params, err := common.ParseParamList(test.fields); err != nil {
			t.Errorf("Cannot parse params fields for #%v: %v", i, err)
		} else if !reflect.DeepEqual(params, test.params) {
			t.Errorf("Invalid params for #%v: got %v but expected %v", i, params, test.params)
		}
	}

	// Malformed params lists

	fields := []interface{}{"cc", []interface{}{"dille"}}
	if params, err := common.ParseParamList(fields); err == nil {
		t.Error("Parsed invalid params list:", params)
	}

	fields = []interface{}{"cc"}
	if params, err := common.ParseParamList(fields); err == nil {
		t.Error("Parsed invalid params list:", params)
	}
}

func TestFormatParamList(t *testing.T) {
	for i, test := range paramsListTest {
		fields := common.FormatParamList(test.params)

		if !reflect.DeepEqual(fields, test.fields) {
			t.Errorf("Invalid params fields for #%v: got %v but expected %v", i, fields, test.fields)
		}
	}
}

var bodyStructureTests = []struct{
	fields []interface{}
	bodyStructure *common.BodyStructure
}{
	{
		fields: []interface{}{"image", "jpeg", []interface{}{}, "<foo4%25foo1@bar.net>", "A picture of cat", "base64", "4242"},
		bodyStructure: &common.BodyStructure{
			MimeType: "image",
			MimeSubType: "jpeg",
			Params: map[string]string{},
			Id: "<foo4%25foo1@bar.net>",
			Description: "A picture of cat",
			Encoding: "base64",
			Size: 4242,
		},
	},
	{
		fields: []interface{}{"text", "plain", []interface{}{"charset", "utf-8"}, nil, nil, "us-ascii", "42", "2"},
		bodyStructure: &common.BodyStructure{
			MimeType: "text",
			MimeSubType: "plain",
			Params: map[string]string{"charset": "utf-8"},
			Encoding: "us-ascii",
			Size: 42,
			Lines: 2,
		},
	},
	{
		fields: []interface{}{
			"message", "rfc822", []interface{}{}, nil, nil, "us-ascii", "42",
			(&common.Envelope{}).Format(),
			(&common.BodyStructure{}).Format(),
			"67",
		},
		bodyStructure: &common.BodyStructure{
			MimeType: "message",
			MimeSubType: "rfc822",
			Params: map[string]string{},
			Encoding: "us-ascii",
			Size: 42,
			Lines: 67,
			Envelope: &common.Envelope{
				From: []*common.Address{},
				Sender: []*common.Address{},
				ReplyTo: []*common.Address{},
				To: []*common.Address{},
				Cc: []*common.Address{},
				Bcc: []*common.Address{},
			},
			BodyStructure: &common.BodyStructure{
				Params: map[string]string{},
			},
		},
	},
	{
		fields: []interface{}{"application", "pdf", []interface{}{}, nil, nil, "base64", "4242",
			"e0323a9039add2978bf5b49550572c7c", "attachment", []interface{}{"en-US"}, []interface{}{}},
		bodyStructure: &common.BodyStructure{
			MimeType: "application",
			MimeSubType: "pdf",
			Params: map[string]string{},
			Encoding: "base64",
			Size: 4242,
			Extended: true,
			Md5: "e0323a9039add2978bf5b49550572c7c",
			Disposition: "attachment",
			Language: []string{"en-US"},
			Location: []string{},
		},
	},
	{
		fields: []interface{}{
			[]interface{}{"text", "plain", []interface{}{}, nil, nil, "us-ascii", "87", "22"},
			[]interface{}{"text", "html", []interface{}{}, nil, nil, "us-ascii", "106", "36"},
			"alternative",
		},
		bodyStructure: &common.BodyStructure{
			MimeType: "multipart",
			MimeSubType: "alternative",
			Params: map[string]string{},
			Parts: []*common.BodyStructure{
				&common.BodyStructure{
					MimeType: "text",
					MimeSubType: "plain",
					Params: map[string]string{},
					Encoding: "us-ascii",
					Size: 87,
					Lines: 22,
				},
				&common.BodyStructure{
					MimeType: "text",
					MimeSubType: "html",
					Params: map[string]string{},
					Encoding: "us-ascii",
					Size: 106,
					Lines: 36,
				},
			},
		},
	},
	{
		fields: []interface{}{
			[]interface{}{"text", "plain", []interface{}{}, nil, nil, "us-ascii", "87", "22"},
			"alternative", []interface{}{"hello", "world"}, "inline", []interface{}{"en-US"}, []interface{}{},
		},
		bodyStructure: &common.BodyStructure{
			MimeType: "multipart",
			MimeSubType: "alternative",
			Params: map[string]string{"hello": "world"},
			Parts: []*common.BodyStructure{
				&common.BodyStructure{
					MimeType: "text",
					MimeSubType: "plain",
					Params: map[string]string{},
					Encoding: "us-ascii",
					Size: 87,
					Lines: 22,
				},
			},
			Extended: true,
			Disposition: "inline",
			Language: []string{"en-US"},
			Location: []string{},
		},
	},
}

func TestBodyStructure_Parse(t *testing.T) {
	for i, test := range bodyStructureTests {
		bs := &common.BodyStructure{}

		if err := bs.Parse(test.fields); err != nil {
			t.Errorf("Cannot parse #%v: %v", i, err)
		} else if !reflect.DeepEqual(bs, test.bodyStructure) {
			t.Errorf("Invalid body structure for #%v: got %v but expected %v", i, bs, test.bodyStructure)
		}
	}
}

func TestBodyStructure_Format(t *testing.T) {
	b := &bytes.Buffer{}
	w := common.NewWriter(b)

	formatFields := func(fields []interface{}) string {
		if _, err := w.WriteList(fields); err != nil {
			t.Fatalf("Cannot format %v: %v", fields, err)
		}

		s := b.String()
		b.Reset()
		return s
	}

	for i, test := range bodyStructureTests {
		fields := test.bodyStructure.Format()
		got := formatFields(fields)

		expected := formatFields(test.fields)

		if got != expected {
			t.Errorf("Invalid body structure fields for #%v: has %v but expected %v", i, got, expected)
		}
	}
}
<|endoftext|>


<commit_before>package torrent

import (
	"context"
	"errors"
	"fmt"
	"sync"

	"github.com/RoaringBitmap/roaring"
	"github.com/anacrolix/log"
	"github.com/anacrolix/torrent/metainfo"
	pp "github.com/anacrolix/torrent/peer_protocol"
	"github.com/anacrolix/torrent/webseed"
)

type webseedPeer struct {
	client         webseed.Client
	activeRequests map[Request]webseed.Request
	requesterCond  sync.Cond
	peer           Peer
	// Number of requester routines.
	maxRequests int
}

var _ peerImpl = (*webseedPeer)(nil)

func (me *webseedPeer) connStatusString() string {
	return me.client.Url
}

func (ws *webseedPeer) String() string {
	return fmt.Sprintf("webseed peer for %q", ws.client.Url)
}

func (ws *webseedPeer) onGotInfo(info *metainfo.Info) {
	ws.client.SetInfo(info)
	// There should be probably be a callback in Client instead, so it can remove pieces at its whim
	// too.
	ws.client.Pieces.Iterate(func(x uint32) bool {
		ws.peer.t.incPieceAvailability(pieceIndex(x))
		return true
	})
}

func (ws *webseedPeer) writeInterested(interested bool) bool {
	return true
}

func (ws *webseedPeer) _cancel(r RequestIndex) bool {
	active, ok := ws.activeRequests[ws.peer.t.requestIndexToRequest(r)]
	if ok {
		active.Cancel()
	}
	if !ws.peer.deleteRequest(r) {
		panic("cancelled webseed request should exist")
	}
	if ws.peer.isLowOnRequests() {
		ws.peer.updateRequests("webseedPeer._cancel")
	}
	return true
}

func (ws *webseedPeer) intoSpec(r Request) webseed.RequestSpec {
	return webseed.RequestSpec{ws.peer.t.requestOffset(r), int64(r.Length)}
}

func (ws *webseedPeer) _request(r Request) bool {
	ws.requesterCond.Signal()
	return true
}

func (ws *webseedPeer) doRequest(r Request) {
	webseedRequest := ws.client.NewRequest(ws.intoSpec(r))
	ws.activeRequests[r] = webseedRequest
	func() {
		ws.requesterCond.L.Unlock()
		defer ws.requesterCond.L.Lock()
		ws.requestResultHandler(r, webseedRequest)
	}()
	delete(ws.activeRequests, r)
}

func (ws *webseedPeer) requester() {
	ws.requesterCond.L.Lock()
	defer ws.requesterCond.L.Unlock()
start:
	for !ws.peer.closed.IsSet() {
		restart := false
		ws.peer.actualRequestState.Requests.Iterate(func(x uint32) bool {
			r := ws.peer.t.requestIndexToRequest(x)
			if _, ok := ws.activeRequests[r]; ok {
				return true
			}
			ws.doRequest(r)
			restart = true
			return false
		})
		if restart {
			goto start
		}
		ws.requesterCond.Wait()
	}
}

func (ws *webseedPeer) connectionFlags() string {
	return "WS"
}

// TODO: This is called when banning peers. Perhaps we want to be able to ban webseeds too. We could
// return bool if this is even possible, and if it isn't, skip to the next drop candidate.
func (ws *webseedPeer) drop() {}

func (ws *webseedPeer) handleUpdateRequests() {
	ws.peer.maybeUpdateActualRequestState()
}

func (ws *webseedPeer) onClose() {
	ws.peer.logger.WithLevel(log.Debug).Print("closing")
	ws.peer.deleteAllRequests()
	for _, r := range ws.activeRequests {
		r.Cancel()
	}
	ws.requesterCond.Broadcast()
}

func (ws *webseedPeer) requestResultHandler(r Request, webseedRequest webseed.Request) {
	result := <-webseedRequest.Result
	close(webseedRequest.Result) // one-shot
	// We do this here rather than inside receiveChunk, since we want to count errors too. I'm not
	// sure if we can divine which errors indicate cancellation on our end without hitting the
	// network though.
	if len(result.Bytes) != 0 || result.Err == nil {
		// Increment ChunksRead and friends
		ws.peer.doChunkReadStats(int64(len(result.Bytes)))
	}
	ws.peer.readBytes(int64(len(result.Bytes)))
	ws.peer.t.cl.lock()
	defer ws.peer.t.cl.unlock()
	if ws.peer.t.closed.IsSet() {
		return
	}
	if result.Err != nil {
		if !errors.Is(result.Err, context.Canceled) && !ws.peer.closed.IsSet() {
			ws.peer.logger.Printf("Request %v rejected: %v", r, result.Err)
			// // Here lies my attempt to extract something concrete from Go's error system. RIP.
			// cfg := spew.NewDefaultConfig()
			// cfg.DisableMethods = true
			// cfg.Dump(result.Err)
			log.Printf("closing %v", ws)
			ws.peer.close()
		}
		ws.peer.remoteRejectedRequest(ws.peer.t.requestIndexFromRequest(r))
	} else {
		err := ws.peer.receiveChunk(&pp.Message{
			Type:  pp.Piece,
			Index: r.Index,
			Begin: r.Begin,
			Piece: result.Bytes,
		})
		if err != nil {
			panic(err)
		}
	}
}

func (me *webseedPeer) isLowOnRequests() bool {
	return me.peer.actualRequestState.Requests.GetCardinality() < uint64(me.maxRequests)
}

func (me *webseedPeer) peerPieces() *roaring.Bitmap {
	return &me.client.Pieces
}

func (cn *webseedPeer) peerHasAllPieces() (all, known bool) {
	if !cn.peer.t.haveInfo() {
		return true, false
	}
	return cn.client.Pieces.GetCardinality() == uint64(cn.peer.t.numPieces()), true
}
<commit_msg>Record an observation about why webseed peers are doing most of the work in recent testing<commit_after>package torrent

import (
	"context"
	"errors"
	"fmt"
	"sync"

	"github.com/RoaringBitmap/roaring"
	"github.com/anacrolix/log"
	"github.com/anacrolix/torrent/metainfo"
	pp "github.com/anacrolix/torrent/peer_protocol"
	"github.com/anacrolix/torrent/webseed"
)

type webseedPeer struct {
	client         webseed.Client
	activeRequests map[Request]webseed.Request
	requesterCond  sync.Cond
	peer           Peer
	// Number of requester routines.
	maxRequests int
}

var _ peerImpl = (*webseedPeer)(nil)

func (me *webseedPeer) connStatusString() string {
	return me.client.Url
}

func (ws *webseedPeer) String() string {
	return fmt.Sprintf("webseed peer for %q", ws.client.Url)
}

func (ws *webseedPeer) onGotInfo(info *metainfo.Info) {
	ws.client.SetInfo(info)
	// There should be probably be a callback in Client instead, so it can remove pieces at its whim
	// too.
	ws.client.Pieces.Iterate(func(x uint32) bool {
		ws.peer.t.incPieceAvailability(pieceIndex(x))
		return true
	})
}

func (ws *webseedPeer) writeInterested(interested bool) bool {
	return true
}

func (ws *webseedPeer) _cancel(r RequestIndex) bool {
	active, ok := ws.activeRequests[ws.peer.t.requestIndexToRequest(r)]
	if ok {
		active.Cancel()
	}
	if !ws.peer.deleteRequest(r) {
		panic("cancelled webseed request should exist")
	}
	if ws.peer.isLowOnRequests() {
		ws.peer.updateRequests("webseedPeer._cancel")
	}
	return true
}

func (ws *webseedPeer) intoSpec(r Request) webseed.RequestSpec {
	return webseed.RequestSpec{ws.peer.t.requestOffset(r), int64(r.Length)}
}

func (ws *webseedPeer) _request(r Request) bool {
	ws.requesterCond.Signal()
	return true
}

func (ws *webseedPeer) doRequest(r Request) {
	webseedRequest := ws.client.NewRequest(ws.intoSpec(r))
	ws.activeRequests[r] = webseedRequest
	func() {
		ws.requesterCond.L.Unlock()
		defer ws.requesterCond.L.Lock()
		ws.requestResultHandler(r, webseedRequest)
	}()
	delete(ws.activeRequests, r)
}

func (ws *webseedPeer) requester() {
	ws.requesterCond.L.Lock()
	defer ws.requesterCond.L.Unlock()
start:
	for !ws.peer.closed.IsSet() {
		restart := false
		ws.peer.actualRequestState.Requests.Iterate(func(x uint32) bool {
			r := ws.peer.t.requestIndexToRequest(x)
			if _, ok := ws.activeRequests[r]; ok {
				return true
			}
			ws.doRequest(r)
			restart = true
			return false
		})
		if restart {
			goto start
		}
		ws.requesterCond.Wait()
	}
}

func (ws *webseedPeer) connectionFlags() string {
	return "WS"
}

// TODO: This is called when banning peers. Perhaps we want to be able to ban webseeds too. We could
// return bool if this is even possible, and if it isn't, skip to the next drop candidate.
func (ws *webseedPeer) drop() {}

func (ws *webseedPeer) handleUpdateRequests() {
	// Because this is synchronous, webseed peers seem to get first dibs on newly prioritized
	// pieces.
	ws.peer.maybeUpdateActualRequestState()
}

func (ws *webseedPeer) onClose() {
	ws.peer.logger.WithLevel(log.Debug).Print("closing")
	ws.peer.deleteAllRequests()
	for _, r := range ws.activeRequests {
		r.Cancel()
	}
	ws.requesterCond.Broadcast()
}

func (ws *webseedPeer) requestResultHandler(r Request, webseedRequest webseed.Request) {
	result := <-webseedRequest.Result
	close(webseedRequest.Result) // one-shot
	// We do this here rather than inside receiveChunk, since we want to count errors too. I'm not
	// sure if we can divine which errors indicate cancellation on our end without hitting the
	// network though.
	if len(result.Bytes) != 0 || result.Err == nil {
		// Increment ChunksRead and friends
		ws.peer.doChunkReadStats(int64(len(result.Bytes)))
	}
	ws.peer.readBytes(int64(len(result.Bytes)))
	ws.peer.t.cl.lock()
	defer ws.peer.t.cl.unlock()
	if ws.peer.t.closed.IsSet() {
		return
	}
	if result.Err != nil {
		if !errors.Is(result.Err, context.Canceled) && !ws.peer.closed.IsSet() {
			ws.peer.logger.Printf("Request %v rejected: %v", r, result.Err)
			// // Here lies my attempt to extract something concrete from Go's error system. RIP.
			// cfg := spew.NewDefaultConfig()
			// cfg.DisableMethods = true
			// cfg.Dump(result.Err)
			log.Printf("closing %v", ws)
			ws.peer.close()
		}
		ws.peer.remoteRejectedRequest(ws.peer.t.requestIndexFromRequest(r))
	} else {
		err := ws.peer.receiveChunk(&pp.Message{
			Type:  pp.Piece,
			Index: r.Index,
			Begin: r.Begin,
			Piece: result.Bytes,
		})
		if err != nil {
			panic(err)
		}
	}
}

func (me *webseedPeer) isLowOnRequests() bool {
	return me.peer.actualRequestState.Requests.GetCardinality() < uint64(me.maxRequests)
}

func (me *webseedPeer) peerPieces() *roaring.Bitmap {
	return &me.client.Pieces
}

func (cn *webseedPeer) peerHasAllPieces() (all, known bool) {
	if !cn.peer.t.haveInfo() {
		return true, false
	}
	return cn.client.Pieces.GetCardinality() == uint64(cn.peer.t.numPieces()), true
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"
)

var (
	helpflag         = flag.Bool("help", false, "Prints this help message")
	subcommands_path = flag.String("subcommands_path", "./config/subcommands.json", "Specifies the path to the subcommands json config file.")
	subcommandlist   SubcommandList
	running_forever  bool

	running = true  // is the process running?
	pids    []int // pids of all running processes
	LOGDIR  = "logs"
)

type Subcommand struct {
	Name        string
	Command     []string
	Envflags    map[string]string
	Depends     []string
	Run_forever bool
}

type SubcommandList struct {
	Env         map[string]string // the default environment params
	Subcommands []Subcommand
}

func (sl SubcommandList) ParseEnv(env string) {
	strs := strings.Split(env, "=")

	if len(strs) != 2 {
		fmt.Printf("Cannot parse: '%v' as subcommand environment var\n")
	}

	sl.Env[strs[0]] = strs[1]
}

// Augment the environment vars with those from a command line
func (sl SubcommandList) Augment(params []string) {
	for _, arg := range params {
		if strings.Contains(arg, "|") {
			sl.ParseEnv(arg)
		}
	}
}

func (sl SubcommandList) HasAllKeys(s Subcommand) bool {

	for k, _ := range s.Envflags {
		_, ok := sl.Env[k]
		if !ok {
			return false
		}
	}

	return true
}

func (sl SubcommandList) RunCommand(cmd string) {

	log.Printf("RunCommand %v", cmd)
	var sc Subcommand

	found := false
	for _, s := range sl.Subcommands {
		if s.Name == cmd {
			sc = s
			found = true
			break
		}
	}

	if !found {
		log.Printf("Cannot find subcommand: '%v'\n", cmd)
		os.Exit(1)
	}

	log.Printf("Command Found: %v", sc)

	/**
	  if sl.HasAllKeys(sc) {
	      fmt.Printf("Already have all env vars for: %v, not running.\n", cmd)
	      return
	  }
	  **/

	// add all of our commands to the envflags, ignore those that already exist
	for k, v := range sc.Envflags {
		_, ok := sl.Env[k]
		if !ok {
			sl.Env[k] = v
		}
	}

	for _, cmd := range sc.Depends {
		sl.RunCommand(cmd)
	}

	// Replace all replacable arguments in the command.
	for pos, arg := range sc.Command {
		rep, ok := sl.Env[arg]

		if ok {
			sc.Command[pos] = rep
		}
	}

	log.Printf("Running: %v", sc)

	if len(sc.Command) == 0 {
		log.Printf("No command found.")
		return
	}

	if sc.Run_forever {
		running_forever = true
		go sc.RunForever()
		return
	} else {
		sc.RunOnce()
	}
}

// Runs the subcommand, returns the exit status of the process
func (s Subcommand) RunOnce() bool {
	cmd := exec.Command(s.Command[0], s.Command[1:]...)

	// this will overwrite whenever needed
	outfile, err := os.Create(LOGDIR + "/" + s.Name + ".log")
	if err != nil {
		panic(err)
	}
	defer outfile.Close()
	cmd.Stdout = outfile
	cmd.Stderr = outfile

    cmd.Start()
    time.Sleep(time.Duration(5) * time.Second)

	for {
		switch {
		//case running == false:
		//	cmd.Process.Kill()
		//	return false // not success
		case cmd.ProcessState.Exited():
			success := cmd.ProcessState.Success()
			log.Printf("Process %v exited, success? %v", cmd.ProcessState.Pid(), success)
			return success
		default:
			// arbitrary sleep so we don't hog the CPU
			time.Sleep(time.Duration(1) * time.Second)
		}
	}
}

func (s Subcommand) RunForever() {
	log.Printf("Running %s Forever", s.Name)
	for {
		if !running {
			return
		}

		s.RunOnce()
		log.Printf("%v crashed!", s.Name)
	}
}

func main() {
    running = true

	flag.Parse()

	if *helpflag {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
		return
	}

	os.Mkdir(LOGDIR, 0777)

	content, err := ioutil.ReadFile(*subcommands_path)
	if err != nil {

		fmt.Printf("Cannot continue without the subcommands json file.\n")
		os.Exit(2)
	}

	err = json.Unmarshal(content, &subcommandlist)
	if err != nil {
		fmt.Printf("Cannot parse the json file. %v\n", err)
		os.Exit(3)
	}

	subcommandlist.Augment(flag.Args())

	for _, param := range flag.Args() {
		if !strings.Contains(param, "|") {
			subcommandlist.RunCommand(param)
		}
	}

	if running_forever {
		select {} // sleep forever.
	} else {
		fmt.Printf("Finished Executing")
	}
}
<commit_msg>Removed unneeded connectordb.go file that is being replaced with v2<commit_after><|endoftext|>


<commit_before>package ws

import (
	"github.com/Vivena/babelweb2/parser"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"sync"
)

type node struct {
	m    *sync.Mutex
	desc *parser.BabelDesc
}

var nodes map[parser.Id]*node
var nodesMutex sync.Mutex

func Init() {
	nodes = make(map[parser.Id]*node)
}

func AddDesc(d *parser.BabelDesc) {
	nodesMutex.Lock()
	nodes[d.Id()] = &node{desc: d, m: new(sync.Mutex)}
	nodesMutex.Unlock()
}

func RemoveDesc(id parser.Id) {
	nodesMutex.Lock()
	delete(nodes, id)
	nodesMutex.Unlock()
}

func GetDesc(id parser.Id) *parser.BabelDesc {
	return nodes[id].desc
}

func LockDesc(id parser.Id) {
	nodes[id].m.Lock()
}

func UnlockDesc(id parser.Id) {
	nodes[id].m.Unlock()
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

//Handler manage the websockets
func Handler(l *Listenergroup) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		log.Println("New connection to a websocket")
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			log.Println("Could not create the socket.", err)
			return
		}

		for router := range nodes {
			nodes[router].m.Lock()
			nodes[router].desc.Iter(
				func(bu parser.BabelUpdate) error {
					sbu := bu.ToSUpdate()
					err := conn.WriteJSON(sbu)
					if err != nil {
						log.Println(err)
					}
					return err
				})
			nodes[router].m.Unlock()
		}
		updates := NewListener()
		l.Push(updates)

		// Ignore any data received on the websocket and detect
		// any errors.
		go func() {
			for {
				_, _, err := conn.NextReader()
				if err != nil {
					l.Flush(updates)
					conn.Close()
					break
				}
			}
		}()

		for {
			err := conn.WriteJSON(<-updates.Channel)
			if err != nil {
				log.Println(err)
			}
		}
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Use embedded anonymous mutexes in websocket.<commit_after>package ws

import (
	"github.com/Vivena/babelweb2/parser"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"sync"
)

type node struct {
	sync.Mutex
	desc *parser.BabelDesc
}

type nodelist struct {
	sync.Mutex
	nodes map[parser.Id]*node
}

var nodes nodelist

func Init() {
	nodes.nodes = make(map[parser.Id]*node)
}

func AddDesc(d *parser.BabelDesc) {
	nodes.Lock()
	nodes.nodes[d.Id()] = &node{desc: d}
	nodes.Unlock()
}

func RemoveDesc(id parser.Id) {
	nodes.Lock()
	delete(nodes.nodes, id)
	nodes.Unlock()
}

func GetDesc(id parser.Id) *parser.BabelDesc {
	return nodes.nodes[id].desc
}

func LockDesc(id parser.Id) {
	nodes.nodes[id].Lock()
}

func UnlockDesc(id parser.Id) {
	nodes.nodes[id].Unlock()
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

//Handler manage the websockets
func Handler(l *Listenergroup) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		log.Println("New connection to a websocket")
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			log.Println("Could not create the socket.", err)
			return
		}

		for _, node := range nodes.nodes {
			node.Lock()
			node.desc.Iter(
				func(bu parser.BabelUpdate) error {
					sbu := bu.ToSUpdate()
					err := conn.WriteJSON(sbu)
					if err != nil {
						log.Println(err)
					}
					return err
				})
			node.Unlock()
		}
		updates := NewListener()
		l.Push(updates)

		// Ignore any data received on the websocket and detect
		// any errors.
		go func() {
			for {
				_, _, err := conn.NextReader()
				if err != nil {
					l.Flush(updates)
					conn.Close()
					break
				}
			}
		}()

		for {
			err := conn.WriteJSON(<-updates.Channel)
			if err != nil {
				log.Println(err)
			}
		}
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


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

package bytes

// Simple byte buffer for marshaling data.

import (
	"io"
	"os"
	"utf8"
)

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
	buf       []byte            // contents are the bytes buf[off : len(buf)]
	off       int               // read at &buf[off], write at &buf[len(buf)]
	runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
	bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
	lastRead  readOp            // last read operation, so that Unread* can work correctly.
}

// The readOp constants describe the last action performed on
// the buffer, so that UnreadRune and UnreadByte can
// check for invalid usage.
type readOp int

const (
	opInvalid  readOp = iota // Non-read operation.
	opReadRune               // Read rune.
	opRead                   // Any other read operation.
)

// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len().  If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
// are no intervening method calls on the Buffer.
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

// String returns the contents of the unread portion of the buffer
// as a string.  If the Buffer is a nil pointer, it returns "<nil>".
func (b *Buffer) String() string {
	if b == nil {
		// Special case, useful in debugging.
		return "<nil>"
	}
	return string(b.buf[b.off:])
}

// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func (b *Buffer) Len() int { return len(b.buf) - b.off }

// Truncate discards all but the first n unread bytes from the buffer.
// It is an error to call b.Truncate(n) with n > b.Len().
func (b *Buffer) Truncate(n int) {
	b.lastRead = opInvalid
	if n == 0 {
		// Reuse buffer space.
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+n]
}

// Reset resets the buffer so it has no content.
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }

// Grow buffer to guarantee space for n more bytes.
// Return index where bytes should be written.
func (b *Buffer) grow(n int) int {
	m := b.Len()
	// If buffer is empty, reset to recover space.
	if m == 0 && b.off != 0 {
		b.Truncate(0)
	}
	if len(b.buf)+n > cap(b.buf) {
		var buf []byte
		if b.buf == nil && n <= len(b.bootstrap) {
			buf = b.bootstrap[0:]
		} else {
			// not enough space anywhere
			buf = make([]byte, 2*cap(b.buf)+n)
			copy(buf, b.buf[b.off:])
		}
		b.buf = buf
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+m+n]
	return b.off + m
}

// Write appends the contents of p to the buffer.  The return
// value n is the length of p; err is always nil.
func (b *Buffer) Write(p []byte) (n int, err os.Error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	copy(b.buf[m:], p)
	return len(p), nil
}

// WriteString appends the contents of s to the buffer.  The return
// value n is the length of s; err is always nil.
func (b *Buffer) WriteString(s string) (n int, err os.Error) {
	b.lastRead = opInvalid
	m := b.grow(len(s))
	return copy(b.buf[m:], s), nil
}

// MinRead is the minimum slice size passed to a Read call by
// Buffer.ReadFrom.  As long as the Buffer has at least MinRead bytes beyond
// what is required to hold the contents of r, ReadFrom will not grow the
// underlying buffer.
const MinRead = 512

// ReadFrom reads data from r until EOF and appends it to the buffer.
// The return value n is the number of bytes read.
// Any error except os.EOF encountered during the read
// is also returned.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
	b.lastRead = opInvalid
	// If buffer is empty, reset to recover space.
	if b.off >= len(b.buf) {
		b.Truncate(0)
	}
	for {
		if cap(b.buf)-len(b.buf) < MinRead {
			var newBuf []byte
			// can we get space without allocation?
			if b.off+cap(b.buf)-len(b.buf) >= MinRead {
				// reuse beginning of buffer
				newBuf = b.buf[0 : len(b.buf)-b.off]
			} else {
				// not enough space at end; put space on end
				newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
			}
			copy(newBuf, b.buf[b.off:])
			b.buf = newBuf
			b.off = 0
		}
		m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
		b.buf = b.buf[0 : len(b.buf)+m]
		n += int64(m)
		if e == os.EOF {
			break
		}
		if e != nil {
			return n, e
		}
	}
	return n, nil // err is EOF, so return nil explicitly
}

// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written.
// Any error encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
	b.lastRead = opInvalid
	for b.off < len(b.buf) {
		m, e := w.Write(b.buf[b.off:])
		n += int64(m)
		b.off += m
		if e != nil {
			return n, e
		}
	}
	// Buffer is now empty; reset.
	b.Truncate(0)
	return
}

// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
func (b *Buffer) WriteByte(c byte) os.Error {
	b.lastRead = opInvalid
	m := b.grow(1)
	b.buf[m] = c
	return nil
}

// WriteRune appends the UTF-8 encoding of Unicode
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
	if r < utf8.RuneSelf {
		b.WriteByte(byte(r))
		return 1, nil
	}
	n = utf8.EncodeRune(b.runeBytes[0:], r)
	b.Write(b.runeBytes[0:n])
	return n, nil
}

// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained.  The return value n is the number of bytes read.  If the
// buffer has no data to return, err is os.EOF even if len(p) is zero;
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err os.Error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, os.EOF
	}
	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return
}

// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (b *Buffer) Next(n int) []byte {
	b.lastRead = opInvalid
	m := b.Len()
	if n > m {
		n = m
	}
	data := b.buf[b.off : b.off+n]
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return data
}

// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error os.EOF.
func (b *Buffer) ReadByte() (c byte, err os.Error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, os.EOF
	}
	c = b.buf[b.off]
	b.off++
	b.lastRead = opRead
	return c, nil
}

// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is os.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, 0, os.EOF
	}
	b.lastRead = opReadRune
	c := b.buf[b.off]
	if c < utf8.RuneSelf {
		b.off++
		return int(c), 1, nil
	}
	r, n := utf8.DecodeRune(b.buf[b.off:])
	b.off += n
	return r, n, nil
}

// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a ReadRune, UnreadRune returns an error.  (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() os.Error {
	if b.lastRead != opReadRune {
		return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		_, n := utf8.DecodeLastRune(b.buf[0:b.off])
		b.off -= n
	}
	return nil
}

// UnreadByte unreads the last byte returned by the most recent
// read operation.  If write has happened since the last read, UnreadByte
// returns an error.
func (b *Buffer) UnreadByte() os.Error {
	if b.lastRead == opReadRune || b.lastRead == opRead {
		return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		b.off--
	}
	return nil
}

// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents.  It is intended to prepare a Buffer to read existing data.  It
// can also be used to to size the internal buffer for writing.  To do that,
// buf should have the desired capacity but a length of zero.
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

// NewBufferString creates and initializes a new Buffer using string s as its
// initial contents.  It is intended to prepare a buffer to read an existing
// string.
func NewBufferString(s string) *Buffer {
	return &Buffer{buf: []byte(s)}
}
<commit_msg>bytes.Buffer: Fix bug in UnreadByte. Error check was inverted.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bytes

// Simple byte buffer for marshaling data.

import (
	"io"
	"os"
	"utf8"
)

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
	buf       []byte            // contents are the bytes buf[off : len(buf)]
	off       int               // read at &buf[off], write at &buf[len(buf)]
	runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
	bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
	lastRead  readOp            // last read operation, so that Unread* can work correctly.
}

// The readOp constants describe the last action performed on
// the buffer, so that UnreadRune and UnreadByte can
// check for invalid usage.
type readOp int

const (
	opInvalid  readOp = iota // Non-read operation.
	opReadRune               // Read rune.
	opRead                   // Any other read operation.
)

// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len().  If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
// are no intervening method calls on the Buffer.
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

// String returns the contents of the unread portion of the buffer
// as a string.  If the Buffer is a nil pointer, it returns "<nil>".
func (b *Buffer) String() string {
	if b == nil {
		// Special case, useful in debugging.
		return "<nil>"
	}
	return string(b.buf[b.off:])
}

// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func (b *Buffer) Len() int { return len(b.buf) - b.off }

// Truncate discards all but the first n unread bytes from the buffer.
// It is an error to call b.Truncate(n) with n > b.Len().
func (b *Buffer) Truncate(n int) {
	b.lastRead = opInvalid
	if n == 0 {
		// Reuse buffer space.
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+n]
}

// Reset resets the buffer so it has no content.
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }

// Grow buffer to guarantee space for n more bytes.
// Return index where bytes should be written.
func (b *Buffer) grow(n int) int {
	m := b.Len()
	// If buffer is empty, reset to recover space.
	if m == 0 && b.off != 0 {
		b.Truncate(0)
	}
	if len(b.buf)+n > cap(b.buf) {
		var buf []byte
		if b.buf == nil && n <= len(b.bootstrap) {
			buf = b.bootstrap[0:]
		} else {
			// not enough space anywhere
			buf = make([]byte, 2*cap(b.buf)+n)
			copy(buf, b.buf[b.off:])
		}
		b.buf = buf
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+m+n]
	return b.off + m
}

// Write appends the contents of p to the buffer.  The return
// value n is the length of p; err is always nil.
func (b *Buffer) Write(p []byte) (n int, err os.Error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	copy(b.buf[m:], p)
	return len(p), nil
}

// WriteString appends the contents of s to the buffer.  The return
// value n is the length of s; err is always nil.
func (b *Buffer) WriteString(s string) (n int, err os.Error) {
	b.lastRead = opInvalid
	m := b.grow(len(s))
	return copy(b.buf[m:], s), nil
}

// MinRead is the minimum slice size passed to a Read call by
// Buffer.ReadFrom.  As long as the Buffer has at least MinRead bytes beyond
// what is required to hold the contents of r, ReadFrom will not grow the
// underlying buffer.
const MinRead = 512

// ReadFrom reads data from r until EOF and appends it to the buffer.
// The return value n is the number of bytes read.
// Any error except os.EOF encountered during the read
// is also returned.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
	b.lastRead = opInvalid
	// If buffer is empty, reset to recover space.
	if b.off >= len(b.buf) {
		b.Truncate(0)
	}
	for {
		if cap(b.buf)-len(b.buf) < MinRead {
			var newBuf []byte
			// can we get space without allocation?
			if b.off+cap(b.buf)-len(b.buf) >= MinRead {
				// reuse beginning of buffer
				newBuf = b.buf[0 : len(b.buf)-b.off]
			} else {
				// not enough space at end; put space on end
				newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
			}
			copy(newBuf, b.buf[b.off:])
			b.buf = newBuf
			b.off = 0
		}
		m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
		b.buf = b.buf[0 : len(b.buf)+m]
		n += int64(m)
		if e == os.EOF {
			break
		}
		if e != nil {
			return n, e
		}
	}
	return n, nil // err is EOF, so return nil explicitly
}

// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written.
// Any error encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
	b.lastRead = opInvalid
	for b.off < len(b.buf) {
		m, e := w.Write(b.buf[b.off:])
		n += int64(m)
		b.off += m
		if e != nil {
			return n, e
		}
	}
	// Buffer is now empty; reset.
	b.Truncate(0)
	return
}

// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
func (b *Buffer) WriteByte(c byte) os.Error {
	b.lastRead = opInvalid
	m := b.grow(1)
	b.buf[m] = c
	return nil
}

// WriteRune appends the UTF-8 encoding of Unicode
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
	if r < utf8.RuneSelf {
		b.WriteByte(byte(r))
		return 1, nil
	}
	n = utf8.EncodeRune(b.runeBytes[0:], r)
	b.Write(b.runeBytes[0:n])
	return n, nil
}

// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained.  The return value n is the number of bytes read.  If the
// buffer has no data to return, err is os.EOF even if len(p) is zero;
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err os.Error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, os.EOF
	}
	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return
}

// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (b *Buffer) Next(n int) []byte {
	b.lastRead = opInvalid
	m := b.Len()
	if n > m {
		n = m
	}
	data := b.buf[b.off : b.off+n]
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return data
}

// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error os.EOF.
func (b *Buffer) ReadByte() (c byte, err os.Error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, os.EOF
	}
	c = b.buf[b.off]
	b.off++
	b.lastRead = opRead
	return c, nil
}

// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is os.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, 0, os.EOF
	}
	b.lastRead = opReadRune
	c := b.buf[b.off]
	if c < utf8.RuneSelf {
		b.off++
		return int(c), 1, nil
	}
	r, n := utf8.DecodeRune(b.buf[b.off:])
	b.off += n
	return r, n, nil
}

// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a ReadRune, UnreadRune returns an error.  (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() os.Error {
	if b.lastRead != opReadRune {
		return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		_, n := utf8.DecodeLastRune(b.buf[0:b.off])
		b.off -= n
	}
	return nil
}

// UnreadByte unreads the last byte returned by the most recent
// read operation.  If write has happened since the last read, UnreadByte
// returns an error.
func (b *Buffer) UnreadByte() os.Error {
	if b.lastRead != opReadRune && b.lastRead != opRead {
		return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		b.off--
	}
	return nil
}

// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents.  It is intended to prepare a Buffer to read existing data.  It
// can also be used to to size the internal buffer for writing.  To do that,
// buf should have the desired capacity but a length of zero.
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

// NewBufferString creates and initializes a new Buffer using string s as its
// initial contents.  It is intended to prepare a buffer to read an existing
// string.
func NewBufferString(s string) *Buffer {
	return &Buffer{buf: []byte(s)}
}
<|endoftext|>