<commit_before>package types

import (
	"testing"
	"time"
)

// TestJourneyString shocases the String method without first unmarshalling
func TestJourneyString(t *testing.T) {
	from := Container{
		ID:   "2.399803859568057;48.88150165806373",
		Name: "54 Boulevard d'Algérie (Paris)",
		embeddedObject: Address{
			ID:    "2.399803859568057;48.88150165806373",
			Label: "54 Boulevard d'Algérie (Paris)",
			Name:  "Boulevard d'Algérie",
		},
	}

	to := Container{
		ID:   "2.344404;48.835114",
		Name: "54 Boulevard Arago (Paris)",
		embeddedObject: Address{
			ID:    "2.344404;48.835114",
			Label: "54 Boulevard Arago (Paris)",
			Name:  "Boulevard Arago",
		},
	}

	departure, err := time.Parse("2006-01-02T15:04:05", "2017-04-11T21:33:55")
	if err != nil {
		t.Fatal(err)
	}
	arrival, err := time.Parse("2006-01-02T15:04:05", "2017-04-11T22:24:13")
	if err != nil {
		t.Fatal(err)
	}

	section := Section{
		From:      from,
		To:        to,
		Departure: departure,
		Arrival:   arrival,
		Duration:  time.Duration(3018) * time.Second,
		Display: Display{
			Label:        "11",
			PhysicalMode: "Métro",
		},
	}

	journey := Journey{
		From:      from,
		To:        to,
		Departure: departure,
		Arrival:   arrival,
		Duration:  time.Duration(3018) * time.Second,
		Sections:  []Section{section},
	}

	t.Logf("For journey we have: %s", journey.String())
}

// TestJourneyUnmarshal_NoCompare tries to unmarshal all json test data for this type, but doesn't compare its response to a known correct output.
func TestJourneyUnmarshal_NoCompare(t *testing.T) {
	// Get the input
	pairs := testData["journey"].known
	if len(pairs) == 0 {
		t.Skip("No data to test")
	}

	// Create the run function generator, allowing us to run this in parallel
	rgen := func(data []byte) func(t *testing.T) {
		return func(t *testing.T) {
			var j = &Journey{}

			err := j.UnmarshalJSON(data)
			if err != nil {
				t.Errorf("Error while unmarshalling: %v", err)
			}

			str := j.String()
			t.Log("\n" + str)
		}
	}

	// For each of them, let's run a subtest
	for name, pair := range pairs {
		// Get the run function
		rfunc := rgen(pair.raw)

		// Run !
		t.Run(name, rfunc)
	}
}

// BenchmarkJourneyUnmarshal benchmarks Journey unmarshalling via subbenchmarks
func BenchmarkJourneyUnmarshal(b *testing.B) {
	// Get the bench data
	data := testData["journey"].bench
	if len(data) == 0 {
		b.Skip("No data to test")
	}

	// Run function generator, allowing parallel run
	runGen := func(in []byte) func(*testing.B) {
		return func(b *testing.B) {
			for i := 0; i < b.N; i++ {
				// Unmarshal a Journey
				var j = &Journey{}
				_ = j.UnmarshalJSON(in)
			}
		}
	}

	// Loop over all corpus
	for name, datum := range data {
		// Get run function
		runFunc := runGen(datum)

		// Run it !
		b.Run(name, runFunc)
	}
}
<commit_msg>Cosmetic change to BenchmarkXXX names for harmonisation<commit_after>package types

import (
	"testing"
	"time"
)

// TestJourneyString shocases the String method without first unmarshalling
func TestJourneyString(t *testing.T) {
	from := Container{
		ID:   "2.399803859568057;48.88150165806373",
		Name: "54 Boulevard d'Algérie (Paris)",
		embeddedObject: Address{
			ID:    "2.399803859568057;48.88150165806373",
			Label: "54 Boulevard d'Algérie (Paris)",
			Name:  "Boulevard d'Algérie",
		},
	}

	to := Container{
		ID:   "2.344404;48.835114",
		Name: "54 Boulevard Arago (Paris)",
		embeddedObject: Address{
			ID:    "2.344404;48.835114",
			Label: "54 Boulevard Arago (Paris)",
			Name:  "Boulevard Arago",
		},
	}

	departure, err := time.Parse("2006-01-02T15:04:05", "2017-04-11T21:33:55")
	if err != nil {
		t.Fatal(err)
	}
	arrival, err := time.Parse("2006-01-02T15:04:05", "2017-04-11T22:24:13")
	if err != nil {
		t.Fatal(err)
	}

	section := Section{
		From:      from,
		To:        to,
		Departure: departure,
		Arrival:   arrival,
		Duration:  time.Duration(3018) * time.Second,
		Display: Display{
			Label:        "11",
			PhysicalMode: "Métro",
		},
	}

	journey := Journey{
		From:      from,
		To:        to,
		Departure: departure,
		Arrival:   arrival,
		Duration:  time.Duration(3018) * time.Second,
		Sections:  []Section{section},
	}

	t.Logf("For journey we have: %s", journey.String())
}

// TestJourneyUnmarshal_NoCompare tries to unmarshal all json test data for this type, but doesn't compare its response to a known correct output.
func TestJourneyUnmarshal_NoCompare(t *testing.T) {
	// Get the input
	pairs := testData["journey"].known
	if len(pairs) == 0 {
		t.Skip("No data to test")
	}

	// Create the run function generator, allowing us to run this in parallel
	rgen := func(data []byte) func(t *testing.T) {
		return func(t *testing.T) {
			var j = &Journey{}

			err := j.UnmarshalJSON(data)
			if err != nil {
				t.Errorf("Error while unmarshalling: %v", err)
			}

			str := j.String()
			t.Log("\n" + str)
		}
	}

	// For each of them, let's run a subtest
	for name, pair := range pairs {
		// Get the run function
		rfunc := rgen(pair.raw)

		// Run !
		t.Run(name, rfunc)
	}
}

// BenchmarkJourney_UnmarshalJSON benchmarks Journey unmarshalling via subbenchmarks
func BenchmarkJourney_UnmarshalJSON(b *testing.B) {
	// Get the bench data
	data := testData["journey"].bench
	if len(data) == 0 {
		b.Skip("No data to test")
	}

	// Run function generator, allowing parallel run
	runGen := func(in []byte) func(*testing.B) {
		return func(b *testing.B) {
			for i := 0; i < b.N; i++ {
				// Unmarshal a Journey
				var j = &Journey{}
				_ = j.UnmarshalJSON(in)
			}
		}
	}

	// Loop over all corpus
	for name, datum := range data {
		// Get run function
		runFunc := runGen(datum)

		// Run it !
		b.Run(name, runFunc)
	}
}
<|endoftext|>


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

// Package tests contains test cases. To run the tests go to tests directory and run:
// RUN_TESTBED=1 go test -v

package tests

import (
	"fmt"
	"path"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/open-telemetry/opentelemetry-collector-contrib/testbed/testbed"
)

func TestIdleMode(t *testing.T) {

	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)

	resultDir, err := filepath.Abs(path.Join("results", t.Name()))
	require.NoError(t, err)

	sender := testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t))
	receiver := testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t))
	cfg := createConfigYaml(t, sender, receiver, resultDir, nil, nil)
	cp := testbed.NewChildProcessCollector()
	cleanup, err := cp.PrepareConfig(cfg)
	require.NoError(t, err)
	t.Cleanup(cleanup)

	tc := testbed.NewTestCase(
		t,
		dataProvider,
		sender,
		receiver,
		cp,
		&testbed.PerfTestValidator{},
		performanceResultsSummary,
		testbed.WithResourceLimits(testbed.ResourceSpec{ExpectedMaxCPU: 20, ExpectedMaxRAM: 83}),
	)
	tc.StartAgent()

	tc.Sleep(tc.Duration)

	tc.Stop()
}

const ballastConfig = `
  memory_ballast:
    size_mib: %d
`

func TestBallastMemory(t *testing.T) {
	tests := []struct {
		ballastSize uint32
		maxRSS      uint32
	}{
		{100, 70},
		{500, 80},
		{1000, 110},
	}

	resultDir, err := filepath.Abs(path.Join("results", t.Name()))
	require.NoError(t, err)

	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)
	for _, test := range tests {
		sender := testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t))
		receiver := testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t))
		ballastCfg := createConfigYaml(
			t, sender, receiver, resultDir, nil,
			map[string]string{"memory_ballast": fmt.Sprintf(ballastConfig, test.ballastSize)})
		cp := testbed.NewChildProcessCollector()
		cleanup, err := cp.PrepareConfig(ballastCfg)
		require.NoError(t, err)
		tc := testbed.NewTestCase(
			t,
			dataProvider,
			sender,
			receiver,
			cp,
			&testbed.PerfTestValidator{},
			performanceResultsSummary,
			testbed.WithSkipResults(),
			testbed.WithResourceLimits(testbed.ResourceSpec{ExpectedMaxRAM: test.maxRSS}),
		)
		tc.StartAgent()

		var rss, vms uint32
		// It is possible that the process is not ready or the ballast code path
		// is not hit immediately so we give the process up to a couple of seconds
		// to fire up and setup ballast. 2 seconds is a long time for this case but
		// it is short enough to not be annoying if the test fails repeatedly
		tc.WaitForN(func() bool {
			rss, vms, _ = tc.AgentMemoryInfo()
			return vms > test.ballastSize
		}, time.Second*2, fmt.Sprintf("VMS must be greater than %d", test.ballastSize))

		// https://github.com/open-telemetry/opentelemetry-collector/issues/3233
		// given that the maxRSS isn't an absolute maximum and that the actual maximum might be a bit off,
		// we give some room here instead of failing when the memory usage isn't that much higher than the max
		lenientMax := 1.1 * float32(test.maxRSS)
		assert.LessOrEqual(t, float32(rss), lenientMax)
		cleanup()
		tc.Stop()
	}
}
<commit_msg>`testbed`: increase limit for TestBallastMemory (#6691)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package tests contains test cases. To run the tests go to tests directory and run:
// RUN_TESTBED=1 go test -v

package tests

import (
	"fmt"
	"path"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/open-telemetry/opentelemetry-collector-contrib/testbed/testbed"
)

func TestIdleMode(t *testing.T) {

	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)

	resultDir, err := filepath.Abs(path.Join("results", t.Name()))
	require.NoError(t, err)

	sender := testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t))
	receiver := testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t))
	cfg := createConfigYaml(t, sender, receiver, resultDir, nil, nil)
	cp := testbed.NewChildProcessCollector()
	cleanup, err := cp.PrepareConfig(cfg)
	require.NoError(t, err)
	t.Cleanup(cleanup)

	tc := testbed.NewTestCase(
		t,
		dataProvider,
		sender,
		receiver,
		cp,
		&testbed.PerfTestValidator{},
		performanceResultsSummary,
		testbed.WithResourceLimits(testbed.ResourceSpec{ExpectedMaxCPU: 20, ExpectedMaxRAM: 83}),
	)
	tc.StartAgent()

	tc.Sleep(tc.Duration)

	tc.Stop()
}

const ballastConfig = `
  memory_ballast:
    size_mib: %d
`

func TestBallastMemory(t *testing.T) {
	tests := []struct {
		ballastSize uint32
		maxRSS      uint32
	}{
		{100, 70},
		{500, 90},
		{1000, 110},
	}

	resultDir, err := filepath.Abs(path.Join("results", t.Name()))
	require.NoError(t, err)

	options := testbed.LoadOptions{DataItemsPerSecond: 10_000, ItemsPerBatch: 10}
	dataProvider := testbed.NewPerfTestDataProvider(options)
	for _, test := range tests {
		t.Run(fmt.Sprintf("ballast-size-%d", test.ballastSize), func(t *testing.T) {
			sender := testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t))
			receiver := testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t))
			ballastCfg := createConfigYaml(
				t, sender, receiver, resultDir, nil,
				map[string]string{"memory_ballast": fmt.Sprintf(ballastConfig, test.ballastSize)})
			cp := testbed.NewChildProcessCollector()
			cleanup, err := cp.PrepareConfig(ballastCfg)
			require.NoError(t, err)
			tc := testbed.NewTestCase(
				t,
				dataProvider,
				sender,
				receiver,
				cp,
				&testbed.PerfTestValidator{},
				performanceResultsSummary,
				testbed.WithSkipResults(),
				testbed.WithResourceLimits(testbed.ResourceSpec{ExpectedMaxRAM: test.maxRSS}),
			)
			tc.StartAgent()

			var rss, vms uint32
			// It is possible that the process is not ready or the ballast code path
			// is not hit immediately so we give the process up to a couple of seconds
			// to fire up and setup ballast. 2 seconds is a long time for this case but
			// it is short enough to not be annoying if the test fails repeatedly
			tc.WaitForN(func() bool {
				rss, vms, _ = tc.AgentMemoryInfo()
				return vms > test.ballastSize
			}, time.Second*2, fmt.Sprintf("VMS must be greater than %d", test.ballastSize))

			// https://github.com/open-telemetry/opentelemetry-collector/issues/3233
			// given that the maxRSS isn't an absolute maximum and that the actual maximum might be a bit off,
			// we give some room here instead of failing when the memory usage isn't that much higher than the max
			lenientMax := 1.1 * float32(test.maxRSS)
			assert.LessOrEqual(t, float32(rss), lenientMax, fmt.Sprintf("The RSS memory usage (%d) is >10%% higher than the limit (%d).", rss, test.maxRSS))
			cleanup()
			tc.Stop()
		})
	}
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/stretchr/testify/assert"
	"github.com/yamamoto-febc/libsacloud/sacloud"
	"testing"
	"time"
)

const testLoadBalancerName = "libsacloud_test_LoadBalancer"

var (
	createLoadBalancerValues = &sacloud.CreateLoadBalancerValue{
		VRID:         1,
		Plan:         sacloud.LoadBalancerPlanStandard,
		IPAddress1:   "192.168.11.11",
		MaskLen:      24,
		DefaultRoute: "192.168.11.1",
		Name:         "TestLoadBalancer",
		Description:  "TestDescription",
		Tags:         []string{"tag1", "tag2", "tag3"},
	}
	loadBalancerSettings = []*sacloud.LoadBalancerSetting{
		{
			VirtualIPAddress: "192.168.11.101",
			Port:             "8080",
			DelayLoop:        "30",
			SorryServer:      "192.168.11.201",
			Servers: []*sacloud.LoadBalancerServer{
				{
					IPAddress: "192.168.11.51",
					Port:      "8080",
					HealthCheck: &sacloud.LoadBalancerHealthCheck{
						Protocol: "http",
						Path:     "/",
						Status:   "200",
					},
				},
				{
					IPAddress: "192.168.11.52",
					Port:      "8080",
					HealthCheck: &sacloud.LoadBalancerHealthCheck{
						Protocol: "http",
						Path:     "/",
						Status:   "200",
					},
				},
			},
		},
	}
)

func TestLoadBalancerCRUD(t *testing.T) {
	api := client.LoadBalancer

	//prerequired
	sw := client.Switch.New()
	sw.Name = testLoadBalancerName
	sw, err := client.Switch.Create(sw)

	assert.NoError(t, err)
	assert.NotEmpty(t, sw)

	//CREATE
	createLoadBalancerValues.SwitchID = sw.ID
	newItem, err := sacloud.CreateNewLoadBalancerSingle(createLoadBalancerValues, loadBalancerSettings)
	assert.NoError(t, err)

	item, err := api.Create(newItem)

	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	id := item.ID

	api.SleepWhileCopying(id, 20*time.Minute, 3)
	if !assert.NoError(t, err) {
		return
	}

	api.SleepUntilUp(id, 10*time.Minute)
	if !assert.NoError(t, err) {
		return
	}

	//READ
	item, err = api.Read(id)
	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	//UPDATE
	item.Description = "after"
	item, err = api.Update(id, item)

	assert.NoError(t, err)
	assert.NotEqual(t, item.Description, "before")

	_, err = api.Stop(id)
	assert.NoError(t, err)

	err = api.SleepUntilDown(id, 120*time.Second)
	if !assert.NoError(t, err) {
		return
	}

	//Delete
	_, err = api.Delete(id)
	assert.NoError(t, err)

	_, err = client.Switch.Delete(sw.ID)
	assert.NoError(t, err)

}

func TestLoadBalancerCRUDWithoutVIP(t *testing.T) {
	api := client.LoadBalancer

	//prerequired
	sw := client.Switch.New()
	sw.Name = testLoadBalancerName
	sw, err := client.Switch.Create(sw)

	assert.NoError(t, err)
	assert.NotEmpty(t, sw)

	//CREATE
	createLoadBalancerValues.SwitchID = sw.ID
	newItem, err := sacloud.CreateNewLoadBalancerSingle(createLoadBalancerValues, nil)
	assert.NoError(t, err)

	item, err := api.Create(newItem)
	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	id := item.ID

	api.SleepWhileCopying(id, 20*time.Minute, 3)

	//power off
	_, err = api.Stop(id)
	assert.NoError(t, err)
	err = api.SleepUntilDown(id, 120*time.Second)
	if !assert.NoError(t, err) {
		return
	}

	//Delete
	_, err = api.Delete(id)
	assert.NoError(t, err)

	_, err = client.Switch.Delete(sw.ID)
	assert.NoError(t, err)

}

func init() {
	testSetupHandlers = append(testSetupHandlers, cleanupLoadBalancer)
	testTearDownHandlers = append(testTearDownHandlers, cleanupLoadBalancer)
}

func cleanupLoadBalancer() {
	sw, _ := client.Switch.Reset().WithNameLike(testLoadBalancerName).Find()
	for _, item := range sw.Switches {
		client.Switch.Delete(item.ID)
	}

	items, _ := client.LoadBalancer.Reset().WithNameLike(testLoadBalancerName).Find()
	for _, item := range items.LoadBalancers {
		client.LoadBalancer.Delete(item.ID)
	}

}
<commit_msg>Fix the LoadBalancer API test case<commit_after>package api

import (
	"github.com/stretchr/testify/assert"
	"github.com/yamamoto-febc/libsacloud/sacloud"
	"testing"
	"time"
)

const testLoadBalancerName = "libsacloud_test_LoadBalancer"

var (
	createLoadBalancerValues = &sacloud.CreateLoadBalancerValue{
		VRID:         1,
		Plan:         sacloud.LoadBalancerPlanStandard,
		IPAddress1:   "192.168.11.11",
		MaskLen:      24,
		DefaultRoute: "192.168.11.1",
		Name:         "TestLoadBalancer",
		Description:  "TestDescription",
		Tags:         []string{"tag1", "tag2", "tag3"},
	}
	loadBalancerSettings = []*sacloud.LoadBalancerSetting{
		{
			VirtualIPAddress: "192.168.11.101",
			Port:             "8080",
			DelayLoop:        "30",
			SorryServer:      "192.168.11.201",
			Servers: []*sacloud.LoadBalancerServer{
				{
					IPAddress: "192.168.11.51",
					Port:      "8080",
					HealthCheck: &sacloud.LoadBalancerHealthCheck{
						Protocol: "http",
						Path:     "/",
						Status:   "200",
					},
				},
				{
					IPAddress: "192.168.11.52",
					Port:      "8080",
					HealthCheck: &sacloud.LoadBalancerHealthCheck{
						Protocol: "http",
						Path:     "/",
						Status:   "200",
					},
				},
			},
		},
	}
)

func TestLoadBalancerCRUD(t *testing.T) {
	api := client.LoadBalancer

	//prerequired
	sw := client.Switch.New()
	sw.Name = testLoadBalancerName
	sw, err := client.Switch.Create(sw)

	assert.NoError(t, err)
	assert.NotEmpty(t, sw)

	//CREATE
	createLoadBalancerValues.SwitchID = sw.ID
	newItem, err := sacloud.CreateNewLoadBalancerSingle(createLoadBalancerValues, loadBalancerSettings)
	assert.NoError(t, err)

	item, err := api.Create(newItem)

	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	id := item.ID

	err = api.SleepWhileCopying(id, 20*time.Minute, 3)
	if !assert.NoError(t, err) {
		return
	}

	err = api.SleepUntilUp(id, 10*time.Minute)
	if !assert.NoError(t, err) {
		return
	}

	//READ
	item, err = api.Read(id)
	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	//UPDATE
	item.Description = "after"
	item, err = api.Update(id, item)

	assert.NoError(t, err)
	assert.NotEqual(t, item.Description, "before")

	_, err = api.Stop(id)
	assert.NoError(t, err)

	err = api.SleepUntilDown(id, 120*time.Second)
	if !assert.NoError(t, err) {
		return
	}

	//Delete
	_, err = api.Delete(id)
	assert.NoError(t, err)

	_, err = client.Switch.Delete(sw.ID)
	assert.NoError(t, err)

}

func TestLoadBalancerCRUDWithoutVIP(t *testing.T) {
	api := client.LoadBalancer

	//prerequired
	sw := client.Switch.New()
	sw.Name = testLoadBalancerName
	sw, err := client.Switch.Create(sw)

	assert.NoError(t, err)
	assert.NotEmpty(t, sw)

	//CREATE
	createLoadBalancerValues.SwitchID = sw.ID
	newItem, err := sacloud.CreateNewLoadBalancerSingle(createLoadBalancerValues, nil)
	assert.NoError(t, err)

	item, err := api.Create(newItem)
	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	id := item.ID

	err = api.SleepWhileCopying(id, 20*time.Minute, 3)
	if !assert.NoError(t, err) {
		return
	}

	err = api.SleepUntilUp(id, 10*time.Minute)
	if !assert.NoError(t, err) {
		return
	}
	//power off
	_, err = api.Stop(id)
	assert.NoError(t, err)
	err = api.SleepUntilDown(id, 120*time.Second)
	if !assert.NoError(t, err) {
		return
	}

	//Delete
	_, err = api.Delete(id)
	assert.NoError(t, err)

	_, err = client.Switch.Delete(sw.ID)
	assert.NoError(t, err)

}

func init() {
	testSetupHandlers = append(testSetupHandlers, cleanupLoadBalancer)
	testTearDownHandlers = append(testTearDownHandlers, cleanupLoadBalancer)
}

func cleanupLoadBalancer() {
	sw, _ := client.Switch.Reset().WithNameLike(testLoadBalancerName).Find()
	for _, item := range sw.Switches {
		client.Switch.Delete(item.ID)
	}

	items, _ := client.LoadBalancer.Reset().WithNameLike(testLoadBalancerName).Find()
	for _, item := range items.LoadBalancers {
		client.LoadBalancer.Delete(item.ID)
	}

}
<|endoftext|>


<commit_before>package goregexp

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

func TestProject(t *testing.T) {
	Convey("Test new regexp res container", t, func() {

		Convey("A Regexp res container can be build", func() {
			r := regexp.MustCompile("test")
			rx := NewReres("test", r)
			So(rx.String(), ShouldEqual, "Regexp res for 'test': (0-0; len 4) [[0 4]]")
		})

		Convey("A Regexp res container can display the string on which the regexp is applied", func() {
			r := regexp.MustCompile("test")
			rx := NewReres("test2", r)
			So(rx.Text(), ShouldEqual, "test2")
		})

		Convey("A Regexp res container knows if it has any match", func() {
			r := regexp.MustCompile("test")
			rx := NewReres("test3", r)
			So(rx.HasAnyMatch(), ShouldBeTrue)
			rx = NewReres("aaa", r)
			So(rx.HasAnyMatch(), ShouldBeFalse)
		})

		Convey("A Regexp res can reference groups", func() {
			r := regexp.MustCompile("(test)+")
			rx := NewReres("testatest", r)
			So(rx.HasNext(), ShouldBeTrue)
			rx.Next()
			So(rx.HasNext(), ShouldBeFalse)
			rx.ResetNext()
			So(rx.HasNext(), ShouldBeTrue)
		})

		Convey("A Regexp res can get prefix and suffix", func() {
			r := regexp.MustCompile("(test)+")
			rx := NewReres("aaatesttestbbb", r)
			So(rx.Prefix(), ShouldEqual, "aaa")
			So(rx.Suffix(), ShouldEqual, "bbb")
			So(rx.HasNext(), ShouldBeFalse)
		})

		Convey("A Regexp res can get the first char of the current match", func() {
			r := regexp.MustCompile("(.est)")
			rx := NewReres("aaaTestcccUestbbb", r)
			So(rx.FirstChar(), ShouldEqual, 'T')
			So(rx.HasNext(), ShouldBeTrue)
			rx.Next()
			So(rx.FirstChar(), ShouldEqual, 'U')
			So(rx.HasNext(), ShouldBeFalse)
		})

		Convey("A Regexp res can detect if the first char of the current match is \\", func() {
			r := regexp.MustCompile("(.est)")
			rx := NewReres("aaaTestccc\\estbbb", r)
			So(rx.IsEscaped(), ShouldBeFalse)
			rx.Next()
			So(rx.IsEscaped(), ShouldBeTrue)
		})

		Convey("A Regexp res can get full match", func() {
			r := regexp.MustCompile("(.est)")
			rx := NewReres("aaa1Testccc2Uestbbb3", r)
			So(rx.FullMatch(), ShouldEqual, "Test")
			rx.Next()
			So(rx.FullMatch(), ShouldEqual, "Uest")
		})

		Convey("A Regexp res can check if a group is matched", func() {
			r := regexp.MustCompile("(Test)(b?)(c)")
			rx := NewReres("Testc", r)
			// fmt.Println(rx.matches)
			So(rx.HasGroup(1), ShouldBeTrue)
			So(rx.HasGroup(2), ShouldBeFalse)
			So(rx.HasGroup(3), ShouldBeTrue)
		})

		Convey("A Regexp res get the group (string)", func() {
			r := regexp.MustCompile("(TesT)(a?)(d)")
			rx := NewReres("TesTd", r)
			// fmt.Println(rx.matches)
			So(rx.Group(1), ShouldEqual, "TesT")
			So(rx.Group(2), ShouldEqual, "")
			So(rx.Group(3), ShouldEqual, "d")
		})

	})
}
<commit_msg>Complete escape test<commit_after>package goregexp

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

func TestProject(t *testing.T) {
	Convey("Test new regexp res container", t, func() {

		Convey("A Regexp res container can be build", func() {
			r := regexp.MustCompile("test")
			rx := NewReres("test", r)
			So(rx.String(), ShouldEqual, "Regexp res for 'test': (0-0; len 4) [[0 4]]")
		})

		Convey("A Regexp res container can display the string on which the regexp is applied", func() {
			r := regexp.MustCompile("test")
			rx := NewReres("test2", r)
			So(rx.Text(), ShouldEqual, "test2")
		})

		Convey("A Regexp res container knows if it has any match", func() {
			r := regexp.MustCompile("test")
			rx := NewReres("test3", r)
			So(rx.HasAnyMatch(), ShouldBeTrue)
			rx = NewReres("aaa", r)
			So(rx.HasAnyMatch(), ShouldBeFalse)
		})

		Convey("A Regexp res can reference groups", func() {
			r := regexp.MustCompile("(test)+")
			rx := NewReres("testatest", r)
			So(rx.HasNext(), ShouldBeTrue)
			rx.Next()
			So(rx.HasNext(), ShouldBeFalse)
			rx.ResetNext()
			So(rx.HasNext(), ShouldBeTrue)
		})

		Convey("A Regexp res can get prefix and suffix", func() {
			r := regexp.MustCompile("(test)+")
			rx := NewReres("aaatesttestbbb", r)
			So(rx.Prefix(), ShouldEqual, "aaa")
			So(rx.Suffix(), ShouldEqual, "bbb")
			So(rx.HasNext(), ShouldBeFalse)
		})

		Convey("A Regexp res can get the first char of the current match", func() {
			r := regexp.MustCompile("(.est)")
			rx := NewReres("aaaTestcccUestbbb", r)
			So(rx.FirstChar(), ShouldEqual, 'T')
			So(rx.HasNext(), ShouldBeTrue)
			rx.Next()
			So(rx.FirstChar(), ShouldEqual, 'U')
			So(rx.HasNext(), ShouldBeFalse)
		})

		Convey("A Regexp res can detect if the first char of the current match is \\", func() {
			r := regexp.MustCompile("(.est)")
			rx := NewReres("aaaTestccc\\estbbb", r)
			So(rx.IsEscaped(), ShouldBeFalse)
			rx.Next()
			So(rx.IsEscaped(), ShouldBeTrue)
			So(rx.HasNext(), ShouldBeFalse)
		})

		Convey("A Regexp res can get full match", func() {
			r := regexp.MustCompile("(.est)")
			rx := NewReres("aaa1Testccc2Uestbbb3", r)
			So(rx.FullMatch(), ShouldEqual, "Test")
			rx.Next()
			So(rx.FullMatch(), ShouldEqual, "Uest")
		})

		Convey("A Regexp res can check if a group is matched", func() {
			r := regexp.MustCompile("(Test)(b?)(c)")
			rx := NewReres("Testc", r)
			// fmt.Println(rx.matches)
			So(rx.HasGroup(1), ShouldBeTrue)
			So(rx.HasGroup(2), ShouldBeFalse)
			So(rx.HasGroup(3), ShouldBeTrue)
		})

		Convey("A Regexp res get the group (string)", func() {
			r := regexp.MustCompile("(TesT)(a?)(d)")
			rx := NewReres("TesTd", r)
			// fmt.Println(rx.matches)
			So(rx.Group(1), ShouldEqual, "TesT")
			So(rx.Group(2), ShouldEqual, "")
			So(rx.Group(3), ShouldEqual, "d")
		})

	})
}
<|endoftext|>


<commit_before>package operation

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strconv"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type AssignResult struct {
	Fid       string `json:"fid,omitempty"`
	Url       string `json:"url,omitempty"`
	PublicUrl string `json:"publicUrl,omitempty"`
	Count     uint64 `json:"count,omitempty"`
	Error     string `json:"error,omitempty"`
}

func Assign(server string, count uint64, replication string, collection string, ttl string) (*AssignResult, error) {
	values := make(url.Values)
	values.Add("count", strconv.FormatUint(count, 10))
	if replication != "" {
		values.Add("replication", replication)
	}
	if collection != "" {
		values.Add("collection", collection)
	}
	if ttl != "" {
		values.Add("ttl", ttl)
	}
	jsonBlob, err := util.Post("http://"+server+"/dir/assign", values)
	glog.V(2).Info("assign result :", string(jsonBlob))
	if err != nil {
		return nil, err
	}
	var ret AssignResult
	err = json.Unmarshal(jsonBlob, &ret)
	if err != nil {
		return nil, fmt.Errorf("/dir/assign result JSON unmarshal error:%v, json:%s", err, string(jsonBlob))
	}
	if ret.Count <= 0 {
		return nil, errors.New(ret.Error)
	}
	return &ret, nil
}
<commit_msg>add options params for the Assign func<commit_after>package operation

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strconv"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type AssignResult struct {
	Fid       string `json:"fid,omitempty"`
	Url       string `json:"url,omitempty"`
	PublicUrl string `json:"publicUrl,omitempty"`
	Count     uint64 `json:"count,omitempty"`
	Error     string `json:"error,omitempty"`
}

/*
options params meaning:
options[0] main data Center
options[1] main rack
options[2] main data node
*/
func Assign(server string, count uint64, replication string, collection string, ttl string, options ...string) (*AssignResult, error) {
	values := make(url.Values)
	values.Add("count", strconv.FormatUint(count, 10))
	if replication != "" {
		values.Add("replication", replication)
	}
	if collection != "" {
		values.Add("collection", collection)
	}
	if ttl != "" {
		values.Add("ttl", ttl)
	}

	var dataCenter, rack, dataNode string
	switch len(options) {
	case 1:
		dataCenter = options[0]
	case 2:
		dataCenter = options[0]
		rack = options[1]
	case 3:
		dataCenter = options[0]
		rack = options[1]
		dataNode = options[2]
	default:
	}

	if dataCenter != "" {
		values.Add("dataCenter", dataCenter)
	}
	if rack != "" {
		values.Add("rack", rack)
	}
	if dataNode != "" {
		values.Add("dataNode", dataNode)
	}

	jsonBlob, err := util.Post("http://"+server+"/dir/assign", values)
	glog.V(2).Info("assign result :", string(jsonBlob))
	if err != nil {
		return nil, err
	}
	var ret AssignResult
	err = json.Unmarshal(jsonBlob, &ret)
	if err != nil {
		return nil, fmt.Errorf("/dir/assign result JSON unmarshal error:%v, json:%s", err, string(jsonBlob))
	}
	if ret.Count <= 0 {
		return nil, errors.New(ret.Error)
	}
	return &ret, nil
}
<|endoftext|>


<commit_before>package gostruct

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"golang.org/x/net/html"
)

// helpers

func doc(t *testing.T, body string) *goquery.Document {
	root, err := html.Parse(strings.NewReader(body))
	require.Nil(t, err)
	return goquery.NewDocumentFromNode(root)
}

func baseDoc(t *testing.T) *goquery.Document {
	return doc(t, "
hello
")
}

func makeServer(t *testing.T, body string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "text/html")
			fmt.Fprintln(w, body)
		}))
}

// noop cases

func TestEmptyStruct(t *testing.T) {
	s := struct{}{}

	assert.Nil(t, Populate(&s, baseDoc(t)))
}

func TestNoSelectorsStruct(t *testing.T) {
	s := struct {
		Foo string
	}{}

	assert.Nil(t, Populate(&s, baseDoc(t)))
	assert.Equal(t, "", s.Foo)
}

func TestUnexportedFieldsStruct(t *testing.T) {
	s := struct {
		foo string
	}{}

	assert.Nil(t, Populate(&s, baseDoc(t)))
}

// wrong arguments

func TestNotAPointer(t *testing.T) {
	assert.NotNil(t, Populate(struct{}{}, baseDoc(t)))
	assert.NotNil(t, Populate(42, baseDoc(t)))
}

func TestNotAStructPointer(t *testing.T) {
	n := 2

	assert.NotNil(t, Populate(&n, baseDoc(t)))
}

// string field

func TestEmptyStringElement(t *testing.T) {
	s := struct {
		Title string `gostruct:"#title"`
	}{"something"}

	assert.Nil(t, Populate(&s, doc(t, `<h1 id="title"></h1>`)))
	assert.Equal(t, "", s.Title)
}

func TestStringElement(t *testing.T) {
	s := struct {
		Title string `gostruct:"#title"`
	}{}

	assert.Nil(t, Populate(&s, doc(t, `<h1 id="title">hello</h1>`)))
	assert.Equal(t, "hello", s.Title)
}

func TestMultipleStringElements(t *testing.T) {
	s := struct {
		Letters string `gostruct:".c"`
	}{}

	assert.Nil(t, Populate(&s, doc(t, `<p class="c">H</p>x<p class="c">i</p>`)))
	assert.Equal(t, "Hi", s.Letters)
}

// bool field

func TestEmptyBoolElement(t *testing.T) {
	s := struct {
		Title bool `gostruct:"#title"`
	}{true}

	d := doc(t, `<h1 id="title"></h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, false, s.Title)
}

func TestEmptyBoolSelection(t *testing.T) {
	s := struct {
		Title bool `gostruct:".foo"`
	}{}

	d := doc(t, `<h1 id="title">hi</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, false, s.Title)
}

func TestBoolElement(t *testing.T) {
	s := struct {
		Title bool `gostruct:"#title"`
	}{}

	d := doc(t, `<h1 id="title">hi</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, true, s.Title)
}

// int field

func TestEmptyIntElement(t *testing.T) {
	s := struct {
		Title int `gostruct:"#title"`
	}{42}

	d := doc(t, `<h1 id="title"></h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 0, s.Title)
}

func TestEmptyIntSelection(t *testing.T) {
	s := struct {
		Title int `gostruct:".t"`
	}{42}

	d := doc(t, `<h1 id="title">37</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 0, s.Title)
}

func TestIntWrongValue(t *testing.T) {
	s := struct {
		Title int `gostruct:"#title"`
	}{42}

	d := doc(t, `<h1 id="title">two</h1>`)

	assert.NotNil(t, Populate(&s, d))
	assert.Equal(t, 42, s.Title, "fields shouldn't be changed on parsing error")
}

func TestIntMultipleElements(t *testing.T) {
	s := struct {
		Count int `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p><p>17</p><p>1034</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 42, s.Count, "int fields should only take the first element")
}

func TestNegativeInt(t *testing.T) {
	s := struct {
		Count int `gostruct:"p"`
	}{}

	d := doc(t, `<p>-42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, -42, s.Count)
}

func TestInt(t *testing.T) {
	s := struct {
		Count int `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 42, s.Count)
}

func TestInt8(t *testing.T) {
	s := struct {
		Count int8 `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, int8(42), s.Count)
}

// uint field

func TestEmptyUintElement(t *testing.T) {
	s := struct {
		Count uint `gostruct:"p"`
	}{}

	d := doc(t, `<p></p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, uint64(0), s.Count)
}

func TestUintNegativeInt(t *testing.T) {
	s := struct {
		Count uint `gostruct:"p"`
	}{}

	d := doc(t, `<p>-42</p>`)

	assert.NotNil(t, Populate(&s, d))
}

func TestUint(t *testing.T) {
	s := struct {
		Count uint `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, uint(42), s.Count)
}

// float field

func TestFloatFirstElement(t *testing.T) {
	s := struct {
		Count float64 `gostruct:"p"`
	}{}

	d := doc(t, `<p>42.6</p><p>25.7</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, float64(42.6), s.Count)
}

func TestEmptyFloatElement(t *testing.T) {
	s := struct {
		Count float64 `gostruct:"p"`
	}{}

	d := doc(t, `<p></p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, float64(0), s.Count)
}

func TestFloat(t *testing.T) {
	s := struct {
		Count float64 `gostruct:"p"`
	}{}

	d := doc(t, `<p>42.6</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, float64(42.6), s.Count)
}

// sub-structs

func TestEmptySubStruct(t *testing.T) {
	s := struct {
		X struct{} `gostruct:"#foo"`
	}{}

	assert.Nil(t, Populate(&s, doc(t, `<p id="#foo">x</p>`)))
}

func TestUnexportedSubStruct(t *testing.T) {
	s := struct {
		x struct {
			Foo string `gostruct:"#foo"`
		} `gostruct:".x"`
	}{}

	d := doc(t, `<p class="x"><span id="foo">Bar</span></p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "", s.x.Foo)
}

func TestSubStruct(t *testing.T) {
	s := struct {
		Header struct {
			Title string `gostruct:"h1"`
		} `gostruct:"header"`
	}{}

	d := doc(t, `<header><h1>Good</h1></header><h1>Bad</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "Good", s.Header.Title)
}

func TestSubStructPtr(t *testing.T) {
	s := struct {
		Header *struct {
			Title string `gostruct:"h1"`
		} `gostruct:"header"`
	}{}

	d := doc(t, `<header><h1>Good</h1></header><h1>Bad</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "Good", s.Header.Title)
}

// fetching test

func TestFetchWrongURL(t *testing.T) {
	s := struct{}{}

	assert.NotNil(t, Fetch(&s, "::not an URL"))
}

func TestFetch(t *testing.T) {
	server := makeServer(t, `<h1>Hello</h1>`)
	defer server.Close()

	s := struct {
		Title string `gostruct:"h1"`
	}{}

	assert.Nil(t, Fetch(&s, server.URL))
	assert.Equal(t, "Hello", s.Title)
}

// general tests

func TestPopulatePointer(t *testing.T) {
	s := &struct {
		Title string `gostruct:"h1"`
	}{}

	d := doc(t, `<h1>This is a test</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "This is a test", s.Title)
}

func TestMultipleFields(t *testing.T) {
	s := struct {
		Title  string        `gostruct:"h1"`
		Desc   string        `gostruct:"p"`
		PubAge time.Duration `gostruct:".pub-age"`
	}{}

	d := doc(t, `

This is a test

This is its description

			Author: Foo

			Published 1h30m ago.

	`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "This is a test", s.Title)
	assert.Equal(t, "This is its description", s.Desc)
	assert.Equal(t, "1h30m0s", s.PubAge.String())
}
<commit_msg>slice tests<commit_after>package gostruct

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"golang.org/x/net/html"
)

// helpers

func doc(t *testing.T, body string) *goquery.Document {
	root, err := html.Parse(strings.NewReader(body))
	require.Nil(t, err)
	return goquery.NewDocumentFromNode(root)
}

func baseDoc(t *testing.T) *goquery.Document {
	return doc(t, "
hello
")
}

func makeServer(t *testing.T, body string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "text/html")
			fmt.Fprintln(w, body)
		}))
}

// noop cases

func TestEmptyStruct(t *testing.T) {
	s := struct{}{}

	assert.Nil(t, Populate(&s, baseDoc(t)))
}

func TestNoSelectorsStruct(t *testing.T) {
	s := struct {
		Foo string
	}{}

	assert.Nil(t, Populate(&s, baseDoc(t)))
	assert.Equal(t, "", s.Foo)
}

func TestUnexportedFieldsStruct(t *testing.T) {
	s := struct {
		foo string
	}{}

	assert.Nil(t, Populate(&s, baseDoc(t)))
}

// wrong arguments

func TestNotAPointer(t *testing.T) {
	assert.NotNil(t, Populate(struct{}{}, baseDoc(t)))
	assert.NotNil(t, Populate(42, baseDoc(t)))
}

func TestNotAStructPointer(t *testing.T) {
	n := 2

	assert.NotNil(t, Populate(&n, baseDoc(t)))
}

// string field

func TestEmptyStringElement(t *testing.T) {
	s := struct {
		Title string `gostruct:"#title"`
	}{"something"}

	assert.Nil(t, Populate(&s, doc(t, `<h1 id="title"></h1>`)))
	assert.Equal(t, "", s.Title)
}

func TestStringElement(t *testing.T) {
	s := struct {
		Title string `gostruct:"#title"`
	}{}

	assert.Nil(t, Populate(&s, doc(t, `<h1 id="title">hello</h1>`)))
	assert.Equal(t, "hello", s.Title)
}

func TestMultipleStringElements(t *testing.T) {
	s := struct {
		Letters string `gostruct:".c"`
	}{}

	assert.Nil(t, Populate(&s, doc(t, `<p class="c">H</p>x<p class="c">i</p>`)))
	assert.Equal(t, "Hi", s.Letters)
}

// bool field

func TestEmptyBoolElement(t *testing.T) {
	s := struct {
		Title bool `gostruct:"#title"`
	}{true}

	d := doc(t, `<h1 id="title"></h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, false, s.Title)
}

func TestEmptyBoolSelection(t *testing.T) {
	s := struct {
		Title bool `gostruct:".foo"`
	}{}

	d := doc(t, `<h1 id="title">hi</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, false, s.Title)
}

func TestBoolElement(t *testing.T) {
	s := struct {
		Title bool `gostruct:"#title"`
	}{}

	d := doc(t, `<h1 id="title">hi</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, true, s.Title)
}

// int field

func TestEmptyIntElement(t *testing.T) {
	s := struct {
		Title int `gostruct:"#title"`
	}{42}

	d := doc(t, `<h1 id="title"></h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 0, s.Title)
}

func TestEmptyIntSelection(t *testing.T) {
	s := struct {
		Title int `gostruct:".t"`
	}{42}

	d := doc(t, `<h1 id="title">37</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 0, s.Title)
}

func TestIntWrongValue(t *testing.T) {
	s := struct {
		Title int `gostruct:"#title"`
	}{42}

	d := doc(t, `<h1 id="title">two</h1>`)

	assert.NotNil(t, Populate(&s, d))
	assert.Equal(t, 42, s.Title, "fields shouldn't be changed on parsing error")
}

func TestIntMultipleElements(t *testing.T) {
	s := struct {
		Count int `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p><p>17</p><p>1034</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 42, s.Count, "int fields should only take the first element")
}

func TestNegativeInt(t *testing.T) {
	s := struct {
		Count int `gostruct:"p"`
	}{}

	d := doc(t, `<p>-42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, -42, s.Count)
}

func TestInt(t *testing.T) {
	s := struct {
		Count int `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, 42, s.Count)
}

func TestInt8(t *testing.T) {
	s := struct {
		Count int8 `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, int8(42), s.Count)
}

// uint field

func TestEmptyUintElement(t *testing.T) {
	s := struct {
		Count uint `gostruct:"p"`
	}{}

	d := doc(t, `<p></p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, uint64(0), s.Count)
}

func TestUintNegativeInt(t *testing.T) {
	s := struct {
		Count uint `gostruct:"p"`
	}{}

	d := doc(t, `<p>-42</p>`)

	assert.NotNil(t, Populate(&s, d))
}

func TestUint(t *testing.T) {
	s := struct {
		Count uint `gostruct:"p"`
	}{}

	d := doc(t, `<p>42</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, uint(42), s.Count)
}

// float field

func TestFloatFirstElement(t *testing.T) {
	s := struct {
		Count float64 `gostruct:"p"`
	}{}

	d := doc(t, `<p>42.6</p><p>25.7</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, float64(42.6), s.Count)
}

func TestEmptyFloatElement(t *testing.T) {
	s := struct {
		Count float64 `gostruct:"p"`
	}{}

	d := doc(t, `<p></p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, float64(0), s.Count)
}

func TestFloat(t *testing.T) {
	s := struct {
		Count float64 `gostruct:"p"`
	}{}

	d := doc(t, `<p>42.6</p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, float64(42.6), s.Count)
}

// sub-structs

func TestEmptySubStruct(t *testing.T) {
	s := struct {
		X struct{} `gostruct:"#foo"`
	}{}

	assert.Nil(t, Populate(&s, doc(t, `<p id="#foo">x</p>`)))
}

func TestUnexportedSubStruct(t *testing.T) {
	s := struct {
		x struct {
			Foo string `gostruct:"#foo"`
		} `gostruct:".x"`
	}{}

	d := doc(t, `<p class="x"><span id="foo">Bar</span></p>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "", s.x.Foo)
}

func TestSubStruct(t *testing.T) {
	s := struct {
		Header struct {
			Title string `gostruct:"h1"`
		} `gostruct:"header"`
	}{}

	d := doc(t, `<header><h1>Good</h1></header><h1>Bad</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "Good", s.Header.Title)
}

func TestSubStructPtr(t *testing.T) {
	s := struct {
		Header *struct {
			Title string `gostruct:"h1"`
		} `gostruct:"header"`
	}{}

	d := doc(t, `<header><h1>Good</h1></header><h1>Bad</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "Good", s.Header.Title)
}

// fetching test

func TestFetchWrongURL(t *testing.T) {
	s := struct{}{}

	assert.NotNil(t, Fetch(&s, "::not an URL"))
}

func TestFetch(t *testing.T) {
	server := makeServer(t, `<h1>Hello</h1>`)
	defer server.Close()

	s := struct {
		Title string `gostruct:"h1"`
	}{}

	assert.Nil(t, Fetch(&s, server.URL))
	assert.Equal(t, "Hello", s.Title)
}

// byte slice tests

func TestPopulateByteSliceEmptyString(t *testing.T) {
	s := struct {
		Title []byte `gostruct:"h1"`
	}{}

	d := doc(t, `<h1></h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, []byte(""), s.Title)
}

func TestPopulateByteSlice(t *testing.T) {
	s := struct {
		Title []byte `gostruct:"h1"`
	}{}

	d := doc(t, `<h1>Hello</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, []byte("Hello"), s.Title)
}

// slice tests

func TestPopulateSliceEmptySelection(t *testing.T) {
	s := struct {
		Names []string `gostruct:"li"`
	}{}

	d := doc(t, `<ol></ol>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, []string{}, s.Names)
}

func TestPopulateStringSlice(t *testing.T) {
	s := struct {
		Names []string `gostruct:"li"`
	}{}

	d := doc(t, `<ol><li>A</li><li>B</li><li>C</li></ol>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, []string{"A", "B", "C"}, s.Names)
}

// general tests

func TestPopulatePointer(t *testing.T) {
	s := &struct {
		Title string `gostruct:"h1"`
	}{}

	d := doc(t, `<h1>This is a test</h1>`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "This is a test", s.Title)
}

func TestMultipleFields(t *testing.T) {
	s := struct {
		Title  string        `gostruct:"h1"`
		Desc   string        `gostruct:"p"`
		PubAge time.Duration `gostruct:".pub-age"`
	}{}

	d := doc(t, `

This is a test

This is its description

			Author: Foo

			Published 1h30m ago.

	`)

	assert.Nil(t, Populate(&s, d))
	assert.Equal(t, "This is a test", s.Title)
	assert.Equal(t, "This is its description", s.Desc)
	assert.Equal(t, "1h30m0s", s.PubAge.String())
}
<|endoftext|>


<commit_before>package gotermBox

import (
	"bytes"
	"io"

	"github.com/antongulenko/goterm"
)

// CliLogBox can display a box spanning over the entire command-line screen
// containing arbitrary content that can be updated from outside, and an additional
// section at the bottom containing log messages captured using a LogBuffer.
type CliLogBox struct {
	// LogBuffer provides the underlying functionality for capturing log messages.
	// CliLogBox acts like an extension of LogBuffer. After calling Init(),
	// the log capturing must be taken care of using RegisterMessageHooks(),
	// InterceptLogger() and RestoreLogger().
	*LogBuffer

	// NoUtf8 can be set to true to replace UTF8 border drawing characters with
	// regular ASCII characters.
	NoUtf8 bool

	// LogLines configures the minimum number of log entries that must remain visible
	// in the lower part of the console box. The log entries are appended directly
	// to the actual output and usually take the rest of the screen. If the box content
	// is so long, that it would leave less than LogLines log entries, the content is
	// truncated. The truncation is visualized by three dots in the separator line
	// between the content and the log entries.
	LogLines int

	// MessageBuffer configures the number of messages stored in the underlying LogBuffer.
	MessageBuffer int
}

// Init initializes the underlying LogBuffer and should be called before any other methods.
func (box *CliLogBox) Init() {
	box.LogBuffer = NewDefaultLogBuffer(box.MessageBuffer)
}

// Updates refreshes the entire display output. It can be called in arbitrary time intervals,
// but should never be called concurrently. The content must be written by the given function,
// which also receives the width of the screen. If it prints lines that are longer than the screen
// width, they will be cut off. It can produce an arbitrary number of lines.
func (box *CliLogBox) Update(writeContent func(out io.Writer, width int)) {
	gotermBox := goterm.Box{
		Buf:      new(bytes.Buffer),
		Width:    goterm.Width(),
		Height:   goterm.Height() - 1, // Subtract 1 for the line with cursor
		PaddingX: 1,
		PaddingY: 0,
	}
	var separator, dots string
	if box.NoUtf8 {
		gotermBox.Border = "- | - - - -"
		separator = "-"
		dots = "... "
	} else {
		gotermBox.Border = "═ ║ ╔ ╗ ╚ ╝"
		separator = "═"
		dots = "··· "
	}
	lines := gotermBox.Height - 3 // borders + separator

	counter := newlineCounter{out: &gotermBox}
	if box.LogLines > 0 {
		counter.max_lines = lines - box.LogLines
	}
	writeContent(&counter, gotermBox.Width)
	lines -= counter.num

	if counter.num > 0 {
		i := 0
		if counter.truncated {
			gotermBox.Write([]byte(dots))
			i += len(dots)
		}
		for i := 0; i < gotermBox.Width; i++ {
			gotermBox.Write([]byte(separator))
		}
		gotermBox.Write([]byte("\n"))
	}
	box.PrintMessages(&gotermBox, lines)
	goterm.MoveCursor(1, 1)
	goterm.Print(gotermBox)
	goterm.Flush()
}

type newlineCounter struct {
	out       io.Writer
	num       int
	max_lines int
	truncated bool
}

func (counter *newlineCounter) Write(data []byte) (int, error) {
	total := len(data)
	if counter.max_lines <= 0 || counter.num < counter.max_lines {
		written := 0
		start := 0
		for i, char := range data {
			if char == '\n' {
				counter.num++
				num, err := counter.out.Write(data[start : i+1])
				written += num
				start = i + 1
				if err != nil {
					return written, err
				}
				if counter.max_lines > 0 && counter.num >= counter.max_lines {
					return total, err
				}
			}
		}
		num, err := counter.out.Write(data[start:])
		written += num
		if err != nil {
			return written, err
		}
	} else {
		counter.truncated = true
	}
	return total, nil
}
<commit_msg>fixing<commit_after>package gotermBox

import (
	"bytes"
	"io"

	"github.com/antongulenko/goterm"
)

// CliLogBox can display a box spanning over the entire command-line screen
// containing arbitrary content that can be updated from outside, and an additional
// section at the bottom containing log messages captured using a LogBuffer.
type CliLogBox struct {
	// LogBuffer provides the underlying functionality for capturing log messages.
	// CliLogBox acts like an extension of LogBuffer. After calling Init(),
	// the log capturing must be taken care of using RegisterMessageHooks(),
	// InterceptLogger() and RestoreLogger().
	*LogBuffer

	// NoUtf8 can be set to true to replace UTF8 border drawing characters with
	// regular ASCII characters.
	NoUtf8 bool

	// LogLines configures the minimum number of log entries that must remain visible
	// in the lower part of the console box. The log entries are appended directly
	// to the actual output and usually take the rest of the screen. If the box content
	// is so long, that it would leave less than LogLines log entries, the content is
	// truncated. The truncation is visualized by three dots in the separator line
	// between the content and the log entries.
	LogLines int

	// MessageBuffer configures the number of messages stored in the underlying LogBuffer.
	MessageBuffer int
}

// Init initializes the underlying LogBuffer and should be called before any other methods.
func (box *CliLogBox) Init() {
	box.LogBuffer = NewDefaultLogBuffer(box.MessageBuffer)
}

// Updates refreshes the entire display output. It can be called in arbitrary time intervals,
// but should never be called concurrently. The content must be written by the given function,
// which also receives the width of the screen. If it prints lines that are longer than the screen
// width, they will be cut off. It can produce an arbitrary number of lines.
func (box *CliLogBox) Update(writeContent func(out io.Writer, width int)) {
	gotermBox := &goterm.Box{
		Buf:      new(bytes.Buffer),
		Width:    goterm.Width(),
		Height:   goterm.Height() - 1, // Subtract 1 for the line with cursor
		PaddingX: 1,
		PaddingY: 0,
	}
	var separator, dots string
	if box.NoUtf8 {
		gotermBox.Border = "- | - - - -"
		separator = "-"
		dots = "... "
	} else {
		gotermBox.Border = "═ ║ ╔ ╗ ╚ ╝"
		separator = "═"
		dots = "··· "
	}
	lines := gotermBox.Height - 3 // borders + separator

	counter := newlineCounter{out: gotermBox}
	if box.LogLines > 0 {
		counter.max_lines = lines - box.LogLines
	}
	writeContent(&counter, gotermBox.Width)
	lines -= counter.num

	if counter.num > 0 {
		i := 0
		if counter.truncated {
			gotermBox.Write([]byte(dots))
			i += len(dots)
		}
		for i := 0; i < gotermBox.Width; i++ {
			gotermBox.Write([]byte(separator))
		}
		gotermBox.Write([]byte("\n"))
	}
	box.PrintMessages(gotermBox, lines)
	goterm.MoveCursor(1, 1)
	goterm.Print(gotermBox)
	goterm.Flush()
}

type newlineCounter struct {
	out       io.Writer
	num       int
	max_lines int
	truncated bool
}

func (counter *newlineCounter) Write(data []byte) (int, error) {
	total := len(data)
	if counter.max_lines <= 0 || counter.num < counter.max_lines {
		written := 0
		start := 0
		for i, char := range data {
			if char == '\n' {
				counter.num++
				num, err := counter.out.Write(data[start : i+1])
				written += num
				start = i + 1
				if err != nil {
					return written, err
				}
				if counter.max_lines > 0 && counter.num >= counter.max_lines {
					return total, err
				}
			}
		}
		num, err := counter.out.Write(data[start:])
		written += num
		if err != nil {
			return written, err
		}
	} else {
		counter.truncated = true
	}
	return total, nil
}
<|endoftext|>


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

package wav

import (
	"encoding/binary"
	"errors"
	"io"
	"sync"

	"azul3d.org/audio.v1"
)

const (
	// Data format codes

	// PCM
	wave_FORMAT_PCM = 0x0001

	// IEEE float
	wave_FORMAT_IEEE_FLOAT = 0x0003

	// 8-bit ITU-T G.711 A-law
	wave_FORMAT_ALAW = 0x0006

	// 8-bit ITU-T G.711 µ-law
	wave_FORMAT_MULAW = 0x0007

	// Determined by SubFormat
	wave_FORMAT_EXTENSIBLE = 0xFFFE
)

type decoder struct {
	access sync.RWMutex

	format, bitsPerSample   uint16
	chunkSize, currentCount uint32
	dataChunkBegin          int32

	r      interface{}
	rd     io.Reader
	config *audio.Config
}

// advance advances the byte counter by sz. If the chunk size is known and
// after advancement the byte counter is larger than the chunk size, then
// audio.EOS is returned.
//
// If the chunk size is not known, the data chunk marker is extended by sz as
// well.
func (d *decoder) advance(sz int) error {
	d.currentCount += uint32(sz)
	if d.chunkSize > 0 {
		if d.currentCount > d.chunkSize {
			return audio.EOS
		}
	} else {
		d.dataChunkBegin += int32(sz)
	}
	return nil
}

func (d *decoder) bRead(data interface{}, sz int) error {
	err := d.advance(sz)
	if err != nil {
		return err
	}
	return binary.Read(d.rd, binary.LittleEndian, data)
}

// Reads and returns the next RIFF chunk, note that always len(ident) == 4
// E.g.
//
//  "fmt " (notice space).
//
// Length is length of chunk data.
//
// Returns any read errors.
func (d *decoder) nextChunk() (ident string, length uint32, err error) {
	// Read chunk identity, like "RIFF" or "fmt "
	var chunkIdent [4]byte
	err = d.bRead(&chunkIdent, binary.Size(chunkIdent))
	if err != nil {
		return "", 0, err
	}
	ident = string(chunkIdent[:])

	// Read chunk length
	err = d.bRead(&length, binary.Size(length))
	if err != nil {
		return "", 0, err
	}
	return
}

func (d *decoder) Seek(sample uint64) error {
	rs, ok := d.r.(io.ReadSeeker)
	if ok {
		offset := int64(sample * (uint64(d.bitsPerSample) / 8))
		_, err := rs.Seek(int64(d.dataChunkBegin)+offset, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *decoder) readPCM8(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM8Samples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM8(sample)
		} else {
			f64 := audio.PCM8ToF64(audio.PCM8(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM16(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM16Samples)

	var sample int16
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(2) // 2 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM16(sample)
		} else {
			f64 := audio.PCM16ToF64(audio.PCM16(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM24(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample [3]uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(3) // 3 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		var ss audio.PCM32
		ss = audio.PCM32(sample[0]) | audio.PCM32(sample[1])<<8 | audio.PCM32(sample[2])<<16
		if (ss & 0x800000) > 0 {
			ss |= ^0xffffff
		}

		if bbOk {
			bb[read] = ss
		} else {
			f64 := audio.PCM32ToF64(ss)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample int32
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM32(sample)
		} else {
			f64 := audio.PCM32ToF64(audio.PCM32(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readF32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.F32Samples)

	var sample float32
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.F32(sample)
		} else {
			b.Set(read, audio.F64(sample))
		}
	}

	return
}

func (d *decoder) readF64(b audio.Slice) (read int, err error) {
	var sample float64
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(8) // 8 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		b.Set(read, audio.F64(sample))
	}

	return
}

func (d *decoder) readMuLaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.MuLawSamples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.MuLaw(sample)
		} else {
			p16 := audio.MuLawToPCM16(audio.MuLaw(sample))
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) readALaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.ALawSamples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.ALaw(sample)
		} else {
			p16 := audio.ALawToPCM16(audio.ALaw(sample))
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) Read(b audio.Slice) (read int, err error) {
	if b.Len() == 0 {
		return
	}

	d.access.Lock()
	defer d.access.Unlock()

	switch d.format {
	case wave_FORMAT_PCM:
		switch d.bitsPerSample {
		case 8:
			return d.readPCM8(b)
		case 16:
			return d.readPCM16(b)
		case 24:
			return d.readPCM24(b)
		case 32:
			return d.readPCM32(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_IEEE_FLOAT:
		switch d.bitsPerSample {
		case 32:
			return d.readF32(b)
		case 64:
			return d.readF64(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_MULAW:
		return d.readMuLaw(b)
	case wave_FORMAT_ALAW:
		return d.readALaw(b)
	default:
		panic("invalid format")
	}
	return
}

func (d *decoder) Config() audio.Config {
	d.access.RLock()
	defer d.access.RUnlock()

	return *d.config
}

// ErrUnsupported defines an error for decoding wav data that is valid (by the
// wave specification) but not supported by the decoder in this package.
//
// This error only happens for audio files containing extensible wav data.
var ErrUnsupported = errors.New("wav: data format is valid but not supported by decoder")

// NewDecoder returns a new initialized audio decoder for the io.Reader or
// io.ReadSeeker, r.
func newDecoder(r interface{}) (audio.Decoder, error) {
	d := new(decoder)
	d.r = r

	switch t := r.(type) {
	case io.Reader:
		d.rd = t
	case io.ReadSeeker:
		d.rd = io.Reader(t)
	default:
		panic("NewDecoder(): Invalid reader type; must be io.Reader or io.ReadSeeker!")
	}

	var (
		complete bool

		c16 fmtChunk16
		c18 fmtChunk18
		c40 fmtChunk40
	)
	for !complete {
		ident, length, err := d.nextChunk()
		if err != nil {
			return nil, err
		}

		switch ident {
		case "RIFF":
			var format [4]byte
			err = d.bRead(&format, binary.Size(format))
			if string(format[:]) != "WAVE" {
				return nil, audio.ErrInvalidData
			}

		case "fmt ":
			// Always contains the 16-byte chunk
			err = d.bRead(&c16, binary.Size(c16))
			if err != nil {
				return nil, err
			}
			d.bitsPerSample = c16.BitsPerSample

			// Sometimes contains extensive 18/40 total byte chunks
			switch length {
			case 18:
				err = d.bRead(&c18, binary.Size(c18))
				if err != nil {
					return nil, err
				}
			case 40:
				err = d.bRead(&c40, binary.Size(c40))
				if err != nil {
					return nil, err
				}
			}

			// Verify format tag
			ft := c16.FormatTag
			switch {
			case ft == wave_FORMAT_PCM && (d.bitsPerSample == 8 || d.bitsPerSample == 16 || d.bitsPerSample == 24 || d.bitsPerSample == 32):
				break
			case ft == wave_FORMAT_IEEE_FLOAT && (d.bitsPerSample == 32 || d.bitsPerSample == 64):
				break
			case ft == wave_FORMAT_ALAW && d.bitsPerSample == 8:
				break
			case ft == wave_FORMAT_MULAW && d.bitsPerSample == 8:
				break
			// We don't support extensible wav files
			//case wave_FORMAT_EXTENSIBLE:
			//	break
			default:
				return nil, ErrUnsupported
			}

			// Assign format tag for later (See Read() method)
			d.format = c16.FormatTag

			// We now have enough information to build the audio configuration
			d.config = &audio.Config{
				Channels:   int(c16.Channels),
				SampleRate: int(c16.SamplesPerSec),
			}

		case "fact":
			// We need to scan fact chunk first.
			var fact factChunk
			err = d.bRead(&fact, binary.Size(fact))
			if err != nil {
				return nil, err
			}

		case "data":
			// Read the data chunk header now
			d.chunkSize = length
			complete = true
		}
	}

	return d, nil
}

func init() {
	audio.RegisterFormat("wav", "RIFF", newDecoder)
}
<commit_msg>Improve Float32/Float64 decoding performance by 64-65%; See azul3d/audio#5<commit_after>// Copyright 2014 The Azul3D Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package wav

import (
	"encoding/binary"
	"errors"
	"io"
	"math"
	"sync"

	"azul3d.org/audio.v1"
)

const (
	// Data format codes

	// PCM
	wave_FORMAT_PCM = 0x0001

	// IEEE float
	wave_FORMAT_IEEE_FLOAT = 0x0003

	// 8-bit ITU-T G.711 A-law
	wave_FORMAT_ALAW = 0x0006

	// 8-bit ITU-T G.711 µ-law
	wave_FORMAT_MULAW = 0x0007

	// Determined by SubFormat
	wave_FORMAT_EXTENSIBLE = 0xFFFE
)

type decoder struct {
	access sync.RWMutex

	format, bitsPerSample   uint16
	chunkSize, currentCount uint32
	dataChunkBegin          int32

	r      interface{}
	rd     io.Reader
	config *audio.Config
}

// advance advances the byte counter by sz. If the chunk size is known and
// after advancement the byte counter is larger than the chunk size, then
// audio.EOS is returned.
//
// If the chunk size is not known, the data chunk marker is extended by sz as
// well.
func (d *decoder) advance(sz int) error {
	d.currentCount += uint32(sz)
	if d.chunkSize > 0 {
		if d.currentCount > d.chunkSize {
			return audio.EOS
		}
	} else {
		d.dataChunkBegin += int32(sz)
	}
	return nil
}

func (d *decoder) bRead(data interface{}, sz int) error {
	err := d.advance(sz)
	if err != nil {
		return err
	}
	return binary.Read(d.rd, binary.LittleEndian, data)
}

// Reads and returns the next RIFF chunk, note that always len(ident) == 4
// E.g.
//
//  "fmt " (notice space).
//
// Length is length of chunk data.
//
// Returns any read errors.
func (d *decoder) nextChunk() (ident string, length uint32, err error) {
	// Read chunk identity, like "RIFF" or "fmt "
	var chunkIdent [4]byte
	err = d.bRead(&chunkIdent, binary.Size(chunkIdent))
	if err != nil {
		return "", 0, err
	}
	ident = string(chunkIdent[:])

	// Read chunk length
	err = d.bRead(&length, binary.Size(length))
	if err != nil {
		return "", 0, err
	}
	return
}

func (d *decoder) Seek(sample uint64) error {
	rs, ok := d.r.(io.ReadSeeker)
	if ok {
		offset := int64(sample * (uint64(d.bitsPerSample) / 8))
		_, err := rs.Seek(int64(d.dataChunkBegin)+offset, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *decoder) readPCM8(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM8Samples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM8(sample)
		} else {
			f64 := audio.PCM8ToF64(audio.PCM8(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM16(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM16Samples)

	var sample int16
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(2) // 2 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM16(sample)
		} else {
			f64 := audio.PCM16ToF64(audio.PCM16(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM24(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample [3]uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(3) // 3 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		var ss audio.PCM32
		ss = audio.PCM32(sample[0]) | audio.PCM32(sample[1])<<8 | audio.PCM32(sample[2])<<16
		if (ss & 0x800000) > 0 {
			ss |= ^0xffffff
		}

		if bbOk {
			bb[read] = ss
		} else {
			f64 := audio.PCM32ToF64(ss)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample int32
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM32(sample)
		} else {
			f64 := audio.PCM32ToF64(audio.PCM32(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readF32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.F32Samples)

	var sample uint32
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.F32(math.Float32frombits(sample))
		} else {
			b.Set(read, audio.F64(math.Float32frombits(sample)))
		}
	}

	return
}

func (d *decoder) readF64(b audio.Slice) (read int, err error) {
	var sample uint64
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(8) // 8 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		b.Set(read, audio.F64(math.Float64frombits(sample)))
	}

	return
}

func (d *decoder) readMuLaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.MuLawSamples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.MuLaw(sample)
		} else {
			p16 := audio.MuLawToPCM16(audio.MuLaw(sample))
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) readALaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.ALawSamples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.ALaw(sample)
		} else {
			p16 := audio.ALawToPCM16(audio.ALaw(sample))
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) Read(b audio.Slice) (read int, err error) {
	if b.Len() == 0 {
		return
	}

	d.access.Lock()
	defer d.access.Unlock()

	switch d.format {
	case wave_FORMAT_PCM:
		switch d.bitsPerSample {
		case 8:
			return d.readPCM8(b)
		case 16:
			return d.readPCM16(b)
		case 24:
			return d.readPCM24(b)
		case 32:
			return d.readPCM32(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_IEEE_FLOAT:
		switch d.bitsPerSample {
		case 32:
			return d.readF32(b)
		case 64:
			return d.readF64(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_MULAW:
		return d.readMuLaw(b)
	case wave_FORMAT_ALAW:
		return d.readALaw(b)
	default:
		panic("invalid format")
	}
	return
}

func (d *decoder) Config() audio.Config {
	d.access.RLock()
	defer d.access.RUnlock()

	return *d.config
}

// ErrUnsupported defines an error for decoding wav data that is valid (by the
// wave specification) but not supported by the decoder in this package.
//
// This error only happens for audio files containing extensible wav data.
var ErrUnsupported = errors.New("wav: data format is valid but not supported by decoder")

// NewDecoder returns a new initialized audio decoder for the io.Reader or
// io.ReadSeeker, r.
func newDecoder(r interface{}) (audio.Decoder, error) {
	d := new(decoder)
	d.r = r

	switch t := r.(type) {
	case io.Reader:
		d.rd = t
	case io.ReadSeeker:
		d.rd = io.Reader(t)
	default:
		panic("NewDecoder(): Invalid reader type; must be io.Reader or io.ReadSeeker!")
	}

	var (
		complete bool

		c16 fmtChunk16
		c18 fmtChunk18
		c40 fmtChunk40
	)
	for !complete {
		ident, length, err := d.nextChunk()
		if err != nil {
			return nil, err
		}

		switch ident {
		case "RIFF":
			var format [4]byte
			err = d.bRead(&format, binary.Size(format))
			if string(format[:]) != "WAVE" {
				return nil, audio.ErrInvalidData
			}

		case "fmt ":
			// Always contains the 16-byte chunk
			err = d.bRead(&c16, binary.Size(c16))
			if err != nil {
				return nil, err
			}
			d.bitsPerSample = c16.BitsPerSample

			// Sometimes contains extensive 18/40 total byte chunks
			switch length {
			case 18:
				err = d.bRead(&c18, binary.Size(c18))
				if err != nil {
					return nil, err
				}
			case 40:
				err = d.bRead(&c40, binary.Size(c40))
				if err != nil {
					return nil, err
				}
			}

			// Verify format tag
			ft := c16.FormatTag
			switch {
			case ft == wave_FORMAT_PCM && (d.bitsPerSample == 8 || d.bitsPerSample == 16 || d.bitsPerSample == 24 || d.bitsPerSample == 32):
				break
			case ft == wave_FORMAT_IEEE_FLOAT && (d.bitsPerSample == 32 || d.bitsPerSample == 64):
				break
			case ft == wave_FORMAT_ALAW && d.bitsPerSample == 8:
				break
			case ft == wave_FORMAT_MULAW && d.bitsPerSample == 8:
				break
			// We don't support extensible wav files
			//case wave_FORMAT_EXTENSIBLE:
			//	break
			default:
				return nil, ErrUnsupported
			}

			// Assign format tag for later (See Read() method)
			d.format = c16.FormatTag

			// We now have enough information to build the audio configuration
			d.config = &audio.Config{
				Channels:   int(c16.Channels),
				SampleRate: int(c16.SamplesPerSec),
			}

		case "fact":
			// We need to scan fact chunk first.
			var fact factChunk
			err = d.bRead(&fact, binary.Size(fact))
			if err != nil {
				return nil, err
			}

		case "data":
			// Read the data chunk header now
			d.chunkSize = length
			complete = true
		}
	}

	return d, nil
}

func init() {
	audio.RegisterFormat("wav", "RIFF", newDecoder)
}
<|endoftext|>


<commit_before>package logger

func SetLevel(level LogLevel) {
	DefaultLogger.SetLevel(level)
}

func Level() LogLevel {
	return DefaultLogger.Level()
}

func Debugln(val ...interface{}) {
	DefaultLogger.Debugln(val)
}

func Debugf(format string, val ...interface{}) {
	DefaultLogger.Debugf(format, val)
}

func Verboseln(val ...interface{}) {
	DefaultLogger.Verboseln(val)
}

func Verbosef(format string, val ...interface{}) {
	DefaultLogger.Verbosef(val)
}

func Infoln(val ...interface{}) {
	DefaultLogger.Infoln(val)
}

func Infof(format string, val ...interface{}) {
	DefaultLogger.Infof(val)
}

func Okln(val ...interface{}) {
	DefaultLogger.Okln(val)
}

func Okf(format string, val ...interface{}) {
	DefaultLogger.Okf(val)
}

func Warnln(val ...interface{}) {
	DefaultLogger.Warnln(val)
}

func Warnf(format string, val ...interface{}) {
	DefaultLogger.Warnf(val)
}

func Fatalln(val ...interface{}) {
	DefaultLogger.Fatalln(val)
}

func Fatalf(format string, val ...interface{}) {
	DefaultLogger.Fatalf(val)
}
<commit_msg>fixed default logging<commit_after>package logger

func SetLevel(level LogLevel) {
	DefaultLogger.SetLevel(level)
}

func Level() LogLevel {
	return DefaultLogger.Level()
}

func Debugln(val ...interface{}) {
	DefaultLogger.Debugln(val)
}

func Debugf(format string, val ...interface{}) {
	DefaultLogger.Debugf(format, val)
}

func Verboseln(val ...interface{}) {
	DefaultLogger.Verboseln(val)
}

func Verbosef(format string, val ...interface{}) {
	DefaultLogger.Verbosef(format, val)
}

func Infoln(val ...interface{}) {
	DefaultLogger.Infoln(val)
}

func Infof(format string, val ...interface{}) {
	DefaultLogger.Infof(format, val)
}

func Okln(val ...interface{}) {
	DefaultLogger.Okln(val)
}

func Okf(format string, val ...interface{}) {
	DefaultLogger.Okf(format, val)
}

func Warnln(val ...interface{}) {
	DefaultLogger.Warnln(val)
}

func Warnf(format string, val ...interface{}) {
	DefaultLogger.Warnf(format, val)
}

func Fatalln(val ...interface{}) {
	DefaultLogger.Fatalln(val)
}

func Fatalf(format string, val ...interface{}) {
	DefaultLogger.Fatalf(format, val)
}
<|endoftext|>


<commit_before>package ev3

import (
	"io/ioutil"
	"log"
	"math"
	"os"
	fp "path/filepath"
	"strings"
)

type Ev3Devices struct {
	In1  string
	In2  string
	In3  string
	In4  string
	OutA string
	OutB string
	OutC string
	OutD string
	LedL string
	LedR string
}

const DriverIr = "lego-ev3-ir"
const DriverColor = "lego-ev3-color"
const DriverTachoMotorLarge = "lego-ev3-l-motor"
const DriverTachoMotorMedium = "lego-ev3-m-motor"
const DriverDcMotor = "dc-motor"

const IrModeProx = "IR-PROX"
const IrModeRemote = "IR-REMOTE"

const ColorModeReflect = "COL-REFLECT"
const ColorModeColor = "COL-COLOR"
const ColorModeAmbient = "COL-AMBIENT"
const ColorModeRaw = "COL-RAW"

const In1 = "in1"
const In2 = "in2"
const In3 = "in3"
const In4 = "in4"
const OutA = "outA"
const OutB = "outB"
const OutC = "outC"
const OutD = "outD"

const Address = "address"
const Value0 = "value0"
const Value1 = "value1"
const Value2 = "value2"
const Value3 = "value3"
const BinData = "bin_data"
const Mode = "mode"
const Modes = "modes"
const Command = "command"
const Commands = "commands"
const DriverName = "driver_name"

const CountPerRot = "count_per_rot"
const DutyCycle = "duty_cycle"
const DutyCycleSp = "duty_cycle_sp"
const MaxSpeed = "max_speed"
const Polarity = "polarity"
const Position = "position"
const PositionSp = "position_sp"
const Speed = "speed"
const SpeedSp = "speed_sp"
const State = "state"
const StopAction = "stop_action"
const StopActions = "stop_actions"
const TimeSp = "time_sp"
const Uevent = "uevent"

const CmdRunForever = "run-forever"
const CmdRunToAbsPos = "run-to-abs-pos"
const CmdRunToRelPos = "run-to-rel-pos"
const CmdRunTimed = "run-timed"
const CmdRunDirect = "run-direct"
const CmdStop = "stop"
const CmdReset = "reset"

func readString(fileName string) string {
	buf, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Fatalln("Cannot read from file", fileName, ":", err)
	}
	text := string(buf)
	text = strings.TrimSuffix(text, "\n")
	return text
}

func writeString(fileName string, v string) {
	err := ioutil.WriteFile(fileName, []byte(v), 0644)
	if err != nil {
		log.Fatalln("Cannot write to file", fileName, ":", err)
	}
}

func contains(stringSlice []string, search string) bool {
	for _, value := range stringSlice {
		if value == search {
			return true
		}
	}
	return false
}

func ReadStringAttribute(dev string, attr string) string {
	return readString(fp.Join(dev, attr))
}
func WriteStringAttribute(dev string, attr string, v string) {
	writeString(fp.Join(dev, attr), v)
}

func SetMode(dev string, mode string) {
	modesText := ReadStringAttribute(dev, Modes)
	modes := strings.Split(modesText, " ")
	if !contains(modes, mode) {
		log.Fatalln("Device", dev, "does not support mode", mode)
	}
	WriteStringAttribute(dev, Mode, mode)
}

func SetStopAction(dev string, action string) {
	actionsText := ReadStringAttribute(dev, StopActions)
	actions := strings.Split(actionsText, " ")
	if !contains(actions, action) {
		log.Fatalln("Device", dev, "does not support stop action", action)
	}
	WriteStringAttribute(dev, StopAction, action)
}

func CheckCommand(dev string, cmd string) {
	commandsText := ReadStringAttribute(dev, Commands)
	commands := strings.Split(commandsText, " ")
	if !contains(commands, cmd) {
		log.Fatalln("Device", dev, "does not support command", cmd)
	}
}

func RunCommand(dev string, cmd string) {
	WriteStringAttribute(dev, Command, cmd)
}

func CheckDriver(dev string, driver string) {
	actualDriver := ReadStringAttribute(dev, DriverName)
	if actualDriver != driver {
		log.Fatalln("Device", dev, "has driver", actualDriver, "instead of", driver)
	}
}

const attributeBufSize int = 64

type Attribute struct {
	path         string
	file         *os.File
	currentValue int
	Value        int
	writable     bool
	text         bool
	buf          [attributeBufSize]byte
}

func (a *Attribute) Path() string {
	return a.path
}
func (a *Attribute) Writable() bool {
	return a.writable
}
func (a *Attribute) Close() {
	err := a.file.Close()
	if err != nil {
		log.Fatalln("Cannot close dev", a.path, ":", err)
	}
	a.file = nil
}

func (a *Attribute) Sync() {
	if a.file == nil {
		log.Fatalln("Cannot write to closed attribute", a.path)
	}
	if a.writable {
		if a.Value != a.currentValue {
			var toWrite []byte
			if a.text {
				v := a.Value
				abs := v
				if abs < 0 {
					abs = -abs
				}
				digits := 1
				ceiling := 10
				for abs >= ceiling {
					digits += 1
					ceiling *= 10
				}
				length := digits
				if v < 0 {
					length += 1
				}
				toWrite = a.buf[0:length]
				index := 0
				if v < 0 {
					toWrite[0] = '-'
					index += 1
				}
				for digits > 0 {
					ceiling /= 10
					digitValue := abs / ceiling
					toWrite[index] = '0' + byte(digitValue)
					index += 1
					abs = abs % ceiling
					digits -= 1
				}
			} else {
				a.buf[0] = byte(a.Value)
				toWrite = a.buf[0:1]
			}
			n, err := a.file.WriteAt(toWrite, 0)
			if err != nil {
				log.Fatalln("Cannot write to attribute file", a.path, ":", err)
			}
			if n != len(toWrite) {
				log.Fatalln("Cannot write bytes to attribute file", a.path, ":", err)
			}
			a.currentValue = a.Value
		}
	} else {
		if a.text {
			_, err := a.file.Seek(0, 0)
			if err != nil {
				log.Fatalln("Cannot rewind text attribute file", a.path, ":", err)
			}
			toRead, err := ioutil.ReadAll(a.file)
			if err != nil {
				log.Fatalln("Cannot read from text attribute file", a.path, ":", err)
			}
			if len(toRead) == 0 {
				log.Fatalln("Cannot read one byte from text attribute file", a.path, ":", err)
			}
			if toRead[len(toRead)-1] == '\n' {
				toRead = toRead[0 : len(toRead)-1]
			}
			isNegative := false
			if toRead[0] == '-' {
				toRead = toRead[1:]
				isNegative = true
			}
			v := 0
			digitValue := 1
			index := len(toRead) - 1
			for index >= 0 {
				digit := int(toRead[index] - '0')
				v += digitValue * digit
				index -= 1
				digitValue *= 10
			}
			if isNegative {
				v = -v
			}
			a.Value = v
		} else {
			n, err := a.file.ReadAt(a.buf[0:1], 0)
			if err != nil {
				log.Fatalln("Cannot read from attribute file", a.path, ":", err)
			}
			if n != 1 {
				log.Fatalln("Cannot read one byte from attribute file", a.path, ":", err)
			}
			a.Value = int(a.buf[0])
		}
	}
}

func OpenAttribute(dev string, attr string, writable bool, text bool) *Attribute {
	path := fp.Join(dev, attr)
	flag := os.O_RDONLY
	if writable {
		flag = os.O_RDWR
	}
	f, err := os.OpenFile(path, flag, 0666)
	if err != nil {
		log.Fatalln("Cannot open device", dev, ":", err)
	}

	log.Println("Open", path, "writable", writable, "text", text)

	return &Attribute{
		path:         path,
		file:         f,
		currentValue: math.MaxInt32,
		Value:        0,
		writable:     writable,
		text:         text,
		buf:          [attributeBufSize]byte{},
	}
}

func OpenByteR(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, false, false)
}
func OpenByteW(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, true, false)
}
func OpenTextR(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, false, true)
}
func OpenTextW(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, true, true)
}

func Scan() *Ev3Devices {
	devs := Ev3Devices{}
	classes := "/sys/class"

	sensors, _ := fp.Glob(fp.Join(classes, "/*/sensor*"))
	for _, s := range sensors {
		port := ReadStringAttribute(s, Address)
		switch port {
		case In1:
			devs.In1 = s
		case In2:
			devs.In2 = s
		case In3:
			devs.In3 = s
		case In4:
			devs.In4 = s
		default:
			log.Fatalln("Unknown port", port, "for sensor", s)
		}
	}

	tachoMotors, _ := fp.Glob(fp.Join(classes, "/tacho-motor/*"))
	for _, m := range tachoMotors {
		port := ReadStringAttribute(m, Address)
		switch port {
		case OutA:
			devs.OutA = m
		case OutB:
			devs.OutB = m
		case OutC:
			devs.OutC = m
		case OutD:
			devs.OutD = m
		default:
			log.Fatalln("Unknown port", port, "for tacho motor", m)
		}
	}

	dcMotors, _ := fp.Glob(fp.Join(classes, "/dc-motor/*"))
	for _, m := range dcMotors {
		port := ReadStringAttribute(m, Address)
		switch port {
		case OutA:
			devs.OutA = m
		case OutB:
			devs.OutB = m
		case OutC:
			devs.OutC = m
		case OutD:
			devs.OutD = m
		default:
			log.Fatalln("Unknown port", port, "for dc motor", m)
		}
	}

	return &devs
}
<commit_msg>Handle ev3 port and led devices.<commit_after>package ev3

import (
	"io/ioutil"
	"log"
	"math"
	"os"
	fp "path/filepath"
	"strings"
)

type Ev3Devices struct {
	Port0         string
	Port1         string
	Port2         string
	Port3         string
	Port4         string
	Port5         string
	Port6         string
	Port7         string
	In1           string
	In2           string
	In3           string
	In4           string
	OutA          string
	OutB          string
	OutC          string
	OutD          string
	LedRightGreen string
	LedRightRed   string
	LedLeftGreen  string
	LedLeftRed    string
}

const DriverIr = "lego-ev3-ir"
const DriverColor = "lego-ev3-color"
const DriverTachoMotorLarge = "lego-ev3-l-motor"
const DriverTachoMotorMedium = "lego-ev3-m-motor"
const DriverDcMotor = "dc-motor"

const IrModeProx = "IR-PROX"
const IrModeRemote = "IR-REMOTE"

const ColorModeReflect = "COL-REFLECT"
const ColorModeColor = "COL-COLOR"
const ColorModeAmbient = "COL-AMBIENT"
const ColorModeRaw = "COL-RAW"

const In1 = "in1"
const In2 = "in2"
const In3 = "in3"
const In4 = "in4"
const OutA = "outA"
const OutB = "outB"
const OutC = "outC"
const OutD = "outD"

const Address = "address"
const Value0 = "value0"
const Value1 = "value1"
const Value2 = "value2"
const Value3 = "value3"
const BinData = "bin_data"
const Mode = "mode"
const Modes = "modes"
const Command = "command"
const Commands = "commands"
const DriverName = "driver_name"

const CountPerRot = "count_per_rot"
const DutyCycle = "duty_cycle"
const DutyCycleSp = "duty_cycle_sp"
const MaxSpeed = "max_speed"
const Polarity = "polarity"
const Position = "position"
const PositionSp = "position_sp"
const Speed = "speed"
const SpeedSp = "speed_sp"
const State = "state"
const StopAction = "stop_action"
const StopActions = "stop_actions"
const TimeSp = "time_sp"
const Uevent = "uevent"

const CmdRunForever = "run-forever"
const CmdRunToAbsPos = "run-to-abs-pos"
const CmdRunToRelPos = "run-to-rel-pos"
const CmdRunTimed = "run-timed"
const CmdRunDirect = "run-direct"
const CmdStop = "stop"
const CmdReset = "reset"

func readString(fileName string) string {
	buf, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Fatalln("Cannot read from file", fileName, ":", err)
	}
	text := string(buf)
	text = strings.TrimSuffix(text, "\n")
	return text
}

func writeString(fileName string, v string) {
	err := ioutil.WriteFile(fileName, []byte(v), 0644)
	if err != nil {
		log.Fatalln("Cannot write to file", fileName, ":", err)
	}
}

func contains(stringSlice []string, search string) bool {
	for _, value := range stringSlice {
		if value == search {
			return true
		}
	}
	return false
}

func ReadStringAttribute(dev string, attr string) string {
	return readString(fp.Join(dev, attr))
}
func WriteStringAttribute(dev string, attr string, v string) {
	writeString(fp.Join(dev, attr), v)
}

func SetMode(dev string, mode string) {
	modesText := ReadStringAttribute(dev, Modes)
	modes := strings.Split(modesText, " ")
	if !contains(modes, mode) {
		log.Fatalln("Device", dev, "does not support mode", mode)
	}
	WriteStringAttribute(dev, Mode, mode)
}

func SetStopAction(dev string, action string) {
	actionsText := ReadStringAttribute(dev, StopActions)
	actions := strings.Split(actionsText, " ")
	if !contains(actions, action) {
		log.Fatalln("Device", dev, "does not support stop action", action)
	}
	WriteStringAttribute(dev, StopAction, action)
}

func CheckCommand(dev string, cmd string) {
	commandsText := ReadStringAttribute(dev, Commands)
	commands := strings.Split(commandsText, " ")
	if !contains(commands, cmd) {
		log.Fatalln("Device", dev, "does not support command", cmd)
	}
}

func RunCommand(dev string, cmd string) {
	WriteStringAttribute(dev, Command, cmd)
}

func CheckDriver(dev string, driver string) {
	actualDriver := ReadStringAttribute(dev, DriverName)
	if actualDriver != driver {
		log.Fatalln("Device", dev, "has driver", actualDriver, "instead of", driver)
	}
}

const attributeBufSize int = 64

type Attribute struct {
	path         string
	file         *os.File
	currentValue int
	Value        int
	writable     bool
	text         bool
	buf          [attributeBufSize]byte
}

func (a *Attribute) Path() string {
	return a.path
}
func (a *Attribute) Writable() bool {
	return a.writable
}
func (a *Attribute) Close() {
	err := a.file.Close()
	if err != nil {
		log.Fatalln("Cannot close dev", a.path, ":", err)
	}
	a.file = nil
}

func (a *Attribute) Sync() {
	if a.file == nil {
		log.Fatalln("Cannot write to closed attribute", a.path)
	}
	if a.writable {
		if a.Value != a.currentValue {
			var toWrite []byte
			if a.text {
				v := a.Value
				abs := v
				if abs < 0 {
					abs = -abs
				}
				digits := 1
				ceiling := 10
				for abs >= ceiling {
					digits += 1
					ceiling *= 10
				}
				length := digits
				if v < 0 {
					length += 1
				}
				toWrite = a.buf[0:length]
				index := 0
				if v < 0 {
					toWrite[0] = '-'
					index += 1
				}
				for digits > 0 {
					ceiling /= 10
					digitValue := abs / ceiling
					toWrite[index] = '0' + byte(digitValue)
					index += 1
					abs = abs % ceiling
					digits -= 1
				}
			} else {
				a.buf[0] = byte(a.Value)
				toWrite = a.buf[0:1]
			}
			n, err := a.file.WriteAt(toWrite, 0)
			if err != nil {
				log.Fatalln("Cannot write to attribute file", a.path, ":", err)
			}
			if n != len(toWrite) {
				log.Fatalln("Cannot write bytes to attribute file", a.path, ":", err)
			}
			a.currentValue = a.Value
		}
	} else {
		if a.text {
			_, err := a.file.Seek(0, 0)
			if err != nil {
				log.Fatalln("Cannot rewind text attribute file", a.path, ":", err)
			}
			toRead, err := ioutil.ReadAll(a.file)
			if err != nil {
				log.Fatalln("Cannot read from text attribute file", a.path, ":", err)
			}
			if len(toRead) == 0 {
				log.Fatalln("Cannot read one byte from text attribute file", a.path, ":", err)
			}
			if toRead[len(toRead)-1] == '\n' {
				toRead = toRead[0 : len(toRead)-1]
			}
			isNegative := false
			if toRead[0] == '-' {
				toRead = toRead[1:]
				isNegative = true
			}
			v := 0
			digitValue := 1
			index := len(toRead) - 1
			for index >= 0 {
				digit := int(toRead[index] - '0')
				v += digitValue * digit
				index -= 1
				digitValue *= 10
			}
			if isNegative {
				v = -v
			}
			a.Value = v
		} else {
			n, err := a.file.ReadAt(a.buf[0:1], 0)
			if err != nil {
				log.Fatalln("Cannot read from attribute file", a.path, ":", err)
			}
			if n != 1 {
				log.Fatalln("Cannot read one byte from attribute file", a.path, ":", err)
			}
			a.Value = int(a.buf[0])
		}
	}
}

func OpenAttribute(dev string, attr string, writable bool, text bool) *Attribute {
	path := fp.Join(dev, attr)
	flag := os.O_RDONLY
	if writable {
		flag = os.O_RDWR
	}
	f, err := os.OpenFile(path, flag, 0666)
	if err != nil {
		log.Fatalln("Cannot open device", dev, ":", err)
	}

	log.Println("Open", path, "writable", writable, "text", text)

	return &Attribute{
		path:         path,
		file:         f,
		currentValue: math.MaxInt32,
		Value:        0,
		writable:     writable,
		text:         text,
		buf:          [attributeBufSize]byte{},
	}
}

func OpenByteR(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, false, false)
}
func OpenByteW(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, true, false)
}
func OpenTextR(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, false, true)
}
func OpenTextW(dev string, attr string) *Attribute {
	return OpenAttribute(dev, attr, true, true)
}

func Scan() *Ev3Devices {
	devs := Ev3Devices{}
	classes := "/sys/class"

	ports := fp.Join(classes, "ports")
	devs.Port0 = fp.Join(ports, "port0")
	devs.Port1 = fp.Join(ports, "port1")
	devs.Port2 = fp.Join(ports, "port2")
	devs.Port3 = fp.Join(ports, "port3")
	devs.Port4 = fp.Join(ports, "port4")
	devs.Port5 = fp.Join(ports, "port5")
	devs.Port6 = fp.Join(ports, "port6")
	devs.Port7 = fp.Join(ports, "port7")

	leds := fp.Join(classes, "leds")
	devs.LedRightGreen = fp.Join(leds, "ev3:right:green:ev3dev")
	devs.LedRightRed = fp.Join(leds, "ev3:right:red:ev3dev")
	devs.LedLeftGreen = fp.Join(leds, "ev3:left:green:ev3dev")
	devs.LedLeftRed = fp.Join(leds, "ev3:left:red:ev3dev")

	sensors, _ := fp.Glob(fp.Join(classes, "/*/sensor*"))
	for _, s := range sensors {
		port := ReadStringAttribute(s, Address)
		switch port {
		case In1:
			devs.In1 = s
		case In2:
			devs.In2 = s
		case In3:
			devs.In3 = s
		case In4:
			devs.In4 = s
		default:
			log.Fatalln("Unknown port", port, "for sensor", s)
		}
	}

	tachoMotors, _ := fp.Glob(fp.Join(classes, "/tacho-motor/*"))
	for _, m := range tachoMotors {
		port := ReadStringAttribute(m, Address)
		switch port {
		case OutA:
			devs.OutA = m
		case OutB:
			devs.OutB = m
		case OutC:
			devs.OutC = m
		case OutD:
			devs.OutD = m
		default:
			log.Fatalln("Unknown port", port, "for tacho motor", m)
		}
	}

	dcMotors, _ := fp.Glob(fp.Join(classes, "/dc-motor/*"))
	for _, m := range dcMotors {
		port := ReadStringAttribute(m, Address)
		switch port {
		case OutA:
			devs.OutA = m
		case OutB:
			devs.OutB = m
		case OutC:
			devs.OutC = m
		case OutD:
			devs.OutD = m
		default:
			log.Fatalln("Unknown port", port, "for dc motor", m)
		}
	}

	return &devs
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	. "github.com/SimonRichardson/butler/butler"
	g "github.com/SimonRichardson/butler/generic"
	"github.com/SimonRichardson/butler/io"
	"github.com/SimonRichardson/butler/markdown"
)

type User struct {
	FirstName string `json:"first-name"`
	LastName  string `json:"last-name"`
}

func main() {

	hint := User{}

	request := Butler().
		Post().
		Path("/name/:id").
		ContentType("application/json").
		AcceptLanguage("en").
		QueryInt("limit")

	response := Butler().
		ContentType("application/json").
		Content(io.JsonEncoder{}, g.Constant(hint))

	listEmployees := Service(request, response).Then(func(args map[string]g.Any) g.Any {
		loadAllEmployees := func(x int) g.Any {
			return []g.Any{}
		}
		return loadAllEmployees(args["limit"].(int))
	})

	server := Compile(listEmployees)

	// You can also render the server to markdown, for up to
	// date documentation
	markdown.Output(server).Fold(
		func(err g.Any) g.Any {
			fmt.Println(err)
			return err
		},
		func(doc g.Any) g.Any {
			fmt.Println(doc)
			return doc
		},
	)

	/*
		// Run the documentation
		service := Remotely(server)("localhost", 80)
		service.Run()
	*/
}
<commit_msg>Adding the example<commit_after>package main

import (
	"fmt"
	. "github.com/SimonRichardson/butler/butler"
	g "github.com/SimonRichardson/butler/generic"
	"github.com/SimonRichardson/butler/io"
	"github.com/SimonRichardson/butler/markdown"
)

type User struct {
	FirstName string `json:"first-name"`
	LastName  string `json:"last-name"`
	Age       int    `json:"age"`
}

func main() {

	hint := User{}

	request := Butler().
		Post().
		Path("/name/:id").
		ContentType("application/json").
		AcceptLanguage("en").
		QueryInt("limit")

	response := Butler().
		ContentType("application/json").
		Content(io.JsonEncoder{}, g.Constant(hint))

	listEmployees := Service(request, response).Then(func(args map[string]g.Any) g.Any {
		loadAllEmployees := func(x int) g.Any {
			return []g.Any{}
		}
		return loadAllEmployees(args["limit"].(int))
	})

	server := Compile(listEmployees)

	// You can also render the server to markdown, for up to
	// date documentation
	markdown.Output(server).Fold(
		func(err g.Any) g.Any {
			fmt.Println(err)
			return err
		},
		func(doc g.Any) g.Any {
			fmt.Println(doc)
			return doc
		},
	)

	/*
		// Run the documentation
		service := Remotely(server)("localhost", 80)
		service.Run()
	*/
}
<|endoftext|>