<commit_before>package main

import (
	"github.com/hobeone/rss2go/config"
	"github.com/hobeone/rss2go/db"
	"github.com/hobeone/rss2go/feed_watcher"
	"github.com/hobeone/rss2go/mail"
	"io/ioutil"
	"github.com/golang/glog"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
	"time"
)

func MakeDbFixtures(d db.DbDispatcher, local_url string) {
	all_feeds := []db.FeedInfo{
		{
			Name: "Testing1",
			Url:  local_url + "/test.rss",
		},
	}

	for _, f := range all_feeds {
		d.Orm.Save(&f)
	}
}

var fake_server_handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	var content []byte
	switch {
	case strings.HasSuffix(r.URL.Path, "test.rss"):
		feed_resp, err := ioutil.ReadFile("../testdata/ars.rss")
		if err != nil {
			glog.Fatalf("Error reading test feed: %s", err.Error())
		}
		content = feed_resp
	case true:
		content = []byte("456")
	}
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(content))
})

func TestEndToEndIntegration(t *testing.T) {
	ts := httptest.NewServer(fake_server_handler)
	defer ts.Close()

	// Override the sleep function
	feed_watcher.Sleep = func(d time.Duration) {
		glog.Infof("Call to mock sleep, sleeping for just 1 second.")
		time.Sleep(time.Second * time.Duration(1))
		return
	}

	config := config.NewConfig()

	// Set first argument to true to debug sql
	db := db.NewMemoryDbDispatcher(false, true)
	MakeDbFixtures(*db, ts.URL)
	all_feeds, err := db.GetAllFeeds()

	if err != nil {
		glog.Fatalf("Error reading feeds: %s", err.Error())
	}

	mailer := mail.CreateAndStartStubMailer()

	_, response_channel := CreateAndStartFeedWatchers(
		all_feeds, config, mailer, db)

	resp := <-response_channel
	if len(resp.Items) != 25 {
		t.Errorf("Expected 25 items from the feed. Got %d", len(resp.Items))
	}

	resp = <-response_channel
	if len(resp.Items) != 0 {
		t.Errorf("Expected 0 items from the feed. Got %d", len(resp.Items))
	}
	os.Remove("rss2go_test.db")
}
<commit_msg>Fixup main test after move.<commit_after>package main

import (
	"github.com/golang/glog"
	"github.com/hobeone/rss2go/commands"
	"github.com/hobeone/rss2go/config"
	"github.com/hobeone/rss2go/db"
	"github.com/hobeone/rss2go/feed_watcher"
	"github.com/hobeone/rss2go/mail"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
	"time"
)

func MakeDbFixtures(d db.DbDispatcher, local_url string) {
	all_feeds := []db.FeedInfo{
		{
			Name: "Testing1",
			Url:  local_url + "/test.rss",
		},
	}

	for _, f := range all_feeds {
		d.Orm.Save(&f)
	}
}

var fake_server_handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	var content []byte
	switch {
	case strings.HasSuffix(r.URL.Path, "test.rss"):
		feed_resp, err := ioutil.ReadFile("testdata/ars.rss")
		if err != nil {
			glog.Fatalf("Error reading test feed: %s", err.Error())
		}
		content = feed_resp
	case true:
		content = []byte("456")
	}
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(content))
})

func TestEndToEndIntegration(t *testing.T) {
	ts := httptest.NewServer(fake_server_handler)
	defer ts.Close()

	// Override the sleep function
	feed_watcher.Sleep = func(d time.Duration) {
		glog.Infof("Call to mock sleep, sleeping for just 1 second.")
		time.Sleep(time.Second * time.Duration(1))
		return
	}

	config := config.NewConfig()

	// Set first argument to true to debug sql
	db := db.NewMemoryDbDispatcher(false, true)
	MakeDbFixtures(*db, ts.URL)
	all_feeds, err := db.GetAllFeeds()

	if err != nil {
		glog.Fatalf("Error reading feeds: %s", err.Error())
	}

	mailer := mail.CreateAndStartStubMailer()

	_, response_channel := commands.CreateAndStartFeedWatchers(
		all_feeds, config, mailer, db)

	resp := <-response_channel
	if len(resp.Items) != 25 {
		t.Errorf("Expected 25 items from the feed. Got %d", len(resp.Items))
	}

	resp = <-response_channel
	if len(resp.Items) != 0 {
		t.Errorf("Expected 0 items from the feed. Got %d", len(resp.Items))
	}
	os.Remove("rss2go_test.db")
}
<|endoftext|>


<commit_before>package mat

import (
	"fmt"
	"os"
	"reflect"
	"testing"

	"github.com/ready-steady/assert"
	"github.com/ready-steady/fixture"
)

func TestPut(t *testing.T) {
	path := fixture.MakeTemporaryFile()
	defer os.Remove(path)

	file, _ := Open(path, "w7.3")
	defer file.Close()

	for i, o := range fixtureObjects {
		assert.Success(file.Put(fmt.Sprintf("%c", 'A'+i), o), t)
	}
}

func TestPutMatrix(t *testing.T) {
	path := fixture.MakeTemporaryFile()
	defer os.Remove(path)

	file, _ := Open(path, "w7.3")
	defer file.Close()

	name, rows, cols := "a", uint(2), uint(3)
	data := []float64{1, 2, 3, 4, 5, 6}

	assert.Success(file.PutMatrix(name, data, rows, cols), t)
}

func TestGet(t *testing.T) {
	path := findFixture("data.mat")

	file, _ := Open(path, "r")
	defer file.Close()

	for i, o := range fixtureObjects {
		v := reflect.New(reflect.TypeOf(o))
		p := v.Interface()
		assert.Success(file.Get(fmt.Sprintf("%c", 'A'+i), p), t)
		assert.Equal(reflect.Indirect(v).Interface(), o, t)
	}
}
<commit_msg>Update the usage of fixture<commit_after>package mat

import (
	"fmt"
	"os"
	"reflect"
	"testing"

	"github.com/ready-steady/assert"
	"github.com/ready-steady/fixture"
)

func TestPut(t *testing.T) {
	path := fixture.MakeFile()
	defer os.Remove(path)

	file, _ := Open(path, "w7.3")
	defer file.Close()

	for i, o := range fixtureObjects {
		assert.Success(file.Put(fmt.Sprintf("%c", 'A'+i), o), t)
	}
}

func TestPutMatrix(t *testing.T) {
	path := fixture.MakeFile()
	defer os.Remove(path)

	file, _ := Open(path, "w7.3")
	defer file.Close()

	name, rows, cols := "a", uint(2), uint(3)
	data := []float64{1, 2, 3, 4, 5, 6}

	assert.Success(file.PutMatrix(name, data, rows, cols), t)
}

func TestGet(t *testing.T) {
	path := findFixture("data.mat")

	file, _ := Open(path, "r")
	defer file.Close()

	for i, o := range fixtureObjects {
		v := reflect.New(reflect.TypeOf(o))
		p := v.Interface()
		assert.Success(file.Get(fmt.Sprintf("%c", 'A'+i), p), t)
		assert.Equal(reflect.Indirect(v).Interface(), o, t)
	}
}
<|endoftext|>


<commit_before>package integration_test

import (
	"os/exec"
	"path/filepath"

	"github.com/cloudfoundry/libbuildpack/cutlass"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("nginx logs go to stdout and stderr", func() {
	var app *cutlass.App
	AfterEach(func() {
		if app != nil {
			app.Destroy()
		}
		app = nil
	})

	BeforeEach(func() {
		app = cutlass.New(filepath.Join(bpDir, "fixtures", "staticfile_app"))
		PushAppAndConfirm(app)
	})

	It("", func() {
		By("writes regular logs to stdout and does not write to actual log files", func() {
			Expect(app.GetBody("/")).To(ContainSubstring("This is an example app for Cloud Foundry that is only static HTML/JS/CSS assets."))
			Eventually(app.Stdout.String(), 5*time.Second).Should(MatchRegexp("OUT.*GET / HTTP/1.1"))
			command := exec.Command("cf", "ssh", app.Name, "-c", "ls -l /app/nginx/logs/ | grep access.log")
			Expect(command.Output()).To(ContainSubstring(" vcap 0 "))
		})

		By("writes error logs to stderr and does not write to actual log files", func() {
			Expect(app.GetBody("/idontexist")).To(ContainSubstring("404 Not Found"))
			Eventually(app.Stdout.String(), 5*time.Second).Should(MatchRegexp("ERR.*GET /idontexist HTTP/1.1"))
			command := exec.Command("cf", "ssh", app.Name, "-c", "ls -l /app/nginx/logs/ | grep error.log")
			Expect(command.Output()).To(ContainSubstring(" vcap 0 "))
		})
	})
})
<commit_msg>Pass function to eventually in test (not value)<commit_after>package integration_test

import (
	"os/exec"
	"path/filepath"
	"time"

	"github.com/cloudfoundry/libbuildpack/cutlass"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("nginx logs go to stdout and stderr", func() {
	var app *cutlass.App
	AfterEach(func() {
		if app != nil {
			app.Destroy()
		}
		app = nil
	})

	BeforeEach(func() {
		app = cutlass.New(filepath.Join(bpDir, "fixtures", "staticfile_app"))
		PushAppAndConfirm(app)
	})

	It("", func() {
		By("writes regular logs to stdout and does not write to actual log files", func() {
			Expect(app.GetBody("/")).To(ContainSubstring("This is an example app for Cloud Foundry that is only static HTML/JS/CSS assets."))
			Eventually(app.Stdout.String, 5*time.Second).Should(MatchRegexp("OUT.*GET / HTTP/1.1"))
			command := exec.Command("cf", "ssh", app.Name, "-c", "ls -l /app/nginx/logs/ | grep access.log")
			Expect(command.Output()).To(ContainSubstring(" vcap 0 "))
		})

		By("writes error logs to stderr and does not write to actual log files", func() {
			Expect(app.GetBody("/idontexist")).To(ContainSubstring("404 Not Found"))
			Eventually(app.Stdout.String, 5*time.Second).Should(MatchRegexp("ERR.*GET /idontexist HTTP/1.1"))
			command := exec.Command("cf", "ssh", app.Name, "-c", "ls -l /app/nginx/logs/ | grep error.log")
			Expect(command.Output()).To(ContainSubstring(" vcap 0 "))
		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state_test

import (
	"github.com/juju/loggo"
	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/state"
)

type ActionSuite struct {
	ConnSuite
	charm   *state.Charm
	service *state.Service
	unit    *state.Unit
}

var _ = gc.Suite(&ActionSuite{})

func (s *ActionSuite) SetUpTest(c *gc.C) {
	s.ConnSuite.SetUpTest(c)
	s.charm = s.AddTestingCharm(c, "wordpress")
	var err error
	s.service = s.AddTestingService(c, "wordpress", s.charm)
	c.Assert(err, gc.IsNil)
	s.unit, err = s.service.AddUnit()
	c.Assert(err, gc.IsNil)
	c.Assert(s.unit.Series(), gc.Equals, "quantal")
}

func (s *ActionSuite) TestAddAction(c *gc.C) {
	actionName := "fakeaction"
	actionParams := map[string]interface{}{"outfile": "outfile.tar.bz2"}

	// verify can add an Action
	actionId, err := s.unit.AddAction(actionName, actionParams)
	c.Assert(err, gc.IsNil)
	assertSaneActionId(c, actionId, s.unit.Name())

	// verify we can get it back out by Id
	action, err := s.State.Action(actionId)
	c.Assert(err, gc.IsNil)
	c.Assert(action, gc.NotNil)
	c.Assert(action.Id(), gc.Equals, actionId)

	// verify we get out what we put in
	c.Assert(action.Name(), gc.Equals, actionName)
	c.Assert(action.Payload(), jc.DeepEquals, actionParams)
}

func (s *ActionSuite) TestAddActionLifecycle(c *gc.C) {
	unit, err := s.State.Unit(s.unit.Name())
	c.Assert(err, gc.IsNil)
	preventUnitDestroyRemove(c, unit)

	// make unit state Dying
	err = unit.Destroy()
	c.Assert(err, gc.IsNil)

	// can add action to a dying unit
	actionId, err := unit.AddAction("fakeaction1", map[string]interface{}{})
	c.Assert(err, gc.IsNil)
	assertSaneActionId(c, actionId, s.unit.Name())

	// make sure unit is dead
	err = unit.EnsureDead()
	c.Assert(err, gc.IsNil)

	// cannot add action to a dead unit
	_, err = unit.AddAction("fakeaction2", map[string]interface{}{})
	c.Assert(err, gc.ErrorMatches, "unit .* is dead")
}

func (s *ActionSuite) TestAddActionFailsOnDeadUnitInTransaction(c *gc.C) {
	unit, err := s.State.Unit(s.unit.Name())
	c.Assert(err, gc.IsNil)
	preventUnitDestroyRemove(c, unit)

	killUnit := state.TransactionHook{
		Before: func() {
			c.Assert(unit.Destroy(), gc.IsNil)
			c.Assert(unit.EnsureDead(), gc.IsNil)
		},
	}
	defer state.SetTransactionHooks(c, s.State, killUnit).Check()

	_, err = unit.AddAction("fakeaction", map[string]interface{}{})
	c.Assert(err, gc.ErrorMatches, "unit .* is dead")
}

func (s *ActionSuite) TestFail(c *gc.C) {
	// TODO(jcw4): when action results are implemented we should be
	// checking for a Fail result after calling Fail(), rather than
	// sniffing the logs
	defer loggo.ResetWriters()
	logger := loggo.GetLogger("test")
	logger.SetLogLevel(loggo.DEBUG)
	tw := &loggo.TestWriter{}
	c.Assert(loggo.RegisterWriter("actions-tester", tw, loggo.DEBUG), gc.IsNil)

	// get unit, add an action, retrieve that action
	unit, err := s.State.Unit(s.unit.Name())
	c.Assert(err, gc.IsNil)
	preventUnitDestroyRemove(c, unit)

	actionId, err := unit.AddAction("action1", nil)
	c.Assert(err, gc.IsNil)

	action, err := s.State.Action(actionId)
	c.Assert(err, gc.IsNil)

	// fail the action, and verify that it succeeds (right now, just by
	// sniffing the logs)
	reason := "test fail reason"
	err = action.Fail(reason)
	c.Assert(err, gc.IsNil)
	// TODO(jcw4): replace with action results check when they're implemented
	c.Assert(tw.Log, jc.LogMatches, jc.SimpleMessages{{loggo.WARNING, reason}})

	// validate that a failed action is no longer returned by UnitActions.
	actions, err := s.State.UnitActions(unit.Name())
	c.Assert(err, gc.IsNil)
	c.Assert(len(actions), gc.Equals, 0)
}

// assertSaneActionId verifies that the actionId is of the expected
// form (unit id prefix + sequence)
// This is a temporary assertion, we shouldn't be leaking the actual
// mongo _id
func assertSaneActionId(c *gc.C, actionId, unitName string) {
	c.Assert(actionId, gc.Matches, "^u#"+unitName+"#a#\\d+")
}
<commit_msg>add test to validate we can have multiple actions with same name. simplified local variable names<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state_test

import (
	"github.com/juju/loggo"
	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/state"
)

type ActionSuite struct {
	ConnSuite
	charm   *state.Charm
	service *state.Service
	unit    *state.Unit
}

var _ = gc.Suite(&ActionSuite{})

func (s *ActionSuite) SetUpTest(c *gc.C) {
	s.ConnSuite.SetUpTest(c)
	s.charm = s.AddTestingCharm(c, "wordpress")
	var err error
	s.service = s.AddTestingService(c, "wordpress", s.charm)
	c.Assert(err, gc.IsNil)
	s.unit, err = s.service.AddUnit()
	c.Assert(err, gc.IsNil)
	c.Assert(s.unit.Series(), gc.Equals, "quantal")
}

func (s *ActionSuite) TestAddAction(c *gc.C) {
	name := "fakeaction"
	params := map[string]interface{}{"outfile": "outfile.tar.bz2"}

	// verify can add an Action
	id, err := s.unit.AddAction(name, params)
	c.Assert(err, gc.IsNil)
	assertSaneActionId(c, id, s.unit.Name())

	// verify we can get it back out by Id
	action, err := s.State.Action(id)
	c.Assert(err, gc.IsNil)
	c.Assert(action, gc.NotNil)
	c.Assert(action.Id(), gc.Equals, id)

	// verify we get out what we put in
	c.Assert(action.Name(), gc.Equals, name)
	c.Assert(action.Payload(), jc.DeepEquals, params)
}

func (s *ActionSuite) TestAddActionAcceptsDuplicateNames(c *gc.C) {
	name := "fakeaction"
	params_1 := map[string]interface{}{"outfile": "outfile.tar.bz2"}
	params_2 := map[string]interface{}{"infile": "infile.zip"}

	// verify can add two actions with same name
	id_1, err := s.unit.AddAction(name, params_1)
	c.Assert(err, gc.IsNil)
	assertSaneActionId(c, id_1, s.unit.Name())

	id_2, err := s.unit.AddAction(name, params_2)
	c.Assert(err, gc.IsNil)
	assertSaneActionId(c, id_2, s.unit.Name())

	c.Assert(id_1, gc.Not(gc.Equals), id_2)

	// verify both actually got added
	actions, err := s.State.UnitActions(s.unit.Name())
	c.Assert(err, gc.IsNil)
	c.Assert(len(actions), gc.Equals, 2)

	// verify we can Fail one, retrieve the other, and they're not mixed up
	action_1, err := s.State.Action(id_1)
	c.Assert(err, gc.IsNil)
	err = action_1.Fail("")
	c.Assert(err, gc.IsNil)

	action_2, err := s.State.Action(id_2)
	c.Assert(err, gc.IsNil)
	c.Assert(action_2.Payload(), gc.DeepEquals, params_2)

	// verify only one left, and it's the expected one
	actions, err = s.State.UnitActions(s.unit.Name())
	c.Assert(err, gc.IsNil)
	c.Assert(len(actions), gc.Equals, 1)
	c.Assert(actions[0].Id(), gc.Equals, id_2)
}

func (s *ActionSuite) TestAddActionLifecycle(c *gc.C) {
	unit, err := s.State.Unit(s.unit.Name())
	c.Assert(err, gc.IsNil)
	preventUnitDestroyRemove(c, unit)

	// make unit state Dying
	err = unit.Destroy()
	c.Assert(err, gc.IsNil)

	// can add action to a dying unit
	id, err := unit.AddAction("fakeaction1", map[string]interface{}{})
	c.Assert(err, gc.IsNil)
	assertSaneActionId(c, id, s.unit.Name())

	// make sure unit is dead
	err = unit.EnsureDead()
	c.Assert(err, gc.IsNil)

	// cannot add action to a dead unit
	_, err = unit.AddAction("fakeaction2", map[string]interface{}{})
	c.Assert(err, gc.ErrorMatches, "unit .* is dead")
}

func (s *ActionSuite) TestAddActionFailsOnDeadUnitInTransaction(c *gc.C) {
	unit, err := s.State.Unit(s.unit.Name())
	c.Assert(err, gc.IsNil)
	preventUnitDestroyRemove(c, unit)

	killUnit := state.TransactionHook{
		Before: func() {
			c.Assert(unit.Destroy(), gc.IsNil)
			c.Assert(unit.EnsureDead(), gc.IsNil)
		},
	}
	defer state.SetTransactionHooks(c, s.State, killUnit).Check()

	_, err = unit.AddAction("fakeaction", map[string]interface{}{})
	c.Assert(err, gc.ErrorMatches, "unit .* is dead")
}

func (s *ActionSuite) TestFail(c *gc.C) {
	// TODO(jcw4): when action results are implemented we should be
	// checking for a Fail result after calling Fail(), rather than
	// sniffing the logs
	defer loggo.ResetWriters()
	logger := loggo.GetLogger("test")
	logger.SetLogLevel(loggo.DEBUG)
	tw := &loggo.TestWriter{}
	c.Assert(loggo.RegisterWriter("actions-tester", tw, loggo.DEBUG), gc.IsNil)

	// get unit, add an action, retrieve that action
	unit, err := s.State.Unit(s.unit.Name())
	c.Assert(err, gc.IsNil)
	preventUnitDestroyRemove(c, unit)

	id, err := unit.AddAction("action1", nil)
	c.Assert(err, gc.IsNil)

	action, err := s.State.Action(id)
	c.Assert(err, gc.IsNil)

	// fail the action, and verify that it succeeds (right now, just by
	// sniffing the logs)
	reason := "test fail reason"
	err = action.Fail(reason)
	c.Assert(err, gc.IsNil)
	// TODO(jcw4): replace with action results check when they're implemented
	c.Assert(tw.Log, jc.LogMatches, jc.SimpleMessages{{loggo.WARNING, reason}})

	// validate that a failed action is no longer returned by UnitActions.
	actions, err := s.State.UnitActions(unit.Name())
	c.Assert(err, gc.IsNil)
	c.Assert(len(actions), gc.Equals, 0)
}

// assertSaneActionId verifies that the id is of the expected
// form (unit id prefix + sequence)
// This is a temporary assertion, we shouldn't be leaking the actual
// mongo _id
func assertSaneActionId(c *gc.C, id, unitName string) {
	c.Assert(id, gc.Matches, "^u#"+unitName+"#a#\\d+")
}
<|endoftext|>


<commit_before><commit_msg>refactorings to make zipkin test more consistent<commit_after><|endoftext|>


<commit_before>package fingerprint

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
)

// StorageFingerprint is used to measure the amount of storage free for
// applications that the Nomad agent will run on this machine.
type StorageFingerprint struct {
	logger *log.Logger
}

var (
	reWindowsTotalSpace = regexp.MustCompile("Total # of bytes\\s+: (\\d+)")
	reWindowsFreeSpace  = regexp.MustCompile("Total # of free bytes\\s+: (\\d+)")
)

func NewStorageFingerprint(logger *log.Logger) Fingerprint {
	fp := &StorageFingerprint{logger: logger}
	return fp
}

func (f *StorageFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

	// Initialize these to empty defaults
	node.Attributes["storage.volume"] = ""
	node.Attributes["storage.bytestotal"] = ""
	node.Attributes["storage.bytesfree"] = ""
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	// Guard against unset AllocDir
	storageDir := cfg.AllocDir
	if storageDir == "" {
		var err error
		storageDir, err = os.Getwd()
		if err != nil {
			return false, fmt.Errorf("Unable to get CWD from filesystem: %s", err)
		}
	}

	if runtime.GOOS == "windows" {
		path, err := filepath.Abs(storageDir)
		if err != nil {
			return false, fmt.Errorf("Failed to detect volume for storage directory %s: %s", storageDir, err)
		}
		volume := filepath.VolumeName(path)
		node.Attributes["storage.volume"] = volume
		out, err := exec.Command("fsutil", "volume", "diskfree", volume).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to inspect free space from volume %s: %s", volume, err)
		}
		outstring := string(out)

		totalMatches := reWindowsTotalSpace.FindStringSubmatch(outstring)
		if len(totalMatches) == 2 {
			node.Attributes["storage.bytestotal"] = totalMatches[1]
			total, err := strconv.ParseInt(totalMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytestotal in bytes: %s", err)
			}
			// Convert from bytes to to MB
			node.Resources.DiskMB = int(total / 1024 / 1024)
		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}

		freeMatches := reWindowsFreeSpace.FindStringSubmatch(outstring)
		if len(freeMatches) == 2 {
			node.Attributes["storage.bytesfree"] = freeMatches[1]
			_, err := strconv.ParseInt(freeMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytesfree in bytes: %s", err)
			}

		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}
	} else {
		path, err := filepath.Abs(storageDir)
		if err != nil {
			return false, fmt.Errorf("Failed to determine absolute path for %s", storageDir)
		}

		// Use -k to standardize the output values between darwin and linux
		mountOutput, err := exec.Command("df", "-k", path).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to determine mount point for %s", path)
		}
		// Output looks something like:
		//	Filesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
		//	/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /
		//	[0] volume [1] capacity [2] SKIP  [3] free
		lines := strings.Split(string(mountOutput), "\n")
		if len(lines) < 2 {
			return false, fmt.Errorf("Failed to parse `df` output; expected at least 2 lines")
		}
		fields := strings.Fields(lines[1])
		if len(fields) < 4 {
			return false, fmt.Errorf("Failed to parse `df` output; expected at least 4 columns")
		}
		node.Attributes["storage.volume"] = fields[0]

		total, err := strconv.ParseInt(fields[1], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytestotal size in kilobytes")
		}
		node.Attributes["storage.bytestotal"] = strconv.FormatInt(total*1024, 10)

		free, err := strconv.ParseInt(fields[3], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytesfree size in kilobytes")
		}
		// Convert from KB to MB
		node.Resources.DiskMB = int(free / 1024)
		// Convert from KB to bytes
		node.Attributes["storage.bytesfree"] = strconv.FormatInt(free*1024, 10)
	}

	return true, nil
}
<commit_msg>Prevent df on linux from adding line breaks to output<commit_after>package fingerprint

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
)

// StorageFingerprint is used to measure the amount of storage free for
// applications that the Nomad agent will run on this machine.
type StorageFingerprint struct {
	logger *log.Logger
}

var (
	reWindowsTotalSpace = regexp.MustCompile("Total # of bytes\\s+: (\\d+)")
	reWindowsFreeSpace  = regexp.MustCompile("Total # of free bytes\\s+: (\\d+)")
)

func NewStorageFingerprint(logger *log.Logger) Fingerprint {
	fp := &StorageFingerprint{logger: logger}
	return fp
}

func (f *StorageFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

	// Initialize these to empty defaults
	node.Attributes["storage.volume"] = ""
	node.Attributes["storage.bytestotal"] = ""
	node.Attributes["storage.bytesfree"] = ""
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	// Guard against unset AllocDir
	storageDir := cfg.AllocDir
	if storageDir == "" {
		var err error
		storageDir, err = os.Getwd()
		if err != nil {
			return false, fmt.Errorf("Unable to get CWD from filesystem: %s", err)
		}
	}

	if runtime.GOOS == "windows" {
		path, err := filepath.Abs(storageDir)
		if err != nil {
			return false, fmt.Errorf("Failed to detect volume for storage directory %s: %s", storageDir, err)
		}
		volume := filepath.VolumeName(path)
		node.Attributes["storage.volume"] = volume
		out, err := exec.Command("fsutil", "volume", "diskfree", volume).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to inspect free space from volume %s: %s", volume, err)
		}
		outstring := string(out)

		totalMatches := reWindowsTotalSpace.FindStringSubmatch(outstring)
		if len(totalMatches) == 2 {
			node.Attributes["storage.bytestotal"] = totalMatches[1]
			total, err := strconv.ParseInt(totalMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytestotal in bytes: %s", err)
			}
			// Convert from bytes to to MB
			node.Resources.DiskMB = int(total / 1024 / 1024)
		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}

		freeMatches := reWindowsFreeSpace.FindStringSubmatch(outstring)
		if len(freeMatches) == 2 {
			node.Attributes["storage.bytesfree"] = freeMatches[1]
			_, err := strconv.ParseInt(freeMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytesfree in bytes: %s", err)
			}

		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}
	} else {
		path, err := filepath.Abs(storageDir)
		if err != nil {
			return false, fmt.Errorf("Failed to determine absolute path for %s", storageDir)
		}

		// Use -k to standardize the output values between darwin and linux
		var dfArgs string
		if runtime.GOOS == "linux" {
			// df on linux needs the -P option to prevent linebreaks on long filesystem paths
			dfArgs = "-kP"
		} else {
			dfArgs = "-k"
		}

		mountOutput, err := exec.Command("df", dfArgs, path).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to determine mount point for %s", path)
		}
		// Output looks something like:
		//	Filesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
		//	/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /
		//	[0] volume [1] capacity [2] SKIP  [3] free
		lines := strings.Split(string(mountOutput), "\n")
		if len(lines) < 2 {
			return false, fmt.Errorf("Failed to parse `df` output; expected at least 2 lines")
		}
		fields := strings.Fields(lines[1])
		if len(fields) < 4 {
			return false, fmt.Errorf("Failed to parse `df` output; expected at least 4 columns")
		}
		node.Attributes["storage.volume"] = fields[0]

		total, err := strconv.ParseInt(fields[1], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytestotal size in kilobytes")
		}
		node.Attributes["storage.bytestotal"] = strconv.FormatInt(total*1024, 10)

		free, err := strconv.ParseInt(fields[3], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytesfree size in kilobytes")
		}
		// Convert from KB to MB
		node.Resources.DiskMB = int(free / 1024)
		// Convert from KB to bytes
		node.Attributes["storage.bytesfree"] = strconv.FormatInt(free*1024, 10)
	}

	return true, nil
}
<|endoftext|>


<commit_before>package fingerprint

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
)

// StorageFingerprint is used to measure the amount of storage free for
// applications that the Nomad agent will run on this machine.
type StorageFingerprint struct {
	logger *log.Logger
}

var (
	reWindowsTotalSpace = regexp.MustCompile("Total # of bytes\\s+: (\\d+)")
	reWindowsFreeSpace  = regexp.MustCompile("Total # of free bytes\\s+: (\\d+)")
)

func NewStorageFingerprint(logger *log.Logger) Fingerprint {
	fp := &StorageFingerprint{logger: logger}
	return fp
}

func (f *StorageFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

	// Initialize these to empty defaults
	node.Attributes["storage.volume"] = ""
	node.Attributes["storage.bytestotal"] = ""
	node.Attributes["storage.bytesfree"] = ""
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	if runtime.GOOS == "windows" {
		path, err := filepath.Abs(cfg.AllocDir)
		if err != nil {
			return false, fmt.Errorf("Failed to detect volume for storage directory %s: %s", cfg.AllocDir, err)
		}
		volume := filepath.VolumeName(path)
		node.Attributes["storage.volume"] = volume
		out, err := exec.Command("fsutil", "volume", "diskfree", volume).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to inspect free space from volume %s: %s", volume, err)
		}
		outstring := string(out)

		totalMatches := reWindowsTotalSpace.FindStringSubmatch(outstring)
		if len(totalMatches) == 2 {
			node.Attributes["storage.bytestotal"] = totalMatches[1]
			total, err := strconv.ParseInt(totalMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytestotal in bytes: %s", err)
			}
			// Convert from bytes to to MB
			node.Resources.DiskMB = int(total / 1024 / 1024)
		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}

		freeMatches := reWindowsFreeSpace.FindStringSubmatch(outstring)
		if len(freeMatches) == 2 {
			node.Attributes["storage.bytesfree"] = freeMatches[1]
			_, err := strconv.ParseInt(freeMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytesfree in bytes: %s", err)
			}

		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}
	} else {
		path, err := filepath.Abs(cfg.AllocDir)
		if err != nil {
			return false, fmt.Errorf("Failed to determine absolute path for %s", cfg.AllocDir)
		}

		// Use -k to standardize the output values between darwin and linux
		mountOutput, err := exec.Command("df", "-k", path).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to determine mount point for %s", path)
		}
		// Output looks something like:
		//	Filesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
		//	/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /
		//	[0] volume [1] capacity [2] SKIP  [3] free
		fields := strings.Fields(strings.Split(string(mountOutput), "\n")[1])
		node.Attributes["storage.volume"] = fields[0]

		total, err := strconv.ParseInt(fields[1], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytestotal size in kilobytes")
		}
		node.Attributes["storage.bytestotal"] = strconv.FormatInt(total*1024, 10)

		free, err := strconv.ParseInt(fields[3], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytesfree size in kilobytes")
		}
		// Convert from KB to MB
		node.Resources.DiskMB = int(free / 1024)
		// Convert from KB to bytes
		node.Attributes["storage.bytesfree"] = strconv.FormatInt(free*1024, 10)
	}

	return true, nil
}
<commit_msg>Prevent a panic if the df tool output is not in the expected format<commit_after>package fingerprint

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
)

// StorageFingerprint is used to measure the amount of storage free for
// applications that the Nomad agent will run on this machine.
type StorageFingerprint struct {
	logger *log.Logger
}

var (
	reWindowsTotalSpace = regexp.MustCompile("Total # of bytes\\s+: (\\d+)")
	reWindowsFreeSpace  = regexp.MustCompile("Total # of free bytes\\s+: (\\d+)")
)

func NewStorageFingerprint(logger *log.Logger) Fingerprint {
	fp := &StorageFingerprint{logger: logger}
	return fp
}

func (f *StorageFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {

	// Initialize these to empty defaults
	node.Attributes["storage.volume"] = ""
	node.Attributes["storage.bytestotal"] = ""
	node.Attributes["storage.bytesfree"] = ""
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	if runtime.GOOS == "windows" {
		path, err := filepath.Abs(cfg.AllocDir)
		if err != nil {
			return false, fmt.Errorf("Failed to detect volume for storage directory %s: %s", cfg.AllocDir, err)
		}
		volume := filepath.VolumeName(path)
		node.Attributes["storage.volume"] = volume
		out, err := exec.Command("fsutil", "volume", "diskfree", volume).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to inspect free space from volume %s: %s", volume, err)
		}
		outstring := string(out)

		totalMatches := reWindowsTotalSpace.FindStringSubmatch(outstring)
		if len(totalMatches) == 2 {
			node.Attributes["storage.bytestotal"] = totalMatches[1]
			total, err := strconv.ParseInt(totalMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytestotal in bytes: %s", err)
			}
			// Convert from bytes to to MB
			node.Resources.DiskMB = int(total / 1024 / 1024)
		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}

		freeMatches := reWindowsFreeSpace.FindStringSubmatch(outstring)
		if len(freeMatches) == 2 {
			node.Attributes["storage.bytesfree"] = freeMatches[1]
			_, err := strconv.ParseInt(freeMatches[1], 10, 64)
			if err != nil {
				return false, fmt.Errorf("Failed to parse storage.bytesfree in bytes: %s", err)
			}

		} else {
			return false, fmt.Errorf("Failed to parse output from fsutil")
		}
	} else {
		path, err := filepath.Abs(cfg.AllocDir)
		if err != nil {
			return false, fmt.Errorf("Failed to determine absolute path for %s", cfg.AllocDir)
		}

		// Use -k to standardize the output values between darwin and linux
		mountOutput, err := exec.Command("df", "-k", path).Output()
		if err != nil {
			return false, fmt.Errorf("Failed to determine mount point for %s", path)
		}
		// Output looks something like:
		//	Filesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
		//	/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /
		//	[0] volume [1] capacity [2] SKIP  [3] free
		lines := strings.Split(string(mountOutput), "\n")
		if len(lines) < 2 {
			return false, fmt.Errorf("Failed to parse `df` output; expected 2 lines")
		}
		fields := strings.Fields(lines[1])
		if len(fields) != 9 {
			return false, fmt.Errorf("Failed to parse `df` output; expected 9 columns")
		}
		node.Attributes["storage.volume"] = fields[0]

		total, err := strconv.ParseInt(fields[1], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytestotal size in kilobytes")
		}
		node.Attributes["storage.bytestotal"] = strconv.FormatInt(total*1024, 10)

		free, err := strconv.ParseInt(fields[3], 10, 64)
		if err != nil {
			return false, fmt.Errorf("Failed to parse storage.bytesfree size in kilobytes")
		}
		// Convert from KB to MB
		node.Resources.DiskMB = int(free / 1024)
		// Convert from KB to bytes
		node.Attributes["storage.bytesfree"] = strconv.FormatInt(free*1024, 10)
	}

	return true, nil
}
<|endoftext|>


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

package sdk

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

const (
	coreosId = "{E96281A6-D1AF-4BDE-9A0A-97B76E56DC57}"
)

func getVersion(dir, key string) (ver string, err error) {
	f, err := os.Open(filepath.Join(dir, "version.txt"))
	if err != nil {
		return
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, key) {
			ver = line[len(key):]
			break
		}
	}
	err = scanner.Err()

	if err == nil && ver == "" {
		err = fmt.Errorf("Missing %s value in %s", key, f.Name())
	}

	return
}

func GetVersionFromDir(dir string) (string, error) {
	return getVersion(dir, "COREOS_VERSION=")
}

func GetLatestVersion() (string, error) {
	return getVersion(BuildImageDir("latest"), "COREOS_VERSION=")
}

func GetSDKVersion() (string, error) {
	return getVersion(filepath.Join(RepoRoot(), ".repo", "manifests"), "COREOS_SDK_VERSION=")
}

func GetSDKVersionFromDir(dir string) (string, error) {
	return getVersion(dir, "COREOS_SDK_VERSION=")
}

func GetSDKVersionFromRemoteRepo(url, branch string) (string, error) {
	tmp, err := ioutil.TempDir("", "")
	if err != nil {
		return "", err
	}
	defer os.RemoveAll(tmp)

	clone := exec.Command("git", "clone", "-q", "--depth=1", "--single-branch", "-b", branch, url, tmp)
	clone.Stderr = os.Stderr
	if err := clone.Run(); err != nil {
		return "", err
	}

	return GetSDKVersionFromDir(tmp)
}

func GetDefaultAppId() string {
	// This is a function in case the id needs to be configurable.
	return coreosId
}

const (
	CoreOSEpoch = 1372636800
)

// GetCoreOSAge returns the number of days since the CoreOS epoch.
func GetCoreOSAge() int64 {
	return int64(time.Since(time.Unix(CoreOSEpoch, 0)) / (86400 * time.Second))
}
<commit_msg>sdk: fix SDK version detection for full ref paths<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sdk

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

const (
	coreosId = "{E96281A6-D1AF-4BDE-9A0A-97B76E56DC57}"
)

func getVersion(dir, key string) (ver string, err error) {
	f, err := os.Open(filepath.Join(dir, "version.txt"))
	if err != nil {
		return
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, key) {
			ver = line[len(key):]
			break
		}
	}
	err = scanner.Err()

	if err == nil && ver == "" {
		err = fmt.Errorf("Missing %s value in %s", key, f.Name())
	}

	return
}

func GetVersionFromDir(dir string) (string, error) {
	return getVersion(dir, "COREOS_VERSION=")
}

func GetLatestVersion() (string, error) {
	return getVersion(BuildImageDir("latest"), "COREOS_VERSION=")
}

func GetSDKVersion() (string, error) {
	return getVersion(filepath.Join(RepoRoot(), ".repo", "manifests"), "COREOS_SDK_VERSION=")
}

func GetSDKVersionFromDir(dir string) (string, error) {
	return getVersion(dir, "COREOS_SDK_VERSION=")
}

func GetSDKVersionFromRemoteRepo(url, branch string) (string, error) {
	// git clone cannot be given a full ref path, instead it explicitly checks
	// under both refs/heads/<name> and refs/tags/<name>, in that order.
	if strings.HasPrefix(branch, "refs/") {
		if strings.HasPrefix(branch, "refs/heads/") {
			branch = strings.TrimPrefix(branch, "refs/heads/")
		} else if strings.HasPrefix(branch, "refs/tags/") {
			branch = strings.TrimPrefix(branch, "refs/tags/")
		} else {
			return "", fmt.Errorf("SDK version cannot be detected for %q", branch)
		}
	}

	tmp, err := ioutil.TempDir("", "")
	if err != nil {
		return "", err
	}
	defer os.RemoveAll(tmp)

	clone := exec.Command("git", "clone", "-q", "--depth=1", "--single-branch", "-b", branch, url, tmp)
	clone.Stderr = os.Stderr
	if err := clone.Run(); err != nil {
		return "", err
	}

	return GetSDKVersionFromDir(tmp)
}

func GetDefaultAppId() string {
	// This is a function in case the id needs to be configurable.
	return coreosId
}

const (
	CoreOSEpoch = 1372636800
)

// GetCoreOSAge returns the number of days since the CoreOS epoch.
func GetCoreOSAge() int64 {
	return int64(time.Since(time.Unix(CoreOSEpoch, 0)) / (86400 * time.Second))
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2018 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.
//
// I am making my contributions/submissions to this project solely in my
// personal capacity and am not conveying any rights to any intellectual
// property of any third parties.

package donna

func (p *Position) searchTree(alpha, beta, depth int) (score int) {
	ply := ply()

	// Return if it's time to stop search.
	if ply >= MaxPly || engine.clock.halt {
		return p.Evaluate()
	}

	// Reset principal variation.
	game.pv[ply].size = 0

	// Insufficient material and repetition/perpetual check pruning.
	if p.fifty() || p.insufficient() || p.repetition() {
		return 0
	}

	// Checkmate distance pruning.
	alpha, beta = mateDistance(alpha, beta, ply)
	if alpha >= beta {
		return alpha
	}

	// Initialize node search conditions.
	isNull := p.isNull()
	inCheck := p.isInCheck(p.color)
	isPrincipal := (beta - alpha > 1)

	// Probe cache.
	cached, cachedMove := p.probeCache(), Move(0)
	if cached != nil {
		cachedMove = cached.move
		if !isPrincipal && cached.depth() >= depth {
			bounds, score := cached.bounds(), cached.score(ply)
			if (bounds == cacheBeta && score >= beta) || (bounds == cacheAlpha && score <= alpha) {
				if score >= beta && !inCheck && cachedMove.some() {
					game.saveGood(depth, cachedMove)
				}
				return score
			}
		}
	}

	if !inCheck {
		if depth < 1 {
			return p.searchQuiescence(alpha, beta, 0, inCheck)
		}
		if cached != nil {
			if p.score == Unknown {
				p.score = p.Evaluate()
			}
		} else {
			if isNull {
				p.score = rightToMove.midgame * 2 - tree[node-1].score
			} else {
				p.score = p.Evaluate()
			}
		}
	}

	// Razoring and futility margin pruning.
	if !inCheck && !isPrincipal {

		// No razoring if pawns are on 7th rank.
		if cachedMove.null() && depth < 3 && p.outposts[pawn(p.color)] & mask7th[p.color] == 0 {
			razoringMargin := func(depth int) int {
				return 96 + 64 * (depth - 1)
			}

		   	// Special case for razoring at low depths.
			if p.score <= alpha - razoringMargin(5) {
				return p.searchQuiescence(alpha, beta, 0, inCheck)
			}

			margin := alpha - razoringMargin(depth)
			if score := p.searchQuiescence(margin, margin + 1, 0, inCheck); score <= margin {
				return score
			}
		}

		// Futility pruning is only applicable if we don't have winning score
		// yet and there are pieces other than pawns.
		if !isNull && depth < 14 && !isMate(beta) &&
		   (p.outposts[p.color] & ^(p.outposts[king(p.color)] | p.outposts[pawn(p.color)])).any() {
			// Largest conceivable positional gain.
			if gain := p.score - 256 * depth; gain >= beta {
				return gain
			}
		}

		// Null move pruning.
		if !isNull && depth > 1 && p.outposts[p.color].count() > 5 {
			position := p.makeNullMove()
			game.nodes++
			nullScore := -position.searchTree(-beta, -beta + 1, depth - 1 - 3)
			position.undoLastMove()

			if nullScore >= beta {
				if isMate(nullScore) {
					return beta
				}
				return nullScore
			}
		}
	}

	// Internal iterative deepening.
	if !inCheck && cachedMove.null() && depth > 4 {
		newDepth := depth / 2
		if isPrincipal {
			newDepth = depth - 2
		}
		p.searchTree(alpha, beta, newDepth)
		if cached := p.probeCache(); cached != nil {
			cachedMove = cached.move
		}
	}

	gen := NewGen(p, ply)
	if inCheck {
		gen.generateEvasions().quickRank()
	} else {
		gen.generateMoves().rank(cachedMove)
	}

	bestScore := alpha
	bestMove, moveCount := Move(0), 0
	for move := gen.nextMove(); move.some(); move = gen.nextMove() {
		if !move.valid(p, gen.pins) {
			continue
		}

		position := p.makeMove(move)
		moveCount++; game.nodes++

		// Reduce search depth if we're not checking.
		giveCheck := position.isInCheck(position.color)
		newDepth := let(giveCheck && p.exchange(move) >= 0, depth, depth - 1)

		// Start search with full window.
		if isPrincipal && moveCount == 1 {
			score = -position.searchTree(-beta, -alpha, newDepth)
		} else {
			reduction := 0
			if !isPrincipal && !inCheck && !giveCheck && depth > 2 && move.isQuiet() && !move.isKiller(ply) && !move.isPawnAdvance() {
				reduction = lateMoveReductions[min(63, moveCount-1)][min(63, depth)]
				if game.history[move.piece()][move.to()] < 0 {
					reduction++
				}
			}

			score = -position.searchTree(-alpha - 1, -alpha, max(0, newDepth - reduction))

			// Verify late move reduction and re-run the search if necessary.
			if reduction > 0 && score > alpha {
				score = -position.searchTree(-alpha - 1, -alpha, newDepth)
			}

			// If zero window failed try full window.
			if isPrincipal && score > alpha && score < beta {
				score = -position.searchTree(-beta, -alpha, newDepth)
			}
		}
		position.undoLastMove()

		// Don't touch anything if the time has elapsed and we need to abort th search.
		if engine.clock.halt {
			return alpha
		}

		if score > bestScore {
			bestScore = score
			if score > alpha {
				if isPrincipal {
					game.saveBest(ply, move)
				}
				if isPrincipal && score < beta {
					alpha = score
					bestMove = move
				} else {
					p.cache(move, score, depth, ply, cacheBeta)
					return score
				}
			}
		}
	}

	if moveCount == 0 {
		score = let(inCheck, matedIn(ply), 0)
	} else {
		score = bestScore
		if !inCheck {
			game.saveGood(depth, bestMove)
		}
	}

	cacheFlags := cacheAlpha
	if score >= beta {
		cacheFlags = cacheBeta
	} else if isPrincipal && bestMove.some() {
		cacheFlags = cacheExact
	}
	p.cache(bestMove, score, depth, ply, cacheFlags)

	return score
}
<commit_msg>Allow late move reduction for principal variations<commit_after>// Copyright (c) 2014-2018 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.
//
// I am making my contributions/submissions to this project solely in my
// personal capacity and am not conveying any rights to any intellectual
// property of any third parties.

package donna

func (p *Position) searchTree(alpha, beta, depth int) (score int) {
	ply := ply()

	// Return if it's time to stop search.
	if ply >= MaxPly || engine.clock.halt {
		return p.Evaluate()
	}

	// Reset principal variation.
	game.pv[ply].size = 0

	// Insufficient material and repetition/perpetual check pruning.
	if p.fifty() || p.insufficient() || p.repetition() {
		return 0
	}

	// Checkmate distance pruning.
	alpha, beta = mateDistance(alpha, beta, ply)
	if alpha >= beta {
		return alpha
	}

	// Initialize node search conditions.
	isNull := p.isNull()
	inCheck := p.isInCheck(p.color)
	isPrincipal := (beta - alpha > 1)

	// Probe cache.
	cached, cachedMove := p.probeCache(), Move(0)
	if cached != nil {
		cachedMove = cached.move
		if !isPrincipal && cached.depth() >= depth {
			bounds, score := cached.bounds(), cached.score(ply)
			if (bounds == cacheBeta && score >= beta) || (bounds == cacheAlpha && score <= alpha) {
				if score >= beta && !inCheck && cachedMove.some() {
					game.saveGood(depth, cachedMove)
				}
				return score
			}
		}
	}

	if !inCheck {
		if depth < 1 {
			return p.searchQuiescence(alpha, beta, 0, inCheck)
		}
		if cached != nil {
			if p.score == Unknown {
				p.score = p.Evaluate()
			}
		} else {
			if isNull {
				p.score = rightToMove.midgame * 2 - tree[node-1].score
			} else {
				p.score = p.Evaluate()
			}
		}
	}

	// Razoring and futility margin pruning.
	if !inCheck && !isPrincipal {

		// No razoring if pawns are on 7th rank.
		if cachedMove.null() && depth < 3 && p.outposts[pawn(p.color)] & mask7th[p.color] == 0 {
			razoringMargin := func(depth int) int {
				return 96 + 64 * (depth - 1)
			}

		   	// Special case for razoring at low depths.
			if p.score <= alpha - razoringMargin(5) {
				return p.searchQuiescence(alpha, beta, 0, inCheck)
			}

			margin := alpha - razoringMargin(depth)
			if score := p.searchQuiescence(margin, margin + 1, 0, inCheck); score <= margin {
				return score
			}
		}

		// Futility pruning is only applicable if we don't have winning score
		// yet and there are pieces other than pawns.
		if !isNull && depth < 14 && !isMate(beta) &&
		   (p.outposts[p.color] & ^(p.outposts[king(p.color)] | p.outposts[pawn(p.color)])).any() {
			// Largest conceivable positional gain.
			if gain := p.score - 256 * depth; gain >= beta {
				return gain
			}
		}

		// Null move pruning.
		if !isNull && depth > 1 && p.outposts[p.color].count() > 5 {
			position := p.makeNullMove()
			game.nodes++
			nullScore := -position.searchTree(-beta, -beta + 1, depth - 1 - 3)
			position.undoLastMove()

			if nullScore >= beta {
				if isMate(nullScore) {
					return beta
				}
				return nullScore
			}
		}
	}

	// Internal iterative deepening.
	if !inCheck && cachedMove.null() && depth > 4 {
		newDepth := depth / 2
		if isPrincipal {
			newDepth = depth - 2
		}
		p.searchTree(alpha, beta, newDepth)
		if cached := p.probeCache(); cached != nil {
			cachedMove = cached.move
		}
	}

	gen := NewGen(p, ply)
	if inCheck {
		gen.generateEvasions().quickRank()
	} else {
		gen.generateMoves().rank(cachedMove)
	}

	bestScore := alpha
	bestMove, moveCount := Move(0), 0
	for move := gen.nextMove(); move.some(); move = gen.nextMove() {
		if !move.valid(p, gen.pins) {
			continue
		}

		position := p.makeMove(move)
		moveCount++; game.nodes++

		// Reduce search depth if we're not checking.
		giveCheck := position.isInCheck(position.color)
		newDepth := let(giveCheck && p.exchange(move) >= 0, depth, depth - 1)

		// Start search with full window.
		if isPrincipal && moveCount == 1 {
			score = -position.searchTree(-beta, -alpha, newDepth)
		} else {
			reduction := 0
			if !inCheck && !giveCheck && depth > 2 && move.isQuiet() && !move.isKiller(ply) && !move.isPawnAdvance() {
				reduction = lateMoveReductions[min(63, moveCount-1)][min(63, depth)]
				if isPrincipal {
					reduction /= 2
				} else if game.history[move.piece()][move.to()] < 0 {
					reduction++
				}
			}

			score = -position.searchTree(-alpha - 1, -alpha, max(0, newDepth - reduction))

			// Verify late move reduction and re-run the search if necessary.
			if reduction > 0 && score > alpha {
				score = -position.searchTree(-alpha - 1, -alpha, newDepth)
			}

			// If zero window failed try full window.
			if isPrincipal && score > alpha && score < beta {
				score = -position.searchTree(-beta, -alpha, newDepth)
			}
		}
		position.undoLastMove()

		// Don't touch anything if the time has elapsed and we need to abort th search.
		if engine.clock.halt {
			return alpha
		}

		if score > bestScore {
			bestScore = score
			if score > alpha {
				if isPrincipal {
					game.saveBest(ply, move)
				}
				if isPrincipal && score < beta {
					alpha = score
					bestMove = move
				} else {
					p.cache(move, score, depth, ply, cacheBeta)
					return score
				}
			}
		}
	}

	if moveCount == 0 {
		score = let(inCheck, matedIn(ply), 0)
	} else {
		score = bestScore
		if !inCheck {
			game.saveGood(depth, bestMove)
		}
	}

	cacheFlags := cacheAlpha
	if score >= beta {
		cacheFlags = cacheBeta
	} else if isPrincipal && bestMove.some() {
		cacheFlags = cacheExact
	}
	p.cache(bestMove, score, depth, ply, cacheFlags)

	return score
}
<|endoftext|>


<commit_before>package semver_test

import (
	"fmt"
	"testing"

	"github.com/hansrodtang/semver"
)

type comparison struct {
	main     *semver.Version
	other    *semver.Version
	expected int
}

var correctVersions = []string{
	"0.0.1-alpha.preview+123.456",
	"1.2.3-alpha.1+123.456",
	"1.2.3-alpha.1",
	"1.2.3+123.456",
	"1.2.3-alpha.b-eta+123.b-uild",
	"1.2.3+123.b-uild",
	"1.2.3-alpha.b-eta",
}

var badVersions = []string{
	"",
	".",
	"1.",
	".1",
	"a.b.c",
	"1.a.b",
	"1.1.a",
	"1.a.1",
	"a.1.1",
	"..",
	"1..",
	"1.1.",
	"1..1",
	"1.1.+123",
	"1.1.-beta",
	"-1.1.1",
	"1.-1.1",
	"1.1.-1",
	// Leading zeroes
	"01.1.1",
	"001.1.1",
	"1.01.1",
	"1.001.1",
	"1.1.01",
	"1.1.001",
	"1.1.1-01",
	"1.1.1-001",
	"1.1.1-beta.01",
	"1.1.1-beta.001",
	"0.0.0-!",
	"0.0.0+!",
	// empty prerelease
	"0.0.0-.alpha",
	// empty build metadata
	"0.0.0-alpha+",
	"0.0.0-alpha+test.",
}

var comparisons = []comparison{
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0), 0},
	{semver.Build(2, 0, 0), semver.Build(1, 0, 0), 1},
	{semver.Build(0, 1, 0), semver.Build(0, 1, 0), 0},
	{semver.Build(0, 2, 0), semver.Build(0, 1, 0), 1},
	{semver.Build(0, 0, 1), semver.Build(0, 0, 1), 0},
	{semver.Build(0, 0, 2), semver.Build(0, 0, 1), 1},
	{semver.Build(1, 2, 3), semver.Build(1, 2, 3), 0},
	{semver.Build(2, 2, 4), semver.Build(1, 2, 4), 1},
	{semver.Build(1, 3, 3), semver.Build(1, 2, 3), 1},
	{semver.Build(1, 2, 4), semver.Build(1, 2, 3), 1},

	// Spec Examples #11
	{semver.Build(1, 0, 0), semver.Build(2, 0, 0), -1},
	{semver.Build(2, 0, 0), semver.Build(2, 1, 0), -1},
	{semver.Build(2, 1, 0), semver.Build(2, 1, 1), -1},

	// Spec Examples #9
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0, []string{"alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"alpha"}), semver.Build(1, 0, 0, []string{"alpha", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "1"}), semver.Build(1, 0, 0, []string{"alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"alpha", "1"}), semver.Build(1, 0, 0, []string{"alpha", "beta"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "beta"}), semver.Build(1, 0, 0, []string{"beta"}), -1},
	{semver.Build(1, 0, 0, []string{"beta"}), semver.Build(1, 0, 0, []string{"beta", "2"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "2"}), semver.Build(1, 0, 0, []string{"beta", "11"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"beta", "2"}), 1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"rc", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "beta"}), semver.Build(1, 0, 0, []string{"beta", "alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0), -1},

	{semver.Build(1, 0, 0, []string{"beta", "alpha", "1"}), semver.Build(1, 0, 0, []string{"beta", "alpha"}), 1},

	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0, []string{"rc", "1"}, []string{"435345345"}), 0},
}

var badPreRelease = [][]string{
	{"alpha", "-3"},
}

func TestStringer(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	expected := "1.2.3-alpha.1+35.45"
	result := fmt.Sprint(ver)

	if result != expected {
		t.Errorf("String() => %q, wanted %q", result, expected)
	}
}

func TestGetters(t *testing.T) {
	expectedMajor := uint64(1)
	expectedMinor := uint64(2)
	expectedPatch := uint64(3)
	expectedPrerelease := "alpha.1"
	expectedMetadata := "35.45"

	ver := semver.Build(expectedMajor, expectedMinor, expectedPatch)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	if result := ver.Major(); result != expectedMajor {
		t.Errorf("%q.Major() => %q, wanted %q", ver, result, expectedMajor)
	}
	if result := ver.Minor(); result != expectedMinor {
		t.Errorf("%q.Minor() => %q, wanted %q", ver, result, expectedMinor)
	}
	if result := ver.Patch(); result != expectedPatch {
		t.Errorf("%q.Patch() => %q, wanted %q", ver, result, expectedPatch)
	}
	if result := ver.Prerelease(); result != expectedPrerelease {
		t.Errorf("%q.Prerelease() => %q, wanted %q", ver, result, expectedPrerelease)
	}
	if result := ver.Metadata(); result != expectedMetadata {
		t.Errorf("%q.Metadata() => %q, wanted %q", ver, result, expectedMetadata)
	}
}

func TestSetters(t *testing.T) {
	ver := semver.Build(1, 1, 1)
	ver.SetMajor(2)
	ver.SetMinor(3)
	ver.SetPatch(4)
	if err := ver.SetPrerelease("beta", "1"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}
	if err := ver.SetMetadata("22", "43"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	expected := "2.3.4-beta.1+22.43"
	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, wanted %q", result, expected)
	}
}

func TestNew(t *testing.T) {
	expected := "1.0.3-alpha.1+35.45"

	ver, err := semver.New(expected)
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, want %q", result, expected)
	}

}

func TestBadFormat(t *testing.T) {
	for _, version := range badVersions {
		_, err := semver.New(version)
		if err == nil {
			// TODO: Set up error types
			t.Errorf("New(%q) => %v, want Error", version, err)
		}

	}
}

func TestCorrectFormat(t *testing.T) {
	for _, version := range correctVersions {
		_, err := semver.New(version)
		if err != nil {
			t.Errorf("New(%q) => %v, want <nil>", version, err)
		}
	}
}

func TestComparison(t *testing.T) {
	for _, c := range comparisons {
		result := c.main.Compare(c.other)
		if result != c.expected {
			t.Errorf("%q.Compare(%q) => %#v, want %#v", c.main, c.other, result, c.expected)
		}
	}
}

func TestSetPrerelease(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	err := ver.SetPrerelease("12", "1", "0", "43")
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}
}

func BenchmarkParseSimple(b *testing.B) {
	const VERSION = "0.0.1"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkParseComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkCompareSimple(b *testing.B) {
	const VERSION = "0.0.1"
	v, _ := semver.New(VERSION)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v)
	}
}

func BenchmarkCompareComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	const VERSION2 = "0.0.1-alpha.preview+123.456"
	v, _ := semver.New(VERSION)
	v2, _ := semver.New(VERSION2)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v2)
	}
}
<commit_msg>Added Average benchmarks.<commit_after>package semver_test

import (
	"fmt"
	"testing"

	"github.com/hansrodtang/semver"
)

type comparison struct {
	main     *semver.Version
	other    *semver.Version
	expected int
}

var correctVersions = []string{
	"0.0.1-alpha.preview+123.456",
	"1.2.3-alpha.1+123.456",
	"1.2.3-alpha.1",
	"1.2.3+123.456",
	"1.2.3-alpha.b-eta+123.b-uild",
	"1.2.3+123.b-uild",
	"1.2.3-alpha.b-eta",
}

var badVersions = []string{
	"",
	".",
	"1.",
	".1",
	"a.b.c",
	"1.a.b",
	"1.1.a",
	"1.a.1",
	"a.1.1",
	"..",
	"1..",
	"1.1.",
	"1..1",
	"1.1.+123",
	"1.1.-beta",
	"-1.1.1",
	"1.-1.1",
	"1.1.-1",
	// Leading zeroes
	"01.1.1",
	"001.1.1",
	"1.01.1",
	"1.001.1",
	"1.1.01",
	"1.1.001",
	"1.1.1-01",
	"1.1.1-001",
	"1.1.1-beta.01",
	"1.1.1-beta.001",
	"0.0.0-!",
	"0.0.0+!",
	// empty prerelease
	"0.0.0-.alpha",
	// empty build metadata
	"0.0.0-alpha+",
	"0.0.0-alpha+test.",
}

var comparisons = []comparison{
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0), 0},
	{semver.Build(2, 0, 0), semver.Build(1, 0, 0), 1},
	{semver.Build(0, 1, 0), semver.Build(0, 1, 0), 0},
	{semver.Build(0, 2, 0), semver.Build(0, 1, 0), 1},
	{semver.Build(0, 0, 1), semver.Build(0, 0, 1), 0},
	{semver.Build(0, 0, 2), semver.Build(0, 0, 1), 1},
	{semver.Build(1, 2, 3), semver.Build(1, 2, 3), 0},
	{semver.Build(2, 2, 4), semver.Build(1, 2, 4), 1},
	{semver.Build(1, 3, 3), semver.Build(1, 2, 3), 1},
	{semver.Build(1, 2, 4), semver.Build(1, 2, 3), 1},

	// Spec Examples #11
	{semver.Build(1, 0, 0), semver.Build(2, 0, 0), -1},
	{semver.Build(2, 0, 0), semver.Build(2, 1, 0), -1},
	{semver.Build(2, 1, 0), semver.Build(2, 1, 1), -1},

	// Spec Examples #9
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0, []string{"alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"alpha"}), semver.Build(1, 0, 0, []string{"alpha", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "1"}), semver.Build(1, 0, 0, []string{"alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"alpha", "1"}), semver.Build(1, 0, 0, []string{"alpha", "beta"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "beta"}), semver.Build(1, 0, 0, []string{"beta"}), -1},
	{semver.Build(1, 0, 0, []string{"beta"}), semver.Build(1, 0, 0, []string{"beta", "2"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "2"}), semver.Build(1, 0, 0, []string{"beta", "11"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"beta", "2"}), 1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"rc", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "beta"}), semver.Build(1, 0, 0, []string{"beta", "alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0), -1},

	{semver.Build(1, 0, 0, []string{"beta", "alpha", "1"}), semver.Build(1, 0, 0, []string{"beta", "alpha"}), 1},

	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0, []string{"rc", "1"}, []string{"435345345"}), 0},
}

var badPreRelease = [][]string{
	{"alpha", "-3"},
}

func TestStringer(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	expected := "1.2.3-alpha.1+35.45"
	result := fmt.Sprint(ver)

	if result != expected {
		t.Errorf("String() => %q, wanted %q", result, expected)
	}
}

func TestGetters(t *testing.T) {
	expectedMajor := uint64(1)
	expectedMinor := uint64(2)
	expectedPatch := uint64(3)
	expectedPrerelease := "alpha.1"
	expectedMetadata := "35.45"

	ver := semver.Build(expectedMajor, expectedMinor, expectedPatch)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	if result := ver.Major(); result != expectedMajor {
		t.Errorf("%q.Major() => %q, wanted %q", ver, result, expectedMajor)
	}
	if result := ver.Minor(); result != expectedMinor {
		t.Errorf("%q.Minor() => %q, wanted %q", ver, result, expectedMinor)
	}
	if result := ver.Patch(); result != expectedPatch {
		t.Errorf("%q.Patch() => %q, wanted %q", ver, result, expectedPatch)
	}
	if result := ver.Prerelease(); result != expectedPrerelease {
		t.Errorf("%q.Prerelease() => %q, wanted %q", ver, result, expectedPrerelease)
	}
	if result := ver.Metadata(); result != expectedMetadata {
		t.Errorf("%q.Metadata() => %q, wanted %q", ver, result, expectedMetadata)
	}
}

func TestSetters(t *testing.T) {
	ver := semver.Build(1, 1, 1)
	ver.SetMajor(2)
	ver.SetMinor(3)
	ver.SetPatch(4)
	if err := ver.SetPrerelease("beta", "1"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}
	if err := ver.SetMetadata("22", "43"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	expected := "2.3.4-beta.1+22.43"
	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, wanted %q", result, expected)
	}
}

func TestNew(t *testing.T) {
	expected := "1.0.3-alpha.1+35.45"

	ver, err := semver.New(expected)
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, want %q", result, expected)
	}

}

func TestBadFormat(t *testing.T) {
	for _, version := range badVersions {
		_, err := semver.New(version)
		if err == nil {
			// TODO: Set up error types
			t.Errorf("New(%q) => %v, want Error", version, err)
		}

	}
}

func TestCorrectFormat(t *testing.T) {
	for _, version := range correctVersions {
		_, err := semver.New(version)
		if err != nil {
			t.Errorf("New(%q) => %v, want <nil>", version, err)
		}
	}
}

func TestComparison(t *testing.T) {
	for _, c := range comparisons {
		result := c.main.Compare(c.other)
		if result != c.expected {
			t.Errorf("%q.Compare(%q) => %#v, want %#v", c.main, c.other, result, c.expected)
		}
	}
}

func TestSetPrerelease(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	err := ver.SetPrerelease("12", "1", "0", "43")
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}
}

func BenchmarkParseSimple(b *testing.B) {
	const VERSION = "0.0.1"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkParseComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkParseAverage(b *testing.B) {
	l := len(correctVersions)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(correctVersions[n%l])
	}
}

func BenchmarkCompareSimple(b *testing.B) {
	const VERSION = "0.0.1"
	v, _ := semver.New(VERSION)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v)
	}
}

func BenchmarkCompareComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	const VERSION2 = "0.0.1-alpha.preview+123.456"
	v, _ := semver.New(VERSION)
	v2, _ := semver.New(VERSION2)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v2)
	}
}

func BenchmarkCompareAverage(b *testing.B) {
	l := len(comparisons)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		comparisons[n%l].main.Compare(comparisons[n%l].other)
	}
}
<|endoftext|>


<commit_before>package kasper

import (
	"testing"
	"reflect"
	"github.com/Shopify/sarama"
)

func TestSender_Send_OneMessage(t *testing.T) {
	pp := &partitionProcessor{
		topicProcessor: &TopicProcessor{
			config: &TopicProcessorConfig{
				TopicSerdes: map[Topic]TopicSerde{
					"hello": {
						KeySerde:   NewStringSerde(),
						ValueSerde: NewStringSerde(),
					},
				},
			},
		},
	}
	in := &IncomingMessage{}
	sender := newSender(pp, in)
	out := OutgoingMessage{
		Topic:     "hello",
		Partition: 6,
		Key:       "AAA",
		Value:     "BBB",
	}
	sender.Send(out)
	if len(sender.producerMessages) != 1 {
		t.Fail()
	}
	expected := &sarama.ProducerMessage{
		Topic:     "hello",
		Key:       sarama.ByteEncoder([]byte{65, 65, 65}),
		Value:     sarama.ByteEncoder([]byte{66, 66, 66}),
		Partition: 6,
		Metadata:  in,
	}
	actual := sender.producerMessages[0]
	if ! reflect.DeepEqual(actual, expected) {
		t.Error(actual)
	}
}<commit_msg>More tests on sender<commit_after>package kasper

import (
	"testing"
	"reflect"
	"github.com/Shopify/sarama"
)

type fixture struct {
	pp *partitionProcessor
	in *IncomingMessage
}

func newFixture() *fixture {
	return &fixture{
		&partitionProcessor{
			topicProcessor: &TopicProcessor{
				config: &TopicProcessorConfig{
					TopicSerdes: map[Topic]TopicSerde{
						"hello": {
							KeySerde:   NewStringSerde(),
							ValueSerde: NewStringSerde(),
						},
					},
				},
			},
		},
		&IncomingMessage{},
	}
}

func TestSender_Send_OneMessage(t *testing.T) {
	f := newFixture()
	sender := newSender(f.pp, f.in)
	out := OutgoingMessage{
		Topic:     "hello",
		Partition: 6,
		Key:       "AAA",
		Value:     "BBB",
	}
	sender.Send(out)
	if len(sender.producerMessages) != 1 {
		t.Errorf("Expected 1 message but got %d", len(sender.producerMessages))
	}
	expected := &sarama.ProducerMessage{
		Topic:     "hello",
		Key:       sarama.ByteEncoder([]byte{65, 65, 65}),
		Value:     sarama.ByteEncoder([]byte{66, 66, 66}),
		Partition: 6,
		Metadata:  f.in,
	}
	actual := sender.producerMessages[0]
	if ! reflect.DeepEqual(actual, expected) {
		t.Errorf("Mismatch: %v != %v", actual, expected)
	}
}

func TestSender_Send_TwoMessages(t *testing.T) {
	f := newFixture()
	sender := newSender(f.pp, f.in)
	sender.Send(OutgoingMessage{
		Topic:     "hello",
		Partition: 6,
		Key:       "AAA",
		Value:     "BBB",
	})
	sender.Send(OutgoingMessage{
		Topic:     "hello",
		Partition: 7,
		Key:       "CCC",
		Value:     "DDD",
	})
	if len(sender.producerMessages) != 2 {
		t.Fail()
	}
	expected := []*sarama.ProducerMessage {
		{
			Topic:     "hello",
			Key:       sarama.ByteEncoder([]byte{65, 65, 65}),
			Value:     sarama.ByteEncoder([]byte{66, 66, 66}),
			Partition: 6,
			Metadata:  f.in,
		},
		{
			Topic:     "hello",
			Key:       sarama.ByteEncoder([]byte{67, 67, 67}),
			Value:     sarama.ByteEncoder([]byte{68, 68, 68}),
			Partition: 7,
			Metadata:  f.in,
		},
	}
	actual := sender.producerMessages
	if ! reflect.DeepEqual(actual, expected) {
		t.Errorf("Mismatch: %#v != %#v", actual, expected)
	}
}
<|endoftext|>


<commit_before>/*
    MP3Cat is a fast command line utility for concatenating MP3 files
    without re-encoding. It supports both constant bit rate (CBR) and
    variable bit rate (VBR) files.
*/
package main

import (
    "fmt"
    "io"
    "os"
    "path"
    "path/filepath"
    "golang.org/x/crypto/ssh/terminal"
    "github.com/dmulholland/mp3lib"
    "github.com/dmulholland/clio/go/clio"
)

const version = "2.5.0"

var helptext = fmt.Sprintf(`
Usage: %s [FLAGS] [OPTIONS] [ARGUMENTS]

  This tool concatenates MP3 files without re-encoding. It supports both
  constant bit rate (CBR) and variable bit rate (VBR) MP3 files.

  Files to be merged can be specified as a list of filenames:

    $ mp3cat one.mp3 two.mp3 three.mp3

  Alternatively, an entire directory of .mp3 files can be merged:

    $ mp3cat --dir /path/to/directory/

Arguments:
  [files]                 List of files to merge.

Options:
  -d, --dir <path>        Directory of files to merge.
  -i, --interlace <path>  Interlace a spacer file between each input file.
  -o, --out <path>        Output filename. Defaults to 'output.mp3'.

Flags:
  -f, --force             Overwrite an existing output file.
      --help              Display this help text and exit.
  -t, --tag               Copy the ID3 tag from the first input file.
  -v, --verbose           Report progress.
      --version           Display the application's version number and exit.
`, filepath.Base(os.Args[0]))

func main() {

    // Parse the command line arguments.
    parser := clio.NewParser(helptext, version)
    parser.AddFlag("force f")
    parser.AddFlag("verbose v")
    parser.AddFlag("debug")
    parser.AddFlag("tag t")
    parser.AddStr("out o", "output.mp3")
    parser.AddStr("dir d", "")
    parser.AddStr("interlace i", "")
    parser.Parse()

    // Make sure we have a list of files to merge.
    var files []string
    if parser.Found("dir") {
        globs, err := filepath.Glob(path.Join(parser.GetStr("dir"), "*.mp3"))
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
        if globs == nil || len(globs) == 0 {
            fmt.Fprintln(os.Stderr, "Error: no files found.")
            os.Exit(1)
        }
        files = globs
    } else if parser.HasArgs() {
        files = parser.GetArgs()
    } else {
        fmt.Fprintln(os.Stderr, "Error: you must specify files to merge.")
        os.Exit(1)
    }

    // Are we interlacing a spacer file?
    if parser.Found("interlace") {
        files = interlace(files, parser.GetStr("interlace"))
    }

    // Make sure all the files in the list actually exist.
    validateFiles(files)

    // Set debug mode if the user supplied a --debug flag.
    if parser.GetFlag("debug") {
        mp3lib.DebugMode = true
    }

    // Merge the input files.
    merge(
        parser.GetStr("out"),
        files,
        parser.GetFlag("force"),
        parser.GetFlag("verbose"),
        parser.GetFlag("tag"))
}

// Check that all the files in the list exist.
func validateFiles(files []string) {
    for _, file := range files {
        if _, err := os.Stat(file); err != nil {
            fmt.Fprintf(
                os.Stderr,
                "Error: the file '%v' does not exist.\n", file)
            os.Exit(1)
        }
    }
}

// Interlace a spacer file between each file in the list.
func interlace(files []string, spacer string) []string {
    var interlaced []string
    for _, file := range files {
        interlaced = append(interlaced, file)
        interlaced = append(interlaced, spacer)
    }
    return interlaced[:len(interlaced) - 1]
}

// Create a new file at the specified output path containing the merged
// contents of the list of input files.
func merge(outpath string, inpaths []string, force, verbose, tag bool) {

    var totalFrames uint32
    var totalBytes uint32
    var totalFiles int
    var firstBitRate int
    var isVBR bool

    // Only overwrite an existing file if the --force flag has been used.
    if _, err := os.Stat(outpath); err == nil {
        if !force {
            fmt.Fprintf(
                os.Stderr,
                "Error: the file '%v' already exists.\n", outpath)
            os.Exit(1)
        }
    }

    // If the list of input files includes the output file we'll end up in an
    // infinite loop.
    for _, filepath := range inpaths {
        if filepath == outpath {
            fmt.Fprintln(
                os.Stderr,
                "Error: the list of input files includes the output file.")
            os.Exit(1)
        }
    }

    // Create the output file.
    outfile, err := os.Create(outpath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    if verbose {
        line()
    }

    // Loop over the input files and append their MP3 frames to the output
    // file.
    for _, inpath := range inpaths {

        if verbose {
            fmt.Println("+", inpath)
        }

        infile, err := os.Open(inpath)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        isFirstFrame := true

        for {

            // Read the next frame from the input file.
            frame := mp3lib.NextFrame(infile)
            if frame == nil {
                break
            }

            // Skip the first frame if it's a VBR header.
            if isFirstFrame {
                isFirstFrame = false
                if mp3lib.IsXingHeader(frame) || mp3lib.IsVbriHeader(frame) {
                    continue
                }
            }

            // If we detect more than one bitrate we'll need to add a VBR
            // header to the output file.
            if firstBitRate == 0 {
                firstBitRate = frame.BitRate
            } else if frame.BitRate != firstBitRate {
                isVBR = true
            }

            // Write the frame to the output file.
            _, err := outfile.Write(frame.RawBytes)
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            totalFrames += 1
            totalBytes += uint32(len(frame.RawBytes))
        }

        infile.Close()
        totalFiles += 1
    }

    outfile.Close()
    if verbose {
        line()
    }

    // If we detected multiple bitrates, prepend a VBR header to the file.
    if isVBR {
        if verbose {
            fmt.Println("• Multiple bitrates detected. Adding VBR header.")
        }
        addXingHeader(outpath, totalFrames, totalBytes)
    }

    // Copy the ID3v2 tag from the first input file if requested. Order of
    // operations is important here. The ID3 tag must be the first item in
    // the file - in particular, it must come *before* any VBR header.
    if tag {
        if verbose {
            fmt.Println("• Adding ID3 tag.")
        }
        addID3v2Tag(outpath, inpaths[0])
    }

    // Print a count of the number of files merged.
    if verbose {
        fmt.Printf("• %v files merged.\n", totalFiles)
        line()
    }
}

// Prepend an Xing VBR header to the specified MP3 file.
func addXingHeader(filepath string, totalFrames, totalBytes uint32) {

    outputFile, err := os.Create(filepath + ".mp3cat.tmp")
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    inputFile, err := os.Open(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    templateFrame := mp3lib.NextFrame(inputFile)
    inputFile.Seek(0, 0)

    xingHeader := mp3lib.NewXingHeader(templateFrame, totalFrames, totalBytes)

    _, err = outputFile.Write(xingHeader.RawBytes)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    _, err = io.Copy(outputFile, inputFile)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    outputFile.Close()
    inputFile.Close()

    err = os.Remove(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    err = os.Rename(filepath + ".mp3cat.tmp", filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

// Prepend an ID3v2 tag to the MP3 file at mp3Path, copying from tagPath.
func addID3v2Tag(mp3Path, tagPath string) {

    tagFile, err := os.Open(tagPath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    id3tag := mp3lib.NextID3v2Tag(tagFile)
    tagFile.Close()

    if id3tag != nil {
        outputFile, err := os.Create(mp3Path + ".mp3cat.tmp")
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        inputFile, err := os.Open(mp3Path)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        _, err = outputFile.Write(id3tag.RawBytes)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        _, err = io.Copy(outputFile, inputFile)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        outputFile.Close()
        inputFile.Close()

        err = os.Remove(mp3Path)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        err = os.Rename(mp3Path + ".mp3cat.tmp", mp3Path)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
    }
}

// Print a line to stdout if we're running in a terminal.
func line() {
    if terminal.IsTerminal(int(os.Stdout.Fd())) {
        width, _, err := terminal.GetSize(int(os.Stdout.Fd()))
        if err == nil {
            for i := 0; i < width; i++ {
                fmt.Print("─")
            }
            fmt.Println()
        }
    }
}
<commit_msg>Update Clio dependency to 3.0.0<commit_after>/*
    MP3Cat is a fast command line utility for concatenating MP3 files
    without re-encoding. It supports both constant bit rate (CBR) and
    variable bit rate (VBR) files.
*/
package main

import (
    "fmt"
    "io"
    "os"
    "path"
    "path/filepath"
    "golang.org/x/crypto/ssh/terminal"
    "github.com/dmulholland/mp3lib"
    "github.com/dmulholland/clio/go/clio"
)

const version = "2.5.1"

var helptext = fmt.Sprintf(`
Usage: %s [FLAGS] [OPTIONS] [ARGUMENTS]

  This tool concatenates MP3 files without re-encoding. It supports both
  constant bit rate (CBR) and variable bit rate (VBR) MP3 files.

  Files to be merged can be specified as a list of filenames:

    $ mp3cat one.mp3 two.mp3 three.mp3

  Alternatively, an entire directory of .mp3 files can be merged:

    $ mp3cat --dir /path/to/directory/

Arguments:
  [files]                 List of files to merge.

Options:
  -d, --dir <path>        Directory of files to merge.
  -i, --interlace <path>  Interlace a spacer file between each input file.
  -o, --out <path>        Output filename. Defaults to 'output.mp3'.

Flags:
  -f, --force             Overwrite an existing output file.
      --help              Display this help text and exit.
  -t, --tag               Copy the ID3 tag from the first input file.
  -v, --verbose           Report progress.
      --version           Display the application's version number and exit.
`, filepath.Base(os.Args[0]))

func main() {

    // Parse the command line arguments.
    parser := clio.NewParser(helptext, version)
    parser.NewFlag("force f")
    parser.NewFlag("verbose v")
    parser.NewFlag("debug")
    parser.NewFlag("tag t")
    parser.NewStr("out o", "output.mp3")
    parser.NewStr("dir d", "")
    parser.NewStr("interlace i", "")
    parser.Parse()

    // Make sure we have a list of files to merge.
    var files []string
    if parser.Found("dir") {
        globs, err := filepath.Glob(path.Join(parser.GetStr("dir"), "*.mp3"))
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
        if globs == nil || len(globs) == 0 {
            fmt.Fprintln(os.Stderr, "Error: no files found.")
            os.Exit(1)
        }
        files = globs
    } else if parser.HasArgs() {
        files = parser.GetArgs()
    } else {
        fmt.Fprintln(os.Stderr, "Error: you must specify files to merge.")
        os.Exit(1)
    }

    // Are we interlacing a spacer file?
    if parser.Found("interlace") {
        files = interlace(files, parser.GetStr("interlace"))
    }

    // Make sure all the files in the list actually exist.
    validateFiles(files)

    // Set debug mode if the user supplied a --debug flag.
    if parser.GetFlag("debug") {
        mp3lib.DebugMode = true
    }

    // Merge the input files.
    merge(
        parser.GetStr("out"),
        files,
        parser.GetFlag("force"),
        parser.GetFlag("verbose"),
        parser.GetFlag("tag"))
}

// Check that all the files in the list exist.
func validateFiles(files []string) {
    for _, file := range files {
        if _, err := os.Stat(file); err != nil {
            fmt.Fprintf(
                os.Stderr,
                "Error: the file '%v' does not exist.\n", file)
            os.Exit(1)
        }
    }
}

// Interlace a spacer file between each file in the list.
func interlace(files []string, spacer string) []string {
    var interlaced []string
    for _, file := range files {
        interlaced = append(interlaced, file)
        interlaced = append(interlaced, spacer)
    }
    return interlaced[:len(interlaced) - 1]
}

// Create a new file at the specified output path containing the merged
// contents of the list of input files.
func merge(outpath string, inpaths []string, force, verbose, tag bool) {

    var totalFrames uint32
    var totalBytes uint32
    var totalFiles int
    var firstBitRate int
    var isVBR bool

    // Only overwrite an existing file if the --force flag has been used.
    if _, err := os.Stat(outpath); err == nil {
        if !force {
            fmt.Fprintf(
                os.Stderr,
                "Error: the file '%v' already exists.\n", outpath)
            os.Exit(1)
        }
    }

    // If the list of input files includes the output file we'll end up in an
    // infinite loop.
    for _, filepath := range inpaths {
        if filepath == outpath {
            fmt.Fprintln(
                os.Stderr,
                "Error: the list of input files includes the output file.")
            os.Exit(1)
        }
    }

    // Create the output file.
    outfile, err := os.Create(outpath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    if verbose {
        line()
    }

    // Loop over the input files and append their MP3 frames to the output
    // file.
    for _, inpath := range inpaths {

        if verbose {
            fmt.Println("+", inpath)
        }

        infile, err := os.Open(inpath)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        isFirstFrame := true

        for {

            // Read the next frame from the input file.
            frame := mp3lib.NextFrame(infile)
            if frame == nil {
                break
            }

            // Skip the first frame if it's a VBR header.
            if isFirstFrame {
                isFirstFrame = false
                if mp3lib.IsXingHeader(frame) || mp3lib.IsVbriHeader(frame) {
                    continue
                }
            }

            // If we detect more than one bitrate we'll need to add a VBR
            // header to the output file.
            if firstBitRate == 0 {
                firstBitRate = frame.BitRate
            } else if frame.BitRate != firstBitRate {
                isVBR = true
            }

            // Write the frame to the output file.
            _, err := outfile.Write(frame.RawBytes)
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            totalFrames += 1
            totalBytes += uint32(len(frame.RawBytes))
        }

        infile.Close()
        totalFiles += 1
    }

    outfile.Close()
    if verbose {
        line()
    }

    // If we detected multiple bitrates, prepend a VBR header to the file.
    if isVBR {
        if verbose {
            fmt.Println("• Multiple bitrates detected. Adding VBR header.")
        }
        addXingHeader(outpath, totalFrames, totalBytes)
    }

    // Copy the ID3v2 tag from the first input file if requested. Order of
    // operations is important here. The ID3 tag must be the first item in
    // the file - in particular, it must come *before* any VBR header.
    if tag {
        if verbose {
            fmt.Println("• Adding ID3 tag.")
        }
        addID3v2Tag(outpath, inpaths[0])
    }

    // Print a count of the number of files merged.
    if verbose {
        fmt.Printf("• %v files merged.\n", totalFiles)
        line()
    }
}

// Prepend an Xing VBR header to the specified MP3 file.
func addXingHeader(filepath string, totalFrames, totalBytes uint32) {

    outputFile, err := os.Create(filepath + ".mp3cat.tmp")
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    inputFile, err := os.Open(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    templateFrame := mp3lib.NextFrame(inputFile)
    inputFile.Seek(0, 0)

    xingHeader := mp3lib.NewXingHeader(templateFrame, totalFrames, totalBytes)

    _, err = outputFile.Write(xingHeader.RawBytes)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    _, err = io.Copy(outputFile, inputFile)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    outputFile.Close()
    inputFile.Close()

    err = os.Remove(filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    err = os.Rename(filepath + ".mp3cat.tmp", filepath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

// Prepend an ID3v2 tag to the MP3 file at mp3Path, copying from tagPath.
func addID3v2Tag(mp3Path, tagPath string) {

    tagFile, err := os.Open(tagPath)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    id3tag := mp3lib.NextID3v2Tag(tagFile)
    tagFile.Close()

    if id3tag != nil {
        outputFile, err := os.Create(mp3Path + ".mp3cat.tmp")
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        inputFile, err := os.Open(mp3Path)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        _, err = outputFile.Write(id3tag.RawBytes)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        _, err = io.Copy(outputFile, inputFile)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        outputFile.Close()
        inputFile.Close()

        err = os.Remove(mp3Path)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }

        err = os.Rename(mp3Path + ".mp3cat.tmp", mp3Path)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
    }
}

// Print a line to stdout if we're running in a terminal.
func line() {
    if terminal.IsTerminal(int(os.Stdout.Fd())) {
        width, _, err := terminal.GetSize(int(os.Stdout.Fd()))
        if err == nil {
            for i := 0; i < width; i++ {
                fmt.Print("─")
            }
            fmt.Println()
        }
    }
}
<|endoftext|>