<commit_before>package vdf_test

import (
	"reflect"
	"strings"
	"testing"

	"github.com/andygrunwald/vdf"
)

// Ensure the parser can parse strings into Statement ASTs.
func TestParser_ParseStatement(t *testing.T) {
	var tests = []struct {
		s    string
		m map[string]interface{}
		err  error
	}{
		// Single field statement
		{
			s: `"Example"
{
	"TimeNextStatsReport"      "1234567890"
	"ContentStatsID"           "-7123456789012345678"
}`,
			m: map[string]interface{}{
				"Example": map[string]interface{}{
					"TimeNextStatsReport": "1234567890",
					"ContentStatsID": "-7123456789012345678",
				},
			},
		},
		{
			s: `"Root"
{
 "attr1"       "hey-ho"
 "attr2"       "ho-hey"
 "map1"
 {
   "foo"       "Q79v5tbar"
 }
 "data"
 {
   "val"       "1"
   "map"       "2"
   "player"    "3"
 }
}`,
			m: map[string]interface{}{
				"Root": map[string]interface{}{
					"attr1": "hey-ho",
					"attr2": "ho-hey",
					"map1": map[string]interface{}{
						"foo": "Q79v5tbar",
					},
					"data": map[string]interface{}{
						"val": "1",
						"map": "2",
						"player": "3",
					},
				},
			},
		},
		{
			s: `"Root"
{
 attr1       "hey-ho"
 "attr2"       ho
 "map1"
 {
   "foo"       "Q79v5tbar"
 }
 "data"
 {
   "v\\al"       "1"
   "map"       "2"
   "pl\"ayer"    "3"
 }
}`,
			m: map[string]interface{}{
				"Root": map[string]interface{}{
					"attr1": "hey-ho",
					"attr2": "ho",
					"map1": map[string]interface{}{
						"foo": "Q79v5tbar",
					},
					"data": map[string]interface{}{
						"v\\al": "1",
						"map": "2",
						"pl\"ayer": "3",
					},
				},
			},
		},
	}

	for i, tt := range tests {
		m, err := vdf.NewParser(strings.NewReader(tt.s)).Parse()
		if !reflect.DeepEqual(tt.err, (err)) {
			t.Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == nil && !reflect.DeepEqual(tt.m, m) {
			t.Errorf("%d. %q\n\nparse mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.m, m)
		}
	}
}<commit_msg>go fmt<commit_after>package vdf_test

import (
	"reflect"
	"strings"
	"testing"

	"github.com/andygrunwald/vdf"
)

// Ensure the parser can parse strings into Statement ASTs.
func TestParser_ParseStatement(t *testing.T) {
	var tests = []struct {
		s   string
		m   map[string]interface{}
		err error
	}{
		// Single field statement
		{
			s: `"Example"
{
	"TimeNextStatsReport"      "1234567890"
	"ContentStatsID"           "-7123456789012345678"
}`,
			m: map[string]interface{}{
				"Example": map[string]interface{}{
					"TimeNextStatsReport": "1234567890",
					"ContentStatsID":      "-7123456789012345678",
				},
			},
		},
		{
			s: `"Root"
{
 "attr1"       "hey-ho"
 "attr2"       "ho-hey"
 "map1"
 {
   "foo"       "Q79v5tbar"
 }
 "data"
 {
   "val"       "1"
   "map"       "2"
   "player"    "3"
 }
}`,
			m: map[string]interface{}{
				"Root": map[string]interface{}{
					"attr1": "hey-ho",
					"attr2": "ho-hey",
					"map1": map[string]interface{}{
						"foo": "Q79v5tbar",
					},
					"data": map[string]interface{}{
						"val":    "1",
						"map":    "2",
						"player": "3",
					},
				},
			},
		},
		{
			s: `"Root"
{
 attr1       "hey-ho"
 "attr2"       ho
 "map1"
 {
   "foo"       "Q79v5tbar"
 }
 "data"
 {
   "v\\al"       "1"
   "map"       "2"
   "pl\"ayer"    "3"
 }
}`,
			m: map[string]interface{}{
				"Root": map[string]interface{}{
					"attr1": "hey-ho",
					"attr2": "ho",
					"map1": map[string]interface{}{
						"foo": "Q79v5tbar",
					},
					"data": map[string]interface{}{
						"v\\al":    "1",
						"map":      "2",
						"pl\"ayer": "3",
					},
				},
			},
		},
	}

	for i, tt := range tests {
		m, err := vdf.NewParser(strings.NewReader(tt.s)).Parse()
		if !reflect.DeepEqual(tt.err, (err)) {
			t.Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == nil && !reflect.DeepEqual(tt.m, m) {
			t.Errorf("%d. %q\n\nparse mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.m, m)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/veoo/go-smpp/smpp"
	"github.com/veoo/go-smpp/smpp/pdu"
	"github.com/veoo/go-smpp/smpp/pdu/pdufield"
	"github.com/veoo/go-smpp/smpp/pdu/pdutext"
)

func main() {

	toAddr := flag.String("to", "0", "to address")
	fromAddr := flag.String("from", "447779124374", "from address")
	user := flag.String("u", "0", "Username to use to connect.")
	password := flag.String("p", "0", "Password to connect.")
	address := flag.String("a", "0", "Address to connect to. host:port")

	flag.Parse()

	fmt.Println("to:", *toAddr)
	fmt.Println("from:", *fromAddr)

	text := strings.Join(flag.Args(), " ")

	fmt.Println("message:", text)

	if *toAddr == "0" {
		flag.Usage()
		os.Exit(1)
	}

	deliverChan := make(chan bool)
	transceiverHandler := func(p pdu.Body) {
		fmt.Println("RECEIVED SOMETHING", p.Header().ID.String())
		switch p.Header().ID {
		case pdu.DeliverSMID:
			f := p.Fields()
			src := f[pdufield.SourceAddr]
			dst := f[pdufield.DestinationAddr]
			txt := f[pdufield.ShortMessage]
			fmt.Println("TLVs:", p.TLVFields())
			// fmt.Println(string(p.TLVFields()[pdufield.MessageStateOption].Bytes()))
			// fmt.Println(string(p.TLVFields()[pdufield.ReceiptedMessageID].Bytes()))
			log.Info(fmt.Sprintf("Client: (DeliverSMID) Short message from=%s to=%s: %s", src, dst, txt))
			deliverChan <- true
		}
	}

	transceiver := &smpp.Transceiver{
		Addr:        address,
		User:        user,
		Passwd:      password,
		Handler:     transceiverHandler,
		RespTimeout: 10 * time.Second,
	}

	connA := transceiver.Bind() // make persistent connection.
	defer transceiver.Close()
	go func() {
		for c := range connA {
			log.Info("SMPP connection status: ", c.Status(), c.Error())
		}
	}()

	log.Info("Running basic tests")

	time.Sleep(2 * time.Second)
	req := &smpp.ShortMessage{
		Src:      *fromAddr,
		Dst:      *toAddr,
		Text:     pdutext.UCS2(text),
		Register: smpp.FinalDeliveryReceipt,
	}
	sm, err := transceiver.SubmitLongMsg(req)
	if err != nil {
		log.Fatal("Error:", err)
	}

	log.Info(sm)
	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(10 * time.Second)
		timeout <- true
	}()
	select {
	case <-deliverChan:
		return
	case <-timeout:
		log.Error("timed out waiting for response")
	}
}
<commit_msg>Refactoring and adding signal handling, currently untested<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/veoo/go-smpp/smpp"
	"github.com/veoo/go-smpp/smpp/pdu"
	"github.com/veoo/go-smpp/smpp/pdu/pdufield"
	"github.com/veoo/go-smpp/smpp/pdu/pdutext"
)

func main() {

	// implement toml config reading here

	transceiverHandler := func(p pdu.Body) {
		fmt.Println("RECEIVED SOMETHING", p.Header().ID.String())
		switch p.Header().ID {
		case pdu.DeliverSMID:
			f := p.Fields()
			src := f[pdufield.SourceAddr]
			dst := f[pdufield.DestinationAddr]
			txt := f[pdufield.ShortMessage]
			fmt.Println("TLVs:", p.TLVFields())
			fmt.Println(string(p.TLVFields()[pdufield.MessageStateOption].Bytes()))
			fmt.Println(string(p.TLVFields()[pdufield.ReceiptedMessageID].Bytes()))
			log.Info(fmt.Sprintf("Client: (DeliverSMID) Short message from=%s to=%s: %s", src, dst, txt))
		case pdu.EnquireLinkID:
			log.Info("Enquire link received, sending an enquire link resp")
			// TODO: Implement sending an enquire_link_resp here
		}
	}

	transceiver := &smpp.Transceiver{
		Addr:        address,
		User:        user,
		Passwd:      password,
		Handler:     transceiverHandler,
		RespTimeout: 10 * time.Second,
	}

	connA := transceiver.Bind() // make persistent connection.
	go func() {
		for c := range connA {
			log.Info("SMPP connection status: ", c.Status(), c.Error())
		}
	}()

	time.Sleep(2 * time.Second)
	req := &smpp.ShortMessage{
		Src:      *fromAddr,
		Dst:      *toAddr,
		Text:     pdutext.UCS2(text),
		Register: smpp.FinalDeliveryReceipt,
	}
	sm, err := transceiver.SubmitLongMsg(req)
	if err != nil {
		log.Fatal("Error:", err)
	}

	log.Info(sm)

	// Add signal interrupt here, currently need to confirm an unbund is sent
	// on CTRL - C
	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-sigs
		log.Info("Received interrupt or sigterm unbinding.")
		transceiver.Close()
		done <- true
	}()

	<-done
	log.Info("Exited cleanly, all done!")
}
<|endoftext|>


<commit_before>package wellington

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"regexp"
	"strings"
	"testing"
)

var rerandom *regexp.Regexp

var spritePreamble string

func init() {
	rerandom = regexp.MustCompile(`-\w{6}(?:\.(png|jpg))`)

	bs, err := ioutil.ReadFile("sass/_sprite.scss")
	if err != nil {
		log.Fatal(err)
	}
	spritePreamble = strings.TrimSuffix(string(bs), "\n")
}

func TestParserRelative(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "sprite.css",
		PartialMap: NewPartialMap(),
	}
	f, err := ioutil.ReadFile("sass/_sprite.scss")
	if err != nil {
		log.Fatal(err)
	}
	in := bytes.NewBuffer(f)
	in.WriteString(`div {
  background: image-url('img/139.png');
}`)
	e := fmt.Sprintf(`$rel: "..";
%s
div {
  background: image-url('img/139.png');
}`, spritePreamble)
	bs, _ := p.Start(in, "test")
	out := string(bs)

	if out != e {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, out)
	}

}

func TestParserImporter(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		Includes:   []string{"test/sass"},
		MainFile:   "import.css",
		PartialMap: NewPartialMap(),
	}

	bs, err := p.Start(fileReader("test/sass/import.scss"), "test/")
	if err != nil {
		log.Fatal(err)
	}
	output := string(bs)

	file, _ := ioutil.ReadFile("test/expected/import.parser")
	e := string(file)
	if e != output {
		t.Skipf("File output did not match, exp:\n%s\nwas:\n~%s~",
			e, output)
	}

	lines := map[int]string{
		0:  "../../sass/sprite",
		60: "var",
		71: "string",
	}
	errors := false
	for i, v := range lines {
		if v != p.Line[i] {
			t.Errorf("Invalid expected: %s, was: %s", lines[i], p.Line[i])
			errors = true
		}
	}
	if errors {
		fmt.Printf("% #v\n", p.Line)
	}
}

func TestParseSpriteArgs(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	in := bytes.NewBufferString(`$view_sprite: sprite-map("test/*.png",
  $normal-spacing: 2px,
  $normal-hover-spacing: 2px,
  $selected-spacing: 2px,
  $selected-hover-spacing: 2px);
  @include sprite-dimensions($view_sprite,140);
`)
	e := `$rel: ".";
$view_sprite: (); $view_sprite: map_merge($view_sprite,(139: (width: 96, height: 139, x: 0, y: 0, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(140: (width: 96, height: 140, x: 0, y: 139, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(pixel: (width: 1, height: 1, x: 0, y: 279, url: 'test-d01d06.png')));
  @include sprite-dimensions($view_sprite,140);
`
	bs, _ := p.Start(in, "")
	out := string(bs)

	if out != e {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, out)
	}
}

func TestParseInt(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	var (
		e, res string
	)
	r := bytes.NewBufferString(`p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`)
	bs, _ := p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`
	if e != res {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
	p = Parser{PartialMap: NewPartialMap()}
	r = bytes.NewBufferString(`$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`)
	bs, _ = p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`
	if e != res {
		t.Errorf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
}

func TestParseImage(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`$sprites: sprite-map("img/*.png");
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
$sprites: (); $sprites: map_merge($sprites,(139: (width: 96, height: 139, x: 0, y: 0, url: 'img/img-554064.png'))); $sprites: map_merge($sprites,(140: (width: 96, height: 140, x: 0, y: 139, url: 'img/img-554064.png')));
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`; e != out {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
}

func TestParseImageUrl(t *testing.T) {

	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`background: image-url('test/140.png');`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
background: image-url('test/140.png');`; e != out {
		t.Skipf("mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
	log.SetOutput(os.Stdout)
}

func TestParseLookupFile(t *testing.T) {

	p := Parser{
		BuildDir: "test/build",
		Includes: []string{"test/sass"},
	}
	in := bytes.NewBufferString(`div {
  background: image-url('test/140.png');
}
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3:  "mixin", // Injected mixin, perhaps we need a better name than top level file
		4:  "mixin",
		5:  "mixin",
		6:  "string:1",
		7:  "string:2",
		8:  "string:3",
		9:  "string:4",
		10: "string:5",
		11: "string:6",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}

}

func TestParseLookupImport(t *testing.T) {
	p := NewParser()
	p.BuildDir = "test/build"
	p.Includes = []string{"test/sass"}

	in := bytes.NewBufferString(`@import "file";
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3: "mixin", // Injected mixin, perhaps we need a better name than top level file
		4: "mixin",
		5: "mixin",
		6: "file:1",
		7: "file:2",
		8: "file:3",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}

	smap := [...]string{
		9:  "string:2",
		10: "string:3",
		11: "string:4",
		12: "string:5",
	}

	for i := range smap {
		if smap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != smap[i] {
			t.Skipf("%2d got: %s wanted: %s", i, s, smap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}
}

func TestLoadAndBuild(t *testing.T) {

	err := LoadAndBuild("test", &BuildArgs{}, NewPartialMap())
	if err != nil {
		t.Error(err)
	}

}
<commit_msg>LoadAndBuild test<commit_after>package wellington

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"

	"regexp"
	"strings"
	"testing"
)

var rerandom *regexp.Regexp

var spritePreamble string

func init() {
	rerandom = regexp.MustCompile(`-\w{6}(?:\.(png|jpg))`)

	bs, err := ioutil.ReadFile("sass/_sprite.scss")
	if err != nil {
		log.Fatal(err)
	}
	spritePreamble = strings.TrimSuffix(string(bs), "\n")
}

func TestParserRelative(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "sprite.css",
		PartialMap: NewPartialMap(),
	}
	f, err := ioutil.ReadFile("sass/_sprite.scss")
	if err != nil {
		log.Fatal(err)
	}
	in := bytes.NewBuffer(f)
	in.WriteString(`div {
  background: image-url('img/139.png');
}`)
	e := fmt.Sprintf(`$rel: "..";
%s
div {
  background: image-url('img/139.png');
}`, spritePreamble)
	bs, _ := p.Start(in, "test")
	out := string(bs)

	if out != e {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, out)
	}

}

func TestParserImporter(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		Includes:   []string{"test/sass"},
		MainFile:   "import.css",
		PartialMap: NewPartialMap(),
	}

	bs, err := p.Start(fileReader("test/sass/import.scss"), "test/")
	if err != nil {
		log.Fatal(err)
	}
	output := string(bs)

	file, _ := ioutil.ReadFile("test/expected/import.parser")
	e := string(file)
	if e != output {
		t.Skipf("File output did not match, exp:\n%s\nwas:\n~%s~",
			e, output)
	}

	lines := map[int]string{
		0:  "../../sass/sprite",
		60: "var",
		71: "string",
	}
	errors := false
	for i, v := range lines {
		if v != p.Line[i] {
			t.Errorf("Invalid expected: %s, was: %s", lines[i], p.Line[i])
			errors = true
		}
	}
	if errors {
		fmt.Printf("% #v\n", p.Line)
	}
}

func TestParseSpriteArgs(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	in := bytes.NewBufferString(`$view_sprite: sprite-map("test/*.png",
  $normal-spacing: 2px,
  $normal-hover-spacing: 2px,
  $selected-spacing: 2px,
  $selected-hover-spacing: 2px);
  @include sprite-dimensions($view_sprite,140);
`)
	e := `$rel: ".";
$view_sprite: (); $view_sprite: map_merge($view_sprite,(139: (width: 96, height: 139, x: 0, y: 0, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(140: (width: 96, height: 140, x: 0, y: 139, url: 'test-d01d06.png'))); $view_sprite: map_merge($view_sprite,(pixel: (width: 1, height: 1, x: 0, y: 279, url: 'test-d01d06.png')));
  @include sprite-dimensions($view_sprite,140);
`
	bs, _ := p.Start(in, "")
	out := string(bs)

	if out != e {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, out)
	}
}

func TestParseInt(t *testing.T) {
	p := Parser{PartialMap: NewPartialMap()}
	var (
		e, res string
	)
	r := bytes.NewBufferString(`p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`)
	bs, _ := p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}`
	if e != res {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
	p = Parser{PartialMap: NewPartialMap()}
	r = bytes.NewBufferString(`$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`)
	bs, _ = p.Start(r, "")
	res = string(bs)

	e = `$rel: ".";
$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}`
	if e != res {
		t.Errorf("Mismatch expected:\n%s\nwas:\n%s", e, res)
	}
}

func TestParseImage(t *testing.T) {
	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`$sprites: sprite-map("img/*.png");
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
$sprites: (); $sprites: map_merge($sprites,(139: (width: 96, height: 139, x: 0, y: 0, url: 'img/img-554064.png'))); $sprites: map_merge($sprites,(140: (width: 96, height: 140, x: 0, y: 139, url: 'img/img-554064.png')));
$sfile: sprite-file($sprites, 139);
div {
    height: image-height(sprite-file($sprites, 139));
    width: image-width(test/139.png);
    url: sprite-file($sprites, 139);
}`; e != out {
		t.Skipf("Mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
}

func TestParseImageUrl(t *testing.T) {

	p := Parser{
		BuildDir:   "test/build",
		MainFile:   "test",
		PartialMap: NewPartialMap(),
	}
	in := bytes.NewBufferString(`background: image-url('test/140.png');`)
	bs, _ := p.Start(in, "")
	out := string(bs)

	if e := `$rel: "..";
background: image-url('test/140.png');`; e != out {
		t.Skipf("mismatch expected:\n%s\nwas:\n%s\n", e, out)
	}
	log.SetOutput(os.Stdout)
}

func TestParseLookupFile(t *testing.T) {

	p := Parser{
		BuildDir: "test/build",
		Includes: []string{"test/sass"},
	}
	in := bytes.NewBufferString(`div {
  background: image-url('test/140.png');
}
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3:  "mixin", // Injected mixin, perhaps we need a better name than top level file
		4:  "mixin",
		5:  "mixin",
		6:  "string:1",
		7:  "string:2",
		8:  "string:3",
		9:  "string:4",
		10: "string:5",
		11: "string:6",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}

}

func TestParseLookupImport(t *testing.T) {
	p := NewParser()
	p.BuildDir = "test/build"
	p.Includes = []string{"test/sass"}

	in := bytes.NewBufferString(`@import "file";
p {
  line-height: 2em;
  height: 1px;
}`)
	bs, err := p.Start(in, "")
	if err != nil {
		t.Error(err)
	}
	tmap := [...]string{
		3: "mixin", // Injected mixin, perhaps we need a better name than top level file
		4: "mixin",
		5: "mixin",
		6: "file:1",
		7: "file:2",
		8: "file:3",
	}

	for i := range tmap {
		if tmap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != tmap[i] {
			t.Errorf("%2d got: %s wanted: %s", i, s, tmap[i])
		}
	}

	smap := [...]string{
		9:  "string:2",
		10: "string:3",
		11: "string:4",
		12: "string:5",
	}

	for i := range smap {
		if smap[i] == "" {
			continue
		}
		if s := p.LookupFile(i); s != smap[i] {
			t.Skipf("%2d got: %s wanted: %s", i, s, smap[i])
		}
	}
	if t.Failed() {
		fmt.Printf("% #v\n", p.Line)
		lineArr := bytes.Split(bs, []byte("\n"))
		for i := range lineArr {
			fmt.Printf("%2d: %2d: %s\n", i+1-5, i+1, string(lineArr[i]))
		}
	}
}

func TestLoadAndBuild(t *testing.T) {
	oo := os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	err := LoadAndBuild("test/sass/file.scss", &BuildArgs{}, NewPartialMap())
	if err != nil {
		t.Error(err)
	}
	outC := make(chan string)
	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf.String()
	}()

	w.Close()
	os.Stdout = oo
	out := <-outC

	e := `div {
  color: black; }
Rebuilt: test/sass/file.scss
`
	if e != out {
		t.Errorf("got:\n%s\nwanted:\n%s", out, e)
	}
}
<|endoftext|>


<commit_before>package parser

var items = map[itemType]string{
	0: "itemVersion",
	1: "itemOperator",
	2: "itemSet",
	3: "itemRange",
	4: "itemError",
	5: "itemEOF",
}

var constraints = []string{
	"1.0 || >=2.5.0 || 5.0.0 - 7.2.3",
	"~1.2.3",
	"^4.5.2-alpha.1",
	"=2.3.2",
	"<=1.2.3",
	"5.3.5||4.3.5",
	"5.3.5 ||4.3.5",
	"5.3.5|| 4.3.5",
	"5.3.5 4.3.5",
	"M",
}

// func TestParser(t *testing.T) {
// 	for _, c := range constraints {
// 		_, ch := lex("test", c)
// 		for {
// 			s, ok := <-ch
// 			if ok != false {
// 				fmt.Printf("%v: '%v' \n", items[s.typ], s)
// 			} else {
// 				break
// 			}
// 		}
// 	}
// }

// Poor implementation, just for initial testing.
// func BenchmarkParser(b *testing.B) {
// 	const VERSION = "1.0 || >=2.5.0 || 5.0.0 - 7.2.3"
//
// 	b.ResetTimer()
// 	for n := 0; n < b.N; n++ {
// 		_, ch := lex("test", VERSION)
// 		for {
// 			_, ok := <-ch
// 			if ok == false {
// 				//fmt.Printf("%v: '%v' \n", items[s.typ], s)
// 				//} else {
// 				break
// 			}
// 		}
// 	}
// }
<commit_msg>Turned on test again.<commit_after>package parser

import (
	"fmt"
	"testing"
)

var items = map[itemType]string{
	0: "itemVersion",
	1: "itemOperator",
	2: "itemSet",
	3: "itemRange",
	4: "itemError",
	5: "itemEOF",
}

var constraints = []string{
	"1.0 || >=2.5.0 || 5.0.0 - 7.2.3",
	"~1.2.3",
	"^4.5.2-alpha.1",
	"=2.3.2",
	"<=1.2.3",
	"5.3.5||4.3.5",
	"5.3.5 ||4.3.5",
	"5.3.5|| 4.3.5",
	"5.3.5 4.3.5",
	"M",
}

func TestParser(t *testing.T) {
	for _, c := range constraints {
		_, ch := lex("test", c)
		for {
			s, ok := <-ch
			if ok != false {
				fmt.Printf("%v: '%v' \n", items[s.typ], s)
			} else {
				break
			}
		}
	}
}

// Poor implementation, just for initial testing.
func BenchmarkParser(b *testing.B) {
	const VERSION = "1.0 || >=2.5.0 || 5.0.0 - 7.2.3"

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		_, ch := lex("test", VERSION)
		for {
			_, ok := <-ch
			if ok == false {
				//fmt.Printf("%v: '%v' \n", items[s.typ], s)
				//} else {
				break
			}
		}
	}
}
<|endoftext|>


<commit_before>package parser

import (
	"go/ast"
	"go/token"
	"testing"

	"github.com/nordsieck/defect"
)

const (
	minimal = `package main
`
	comment = `// comment
package main
`
	comments = `// comment
package main

// foo
// bar
`
	hello = `package main

import "fmt"

func main() {
	fmt.Println("hello world")
}
`
)

func TestParseFile_Minimal(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", minimal)
	defect.Equal(t, err, nil)
	defect.DeepEqual(t, *file.File, ast.File{
		Package: token.Pos(1),
		Name:    &ast.Ident{NamePos: 9, Name: "main"},
		Scope:   &ast.Scope{Objects: map[string]*ast.Object{}},
	})
}

func TestParseFile_Comment(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", comment)
	defect.Equal(t, err, nil)
	comment := &ast.Comment{Slash: 1, Text: "// comment"}
	defect.DeepEqual(t, *file.File, ast.File{
		Doc:      &ast.CommentGroup{List: []*ast.Comment{comment}},
		Package:  token.Pos(12),
		Name:     &ast.Ident{NamePos: 20, Name: "main"},
		Scope:    &ast.Scope{Objects: map[string]*ast.Object{}},
		Comments: []*ast.CommentGroup{{List: []*ast.Comment{comment}}},
	})
}

func TestParseFile_Comments(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", comments)
	defect.Equal(t, err, nil)
	top := &ast.CommentGroup{List: []*ast.Comment{{Slash: 1, Text: "// comment"}}}
	next := &ast.CommentGroup{List: []*ast.Comment{
		{Slash: 26, Text: "// foo"},
		{Slash: 33, Text: "// bar"},
	}}

	defect.DeepEqual(t, *file.File, ast.File{
		Doc:      top,
		Package:  token.Pos(12),
		Name:     &ast.Ident{NamePos: 20, Name: "main"},
		Scope:    &ast.Scope{Objects: map[string]*ast.Object{}},
		Comments: []*ast.CommentGroup{top, next},
	})
}

func TestParseFile_Hello(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", hello)
	defect.Equal(t, err, nil)

	expectedDecl := &ast.BlockStmt{
		Lbrace: 41,
		List: []ast.Stmt{
			&ast.ExprStmt{
				X: &ast.CallExpr{
					Fun: &ast.SelectorExpr{
						X:   &ast.Ident{NamePos: 44, Name: "fmt"},
						Sel: &ast.Ident{NamePos: 48, Name: "Println"},
					},
					Lparen: 55,
					Args: []ast.Expr{&ast.BasicLit{
						ValuePos: 56,
						Kind:     token.STRING,
						Value:    `"hello world"`,
					}},
					Rparen: 69,
				},
			},
		},
		Rbrace: 71,
	}

	obj := &ast.Object{
		Kind: ast.Fun,
		Name: "main",
		Decl: expectedDecl,
	}

	fnDecl := &ast.FuncDecl{
		Name: &ast.Ident{Name: "main", NamePos: 34, Obj: obj},
		Type: &ast.FuncType{
			Func:   29,
			Params: &ast.FieldList{Opening: 38, Closing: 39},
		},
		Body: expectedDecl,
	}

	obj.Decl = fnDecl

	importSpec := &ast.ImportSpec{Path: &ast.BasicLit{
		ValuePos: 22,
		Kind:     token.STRING,
		Value:    `"fmt"`,
	}}

	genDecl := &ast.GenDecl{
		TokPos: 15,
		Tok:    token.IMPORT,
		Specs:  []ast.Spec{importSpec},
	}

	defect.DeepEqual(t, file.File, &ast.File{
		Package:    1,
		Name:       &ast.Ident{NamePos: 9, Name: "main"},
		Decls:      []ast.Decl{genDecl, fnDecl},
		Scope:      &ast.Scope{Objects: map[string]*ast.Object{"main": obj}},
		Imports:    []*ast.ImportSpec{importSpec},
		Unresolved: []*ast.Ident{{NamePos: 44, Name: "fmt"}},
	})
}
<commit_msg>Simple<commit_after>package parser

import (
	"go/ast"
	"go/token"
	"testing"

	"github.com/nordsieck/defect"
)

const (
	minimal = `package main
`
	comment = `// comment
package main
`
	comments = `// comment
package main

// foo
// bar
`
	simple = `package main

func main() {}
`
	hello = `package main

import "fmt"

func main() {
	fmt.Println("hello world")
}
`
)

func TestParseFile_Minimal(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", minimal)
	defect.Equal(t, err, nil)
	defect.DeepEqual(t, *file.File, ast.File{
		Package: token.Pos(1),
		Name:    &ast.Ident{NamePos: 9, Name: "main"},
		Scope:   &ast.Scope{Objects: map[string]*ast.Object{}},
	})
}

func TestParseFile_Comment(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", comment)
	defect.Equal(t, err, nil)
	comment := &ast.Comment{Slash: 1, Text: "// comment"}
	defect.DeepEqual(t, *file.File, ast.File{
		Doc:      &ast.CommentGroup{List: []*ast.Comment{comment}},
		Package:  token.Pos(12),
		Name:     &ast.Ident{NamePos: 20, Name: "main"},
		Scope:    &ast.Scope{Objects: map[string]*ast.Object{}},
		Comments: []*ast.CommentGroup{{List: []*ast.Comment{comment}}},
	})
}

func TestParseFile_Comments(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", comments)
	defect.Equal(t, err, nil)
	top := &ast.CommentGroup{List: []*ast.Comment{{Slash: 1, Text: "// comment"}}}
	next := &ast.CommentGroup{List: []*ast.Comment{
		{Slash: 26, Text: "// foo"},
		{Slash: 33, Text: "// bar"},
	}}

	defect.DeepEqual(t, *file.File, ast.File{
		Doc:      top,
		Package:  token.Pos(12),
		Name:     &ast.Ident{NamePos: 20, Name: "main"},
		Scope:    &ast.Scope{Objects: map[string]*ast.Object{}},
		Comments: []*ast.CommentGroup{top, next},
	})
}

func TestParseFile_Simple(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", simple)
	defect.Equal(t, err, nil)

	block := &ast.BlockStmt{Lbrace: 27, Rbrace: 28}
	obj := &ast.Object{Kind: ast.Fun, Name: "main", Decl: block}
	fnDecl := &ast.FuncDecl{
		Name: &ast.Ident{Name: "main", NamePos: 20, Obj: obj},
		Type: &ast.FuncType{
			Func:   15,
			Params: &ast.FieldList{Opening: 24, Closing: 25},
		},
		Body: block,
	}
	obj.Decl = fnDecl

	defect.DeepEqual(t, file.File, &ast.File{
		Package: 1,
		Name:    &ast.Ident{NamePos: 9, Name: "main"},
		Decls:   []ast.Decl{fnDecl},
		Scope:   &ast.Scope{Objects: map[string]*ast.Object{"main": obj}},
	})
}

func TestParseFile_Hello(t *testing.T) {
	fs := token.NewFileSet()
	file, err := ParseFile(fs, "a.go", hello)
	defect.Equal(t, err, nil)

	expectedDecl := &ast.BlockStmt{
		Lbrace: 41,
		List: []ast.Stmt{
			&ast.ExprStmt{
				X: &ast.CallExpr{
					Fun: &ast.SelectorExpr{
						X:   &ast.Ident{NamePos: 44, Name: "fmt"},
						Sel: &ast.Ident{NamePos: 48, Name: "Println"},
					},
					Lparen: 55,
					Args: []ast.Expr{&ast.BasicLit{
						ValuePos: 56,
						Kind:     token.STRING,
						Value:    `"hello world"`,
					}},
					Rparen: 69,
				},
			},
		},
		Rbrace: 71,
	}

	obj := &ast.Object{
		Kind: ast.Fun,
		Name: "main",
		Decl: expectedDecl,
	}

	fnDecl := &ast.FuncDecl{
		Name: &ast.Ident{Name: "main", NamePos: 34, Obj: obj},
		Type: &ast.FuncType{
			Func:   29,
			Params: &ast.FieldList{Opening: 38, Closing: 39},
		},
		Body: expectedDecl,
	}

	obj.Decl = fnDecl

	importSpec := &ast.ImportSpec{Path: &ast.BasicLit{
		ValuePos: 22,
		Kind:     token.STRING,
		Value:    `"fmt"`,
	}}

	genDecl := &ast.GenDecl{
		TokPos: 15,
		Tok:    token.IMPORT,
		Specs:  []ast.Spec{importSpec},
	}

	defect.DeepEqual(t, file.File, &ast.File{
		Package:    1,
		Name:       &ast.Ident{NamePos: 9, Name: "main"},
		Decls:      []ast.Decl{genDecl, fnDecl},
		Scope:      &ast.Scope{Objects: map[string]*ast.Object{"main": obj}},
		Imports:    []*ast.ImportSpec{importSpec},
		Unresolved: []*ast.Ident{{NamePos: 44, Name: "fmt"}},
	})
}
<|endoftext|>


<commit_before>package asciidocgo

import (
	"os"
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

func TestPathResolver(t *testing.T) {

	Convey("A pathResolver can be initialized", t, func() {

		Convey("By default, a pathResolver can be created", func() {
			So(NewPathResolver(0, ""), ShouldNotBeNil)
		})
		Convey("By default, a pathResolver has a system path separator", func() {
			So(NewPathResolver(0, "").FileSeparator(), ShouldEqual, os.PathSeparator)
			So(NewPathResolver('/', "").FileSeparator(), ShouldNotEqual, os.PathSeparator)
			So(NewPathResolver('/', "").FileSeparator(), ShouldEqual, '/')
		})

		Convey("By default, a pathResolver has a current working path", func() {
			pwd, err := os.Getwd()
			if err != nil {
				panic(err)
			}
			So(NewPathResolver(0, "").WorkingDir(), ShouldEqual, pwd)
			So(NewPathResolver(0, "C:\\").WorkingDir(), ShouldEqual, "C:\\")
			So(NewPathResolver(0, "test").WorkingDir(), ShouldEqual, pwd+string(os.PathSeparator)+"test")
			//So(NewPathResolver(0, "panicnoroot").WorkingDir(), ShouldEqual, pwd)

		})
		Convey("A pathResolver should not panic on getting pwd", func() {
			recovered := false
			defer func() {
				recover()
				recovered = true
				So(recovered, ShouldBeTrue)
			}()
			_ = NewPathResolver(0, "panic on os.Getwd")
		})
		Convey("A pathResolver should not panic on filepath.Abs", func() {
			recovered := false
			defer func() {
				recover()
				recovered = true
				So(recovered, ShouldBeTrue)
			}()
			_ = NewPathResolver(0, "panic on filepath.Abs")
		})
	})

	Convey("A pathResolver can test for a web path", t, func() {
		So(IsWebRoot(""), ShouldBeFalse)
		So(IsWebRoot("a"), ShouldBeFalse)
		So(IsWebRoot("\\a\\b/c"), ShouldBeFalse)
		So(IsWebRoot("/a/b/c"), ShouldBeTrue)
	})

	Convey("A pathResolver can replace backslash by slash", t, func() {
		So(Posixfy(""), ShouldEqual, "")
		So(Posixfy("a/b/c"), ShouldEqual, "a/b/c")
		So(Posixfy("a\\b\\c"), ShouldEqual, "a/b/c")
	})

	Convey("A pathResolver can test for root", t, func() {
		Convey("A Path starting with C:/ is root", func() {
			So(IsRoot(""), ShouldBeFalse)
			So(IsRoot("C:\\"), ShouldBeTrue)
			So(IsRoot("C:/"), ShouldBeTrue)
			So(IsRoot("C:\\a/b/"), ShouldBeTrue)
			So(IsRoot("c:/a/b/../c"), ShouldBeTrue)
			So(IsRoot("c:\\a/b/../c"), ShouldBeTrue)
		})
	})

	Convey("A pathResolver can test for web root", t, func() {
		Convey("A Path starting with / is web root", func() {
			So(IsWebRoot(""), ShouldBeFalse)
			So(IsWebRoot("C:\\"), ShouldBeFalse)
			So(IsWebRoot("\\"), ShouldBeFalse)
			So(IsWebRoot("/"), ShouldBeTrue)
			So(IsWebRoot("/a/b/"), ShouldBeTrue)
			So(IsWebRoot("/a\\b/./c"), ShouldBeTrue)
			So(IsWebRoot("/a/b/./c"), ShouldBeTrue)
		})
	})

	Convey("A pathResolver can expand a path", t, func() {
		Convey("empty path returns an empty string", func() {
			So(ExpandPath(""), ShouldEqual, "")
		})
		Convey("non-empty path returns an posix path", func() {
			So(ExpandPath("c:\\a/.\\b/../c"), ShouldEqual, "c:/a/b/../c")
		})
	})

	Convey("A pathResolver can partition a path", t, func() {
		pathSegments, root, posixPath := PartitionPath("", false)
		So(len(pathSegments), ShouldEqual, 0)
		So(root, ShouldEqual, "")
		So(posixPath, ShouldEqual, "")

		Convey("A Path starting with dot has a dot root", func() {
			pathSegments, root, posixPath := PartitionPath(".", false)
			So(len(pathSegments), ShouldEqual, 0)
			So(root, ShouldEqual, ".")
			So(posixPath, ShouldEqual, ".")

			pathSegments, root, posixPath = PartitionPath(".\\a/b", false)
			So(len(pathSegments), ShouldEqual, 2)
			So(root, ShouldEqual, ".")
			So(posixPath, ShouldEqual, "./a/b")

		})
		Convey("A Partition removes self-reference path", func() {
			pathSegments, root, posixPath := PartitionPath("a\\b/./c", false)
			So(len(pathSegments), ShouldEqual, 3)
			So(root, ShouldEqual, "")
			So(posixPath, ShouldEqual, "a/b/./c")

			pathSegments, root, posixPath = PartitionPath("C:/a\\b/./c", false)
			So(len(pathSegments), ShouldEqual, 3)
			So(root, ShouldEqual, "C:")
			So(posixPath, ShouldEqual, "C:/a/b/./c")

			pathSegments, root, posixPath = PartitionPath("/a\\b/./c", true)
			So(len(pathSegments), ShouldEqual, 2)
			So(root, ShouldEqual, "/a")
			So(posixPath, ShouldEqual, "/a/b/./c")
		})
		Convey("A Partition keep '..' paths", func() {
			pathSegments, root, posixPath = PartitionPath("a\\b/../c", true)
			So(len(pathSegments), ShouldEqual, 4)
			So(root, ShouldEqual, "")
			So(posixPath, ShouldEqual, "a/b/../c")

			pathSegments, root, posixPath = PartitionPath("\\a\\b/../c", true)
			So(len(pathSegments), ShouldEqual, 3)
			So(root, ShouldEqual, "/a")
			So(posixPath, ShouldEqual, "/a/b/../c")

			pathSegments, root, posixPath = PartitionPath("c:\\a\\b/../c", false)
			So(len(pathSegments), ShouldEqual, 4)
			So(root, ShouldEqual, "c:")
			So(posixPath, ShouldEqual, "c:/a/b/../c")
		})
	})

	Convey("A pathResolver can join a path", t, func() {
		Convey("No segment and empty root returns an empty string", func() {
			So(JoinPath(nil, ""), ShouldEqual, "")
		})
		Convey("Segments with no root returns an slash-separated segments", func() {
			So(JoinPath([]string{"a"}, ""), ShouldEqual, "a")
			So(JoinPath([]string{"a", "b"}, ""), ShouldEqual, "a/b")
			So(JoinPath([]string{"a", "b", "c"}, ""), ShouldEqual, "a/b/c")
		})
		Convey("Segments with root returns an root plus slash-separated segments", func() {
			So(JoinPath([]string{"a"}, "c:"), ShouldEqual, "c:/a")
			So(JoinPath([]string{"a", "b"}, "d:"), ShouldEqual, "d:/a/b")
			So(JoinPath([]string{"a", "b", "c"}, "e:"), ShouldEqual, "e:/a/b/c")
		})
	})

	Convey("A Partition can resolve a system path from the target and start paths", t, func() {
		pr := NewPathResolver(0, "C:/a/working/dir")
		Convey("A Non-absolute jail path should panic", func() {
			recovered := false
			defer func() {
				r := recover()
				recovered = true
				So(recovered, ShouldBeTrue)
				So(r, ShouldEqual, "Jail is not an absolute path: c")
			}()
			_ = pr.SystemPath("a", "b", "c", false, "")
		})
		Convey("A system path with no start resolves from the root", func() {
			So(pr.SystemPath("images", "", "", false, ""), ShouldEqual, "")
			So(pr.SystemPath("../images", "", "", false, ""), ShouldEqual, "")
			So(pr.SystemPath("/etc/images", "", "", false, ""), ShouldEqual, "")
		})
		Convey("Empty target segment and empty start and empty jail means working dir", func() {
			So(pr.SystemPath("", "", "", false, ""), ShouldEqual, "C:/a/working/dir")
		})
		Convey("Empty target segment, non-empty start and empty jail means expanded start path", func() {
			So(pr.SystemPath("", "C:\\start/../b", "", false, ""), ShouldEqual, "C:/start/../b")
		})
		/*
			resolver.system_path('images')
			    => '/path/to/docs/images'

			    resolver.system_path('../images')
			    => '/path/to/images'

			    resolver.system_path('/etc/images')
			    => '/etc/images'

			    resolver.system_path('images', '/etc')
			    => '/etc/images'

			    resolver.system_path('', '/etc/images')
			    => '/etc/images'

			    resolver.system_path(nil, nil, '/path/to/docs')
			    => '/path/to/docs'

			    resolver.system_path('..', nil, '/path/to/docs')
			    => '/path/to/docs'

			    resolver.system_path('../../../css', nil, '/path/to/docs')
			    => '/path/to/docs/css'

			    resolver.system_path('../../../css', '../../..', '/path/to/docs')
			    => '/path/to/docs/css'

			    resolver.system_path('..', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
			    => 'C:/data/docs'

			    resolver.system_path('..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
			    => 'C:/data/docs/css'

			    begin
			      resolver.system_path('../../../css', '../../..', '/path/to/docs', :recover => false)
			    rescue SecurityError => e
			      puts e.message
			    end
			    => 'path ../../../../../../css refers to location outside jail: /path/to/docs (disallowed in safe mode)'

			    resolver.system_path('/path/to/docs/images', nil, '/path/to/docs')
			    => '/path/to/docs/images'

			    begin
			      resolver.system_path('images', '/etc', '/path/to/docs')
			    rescue SecurityError => e
			      puts e.message
			    end
			    => Start path /etc is outside of jail: /path/to/docs'
		*/
	})
}
<commit_msg>Documente missing implementation for Empty target segment, non-empty non-root start<commit_after>package asciidocgo

import (
	"os"
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

func TestPathResolver(t *testing.T) {

	Convey("A pathResolver can be initialized", t, func() {

		Convey("By default, a pathResolver can be created", func() {
			So(NewPathResolver(0, ""), ShouldNotBeNil)
		})
		Convey("By default, a pathResolver has a system path separator", func() {
			So(NewPathResolver(0, "").FileSeparator(), ShouldEqual, os.PathSeparator)
			So(NewPathResolver('/', "").FileSeparator(), ShouldNotEqual, os.PathSeparator)
			So(NewPathResolver('/', "").FileSeparator(), ShouldEqual, '/')
		})

		Convey("By default, a pathResolver has a current working path", func() {
			pwd, err := os.Getwd()
			if err != nil {
				panic(err)
			}
			So(NewPathResolver(0, "").WorkingDir(), ShouldEqual, pwd)
			So(NewPathResolver(0, "C:\\").WorkingDir(), ShouldEqual, "C:\\")
			So(NewPathResolver(0, "test").WorkingDir(), ShouldEqual, pwd+string(os.PathSeparator)+"test")
			//So(NewPathResolver(0, "panicnoroot").WorkingDir(), ShouldEqual, pwd)

		})
		Convey("A pathResolver should not panic on getting pwd", func() {
			recovered := false
			defer func() {
				recover()
				recovered = true
				So(recovered, ShouldBeTrue)
			}()
			_ = NewPathResolver(0, "panic on os.Getwd")
		})
		Convey("A pathResolver should not panic on filepath.Abs", func() {
			recovered := false
			defer func() {
				recover()
				recovered = true
				So(recovered, ShouldBeTrue)
			}()
			_ = NewPathResolver(0, "panic on filepath.Abs")
		})
	})

	Convey("A pathResolver can test for a web path", t, func() {
		So(IsWebRoot(""), ShouldBeFalse)
		So(IsWebRoot("a"), ShouldBeFalse)
		So(IsWebRoot("\\a\\b/c"), ShouldBeFalse)
		So(IsWebRoot("/a/b/c"), ShouldBeTrue)
	})

	Convey("A pathResolver can replace backslash by slash", t, func() {
		So(Posixfy(""), ShouldEqual, "")
		So(Posixfy("a/b/c"), ShouldEqual, "a/b/c")
		So(Posixfy("a\\b\\c"), ShouldEqual, "a/b/c")
	})

	Convey("A pathResolver can test for root", t, func() {
		Convey("A Path starting with C:/ is root", func() {
			So(IsRoot(""), ShouldBeFalse)
			So(IsRoot("C:\\"), ShouldBeTrue)
			So(IsRoot("C:/"), ShouldBeTrue)
			So(IsRoot("C:\\a/b/"), ShouldBeTrue)
			So(IsRoot("c:/a/b/../c"), ShouldBeTrue)
			So(IsRoot("c:\\a/b/../c"), ShouldBeTrue)
		})
	})

	Convey("A pathResolver can test for web root", t, func() {
		Convey("A Path starting with / is web root", func() {
			So(IsWebRoot(""), ShouldBeFalse)
			So(IsWebRoot("C:\\"), ShouldBeFalse)
			So(IsWebRoot("\\"), ShouldBeFalse)
			So(IsWebRoot("/"), ShouldBeTrue)
			So(IsWebRoot("/a/b/"), ShouldBeTrue)
			So(IsWebRoot("/a\\b/./c"), ShouldBeTrue)
			So(IsWebRoot("/a/b/./c"), ShouldBeTrue)
		})
	})

	Convey("A pathResolver can expand a path", t, func() {
		Convey("empty path returns an empty string", func() {
			So(ExpandPath(""), ShouldEqual, "")
		})
		Convey("non-empty path returns an posix path", func() {
			So(ExpandPath("c:\\a/.\\b/../c"), ShouldEqual, "c:/a/b/../c")
		})
	})

	Convey("A pathResolver can partition a path", t, func() {
		pathSegments, root, posixPath := PartitionPath("", false)
		So(len(pathSegments), ShouldEqual, 0)
		So(root, ShouldEqual, "")
		So(posixPath, ShouldEqual, "")

		Convey("A Path starting with dot has a dot root", func() {
			pathSegments, root, posixPath := PartitionPath(".", false)
			So(len(pathSegments), ShouldEqual, 0)
			So(root, ShouldEqual, ".")
			So(posixPath, ShouldEqual, ".")

			pathSegments, root, posixPath = PartitionPath(".\\a/b", false)
			So(len(pathSegments), ShouldEqual, 2)
			So(root, ShouldEqual, ".")
			So(posixPath, ShouldEqual, "./a/b")

		})
		Convey("A Partition removes self-reference path", func() {
			pathSegments, root, posixPath := PartitionPath("a\\b/./c", false)
			So(len(pathSegments), ShouldEqual, 3)
			So(root, ShouldEqual, "")
			So(posixPath, ShouldEqual, "a/b/./c")

			pathSegments, root, posixPath = PartitionPath("C:/a\\b/./c", false)
			So(len(pathSegments), ShouldEqual, 3)
			So(root, ShouldEqual, "C:")
			So(posixPath, ShouldEqual, "C:/a/b/./c")

			pathSegments, root, posixPath = PartitionPath("/a\\b/./c", true)
			So(len(pathSegments), ShouldEqual, 2)
			So(root, ShouldEqual, "/a")
			So(posixPath, ShouldEqual, "/a/b/./c")
		})
		Convey("A Partition keep '..' paths", func() {
			pathSegments, root, posixPath = PartitionPath("a\\b/../c", true)
			So(len(pathSegments), ShouldEqual, 4)
			So(root, ShouldEqual, "")
			So(posixPath, ShouldEqual, "a/b/../c")

			pathSegments, root, posixPath = PartitionPath("\\a\\b/../c", true)
			So(len(pathSegments), ShouldEqual, 3)
			So(root, ShouldEqual, "/a")
			So(posixPath, ShouldEqual, "/a/b/../c")

			pathSegments, root, posixPath = PartitionPath("c:\\a\\b/../c", false)
			So(len(pathSegments), ShouldEqual, 4)
			So(root, ShouldEqual, "c:")
			So(posixPath, ShouldEqual, "c:/a/b/../c")
		})
	})

	Convey("A pathResolver can join a path", t, func() {
		Convey("No segment and empty root returns an empty string", func() {
			So(JoinPath(nil, ""), ShouldEqual, "")
		})
		Convey("Segments with no root returns an slash-separated segments", func() {
			So(JoinPath([]string{"a"}, ""), ShouldEqual, "a")
			So(JoinPath([]string{"a", "b"}, ""), ShouldEqual, "a/b")
			So(JoinPath([]string{"a", "b", "c"}, ""), ShouldEqual, "a/b/c")
		})
		Convey("Segments with root returns an root plus slash-separated segments", func() {
			So(JoinPath([]string{"a"}, "c:"), ShouldEqual, "c:/a")
			So(JoinPath([]string{"a", "b"}, "d:"), ShouldEqual, "d:/a/b")
			So(JoinPath([]string{"a", "b", "c"}, "e:"), ShouldEqual, "e:/a/b/c")
		})
	})

	Convey("A Partition can resolve a system path from the target and start paths", t, func() {
		pr := NewPathResolver(0, "C:/a/working/dir")
		Convey("A Non-absolute jail path should panic", func() {
			recovered := false
			defer func() {
				r := recover()
				recovered = true
				So(recovered, ShouldBeTrue)
				So(r, ShouldEqual, "Jail is not an absolute path: c")
			}()
			_ = pr.SystemPath("a", "b", "c", false, "")
		})
		Convey("A system path with no start resolves from the root", func() {
			So(pr.SystemPath("images", "", "", false, ""), ShouldEqual, "")
			So(pr.SystemPath("../images", "", "", false, ""), ShouldEqual, "")
			So(pr.SystemPath("/etc/images", "", "", false, ""), ShouldEqual, "")
		})
		Convey("Empty target segment and empty start and empty jail means working dir", func() {
			So(pr.SystemPath("", "", "", false, ""), ShouldEqual, "C:/a/working/dir")
		})
		Convey("Empty target segment, non-empty root start and empty jail means expanded start path", func() {
			So(pr.SystemPath("", "C:\\start/../b", "", false, ""), ShouldEqual, "C:/start/../b")
		})
		Convey("Empty target segment, non-empty non-root start means susyem path start", func() {
			SkipSo(pr.SystemPath("", "start/../b", "", false, ""), ShouldEqual, "start/../b")
			SkipSo(pr.SystemPath("", "start/../b", "C:\\", false, ""), ShouldEqual, "start/../b")
		})

		/*
			resolver.system_path('images')
			    => '/path/to/docs/images'

			    resolver.system_path('../images')
			    => '/path/to/images'

			    resolver.system_path('/etc/images')
			    => '/etc/images'

			    resolver.system_path('images', '/etc')
			    => '/etc/images'

			    resolver.system_path('', '/etc/images')
			    => '/etc/images'

			    resolver.system_path(nil, nil, '/path/to/docs')
			    => '/path/to/docs'

			    resolver.system_path('..', nil, '/path/to/docs')
			    => '/path/to/docs'

			    resolver.system_path('../../../css', nil, '/path/to/docs')
			    => '/path/to/docs/css'

			    resolver.system_path('../../../css', '../../..', '/path/to/docs')
			    => '/path/to/docs/css'

			    resolver.system_path('..', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
			    => 'C:/data/docs'

			    resolver.system_path('..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
			    => 'C:/data/docs/css'

			    begin
			      resolver.system_path('../../../css', '../../..', '/path/to/docs', :recover => false)
			    rescue SecurityError => e
			      puts e.message
			    end
			    => 'path ../../../../../../css refers to location outside jail: /path/to/docs (disallowed in safe mode)'

			    resolver.system_path('/path/to/docs/images', nil, '/path/to/docs')
			    => '/path/to/docs/images'

			    begin
			      resolver.system_path('images', '/etc', '/path/to/docs')
			    rescue SecurityError => e
			      puts e.message
			    end
			    => Start path /etc is outside of jail: /path/to/docs'
		*/
	})
}
<|endoftext|>


<commit_before>package main

import "fmt"

type Test struct {
	num  int
	desc string
}

// main: create and print a slice of many types
func main() {
	var i = make([]interface{}, 1)
	i[0] = "interface{} slice of length 1"
	f := 3.14
	s := "Hello world"
	i = append(i, f, s, Test{1, "test01"})
	fmt.Println(i)
	for idx, v := range i {
		fmt.Printf("%v :: %#v :: %T\n", idx, v, v)
	}
}
<commit_msg>display Type<commit_after>package main

import "fmt"

type Test struct {
	num  int
	desc string
}

// main: create and print a slice of many types
func main() {
	var i = make([]interface{}, 1)
	i[0] = "interface{} slice of length 1"
	f := 3.14
	s := "Hello world"
	i = append(i, f, s, Test{1, "test01"})
	fmt.Printf("%#v :: %T\n", i, i)
	for idx, v := range i {
		fmt.Printf("%v :: %#v :: %T\n", idx, v, v)
	}
}
<|endoftext|>


<commit_before>package command

// TODO(ig): implement a cache mechanism.
// Currently we do 3 HTTP calls concurrently for each `/vizyon` call. As a
// side note, theaters refresh their movie list on every Friday night/Saturday
// morning.  So it is better to invalidate caches before Saturday noon and
// fetch a fresh movie list.

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"sort"
	"strconv"
	"sync"

	"github.com/PuerkitoBio/goquery"
	"github.com/igungor/tlbot"
)

func init() {
	register(cmdMovies)
}

var cmdMovies = &Command{
	Name:      "vizyon",
	ShortLine: "sinema filan",
	Run:       runMovies,
}

var (
	movieURL        = "http://www.google.com/movies?near=Kadikoy,Istanbul&start="
	chromeUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36"
)

func runMovies(b *tlbot.Bot, msg *tlbot.Message) {
	var wg sync.WaitGroup

	// mu guards movies map access
	var mu sync.Mutex
	movies := make(map[string]int)

	// fetch is a closure to fetch the movies in given movieurl and save the
	// result in movies map.
	fetch := func(movieurl string, wg *sync.WaitGroup) {
		defer wg.Done()

		req, _ := http.NewRequest("GET", movieURL, nil)
		req.Header.Set("User-Agent", chromeUserAgent)

		r, err := httpclient.Do(req)
		if err != nil {
			log.Printf("[movies] Error while fetching URL '%v'. Error: %v\n", movieurl, err)
			return
		}
		defer r.Body.Close()

		doc, err := goquery.NewDocumentFromResponse(r)
		if err != nil {
			log.Printf("[movies] Error while fetching DOM from url '%v': %v\n", movieurl, err)
			return
		}

		doc.Find(".theater .desc .name a").Each(func(_ int, s *goquery.Selection) {
			s.Closest(".theater").Find(".showtimes .name").Each(func(_ int, sel *goquery.Selection) {
				mu.Lock()
				movies[sel.Text()]++
				mu.Unlock()
			})
		})
	}

	// fetch 3 pages of theaters
	for i := 0; i < 3; i++ {
		offset := strconv.Itoa(10 * i)
		wg.Add(1)
		go fetch(movieURL+offset, &wg)
	}
	wg.Wait()

	// sort by map values. map values contain frequency of a movie by
	// theater count. most frequent movie in a theater is most probably
	// screened near the caller's home.
	vs := newValSorter(movies)
	sort.Sort(vs)

	var buf bytes.Buffer
	buf.WriteString(" 🎬 İstanbul'da vizyon filmleri\n")
	for _, movie := range vs.Keys {
		buf.WriteString(fmt.Sprintf("🔸 %v\n", movie))
	}

	err := b.SendMessage(msg.Chat, buf.String(), tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("[movies] Error while sending message. Err: %v\n", err)
		return
	}
}

// valsorter is used for sorting the map by value
type valsorter struct {
	Keys []string
	Vals []int
}

func (v *valsorter) Len() int           { return len(v.Vals) }
func (v *valsorter) Less(i, j int) bool { return v.Vals[i] > v.Vals[j] }
func (v *valsorter) Swap(i, j int) {
	v.Vals[i], v.Vals[j] = v.Vals[j], v.Vals[i]
	v.Keys[i], v.Keys[j] = v.Keys[j], v.Keys[i]
}

func newValSorter(m map[string]int) *valsorter {
	vs := &valsorter{
		Keys: make([]string, 0, len(m)),
		Vals: make([]int, 0, len(m)),
	}
	for k, v := range m {
		vs.Keys = append(vs.Keys, k)
		vs.Vals = append(vs.Vals, v)
	}
	return vs
}
<commit_msg>Implement a cache mechanism for /movies command<commit_after>package command

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"sort"
	"strconv"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/igungor/tlbot"
)

func init() {
	register(cmdMovies)
}

var cmdMovies = &Command{
	Name:      "vizyon",
	ShortLine: "sinema filan",
	Run:       runMovies,
}

var (
	movieURL        = "http://www.google.com/movies?near=Kadikoy,Istanbul&start="
	chromeUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36"
	movieCache      = map[string][]string{}
)

func runMovies(b *tlbot.Bot, msg *tlbot.Message) {
	movies, err := fetchOrCache()
	if err != nil {
		log.Printf("[movies] Error while fetching movies: %v\n", err)
		return
	}

	var buf bytes.Buffer
	buf.WriteString(" 🎬 İstanbul'da vizyon filmleri\n")
	for _, movie := range movies {
		buf.WriteString(fmt.Sprintf("🔸 %v\n", movie))
	}

	err = b.SendMessage(msg.Chat, buf.String(), tlbot.ModeNone, false, nil)
	if err != nil {
		log.Printf("[movies] Error while sending message: %v\n", err)
		return
	}
}

func fetchOrCache() ([]string, error) {
	now := time.Now().UTC()
	year, week := now.ISOWeek()
	// YYYYWW is our cache key. Theaters keep their movies for about a week. We
	// don't need a fresh movie list every day or hour. Using year and ISO week
	// gives us the convenience to avoid cache invalidation. everybody hates
	// cache invalidation. thank you ISO week.
	nowstr := fmt.Sprintf("%v%v", year, week)

	// friday nights and saturday mornings are the times theaters renew their
	// movie list. fetching new list on these days are a waste. just go to
	// cache.
	if now.Weekday() > time.Thursday {
		movies, ok := movieCache[nowstr]
		if !ok {
			return nil, fmt.Errorf("unfortunately today is friday/saturday and the cache is empty. nothing to do")
		}
		return movies, nil
	}

	movies, ok := movieCache[nowstr]
	if ok {
		return movies, nil
	}

	// cache-miss. fetch a fresh list.
	movies = fetchMovies()
	if movies == nil {
		return nil, fmt.Errorf("fetched new movies but the list came empty")
	}

	// put the new list in cache
	movieCache[nowstr] = movies

	return movies, nil
}

func fetchMovies() []string {
	var wg sync.WaitGroup

	// mu guards movies map access
	var mu sync.Mutex
	movies := make(map[string]int)

	// fetch is a closure to fetch the movies in given movieurl and save the
	// result in movies map.
	fetch := func(movieurl string, wg *sync.WaitGroup) {
		defer wg.Done()

		req, _ := http.NewRequest("GET", movieURL, nil)
		req.Header.Set("User-Agent", chromeUserAgent)

		r, err := httpclient.Do(req)
		if err != nil {
			log.Printf("[movies] Error while fetching URL '%v'. Error: %v\n", movieurl, err)
			return
		}
		defer r.Body.Close()

		doc, err := goquery.NewDocumentFromResponse(r)
		if err != nil {
			log.Printf("[movies] Error while fetching DOM from url '%v': %v\n", movieurl, err)
			return
		}

		doc.Find(".theater .desc .name a").Each(func(_ int, s *goquery.Selection) {
			s.Closest(".theater").Find(".showtimes .name").Each(func(_ int, sel *goquery.Selection) {
				mu.Lock()
				movies[sel.Text()]++
				mu.Unlock()
			})
		})
	}

	// fetch 3 pages of theaters
	for i := 0; i < 3; i++ {
		offset := strconv.Itoa(10 * i)
		wg.Add(1)
		go fetch(movieURL+offset, &wg)
	}
	wg.Wait()

	// sort by map values. map values contain frequency of a movie by
	// theater count. most frequent movie in a theater is most probably
	// screened near the caller's neighborhood.
	vs := newValSorter(movies)
	sort.Sort(vs)

	return vs.Keys

}

// valsorter is used for sorting the map by value
type valsorter struct {
	Keys []string
	Vals []int
}

func (v *valsorter) Len() int           { return len(v.Vals) }
func (v *valsorter) Less(i, j int) bool { return v.Vals[i] > v.Vals[j] }
func (v *valsorter) Swap(i, j int) {
	v.Vals[i], v.Vals[j] = v.Vals[j], v.Vals[i]
	v.Keys[i], v.Keys[j] = v.Keys[j], v.Keys[i]
}

func newValSorter(m map[string]int) *valsorter {
	vs := &valsorter{
		Keys: make([]string, 0, len(m)),
		Vals: make([]int, 0, len(m)),
	}
	for k, v := range m {
		vs.Keys = append(vs.Keys, k)
		vs.Vals = append(vs.Vals, v)
	}
	return vs
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/fgrehm/devstep-cli/devstep"
	"os"
	"regexp"
	"strings"
)

var dockerRunFlags = []cli.Flag{
	cli.StringFlag{Name: "w, working_dir", Usage: "Working directory inside the container"},
	cli.StringSliceFlag{Name: "p, publish", Value: &cli.StringSlice{}, Usage: "Publish a container's port to the host (hostPort:containerPort)"},
	cli.StringSliceFlag{Name: "link", Value: &cli.StringSlice{}, Usage: "Add link to another container (name:alias)"},
	cli.StringSliceFlag{Name: "e, env", Value: &cli.StringSlice{}, Usage: "Set environment variables"},
	cli.BoolFlag{Name: "privileged", Usage: "Give extended privileges to this container"},
}

func bashCompleteRunArgs(c *cli.Context) {
	args := c.Args()
	if len(args) == 0 {
		fmt.Println("-p")
		fmt.Println("--publish")
		fmt.Println("--link")
		fmt.Println("-w")
		fmt.Println("--working_dir")
		fmt.Println("-e")
		fmt.Println("--env")
		fmt.Println("--privileged")
	}
}

func parseRunOpts(c *cli.Context) *devstep.DockerRunOpts {
	// Sane defaults
	runOpts := &devstep.DockerRunOpts{
		Publish: c.StringSlice("publish"),
		Links:   c.StringSlice("link"),
		Name:    c.String("name"),
		Env:     make(map[string]string),
	}

	// Only set the privileged config if it was provided
	if c.IsSet("privileged") {
		privileged := c.Bool("privileged")
		runOpts.Privileged = &privileged
	}

	// Set working dir directly on the project object so that it get passed
	// along properly
	if workingDir := c.String("working_dir"); workingDir != "" {
		project.Config().GuestDir = workingDir
	}

	// Env vars
	for _, envVar := range c.StringSlice("env") {
		varAndValue := strings.Split(envVar, "=")
		runOpts.Env[varAndValue[0]] = varAndValue[1]
	}

	// Validate ports
	validPort := regexp.MustCompile(`^\d+:\d+$`)
	for _, port := range runOpts.Publish {
		if !validPort.MatchString(port) {
			fmt.Println("Invalid publish arg: " + port)
			os.Exit(1)
		}
	}
	// Validate links
	validLink := regexp.MustCompile(`[^:]+:[^:]+`)
	for _, link := range runOpts.Links {
		if !validLink.MatchString(link) {
			fmt.Println("Invalid link: " + link)
			os.Exit(1)
		}
	}
	return runOpts
}
<commit_msg>Pass on DEVSTEP_LOG to containers<commit_after>package commands

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/fgrehm/devstep-cli/devstep"
	"os"
	"regexp"
	"strings"
)

var dockerRunFlags = []cli.Flag{
	cli.StringFlag{Name: "w, working_dir", Usage: "Working directory inside the container"},
	cli.StringSliceFlag{Name: "p, publish", Value: &cli.StringSlice{}, Usage: "Publish a container's port to the host (hostPort:containerPort)"},
	cli.StringSliceFlag{Name: "link", Value: &cli.StringSlice{}, Usage: "Add link to another container (name:alias)"},
	cli.StringSliceFlag{Name: "e, env", Value: &cli.StringSlice{}, Usage: "Set environment variables"},
	cli.BoolFlag{Name: "privileged", Usage: "Give extended privileges to this container"},
}

func bashCompleteRunArgs(c *cli.Context) {
	args := c.Args()
	if len(args) == 0 {
		fmt.Println("-p")
		fmt.Println("--publish")
		fmt.Println("--link")
		fmt.Println("-w")
		fmt.Println("--working_dir")
		fmt.Println("-e")
		fmt.Println("--env")
		fmt.Println("--privileged")
	}
}

func parseRunOpts(c *cli.Context) *devstep.DockerRunOpts {
	// Sane defaults
	runOpts := &devstep.DockerRunOpts{
		Publish: c.StringSlice("publish"),
		Links:   c.StringSlice("link"),
		Name:    c.String("name"),
		Env:     map[string]string{ "DEVSTEP_LOG": c.GlobalString("log-level") },
	}

	// Only set the privileged config if it was provided
	if c.IsSet("privileged") {
		privileged := c.Bool("privileged")
		runOpts.Privileged = &privileged
	}

	// Set working dir directly on the project object so that it get passed
	// along properly
	if workingDir := c.String("working_dir"); workingDir != "" {
		project.Config().GuestDir = workingDir
	}

	// Env vars
	for _, envVar := range c.StringSlice("env") {
		varAndValue := strings.Split(envVar, "=")
		runOpts.Env[varAndValue[0]] = varAndValue[1]
	}

	// Validate ports
	validPort := regexp.MustCompile(`^\d+:\d+$`)
	for _, port := range runOpts.Publish {
		if !validPort.MatchString(port) {
			fmt.Println("Invalid publish arg: " + port)
			os.Exit(1)
		}
	}
	// Validate links
	validLink := regexp.MustCompile(`[^:]+:[^:]+`)
	for _, link := range runOpts.Links {
		if !validLink.MatchString(link) {
			fmt.Println("Invalid link: " + link)
			os.Exit(1)
		}
	}
	return runOpts
}
<|endoftext|>


<commit_before>// (C) 2017 Julian Andres Klode <jak@jak-linux.org>
// Licensed under the 2-Clause BSD license, see LICENSE for more information.

package permission

import (
	"fmt"
)

// Parser is a parser for the permission syntax.
//
// This parser is implemented as a simple recursive parser, it has horrible
// error reporting, but it works, and has a test suite.
//
// The parser requires one lookahead token in the scanner.
type Parser struct {
	sc *Scanner
}

// NewParser returns a new parser for the permission specification language.
func NewParser(input string) *Parser {
	return &Parser{NewScanner(input)}
}

// Parse parses the permission specification language.
//
// @syntax main <- inner EOF
func (p *Parser) Parse() (perm Permission, err error) {
	defer func() {
		if r := recover(); r != nil {
			switch rr := r.(type) {
			case scannerError:
				perm = nil
				err = rr
			default:
				panic(rr)
			}
		}
	}()
	perm = p.parseInner()

	// Ensure that the inner run is complete
	p.sc.Expect(TokenEndOfFile)
	return perm, nil
}

// parseInner parses a permission spec. The permission spec may contain
// arbitrary garbage at the end, use Parse() to make sure that does not
// happen
//
// @syntax inner <- '_' | basePermission [func | map | chan | pointer | sliceOrArray]
func (p *Parser) parseInner() Permission {
	if _, ok := p.sc.Accept(TokenWildcard); ok {
		return &WildcardPermission{}
	}
	basePerm := p.parseBasePermission()

	switch tok := p.sc.Peek(); tok.Type {
	case TokenFunc, TokenParenLeft:
		return p.parseFunc(basePerm)
	case TokenInterface:
		return p.parseInterface(basePerm)
	case TokenMap:
		return p.parseMap(basePerm)
	case TokenChan:
		return p.parseChan(basePerm)
	case TokenStruct:
		return p.parseStruct(basePerm)
	case TokenStar:
		return p.parsePointer(basePerm)
	case TokenBracketLeft:
		return p.parseSliceOrArray(basePerm)
	default:
		// We are searching the longest match here. If inside somethig else,
		// there might be syntax for the parent node after this - ignore that.
		return basePerm
	}
}

// @syntax basePermission ('o'|'r'|'w'|'R'|'W'|'m'|'l'|'v'|'a'|'n')+
func (p *Parser) parseBasePermission() BasePermission {
	var perm BasePermission
	tok := p.sc.Expect(TokenWord)

	for _, c := range tok.Value {
		switch c {
		case 'o':
			perm |= Owned
		case 'r':
			perm |= Read
		case 'w':
			perm |= Write
		case 'R':
			perm |= ExclRead
		case 'W':
			perm |= ExclWrite
		case 'm':
			perm |= Mutable
		case 'l':
			perm |= LinearValue
		case 'v':
			perm |= Value
		case 'a':
			perm |= Any
		case 'n':
			perm |= None
		default:
			panic(p.sc.wrapError(fmt.Errorf("Unknown permission bit or type: %c", c)))
		}
	}
	if perm.String() != tok.Value {
		fmt.Printf("Warning: Permission %v can be rewritten as %v\n", tok.Value, perm.String())
	}
	return perm
}

// @syntax func <- ['(' param List ')'] 'func' '(' [paramList] ')' ( [inner] |  '(' [paramList] ')')
func (p *Parser) parseFunc(bp BasePermission) Permission {
	var name string
	var receiver []Permission
	var params []Permission
	var results []Permission

	// Parse either a "func" token or a receiver and a func token
	if tok, _ := p.sc.Accept(TokenParenLeft, TokenFunc); tok.Type == TokenParenLeft {
		receiver = p.parseFieldList(TokenComma)
		p.sc.Expect(TokenParenRight)
		p.sc.Expect(TokenFunc)
	}

	// Parse a name
	if nameTok, ok := p.sc.Accept(TokenWord); ok {
		name = nameTok.Value
	}

	// Pararameters
	p.sc.Expect(TokenParenLeft)
	if p.sc.Peek().Type != TokenParenRight {
		params = p.parseFieldList(TokenComma)
	}
	p.sc.Expect(TokenParenRight)

	// Results
	if tok, _ := p.sc.Accept(TokenParenLeft); tok.Type == TokenParenLeft {
		results = p.parseFieldList(TokenComma)
		p.sc.Expect(TokenParenRight)
	} else if tok := p.sc.Peek(); tok.Type == TokenWord {
		// permission starts with word. We peek()ed first, so we can backtrack.
		results = []Permission{p.parseInner()}
	}

	return &FuncPermission{BasePermission: bp, Name: name, Receivers: receiver, Params: params, Results: results}
}

// @syntax paramList <- inner (',' inner)*
// @syntax fieldList <- inner (';' inner)*
func (p *Parser) parseFieldList(sep TokenType) []Permission {
	var tok Token
	var perms []Permission

	perm := p.parseInner()
	perms = append(perms, perm)

	for tok = p.sc.Peek(); tok.Type == sep; tok = p.sc.Peek() {
		p.sc.Scan()
		perms = append(perms, p.parseInner())
	}

	return perms
}

// @syntax sliceOrArray <- '[' [NUMBER] ']' inner
func (p *Parser) parseSliceOrArray(bp BasePermission) Permission {
	p.sc.Expect(TokenBracketLeft)
	_, isArray := p.sc.Accept(TokenNumber, TokenWildcard)
	p.sc.Expect(TokenBracketRight)

	rhs := p.parseInner()

	if isArray {
		return &ArrayPermission{BasePermission: bp, ElementPermission: rhs}
	}
	return &SlicePermission{BasePermission: bp, ElementPermission: rhs}
}

// @syntax chan <- 'chan' inner
func (p *Parser) parseChan(bp BasePermission) Permission {
	p.sc.Expect(TokenChan)
	rhs := p.parseInner()
	return &ChanPermission{BasePermission: bp, ElementPermission: rhs}
}

// @syntax chan <- 'interface' '{' [fieldList] '}'
func (p *Parser) parseInterface(bp BasePermission) Permission {
	var fields []Permission
	p.sc.Expect(TokenInterface)
	p.sc.Expect(TokenBraceLeft)
	if p.sc.Peek().Type != TokenBraceRight {
		fields = p.parseFieldList(TokenSemicolon)
	}
	p.sc.Expect(TokenBraceRight)
	return &InterfacePermission{BasePermission: bp, Methods: fields}
}

// @syntax map <- 'map' '[' inner ']' inner
func (p *Parser) parseMap(bp BasePermission) Permission {
	p.sc.Expect(TokenMap) // Map keyword

	p.sc.Expect(TokenBracketLeft)
	key := p.parseInner()
	p.sc.Expect(TokenBracketRight)

	val := p.parseInner()

	return &MapPermission{BasePermission: bp, KeyPermission: key, ValuePermission: val}
}

// @syntax pointer <- '*' inner
func (p *Parser) parsePointer(bp BasePermission) Permission {
	p.sc.Expect(TokenStar)
	rhs := p.parseInner()
	return &PointerPermission{BasePermission: bp, Target: rhs}
}

// @syntax struct <- 'struct' '{' fieldList '}'
func (p *Parser) parseStruct(bp BasePermission) Permission {
	p.sc.Expect(TokenStruct)
	p.sc.Expect(TokenBraceLeft)
	fields := p.parseFieldList(TokenSemicolon)
	p.sc.Expect(TokenBraceRight)
	return &StructPermission{BasePermission: bp, Fields: fields}
}
<commit_msg>permission/parser: Add wildcard to permission syntax annotation<commit_after>// (C) 2017 Julian Andres Klode <jak@jak-linux.org>
// Licensed under the 2-Clause BSD license, see LICENSE for more information.

package permission

import (
	"fmt"
)

// Parser is a parser for the permission syntax.
//
// This parser is implemented as a simple recursive parser, it has horrible
// error reporting, but it works, and has a test suite.
//
// The parser requires one lookahead token in the scanner.
type Parser struct {
	sc *Scanner
}

// NewParser returns a new parser for the permission specification language.
func NewParser(input string) *Parser {
	return &Parser{NewScanner(input)}
}

// Parse parses the permission specification language.
//
// @syntax main <- inner EOF
func (p *Parser) Parse() (perm Permission, err error) {
	defer func() {
		if r := recover(); r != nil {
			switch rr := r.(type) {
			case scannerError:
				perm = nil
				err = rr
			default:
				panic(rr)
			}
		}
	}()
	perm = p.parseInner()

	// Ensure that the inner run is complete
	p.sc.Expect(TokenEndOfFile)
	return perm, nil
}

// parseInner parses a permission spec. The permission spec may contain
// arbitrary garbage at the end, use Parse() to make sure that does not
// happen
//
// @syntax inner <- '_' | basePermission [func | map | chan | pointer | sliceOrArray]
func (p *Parser) parseInner() Permission {
	if _, ok := p.sc.Accept(TokenWildcard); ok {
		return &WildcardPermission{}
	}
	basePerm := p.parseBasePermission()

	switch tok := p.sc.Peek(); tok.Type {
	case TokenFunc, TokenParenLeft:
		return p.parseFunc(basePerm)
	case TokenInterface:
		return p.parseInterface(basePerm)
	case TokenMap:
		return p.parseMap(basePerm)
	case TokenChan:
		return p.parseChan(basePerm)
	case TokenStruct:
		return p.parseStruct(basePerm)
	case TokenStar:
		return p.parsePointer(basePerm)
	case TokenBracketLeft:
		return p.parseSliceOrArray(basePerm)
	default:
		// We are searching the longest match here. If inside somethig else,
		// there might be syntax for the parent node after this - ignore that.
		return basePerm
	}
}

// @syntax basePermission ('o'|'r'|'w'|'R'|'W'|'m'|'l'|'v'|'a'|'n')+
func (p *Parser) parseBasePermission() BasePermission {
	var perm BasePermission
	tok := p.sc.Expect(TokenWord)

	for _, c := range tok.Value {
		switch c {
		case 'o':
			perm |= Owned
		case 'r':
			perm |= Read
		case 'w':
			perm |= Write
		case 'R':
			perm |= ExclRead
		case 'W':
			perm |= ExclWrite
		case 'm':
			perm |= Mutable
		case 'l':
			perm |= LinearValue
		case 'v':
			perm |= Value
		case 'a':
			perm |= Any
		case 'n':
			perm |= None
		default:
			panic(p.sc.wrapError(fmt.Errorf("Unknown permission bit or type: %c", c)))
		}
	}
	if perm.String() != tok.Value {
		fmt.Printf("Warning: Permission %v can be rewritten as %v\n", tok.Value, perm.String())
	}
	return perm
}

// @syntax func <- ['(' param List ')'] 'func' '(' [paramList] ')' ( [inner] |  '(' [paramList] ')')
func (p *Parser) parseFunc(bp BasePermission) Permission {
	var name string
	var receiver []Permission
	var params []Permission
	var results []Permission

	// Parse either a "func" token or a receiver and a func token
	if tok, _ := p.sc.Accept(TokenParenLeft, TokenFunc); tok.Type == TokenParenLeft {
		receiver = p.parseFieldList(TokenComma)
		p.sc.Expect(TokenParenRight)
		p.sc.Expect(TokenFunc)
	}

	// Parse a name
	if nameTok, ok := p.sc.Accept(TokenWord); ok {
		name = nameTok.Value
	}

	// Pararameters
	p.sc.Expect(TokenParenLeft)
	if p.sc.Peek().Type != TokenParenRight {
		params = p.parseFieldList(TokenComma)
	}
	p.sc.Expect(TokenParenRight)

	// Results
	if tok, _ := p.sc.Accept(TokenParenLeft); tok.Type == TokenParenLeft {
		results = p.parseFieldList(TokenComma)
		p.sc.Expect(TokenParenRight)
	} else if tok := p.sc.Peek(); tok.Type == TokenWord {
		// permission starts with word. We peek()ed first, so we can backtrack.
		results = []Permission{p.parseInner()}
	}

	return &FuncPermission{BasePermission: bp, Name: name, Receivers: receiver, Params: params, Results: results}
}

// @syntax paramList <- inner (',' inner)*
// @syntax fieldList <- inner (';' inner)*
func (p *Parser) parseFieldList(sep TokenType) []Permission {
	var tok Token
	var perms []Permission

	perm := p.parseInner()
	perms = append(perms, perm)

	for tok = p.sc.Peek(); tok.Type == sep; tok = p.sc.Peek() {
		p.sc.Scan()
		perms = append(perms, p.parseInner())
	}

	return perms
}

// @syntax sliceOrArray <- '[' [NUMBER|_] ']' inner
func (p *Parser) parseSliceOrArray(bp BasePermission) Permission {
	p.sc.Expect(TokenBracketLeft)
	_, isArray := p.sc.Accept(TokenNumber, TokenWildcard)
	p.sc.Expect(TokenBracketRight)

	rhs := p.parseInner()

	if isArray {
		return &ArrayPermission{BasePermission: bp, ElementPermission: rhs}
	}
	return &SlicePermission{BasePermission: bp, ElementPermission: rhs}
}

// @syntax chan <- 'chan' inner
func (p *Parser) parseChan(bp BasePermission) Permission {
	p.sc.Expect(TokenChan)
	rhs := p.parseInner()
	return &ChanPermission{BasePermission: bp, ElementPermission: rhs}
}

// @syntax chan <- 'interface' '{' [fieldList] '}'
func (p *Parser) parseInterface(bp BasePermission) Permission {
	var fields []Permission
	p.sc.Expect(TokenInterface)
	p.sc.Expect(TokenBraceLeft)
	if p.sc.Peek().Type != TokenBraceRight {
		fields = p.parseFieldList(TokenSemicolon)
	}
	p.sc.Expect(TokenBraceRight)
	return &InterfacePermission{BasePermission: bp, Methods: fields}
}

// @syntax map <- 'map' '[' inner ']' inner
func (p *Parser) parseMap(bp BasePermission) Permission {
	p.sc.Expect(TokenMap) // Map keyword

	p.sc.Expect(TokenBracketLeft)
	key := p.parseInner()
	p.sc.Expect(TokenBracketRight)

	val := p.parseInner()

	return &MapPermission{BasePermission: bp, KeyPermission: key, ValuePermission: val}
}

// @syntax pointer <- '*' inner
func (p *Parser) parsePointer(bp BasePermission) Permission {
	p.sc.Expect(TokenStar)
	rhs := p.parseInner()
	return &PointerPermission{BasePermission: bp, Target: rhs}
}

// @syntax struct <- 'struct' '{' fieldList '}'
func (p *Parser) parseStruct(bp BasePermission) Permission {
	p.sc.Expect(TokenStruct)
	p.sc.Expect(TokenBraceLeft)
	fields := p.parseFieldList(TokenSemicolon)
	p.sc.Expect(TokenBraceRight)
	return &StructPermission{BasePermission: bp, Fields: fields}
}
<|endoftext|>


<commit_before>package persistence

import (
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/gin-contrib/cache/utils"
)

// RedisStore represents the cache with redis persistence
type RedisStore struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// NewRedisCache returns a RedisStore
// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host string, password string, defaultExpiration time.Duration) *RedisStore {
	var pool = &redis.Pool{
		MaxIdle:     5,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			// the redis protocol should probably be made sett-able
			c, err := redis.Dial("tcp", host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return &RedisStore{pool, defaultExpiration}
}

// NewRedisCacheWithPool returns a RedisStore using the provided pool
// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCacheWithPool(pool *redis.Pool, defaultExpiration time.Duration) *RedisStore {
	return &RedisStore{pool, defaultExpiration}
}

// Set (see CacheStore interface)
func (c *RedisStore) Set(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	return c.invoke(conn.Do, key, value, expires)
}

// Add (see CacheStore interface)
func (c *RedisStore) Add(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if exists(conn, key) {
		return ErrNotStored
	}
	return c.invoke(conn.Do, key, value, expires)
}

// Replace (see CacheStore interface)
func (c *RedisStore) Replace(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		return ErrNotStored
	}
	err := c.invoke(conn.Do, key, value, expires)
	if value == nil {
		return ErrNotStored
	}

	return err

}

// Get (see CacheStore interface)
func (c *RedisStore) Get(key string, ptrValue interface{}) error {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return ErrCacheMiss
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		return err
	}
	return utils.Deserialize(item, ptrValue)
}

func exists(conn redis.Conn, key string) bool {
	retval, _ := redis.Bool(conn.Do("EXISTS", key))
	return retval
}

// Delete (see CacheStore interface)
func (c *RedisStore) Delete(key string) error {
	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		return ErrCacheMiss
	}
	_, err := conn.Do("DEL", key)
	return err
}

// Increment (see CacheStore interface)
func (c *RedisStore) Increment(key string, delta uint64) (uint64, error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that. Since we need to do increment
	// ourselves instead of natively via INCRBY (redis doesn't support wrapping), we get the value
	// and do the exists check this way to minimize calls to Redis
	val, err := conn.Do("GET", key)
	if val == nil {
		return 0, ErrCacheMiss
	}
	if err == nil {
		currentVal, err := redis.Int64(val, nil)
		if err != nil {
			return 0, err
		}
		sum := currentVal + int64(delta)
		_, err = conn.Do("SET", key, sum)
		if err != nil {
			return 0, err
		}
		return uint64(sum), nil
	}

	return 0, err
}

// Decrement (see CacheStore interface)
func (c *RedisStore) Decrement(key string, delta uint64) (newValue uint64, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that, hence the exists call
	if !exists(conn, key) {
		return 0, ErrCacheMiss
	}
	// Decrement contract says you can only go to 0
	// so we go fetch the value and if the delta is greater than the amount,
	// 0 out the value
	currentVal, err := redis.Int64(conn.Do("GET", key))
	if err == nil && delta > uint64(currentVal) {
		tempint, err := redis.Int64(conn.Do("DECRBY", key, currentVal))
		return uint64(tempint), err
	}
	tempint, err := redis.Int64(conn.Do("DECRBY", key, delta))
	return uint64(tempint), err
}

// Flush (see CacheStore interface)
func (c *RedisStore) Flush() error {
	conn := c.pool.Get()
	defer conn.Close()
	_, err := conn.Do("FLUSHALL")
	return err
}

func (c *RedisStore) invoke(f func(string, ...interface{}) (interface{}, error),
	key string, value interface{}, expires time.Duration) error {

	switch expires {
	case DEFAULT:
		expires = c.defaultExpiration
	case FOREVER:
		expires = time.Duration(0)
	}

	b, err := utils.Serialize(value)
	if err != nil {
		return err
	}

	if expires > 0 {
		_, err := f("SETEX", key, int32(expires/time.Second), b)
		return err
	}

	_, err = f("SET", key, b)
	return err

}
<commit_msg>Replaced garyburd/redigo with gomodule/redigo (#30)<commit_after>package persistence

import (
	"time"

	"github.com/gin-contrib/cache/utils"
	"github.com/gomodule/redigo/redis"
)

// RedisStore represents the cache with redis persistence
type RedisStore struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// NewRedisCache returns a RedisStore
// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host string, password string, defaultExpiration time.Duration) *RedisStore {
	var pool = &redis.Pool{
		MaxIdle:     5,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			// the redis protocol should probably be made sett-able
			c, err := redis.Dial("tcp", host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return &RedisStore{pool, defaultExpiration}
}

// NewRedisCacheWithPool returns a RedisStore using the provided pool
// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCacheWithPool(pool *redis.Pool, defaultExpiration time.Duration) *RedisStore {
	return &RedisStore{pool, defaultExpiration}
}

// Set (see CacheStore interface)
func (c *RedisStore) Set(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	return c.invoke(conn.Do, key, value, expires)
}

// Add (see CacheStore interface)
func (c *RedisStore) Add(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if exists(conn, key) {
		return ErrNotStored
	}
	return c.invoke(conn.Do, key, value, expires)
}

// Replace (see CacheStore interface)
func (c *RedisStore) Replace(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		return ErrNotStored
	}
	err := c.invoke(conn.Do, key, value, expires)
	if value == nil {
		return ErrNotStored
	}

	return err

}

// Get (see CacheStore interface)
func (c *RedisStore) Get(key string, ptrValue interface{}) error {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return ErrCacheMiss
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		return err
	}
	return utils.Deserialize(item, ptrValue)
}

func exists(conn redis.Conn, key string) bool {
	retval, _ := redis.Bool(conn.Do("EXISTS", key))
	return retval
}

// Delete (see CacheStore interface)
func (c *RedisStore) Delete(key string) error {
	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		return ErrCacheMiss
	}
	_, err := conn.Do("DEL", key)
	return err
}

// Increment (see CacheStore interface)
func (c *RedisStore) Increment(key string, delta uint64) (uint64, error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that. Since we need to do increment
	// ourselves instead of natively via INCRBY (redis doesn't support wrapping), we get the value
	// and do the exists check this way to minimize calls to Redis
	val, err := conn.Do("GET", key)
	if val == nil {
		return 0, ErrCacheMiss
	}
	if err == nil {
		currentVal, err := redis.Int64(val, nil)
		if err != nil {
			return 0, err
		}
		sum := currentVal + int64(delta)
		_, err = conn.Do("SET", key, sum)
		if err != nil {
			return 0, err
		}
		return uint64(sum), nil
	}

	return 0, err
}

// Decrement (see CacheStore interface)
func (c *RedisStore) Decrement(key string, delta uint64) (newValue uint64, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that, hence the exists call
	if !exists(conn, key) {
		return 0, ErrCacheMiss
	}
	// Decrement contract says you can only go to 0
	// so we go fetch the value and if the delta is greater than the amount,
	// 0 out the value
	currentVal, err := redis.Int64(conn.Do("GET", key))
	if err == nil && delta > uint64(currentVal) {
		tempint, err := redis.Int64(conn.Do("DECRBY", key, currentVal))
		return uint64(tempint), err
	}
	tempint, err := redis.Int64(conn.Do("DECRBY", key, delta))
	return uint64(tempint), err
}

// Flush (see CacheStore interface)
func (c *RedisStore) Flush() error {
	conn := c.pool.Get()
	defer conn.Close()
	_, err := conn.Do("FLUSHALL")
	return err
}

func (c *RedisStore) invoke(f func(string, ...interface{}) (interface{}, error),
	key string, value interface{}, expires time.Duration) error {

	switch expires {
	case DEFAULT:
		expires = c.defaultExpiration
	case FOREVER:
		expires = time.Duration(0)
	}

	b, err := utils.Serialize(value)
	if err != nil {
		return err
	}

	if expires > 0 {
		_, err := f("SETEX", key, int32(expires/time.Second), b)
		return err
	}

	_, err = f("SET", key, b)
	return err

}
<|endoftext|>


<commit_before>package bkdtree

import (
	"encoding/binary"
	"sort"

	"github.com/keegancsmith/nth"
)

type Point struct {
	Vals     []uint64
	UserData uint64
}

type PointArray interface {
	sort.Interface
	GetPoint(idx int) Point
	GetValue(idx int) uint64
	SubArray(begin, end int) PointArray
	Erase(point Point) bool
	Append(point Point)
}

type PointArrayMem struct {
	points []Point
	byDim  int
}

type PointArrayExt struct {
	data        []byte
	numPoints   int
	byDim       int
	bytesPerDim int
	numDims     int
	pointSize   int
}

func (p *Point) Inside(lowPoint, highPoint Point) (isInside bool) {
	for dim := 0; dim < len(p.Vals); dim++ {
		if p.Vals[dim] < lowPoint.Vals[dim] || p.Vals[dim] > highPoint.Vals[dim] {
			return
		}
	}
	isInside = true
	return
}

func (p *Point) Equal(rhs Point) (res bool) {
	if p.UserData != rhs.UserData || len(p.Vals) != len(rhs.Vals) {
		return
	}
	for dim := 0; dim < len(p.Vals); dim++ {
		if p.Vals[dim] != rhs.Vals[dim] {
			return
		}
	}
	res = true
	return
}

//Encode encode in place. Refers to binary.Write impl in standard library.
//len(b) shall be no less than bytesPerDim*numDims+8
func (p *Point) Encode(b []byte, bytesPerDim int) {
	numDims := len(p.Vals)
	for i := 0; i < numDims; i++ {
		switch bytesPerDim {
		case 1:
			b[i] = byte(p.Vals[i])
		case 2:
			binary.BigEndian.PutUint16(b[2*i:], uint16(p.Vals[i]))
		case 4:
			binary.BigEndian.PutUint32(b[4*i:], uint32(p.Vals[i]))
		case 8:
			binary.BigEndian.PutUint64(b[8*i:], p.Vals[i])
		}
	}
	binary.BigEndian.PutUint64(b[numDims*bytesPerDim:], p.UserData)
	return
}

func (p *Point) Decode(b []byte, numDims int, bytesPerDim int) {
	p.Vals = make([]uint64, numDims)
	for i := 0; i < numDims; i++ {
		switch bytesPerDim {
		case 1:
			p.Vals[i] = uint64(b[i])
		case 2:
			p.Vals[i] = uint64(binary.BigEndian.Uint16(b[2*i:]))
		case 4:
			p.Vals[i] = uint64(binary.BigEndian.Uint32(b[4*i:]))
		case 8:
			p.Vals[i] = binary.BigEndian.Uint64(b[8*i:])
		}
	}
	p.UserData = binary.BigEndian.Uint64(b[numDims*bytesPerDim:])
	return
}

// Len is part of sort.Interface.
func (s *PointArrayMem) Len() int {
	return len(s.points)
}

// Swap is part of sort.Interface.
func (s *PointArrayMem) Swap(i, j int) {
	s.points[i], s.points[j] = s.points[j], s.points[i]
}

// Less is part of sort.Interface.
func (s *PointArrayMem) Less(i, j int) bool {
	return s.points[i].Vals[s.byDim] < s.points[j].Vals[s.byDim]
}

func (s *PointArrayMem) GetPoint(idx int) (point Point) {
	point = s.points[idx]
	return
}

func (s *PointArrayMem) GetValue(idx int) (val uint64) {
	val = s.points[idx].Vals[s.byDim]
	return
}

func (s *PointArrayMem) SubArray(begin, end int) (sub PointArray) {
	sub = &PointArrayMem{
		points: s.points[begin:end],
		byDim:  s.byDim,
	}
	return
}

func (s *PointArrayMem) Erase(point Point) (found bool) {
	idx := 0
	for i, point2 := range s.points {
		//assumes each point's userData is unique
		if point.Equal(point2) {
			idx = i
			found = true
			break
		}
	}
	if found {
		s.points = append(s.points[:idx], s.points[idx+1:]...)
	}
	return
}

func (s *PointArrayMem) Append(point Point) {
	s.points = append(s.points, point)
}

func (s *PointArrayMem) ToExt(bytesPerDim int) (pae *PointArrayExt) {
	numDims := len(s.points[0].Vals)
	pointSize := numDims*bytesPerDim + 8
	size := len(s.points) * pointSize
	data := make([]byte, size)
	pae = &PointArrayExt{
		data:        data,
		numPoints:   len(s.points),
		byDim:       s.byDim,
		numDims:     numDims,
		bytesPerDim: bytesPerDim,
		pointSize:   pointSize,
	}
	for i, point := range s.points {
		point.Encode(data[i*pointSize:], bytesPerDim)
	}
	return
}

// Len is part of sort.Interface.
func (s *PointArrayExt) Len() int {
	return s.numPoints
}

// Swap is part of sort.Interface.
func (s *PointArrayExt) Swap(i, j int) {
	offI := i * s.pointSize
	offJ := j * s.pointSize
	for idx := 0; idx < s.pointSize; idx++ {
		s.data[offI+idx], s.data[offJ+idx] = s.data[offJ+idx], s.data[offI+idx]
	}
}

// Less is part of sort.Interface.
func (s *PointArrayExt) Less(i, j int) bool {
	valI := s.GetValue(i)
	valJ := s.GetValue(j)
	return valI < valJ
}

func (s *PointArrayExt) GetPoint(i int) (point Point) {
	point.Decode(s.data[i*s.pointSize:], s.numDims, s.bytesPerDim)
	return
}

func (s *PointArrayExt) GetValue(i int) (val uint64) {
	offI := i * s.pointSize
	switch s.bytesPerDim {
	case 1:
		val = uint64(s.data[offI+s.byDim])
	case 2:
		val = uint64(binary.BigEndian.Uint16(s.data[offI+2*s.byDim:]))
	case 4:
		val = uint64(binary.BigEndian.Uint32(s.data[offI+4*s.byDim:]))
	case 8:
		val = binary.BigEndian.Uint64(s.data[offI+8*s.byDim:])
	}
	return
}

func (s *PointArrayExt) SubArray(begin, end int) (sub PointArray) {
	sub = &PointArrayExt{
		data:        s.data[begin*s.pointSize : end*s.pointSize],
		numPoints:   end - begin,
		byDim:       s.byDim,
		bytesPerDim: s.bytesPerDim,
		numDims:     s.numDims,
		pointSize:   s.pointSize,
	}
	return
}

func (s *PointArrayExt) Erase(point Point) (found bool) {
	var i int
	for i = 0; i < s.numPoints; i++ {
		pI := s.GetPoint(i)
		//assumes each point's userData is unique
		found = point.Equal(pI)
		if found {
			break
		}
	}
	if found {
		//replace the matched point with the last point and decrease the array length
		offI := i * s.pointSize
		offJ := (s.numPoints - 1) * s.pointSize
		for idx := 0; idx < s.pointSize; idx++ {
			s.data[offI+idx] = s.data[offJ+idx]
			s.data[offJ+idx] = 0
		}
		s.numPoints--
	}
	return
}

func (s *PointArrayExt) Append(point Point) {
	off := s.numPoints * s.pointSize
	point.Encode(s.data[off:], s.bytesPerDim)
}

func (s *PointArrayExt) ToMem() (pam *PointArrayMem) {
	points := make([]Point, s.numPoints)
	for i := 0; i < s.numPoints; i++ {
		p := s.GetPoint(i)
		points[i] = p
	}
	pam = &PointArrayMem{
		points: points,
		byDim:  s.byDim,
	}
	return
}

// SplitPoints splits points per byDim
func SplitPoints(points PointArray, numStrips int) (splitValues []uint64, splitPoses []int) {
	if numStrips <= 1 {
		return
	}
	splitPos := points.Len() / 2
	nth.Element(points, splitPos)
	splitValue := points.GetValue(splitPos)

	numStrips1 := (numStrips + 1) / 2
	numStrips2 := numStrips - numStrips1
	splitValues1, splitPoses1 := SplitPoints(points.SubArray(0, splitPos), numStrips1)
	splitValues = append(splitValues, splitValues1...)
	splitPoses = append(splitPoses, splitPoses1...)
	splitValues = append(splitValues, splitValue)
	splitPoses = append(splitPoses, splitPos)
	splitValues2, splitPoses2 := SplitPoints(points.SubArray(splitPos, points.Len()), numStrips2)
	splitValues = append(splitValues, splitValues2...)
	for i := 0; i < len(splitPoses2); i++ {
		splitPoses = append(splitPoses, splitPos+splitPoses2[i])
	}
	return
}
<commit_msg>PointList<commit_after>package bkdtree

import (
	"encoding/binary"
	"sort"

	"github.com/keegancsmith/nth"
)

type Point struct {
	Vals     []uint64
	UserData uint64
}

type PointArray interface {
	sort.Interface
	GetPoint(idx int) Point
	GetValue(idx int) uint64
	SubArray(begin, end int) PointArray
	Erase(point Point) bool
	Append(point Point)
}

type PointList []Point

type PointArrayMem struct {
	points []Point
	byDim  int
}

type PointArrayExt struct {
	data        []byte
	numPoints   int
	byDim       int
	bytesPerDim int
	numDims     int
	pointSize   int
}

func (p *Point) Inside(lowPoint, highPoint Point) (isInside bool) {
	for dim := 0; dim < len(p.Vals); dim++ {
		if p.Vals[dim] < lowPoint.Vals[dim] || p.Vals[dim] > highPoint.Vals[dim] {
			return
		}
	}
	isInside = true
	return
}

func (p *Point) Equal(rhs Point) (res bool) {
	if p.UserData != rhs.UserData || len(p.Vals) != len(rhs.Vals) {
		return
	}
	for dim := 0; dim < len(p.Vals); dim++ {
		if p.Vals[dim] != rhs.Vals[dim] {
			return
		}
	}
	res = true
	return
}

//Encode encode in place. Refers to binary.Write impl in standard library.
//len(b) shall be no less than bytesPerDim*numDims+8
func (p *Point) Encode(b []byte, bytesPerDim int) {
	numDims := len(p.Vals)
	for i := 0; i < numDims; i++ {
		switch bytesPerDim {
		case 1:
			b[i] = byte(p.Vals[i])
		case 2:
			binary.BigEndian.PutUint16(b[2*i:], uint16(p.Vals[i]))
		case 4:
			binary.BigEndian.PutUint32(b[4*i:], uint32(p.Vals[i]))
		case 8:
			binary.BigEndian.PutUint64(b[8*i:], p.Vals[i])
		}
	}
	binary.BigEndian.PutUint64(b[numDims*bytesPerDim:], p.UserData)
	return
}

func (p *Point) Decode(b []byte, numDims int, bytesPerDim int) {
	p.Vals = make([]uint64, numDims)
	for i := 0; i < numDims; i++ {
		switch bytesPerDim {
		case 1:
			p.Vals[i] = uint64(b[i])
		case 2:
			p.Vals[i] = uint64(binary.BigEndian.Uint16(b[2*i:]))
		case 4:
			p.Vals[i] = uint64(binary.BigEndian.Uint32(b[4*i:]))
		case 8:
			p.Vals[i] = binary.BigEndian.Uint64(b[8*i:])
		}
	}
	p.UserData = binary.BigEndian.Uint64(b[numDims*bytesPerDim:])
	return
}

// Len is part of sort.Interface.
func (s PointList) Len() int {
	return len(s)
}

// Swap is part of sort.Interface.
func (s PointList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

// Less is part of sort.Interface.
func (s PointList) Less(i, j int) bool {
	for d := 0; d < len(s[0].Vals); d++ {
		if s[i].Vals[d] != s[j].Vals[d] {
			return s[i].Vals[d] < s[j].Vals[d]
		}
	}
	return false
}

// Len is part of sort.Interface.
func (s *PointArrayMem) Len() int {
	return len(s.points)
}

// Swap is part of sort.Interface.
func (s *PointArrayMem) Swap(i, j int) {
	s.points[i], s.points[j] = s.points[j], s.points[i]
}

// Less is part of sort.Interface.
func (s *PointArrayMem) Less(i, j int) bool {
	return s.points[i].Vals[s.byDim] < s.points[j].Vals[s.byDim]
}

func (s *PointArrayMem) GetPoint(idx int) (point Point) {
	point = s.points[idx]
	return
}

func (s *PointArrayMem) GetValue(idx int) (val uint64) {
	val = s.points[idx].Vals[s.byDim]
	return
}

func (s *PointArrayMem) SubArray(begin, end int) (sub PointArray) {
	sub = &PointArrayMem{
		points: s.points[begin:end],
		byDim:  s.byDim,
	}
	return
}

func (s *PointArrayMem) Erase(point Point) (found bool) {
	idx := 0
	for i, point2 := range s.points {
		//assumes each point's userData is unique
		if point.Equal(point2) {
			idx = i
			found = true
			break
		}
	}
	if found {
		s.points = append(s.points[:idx], s.points[idx+1:]...)
	}
	return
}

func (s *PointArrayMem) Append(point Point) {
	s.points = append(s.points, point)
}

func (s *PointArrayMem) ToExt(bytesPerDim int) (pae *PointArrayExt) {
	numDims := len(s.points[0].Vals)
	pointSize := numDims*bytesPerDim + 8
	size := len(s.points) * pointSize
	data := make([]byte, size)
	pae = &PointArrayExt{
		data:        data,
		numPoints:   len(s.points),
		byDim:       s.byDim,
		numDims:     numDims,
		bytesPerDim: bytesPerDim,
		pointSize:   pointSize,
	}
	for i, point := range s.points {
		point.Encode(data[i*pointSize:], bytesPerDim)
	}
	return
}

// Len is part of sort.Interface.
func (s *PointArrayExt) Len() int {
	return s.numPoints
}

// Swap is part of sort.Interface.
func (s *PointArrayExt) Swap(i, j int) {
	offI := i * s.pointSize
	offJ := j * s.pointSize
	for idx := 0; idx < s.pointSize; idx++ {
		s.data[offI+idx], s.data[offJ+idx] = s.data[offJ+idx], s.data[offI+idx]
	}
}

// Less is part of sort.Interface.
func (s *PointArrayExt) Less(i, j int) bool {
	valI := s.GetValue(i)
	valJ := s.GetValue(j)
	return valI < valJ
}

func (s *PointArrayExt) GetPoint(i int) (point Point) {
	point.Decode(s.data[i*s.pointSize:], s.numDims, s.bytesPerDim)
	return
}

func (s *PointArrayExt) GetValue(i int) (val uint64) {
	offI := i * s.pointSize
	switch s.bytesPerDim {
	case 1:
		val = uint64(s.data[offI+s.byDim])
	case 2:
		val = uint64(binary.BigEndian.Uint16(s.data[offI+2*s.byDim:]))
	case 4:
		val = uint64(binary.BigEndian.Uint32(s.data[offI+4*s.byDim:]))
	case 8:
		val = binary.BigEndian.Uint64(s.data[offI+8*s.byDim:])
	}
	return
}

func (s *PointArrayExt) SubArray(begin, end int) (sub PointArray) {
	sub = &PointArrayExt{
		data:        s.data[begin*s.pointSize : end*s.pointSize],
		numPoints:   end - begin,
		byDim:       s.byDim,
		bytesPerDim: s.bytesPerDim,
		numDims:     s.numDims,
		pointSize:   s.pointSize,
	}
	return
}

func (s *PointArrayExt) Erase(point Point) (found bool) {
	var i int
	for i = 0; i < s.numPoints; i++ {
		pI := s.GetPoint(i)
		//assumes each point's userData is unique
		found = point.Equal(pI)
		if found {
			break
		}
	}
	if found {
		//replace the matched point with the last point and decrease the array length
		offI := i * s.pointSize
		offJ := (s.numPoints - 1) * s.pointSize
		for idx := 0; idx < s.pointSize; idx++ {
			s.data[offI+idx] = s.data[offJ+idx]
			s.data[offJ+idx] = 0
		}
		s.numPoints--
	}
	return
}

func (s *PointArrayExt) Append(point Point) {
	off := s.numPoints * s.pointSize
	point.Encode(s.data[off:], s.bytesPerDim)
}

func (s *PointArrayExt) ToMem() (pam *PointArrayMem) {
	points := make([]Point, s.numPoints)
	for i := 0; i < s.numPoints; i++ {
		p := s.GetPoint(i)
		points[i] = p
	}
	pam = &PointArrayMem{
		points: points,
		byDim:  s.byDim,
	}
	return
}

// SplitPoints splits points per byDim
func SplitPoints(points PointArray, numStrips int) (splitValues []uint64, splitPoses []int) {
	if numStrips <= 1 {
		return
	}
	splitPos := points.Len() / 2
	nth.Element(points, splitPos)
	splitValue := points.GetValue(splitPos)

	numStrips1 := (numStrips + 1) / 2
	numStrips2 := numStrips - numStrips1
	splitValues1, splitPoses1 := SplitPoints(points.SubArray(0, splitPos), numStrips1)
	splitValues = append(splitValues, splitValues1...)
	splitPoses = append(splitPoses, splitPoses1...)
	splitValues = append(splitValues, splitValue)
	splitPoses = append(splitPoses, splitPos)
	splitValues2, splitPoses2 := SplitPoints(points.SubArray(splitPos, points.Len()), numStrips2)
	splitValues = append(splitValues, splitValues2...)
	for i := 0; i < len(splitPoses2); i++ {
		splitPoses = append(splitPoses, splitPos+splitPoses2[i])
	}
	return
}
<|endoftext|>