<commit_before>package tumblr

import (
	"github.com/google/go-querystring/query"
	"path"
)

// Search criteria to be passed to the Posts method
type PostRequestParams struct {
	PostType   string `url:"-"`
	Id         int64  `url:"id,omitempty"`
	Tag        string `url:"tag,omitempty"`
	ReblogInfo bool   `url:"reblog_info,omitempty"`
	NotesInfo  bool   `url:"notes_info,omitempty"`
	Filter     string `url:"filter,omitempty"`
	LimitOffset
}

func (params PostRequestParams) validatePostRequestParams() error {
	if params.Limit < 0 || params.Limit > 20 {
		return TumblrError{"Post request parameter limit out of range"}
	}
	if params.Filter != "" &&
		!(params.Filter == "html" || params.Filter == "raw") {
		return TumblrError{`Filter, if specified, must be either "html" or "raw"`}
	}
	return nil
}

// Posts posted by a blog
func (blog *Blog) Posts(params PostRequestParams) (*PostCollection, error) {
	// Build URL
	url, err := blog.blogEntityURL("posts")
	if err != nil {
		return nil, err
	}

	// PostType fits in the path rather than the query string
	if params.PostType != "" {
		url.Path = path.Join(url.Path, params.PostType)
	}

	// TODO factor this out somewhere nice
	orig := url.Query()
	v, _ := query.Values(params)
	for key, val := range v {
		orig.Set(key, val[0])
	}
	url.RawQuery = orig.Encode()
	addLimitOffset(url, params.LimitOffset)

	data, err := callAPI(url)
	if err != nil {
		return nil, err
	}

	pc, err := NewPostCollection(data)
	return pc, err
}
<commit_msg>Do partial JSON deserialization<commit_after>package tumblr

import (
	"github.com/google/go-querystring/query"
	"encoding/json"
	"path"
)

// Search criteria to be passed to the Posts method
type PostRequestParams struct {
	PostType   string `url:"-"`
	Id         int64  `url:"id,omitempty"`
	Tag        string `url:"tag,omitempty"`
	ReblogInfo bool   `url:"reblog_info,omitempty"`
	NotesInfo  bool   `url:"notes_info,omitempty"`
	Filter     string `url:"filter,omitempty"`
	LimitOffset
}

func (params PostRequestParams) validatePostRequestParams() error {
	if params.Limit < 0 || params.Limit > 20 {
		return TumblrError{"Post request parameter limit out of range"}
	}
	if params.Filter != "" &&
		!(params.Filter == "html" || params.Filter == "raw") {
		return TumblrError{`Filter, if specified, must be either "html" or "raw"`}
	}
	return nil
}

// Posts posted by a blog
func (blog *Blog) Posts(params PostRequestParams) (*PostCollection, error) {
	// Build URL
	url, err := blog.blogEntityURL("posts")
	if err != nil {
		return nil, err
	}

	// PostType fits in the path rather than the query string
	if params.PostType != "" {
		url.Path = path.Join(url.Path, params.PostType)
	}

	// TODO factor this out somewhere nice
	orig := url.Query()
	v, _ := query.Values(params)
	for key, val := range v {
		orig.Set(key, val[0])
	}
	url.RawQuery = orig.Encode()
	addLimitOffset(url, params.LimitOffset)

	res, err := callAPI(url)
	if err != nil {
		return nil, err
	}

	// Decode the response without decoding the posts
	dr := &blogPostsResponse{}
	err = json.Unmarshal(*res, &dr)
	if err != nil {
		return nil, err
	}

	// Create the typed post collection
	pc, err := NewPostCollection(dr.Posts)
	return pc, err
}

type blogPostsResponse struct {
	Posts *json.RawMessage
	Total_Posts int64
}
<|endoftext|>


<commit_before>package widgets

import (
	"fmt"
	"github.com/heysquirrel/tribe/blame/model"
	"github.com/jroimartin/gocui"
)

type SourceCodeView struct {
	name  string
	blame *model.Blame
	gui   *gocui.Gui
}

func NewSourceCodeView(gui *gocui.Gui, blame *model.Blame) *SourceCodeView {
	s := new(SourceCodeView)
	s.name = "source"
	s.gui = gui
	s.blame = blame

	return s
}

func (s *SourceCodeView) Layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()

	x1 := int(0.0 * float64(maxX))
	y1 := int(0.0 * float64(maxY))
	x2 := int(0.5*float64(maxX)) - 1
	y2 := int(0.5*float64(maxY)) - 1

	v, err := g.SetView(s.name, x1, y1, x2, y2)
	if err != gocui.ErrUnknownView {
		return err
	}

	v.Title = "Source"
	v.Highlight = true
	v.SelBgColor = gocui.ColorCyan
	v.SelFgColor = gocui.ColorBlack

	_, err = g.SetCurrentView(s.name)
	if err != nil {
		return err
	}

	for _, line := range s.blame.Lines {
		fmt.Fprintf(v, "%4d| %s\n", line.Number, line.Text)
	}

	return nil
}
<commit_msg>Added cursor movement on the SourceCodeView<commit_after>package widgets

import (
	"fmt"
	"github.com/heysquirrel/tribe/blame/model"
	"github.com/jroimartin/gocui"
	"log"
)

type SourceCodeView struct {
	name        string
	blame       *model.Blame
	gui         *gocui.Gui
	currentLine int
}

func NewSourceCodeView(gui *gocui.Gui, blame *model.Blame) *SourceCodeView {
	s := new(SourceCodeView)
	s.name = "source"
	s.gui = gui
	s.blame = blame
	s.currentLine = 0

	return s
}

func (c *SourceCodeView) SetSelected(index int) {
	c.currentLine = index

	c.gui.Update(func(g *gocui.Gui) error {
		v, err := g.View(c.name)
		if err != nil {
			return err
		}

		err = v.SetCursor(0, index)
		if err != nil {
			log.Panic(err)
		}

		return nil
	})
}

func (s *SourceCodeView) Next() {
	if s.currentLine < len(s.blame.Lines)-1 {
		s.SetSelected(s.currentLine + 1)
	} else {
		s.SetSelected(0)
	}
}

func (s *SourceCodeView) Previous() {
	if s.currentLine > 0 {
		s.SetSelected(s.currentLine - 1)
	} else {
		s.SetSelected(len(s.blame.Lines) - 1)
	}
}

func (s *SourceCodeView) Layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()

	x1 := int(0.0 * float64(maxX))
	y1 := int(0.0 * float64(maxY))
	x2 := int(0.5*float64(maxX)) - 1
	y2 := int(0.5*float64(maxY)) - 1

	v, err := g.SetView(s.name, x1, y1, x2, y2)
	if err != gocui.ErrUnknownView {
		return err
	}

	v.Title = "Source"
	v.Highlight = true
	v.SelBgColor = gocui.ColorCyan
	v.SelFgColor = gocui.ColorBlack

	_, err = g.SetCurrentView(s.name)
	if err != nil {
		return err
	}

	for _, line := range s.blame.Lines {
		fmt.Fprintf(v, "%4d| %s\n", line.Number, line.Text)
	}

	return s.setKeyBindings()
}

func (s *SourceCodeView) setKeyBindings() error {
	next := func(g *gocui.Gui, v *gocui.View) error { s.Next(); return nil }
	previous := func(g *gocui.Gui, v *gocui.View) error { s.Previous(); return nil }

	err := s.gui.SetKeybinding(s.name, gocui.KeyArrowDown, gocui.ModNone, next)
	if err != nil {
		return err
	}

	err = s.gui.SetKeybinding(s.name, gocui.KeyArrowUp, gocui.ModNone, previous)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package yum

import (
	"compress/zlib"
	"encoding/xml"
	"io"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gonuts/logger"
)

// RepositoryXMLBackend is a Backend querying YUM XML repositories
type RepositoryXMLBackend struct {
	Name       string
	Packages   map[string][]*Package
	Provides   map[string][]*Provides
	DBName     string
	Primary    string
	Repository *Repository
	msg        *logger.Logger
}

func NewRepositoryXMLBackend(repo *Repository) (Backend, error) {
	const dbname = "primary.xml.gz"
	return &RepositoryXMLBackend{
		Name:       "RepositoryXMLBackend",
		Packages:   make(map[string][]*Package),
		Provides:   make(map[string][]*Provides),
		DBName:     dbname,
		Primary:    filepath.Join(repo.CacheDir, dbname),
		Repository: repo,
		msg:        repo.msg,
	}, nil
}

// YumDataType returns the ID for the data type as used in the repomd.xml file
func (repo *RepositoryXMLBackend) YumDataType() string {
	return "primary"
}

// Download the DB from server
func (repo *RepositoryXMLBackend) GetLatestDB(url string) error {
	var err error
	out, err := os.Create(repo.Primary)
	if err != nil {
		return err
	}
	defer out.Close()

	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	_, err = io.Copy(out, resp.Body)
	return err
}

// Check whether the DB is there
func (repo *RepositoryXMLBackend) HasDB() bool {
	return path_exists(repo.Primary)
}

// Load loads the DB
func (repo *RepositoryXMLBackend) LoadDB() error {
	var err error

	repo.msg.Debugf("start parsing metadata XML file...\n")
	type xmlTree struct {
		XMLName  xml.Name `xml:"metadata"`
		Packages []struct {
			Type string `xml:"type,attr"`
			Name string `xml:"name"`
			Arch string `xml:"arch"`

			Version struct {
				Epoch   int    `xml:"epoch,attr"`
				Version string `xml:"ver,attr"`
				Release int    `xml:"rel,attr"`
			} `xml:"version"`

			Checksum struct {
				Value string `xml:",innerxml"`
				Type  string `xml:"type,attr"`
				PkgId string `xml:"pkgid,attr"`
			} `xml:"checksum"`

			Summary  string `xml:"summary"`
			Descr    string `xml:"description"`
			Packager string `xml:"packager"`
			Url      string `xml:"url"`

			Time struct {
				File  string `xml:"file,attr"`
				Build string `xml:"build,attr"`
			} `xml:"time"`

			Size struct {
				Package   int64 `xml:"package,attr"`
				Installed int64 `xml:"installed,attr"`
				Archive   int64 `xml:"archive,attr"`
			} `xml:"size"`

			Location struct {
				Href string `xml:"href,attr"`
			} `xml:"location"`

			Format struct {
				License   string `xml:"rpm:license"`
				Vendor    string `xml:"rpm:vendor"`
				Group     string `xml:"rpm:group"`
				BuildHost string `xml:"rpm:buildhost"`
				SourceRpm string `xml:"rpm:sourcerpm"`

				HeaderRange struct {
					Beg int64 `xml:"start,attr"`
					End int64 `xml:"end,attr"`
				} `xml:"rpm:header-range"`

				Provides []struct {
					Name    string `xml:"name,attr"`
					Flags   string `xml:"flags,attr"`
					Epoch   int    `xml:"epoch,attr"`
					Version string `xml:"ver,attr"`
					Release int    `xml:"rel,attr"`
				} `xml:"rpm-provides"`

				Requires []struct {
					Name    string `xml:"name,attr"`
					Flags   string `xml:"flags,attr"`
					Epoch   int    `xml:"epoch,attr"`
					Version string `xml:"ver,attr"`
					Release int    `xml:"rel,attr"`
					Pre     string `xml:"pre,attr"`
				} `xml:"rpm-requires"`
			} `xml:"format"`
		} `xml:"package"`
	}

	// load the yum XML package list
	f, err := os.Open(repo.Primary)
	if err != nil {
		return err
	}
	defer f.Close()

	r, err := zlib.NewReader(f)
	if err != nil {
		repo.msg.Errorf("zip failed to open [%s]: %v\n", repo.Primary, err)
		return err
	}
	defer r.Close()

	var tree xmlTree
	err = xml.NewDecoder(r).Decode(&tree)
	if err != nil {
		return err
	}

	for _, xml := range tree.Packages {
		pkg := NewPackage(xml.Name, xml.Version.Version, xml.Version.Release, xml.Version.Epoch)
		pkg.arch = xml.Arch
		pkg.group = xml.Format.Group
		pkg.location = xml.Location.Href
		for _, v := range xml.Format.Provides {
			prov := NewProvides(
				v.Name,
				v.Version,
				v.Release,
				v.Epoch,
				v.Flags,
				pkg,
			)
			pkg.provides = append(pkg.provides, prov)

			if !str_in_slice(prov.Name(), g_IGNORED_PACKAGES) {
				repo.Provides[prov.Name()] = append(repo.Provides[prov.Name()], prov)
			}
		}

		for _, v := range xml.Format.Requires {
			req := NewRequires(
				v.Name,
				v.Version,
				v.Release,
				v.Epoch,
				v.Flags,
				v.Pre,
			)
			pkg.requires = append(pkg.requires, req)
		}
		pkg.repository = repo.Repository

		// add package to repository
		repo.Packages[pkg.Name()] = append(repo.Packages[pkg.Name()], pkg)
	}
	return err
}

// FindLatestMatchingName locats a package by name, returns the latest available version.
func (repo *RepositoryXMLBackend) FindLatestMatchingName(name, version, release string) (*Package, error) {
	var pkg *Package
	var err error

	return pkg, err
}

// FindLatestMatchingRequire locates a package providing a given functionality.
func (repo *RepositoryXMLBackend) FindLatestMatchingRequire(requirement string) (*Package, error) {
	var pkg *Package
	var err error

	return pkg, err
}

// GetPackages returns all the packages known by a YUM repository
func (repo *RepositoryXMLBackend) GetPackages() []*Package {
	pkgs := make([]*Package, 0, len(repo.Packages))
	for _, pkg := range repo.Packages {
		pkgs = append(pkgs, pkg...)
	}
	return pkgs
}

func init() {
	g_backends["RepositoryXMLBackend"] = NewRepositoryXMLBackend
}
<commit_msg>yum: zlib -> gzip. handle not compressed files<commit_after>package yum

import (
	"compress/gzip"
	"encoding/xml"
	"io"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gonuts/logger"
)

// RepositoryXMLBackend is a Backend querying YUM XML repositories
type RepositoryXMLBackend struct {
	Name       string
	Packages   map[string][]*Package
	Provides   map[string][]*Provides
	DBName     string
	Primary    string
	Repository *Repository
	msg        *logger.Logger
}

func NewRepositoryXMLBackend(repo *Repository) (Backend, error) {
	const dbname = "primary.xml.gz"
	return &RepositoryXMLBackend{
		Name:       "RepositoryXMLBackend",
		Packages:   make(map[string][]*Package),
		Provides:   make(map[string][]*Provides),
		DBName:     dbname,
		Primary:    filepath.Join(repo.CacheDir, dbname),
		Repository: repo,
		msg:        repo.msg,
	}, nil
}

// YumDataType returns the ID for the data type as used in the repomd.xml file
func (repo *RepositoryXMLBackend) YumDataType() string {
	return "primary"
}

// Download the DB from server
func (repo *RepositoryXMLBackend) GetLatestDB(url string) error {
	var err error
	out, err := os.Create(repo.Primary)
	if err != nil {
		return err
	}
	defer out.Close()

	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	_, err = io.Copy(out, resp.Body)
	return err
}

// Check whether the DB is there
func (repo *RepositoryXMLBackend) HasDB() bool {
	return path_exists(repo.Primary)
}

// Load loads the DB
func (repo *RepositoryXMLBackend) LoadDB() error {
	var err error

	repo.msg.Debugf("start parsing metadata XML file...\n")
	type xmlTree struct {
		XMLName  xml.Name `xml:"metadata"`
		Packages []struct {
			Type string `xml:"type,attr"`
			Name string `xml:"name"`
			Arch string `xml:"arch"`

			Version struct {
				Epoch   int    `xml:"epoch,attr"`
				Version string `xml:"ver,attr"`
				Release int    `xml:"rel,attr"`
			} `xml:"version"`

			Checksum struct {
				Value string `xml:",innerxml"`
				Type  string `xml:"type,attr"`
				PkgId string `xml:"pkgid,attr"`
			} `xml:"checksum"`

			Summary  string `xml:"summary"`
			Descr    string `xml:"description"`
			Packager string `xml:"packager"`
			Url      string `xml:"url"`

			Time struct {
				File  string `xml:"file,attr"`
				Build string `xml:"build,attr"`
			} `xml:"time"`

			Size struct {
				Package   int64 `xml:"package,attr"`
				Installed int64 `xml:"installed,attr"`
				Archive   int64 `xml:"archive,attr"`
			} `xml:"size"`

			Location struct {
				Href string `xml:"href,attr"`
			} `xml:"location"`

			Format struct {
				License   string `xml:"rpm:license"`
				Vendor    string `xml:"rpm:vendor"`
				Group     string `xml:"rpm:group"`
				BuildHost string `xml:"rpm:buildhost"`
				SourceRpm string `xml:"rpm:sourcerpm"`

				HeaderRange struct {
					Beg int64 `xml:"start,attr"`
					End int64 `xml:"end,attr"`
				} `xml:"rpm:header-range"`

				Provides []struct {
					Name    string `xml:"name,attr"`
					Flags   string `xml:"flags,attr"`
					Epoch   int    `xml:"epoch,attr"`
					Version string `xml:"ver,attr"`
					Release int    `xml:"rel,attr"`
				} `xml:"rpm-provides"`

				Requires []struct {
					Name    string `xml:"name,attr"`
					Flags   string `xml:"flags,attr"`
					Epoch   int    `xml:"epoch,attr"`
					Version string `xml:"ver,attr"`
					Release int    `xml:"rel,attr"`
					Pre     string `xml:"pre,attr"`
				} `xml:"rpm-requires"`
			} `xml:"format"`
		} `xml:"package"`
	}

	// load the yum XML package list
	f, err := os.Open(repo.Primary)
	if err != nil {
		return err
	}
	defer f.Close()

	var r io.ReadCloser
	r, err = gzip.NewReader(f)
	if err != nil {
		if err == gzip.ErrHeader {
			// perhaps not a compressed file after all...
			r = f
		} else {
			repo.msg.Errorf("zip failed to open [%s]: %v\n", repo.Primary, err)
			return err
		}
	}
	defer r.Close()

	var tree xmlTree
	err = xml.NewDecoder(r).Decode(&tree)
	if err != nil {
		return err
	}

	for _, xml := range tree.Packages {
		pkg := NewPackage(xml.Name, xml.Version.Version, xml.Version.Release, xml.Version.Epoch)
		pkg.arch = xml.Arch
		pkg.group = xml.Format.Group
		pkg.location = xml.Location.Href
		for _, v := range xml.Format.Provides {
			prov := NewProvides(
				v.Name,
				v.Version,
				v.Release,
				v.Epoch,
				v.Flags,
				pkg,
			)
			pkg.provides = append(pkg.provides, prov)

			if !str_in_slice(prov.Name(), g_IGNORED_PACKAGES) {
				repo.Provides[prov.Name()] = append(repo.Provides[prov.Name()], prov)
			}
		}

		for _, v := range xml.Format.Requires {
			req := NewRequires(
				v.Name,
				v.Version,
				v.Release,
				v.Epoch,
				v.Flags,
				v.Pre,
			)
			pkg.requires = append(pkg.requires, req)
		}
		pkg.repository = repo.Repository

		// add package to repository
		repo.Packages[pkg.Name()] = append(repo.Packages[pkg.Name()], pkg)
	}
	return err
}

// FindLatestMatchingName locats a package by name, returns the latest available version.
func (repo *RepositoryXMLBackend) FindLatestMatchingName(name, version, release string) (*Package, error) {
	var pkg *Package
	var err error

	return pkg, err
}

// FindLatestMatchingRequire locates a package providing a given functionality.
func (repo *RepositoryXMLBackend) FindLatestMatchingRequire(requirement string) (*Package, error) {
	var pkg *Package
	var err error

	return pkg, err
}

// GetPackages returns all the packages known by a YUM repository
func (repo *RepositoryXMLBackend) GetPackages() []*Package {
	pkgs := make([]*Package, 0, len(repo.Packages))
	for _, pkg := range repo.Packages {
		pkgs = append(pkgs, pkg...)
	}
	return pkgs
}

func init() {
	g_backends["RepositoryXMLBackend"] = NewRepositoryXMLBackend
}
<|endoftext|>


<commit_before>package system

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/taskcluster/slugid-go/slugid"
	"github.com/taskcluster/taskcluster-worker/runtime/atomics"
	"github.com/taskcluster/taskcluster-worker/runtime/ioext"
)

// This file contains test cases that don't leave risk leaving dirty system
// resources, such as temporary user accounts. However, this file doesn't
// test all the functionality in the system package. Useful, we you want to
// check some of the system package without risking a dirty system.

// Note: Constants testGroup, testCat, testTrue, testFalse, testPrintDir, and
//       testSleep, testChildren, testGroups should be defined per platform

func TestSystemSafely(t *testing.T) {
	var err error
	var u *User

	// Setup temporary home directory
	homeDir := filepath.Join(os.TempDir(), slugid.Nice())
	require.NoError(t, os.MkdirAll(homeDir, 0777))
	defer os.RemoveAll(homeDir)

	t.Run("CurrentUser", func(t *testing.T) {
		u, err = CurrentUser()
		assert.NoError(t, err)
		assert.NotEmpty(t, u.Name())
	})

	t.Run("FindGroup", func(t *testing.T) {
		t.Skip("Not implemented on windows yet")
		g, err := FindGroup(testGroup)
		require.NoError(t, err)
		require.NotNil(t, g)
	})

	t.Run("StartProcess True", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess False", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess True with TTY", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
			TTY:       true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess False with TTY", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
			TTY:       true,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess Cat", func(t *testing.T) {
		t.Skip("Not implemented on windows, we're missing a testCat command that works")
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments: testCat,
			Stdin:     ioutil.NopCloser(bytes.NewBufferString("hello-world")),
			Stdout:    ioext.WriteNopCloser(&out),
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.EqualValues(t, "hello-world", out.String())
	})

	t.Run("StartProcess Cat with TTY", func(t *testing.T) {
		t.Skip("Not implemented on windows, we're missing a testCat command that works")
		p, err := StartProcess(ProcessOptions{
			Arguments: testCat,
			TTY:       true,
			Stdin:     ioutil.NopCloser(bytes.NewBufferString("hello-world")),
			// We can't reliably read output as we kill the process with stdin
			// is closed (EOF)
		})
		require.NoError(t, err)
		assert.False(t, p.Wait())
	})

	t.Run("StartProcess Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments:     testPrintDir,
			Stdout:        ioext.WriteNopCloser(&out),
			WorkingFolder: homeDir,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), homeDir)
	})

	t.Run("StartProcess TTY Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments:     testPrintDir,
			Stdout:        ioext.WriteNopCloser(&out),
			WorkingFolder: homeDir,
			TTY:           true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), homeDir)
	})

	t.Run("StartProcess Owner and Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments: testPrintDir,
			Stdout:    ioext.WriteNopCloser(&out),
			Owner:     u,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), u.Home())
	})

	t.Run("StartProcess TTY, Owner and Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments: testPrintDir,
			Stdout:    ioext.WriteNopCloser(&out),
			Owner:     u,
			TTY:       true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), u.Home())
	})

	t.Run("StartProcess Owner and True", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
			Owner:     u,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess TTY, Owner and True", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
			Owner:     u,
			TTY:       true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess Owner and False", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
			Owner:     u,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess TTY, Owner and False", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
			Owner:     u,
			TTY:       true,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess Kill", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testSleep,
		})
		require.NoError(t, err)
		var waited atomics.Bool
		done := make(chan bool)
		go func() {
			p.Wait()
			done <- waited.Get()
		}()
		time.Sleep(100 * time.Millisecond)
		waited.Set(true)
		p.Kill()
		require.False(t, p.Wait())
		require.True(t, <-done, "p.Wait was done before p.Kill() was called!")
	})

	t.Run("KillProcessTree", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testChildren,
			Owner:     nil,
		})
		require.NoError(t, err)
		done := make(chan bool)
		go func() {
			done <- p.Wait()
		}()
		time.Sleep(100 * time.Millisecond)
		require.NoError(t, KillProcessTree(p))
		select {
		case result := <-done:
			require.False(t, result, "killed process should result in false")
		case <-time.After(10 * time.Second):
			t.Fatal("Processes weren't killed")
		}
	})
}
<commit_msg>Skip test on OS X, I have no hardware available<commit_after>package system

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	rt "runtime"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/taskcluster/slugid-go/slugid"
	"github.com/taskcluster/taskcluster-worker/runtime/atomics"
	"github.com/taskcluster/taskcluster-worker/runtime/ioext"
)

// This file contains test cases that don't leave risk leaving dirty system
// resources, such as temporary user accounts. However, this file doesn't
// test all the functionality in the system package. Useful, we you want to
// check some of the system package without risking a dirty system.

// Note: Constants testGroup, testCat, testTrue, testFalse, testPrintDir, and
//       testSleep, testChildren, testGroups should be defined per platform

func TestSystemSafely(t *testing.T) {
	var err error
	var u *User

	// Setup temporary home directory
	homeDir := filepath.Join(os.TempDir(), slugid.Nice())
	require.NoError(t, os.MkdirAll(homeDir, 0777))
	defer os.RemoveAll(homeDir)

	t.Run("CurrentUser", func(t *testing.T) {
		u, err = CurrentUser()
		assert.NoError(t, err)
		assert.NotEmpty(t, u.Name())
	})

	t.Run("FindGroup", func(t *testing.T) {
		t.Skip("Not implemented on windows yet")
		g, err := FindGroup(testGroup)
		require.NoError(t, err)
		require.NotNil(t, g)
	})

	t.Run("StartProcess True", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess False", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess True with TTY", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
			TTY:       true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess False with TTY", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
			TTY:       true,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess Cat", func(t *testing.T) {
		t.Skip("Not implemented on windows, we're missing a testCat command that works")
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments: testCat,
			Stdin:     ioutil.NopCloser(bytes.NewBufferString("hello-world")),
			Stdout:    ioext.WriteNopCloser(&out),
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.EqualValues(t, "hello-world", out.String())
	})

	t.Run("StartProcess Cat with TTY", func(t *testing.T) {
		t.Skip("Not implemented on windows, we're missing a testCat command that works")
		p, err := StartProcess(ProcessOptions{
			Arguments: testCat,
			TTY:       true,
			Stdin:     ioutil.NopCloser(bytes.NewBufferString("hello-world")),
			// We can't reliably read output as we kill the process with stdin
			// is closed (EOF)
		})
		require.NoError(t, err)
		assert.False(t, p.Wait())
	})

	t.Run("StartProcess Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments:     testPrintDir,
			Stdout:        ioext.WriteNopCloser(&out),
			WorkingFolder: homeDir,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), homeDir)
	})

	t.Run("StartProcess TTY Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments:     testPrintDir,
			Stdout:        ioext.WriteNopCloser(&out),
			WorkingFolder: homeDir,
			TTY:           true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), homeDir)
	})

	t.Run("StartProcess Owner and Print Dir", func(t *testing.T) {
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments: testPrintDir,
			Stdout:    ioext.WriteNopCloser(&out),
			Owner:     u,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), u.Home())
	})

	t.Run("StartProcess TTY, Owner and Print Dir", func(t *testing.T) {
		if rt.GOOS == "darwin" {
			t.Skip("TODO: fix test can on OS X, no idea why it fails")
		}
		var out bytes.Buffer
		p, err := StartProcess(ProcessOptions{
			Arguments: testPrintDir,
			Stdout:    ioext.WriteNopCloser(&out),
			Owner:     u,
			TTY:       true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
		require.Contains(t, out.String(), u.Home())
	})

	t.Run("StartProcess Owner and True", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
			Owner:     u,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess TTY, Owner and True", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testTrue,
			Owner:     u,
			TTY:       true,
		})
		require.NoError(t, err)
		require.True(t, p.Wait())
	})

	t.Run("StartProcess Owner and False", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
			Owner:     u,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess TTY, Owner and False", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testFalse,
			Owner:     u,
			TTY:       true,
		})
		require.NoError(t, err)
		require.False(t, p.Wait())
	})

	t.Run("StartProcess Kill", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testSleep,
		})
		require.NoError(t, err)
		var waited atomics.Bool
		done := make(chan bool)
		go func() {
			p.Wait()
			done <- waited.Get()
		}()
		time.Sleep(100 * time.Millisecond)
		waited.Set(true)
		p.Kill()
		require.False(t, p.Wait())
		require.True(t, <-done, "p.Wait was done before p.Kill() was called!")
	})

	t.Run("KillProcessTree", func(t *testing.T) {
		p, err := StartProcess(ProcessOptions{
			Arguments: testChildren,
			Owner:     nil,
		})
		require.NoError(t, err)
		done := make(chan bool)
		go func() {
			done <- p.Wait()
		}()
		time.Sleep(100 * time.Millisecond)
		require.NoError(t, KillProcessTree(p))
		select {
		case result := <-done:
			require.False(t, result, "killed process should result in false")
		case <-time.After(10 * time.Second):
			t.Fatal("Processes weren't killed")
		}
	})
}
<|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 tabwriter

import (
	"os";
	"io";
	"vector";
	"utf8";
)

// ----------------------------------------------------------------------------
// Basic byteArray support

type byteArray struct {
	a []byte;
}

func (b *byteArray) Init(initial_size int) {
	b.a = make([]byte, initial_size)[0 : 0];
}

func (b *byteArray) Len() int {
	return len(b.a);
}

func (b *byteArray) clear() {
	b.a = b.a[0 : 0];
}

func (b *byteArray) slice(i, j int) []byte {
	return b.a[i : j];  // BUG should really be &b.a[i : j]
}

func (b *byteArray) append(s []byte) {
	a := b.a;
	n := len(a);
	m := n + len(s);

	if m > cap(a) {
		n2 := 2*n;
		if m > n2 {
			n2 = m;
		}
		b := make([]byte, n2);
		for i := 0; i < n; i++ {
			b[i] = a[i];
		}
		a = b;
	}

	a = a[0 : m];
	for i := len(s) - 1; i >= 0; i-- {
		a[n + i] = s[i];
	}
	b.a = a;
}

// ----------------------------------------------------------------------------
// Writer is a filter implementing the io.Write interface. It assumes
// that the incoming bytes represent UTF-8 encoded text consisting of
// lines of tab-terminated "cells". Cells in adjacent lines constitute
// a column. Writer rewrites the incoming text such that all cells in
// a column have the same width; thus it effectively aligns cells. It
// does this by adding padding where necessary. All characters (ASCII
// or not) are assumed to be of the same width - this may not be true
// for arbitrary UTF-8 characters visualized on the screen.
//
// Note that any text at the end of a line that is not tab-terminated
// is not a cell and does not enforce alignment of cells in adjacent
// rows. To make it a cell it needs to be tab-terminated. (For more
// information see http://nickgravgaard.com/elastictabstops/index.html)
//
// Formatting can be controlled via parameters:
//
// cellwidth	minimal cell width
// padding      additional cell padding
// padchar      ASCII char used for padding
//              if padchar == '\t', the Writer will assume that the
//              width of a '\t' in the formatted output is cellwidth,
//              and cells are left-aligned independent of align_left
//              (for correct-looking results, cellwidth must correspond
//              to the tabwidth in the viewer displaying the result)
// filter_html  ignores html tags and handles entities (starting with '&'
//              and ending in ';') as single characters (width = 1)

type Writer struct {
	// configuration
	writer io.Write;
	cellwidth int;
	padding int;
	padbytes [8]byte;
	align_left bool;
	filter_html bool;

	// current state
	html_char byte;  // terminating char of html tag/entity, or 0 ('>', ';', or 0)
	buf byteArray;  // collected text w/o tabs and newlines
	size int;  // size of incomplete cell in bytes
	width int;  // width of incomplete cell in runes up to buf[pos] w/o ignored sections
	pos int;  // buffer position up to which width of incomplete cell has been computed
	lines_size vector.Vector;  // list of lines; each line is a list of cell sizes in bytes
	lines_width vector.Vector;  // list of lines; each line is a list of cell widths in runes
	widths vector.IntVector;  // list of column widths in runes - re-used during formatting
}

// Internal representation (current state):
//
// - all text written is appended to buf; tabs and newlines are stripped away
// - at any given time there is a (possibly empty) incomplete cell at the end
//   (the cell starts after a tab or newline)
// - size is the number of bytes belonging to the cell so far
// - width is text width in runes of that cell from the start of the cell to
//   position pos; html tags and entities are excluded from this width if html
//   filtering is enabled
// - the sizes and widths of processed text are kept in the lines_size and
//   lines_width arrays, which contain an array of sizes or widths for each line
// - the widths array is a temporary array with current widths used during
//   formatting; it is kept in Writer because it's re-used
//
//                    |<---------- size ---------->|
//                    |                            |
//                    |<- width ->|<- ignored ->|  |
//                    |           |             |  |
// [---processed---tab------------<tag>...</tag>...]
// ^                  ^                         ^
// |                  |                         |
// buf                start of incomplete cell  pos

func (b *Writer) addLine() {
	b.lines_size.Push(vector.NewIntVector(0));
	b.lines_width.Push(vector.NewIntVector(0));
}

func (b *Writer) Init(writer io.Write, cellwidth, padding int, padchar byte, align_left, filter_html bool) *Writer {
	if cellwidth < 0 {
		panic("negative cellwidth");
	}
	if padding < 0 {
		panic("negative padding");
	}
	b.writer = writer;
	b.cellwidth = cellwidth;
	b.padding = padding;
	for i := len(b.padbytes) - 1; i >= 0; i-- {
		b.padbytes[i] = padchar;
	}
	b.align_left = align_left || padchar == '\t';  // tab enforces left-alignment
	b.filter_html = filter_html;

	b.buf.Init(1024);
	b.lines_size.Init(0);
	b.lines_width.Init(0);
	b.widths.Init(0);
	b.addLine();  // the very first line

	return b;
}

func (b *Writer) line(i int) (*vector.IntVector, *vector.IntVector) {
	return
		b.lines_size.At(i).(*vector.IntVector),
		b.lines_width.At(i).(*vector.IntVector);
}

// debugging support
func (b *Writer) dump() {
	pos := 0;
	for i := 0; i < b.lines_size.Len(); i++ {
		line_size, line_width := b.line(i);
		print("(", i, ") ");
		for j := 0; j < line_size.Len(); j++ {
			s := line_size.At(j);
			print("[", string(b.buf.slice(pos, pos + s)), "]");
			pos += s;
		}
		print("\n");
	}
	print("\n");
}

func (b *Writer) write0(buf []byte) *os.Error {
	n, err := b.writer.Write(buf);
	if n != len(buf) && err == nil {
		err = os.EIO;
	}
	return err;
}

var newline = []byte{'\n'}

func (b *Writer) writePadding(textw, cellw int) (err *os.Error) {
	if b.padbytes[0] == '\t' {
		// make cell width a multiple of cellwidth
		cellw = ((cellw + b.cellwidth - 1) / b.cellwidth) * b.cellwidth;
	}

	n := cellw - textw;
	if n < 0 {
		panic("internal error");
	}

	if b.padbytes[0] == '\t' {
		n = (n + b.cellwidth - 1) / b.cellwidth;
	}

	for n > len(b.padbytes) {
		err = b.write0(b.padbytes);
		if err != nil {
			goto exit;
		}
		n -= len(b.padbytes);
	}
	err = b.write0(b.padbytes[0 : n]);

exit:
	return err;
}

func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err *os.Error) {
	pos = pos0;
	for i := line0; i < line1; i++ {
		line_size, line_width := b.line(i);
		for j := 0; j < line_size.Len(); j++ {
			s, w := line_size.At(j), line_width.At(j);

			if b.align_left {
				err = b.write0(b.buf.slice(pos, pos + s));
				if err != nil {
					goto exit;
				}
				pos += s;
				if j < b.widths.Len() {
					err = b.writePadding(w, b.widths.At(j));
					if err != nil {
						goto exit;
					}
				}

			} else {  // align right

				if j < b.widths.Len() {
					err = b.writePadding(w, b.widths.At(j));
					if err != nil {
						goto exit;
					}
				}
				err = b.write0(b.buf.slice(pos, pos + s));
				if err != nil {
					goto exit;
				}
				pos += s;
			}
		}

		if i+1 == b.lines_size.Len() {
			// last buffered line - we don't have a newline, so just write
			// any outstanding buffered data
			err = b.write0(b.buf.slice(pos, pos + b.size));
			pos += b.size;
		} else {
			// not the last line - write newline
			err = b.write0(newline);
		}
		if err != nil {
			goto exit;
		}
	}

exit:
	return pos, err;
}

func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err *os.Error) {
	pos = pos0;
	column := b.widths.Len();
	last := line0;
	for this := line0; this < line1; this++ {
		line_size, line_width := b.line(this);

		if column < line_size.Len() - 1 {
			// cell exists in this column
			// (note that the last cell per line is ignored)

			// print unprinted lines until beginning of block
			pos, err = b.writeLines(pos, last, this);
			if err != nil {
				goto exit;
			}
			last = this;

			// column block begin
			width := b.cellwidth;  // minimal width
			for ; this < line1; this++ {
				line_size, line_width = b.line(this);
				if column < line_size.Len() - 1 {
					// cell exists in this column => update width
					w := line_width.At(column) + b.padding;
					if w > width {
						width = w;
					}
				} else {
					break
				}
			}
			// column block end

			// format and print all columns to the right of this column
			// (we know the widths of this column and all columns to the left)
			b.widths.Push(width);
			pos, err = b.format(pos, last, this);
			b.widths.Pop();
			last = this;
		}
	}

	// print unprinted lines until end
	pos, err = b.writeLines(pos, last, line1);

exit:
	return pos, err;
}

func (b *Writer) Flush() *os.Error {
	dummy, err := b.format(0, 0, b.lines_size.Len());
	// reset (even in the presence of errors)
	b.buf.clear();
	b.size, b.width = 0, 0;
	b.pos = 0;
	b.lines_size.Init(0);
	b.lines_width.Init(0);
	b.addLine();
	return err;
}

func unicodeLen(buf []byte) int {
	l := 0;
	for i := 0; i < len(buf); {
		if buf[i] < utf8.RuneSelf {
			i++;
		} else {
			rune, size := utf8.DecodeRune(buf[i : len(buf)]);
			i += size;
		}
		l++;
	}
	return l;
}

func (b *Writer) append(buf []byte) {
	b.buf.append(buf);
	b.size += len(buf);
}

func (b *Writer) Write(buf []byte) (written int, err *os.Error) {
	i0, n := 0, len(buf);

	// split text into cells
	for i := 0; i < n; i++ {
		ch := buf[i];

		if b.html_char == 0 {
			// outside html tag/entity
			switch ch {
			case '\t', '\n':
				b.append(buf[i0 : i]);
				i0 = i + 1;  // exclude ch from (next) cell
				b.width += unicodeLen(b.buf.slice(b.pos, b.buf.Len()));
				b.pos = b.buf.Len();

				// terminate cell
				last_size, last_width := b.line(b.lines_size.Len() - 1);
				last_size.Push(b.size);
				last_width.Push(b.width);
				b.size, b.width = 0, 0;

				if ch == '\n' {
					b.addLine();
					if last_size.Len() == 1 {
						// The previous line has only one cell which does not have
						// an impact on the formatting of the following lines (the
						// last cell per line is ignored by format()), thus we can
						// flush the Writer contents.
						err = b.Flush();
						if err != nil {
							return i0, err;
						}
					}
				}

			case '<', '&':
				if b.filter_html {
					b.append(buf[i0 : i]);
					i0 = i;
					b.width += unicodeLen(b.buf.slice(b.pos, b.buf.Len()));
					b.pos = -1;  // preventative - should not be used (will cause index out of bounds)
					if ch == '<' {
						b.html_char = '>';
					} else {
						b.html_char = ';';
					}
				}
			}

		} else {
			// inside html tag/entity
			if ch == b.html_char {
				// reached the end of tag/entity
				b.append(buf[i0 : i + 1]);
				i0 = i + 1;
				if b.html_char == ';' {
					b.width++;  // count as one char
				}
				b.pos = b.buf.Len();
				b.html_char = 0;
			}
		}
	}

	// append leftover text
	b.append(buf[i0 : n]);
	return n, nil;
}

func New(writer io.Write, cellwidth, padding int, padchar byte, align_left, filter_html bool) *Writer {
	return new(Writer).Init(writer, cellwidth, padding, padchar, align_left, filter_html)
}
<commit_msg>tabwriter documentation<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.

// The tabwriter package implements a write filter (tabwriter.Writer)
// that translates tabbed columns in input into properly aligned text,
// using the Elastic Tabstops algorithm described at
// http://nickgravgaard.com/elastictabstops/index.html.
//
package tabwriter

import (
	"os";
	"io";
	"vector";
	"utf8";
)

// ----------------------------------------------------------------------------
// Basic byteArray support

type byteArray struct {
	a []byte;
}

func (b *byteArray) Init(initial_size int) {
	b.a = make([]byte, initial_size)[0 : 0];
}

func (b *byteArray) Len() int {
	return len(b.a);
}

func (b *byteArray) clear() {
	b.a = b.a[0 : 0];
}

func (b *byteArray) slice(i, j int) []byte {
	return b.a[i : j];  // BUG should really be &b.a[i : j]
}

func (b *byteArray) append(s []byte) {
	a := b.a;
	n := len(a);
	m := n + len(s);

	if m > cap(a) {
		n2 := 2*n;
		if m > n2 {
			n2 = m;
		}
		b := make([]byte, n2);
		for i := 0; i < n; i++ {
			b[i] = a[i];
		}
		a = b;
	}

	a = a[0 : m];
	for i := len(s) - 1; i >= 0; i-- {
		a[n + i] = s[i];
	}
	b.a = a;
}

// ----------------------------------------------------------------------------
// Filter implementation

// A Writer is a filter that inserts padding around
// tab-delimited columns in its input to align them
// in the output.
//
// The Writer treats incoming bytes as UTF-8 encoded text
// consisting of tab-terminated cells. Cells in adjacent lines
// constitute a column. The Writer inserts padding as needed
// to make all cells in a column have the same width, effectively
// aligning the columns. Note that cells are tab-terminated,
// not tab-separated: trailing non-tab text at the end of a line
// is not part of any cell.
//
// The Writer assumes that all characters have the same width;
// this may not be true in some fonts, especially with certain
// UTF-8 characters.
//
// The Writer must buffer input internally, because proper spacing
// of one line may depend on the cells in future lines. Clients must
// call Flush when done calling Write.
//
type Writer struct {
	// configuration
	output io.Write;
	cellwidth int;
	padding int;
	padbytes [8]byte;
	align_left bool;
	filter_html bool;

	// current state
	html_char byte;  // terminating char of html tag/entity, or 0 ('>', ';', or 0)
	buf byteArray;  // collected text w/o tabs and newlines
	size int;  // size of incomplete cell in bytes
	width int;  // width of incomplete cell in runes up to buf[pos] w/o ignored sections
	pos int;  // buffer position up to which width of incomplete cell has been computed
	lines_size vector.Vector;  // list of lines; each line is a list of cell sizes in bytes
	lines_width vector.Vector;  // list of lines; each line is a list of cell widths in runes
	widths vector.IntVector;  // list of column widths in runes - re-used during formatting
}

// Internal representation (current state):
//
// - all text written is appended to buf; tabs and newlines are stripped away
// - at any given time there is a (possibly empty) incomplete cell at the end
//   (the cell starts after a tab or newline)
// - size is the number of bytes belonging to the cell so far
// - width is text width in runes of that cell from the start of the cell to
//   position pos; html tags and entities are excluded from this width if html
//   filtering is enabled
// - the sizes and widths of processed text are kept in the lines_size and
//   lines_width arrays, which contain an array of sizes or widths for each line
// - the widths array is a temporary array with current widths used during
//   formatting; it is kept in Writer because it's re-used
//
//                    |<---------- size ---------->|
//                    |                            |
//                    |<- width ->|<- ignored ->|  |
//                    |           |             |  |
// [---processed---tab------------<tag>...</tag>...]
// ^                  ^                         ^
// |                  |                         |
// buf                start of incomplete cell  pos

func (b *Writer) addLine() {
	b.lines_size.Push(vector.NewIntVector(0));
	b.lines_width.Push(vector.NewIntVector(0));
}

// A Writer must be initialized with a call to Init. The first parameter (output)
// specifies the filter output. The remaining parameters control the formatting:
//
//	cellwidth	minimal cell width
//	padding		additional cell padding
//	padchar		ASCII char used for padding
//				if padchar == '\t', the Writer will assume that the
//				width of a '\t' in the formatted output is cellwidth,
//				and cells are left-aligned independent of align_left
//				(for correct-looking results, cellwidth must correspond
//				to the tab width in the viewer displaying the result)
//	align_left	alignment of cell content
//	filter_html	ignores html tags and treats entities (starting with '&'
//				and ending in ';') as single characters (width = 1)
//
func (b *Writer) Init(output io.Write, cellwidth, padding int, padchar byte, align_left, filter_html bool) *Writer {
	if cellwidth < 0 {
		panic("negative cellwidth");
	}
	if padding < 0 {
		panic("negative padding");
	}
	b.output = output;
	b.cellwidth = cellwidth;
	b.padding = padding;
	for i := len(b.padbytes) - 1; i >= 0; i-- {
		b.padbytes[i] = padchar;
	}
	b.align_left = align_left || padchar == '\t';  // tab enforces left-alignment
	b.filter_html = filter_html;

	b.buf.Init(1024);
	b.lines_size.Init(0);
	b.lines_width.Init(0);
	b.widths.Init(0);
	b.addLine();  // the very first line

	return b;
}

func (b *Writer) line(i int) (*vector.IntVector, *vector.IntVector) {
	return
		b.lines_size.At(i).(*vector.IntVector),
		b.lines_width.At(i).(*vector.IntVector);
}

// debugging support
func (b *Writer) dump() {
	pos := 0;
	for i := 0; i < b.lines_size.Len(); i++ {
		line_size, line_width := b.line(i);
		print("(", i, ") ");
		for j := 0; j < line_size.Len(); j++ {
			s := line_size.At(j);
			print("[", string(b.buf.slice(pos, pos + s)), "]");
			pos += s;
		}
		print("\n");
	}
	print("\n");
}

func (b *Writer) write0(buf []byte) *os.Error {
	n, err := b.output.Write(buf);
	if n != len(buf) && err == nil {
		err = os.EIO;
	}
	return err;
}

var newline = []byte{'\n'}

func (b *Writer) writePadding(textw, cellw int) (err *os.Error) {
	if b.padbytes[0] == '\t' {
		// make cell width a multiple of cellwidth
		cellw = ((cellw + b.cellwidth - 1) / b.cellwidth) * b.cellwidth;
	}

	n := cellw - textw;
	if n < 0 {
		panic("internal error");
	}

	if b.padbytes[0] == '\t' {
		n = (n + b.cellwidth - 1) / b.cellwidth;
	}

	for n > len(b.padbytes) {
		err = b.write0(b.padbytes);
		if err != nil {
			goto exit;
		}
		n -= len(b.padbytes);
	}
	err = b.write0(b.padbytes[0 : n]);

exit:
	return err;
}

func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err *os.Error) {
	pos = pos0;
	for i := line0; i < line1; i++ {
		line_size, line_width := b.line(i);
		for j := 0; j < line_size.Len(); j++ {
			s, w := line_size.At(j), line_width.At(j);

			if b.align_left {
				err = b.write0(b.buf.slice(pos, pos + s));
				if err != nil {
					goto exit;
				}
				pos += s;
				if j < b.widths.Len() {
					err = b.writePadding(w, b.widths.At(j));
					if err != nil {
						goto exit;
					}
				}

			} else {  // align right

				if j < b.widths.Len() {
					err = b.writePadding(w, b.widths.At(j));
					if err != nil {
						goto exit;
					}
				}
				err = b.write0(b.buf.slice(pos, pos + s));
				if err != nil {
					goto exit;
				}
				pos += s;
			}
		}

		if i+1 == b.lines_size.Len() {
			// last buffered line - we don't have a newline, so just write
			// any outstanding buffered data
			err = b.write0(b.buf.slice(pos, pos + b.size));
			pos += b.size;
		} else {
			// not the last line - write newline
			err = b.write0(newline);
		}
		if err != nil {
			goto exit;
		}
	}

exit:
	return pos, err;
}

func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err *os.Error) {
	pos = pos0;
	column := b.widths.Len();
	last := line0;
	for this := line0; this < line1; this++ {
		line_size, line_width := b.line(this);

		if column < line_size.Len() - 1 {
			// cell exists in this column
			// (note that the last cell per line is ignored)

			// print unprinted lines until beginning of block
			pos, err = b.writeLines(pos, last, this);
			if err != nil {
				goto exit;
			}
			last = this;

			// column block begin
			width := b.cellwidth;  // minimal width
			for ; this < line1; this++ {
				line_size, line_width = b.line(this);
				if column < line_size.Len() - 1 {
					// cell exists in this column => update width
					w := line_width.At(column) + b.padding;
					if w > width {
						width = w;
					}
				} else {
					break
				}
			}
			// column block end

			// format and print all columns to the right of this column
			// (we know the widths of this column and all columns to the left)
			b.widths.Push(width);
			pos, err = b.format(pos, last, this);
			b.widths.Pop();
			last = this;
		}
	}

	// print unprinted lines until end
	pos, err = b.writeLines(pos, last, line1);

exit:
	return pos, err;
}

// Flush should be called after the last call to Write to ensure
// that any data buffered in the Writer is written to output.
//
func (b *Writer) Flush() *os.Error {
	dummy, err := b.format(0, 0, b.lines_size.Len());
	// reset (even in the presence of errors)
	b.buf.clear();
	b.size, b.width = 0, 0;
	b.pos = 0;
	b.lines_size.Init(0);
	b.lines_width.Init(0);
	b.addLine();
	return err;
}

func unicodeLen(buf []byte) int {
	l := 0;
	for i := 0; i < len(buf); {
		if buf[i] < utf8.RuneSelf {
			i++;
		} else {
			rune, size := utf8.DecodeRune(buf[i : len(buf)]);
			i += size;
		}
		l++;
	}
	return l;
}

func (b *Writer) append(buf []byte) {
	b.buf.append(buf);
	b.size += len(buf);
}

// Write writes buf to the writer b.
// The only errors returned are ones encountered
// while writing to the underlying output stream.
//
func (b *Writer) Write(buf []byte) (written int, err *os.Error) {
	i0, n := 0, len(buf);

	// split text into cells
	for i := 0; i < n; i++ {
		ch := buf[i];

		if b.html_char == 0 {
			// outside html tag/entity
			switch ch {
			case '\t', '\n':
				b.append(buf[i0 : i]);
				i0 = i + 1;  // exclude ch from (next) cell
				b.width += unicodeLen(b.buf.slice(b.pos, b.buf.Len()));
				b.pos = b.buf.Len();

				// terminate cell
				last_size, last_width := b.line(b.lines_size.Len() - 1);
				last_size.Push(b.size);
				last_width.Push(b.width);
				b.size, b.width = 0, 0;

				if ch == '\n' {
					b.addLine();
					if last_size.Len() == 1 {
						// The previous line has only one cell which does not have
						// an impact on the formatting of the following lines (the
						// last cell per line is ignored by format()), thus we can
						// flush the Writer contents.
						err = b.Flush();
						if err != nil {
							return i0, err;
						}
					}
				}

			case '<', '&':
				if b.filter_html {
					b.append(buf[i0 : i]);
					i0 = i;
					b.width += unicodeLen(b.buf.slice(b.pos, b.buf.Len()));
					b.pos = -1;  // preventative - should not be used (will cause index out of bounds)
					if ch == '<' {
						b.html_char = '>';
					} else {
						b.html_char = ';';
					}
				}
			}

		} else {
			// inside html tag/entity
			if ch == b.html_char {
				// reached the end of tag/entity
				b.append(buf[i0 : i + 1]);
				i0 = i + 1;
				if b.html_char == ';' {
					b.width++;  // count as one char
				}
				b.pos = b.buf.Len();
				b.html_char = 0;
			}
		}
	}

	// append leftover text
	b.append(buf[i0 : n]);
	return n, nil;
}

// New allocates and initializes a new tabwriter.Writer.
// The parameters are the same as for the the Init function.
//
func New(writer io.Write, cellwidth, padding int, padchar byte, align_left, filter_html bool) *Writer {
	return new(Writer).Init(writer, cellwidth, padding, padchar, align_left, filter_html)
}
<|endoftext|>


<commit_before>package dbTest

import (
	"testing"

	"github.com/Everlag/poeitemstore/db"
)

var benchQueryResult []db.ID

// BenchmarkSingleIndexQuery runs a single query on the database.
//
// Consider this the absolute best case scenario as the cache will
// be as hot as it can possibly be.
func BenchmarkSingleIndexQuery(b *testing.B) {

	b.ReportAllocs()

	bdb := NewTempDatabase(b)

	// Define our search up here, it will be constant for all of
	// our sub-tests
	search := QueryBootsMovespeedFireResist.Clone()

	// Fetch the changes we need
	set := GetChangeSet("testSet - 11 updates.msgp", b)
	if len(set.Changes) != 11 {
		b.Fatalf("wrong number of changes, expected 11 got %d",
			len(set.Changes))
	}

	// Run the changes, nop for the callback as
	// we only care about the end result
	RunChangeSet(set, func(id string) error {
		return nil
	}, bdb, b)

	// Translate the query now, after we are more likely
	// to have the desired mods available on the StringHeap
	indexQuery, _ := MultiModSearchToIndexQuery(search, bdb, b)

	b.ResetTimer()

	var err error

	for i := 0; i < b.N; i++ {
		benchQueryResult, err = indexQuery.Run(bdb)
		if err != nil {
			b.Fatalf("failed IndexQuery.Run, err=%s", err)
		}

		if len(benchQueryResult) < search.MaxDesired {
			b.Fatalf("failed to find enough results in query")
		}
	}
}
<commit_msg>dbTest BenchmarkSingleIndexQuery benchmark query translation<commit_after>package dbTest

import (
	"testing"

	"github.com/Everlag/poeitemstore/db"
)

var benchQueryResult []db.ID

// BenchmarkSingleIndexQuery runs a single query on the database.
//
// Consider this the absolute best case scenario as the cache will
// be as hot as it can possibly be.
func BenchmarkSingleIndexQuery(b *testing.B) {

	b.ReportAllocs()

	bdb := NewTempDatabase(b)

	// Fetch the changes we need
	set := GetChangeSet("testSet - 11 updates.msgp", b)
	if len(set.Changes) != 11 {
		b.Fatalf("wrong number of changes, expected 11 got %d",
			len(set.Changes))
	}

	// Run the changes, nop for the callback as
	// we only care about the end result
	RunChangeSet(set, func(id string) error {
		return nil
	}, bdb, b)

	b.ResetTimer()

	var err error

	for i := 0; i < b.N; i++ {

		// Define our search here
		search := QueryBootsMovespeedFireResist.Clone()

		// Translate the query now, after we are more likely
		// to have the desired mods available on the StringHeap.
		//
		// This is done within the benchmarking time as it must be done
		// for any query
		indexQuery, _ := MultiModSearchToIndexQuery(search, bdb, b)

		benchQueryResult, err = indexQuery.Run(bdb)
		if err != nil {
			b.Fatalf("failed IndexQuery.Run, err=%s", err)
		}

		if len(benchQueryResult) < search.MaxDesired {
			b.Fatalf("failed to find enough results in query")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
	"fmt"
	"flag"
	"time"
	"os"
)

func main() {
	bucket := flag.String("bucket", "", "bucket")
	key := flag.String("key", "", "key")
	region := flag.String("region", aws.USEast.Name, "region")
	expiration := flag.String("expiration", "1h", "expiration in the Go duration format.  A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as \"300ms\", \"-1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
	verbose := flag.Bool("v", false, "verbose")

	flag.Parse()

	if *bucket == "" || *key == "" {
		fmt.Printf("bucket and key are required\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	auth, err := aws.GetAuth("", "")

	if err != nil {
		panic(err)
	}

	if *verbose {
		fmt.Fprintf(os.Stderr, "auth: %#v\n", auth)
	}

	reg, found := aws.Regions[*region]

	if ! found {
		panic(fmt.Sprintf("invalid region: %s", *region))
	}

	s3c := s3.New(auth, reg)
	buck := s3c.Bucket(*bucket)

	dur, err := time.ParseDuration(*expiration)

	if err != nil {
		panic(err)
	}

	exp := time.Now().Add(dur)

	fmt.Println(buck.SignedURL(*key, exp))
}
<commit_msg>added "cat" mode<commit_after>package main

import (
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
	"fmt"
	"flag"
	"time"
	"os"
	"io"
)

func main() {
	bucket := flag.String("bucket", "", "bucket")
	key := flag.String("key", "", "key")
	region := flag.String("region", aws.USEast.Name, "region")
	expiration := flag.String("expiration", "1h", "expiration in the Go duration format.  A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as \"300ms\", \"-1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
	verbose := flag.Bool("v", false, "verbose")
	mode := flag.String("mode", "sign", "sign or cat")

	flag.Parse()

	if *bucket == "" || *key == "" {
		fmt.Printf("bucket and key are required\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

	auth, err := aws.GetAuth("", "")

	if err != nil {
		panic(err)
	}

	if *verbose {
		fmt.Fprintf(os.Stderr, "auth: %#v\n", auth)
	}

	reg, found := aws.Regions[*region]

	if ! found {
		panic(fmt.Sprintf("invalid region: %s", *region))
	}

	s3c := s3.New(auth, reg)
	buck := s3c.Bucket(*bucket)

	switch *mode {
	case "sign":
		dur, err := time.ParseDuration(*expiration)

		if err != nil {
			panic(err)
		}

		exp := time.Now().Add(dur)

		fmt.Println(buck.SignedURL(*key, exp))

	case "cat":
		reader, err := buck.GetReader(*key)

		if err != nil {
			panic(err)
		}

		io.Copy(os.Stdout, reader)

	default:
		panic(fmt.Sprintf("invalid mode: %s", *mode))
	}
}
<|endoftext|>


<commit_before>package testing

import (
	"bytes"
	"context"
	"fmt"
	"sort"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/influxdata/platform"
	kerrors "github.com/influxdata/platform/kit/errors"
	"github.com/influxdata/platform/mock"
)

const (
	idA = "020f755c3c082000"
	idB = "020f755c3c082001"
	idC = "020f755c3c082002"
)

var macroCmpOptions = cmp.Options{
	cmp.Comparer(func(x, y []byte) bool {
		return bytes.Equal(x, y)
	}),
	cmp.Transformer("Sort", func(in []*platform.Macro) []*platform.Macro {
		out := append([]*platform.Macro(nil), in...)
		sort.Slice(out, func(i, j int) bool {
			return out[i].ID.String() > out[j].ID.String()
		})
		return out
	}),
}

// MacroFields defines fields for a macro test
type MacroFields struct {
	Macros      []*platform.Macro
	IDGenerator platform.IDGenerator
}

// CreateMacro tests platform.MacroService CreateMacro interface method
func CreateMacro(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		macro *platform.Macro
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "creating a macro assigns the macro an id and adds it to the store",
			fields: MacroFields{
				IDGenerator: &mock.IDGenerator{
					IDFn: func() platform.ID {
						return idFromString(t, idA)
					},
				},
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				macro: &platform.Macro{
					Name: "my-macro",
					Arguments: platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{},
					},
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "my-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		err := s.CreateMacro(ctx, tt.args.macro)
		diffErrors(err, tt.wants.err, t)

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

// FindMacroByID tests platform.MacroService FindMacroByID interface method
func FindMacroByID(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err   error
		macro *platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "finding a macro that exists by id",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro-a",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro-b",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idB),
			},
			wants: wants{
				err: nil,
				macro: &platform.Macro{
					ID:   idFromString(t, idB),
					Name: "existing-macro-b",
					Arguments: platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{},
					},
				},
			},
		},
		{
			name: "finding a non-existant macro",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id: idFromString(t, idA),
			},
			wants: wants{
				err:   kerrors.Errorf(kerrors.NotFound, "macro with ID %s not found", idA),
				macro: nil,
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		macro, err := s.FindMacroByID(ctx, tt.args.id)
		diffErrors(err, tt.wants.err, t)

		if diff := cmp.Diff(macro, tt.wants.macro); diff != "" {
			t.Fatalf("found unexpected macro -got/+want\ndiff %s", diff)
		}
	}
}

// UpdateMacro tests platform.MacroService UpdateMacro interface method
func UpdateMacro(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		id     platform.ID
		update *platform.MacroUpdate
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "updating a macro's name",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro-a",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro-b",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idB),
				update: &platform.MacroUpdate{
					Name: "new-macro-b-name",
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro-a",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "new-macro-b-name",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
		{
			name: "updating a non-existant macro fails",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id:     idFromString(t, idA),
				update: &platform.MacroUpdate{},
			},
			wants: wants{
				err:    fmt.Errorf("macro with ID %s not found (error reference code: 5)", idA),
				macros: []*platform.Macro{},
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		macro, err := s.UpdateMacro(ctx, tt.args.id, tt.args.update)
		diffErrors(err, tt.wants.err, t)

		if tt.args.update.Name != "" && macro.Name != tt.args.update.Name {
			t.Fatalf("macro name not updated")
		}

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

// DeleteMacro tests platform.MacroService DeleteMacro interface method
func DeleteMacro(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "deleting a macro",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idA),
			},
			wants: wants{
				err:    nil,
				macros: []*platform.Macro{},
			},
		},
		{
			name: "deleting a macro that doesn't exist",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idB),
			},
			wants: wants{
				err: kerrors.Errorf(kerrors.NotFound, "macro with ID %s not found", idB),
				macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		err := s.DeleteMacro(ctx, tt.args.id)
		defer s.PutMacro(ctx, &platform.Macro{
			ID: tt.args.id,
		})
		diffErrors(err, tt.wants.err, t)

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

func diffErrors(actual, expected error, t *testing.T) {
	if expected == nil && actual != nil {
		t.Fatalf("unexpected error %q", actual.Error())
	}

	if expected != nil && actual == nil {
		t.Fatalf("expected error %q but received nil", expected.Error())
	}

	if expected != nil && actual != nil && expected.Error() != actual.Error() {
		t.Fatalf("expected error %q but received error %q", expected.Error(), actual.Error())
	}
}
<commit_msg>fix(testing): use new error formatting in macro test<commit_after>package testing

import (
	"bytes"
	"context"
	"fmt"
	"sort"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/influxdata/platform"
	kerrors "github.com/influxdata/platform/kit/errors"
	"github.com/influxdata/platform/mock"
)

const (
	idA = "020f755c3c082000"
	idB = "020f755c3c082001"
	idC = "020f755c3c082002"
)

var macroCmpOptions = cmp.Options{
	cmp.Comparer(func(x, y []byte) bool {
		return bytes.Equal(x, y)
	}),
	cmp.Transformer("Sort", func(in []*platform.Macro) []*platform.Macro {
		out := append([]*platform.Macro(nil), in...)
		sort.Slice(out, func(i, j int) bool {
			return out[i].ID.String() > out[j].ID.String()
		})
		return out
	}),
}

// MacroFields defines fields for a macro test
type MacroFields struct {
	Macros      []*platform.Macro
	IDGenerator platform.IDGenerator
}

// CreateMacro tests platform.MacroService CreateMacro interface method
func CreateMacro(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		macro *platform.Macro
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "creating a macro assigns the macro an id and adds it to the store",
			fields: MacroFields{
				IDGenerator: &mock.IDGenerator{
					IDFn: func() platform.ID {
						return idFromString(t, idA)
					},
				},
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				macro: &platform.Macro{
					Name: "my-macro",
					Arguments: platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{},
					},
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "my-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		err := s.CreateMacro(ctx, tt.args.macro)
		diffErrors(err, tt.wants.err, t)

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

// FindMacroByID tests platform.MacroService FindMacroByID interface method
func FindMacroByID(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err   error
		macro *platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "finding a macro that exists by id",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro-a",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro-b",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idB),
			},
			wants: wants{
				err: nil,
				macro: &platform.Macro{
					ID:   idFromString(t, idB),
					Name: "existing-macro-b",
					Arguments: platform.MacroArguments{
						Type:   "constant",
						Values: platform.MacroConstantValues{},
					},
				},
			},
		},
		{
			name: "finding a non-existant macro",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id: idFromString(t, idA),
			},
			wants: wants{
				err:   kerrors.Errorf(kerrors.NotFound, "macro with ID %s not found", idA),
				macro: nil,
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		macro, err := s.FindMacroByID(ctx, tt.args.id)
		diffErrors(err, tt.wants.err, t)

		if diff := cmp.Diff(macro, tt.wants.macro); diff != "" {
			t.Fatalf("found unexpected macro -got/+want\ndiff %s", diff)
		}
	}
}

// UpdateMacro tests platform.MacroService UpdateMacro interface method
func UpdateMacro(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		id     platform.ID
		update *platform.MacroUpdate
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "updating a macro's name",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro-a",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "existing-macro-b",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idB),
				update: &platform.MacroUpdate{
					Name: "new-macro-b-name",
				},
			},
			wants: wants{
				err: nil,
				macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro-a",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
					&platform.Macro{
						ID:   idFromString(t, idB),
						Name: "new-macro-b-name",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
		{
			name: "updating a non-existant macro fails",
			fields: MacroFields{
				Macros: []*platform.Macro{},
			},
			args: args{
				id:     idFromString(t, idA),
				update: &platform.MacroUpdate{},
			},
			wants: wants{
				err:    fmt.Errorf("macro with ID %s not found", idA),
				macros: []*platform.Macro{},
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		macro, err := s.UpdateMacro(ctx, tt.args.id, tt.args.update)
		diffErrors(err, tt.wants.err, t)

		if tt.args.update.Name != "" && macro.Name != tt.args.update.Name {
			t.Fatalf("macro name not updated")
		}

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

// DeleteMacro tests platform.MacroService DeleteMacro interface method
func DeleteMacro(init func(MacroFields, *testing.T) (platform.MacroService, func()), t *testing.T) {
	type args struct {
		id platform.ID
	}
	type wants struct {
		err    error
		macros []*platform.Macro
	}

	tests := []struct {
		name   string
		fields MacroFields
		args   args
		wants  wants
	}{
		{
			name: "deleting a macro",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idA),
			},
			wants: wants{
				err:    nil,
				macros: []*platform.Macro{},
			},
		},
		{
			name: "deleting a macro that doesn't exist",
			fields: MacroFields{
				Macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
			args: args{
				id: idFromString(t, idB),
			},
			wants: wants{
				err: kerrors.Errorf(kerrors.NotFound, "macro with ID %s not found", idB),
				macros: []*platform.Macro{
					&platform.Macro{
						ID:   idFromString(t, idA),
						Name: "existing-macro",
						Arguments: platform.MacroArguments{
							Type:   "constant",
							Values: platform.MacroConstantValues{},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		s, done := init(tt.fields, t)
		defer done()
		ctx := context.TODO()

		err := s.DeleteMacro(ctx, tt.args.id)
		defer s.PutMacro(ctx, &platform.Macro{
			ID: tt.args.id,
		})
		diffErrors(err, tt.wants.err, t)

		macros, err := s.FindMacros(ctx)
		if err != nil {
			t.Fatalf("failed to retrieve macros: %v", err)
		}
		if diff := cmp.Diff(macros, tt.wants.macros, macroCmpOptions...); diff != "" {
			t.Fatalf("found unexpected macros -got/+want\ndiff %s", diff)
		}
	}
}

func diffErrors(actual, expected error, t *testing.T) {
	if expected == nil && actual != nil {
		t.Fatalf("unexpected error %q", actual.Error())
	}

	if expected != nil && actual == nil {
		t.Fatalf("expected error %q but received nil", expected.Error())
	}

	if expected != nil && actual != nil && expected.Error() != actual.Error() {
		t.Fatalf("expected error %q but received error %q", expected.Error(), actual.Error())
	}
}
<|endoftext|>


<commit_before>package scard

import (
	"fmt"
	"syscall"
	"unsafe"
)

var (
	modwinscard = syscall.NewLazyDLL("winscard.dll")

	procEstablishContext = modwinscard.NewProc("SCardEstablishContext")
	procReleaseContext   = modwinscard.NewProc("SCardReleaseContext")
	procIsValidContext   = modwinscard.NewProc("SCardIsValidContext")
	procCancel           = modwinscard.NewProc("SCardCancel")
	procListReaders      = modwinscard.NewProc("SCardListReadersW")
	procListReaderGroups = modwinscard.NewProc("SCardListReaderGroupsW")
	procGetStatusChange  = modwinscard.NewProc("SCardGetStatusChangeW")
	procConnect          = modwinscard.NewProc("SCardConnectW")
	procDisconnect       = modwinscard.NewProc("SCardDisconnect")
	procReconnect        = modwinscard.NewProc("SCardReconnect")
	procBeginTransaction = modwinscard.NewProc("SCardBeginTransaction")
	procEndTransaction   = modwinscard.NewProc("SCardEndTransaction")
	procStatus           = modwinscard.NewProc("SCardStatusW")
	procTransmit         = modwinscard.NewProc("SCardTransmit")
	procControl          = modwinscard.NewProc("SCardControl")
	procGetAttrib        = modwinscard.NewProc("SCardGetAttrib")
	procSetAttrib        = modwinscard.NewProc("SCardSetAttrib")

	dataT0Pci = modwinscard.NewProc("g_rgSCardT0Pci")
	dataT1Pci = modwinscard.NewProc("g_rgSCardT1Pci")
)

var scardIoReqT0 uintptr
var scardIoReqT1 uintptr

func init() {
	if err := dataT0Pci.Find(); err != nil {
		panic(err)
	}
	scardIoReqT0 = dataT0Pci.Addr()
	if err := dataT1Pci.Find(); err != nil {
		panic(err)
	}
	scardIoReqT1 = dataT1Pci.Addr()
}

func (e Error) Error() string {
	err := syscall.Errno(e)
	return fmt.Sprintf("scard: error(%x): %s", uintptr(e), err.Error())
}

func scardEstablishContext(scope uint32, reserved1, reserved2 uintptr) (uintptr, Error) {
	var ctx uintptr
	r, _, _ := procEstablishContext.Call(uintptr(scope), reserved1, reserved2, uintptr(unsafe.Pointer(&ctx)))
	return ctx, Error(r)
}

func scardIsValidContext(ctx uintptr) Error {
	r, _, _ := procIsValidContext.Call(ctx)
	return Error(r)
}

func scardCancel(ctx uintptr) Error {
	r, _, _ := procCancel.Call(ctx)
	return Error(r)
}

func scardReleaseContext(ctx uintptr) Error {
	r, _, _ := procReleaseContext.Call(ctx)
	return Error(r)
}

func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
	dwBufLen := uint32(bufLen)
	r, _, _ := procListReaders.Call(ctx, uintptr(groups), uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
	return dwBufLen, Error(r)
}

func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
	dwBufLen := uint32(bufLen)
	r, _, _ := procListReaderGroups.Call(ctx, uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
	return dwBufLen, Error(r)
}

func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
	r, _, _ := procGetStatusChange.Call(ctx, uintptr(timeout), uintptr(unsafe.Pointer(&states[0])), uintptr(len(states)))
	return Error(r)
}

func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
	var handle uintptr
	var activeProto uint32

	r, _, _ := procConnect.Call(ctx, uintptr(reader), uintptr(shareMode), uintptr(proto), uintptr(unsafe.Pointer(&handle)), uintptr(unsafe.Pointer(&activeProto)))

	return handle, Protocol(activeProto), Error(r)
}

func scardDisconnect(card uintptr, d Disposition) Error {
	r, _, _ := procDisconnect.Call(card, uintptr(d))
	return Error(r)
}

func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
	var activeProtocol uint32
	r, _, _ := procReconnect.Call(card, uintptr(mode), uintptr(proto), uintptr(disp), uintptr(unsafe.Pointer(&activeProtocol)))
	return Protocol(activeProtocol), Error(r)
}

func scardBeginTransaction(card uintptr) Error {
	r, _, _ := procBeginTransaction.Call(card)
	return Error(r)
}

func scardEndTransaction(card uintptr, disp Disposition) Error {
	r, _, _ := procEndTransaction.Call(card, uintptr(disp))
	return Error(r)
}

func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
	var state, proto uint32
	var atr [maxAtrSize]byte
	var atrLen = uint32(len(atr))

	reader := make(strbuf, maxReadername+1)
	readerLen := uint32(len(reader))

	r, _, _ := procStatus.Call(card, uintptr(reader.ptr()), uintptr(unsafe.Pointer(&readerLen)), uintptr(unsafe.Pointer(&state)), uintptr(unsafe.Pointer(&proto)), uintptr(unsafe.Pointer(&atr[0])), uintptr(unsafe.Pointer(&atrLen)))

	return decodestr(reader[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
}

func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
	var sendpci uintptr
	var rspLen = uint32(len(rsp))

	switch proto {
	case ProtocolT0:
		sendpci = scardIoReqT0
	case ProtocolT1:
		sendpci = scardIoReqT1
	default:
		panic("unknown protocol")
	}

	r, _, _ := procTransmit.Call(card, sendpci, uintptr(unsafe.Pointer(&cmd[0])), uintptr(len(cmd)), uintptr(0), uintptr(unsafe.Pointer(&rsp[0])), uintptr(unsafe.Pointer(&rspLen)))

	return rspLen, Error(r)
}

func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
	var ptrIn uintptr
	var outLen = uint32(len(out))

	if len(in) != 0 {
		ptrIn = uintptr(unsafe.Pointer(&in[0]))
	}

	r, _, _ := procControl.Call(card, uintptr(ioctl), ptrIn, uintptr(len(in)), uintptr(unsafe.Pointer(&out[0])), uintptr(len(out)), uintptr(unsafe.Pointer(&outLen)))
	return outLen, Error(r)
}

func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
	var ptr uintptr

	if len(buf) != 0 {
		ptr = uintptr(unsafe.Pointer(&buf[0]))
	}

	bufLen := uint32(len(buf))
	r, _, _ := procGetAttrib.Call(card, uintptr(id), ptr, uintptr(unsafe.Pointer(&bufLen)))

	return bufLen, Error(r)
}

func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
	r, _, _ := procSetAttrib.Call(card, uintptr(id), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
	return Error(r)
}
/*
// wraps SCardEstablishContext
func EstablishContext() (*Context, error) {
	var ctx Context

	r, _, _ := procEstablishContext.Call(2, uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&ctx.ctx)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	return &ctx, nil
}

// wraps SCardIsValidContext
func (ctx *Context) IsValid() (bool, error) {
	r, _, _ := procIsValidContext.Call(ctx.ctx)
	if Error(r) != ErrSuccess {
		return false, Error(r)
	}
	return true, nil
}

// wraps SCardCancel
func (ctx *Context) Cancel() error {
	r, _, _ := procCancel.Call(ctx.ctx)
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}

// wraps SCardReleaseContext
func (ctx *Context) Release() error {
	r, _, _ := procReleaseContext.Call(uintptr(ctx.ctx))
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}

// wraps SCardListReaders
func (ctx *Context) ListReaders() ([]string, error) {
	var needed uintptr

	r, _, _ := procListReaders.Call(
		ctx.ctx,
		0,
		0,
		uintptr(unsafe.Pointer(&needed)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	data := make(strbuf, needed)
	r, _, _ = procListReaders.Call(
		ctx.ctx,
		0,
		uintptr(data.ptr()),
		uintptr(unsafe.Pointer(&needed)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	return decodemstr(data[:needed]), nil
}

// wraps SCardListReaderGroups
func (ctx *Context) ListReaderGroups() ([]string, error) {
	var needed uintptr

	r, _, _ := procListReaderGroups.Call(
		ctx.ctx,
		0,
		uintptr(unsafe.Pointer(&needed)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	data := make(strbuf, needed)
	r, _, _ = procListReaderGroups.Call(
		ctx.ctx,
		uintptr(data.ptr()),
		uintptr(unsafe.Pointer(&needed)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	return decodemstr(data[:needed]), nil
}

// wraps SCardGetStatusChange
func (ctx *Context) GetStatusChange(readerStates []ReaderState, timeout time.Duration) error {

	dwTimeout := durationToTimeout(timeout)
	crs := make([]scardReaderState, len(readerStates))

	for i := range readerStates {
		buf, err := encodestr(readerStates[i].Reader)
		if err != nil {
			return err
		}
		crs[i].szReader = uintptr(buf.ptr())
		crs[i].dwCurrentState = uint32(readerStates[i].CurrentState)
		crs[i].cbAtr = uint32(len(readerStates[i].Atr))
		copy(crs[i].rgbAtr[:], readerStates[i].Atr)
	}

	r, _, _ := procGetStatusChange.Call(
		ctx.ctx,
		uintptr(dwTimeout),
		uintptr(unsafe.Pointer(&crs[0])),
		uintptr(len(crs)))

	if Error(r) != ErrSuccess {
		return Error(r)
	}

	for i := range readerStates {
		readerStates[i].EventState = StateFlag(crs[i].dwEventState)
		if crs[i].cbAtr > 0 {
			readerStates[i].Atr = make([]byte, int(crs[i].cbAtr))
			copy(readerStates[i].Atr, crs[i].rgbAtr[:crs[i].cbAtr])
		}
	}

	return nil
}

// wraps SCardConnect
func (ctx *Context) Connect(reader string, mode ShareMode, proto Protocol) (*Card, error) {
	var handle uintptr
	var activeProtocol uintptr

	creader, err := encodemstr(reader)
	if err != nil {
		return nil, err
	}

	r, _, _ := procConnect.Call(
		ctx.ctx,
		uintptr(creader.ptr()),
		uintptr(mode),
		uintptr(proto),
		uintptr(unsafe.Pointer(handle)),
		uintptr(unsafe.Pointer(activeProtocol)))

	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	return &Card{handle: handle, activeProtocol: Protocol(activeProtocol)}, nil
}

// wraps SCardDisconnect
func (card *Card) Disconnect(d Disposition) error {
	r, _, _ := procDisconnect.Call(card.handle, uintptr(d))
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}

// wraps SCardReconnect
func (card *Card) Reconnect(mode ShareMode, protocol Protocol, init Disposition) error {
	r, _, _ := procReconnect.Call(card.handle, uintptr(protocol), uintptr(init))
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}

// wraps SCardBeginTransaction
func (card *Card) BeginTransaction() error {
	r, _, _ := procBeginTransaction.Call(card.handle)
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}

// wraps SCardEndTransaction
func (card *Card) EndTransaction(d Disposition) error {
	r, _, _ := procEndTransaction.Call(card.handle, uintptr(d))
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}

// wraps SCardStatus
func (card *Card) Status() (*CardStatus, error) {
	var state, proto uint32
	var atr [maxAtrSize]byte
	var atrLen = uint32(len(atr))

	reader := make(strbuf, maxReadername+1)
	readerLen := len(reader)

	r, _, _ := procStatus.Call(
		card.handle,
		uintptr(reader.ptr()),
		uintptr(unsafe.Pointer(&readerLen)),
		uintptr(unsafe.Pointer(&state)),
		uintptr(unsafe.Pointer(&proto)),
		uintptr(unsafe.Pointer(&atr[0])),
		uintptr(unsafe.Pointer(&atrLen)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	reader = reader[:readerLen]

	status := &CardStatus{
		Reader:         decodestr(reader),
		State:          State(state),
		ActiveProtocol: Protocol(proto),
		Atr:            atr[0:atrLen],
	}

	return status, nil
}

// wraps SCardTransmit
func (card *Card) Transmit(cmd []byte) ([]byte, error) {
	var sendpci uintptr

	switch card.activeProtocol {
	case ProtocolT0:
		sendpci = scardIoReqT0
	case ProtocolT1:
		sendpci = scardIoReqT1
	default:
		panic("unknown protocol")
	}

	var recv [maxBufferSizeExtended]byte
	var recvlen = uint32(len(recv))

	r, _, _ := procTransmit.Call(card.handle,
		sendpci,
		uintptr(unsafe.Pointer(&cmd[0])),
		uintptr(len(cmd)),
		0,
		uintptr(unsafe.Pointer(&recv[0])),
		uintptr(unsafe.Pointer(&recvlen)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	rsp := make([]byte, recvlen)
	copy(rsp, recv[0:recvlen])

	return rsp, nil
}

// wraps SCardControl
func (card *Card) Control(ctrl uint32, cmd []byte) ([]byte, error) {
	var recv [0xffff]byte
	var recvlen uintptr
	var r uintptr

	if len(cmd) == 0 {
		r, _, _ = procControl.Call(
			card.handle,
			uintptr(ctrl),
			0,
			0,
			uintptr(unsafe.Pointer(&recv[0])),
			uintptr(len(recv)),
			uintptr(unsafe.Pointer(&recvlen)))
	} else {
		r, _, _ = procControl.Call(
			card.handle,
			uintptr(ctrl),
			uintptr(unsafe.Pointer(&cmd[0])),
			uintptr(len(cmd)),
			uintptr(unsafe.Pointer(&recv[0])),
			uintptr(len(recv)),
			uintptr(unsafe.Pointer(&recvlen)))
	}
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	rsp := make([]byte, recvlen)
	copy(rsp, recv[0:recvlen])

	return rsp, nil
}

// wraps SCardGetAttrib
func (card *Card) GetAttrib(id Attrib) ([]byte, error) {
	var needed uintptr

	r, _, _ := procGetAttrib.Call(
		card.handle,
		uintptr(id),
		0,
		uintptr(unsafe.Pointer(&needed)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	var attrib = make([]byte, needed)

	r, _, _ = procGetAttrib.Call(
		card.handle,
		uintptr(id),
		uintptr(unsafe.Pointer(&attrib[0])),
		uintptr(unsafe.Pointer(&needed)))
	if Error(r) != ErrSuccess {
		return nil, Error(r)
	}

	return attrib[0:needed], nil
}

// wraps SCardSetAttrib
func (card *Card) SetAttrib(id Attrib, data []byte) error {
	r, _, _ := procSetAttrib.Call(
		card.handle,
		uintptr(id),
		uintptr(unsafe.Pointer(&data[0])),
		uintptr(len(data)))
	if Error(r) != ErrSuccess {
		return Error(r)
	}
	return nil
}
*/

type scardReaderState struct {
	szReader       uintptr
	pvUserData     uintptr
	dwCurrentState uint32
	dwEventState   uint32
	cbAtr          uint32
	rgbAtr         [36]byte
}

func (rs *ReaderState) toSys() (scardReaderState, error) {
	var sys scardReaderState
	creader, err := encodestr(rs.Reader)
	if err != nil {
		return scardReaderState{}, err
	}
	sys.szReader = uintptr(creader.ptr())
	sys.dwCurrentState = uint32(rs.CurrentState)
	sys.cbAtr = uint32(len(rs.Atr))
	copy(sys.rgbAtr[:], rs.Atr)
	return sys, nil
}

func (rs *ReaderState) update(sys *scardReaderState) {
	rs.EventState = StateFlag(sys.dwEventState)
	if sys.cbAtr > 0 {
		rs.Atr = make([]byte, int(sys.cbAtr))
		copy(rs.Atr, sys.rgbAtr[:])
	}
}

type strbuf []uint16

func encodestr(s string) (strbuf, error) {
	utf16, err := syscall.UTF16FromString(s)
	return strbuf(utf16), err
}

func decodestr(buf strbuf) string {
	return syscall.UTF16ToString(buf)
}
<commit_msg>remove unused code<commit_after>package scard

import (
	"fmt"
	"syscall"
	"unsafe"
)

var (
	modwinscard = syscall.NewLazyDLL("winscard.dll")

	procEstablishContext = modwinscard.NewProc("SCardEstablishContext")
	procReleaseContext   = modwinscard.NewProc("SCardReleaseContext")
	procIsValidContext   = modwinscard.NewProc("SCardIsValidContext")
	procCancel           = modwinscard.NewProc("SCardCancel")
	procListReaders      = modwinscard.NewProc("SCardListReadersW")
	procListReaderGroups = modwinscard.NewProc("SCardListReaderGroupsW")
	procGetStatusChange  = modwinscard.NewProc("SCardGetStatusChangeW")
	procConnect          = modwinscard.NewProc("SCardConnectW")
	procDisconnect       = modwinscard.NewProc("SCardDisconnect")
	procReconnect        = modwinscard.NewProc("SCardReconnect")
	procBeginTransaction = modwinscard.NewProc("SCardBeginTransaction")
	procEndTransaction   = modwinscard.NewProc("SCardEndTransaction")
	procStatus           = modwinscard.NewProc("SCardStatusW")
	procTransmit         = modwinscard.NewProc("SCardTransmit")
	procControl          = modwinscard.NewProc("SCardControl")
	procGetAttrib        = modwinscard.NewProc("SCardGetAttrib")
	procSetAttrib        = modwinscard.NewProc("SCardSetAttrib")

	dataT0Pci = modwinscard.NewProc("g_rgSCardT0Pci")
	dataT1Pci = modwinscard.NewProc("g_rgSCardT1Pci")
)

var scardIoReqT0 uintptr
var scardIoReqT1 uintptr

func init() {
	if err := dataT0Pci.Find(); err != nil {
		panic(err)
	}
	scardIoReqT0 = dataT0Pci.Addr()
	if err := dataT1Pci.Find(); err != nil {
		panic(err)
	}
	scardIoReqT1 = dataT1Pci.Addr()
}

func (e Error) Error() string {
	err := syscall.Errno(e)
	return fmt.Sprintf("scard: error(%x): %s", uintptr(e), err.Error())
}

func scardEstablishContext(scope uint32, reserved1, reserved2 uintptr) (uintptr, Error) {
	var ctx uintptr
	r, _, _ := procEstablishContext.Call(uintptr(scope), reserved1, reserved2, uintptr(unsafe.Pointer(&ctx)))
	return ctx, Error(r)
}

func scardIsValidContext(ctx uintptr) Error {
	r, _, _ := procIsValidContext.Call(ctx)
	return Error(r)
}

func scardCancel(ctx uintptr) Error {
	r, _, _ := procCancel.Call(ctx)
	return Error(r)
}

func scardReleaseContext(ctx uintptr) Error {
	r, _, _ := procReleaseContext.Call(ctx)
	return Error(r)
}

func scardListReaders(ctx uintptr, groups, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
	dwBufLen := uint32(bufLen)
	r, _, _ := procListReaders.Call(ctx, uintptr(groups), uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
	return dwBufLen, Error(r)
}

func scardListReaderGroups(ctx uintptr, buf unsafe.Pointer, bufLen uint32) (uint32, Error) {
	dwBufLen := uint32(bufLen)
	r, _, _ := procListReaderGroups.Call(ctx, uintptr(buf), uintptr(unsafe.Pointer(&dwBufLen)))
	return dwBufLen, Error(r)
}

func scardGetStatusChange(ctx uintptr, timeout uint32, states []scardReaderState) Error {
	r, _, _ := procGetStatusChange.Call(ctx, uintptr(timeout), uintptr(unsafe.Pointer(&states[0])), uintptr(len(states)))
	return Error(r)
}

func scardConnect(ctx uintptr, reader unsafe.Pointer, shareMode ShareMode, proto Protocol) (uintptr, Protocol, Error) {
	var handle uintptr
	var activeProto uint32

	r, _, _ := procConnect.Call(ctx, uintptr(reader), uintptr(shareMode), uintptr(proto), uintptr(unsafe.Pointer(&handle)), uintptr(unsafe.Pointer(&activeProto)))

	return handle, Protocol(activeProto), Error(r)
}

func scardDisconnect(card uintptr, d Disposition) Error {
	r, _, _ := procDisconnect.Call(card, uintptr(d))
	return Error(r)
}

func scardReconnect(card uintptr, mode ShareMode, proto Protocol, disp Disposition) (Protocol, Error) {
	var activeProtocol uint32
	r, _, _ := procReconnect.Call(card, uintptr(mode), uintptr(proto), uintptr(disp), uintptr(unsafe.Pointer(&activeProtocol)))
	return Protocol(activeProtocol), Error(r)
}

func scardBeginTransaction(card uintptr) Error {
	r, _, _ := procBeginTransaction.Call(card)
	return Error(r)
}

func scardEndTransaction(card uintptr, disp Disposition) Error {
	r, _, _ := procEndTransaction.Call(card, uintptr(disp))
	return Error(r)
}

func scardCardStatus(card uintptr) (string, State, Protocol, []byte, Error) {
	var state, proto uint32
	var atr [maxAtrSize]byte
	var atrLen = uint32(len(atr))

	reader := make(strbuf, maxReadername+1)
	readerLen := uint32(len(reader))

	r, _, _ := procStatus.Call(card, uintptr(reader.ptr()), uintptr(unsafe.Pointer(&readerLen)), uintptr(unsafe.Pointer(&state)), uintptr(unsafe.Pointer(&proto)), uintptr(unsafe.Pointer(&atr[0])), uintptr(unsafe.Pointer(&atrLen)))

	return decodestr(reader[:readerLen]), State(state), Protocol(proto), atr[:atrLen], Error(r)
}

func scardTransmit(card uintptr, proto Protocol, cmd []byte, rsp []byte) (uint32, Error) {
	var sendpci uintptr
	var rspLen = uint32(len(rsp))

	switch proto {
	case ProtocolT0:
		sendpci = scardIoReqT0
	case ProtocolT1:
		sendpci = scardIoReqT1
	default:
		panic("unknown protocol")
	}

	r, _, _ := procTransmit.Call(card, sendpci, uintptr(unsafe.Pointer(&cmd[0])), uintptr(len(cmd)), uintptr(0), uintptr(unsafe.Pointer(&rsp[0])), uintptr(unsafe.Pointer(&rspLen)))

	return rspLen, Error(r)
}

func scardControl(card uintptr, ioctl uint32, in, out []byte) (uint32, Error) {
	var ptrIn uintptr
	var outLen = uint32(len(out))

	if len(in) != 0 {
		ptrIn = uintptr(unsafe.Pointer(&in[0]))
	}

	r, _, _ := procControl.Call(card, uintptr(ioctl), ptrIn, uintptr(len(in)), uintptr(unsafe.Pointer(&out[0])), uintptr(len(out)), uintptr(unsafe.Pointer(&outLen)))
	return outLen, Error(r)
}

func scardGetAttrib(card uintptr, id Attrib, buf []byte) (uint32, Error) {
	var ptr uintptr

	if len(buf) != 0 {
		ptr = uintptr(unsafe.Pointer(&buf[0]))
	}

	bufLen := uint32(len(buf))
	r, _, _ := procGetAttrib.Call(card, uintptr(id), ptr, uintptr(unsafe.Pointer(&bufLen)))

	return bufLen, Error(r)
}

func scardSetAttrib(card uintptr, id Attrib, buf []byte) Error {
	r, _, _ := procSetAttrib.Call(card, uintptr(id), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
	return Error(r)
}

type scardReaderState struct {
	szReader       uintptr
	pvUserData     uintptr
	dwCurrentState uint32
	dwEventState   uint32
	cbAtr          uint32
	rgbAtr         [36]byte
}

func (rs *ReaderState) toSys() (scardReaderState, error) {
	var sys scardReaderState
	creader, err := encodestr(rs.Reader)
	if err != nil {
		return scardReaderState{}, err
	}
	sys.szReader = uintptr(creader.ptr())
	sys.dwCurrentState = uint32(rs.CurrentState)
	sys.cbAtr = uint32(len(rs.Atr))
	copy(sys.rgbAtr[:], rs.Atr)
	return sys, nil
}

func (rs *ReaderState) update(sys *scardReaderState) {
	rs.EventState = StateFlag(sys.dwEventState)
	if sys.cbAtr > 0 {
		rs.Atr = make([]byte, int(sys.cbAtr))
		copy(rs.Atr, sys.rgbAtr[:])
	}
}

type strbuf []uint16

func encodestr(s string) (strbuf, error) {
	utf16, err := syscall.UTF16FromString(s)
	return strbuf(utf16), err
}

func decodestr(buf strbuf) string {
	return syscall.UTF16ToString(buf)
}
<|endoftext|>