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

package runtime_test

import (
	. "runtime"
	"strings"
	"sync"
	"testing"
	"time"
)

// TestStackMem measures per-thread stack segment cache behavior.
// The test consumed up to 500MB in the past.
func TestStackMem(t *testing.T) {
	const (
		BatchSize      = 32
		BatchCount     = 256
		ArraySize      = 1024
		RecursionDepth = 128
	)
	if testing.Short() {
		return
	}
	defer GOMAXPROCS(GOMAXPROCS(BatchSize))
	s0 := new(MemStats)
	ReadMemStats(s0)
	for b := 0; b < BatchCount; b++ {
		c := make(chan bool, BatchSize)
		for i := 0; i < BatchSize; i++ {
			go func() {
				var f func(k int, a [ArraySize]byte)
				f = func(k int, a [ArraySize]byte) {
					if k == 0 {
						time.Sleep(time.Millisecond)
						return
					}
					f(k-1, a)
				}
				f(RecursionDepth, [ArraySize]byte{})
				c <- true
			}()
		}
		for i := 0; i < BatchSize; i++ {
			<-c
		}

		// The goroutines have signaled via c that they are ready to exit.
		// Give them a chance to exit by sleeping. If we don't wait, we
		// might not reuse them on the next batch.
		time.Sleep(10 * time.Millisecond)
	}
	s1 := new(MemStats)
	ReadMemStats(s1)
	consumed := int64(s1.StackSys - s0.StackSys)
	t.Logf("Consumed %vMB for stack mem", consumed>>20)
	estimate := int64(8 * BatchSize * ArraySize * RecursionDepth) // 8 is to reduce flakiness.
	if consumed > estimate {
		t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
	}
	// Due to broken stack memory accounting (https://golang.org/issue/7468),
	// StackInuse can decrease during function execution, so we cast the values to int64.
	inuse := int64(s1.StackInuse) - int64(s0.StackInuse)
	t.Logf("Inuse %vMB for stack mem", inuse>>20)
	if inuse > 4<<20 {
		t.Fatalf("Stack inuse: want %v, got %v", 4<<20, inuse)
	}
}

// Test stack growing in different contexts.
func TestStackGrowth(t *testing.T) {
	t.Parallel()
	var wg sync.WaitGroup

	// in a normal goroutine
	wg.Add(1)
	go func() {
		defer wg.Done()
		growStack()
	}()
	wg.Wait()

	// in locked goroutine
	wg.Add(1)
	go func() {
		defer wg.Done()
		LockOSThread()
		growStack()
		UnlockOSThread()
	}()
	wg.Wait()

	// in finalizer
	wg.Add(1)
	go func() {
		defer wg.Done()
		done := make(chan bool)
		go func() {
			s := new(string)
			SetFinalizer(s, func(ss *string) {
				growStack()
				done <- true
			})
			s = nil
			done <- true
		}()
		<-done
		GC()
		select {
		case <-done:
		case <-time.After(20 * time.Second):
			t.Fatal("finalizer did not run")
		}
	}()
	wg.Wait()
}

// ... and in init
//func init() {
//	growStack()
//}

func growStack() {
	n := 1 << 10
	if testing.Short() {
		n = 1 << 8
	}
	for i := 0; i < n; i++ {
		x := 0
		growStackIter(&x, i)
		if x != i+1 {
			panic("stack is corrupted")
		}
	}
	GC()
}

// This function is not an anonymous func, so that the compiler can do escape
// analysis and place x on stack (and subsequently stack growth update the pointer).
func growStackIter(p *int, n int) {
	if n == 0 {
		*p = n + 1
		GC()
		return
	}
	*p = n + 1
	x := 0
	growStackIter(&x, n-1)
	if x != n {
		panic("stack is corrupted")
	}
}

func TestStackGrowthCallback(t *testing.T) {
	t.Parallel()
	var wg sync.WaitGroup

	// test stack growth at chan op
	wg.Add(1)
	go func() {
		defer wg.Done()
		c := make(chan int, 1)
		growStackWithCallback(func() {
			c <- 1
			<-c
		})
	}()

	// test stack growth at map op
	wg.Add(1)
	go func() {
		defer wg.Done()
		m := make(map[int]int)
		growStackWithCallback(func() {
			_, _ = m[1]
			m[1] = 1
		})
	}()

	// test stack growth at goroutine creation
	wg.Add(1)
	go func() {
		defer wg.Done()
		growStackWithCallback(func() {
			done := make(chan bool)
			go func() {
				done <- true
			}()
			<-done
		})
	}()

	wg.Wait()
}

func growStackWithCallback(cb func()) {
	var f func(n int)
	f = func(n int) {
		if n == 0 {
			cb()
			return
		}
		f(n - 1)
	}
	for i := 0; i < 1<<10; i++ {
		f(i)
	}
}

// TestDeferPtrs tests the adjustment of Defer's argument pointers (p aka &y)
// during a stack copy.
func set(p *int, x int) {
	*p = x
}
func TestDeferPtrs(t *testing.T) {
	var y int

	defer func() {
		if y != 42 {
			t.Errorf("defer's stack references were not adjusted appropriately")
		}
	}()
	defer set(&y, 42)
	growStack()
}

type bigBuf [4 * 1024]byte

// TestDeferPtrsGoexit is like TestDeferPtrs but exercises the possibility that the
// stack grows as part of starting the deferred function. It calls Goexit at various
// stack depths, forcing the deferred function (with >4kB of args) to be run at
// the bottom of the stack. The goal is to find a stack depth less than 4kB from
// the end of the stack. Each trial runs in a different goroutine so that an earlier
// stack growth does not invalidate a later attempt.
func TestDeferPtrsGoexit(t *testing.T) {
	for i := 0; i < 100; i++ {
		c := make(chan int, 1)
		go testDeferPtrsGoexit(c, i)
		if n := <-c; n != 42 {
			t.Fatalf("defer's stack references were not adjusted appropriately (i=%d n=%d)", i, n)
		}
	}
}

func testDeferPtrsGoexit(c chan int, i int) {
	var y int
	defer func() {
		c <- y
	}()
	defer setBig(&y, 42, bigBuf{})
	useStackAndCall(i, Goexit)
}

func setBig(p *int, x int, b bigBuf) {
	*p = x
}

// TestDeferPtrsPanic is like TestDeferPtrsGoexit, but it's using panic instead
// of Goexit to run the Defers. Those two are different execution paths
// in the runtime.
func TestDeferPtrsPanic(t *testing.T) {
	for i := 0; i < 100; i++ {
		c := make(chan int, 1)
		go testDeferPtrsGoexit(c, i)
		if n := <-c; n != 42 {
			t.Fatalf("defer's stack references were not adjusted appropriately (i=%d n=%d)", i, n)
		}
	}
}

func testDeferPtrsPanic(c chan int, i int) {
	var y int
	defer func() {
		if recover() == nil {
			c <- -1
			return
		}
		c <- y
	}()
	defer setBig(&y, 42, bigBuf{})
	useStackAndCall(i, func() { panic(1) })
}

// TestPanicUseStack checks that a chain of Panic structs on the stack are
// updated correctly if the stack grows during the deferred execution that
// happens as a result of the panic.
func TestPanicUseStack(t *testing.T) {
	pc := make([]uintptr, 10000)
	defer func() {
		recover()
		Callers(0, pc) // force stack walk
		useStackAndCall(100, func() {
			defer func() {
				recover()
				Callers(0, pc) // force stack walk
				useStackAndCall(200, func() {
					defer func() {
						recover()
						Callers(0, pc) // force stack walk
					}()
					panic(3)
				})
			}()
			panic(2)
		})
	}()
	panic(1)
}

func TestPanicFar(t *testing.T) {
	var xtree *xtreeNode
	pc := make([]uintptr, 10000)
	defer func() {
		// At this point we created a large stack and unwound
		// it via recovery. Force a stack walk, which will
		// check the consistency of stack barriers.
		Callers(0, pc)
	}()
	defer func() {
		recover()
	}()
	useStackAndCall(100, func() {
		// Kick off the GC and make it do something nontrivial
		// to keep stack barriers installed for a while.
		xtree = makeTree(18)
		// Give the GC time to install stack barriers.
		time.Sleep(time.Millisecond)
		panic(1)
	})
	_ = xtree
}

type xtreeNode struct {
	l, r *xtreeNode
}

func makeTree(d int) *xtreeNode {
	if d == 0 {
		return new(xtreeNode)
	}
	return &xtreeNode{makeTree(d - 1), makeTree(d - 1)}
}

// use about n KB of stack and call f
func useStackAndCall(n int, f func()) {
	if n == 0 {
		f()
		return
	}
	var b [1024]byte // makes frame about 1KB
	useStackAndCall(n-1+int(b[99]), f)
}

func useStack(n int) {
	useStackAndCall(n, func() {})
}

func growing(c chan int, done chan struct{}) {
	for n := range c {
		useStack(n)
		done <- struct{}{}
	}
	done <- struct{}{}
}

func TestStackCache(t *testing.T) {
	// Allocate a bunch of goroutines and grow their stacks.
	// Repeat a few times to test the stack cache.
	const (
		R = 4
		G = 200
		S = 5
	)
	for i := 0; i < R; i++ {
		var reqchans [G]chan int
		done := make(chan struct{})
		for j := 0; j < G; j++ {
			reqchans[j] = make(chan int)
			go growing(reqchans[j], done)
		}
		for s := 0; s < S; s++ {
			for j := 0; j < G; j++ {
				reqchans[j] <- 1 << uint(s)
			}
			for j := 0; j < G; j++ {
				<-done
			}
		}
		for j := 0; j < G; j++ {
			close(reqchans[j])
		}
		for j := 0; j < G; j++ {
			<-done
		}
	}
}

func TestStackOutput(t *testing.T) {
	b := make([]byte, 1024)
	stk := string(b[:Stack(b, false)])
	if !strings.HasPrefix(stk, "goroutine ") {
		t.Errorf("Stack (len %d):\n%s", len(stk), stk)
		t.Errorf("Stack output should begin with \"goroutine \"")
	}
}

func TestStackAllOutput(t *testing.T) {
	b := make([]byte, 1024)
	stk := string(b[:Stack(b, true)])
	if !strings.HasPrefix(stk, "goroutine ") {
		t.Errorf("Stack (len %d):\n%s", len(stk), stk)
		t.Errorf("Stack output should begin with \"goroutine \"")
	}
}

func TestStackPanic(t *testing.T) {
	// Test that stack copying copies panics correctly.  This is difficult
	// to test because it is very unlikely that the stack will be copied
	// in the middle of gopanic.  But it can happen.
	// To make this test effective, edit panic.go:gopanic and uncomment
	// the GC() call just before freedefer(d).
	defer func() {
		if x := recover(); x == nil {
			t.Errorf("recover failed")
		}
	}()
	useStack(32)
	panic("test panic")
}

func BenchmarkStackCopy(b *testing.B) {
	c := make(chan bool)
	for i := 0; i < b.N; i++ {
		go func() {
			count(1000000)
			c <- true
		}()
		<-c
	}
}

func count(n int) int {
	if n == 0 {
		return 0
	}
	return 1 + count(n-1)
}
<commit_msg>runtime: don't call testing.Fatal from worker goroutines<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime_test

import (
	. "runtime"
	"strings"
	"sync"
	"testing"
	"time"
)

// TestStackMem measures per-thread stack segment cache behavior.
// The test consumed up to 500MB in the past.
func TestStackMem(t *testing.T) {
	const (
		BatchSize      = 32
		BatchCount     = 256
		ArraySize      = 1024
		RecursionDepth = 128
	)
	if testing.Short() {
		return
	}
	defer GOMAXPROCS(GOMAXPROCS(BatchSize))
	s0 := new(MemStats)
	ReadMemStats(s0)
	for b := 0; b < BatchCount; b++ {
		c := make(chan bool, BatchSize)
		for i := 0; i < BatchSize; i++ {
			go func() {
				var f func(k int, a [ArraySize]byte)
				f = func(k int, a [ArraySize]byte) {
					if k == 0 {
						time.Sleep(time.Millisecond)
						return
					}
					f(k-1, a)
				}
				f(RecursionDepth, [ArraySize]byte{})
				c <- true
			}()
		}
		for i := 0; i < BatchSize; i++ {
			<-c
		}

		// The goroutines have signaled via c that they are ready to exit.
		// Give them a chance to exit by sleeping. If we don't wait, we
		// might not reuse them on the next batch.
		time.Sleep(10 * time.Millisecond)
	}
	s1 := new(MemStats)
	ReadMemStats(s1)
	consumed := int64(s1.StackSys - s0.StackSys)
	t.Logf("Consumed %vMB for stack mem", consumed>>20)
	estimate := int64(8 * BatchSize * ArraySize * RecursionDepth) // 8 is to reduce flakiness.
	if consumed > estimate {
		t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
	}
	// Due to broken stack memory accounting (https://golang.org/issue/7468),
	// StackInuse can decrease during function execution, so we cast the values to int64.
	inuse := int64(s1.StackInuse) - int64(s0.StackInuse)
	t.Logf("Inuse %vMB for stack mem", inuse>>20)
	if inuse > 4<<20 {
		t.Fatalf("Stack inuse: want %v, got %v", 4<<20, inuse)
	}
}

// Test stack growing in different contexts.
func TestStackGrowth(t *testing.T) {
	t.Parallel()
	var wg sync.WaitGroup

	// in a normal goroutine
	wg.Add(1)
	go func() {
		defer wg.Done()
		growStack()
	}()
	wg.Wait()

	// in locked goroutine
	wg.Add(1)
	go func() {
		defer wg.Done()
		LockOSThread()
		growStack()
		UnlockOSThread()
	}()
	wg.Wait()

	// in finalizer
	wg.Add(1)
	go func() {
		defer wg.Done()
		done := make(chan bool)
		go func() {
			s := new(string)
			SetFinalizer(s, func(ss *string) {
				growStack()
				done <- true
			})
			s = nil
			done <- true
		}()
		<-done
		GC()
		select {
		case <-done:
		case <-time.After(20 * time.Second):
			t.Error("finalizer did not run")
			return
		}
	}()
	wg.Wait()
}

// ... and in init
//func init() {
//	growStack()
//}

func growStack() {
	n := 1 << 10
	if testing.Short() {
		n = 1 << 8
	}
	for i := 0; i < n; i++ {
		x := 0
		growStackIter(&x, i)
		if x != i+1 {
			panic("stack is corrupted")
		}
	}
	GC()
}

// This function is not an anonymous func, so that the compiler can do escape
// analysis and place x on stack (and subsequently stack growth update the pointer).
func growStackIter(p *int, n int) {
	if n == 0 {
		*p = n + 1
		GC()
		return
	}
	*p = n + 1
	x := 0
	growStackIter(&x, n-1)
	if x != n {
		panic("stack is corrupted")
	}
}

func TestStackGrowthCallback(t *testing.T) {
	t.Parallel()
	var wg sync.WaitGroup

	// test stack growth at chan op
	wg.Add(1)
	go func() {
		defer wg.Done()
		c := make(chan int, 1)
		growStackWithCallback(func() {
			c <- 1
			<-c
		})
	}()

	// test stack growth at map op
	wg.Add(1)
	go func() {
		defer wg.Done()
		m := make(map[int]int)
		growStackWithCallback(func() {
			_, _ = m[1]
			m[1] = 1
		})
	}()

	// test stack growth at goroutine creation
	wg.Add(1)
	go func() {
		defer wg.Done()
		growStackWithCallback(func() {
			done := make(chan bool)
			go func() {
				done <- true
			}()
			<-done
		})
	}()
	wg.Wait()
}

func growStackWithCallback(cb func()) {
	var f func(n int)
	f = func(n int) {
		if n == 0 {
			cb()
			return
		}
		f(n - 1)
	}
	for i := 0; i < 1<<10; i++ {
		f(i)
	}
}

// TestDeferPtrs tests the adjustment of Defer's argument pointers (p aka &y)
// during a stack copy.
func set(p *int, x int) {
	*p = x
}
func TestDeferPtrs(t *testing.T) {
	var y int

	defer func() {
		if y != 42 {
			t.Errorf("defer's stack references were not adjusted appropriately")
		}
	}()
	defer set(&y, 42)
	growStack()
}

type bigBuf [4 * 1024]byte

// TestDeferPtrsGoexit is like TestDeferPtrs but exercises the possibility that the
// stack grows as part of starting the deferred function. It calls Goexit at various
// stack depths, forcing the deferred function (with >4kB of args) to be run at
// the bottom of the stack. The goal is to find a stack depth less than 4kB from
// the end of the stack. Each trial runs in a different goroutine so that an earlier
// stack growth does not invalidate a later attempt.
func TestDeferPtrsGoexit(t *testing.T) {
	for i := 0; i < 100; i++ {
		c := make(chan int, 1)
		go testDeferPtrsGoexit(c, i)
		if n := <-c; n != 42 {
			t.Fatalf("defer's stack references were not adjusted appropriately (i=%d n=%d)", i, n)
		}
	}
}

func testDeferPtrsGoexit(c chan int, i int) {
	var y int
	defer func() {
		c <- y
	}()
	defer setBig(&y, 42, bigBuf{})
	useStackAndCall(i, Goexit)
}

func setBig(p *int, x int, b bigBuf) {
	*p = x
}

// TestDeferPtrsPanic is like TestDeferPtrsGoexit, but it's using panic instead
// of Goexit to run the Defers. Those two are different execution paths
// in the runtime.
func TestDeferPtrsPanic(t *testing.T) {
	for i := 0; i < 100; i++ {
		c := make(chan int, 1)
		go testDeferPtrsGoexit(c, i)
		if n := <-c; n != 42 {
			t.Fatalf("defer's stack references were not adjusted appropriately (i=%d n=%d)", i, n)
		}
	}
}

func testDeferPtrsPanic(c chan int, i int) {
	var y int
	defer func() {
		if recover() == nil {
			c <- -1
			return
		}
		c <- y
	}()
	defer setBig(&y, 42, bigBuf{})
	useStackAndCall(i, func() { panic(1) })
}

// TestPanicUseStack checks that a chain of Panic structs on the stack are
// updated correctly if the stack grows during the deferred execution that
// happens as a result of the panic.
func TestPanicUseStack(t *testing.T) {
	pc := make([]uintptr, 10000)
	defer func() {
		recover()
		Callers(0, pc) // force stack walk
		useStackAndCall(100, func() {
			defer func() {
				recover()
				Callers(0, pc) // force stack walk
				useStackAndCall(200, func() {
					defer func() {
						recover()
						Callers(0, pc) // force stack walk
					}()
					panic(3)
				})
			}()
			panic(2)
		})
	}()
	panic(1)
}

func TestPanicFar(t *testing.T) {
	var xtree *xtreeNode
	pc := make([]uintptr, 10000)
	defer func() {
		// At this point we created a large stack and unwound
		// it via recovery. Force a stack walk, which will
		// check the consistency of stack barriers.
		Callers(0, pc)
	}()
	defer func() {
		recover()
	}()
	useStackAndCall(100, func() {
		// Kick off the GC and make it do something nontrivial
		// to keep stack barriers installed for a while.
		xtree = makeTree(18)
		// Give the GC time to install stack barriers.
		time.Sleep(time.Millisecond)
		panic(1)
	})
	_ = xtree
}

type xtreeNode struct {
	l, r *xtreeNode
}

func makeTree(d int) *xtreeNode {
	if d == 0 {
		return new(xtreeNode)
	}
	return &xtreeNode{makeTree(d - 1), makeTree(d - 1)}
}

// use about n KB of stack and call f
func useStackAndCall(n int, f func()) {
	if n == 0 {
		f()
		return
	}
	var b [1024]byte // makes frame about 1KB
	useStackAndCall(n-1+int(b[99]), f)
}

func useStack(n int) {
	useStackAndCall(n, func() {})
}

func growing(c chan int, done chan struct{}) {
	for n := range c {
		useStack(n)
		done <- struct{}{}
	}
	done <- struct{}{}
}

func TestStackCache(t *testing.T) {
	// Allocate a bunch of goroutines and grow their stacks.
	// Repeat a few times to test the stack cache.
	const (
		R = 4
		G = 200
		S = 5
	)
	for i := 0; i < R; i++ {
		var reqchans [G]chan int
		done := make(chan struct{})
		for j := 0; j < G; j++ {
			reqchans[j] = make(chan int)
			go growing(reqchans[j], done)
		}
		for s := 0; s < S; s++ {
			for j := 0; j < G; j++ {
				reqchans[j] <- 1 << uint(s)
			}
			for j := 0; j < G; j++ {
				<-done
			}
		}
		for j := 0; j < G; j++ {
			close(reqchans[j])
		}
		for j := 0; j < G; j++ {
			<-done
		}
	}
}

func TestStackOutput(t *testing.T) {
	b := make([]byte, 1024)
	stk := string(b[:Stack(b, false)])
	if !strings.HasPrefix(stk, "goroutine ") {
		t.Errorf("Stack (len %d):\n%s", len(stk), stk)
		t.Errorf("Stack output should begin with \"goroutine \"")
	}
}

func TestStackAllOutput(t *testing.T) {
	b := make([]byte, 1024)
	stk := string(b[:Stack(b, true)])
	if !strings.HasPrefix(stk, "goroutine ") {
		t.Errorf("Stack (len %d):\n%s", len(stk), stk)
		t.Errorf("Stack output should begin with \"goroutine \"")
	}
}

func TestStackPanic(t *testing.T) {
	// Test that stack copying copies panics correctly.  This is difficult
	// to test because it is very unlikely that the stack will be copied
	// in the middle of gopanic.  But it can happen.
	// To make this test effective, edit panic.go:gopanic and uncomment
	// the GC() call just before freedefer(d).
	defer func() {
		if x := recover(); x == nil {
			t.Errorf("recover failed")
		}
	}()
	useStack(32)
	panic("test panic")
}

func BenchmarkStackCopy(b *testing.B) {
	c := make(chan bool)
	for i := 0; i < b.N; i++ {
		go func() {
			count(1000000)
			c <- true
		}()
		<-c
	}
}

func count(n int) int {
	if n == 0 {
		return 0
	}
	return 1 + count(n-1)
}
<|endoftext|>


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

package android

import (
	"context"
	"fmt"
	"time"

	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/core/os/device/bind"
)

// Device extends the bind.Device interface with capabilities specific to android devices.
type Device interface {
	bind.Device
	// InstallAPK installs the specified APK to the device. If reinstall is true
	// and the package is already installed on the device then it will be replaced.
	InstallAPK(ctx context.Context, path string, reinstall bool, grantPermissions bool) error
	// SELinuxEnforcing returns true if the device is currently in a
	// SELinux enforcing mode, or false if the device is currently in a SELinux
	// permissive mode.
	SELinuxEnforcing(ctx context.Context) (bool, error)
	// SetSELinuxEnforcing changes the SELinux-enforcing mode.
	SetSELinuxEnforcing(ctx context.Context, enforce bool) error
	// StartActivity launches the specified action.
	StartActivity(ctx context.Context, a ActivityAction, extras ...ActionExtra) error
	// StartActivityForDebug launches an activity in debug mode.
	StartActivityForDebug(ctx context.Context, a ActivityAction, extras ...ActionExtra) error
	// StartService launches the specified service.
	StartService(ctx context.Context, a ServiceAction, extras ...ActionExtra) error
	// Pushes the local file to the remote one.
	Push(ctx context.Context, local, remote string) error
	// Pulls the remote file to the local one.
	Pull(ctx context.Context, remote, local string) error
	// KeyEvent simulates a key-event on the device.
	KeyEvent(ctx context.Context, key KeyCode) error
	// SendEvent simulates low-level user-input to the device.
	SendEvent(ctx context.Context, deviceID, eventType, eventCode, value int) error
	// SendTouch simulates touch-screen press or release.
	SendTouch(ctx context.Context, deviceID, x, y int, pressed bool)
	// GetTouchDimensions returns the resolution of the touch sensor.
	// This may be different to the dimensions of the LCD screen.
	GetTouchDimensions(ctx context.Context) (deviceID, minX, maxX, minY, maxY int, ok bool)
	// GetScreenDimensions returns the resolution of the display.
	GetScreenDimensions(ctx context.Context) (orientation, width, height int, ok bool)
	// InstalledPackages returns the sorted list of installed packages on the device.
	InstalledPackages(ctx context.Context) (InstalledPackages, error)
	// IsScreenOn returns true if the device's screen is currently on.
	IsScreenOn(ctx context.Context) (bool, error)
	// TurnScreenOn turns the device's screen on.
	TurnScreenOn(ctx context.Context) error
	// TurnScreenOff turns the device's screen off.
	TurnScreenOff(ctx context.Context) error
	// IsShowingLockscreen returns true if the device's lockscreen is currently showing.
	IsShowingLockscreen(ctx context.Context) (bool, error)
	// Logcat writes all logcat messages reported by the device to the chan msgs,
	// blocking until the context is stopped.
	Logcat(ctx context.Context, msgs chan<- LogcatMessage) error
	// NativeBridgeABI returns the native ABI for the given emulated ABI for the
	// device by consulting the ro.dalvik.vm.isa.<emulated_isa>=<native_isa>
	// system properties.
	NativeBridgeABI(ctx context.Context, abi *device.ABI) *device.ABI
}

// LogcatMessage represents a single logcat message.
type LogcatMessage struct {
	Timestamp time.Time
	Priority  LogcatPriority
	Tag       string
	ProcessID int
	ThreadID  int
	Message   string
}

// Log writes the LogcatMessage to ctx with the corresponding message severity.
func (m LogcatMessage) Log(ctx context.Context) {
	// Override the timestamping function to replicate the logcat timestamp
	ctx = log.PutClock(ctx, log.FixedClock(m.Timestamp))
	ctx = log.PutTag(ctx, m.Tag)
	ctx = log.V{
		"pid": m.ProcessID,
		"tid": m.ThreadID,
	}.Bind(ctx)
	log.From(ctx).Log(m.Priority.Severity(), m.Message)
}

// LogcatPriority represents the priority of a logcat message.
type LogcatPriority int

const (
	// Verbose represents the 'V' logcat message priority.
	Verbose = LogcatPriority(iota)
	// Debug represents the 'D' logcat message priority.
	Debug
	// Info represents the 'I' logcat message priority.
	Info
	// Warning represents the 'W' logcat message priority.
	Warning
	// Error represents the 'E' logcat message priority.
	Error
	// Fatal represents the 'F' logcat message priority.
	Fatal
)

// Severity returns a Severity that closely corresponds to the priority.
func (p LogcatPriority) Severity() log.Severity {
	switch p {
	case Verbose:
		return log.Verbose
	case Debug:
		return log.Debug
	case Info:
		return log.Info
	case Warning:
		return log.Warning
	case Error:
		return log.Error
	case Fatal:
		return log.Fatal
	default:
		panic(fmt.Errorf("Unknown LogcatPriority %v", p))
	}
}
<commit_msg>Clarify NativeBridgeAPI documentation <commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package android

import (
	"context"
	"fmt"
	"time"

	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/core/os/device/bind"
)

// Device extends the bind.Device interface with capabilities specific to android devices.
type Device interface {
	bind.Device
	// InstallAPK installs the specified APK to the device. If reinstall is true
	// and the package is already installed on the device then it will be replaced.
	InstallAPK(ctx context.Context, path string, reinstall bool, grantPermissions bool) error
	// SELinuxEnforcing returns true if the device is currently in a
	// SELinux enforcing mode, or false if the device is currently in a SELinux
	// permissive mode.
	SELinuxEnforcing(ctx context.Context) (bool, error)
	// SetSELinuxEnforcing changes the SELinux-enforcing mode.
	SetSELinuxEnforcing(ctx context.Context, enforce bool) error
	// StartActivity launches the specified action.
	StartActivity(ctx context.Context, a ActivityAction, extras ...ActionExtra) error
	// StartActivityForDebug launches an activity in debug mode.
	StartActivityForDebug(ctx context.Context, a ActivityAction, extras ...ActionExtra) error
	// StartService launches the specified service.
	StartService(ctx context.Context, a ServiceAction, extras ...ActionExtra) error
	// Pushes the local file to the remote one.
	Push(ctx context.Context, local, remote string) error
	// Pulls the remote file to the local one.
	Pull(ctx context.Context, remote, local string) error
	// KeyEvent simulates a key-event on the device.
	KeyEvent(ctx context.Context, key KeyCode) error
	// SendEvent simulates low-level user-input to the device.
	SendEvent(ctx context.Context, deviceID, eventType, eventCode, value int) error
	// SendTouch simulates touch-screen press or release.
	SendTouch(ctx context.Context, deviceID, x, y int, pressed bool)
	// GetTouchDimensions returns the resolution of the touch sensor.
	// This may be different to the dimensions of the LCD screen.
	GetTouchDimensions(ctx context.Context) (deviceID, minX, maxX, minY, maxY int, ok bool)
	// GetScreenDimensions returns the resolution of the display.
	GetScreenDimensions(ctx context.Context) (orientation, width, height int, ok bool)
	// InstalledPackages returns the sorted list of installed packages on the device.
	InstalledPackages(ctx context.Context) (InstalledPackages, error)
	// IsScreenOn returns true if the device's screen is currently on.
	IsScreenOn(ctx context.Context) (bool, error)
	// TurnScreenOn turns the device's screen on.
	TurnScreenOn(ctx context.Context) error
	// TurnScreenOff turns the device's screen off.
	TurnScreenOff(ctx context.Context) error
	// IsShowingLockscreen returns true if the device's lockscreen is currently showing.
	IsShowingLockscreen(ctx context.Context) (bool, error)
	// Logcat writes all logcat messages reported by the device to the chan msgs,
	// blocking until the context is stopped.
	Logcat(ctx context.Context, msgs chan<- LogcatMessage) error
	// NativeBridgeABI returns the native ABI for the given emulated ABI for the
	// device by consulting the ro.dalvik.vm.isa.<emulated_isa>=<native_isa>
	// system properties. If there is no native ABI for the given ABI, then abi
	// is simply returned.
	NativeBridgeABI(ctx context.Context, abi *device.ABI) *device.ABI
}

// LogcatMessage represents a single logcat message.
type LogcatMessage struct {
	Timestamp time.Time
	Priority  LogcatPriority
	Tag       string
	ProcessID int
	ThreadID  int
	Message   string
}

// Log writes the LogcatMessage to ctx with the corresponding message severity.
func (m LogcatMessage) Log(ctx context.Context) {
	// Override the timestamping function to replicate the logcat timestamp
	ctx = log.PutClock(ctx, log.FixedClock(m.Timestamp))
	ctx = log.PutTag(ctx, m.Tag)
	ctx = log.V{
		"pid": m.ProcessID,
		"tid": m.ThreadID,
	}.Bind(ctx)
	log.From(ctx).Log(m.Priority.Severity(), m.Message)
}

// LogcatPriority represents the priority of a logcat message.
type LogcatPriority int

const (
	// Verbose represents the 'V' logcat message priority.
	Verbose = LogcatPriority(iota)
	// Debug represents the 'D' logcat message priority.
	Debug
	// Info represents the 'I' logcat message priority.
	Info
	// Warning represents the 'W' logcat message priority.
	Warning
	// Error represents the 'E' logcat message priority.
	Error
	// Fatal represents the 'F' logcat message priority.
	Fatal
)

// Severity returns a Severity that closely corresponds to the priority.
func (p LogcatPriority) Severity() log.Severity {
	switch p {
	case Verbose:
		return log.Verbose
	case Debug:
		return log.Debug
	case Info:
		return log.Info
	case Warning:
		return log.Warning
	case Error:
		return log.Error
	case Fatal:
		return log.Fatal
	default:
		panic(fmt.Errorf("Unknown LogcatPriority %v", p))
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd 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 grpcproxy

import (
	"github.com/coreos/etcd/clientv3"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/proxy/grpcproxy/cache"

	"golang.org/x/net/context"
)

type kvProxy struct {
	kv    clientv3.KV
	cache cache.Cache
}

func NewKvProxy(c *clientv3.Client) pb.KVServer {
	return &kvProxy{
		kv:    c.KV,
		cache: cache.NewCache(cache.DefaultMaxEntries),
	}
}

func (p *kvProxy) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
	// if request set Serializable, serve it from local cache first
	if r.Serializable {
		resp, err := p.cache.Get(r)
		switch err {
		case nil:
			return resp, nil
		case cache.ErrCompacted:
			return nil, err
		}
	}

	resp, err := p.kv.Do(ctx, RangeRequestToOp(r))
	if err != nil {
		return nil, err
	}

	p.cache.Add(r, (*pb.RangeResponse)(resp.Get()))

	return (*pb.RangeResponse)(resp.Get()), nil
}

func (p *kvProxy) Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error) {
	resp, err := p.kv.Do(ctx, PutRequestToOp(r))
	return (*pb.PutResponse)(resp.Put()), err
}

func (p *kvProxy) DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) {
	resp, err := p.kv.Do(ctx, DelRequestToOp(r))
	return (*pb.DeleteRangeResponse)(resp.Del()), err
}

func (p *kvProxy) Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error) {
	txn := p.kv.Txn(ctx)
	cmps := make([]clientv3.Cmp, len(r.Compare))
	thenops := make([]clientv3.Op, len(r.Success))
	elseops := make([]clientv3.Op, len(r.Failure))

	for i := range r.Compare {
		cmps[i] = (clientv3.Cmp)(*r.Compare[i])
	}

	for i := range r.Success {
		thenops[i] = requestOpToOp(r.Success[i])
	}

	for i := range r.Failure {
		elseops[i] = requestOpToOp(r.Failure[i])
	}

	resp, err := txn.If(cmps...).Then(thenops...).Else(elseops...).Commit()
	return (*pb.TxnResponse)(resp), err
}

func (p *kvProxy) Compact(ctx context.Context, r *pb.CompactionRequest) (*pb.CompactionResponse, error) {
	var opts []clientv3.CompactOption
	if r.Physical {
		opts = append(opts, clientv3.WithCompactPhysical())
	}

	resp, err := p.kv.Compact(ctx, r.Revision, opts...)
	if err == nil {
		p.cache.Compact(r.Revision)
	}

	return (*pb.CompactionResponse)(resp), err
}

func requestOpToOp(union *pb.RequestOp) clientv3.Op {
	switch tv := union.Request.(type) {
	case *pb.RequestOp_RequestRange:
		if tv.RequestRange != nil {
			return RangeRequestToOp(tv.RequestRange)
		}
	case *pb.RequestOp_RequestPut:
		if tv.RequestPut != nil {
			return PutRequestToOp(tv.RequestPut)
		}
	case *pb.RequestOp_RequestDeleteRange:
		if tv.RequestDeleteRange != nil {
			return DelRequestToOp(tv.RequestDeleteRange)
		}
	}
	panic("unknown request")
}

func RangeRequestToOp(r *pb.RangeRequest) clientv3.Op {
	opts := []clientv3.OpOption{}
	if len(r.RangeEnd) != 0 {
		opts = append(opts, clientv3.WithRange(string(r.RangeEnd)))
	}
	opts = append(opts, clientv3.WithRev(r.Revision))
	opts = append(opts, clientv3.WithLimit(r.Limit))
	opts = append(opts, clientv3.WithSort(
		clientv3.SortTarget(r.SortTarget),
		clientv3.SortOrder(r.SortOrder)),
	)

	if r.Serializable {
		opts = append(opts, clientv3.WithSerializable())
	}

	return clientv3.OpGet(string(r.Key), opts...)
}

func PutRequestToOp(r *pb.PutRequest) clientv3.Op {
	opts := []clientv3.OpOption{}
	opts = append(opts, clientv3.WithLease(clientv3.LeaseID(r.Lease)))

	return clientv3.OpPut(string(r.Key), string(r.Value), opts...)
}

func DelRequestToOp(r *pb.DeleteRangeRequest) clientv3.Op {
	opts := []clientv3.OpOption{}
	if len(r.RangeEnd) != 0 {
		opts = append(opts, clientv3.WithRange(string(r.RangeEnd)))
	}

	return clientv3.OpDelete(string(r.Key), opts...)
}
<commit_msg>grpcproxy: respect prev_kv flag<commit_after>// Copyright 2016 The etcd 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 grpcproxy

import (
	"github.com/coreos/etcd/clientv3"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/proxy/grpcproxy/cache"

	"golang.org/x/net/context"
)

type kvProxy struct {
	kv    clientv3.KV
	cache cache.Cache
}

func NewKvProxy(c *clientv3.Client) pb.KVServer {
	return &kvProxy{
		kv:    c.KV,
		cache: cache.NewCache(cache.DefaultMaxEntries),
	}
}

func (p *kvProxy) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
	// if request set Serializable, serve it from local cache first
	if r.Serializable {
		resp, err := p.cache.Get(r)
		switch err {
		case nil:
			return resp, nil
		case cache.ErrCompacted:
			return nil, err
		}
	}

	resp, err := p.kv.Do(ctx, RangeRequestToOp(r))
	if err != nil {
		return nil, err
	}

	p.cache.Add(r, (*pb.RangeResponse)(resp.Get()))

	return (*pb.RangeResponse)(resp.Get()), nil
}

func (p *kvProxy) Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error) {
	resp, err := p.kv.Do(ctx, PutRequestToOp(r))
	return (*pb.PutResponse)(resp.Put()), err
}

func (p *kvProxy) DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) {
	resp, err := p.kv.Do(ctx, DelRequestToOp(r))
	return (*pb.DeleteRangeResponse)(resp.Del()), err
}

func (p *kvProxy) Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error) {
	txn := p.kv.Txn(ctx)
	cmps := make([]clientv3.Cmp, len(r.Compare))
	thenops := make([]clientv3.Op, len(r.Success))
	elseops := make([]clientv3.Op, len(r.Failure))

	for i := range r.Compare {
		cmps[i] = (clientv3.Cmp)(*r.Compare[i])
	}

	for i := range r.Success {
		thenops[i] = requestOpToOp(r.Success[i])
	}

	for i := range r.Failure {
		elseops[i] = requestOpToOp(r.Failure[i])
	}

	resp, err := txn.If(cmps...).Then(thenops...).Else(elseops...).Commit()
	return (*pb.TxnResponse)(resp), err
}

func (p *kvProxy) Compact(ctx context.Context, r *pb.CompactionRequest) (*pb.CompactionResponse, error) {
	var opts []clientv3.CompactOption
	if r.Physical {
		opts = append(opts, clientv3.WithCompactPhysical())
	}

	resp, err := p.kv.Compact(ctx, r.Revision, opts...)
	if err == nil {
		p.cache.Compact(r.Revision)
	}

	return (*pb.CompactionResponse)(resp), err
}

func requestOpToOp(union *pb.RequestOp) clientv3.Op {
	switch tv := union.Request.(type) {
	case *pb.RequestOp_RequestRange:
		if tv.RequestRange != nil {
			return RangeRequestToOp(tv.RequestRange)
		}
	case *pb.RequestOp_RequestPut:
		if tv.RequestPut != nil {
			return PutRequestToOp(tv.RequestPut)
		}
	case *pb.RequestOp_RequestDeleteRange:
		if tv.RequestDeleteRange != nil {
			return DelRequestToOp(tv.RequestDeleteRange)
		}
	}
	panic("unknown request")
}

func RangeRequestToOp(r *pb.RangeRequest) clientv3.Op {
	opts := []clientv3.OpOption{}
	if len(r.RangeEnd) != 0 {
		opts = append(opts, clientv3.WithRange(string(r.RangeEnd)))
	}
	opts = append(opts, clientv3.WithRev(r.Revision))
	opts = append(opts, clientv3.WithLimit(r.Limit))
	opts = append(opts, clientv3.WithSort(
		clientv3.SortTarget(r.SortTarget),
		clientv3.SortOrder(r.SortOrder)),
	)

	if r.Serializable {
		opts = append(opts, clientv3.WithSerializable())
	}

	return clientv3.OpGet(string(r.Key), opts...)
}

func PutRequestToOp(r *pb.PutRequest) clientv3.Op {
	opts := []clientv3.OpOption{}
	opts = append(opts, clientv3.WithLease(clientv3.LeaseID(r.Lease)))

	return clientv3.OpPut(string(r.Key), string(r.Value), opts...)
}

func DelRequestToOp(r *pb.DeleteRangeRequest) clientv3.Op {
	opts := []clientv3.OpOption{}
	if len(r.RangeEnd) != 0 {
		opts = append(opts, clientv3.WithRange(string(r.RangeEnd)))
	}
	if r.PrevKv {
		opts = append(opts, clientv3.WithPrevKV())
	}
	return clientv3.OpDelete(string(r.Key), opts...)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/beard1ess/gauss/parsing"
	"github.com/beard1ess/gauss/ui"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"io/ioutil"
	"reflect"
	"strings"
	"testing"
)

func TestDiff(t *testing.T) {

	/*
	 * Create instances of test helper objects
	 */
	assert := assert.New(t)
	require := require.New(t)

	/*
	 * Test Cases
	 */
	testCases := []struct {
		origin   string
		modified string
		diff     string
		path     string
		output   string
	}{
		{"addKey_o.json", "addKey_m.json", "addKey_d.json", "", "raw"},
		{"rmKey_o.json", "rmKey_m.json", "rmKey_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modDeepKey_d.json", "", "raw"},
		{"addModKey_o.json", "addModKey_m.json", "addModKey_d.json", "", "raw"},
		{"modArray_o.json", "modArray_m.json", "modArray_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modPathDeepKey_d.json", "key1.\"key1-1\"", "raw"},
		{"modArrayKeepPath_o.json", "modArrayKeepPath_m.json", "modArrayKeepPath_d.json", "Outputs.Default[5]", "raw"},
	}
//
	/*
	 * Test Logic
	 */
	for _, tc := range testCases {

		t.Run(
			fmt.Sprintf(
				"Origin:%s, Modified:%s, Diff:%s, Path:%s, Output:%s",
				tc.origin,
				tc.modified,
				tc.diff,
				tc.path,
				tc.output,
			),

			func(t *testing.T) {

				// Read and unmarshal the expected output.
				expectedJson, err := ioutil.ReadFile("./tests/" + tc.diff)
				require.Nil(err, "The test diff should be readable.")

				var expected parsing.ConsumableDifference
				json.Unmarshal(expectedJson, &expected)
				require.Nil(err, "The test data should be unmarshaled without error.")
				// sort the arrays

				// Execute a Diff against the Origin and Modified test files.
				var testBuffer *bytes.Buffer = bytes.NewBuffer(nil)

				ui.Diff(
					"./tests/"+tc.origin,
					"./tests/"+tc.modified,
					tc.output,
					tc.path,
					testBuffer,
				)

				// Read and unmarshal the actual output.
				result, err := ioutil.ReadAll(testBuffer)
				require.Nil(err, "The test buffer should be readable")

				var actual parsing.ConsumableDifference
				json.Unmarshal(result, &actual)
				assert.Nil(err, "The result should be unmarshaled without error.")

				// sort the arrays
				actual.Sort()
				expected.Sort()

				// The Expected and Actual output should be deeply equal.
				assert.Equal(
					reflect.DeepEqual(expected, actual),
					true,
					fmt.Sprintf(
						strings.Join(
							[]string{
								"The diff of %s and %s should equal %s.\n",
								"Expected:\n",
								"%s",
								"Actual:\n",
								"%s",
							},
							" ",
						),
						tc.origin,
						tc.modified,
						tc.diff,
						string(expectedJson),
						string(result),
					),
				)
			},
		)
	}
}

/*
func TestPatch(t *testing.T) {

	 // Create instances of test helper objects

	assert := assert.New(t)
	require := require.New(t)

	 // Test Cases

	testCases := []struct {
		origin   string
		modified string
		diff     string
		path     string
		output   string
	}{
		{"addKey_o.json", "addKey_m.json", "addKey_d.json", "", "raw"},
		{"rmKey_o.json", "rmKey_m.json", "rmKey_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modDeepKey_d.json", "", "raw"},
		{"addModKey_o.json", "addModKey_m.json", "addModKey_d.json", "", "raw"},
		{"modArray_o.json", "modArray_m.json", "modArray_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modPathDeepKey_d.json", "key1.\"key1-1\"", "raw"},
		{"modArrayKeepPath_o.json", "modArrayKeepPath_m.json", "modArrayKeepPath_d.json", "Outputs.Default[5]", "raw"},
	}
	//

	 // Test Logic

	for _, tc := range testCases {

		t.Run(
			fmt.Sprintf(
				"Origin:%s, Modified:%s, Diff:%s, Path:%s, Output:%s",
				tc.origin,
				tc.modified,
				tc.diff,
				tc.path,
				tc.output,
			),

			func(t *testing.T) {

				// Read and unmarshal the expected output.
				expectedJson, err := ioutil.ReadFile("./tests/" + tc.diff)
				require.Nil(err, "The test diff should be readable.")

				var expected parsing.ConsumableDifference
				json.Unmarshal(expectedJson, &expected)
				require.Nil(err, "The test data should be unmarshaled without error.")
				// sort the arrays

				// Execute a Diff against the Origin and Modified test files.
				var testBuffer *bytes.Buffer = bytes.NewBuffer(nil)

				ui.Patch(
					"./tests/"+tc.diff,
					"./tests/"+tc.origin,
					tc.output,
					tc.path,
					testBuffer,
				)

					patch string,
	original string,
	output string,
	skipKeys string,
	writer io.Writer,

				// Read and unmarshal the actual output.
				result, err := ioutil.ReadAll(testBuffer)
				require.Nil(err, "The test buffer should be readable")

				var actual parsing.ConsumableDifference
                json.Unmarshal(result, &actual)
				assert.Nil(err, "The result should be unmarshaled without error.")

				// sort the arrays
				actual.Sort()
				expected.Sort()

				// The Expected and Actual output should be deeply equal.
				assert.Equal(
					reflect.DeepEqual(expected, actual),
					true,
					fmt.Sprintf(
						strings.Join(
							[]string{
								"The diff of %s and %s should equal %s.\n",
								"Expected:\n",
								"%s",
								"Actual:\n",
								"%s",
							},
							" ",
						),
						tc.origin,
						tc.modified,
						tc.diff,
						string(expectedJson),
						string(result),
					),
				)
			},
		)
	}
}
*/<commit_msg>patch functions working. put together tests.<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/beard1ess/gauss/parsing"
	"github.com/beard1ess/gauss/ui"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"io/ioutil"
	"reflect"
	"strings"
	"testing"
)

func TestDiff(t *testing.T) {

	/*
	 * Create instances of test helper objects
	 */
	assert := assert.New(t)
	require := require.New(t)

	/*
	 * Test Cases
	 */
	testCases := []struct {
		origin   string
		modified string
		diff     string
		path     string
		output   string
	}{
		{"addKey_o.json", "addKey_m.json", "addKey_d.json", "", "raw"},
		{"rmKey_o.json", "rmKey_m.json", "rmKey_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modDeepKey_d.json", "", "raw"},
		{"addModKey_o.json", "addModKey_m.json", "addModKey_d.json", "", "raw"},
		{"modArray_o.json", "modArray_m.json", "modArray_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modPathDeepKey_d.json", "key1.\"key1-1\"", "raw"},
		{"modArrayKeepPath_o.json", "modArrayKeepPath_m.json", "modArrayKeepPath_d.json", "Outputs.Default[5]", "raw"},
	}
//
	/*
	 * Test Logic
	 */
	for _, tc := range testCases {

		t.Run(
			fmt.Sprintf(
				"Origin:%s, Modified:%s, Diff:%s, Path:%s, Output:%s",
				tc.origin,
				tc.modified,
				tc.diff,
				tc.path,
				tc.output,
			),

			func(t *testing.T) {

				// Read and unmarshal the expected output.
				expectedJson, err := ioutil.ReadFile("./tests/" + tc.diff)
				require.Nil(err, "The test diff should be readable.")

				var expected parsing.ConsumableDifference
				json.Unmarshal(expectedJson, &expected)
				require.Nil(err, "The test data should be unmarshaled without error.")
				// sort the arrays

				// Execute a Diff against the Origin and Modified test files.
				var testBuffer *bytes.Buffer = bytes.NewBuffer(nil)

				ui.Diff(
					"./tests/"+tc.origin,
					"./tests/"+tc.modified,
					tc.output,
					tc.path,
					testBuffer,
				)

				// Read and unmarshal the actual output.
				result, err := ioutil.ReadAll(testBuffer)
				require.Nil(err, "The test buffer should be readable")

				var actual parsing.ConsumableDifference
				json.Unmarshal(result, &actual)
				assert.Nil(err, "The result should be unmarshaled without error.")

				// sort the arrays
				actual.Sort()
				expected.Sort()

				// The Expected and Actual output should be deeply equal.
				assert.Equal(
					reflect.DeepEqual(expected, actual),
					true,
					fmt.Sprintf(
						strings.Join(
							[]string{
								"The diff of %s and %s should equal %s.\n",
								"Expected:\n",
								"%s",
								"Actual:\n",
								"%s",
							},
							" ",
						),
						tc.origin,
						tc.modified,
						tc.diff,
						string(expectedJson),
						string(result),
					),
				)
			},
		)
	}
}

func TestPatch(t *testing.T) {

	 // Create instances of test helper objects

	assert := assert.New(t)
	require := require.New(t)

	 // Test Cases

	testCases := []struct {
		origin   string
		modified string
		patch     string
		skipKeys     string
		output   string
	}{
		{"addKey_o.json", "addKey_m.json", "addKey_d.json", "", "raw"},
		{"rmKey_o.json", "rmKey_m.json", "rmKey_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modDeepKey_d.json", "", "raw"},
		{"addModKey_o.json", "addModKey_m.json", "addModKey_d.json", "", "raw"},
		{"modArray_o.json", "modArray_m.json", "modArray_d.json", "", "raw"},
		{"modDeepKey_o.json", "modDeepKey_m.json", "modPathDeepKey_d.json", "key1.\"key1-1\"", "raw"},
		{"modArrayKeepPath_o.json", "modArrayKeepPath_m.json", "modArrayKeepPath_d.json", "Outputs.Default[5]", "raw"},
	}
	//

	 // Test Logic

	for _, tc := range testCases {

		t.Run(
			fmt.Sprintf(
				"Origin:%s, Modified:%s, Diff:%s, Path:%s, Output:%s",
				tc.origin,
				tc.modified,
				tc.patch,
				tc.skipKeys,
				tc.output,
			),

			func(t *testing.T) {

				// Read and unmarshal the expected output.
				expectedJson, err := ioutil.ReadFile("./tests/" + tc.modified)
				require.Nil(err, "The test diff should be readable.")

				var expected parsing.ConsumableDifference
				json.Unmarshal(expectedJson, &expected)
				require.Nil(err, "The test data should be unmarshaled without error.")
				// sort the arrays

				// Execute a Diff against the Origin and Modified test files.
				var testBuffer *bytes.Buffer = bytes.NewBuffer(nil)

				ui.Patch(
					"./tests/"+tc.modified,
					"./tests/"+tc.origin,
					tc.output,
					tc.skipKeys,
					testBuffer,
				)

				// Read and unmarshal the actual output.
				result, err := ioutil.ReadAll(testBuffer)
				require.Nil(err, "The test buffer should be readable")

				var actual parsing.ConsumableDifference
                json.Unmarshal(result, &actual)
				assert.Nil(err, "The result should be unmarshaled without error.")

				// sort the arrays
				actual.Sort()
				expected.Sort()

				// The Expected and Actual output should be deeply equal.
				assert.Equal(
					reflect.DeepEqual(expected, actual),
					true,
					fmt.Sprintf(
						strings.Join(
							[]string{
								"The diff of %s and %s should equal %s.\n",
								"Expected:\n",
								"%s",
								"Actual:\n",
								"%s",
							},
							" ",
						),
						tc.origin,
						tc.modified,
						tc.patch,
						string(expectedJson),
						string(result),
					),
				)
			},
		)
	}
}
<|endoftext|>


<commit_before>// Package qemu provides implementations of a net.Conn and net.Listener backed by qemu_pipe
package qemu

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"
)

const (
	// SocketName value passed to the emulator at startup time and can't change.
	SocketName = "sockets/h2o"

	qemuDriver = "/dev/qemu_pipe"
	svcName    = "pipe:unix:sockets/h2o"
	ioErrMsg   = "input/output error"
	rdyMsg     = "rdy"
)

var errClosed = errors.New("error connection closed")
var errNotImplemented = errors.New("error not implemented")

type qemuAddr string

// Network returns the network type of the connection
func (a qemuAddr) Network() string {
	return qemuDriver
}

// String returns the description of the connection
func (a qemuAddr) String() string {
	return svcName
}

// Pipe implements a net.Listener on top of a guest qemu pipe
type Pipe struct {
	closed bool
}

// Conn implements the net.Conn interface on top of a qemu_pipe
type Conn struct {
	// Backed by qemu_pipe
	conn io.ReadWriteCloser

	// Dummy addr
	addr net.Addr

	// Bytes remaining in the connection buffer
	// it would be tempting to simplify the code and use
	// an intermediate buffer to hold overflow buffer
	// but bytes.Buffer does not shrink which causes memory usage
	// to blow up
	left int

	closedReads  bool
	closedWrites bool

	readLock  *sync.Mutex
	writeLock *sync.Mutex
}

// Read reads from from the Conn connection.
// Note that each message is prepended with the size, so we need to keep
// track of how many bytes we need to read across Read calls
func (q *Conn) Read(b []byte) (int, error) {
	q.readLock.Lock()
	defer q.readLock.Unlock()

	// Normally this could be done by just checking status != io.EOF, however
	// a read on /dev/qemu-pipe associated with a closed connection will return
	// EIO with the string "input/output error". Since errno isn't visible to us,
	// we check the error message and ensure the target string is not present.
	n, err := q.read(b)
	if err != nil && strings.Contains(err.Error(), ioErrMsg) {
		return n, io.EOF
	}
	return n, err

}

func (q *Conn) read(b []byte) (int, error) {
	if q.closedReads {
		return 0, errClosed
	}

	toRead := q.left
	if toRead > len(b) {
		toRead = len(b)
	}

	// read leftovers from previous reads
	ln := toRead
	if q.left > 0 {
		if n, err := io.ReadFull(q.conn, b[:toRead]); err != nil {
			return n, err
		}
		// If ReadFull finished without issues, exactly toRead bytes were read
		q.left = q.left - toRead

		if q.left > 0 || toRead == len(b) {
			return toRead, nil
		}
	}

	var recd int32
	if err := binary.Read(q.conn, binary.LittleEndian, &recd); err != nil {
		return 0, err
	}

	// The other side has signaled an EOF. Close connection for reads, we might have leftover writes
	if recd == 0 {
		q.closedReads = true
		if q.closedWrites {
			// No more to read or write, close the pipe
			q.conn.Close()
		}
		return ln, io.EOF
	}

	sCap := len(b) - ln
	toRead = int(recd)
	if toRead > sCap {
		toRead = sCap
	}
	b = b[ln : ln+toRead]

	rn, err := io.ReadFull(q.conn, b)
	if err != nil {
		return rn, err
	}
	q.left = int(recd) - toRead
	return ln + rn, nil
}

// Write writes the contents of b to the underlying connection
func (q *Conn) Write(b []byte) (int, error) {
	q.writeLock.Lock()
	defer q.writeLock.Unlock()

	if q.closedWrites {
		return 0, errClosed
	}

	// Prepend the message with size
	if err := binary.Write(q.conn, binary.LittleEndian, uint32(len(b))); err != nil {
		return 0, err
	}
	n, e := q.conn.Write(b)
	return n, e
}

func (q *Conn) sendClose() error {
	if err := binary.Write(q.conn, binary.LittleEndian, uint32(0)); err != nil {
		return err
	}
	_, e := q.conn.Write([]byte{})
	return e
}

// Close closes the connection
func (q *Conn) Close() error {
	q.writeLock.Lock()
	defer q.writeLock.Unlock()

	if q.closedWrites {
		return errClosed
	}
	q.closedWrites = true
	if err := q.sendClose(); err != nil {
		return err
	}
	if q.closedReads {
		// Nothing else to write or read, close the pipe
		if err := q.conn.Close(); err != nil {
			return err
		}
	}
	return nil
}

// LocalAddr returns the qemu address
func (q *Conn) LocalAddr() net.Addr {
	return q.addr
}

// RemoteAddr returns the qemu address
func (q *Conn) RemoteAddr() net.Addr {
	return q.addr
}

// SetDeadline sets the connection deadline
func (q *Conn) SetDeadline(t time.Time) error {
	return errNotImplemented
}

// SetReadDeadline sets the read deadline
func (q *Conn) SetReadDeadline(t time.Time) error {
	return errNotImplemented
}

// SetWriteDeadline sets the write deadline
func (q *Conn) SetWriteDeadline(t time.Time) error {
	return errNotImplemented
}

// Accept creates a new net.Conn backed by a qemu_pipe connetion
func (q *Pipe) Accept() (net.Conn, error) {

	if q.closed {
		return nil, errClosed
	}

	// Each new file descriptor we open will create a new connection
	// We need to wait on the host to be ready:
	// 1) poll the qemu_pipe driver with the desiered socket name
	// 2) wait until the client is read to send/recv, we do this waiting until we read a rdy message
	var conn *os.File
	var err error
	br := false
	for {
		if conn != nil {
			// Got an error, close connection and try again
			conn.Close()
			time.Sleep(20 * time.Millisecond)
		}

		if conn, err = os.OpenFile(qemuDriver, os.O_RDWR, 0600); err != nil {
			return nil, err
		}

		// qemu_pipe does not properly support polling io. Force blocking io
		if err := syscall.SetNonblock(int(conn.Fd()), false); err != nil {
			return nil, err
		}

		buff := make([]byte, len(svcName)+1)
		copy(buff, svcName)

		// retry loop to wait until we can start the service on the qemu_pipe
		for {
			written, err := conn.Write(buff)
			if err != nil {
				// The host has not opened the socket. Sleep and try again
				conn.Close()
				time.Sleep(100 * time.Millisecond)
				break
			}
			buff = buff[written:]
			if len(buff) == 0 {
				br = true
				break
			}
		}

		if br {
			// Wait for the client to open a socket on the host
			waitBuff := make([]byte, len(rdyMsg))
			if _, err := io.ReadFull(conn, waitBuff); err != nil {
				br = false
				continue
			}
			if !bytes.Equal([]byte(rdyMsg), waitBuff) {
				br = false
				continue
			}
			if _, err := conn.Write(waitBuff); err != nil {
				br = false
				continue
			}

			return &Conn{
				conn:      conn,
				addr:      qemuAddr(""),
				readLock:  &sync.Mutex{},
				writeLock: &sync.Mutex{},
			}, nil

		}
	}

}

// Close closes the connection
func (q *Pipe) Close() error {
	q.closed = true
	return nil
}

// Addr returns the connection address
func (q *Pipe) Addr() net.Addr {
	return qemuAddr("")
}

// MakePipe will return a new net.Listener
// backed by a qemu pipe. Qemu pipes are implemented as virtual
// devices. To get a handle an open("/dev/qemu_pipe") is issued.
// The virtual driver keeps a map of file descriptors to available
// services. In this case we open a unix socket service and return that.
func MakePipe() (*Pipe, error) {
	if _, err := os.Stat(qemuDriver); err != nil {
		return nil, err
	}

	return &Pipe{}, nil
}

// ConnBuilder implements a qemu connection builder. It wraps around listener
// listening on a qemu pipe. It accepts connectsion and sync with the client
// before returning
type ConnBuilder struct {
	lis net.Listener
}

// Close closes the underlying net.Listener
func (b *ConnBuilder) Close() error {
	return b.lis.Close()
}

// Next will connect to the guest and return the connection.
func (b *ConnBuilder) Next() (net.Conn, error) {
	for {
		conn, err := b.lis.Accept()
		if err != nil {
			return nil, err
		}

		// sync with the server
		rdy := []byte(rdyMsg)
		if _, err := conn.Write(rdy); err != nil {
			continue
		}
		if _, err := io.ReadFull(conn, rdy); err != nil {
			continue
		}
		if !bytes.Equal([]byte(rdyMsg), rdy) {
			continue
		}

		return &Conn{
			conn:      conn,
			addr:      qemuAddr(""),
			readLock:  &sync.Mutex{},
			writeLock: &sync.Mutex{},
		}, nil
	}
}

// MakeConnBuilder creates a new ConnBuilder struct
func MakeConnBuilder(dir string) (*ConnBuilder, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	if err := os.Chdir(dir); err != nil {
		return nil, err
	}

	os.Remove(SocketName)
	lis, err := net.Listen("unix", SocketName)
	if err != nil {
		return nil, err
	}

	if err := os.Chdir(wd); err != nil {
		return nil, err
	}

	return &ConnBuilder{lis: lis}, nil
}
<commit_msg>return early on short reads so we dont block waiting for reads<commit_after>// Package qemu provides implementations of a net.Conn and net.Listener backed by qemu_pipe
package qemu

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"
)

const (
	// SocketName value passed to the emulator at startup time and can't change.
	SocketName = "sockets/h2o"

	qemuDriver = "/dev/qemu_pipe"
	svcName    = "pipe:unix:sockets/h2o"
	ioErrMsg   = "input/output error"
	rdyMsg     = "rdy"
)

var errClosed = errors.New("error connection closed")
var errNotImplemented = errors.New("error not implemented")

type qemuAddr string

// Network returns the network type of the connection
func (a qemuAddr) Network() string {
	return qemuDriver
}

// String returns the description of the connection
func (a qemuAddr) String() string {
	return svcName
}

// Pipe implements a net.Listener on top of a guest qemu pipe
type Pipe struct {
	closed bool
}

// Conn implements the net.Conn interface on top of a qemu_pipe
type Conn struct {
	// Backed by qemu_pipe
	conn io.ReadWriteCloser

	// Dummy addr
	addr net.Addr

	// Bytes remaining in the connection buffer
	// it would be tempting to simplify the code and use
	// an intermediate buffer to hold overflow buffer
	// but bytes.Buffer does not shrink which causes memory usage
	// to blow up
	left int

	closedReads  bool
	closedWrites bool

	readLock  *sync.Mutex
	writeLock *sync.Mutex
}

// Read reads from from the Conn connection.
// Note that each message is prepended with the size, so we need to keep
// track of how many bytes we need to read across Read calls
func (q *Conn) Read(b []byte) (int, error) {
	q.readLock.Lock()
	defer q.readLock.Unlock()

	// Normally this could be done by just checking status != io.EOF, however
	// a read on /dev/qemu-pipe associated with a closed connection will return
	// EIO with the string "input/output error". Since errno isn't visible to us,
	// we check the error message and ensure the target string is not present.
	n, err := q.read(b)
	if err != nil && strings.Contains(err.Error(), ioErrMsg) {
		return n, io.EOF
	}
	return n, err

}

func (q *Conn) read(b []byte) (int, error) {
	if q.closedReads {
		return 0, errClosed
	}

	toRead := q.left
	if toRead > len(b) {
		toRead = len(b)
	}

	// read leftovers from previous reads before trying to read the size
	if toRead > 0 {
		n, err := io.ReadFull(q.conn, b[:toRead])
		if err != nil {
			return n, err
		}
		q.left = q.left - n

		// b might be bigger than remaining bytes but conn might be empty and
		// we dont want to block on size read, so return early.
		return n, nil
	}

	var recd uint32
	if err := binary.Read(q.conn, binary.LittleEndian, &recd); err != nil {
		return 0, err
	}

	// The other side has signaled an EOF. Close connection for reads, we might have leftover writes
	if recd == 0 {
		q.closedReads = true
		if q.closedWrites {
			// No more to read or write, close the pipe
			q.conn.Close()
		}
		return 0, io.EOF
	}

	toRead = int(recd)
	if toRead > len(b) {
		toRead = len(b)
	}

	n, err := io.ReadFull(q.conn, b[:toRead])
	if err != nil {
		return n, err
	}
	q.left = int(recd) - toRead
	return n, nil
}

// Write writes the contents of b to the underlying connection
func (q *Conn) Write(b []byte) (int, error) {
	q.writeLock.Lock()
	defer q.writeLock.Unlock()

	if q.closedWrites {
		return 0, errClosed
	}

	// Prepend the message with size
	if err := binary.Write(q.conn, binary.LittleEndian, uint32(len(b))); err != nil {
		return 0, err
	}
	n, e := q.conn.Write(b)
	return n, e
}

func (q *Conn) sendClose() error {
	if err := binary.Write(q.conn, binary.LittleEndian, uint32(0)); err != nil {
		return err
	}
	_, e := q.conn.Write([]byte{})
	return e
}

// Close closes the connection
func (q *Conn) Close() error {
	q.writeLock.Lock()
	defer q.writeLock.Unlock()

	if q.closedWrites {
		return errClosed
	}
	q.closedWrites = true
	if err := q.sendClose(); err != nil {
		return err
	}
	if q.closedReads {
		// Nothing else to write or read, close the pipe
		if err := q.conn.Close(); err != nil {
			return err
		}
	}
	return nil
}

// LocalAddr returns the qemu address
func (q *Conn) LocalAddr() net.Addr {
	return q.addr
}

// RemoteAddr returns the qemu address
func (q *Conn) RemoteAddr() net.Addr {
	return q.addr
}

// SetDeadline sets the connection deadline
func (q *Conn) SetDeadline(t time.Time) error {
	return errNotImplemented
}

// SetReadDeadline sets the read deadline
func (q *Conn) SetReadDeadline(t time.Time) error {
	return errNotImplemented
}

// SetWriteDeadline sets the write deadline
func (q *Conn) SetWriteDeadline(t time.Time) error {
	return errNotImplemented
}

// Accept creates a new net.Conn backed by a qemu_pipe connetion
func (q *Pipe) Accept() (net.Conn, error) {

	if q.closed {
		return nil, errClosed
	}

	// Each new file descriptor we open will create a new connection
	// We need to wait on the host to be ready:
	// 1) poll the qemu_pipe driver with the desiered socket name
	// 2) wait until the client is read to send/recv, we do this waiting until we read a rdy message
	var conn *os.File
	var err error
	br := false
	for {
		if conn != nil {
			// Got an error, close connection and try again
			conn.Close()
			time.Sleep(20 * time.Millisecond)
		}

		if conn, err = os.OpenFile(qemuDriver, os.O_RDWR, 0600); err != nil {
			return nil, err
		}

		// qemu_pipe does not properly support polling io. Force blocking io
		if err := syscall.SetNonblock(int(conn.Fd()), false); err != nil {
			return nil, err
		}

		buff := make([]byte, len(svcName)+1)
		copy(buff, svcName)

		// retry loop to wait until we can start the service on the qemu_pipe
		for {
			written, err := conn.Write(buff)
			if err != nil {
				// The host has not opened the socket. Sleep and try again
				conn.Close()
				time.Sleep(100 * time.Millisecond)
				break
			}
			buff = buff[written:]
			if len(buff) == 0 {
				br = true
				break
			}
		}

		if br {
			// Wait for the client to open a socket on the host
			waitBuff := make([]byte, len(rdyMsg))
			if _, err := io.ReadFull(conn, waitBuff); err != nil {
				br = false
				continue
			}
			if !bytes.Equal([]byte(rdyMsg), waitBuff) {
				br = false
				continue
			}
			if _, err := conn.Write(waitBuff); err != nil {
				br = false
				continue
			}

			return &Conn{
				conn:      conn,
				addr:      qemuAddr(""),
				readLock:  &sync.Mutex{},
				writeLock: &sync.Mutex{},
			}, nil

		}
	}

}

// Close closes the connection
func (q *Pipe) Close() error {
	q.closed = true
	return nil
}

// Addr returns the connection address
func (q *Pipe) Addr() net.Addr {
	return qemuAddr("")
}

// MakePipe will return a new net.Listener
// backed by a qemu pipe. Qemu pipes are implemented as virtual
// devices. To get a handle an open("/dev/qemu_pipe") is issued.
// The virtual driver keeps a map of file descriptors to available
// services. In this case we open a unix socket service and return that.
func MakePipe() (*Pipe, error) {
	if _, err := os.Stat(qemuDriver); err != nil {
		return nil, err
	}

	return &Pipe{}, nil
}

// ConnBuilder implements a qemu connection builder. It wraps around listener
// listening on a qemu pipe. It accepts connectsion and sync with the client
// before returning
type ConnBuilder struct {
	lis net.Listener
}

// Close closes the underlying net.Listener
func (b *ConnBuilder) Close() error {
	return b.lis.Close()
}

// Next will connect to the guest and return the connection.
func (b *ConnBuilder) Next() (net.Conn, error) {
	for {
		conn, err := b.lis.Accept()
		if err != nil {
			return nil, err
		}

		// sync with the server
		rdy := []byte(rdyMsg)
		if _, err := conn.Write(rdy); err != nil {
			continue
		}
		if _, err := io.ReadFull(conn, rdy); err != nil {
			continue
		}
		if !bytes.Equal([]byte(rdyMsg), rdy) {
			continue
		}

		return &Conn{
			conn:      conn,
			addr:      qemuAddr(""),
			readLock:  &sync.Mutex{},
			writeLock: &sync.Mutex{},
		}, nil
	}
}

// MakeConnBuilder creates a new ConnBuilder struct
func MakeConnBuilder(dir string) (*ConnBuilder, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	if err := os.Chdir(dir); err != nil {
		return nil, err
	}

	os.Remove(SocketName)
	lis, err := net.Listen("unix", SocketName)
	if err != nil {
		return nil, err
	}

	if err := os.Chdir(wd); err != nil {
		return nil, err
	}

	return &ConnBuilder{lis: lis}, nil
}
<|endoftext|>


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

package handler

import (
	"bytes"
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/web/orchestrator"
	"github.com/andreaskoch/allmark2/web/view/templates"
	"github.com/andreaskoch/allmark2/web/view/viewmodel"
	"net/http"
	"text/template"
)

type Tags struct {
	logger logger.Logger

	templateProvider       templates.Provider
	navigationOrchestrator orchestrator.NavigationOrchestrator
	tagsOrchestrator       orchestrator.TagsOrchestrator
}

func (self *Tags) Func() func(w http.ResponseWriter, r *http.Request) {

	return func(w http.ResponseWriter, r *http.Request) {

		tagmapTemplate, err := self.templateProvider.GetFullTemplate(templates.TagmapTemplateName)
		if err != nil {
			fmt.Fprintf(w, "Template not found. Error: %s", err)
			return
		}

		tagmapContentTemplate, err := self.templateProvider.GetSubTemplate(templates.TagmapContentTemplateName)
		if err != nil {
			fmt.Fprintf(w, "Content template not found. Error: %s", err)
			return
		}

		tagMapItems := ""
		tags := self.tagsOrchestrator.GetTags()

		if len(tags) > 0 {
			for _, tag := range tags {
				tagMapItems += renderTagmapEntry(tagmapContentTemplate, tag)
			}
		} else {
			tagMapItems = "-- There are currently not tagged items --"
		}

		tagmapViewModel := viewmodel.Model{
			Content: tagMapItems,
		}

		tagmapViewModel.Type = "tagmap"
		tagmapViewModel.Title = "Tags"
		tagmapViewModel.ToplevelNavigation = self.navigationOrchestrator.GetToplevelNavigation()
		tagmapViewModel.TagCloud = self.tagsOrchestrator.GetTagCloud()

		renderTemplate(tagmapViewModel, tagmapTemplate, w)
	}
}

func renderTagmapEntry(templ *template.Template, tagModel *viewmodel.Tag) string {
	buffer := new(bytes.Buffer)
	renderTemplate(tagModel, templ, buffer)
	return buffer.String()
}
<commit_msg>Include the Breadcrumb navigation on the tags overview page<commit_after>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package handler

import (
	"bytes"
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/web/orchestrator"
	"github.com/andreaskoch/allmark2/web/view/templates"
	"github.com/andreaskoch/allmark2/web/view/viewmodel"
	"net/http"
	"text/template"
)

type Tags struct {
	logger logger.Logger

	templateProvider       templates.Provider
	navigationOrchestrator orchestrator.NavigationOrchestrator
	tagsOrchestrator       orchestrator.TagsOrchestrator
}

func (self *Tags) Func() func(w http.ResponseWriter, r *http.Request) {

	return func(w http.ResponseWriter, r *http.Request) {

		tagmapTemplate, err := self.templateProvider.GetFullTemplate(templates.TagmapTemplateName)
		if err != nil {
			fmt.Fprintf(w, "Template not found. Error: %s", err)
			return
		}

		tagmapContentTemplate, err := self.templateProvider.GetSubTemplate(templates.TagmapContentTemplateName)
		if err != nil {
			fmt.Fprintf(w, "Content template not found. Error: %s", err)
			return
		}

		tagMapItems := ""
		tags := self.tagsOrchestrator.GetTags()

		if len(tags) > 0 {
			for _, tag := range tags {
				tagMapItems += renderTagmapEntry(tagmapContentTemplate, tag)
			}
		} else {
			tagMapItems = "-- There are currently not tagged items --"
		}

		tagmapViewModel := viewmodel.Model{
			Content: tagMapItems,
		}

		tagmapViewModel.Type = "tagmap"
		tagmapViewModel.Title = "Tags"
		tagmapViewModel.ToplevelNavigation = self.navigationOrchestrator.GetToplevelNavigation()
		tagmapViewModel.BreadcrumbNavigation = self.navigationOrchestrator.GetBreadcrumbNavigation(route.New())
		tagmapViewModel.TagCloud = self.tagsOrchestrator.GetTagCloud()

		renderTemplate(tagmapViewModel, tagmapTemplate, w)
	}
}

func renderTagmapEntry(templ *template.Template, tagModel *viewmodel.Tag) string {
	buffer := new(bytes.Buffer)
	renderTemplate(tagModel, templ, buffer)
	return buffer.String()
}
<|endoftext|>


<commit_before>// Package gpio implements a timer/counter unit.
// Tested compatibility:
//   ATmega48/88/168 (timer 0 only)
// Untested compatability:
//   ATmega48/88/168 (timers 1 and 2)
//   ATtiny4/5/9/10
package timer

import (
    "fmt"
    "github.com/kierdavis/avr/emulator"
    "github.com/kierdavis/avr/hardware/gpio"
    "log"
)

// TODO: for a OSCx output, require corresponding DDR bit to be set to output

// TODO: thread-safety!!

// TODO: OCFy/TOV flags should not be cleared upon interrupt execution if the
// emulator's global interrupt enable flag is cleared

type Timer struct {
    em *emulator.Emulator
    digit uint
    controlA uint8
    controlB uint8
    count uint8
    compareValA uint8
    compareValB uint8
    interruptMask uint8
    interruptFlags uint8
    downwards bool // count direction
    ocPinStates [2]bool
    ocPinCallbacks [2]func(bool)
    logging bool
    inhibitCompareMatch bool // set when TCNT is written to prevent a compare match on the next clock
    excessTicks uint
}

func New(digit uint) (t *Timer) {
    return &Timer{
        digit: digit,
    }
}

func (t *Timer) SetLogging(enabled bool) {
    t.logging = enabled
}

func (t *Timer) AddTo(em *emulator.Emulator) {
    t.em = em

    em.RegisterPortByName(fmt.Sprintf("TCCR%dA", t.digit), tccra{t})
    em.RegisterPortByName(fmt.Sprintf("TCCR%dB", t.digit), tccrb{t})
    em.RegisterPortByName(fmt.Sprintf("TCNT%d", t.digit), tcnt{t})
    em.RegisterPortByName(fmt.Sprintf("OCR%dA", t.digit), ocra{t})
    em.RegisterPortByName(fmt.Sprintf("OCR%dB", t.digit), ocrb{t})
    em.RegisterPortByName(fmt.Sprintf("TIMSK%d", t.digit), timsk{t})
    em.RegisterPortByName(fmt.Sprintf("TIFR%d", t.digit), tifr{t})
}

// Connect an output-compare pin to a GPIO port by calling the GPIO's
// OverrideOutput method.
func (t *Timer) OverrideOCPin(ocPinNum uint, gpioPinNum uint, g *gpio.GPIO) {
    t.ocPinCallbacks[ocPinNum] = g.OverrideOutput(gpioPinNum)
}

// Note: in PWM modes, OCRA/OCRB do not exhibit a newly written value until the count overflows

// TODO: in PC-PWM mode, an OCRx bit may transition without a compare match for two reasons (see datasheet page 98)

func (t *Timer) Run(ticks uint) {
    var ticksIncr uint

    switch t.controlB & 0x07 {
    case 0: // disabled
        t.excessTicks = 0
        return
    case 1: // divider = 1
        ticksIncr = 1
    case 2: // divider = 8
        ticksIncr = 8
    case 3: // divider = 64
        ticksIncr = 64
    case 4: // divider = 256
        ticksIncr = 256
    case 5: // divider = 1024
        ticksIncr = 1024
    case 6, 7:
        panic("(*Timer).Run: external clock sources not implemented")
    }
    ticksExecuted := t.excessTicks

    for ticksExecuted < ticks {
        t.Tick()
        ticksExecuted += ticksIncr
    }

    t.excessTicks = ticksExecuted - ticks
}

// Tick the timer.
func (t *Timer) Tick() {
    // Get the waveform generation mode bits
    wgm := t.getWGM()

    // Handle match-compare interrupts
    if t.inhibitCompareMatch {
        t.inhibitCompareMatch = false
    } else {
        if t.count == t.compareValA {
            t.setOCF(0)
        }
        if t.count == t.compareValB {
            t.setOCF(1)
        }
    }

    // Prepare to tick counter
    switch wgm {
    case 0: // Normal
        t.tickNormalMode()
    case 1: // Phase-correct PWM (TOP = 0xFF)
        t.tickPCPWMMode(0xFF)
    case 2: // Clear timer on compare
        t.tickCTCMode()
    case 3: // Fast PWM (TOP = 0xFF)
        t.tickFastPWMMode(0xFF)
    case 5: // Phase-correct PWM (TOP = OCRA)
        t.tickPCPWMMode(t.compareValA)
    case 7: // Fast PWM (TOP = OCRA)
        t.tickPCPWMMode(t.compareValA)
    }

    // Actually tick the counter
    if t.downwards {
        t.count--
    } else {
        t.count++
    }

    // Trigger interrupts, if possible
    if t.em != nil && t.em.InterruptsEnabled() {
        intName := ""
        if t.interruptFlags & 0x01 != 0 && t.interruptMask & 0x01 != 0 {
            t.interruptFlags &= 0xFE
            intName = fmt.Sprintf("TIMER%d_OVF", t.digit)
        } else if t.interruptFlags & 0x02 != 0 && t.interruptMask & 0x02 != 0 {
            t.interruptFlags &= 0xFD
            intName = fmt.Sprintf("TIMER%d_COMPA", t.digit)
        } else if t.interruptFlags & 0x04 != 0 && t.interruptMask & 0x04 != 0 {
            t.interruptFlags &= 0xFB
            intName = fmt.Sprintf("TIMER%d_COMPB", t.digit)
        }

        if intName != "" {
            ok := t.em.InterruptByName(intName)
            if !ok && t.logging {
                log.Printf("[avr/hardware/timer:(*Timer).Tick] failed to trigger interrupt %s", intName)
            }
        }
    }
}

// Tick the timer in Normal mode.
func (t *Timer) tickNormalMode() {
    t.downwards = false
    if t.count == 0xFF { // Overflow
        t.setTOV()
    }

    t.checkOCPinNormalMode(0, t.compareValA)
    t.checkOCPinNormalMode(1, t.compareValB)
}

// Check for output-compare in normal mode.
func (t *Timer) checkOCPinNormalMode(ocPinNum uint, compareVal uint8) {
    if t.count == compareVal {
        t.changeOCPinNormalMode(ocPinNum)
    }
}

func (t *Timer) changeOCPinNormalMode(ocPinNum uint) {
    // Get COMxy bits
    com := t.getCOM(ocPinNum)
    switch com {
    case 0: // OCy disabled
        // do nothing
    case 1: // toggle OCy
        t.toggleOCPin(ocPinNum)
    case 2: // clear OCy
        t.clearOCPin(ocPinNum)
    case 3: // set OCy
        t.setOCPin(ocPinNum)
    }
}

// Tick the timer in phase-corrected PWM mode.
func (t *Timer) tickPCPWMMode(top uint8) {
    if t.downwards {
        if t.count == 0x00 { // Reached BOTTOM
            t.downwards = false // Begin counting upwards
            t.setTOV()
        }
    } else {
        if t.count == top { // Reached TOP
            t.downwards = true // Begin counting downwards
        }
    }

    t.checkOCPinPCPWMMode(0, t.compareValA)
    t.checkOCPinPCPWMMode(1, t.compareValB)
}

// TODO: there is a special case in the OC pin checking for both PWM modes when OCRy == TOP and COMxy1 is set (see datasheet page 101)

// Check for output-compare in phase-corrected PWM mode.
func (t *Timer) checkOCPinPCPWMMode(ocPinNum uint, compareVal uint8) {
    if t.count == compareVal {
        // Get COMxy bits
        com := t.getCOM(ocPinNum)
        switch com {
        case 0: // OCy disabled
            // do nothing
        case 1: // Toggle OCy (only on OC pin 0 with WGM2 bit set)
            if ocPinNum == 0 && (t.controlB & 0x80) != 0 {
                t.toggleOCPin(ocPinNum)
            }
        case 2: // Clear OCy if counting upwards or set OCy if counting downwards
            if t.downwards {
                t.setOCPin(ocPinNum)
            } else {
                t.clearOCPin(ocPinNum)
            }
        case 3: // Set OCy if counting upwards or clear OCy if counting downwards
            if t.downwards {
                t.clearOCPin(ocPinNum)
            } else {
                t.setOCPin(ocPinNum)
            }
        }
    }
}

// Tick the timer in clear-timer-on-compare mode.
func (t *Timer) tickCTCMode() {
    t.downwards = false

    if t.count == 0xFF { // Overflow
        t.setTOV()
    }

    if t.count == t.compareValA {
        // this tick should set counter to 0
        t.count = 0xFF
    }

    t.checkOCPinCTCMode(0, t.compareValA)
    t.checkOCPinCTCMode(1, t.compareValB)
}

// Check for output-compare in normal mode.
func (t *Timer) checkOCPinCTCMode(ocPinNum uint, compareVal uint8) {
    if t.count == compareVal {
        t.changeOCPinCTCMode(ocPinNum)
    }
}

func (t *Timer) changeOCPinCTCMode(ocPinNum uint) {
    // Get COMxy bits
    com := t.getCOM(ocPinNum)
    switch com {
    case 0: // OCy disabled
        // do nothing
    case 1: // toggle OCy
        t.toggleOCPin(ocPinNum)
    case 2: // clear OCy
        t.clearOCPin(ocPinNum)
    case 3: // set OCy
        t.setOCPin(ocPinNum)
    }
}

// Tick the timer in fast PWM mode.
func (t *Timer) tickFastPWMMode(top uint8) {
    t.downwards = false

    if t.count == top {
        // this tick should set counter to 0
        t.count = 0xFF
        t.setTOV()
    }

    t.checkOCPinFastPWMMode(0, t.compareValA)
    t.checkOCPinFastPWMMode(1, t.compareValB)
}

// Check for output-compare in fast PWM mode.
func (t *Timer) checkOCPinFastPWMMode(ocPinNum uint, compareVal uint8) {
    // BOTTOM
    if t.count == 0x00 {
        // Get COMxy bits
        com := t.getCOM(ocPinNum)
        switch com {
        case 0: // OCy disabled
            // do nothing
        case 1: // Toggle OCy on compare match (only on OC pin 0 with WGM2 bit set)
            // do nothing
        case 2: // Clear OCy on compare match, set OCy at BOTTOM
            t.setOCPin(ocPinNum)
        case 3: // Set OCy on compare match, clear OCy at BOTTOM
            t.clearOCPin(ocPinNum)
        }
    }

    // Compare match
    if t.count == compareVal {
        // Get COMxy bits
        com := t.getCOM(ocPinNum)
        switch com {
        case 0: // OCy disabled
            // do nothing
        case 1: // Toggle OCy on compare match (only on OC pin 0 with WGM2 bit set)
            if ocPinNum == 0 && (t.controlB & 0x80) != 0 {
                t.toggleOCPin(ocPinNum)
            }
        case 2: // Clear OCy on compare match, set OCy at BOTTOM
            t.clearOCPin(ocPinNum)
        case 3: // Set OCy on compare match, clear OCy at BOTTOM
            t.setOCPin(ocPinNum)
        }
    }
}

// Force an output compare by calling the appropriate changeOCPin method.
func (t *Timer) forceOutputCompare(ocPinNum uint) {
    switch t.getWGM() {
    case 0: // Normal
        t.changeOCPinNormalMode(ocPinNum)
    case 2: // Clear timer on compare
        t.changeOCPinCTCMode(ocPinNum)
    default:
        // Force output compare has no effect in non-PWM modes.
    }
}

// Toggle an output-compare pin.
func (t *Timer) toggleOCPin(ocPinNum uint) {
    t.ocPinStates[ocPinNum] = !t.ocPinStates[ocPinNum]
    t.updateOCPin(ocPinNum)
}

// Set an output-compare pin to low.
func (t *Timer) clearOCPin(ocPinNum uint) {
    if t.ocPinStates[ocPinNum] {
        t.ocPinStates[ocPinNum] = false
        t.updateOCPin(ocPinNum)
    }
}

// Set an output-compare pin to high.
func (t *Timer) setOCPin(ocPinNum uint) {
    if !t.ocPinStates[ocPinNum] {
        t.ocPinStates[ocPinNum] = true
        t.updateOCPin(ocPinNum)
    }
}

// Push the new status of an output-compare pin to the GPIO layer.
func (t *Timer) updateOCPin(ocPinNum uint) {
    callback := t.ocPinCallbacks[ocPinNum]
    if callback != nil {
        callback(t.ocPinStates[ocPinNum])
    }
}

// Set an output compare match (OCFy) flag.
func (t *Timer) setOCF(ocPinNum uint) {
    if ocPinNum == 0 { // A
        t.interruptFlags |= 0x02
    } else { // B
        t.interruptFlags |= 0x04
    }
}

// Set the timer overflow (TOV) flag.
func (t *Timer) setTOV() {
    t.interruptFlags |= 0x01
}

// Get the WGM (waveform generation mode) bits
func (t *Timer) getWGM() (wgm uint8) {
    wgmA := t.controlA & 0x03 // bits 1 and 0
    wgmB := (t.controlB & 0x08) >> 1 // bit 3 (shifted to bit 2)
    return wgmB | wgmA
}

// Get the COM (compare output mode) bits for a given OC pin number.
func (t *Timer) getCOM(ocPinNum uint) (com uint8) {
    shiftAmt := 6 - 2*ocPinNum // 0 => 6, 1 => 4
    return (t.controlA >> shiftAmt) & 0x03
}
<commit_msg>Remove some unnecessary variables<commit_after>// Package gpio implements a timer/counter unit.
// Tested compatibility:
//   ATmega48/88/168 (timer 0 only)
// Untested compatability:
//   ATmega48/88/168 (timers 1 and 2)
//   ATtiny4/5/9/10
package timer

import (
    "fmt"
    "github.com/kierdavis/avr/emulator"
    "github.com/kierdavis/avr/hardware/gpio"
    "log"
)

// TODO: for a OSCx output, require corresponding DDR bit to be set to output

// TODO: thread-safety!!

// TODO: OCFy/TOV flags should not be cleared upon interrupt execution if the
// emulator's global interrupt enable flag is cleared

type Timer struct {
    em *emulator.Emulator
    digit uint
    controlA uint8
    controlB uint8
    count uint8
    compareValA uint8
    compareValB uint8
    interruptMask uint8
    interruptFlags uint8
    downwards bool // count direction
    ocPinStates [2]bool
    ocPinCallbacks [2]func(bool)
    logging bool
    inhibitCompareMatch bool // set when TCNT is written to prevent a compare match on the next clock
    excessTicks uint
}

func New(digit uint) (t *Timer) {
    return &Timer{
        digit: digit,
    }
}

func (t *Timer) SetLogging(enabled bool) {
    t.logging = enabled
}

func (t *Timer) AddTo(em *emulator.Emulator) {
    t.em = em

    em.RegisterPortByName(fmt.Sprintf("TCCR%dA", t.digit), tccra{t})
    em.RegisterPortByName(fmt.Sprintf("TCCR%dB", t.digit), tccrb{t})
    em.RegisterPortByName(fmt.Sprintf("TCNT%d", t.digit), tcnt{t})
    em.RegisterPortByName(fmt.Sprintf("OCR%dA", t.digit), ocra{t})
    em.RegisterPortByName(fmt.Sprintf("OCR%dB", t.digit), ocrb{t})
    em.RegisterPortByName(fmt.Sprintf("TIMSK%d", t.digit), timsk{t})
    em.RegisterPortByName(fmt.Sprintf("TIFR%d", t.digit), tifr{t})
}

// Connect an output-compare pin to a GPIO port by calling the GPIO's
// OverrideOutput method.
func (t *Timer) OverrideOCPin(ocPinNum uint, gpioPinNum uint, g *gpio.GPIO) {
    t.ocPinCallbacks[ocPinNum] = g.OverrideOutput(gpioPinNum)
}

// Note: in PWM modes, OCRA/OCRB do not exhibit a newly written value until the count overflows

// TODO: in PC-PWM mode, an OCRx bit may transition without a compare match for two reasons (see datasheet page 98)

func (t *Timer) Run(ticks uint) {
    var ticksIncr uint

    switch t.controlB & 0x07 {
    case 0: // disabled
        t.excessTicks = 0
        return
    case 1: // divider = 1
        ticksIncr = 1
    case 2: // divider = 8
        ticksIncr = 8
    case 3: // divider = 64
        ticksIncr = 64
    case 4: // divider = 256
        ticksIncr = 256
    case 5: // divider = 1024
        ticksIncr = 1024
    case 6, 7:
        panic("(*Timer).Run: external clock sources not implemented")
    }
    ticksExecuted := t.excessTicks

    for ticksExecuted < ticks {
        t.Tick()
        ticksExecuted += ticksIncr
    }

    t.excessTicks = ticksExecuted - ticks
}

// Tick the timer.
func (t *Timer) Tick() {
    // Handle match-compare interrupts
    if t.inhibitCompareMatch {
        t.inhibitCompareMatch = false
    } else {
        if t.count == t.compareValA {
            t.setOCF(0)
        }
        if t.count == t.compareValB {
            t.setOCF(1)
        }
    }

    // Prepare to tick counter
    switch t.getWGM() {
    case 0: // Normal
        t.tickNormalMode()
    case 1: // Phase-correct PWM (TOP = 0xFF)
        t.tickPCPWMMode(0xFF)
    case 2: // Clear timer on compare
        t.tickCTCMode()
    case 3: // Fast PWM (TOP = 0xFF)
        t.tickFastPWMMode(0xFF)
    case 5: // Phase-correct PWM (TOP = OCRA)
        t.tickPCPWMMode(t.compareValA)
    case 7: // Fast PWM (TOP = OCRA)
        t.tickPCPWMMode(t.compareValA)
    }

    // Actually tick the counter
    if t.downwards {
        t.count--
    } else {
        t.count++
    }

    // Trigger interrupts, if possible
    if t.em != nil && t.em.InterruptsEnabled() {
        intName := ""
        if t.interruptFlags & 0x01 != 0 && t.interruptMask & 0x01 != 0 {
            t.interruptFlags &= 0xFE
            intName = fmt.Sprintf("TIMER%d_OVF", t.digit)
        } else if t.interruptFlags & 0x02 != 0 && t.interruptMask & 0x02 != 0 {
            t.interruptFlags &= 0xFD
            intName = fmt.Sprintf("TIMER%d_COMPA", t.digit)
        } else if t.interruptFlags & 0x04 != 0 && t.interruptMask & 0x04 != 0 {
            t.interruptFlags &= 0xFB
            intName = fmt.Sprintf("TIMER%d_COMPB", t.digit)
        }

        if intName != "" {
            ok := t.em.InterruptByName(intName)
            if !ok && t.logging {
                log.Printf("[avr/hardware/timer:(*Timer).Tick] failed to trigger interrupt %s", intName)
            }
        }
    }
}

// Tick the timer in Normal mode.
func (t *Timer) tickNormalMode() {
    t.downwards = false
    if t.count == 0xFF { // Overflow
        t.setTOV()
    }

    t.checkOCPinNormalMode(0, t.compareValA)
    t.checkOCPinNormalMode(1, t.compareValB)
}

// Check for output-compare in normal mode.
func (t *Timer) checkOCPinNormalMode(ocPinNum uint, compareVal uint8) {
    if t.count == compareVal {
        t.changeOCPinNormalMode(ocPinNum)
    }
}

func (t *Timer) changeOCPinNormalMode(ocPinNum uint) {
    // Get COMxy bits
    switch t.getCOM(ocPinNum) {
    case 0: // OCy disabled
        // do nothing
    case 1: // toggle OCy
        t.toggleOCPin(ocPinNum)
    case 2: // clear OCy
        t.clearOCPin(ocPinNum)
    case 3: // set OCy
        t.setOCPin(ocPinNum)
    }
}

// Tick the timer in phase-corrected PWM mode.
func (t *Timer) tickPCPWMMode(top uint8) {
    if t.downwards {
        if t.count == 0x00 { // Reached BOTTOM
            t.downwards = false // Begin counting upwards
            t.setTOV()
        }
    } else {
        if t.count == top { // Reached TOP
            t.downwards = true // Begin counting downwards
        }
    }

    t.checkOCPinPCPWMMode(0, t.compareValA)
    t.checkOCPinPCPWMMode(1, t.compareValB)
}

// TODO: there is a special case in the OC pin checking for both PWM modes when OCRy == TOP and COMxy1 is set (see datasheet page 101)

// Check for output-compare in phase-corrected PWM mode.
func (t *Timer) checkOCPinPCPWMMode(ocPinNum uint, compareVal uint8) {
    if t.count == compareVal {
        // Get COMxy bits
        switch t.getCOM(ocPinNum) {
        case 0: // OCy disabled
            // do nothing
        case 1: // Toggle OCy (only on OC pin 0 with WGM2 bit set)
            if ocPinNum == 0 && (t.controlB & 0x80) != 0 {
                t.toggleOCPin(ocPinNum)
            }
        case 2: // Clear OCy if counting upwards or set OCy if counting downwards
            if t.downwards {
                t.setOCPin(ocPinNum)
            } else {
                t.clearOCPin(ocPinNum)
            }
        case 3: // Set OCy if counting upwards or clear OCy if counting downwards
            if t.downwards {
                t.clearOCPin(ocPinNum)
            } else {
                t.setOCPin(ocPinNum)
            }
        }
    }
}

// Tick the timer in clear-timer-on-compare mode.
func (t *Timer) tickCTCMode() {
    t.downwards = false

    if t.count == 0xFF { // Overflow
        t.setTOV()
    }

    if t.count == t.compareValA {
        // this tick should set counter to 0
        t.count = 0xFF
    }

    t.checkOCPinCTCMode(0, t.compareValA)
    t.checkOCPinCTCMode(1, t.compareValB)
}

// Check for output-compare in normal mode.
func (t *Timer) checkOCPinCTCMode(ocPinNum uint, compareVal uint8) {
    if t.count == compareVal {
        t.changeOCPinCTCMode(ocPinNum)
    }
}

func (t *Timer) changeOCPinCTCMode(ocPinNum uint) {
    // Get COMxy bits
    switch t.getCOM(ocPinNum) {
    case 0: // OCy disabled
        // do nothing
    case 1: // toggle OCy
        t.toggleOCPin(ocPinNum)
    case 2: // clear OCy
        t.clearOCPin(ocPinNum)
    case 3: // set OCy
        t.setOCPin(ocPinNum)
    }
}

// Tick the timer in fast PWM mode.
func (t *Timer) tickFastPWMMode(top uint8) {
    t.downwards = false

    if t.count == top {
        // this tick should set counter to 0
        t.count = 0xFF
        t.setTOV()
    }

    t.checkOCPinFastPWMMode(0, t.compareValA)
    t.checkOCPinFastPWMMode(1, t.compareValB)
}

// Check for output-compare in fast PWM mode.
func (t *Timer) checkOCPinFastPWMMode(ocPinNum uint, compareVal uint8) {
    // BOTTOM
    if t.count == 0x00 {
        // Get COMxy bits
        switch t.getCOM(ocPinNum) {
        case 0: // OCy disabled
            // do nothing
        case 1: // Toggle OCy on compare match (only on OC pin 0 with WGM2 bit set)
            // do nothing
        case 2: // Clear OCy on compare match, set OCy at BOTTOM
            t.setOCPin(ocPinNum)
        case 3: // Set OCy on compare match, clear OCy at BOTTOM
            t.clearOCPin(ocPinNum)
        }
    }

    // Compare match
    if t.count == compareVal {
        // Get COMxy bits
        switch t.getCOM(ocPinNum) {
        case 0: // OCy disabled
            // do nothing
        case 1: // Toggle OCy on compare match (only on OC pin 0 with WGM2 bit set)
            if ocPinNum == 0 && (t.controlB & 0x80) != 0 {
                t.toggleOCPin(ocPinNum)
            }
        case 2: // Clear OCy on compare match, set OCy at BOTTOM
            t.clearOCPin(ocPinNum)
        case 3: // Set OCy on compare match, clear OCy at BOTTOM
            t.setOCPin(ocPinNum)
        }
    }
}

// Force an output compare by calling the appropriate changeOCPin method.
func (t *Timer) forceOutputCompare(ocPinNum uint) {
    switch t.getWGM() {
    case 0: // Normal
        t.changeOCPinNormalMode(ocPinNum)
    case 2: // Clear timer on compare
        t.changeOCPinCTCMode(ocPinNum)
    default:
        // Force output compare has no effect in non-PWM modes.
    }
}

// Toggle an output-compare pin.
func (t *Timer) toggleOCPin(ocPinNum uint) {
    t.ocPinStates[ocPinNum] = !t.ocPinStates[ocPinNum]
    t.updateOCPin(ocPinNum)
}

// Set an output-compare pin to low.
func (t *Timer) clearOCPin(ocPinNum uint) {
    if t.ocPinStates[ocPinNum] {
        t.ocPinStates[ocPinNum] = false
        t.updateOCPin(ocPinNum)
    }
}

// Set an output-compare pin to high.
func (t *Timer) setOCPin(ocPinNum uint) {
    if !t.ocPinStates[ocPinNum] {
        t.ocPinStates[ocPinNum] = true
        t.updateOCPin(ocPinNum)
    }
}

// Push the new status of an output-compare pin to the GPIO layer.
func (t *Timer) updateOCPin(ocPinNum uint) {
    callback := t.ocPinCallbacks[ocPinNum]
    if callback != nil {
        callback(t.ocPinStates[ocPinNum])
    }
}

// Set an output compare match (OCFy) flag.
func (t *Timer) setOCF(ocPinNum uint) {
    if ocPinNum == 0 { // A
        t.interruptFlags |= 0x02
    } else { // B
        t.interruptFlags |= 0x04
    }
}

// Set the timer overflow (TOV) flag.
func (t *Timer) setTOV() {
    t.interruptFlags |= 0x01
}

// Get the WGM (waveform generation mode) bits
func (t *Timer) getWGM() (wgm uint8) {
    wgmA := t.controlA & 0x03 // bits 1 and 0
    wgmB := (t.controlB & 0x08) >> 1 // bit 3 (shifted to bit 2)
    return wgmB | wgmA
}

// Get the COM (compare output mode) bits for a given OC pin number.
func (t *Timer) getCOM(ocPinNum uint) (com uint8) {
    shiftAmt := 6 - 2*ocPinNum // 0 => 6, 1 => 4
    return (t.controlA >> shiftAmt) & 0x03
}
<|endoftext|>