<commit_before>// Copyright 2012-2018, Rolf Veen and contributors.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ogdl

import (
	"bytes"
	"reflect"
	"strings"
)

// Graph is a node with outgoing pointers to other Graph objects.
// It is implemented as a named list.
type Graph struct {
	This interface{}
	Out  []*Graph
}

// New returns a pointer to Graph initialized to the object given.
func New(n interface{}) *Graph {
	return &Graph{n, nil}
}

// Len returns the number of subnodes (outgoing edges, out degree) of this node.
func (g *Graph) Len() int {
	if g == nil {
		return -1
	}
	return len(g.Out)
}

// ThisType returns the name of the native type contained in the current node.
func (g *Graph) ThisType() string {
	return reflect.TypeOf(g.This).String()
}

// Equals returns true if the given graph and the receiver graph are equal.
func (g *Graph) Equals(c *Graph) bool {

	if c.This != g.This {
		return false
	}
	if g.Len() != c.Len() {
		return false
	}

	for i := 0; i < g.Len(); i++ {
		if !g.Out[i].Equals(c.Out[i]) {
			return false
		}
	}
	return true
}

// Add adds a subnode to the current node.
func (g *Graph) Add(n interface{}) *Graph {

	if g == nil {
		return nil
	}

	if node, ok := n.(*Graph); ok && node != nil {
		g.Out = append(g.Out, node)
		return node
	}

	gg := Graph{n, nil}
	g.Out = append(g.Out, &gg)
	return &gg
}

// Add adds a subnode to the current node.
func (g *Graph) addNodes(n interface{}) *Graph {

	if g == nil {
		return nil
	}

	if node, ok := n.(*Graph); ok && node != nil {
		g.Out = append(g.Out, node.Out...)
		return node
	}

	gg := Graph{n, nil}
	g.Out = append(g.Out, &gg)
	return &gg
}

// AddNodes adds subnodes of the given Graph to the current node.
func (g *Graph) AddNodes(g2 *Graph) *Graph {

	if g == nil {
		return nil
	}

	if g2 != nil {
		g.Out = append(g.Out, g2.Out...)
	}
	return g
}

// addEqualNodes adds subnodes of the given Graph to the current node,
// if their content equals the given key. Optionally recurse into subnodes
// of the receiver graph.
func (g *Graph) addEqualNodes(g2 *Graph, key string, recurse bool) *Graph {
	if g2 != nil {
		for _, n := range g2.Out {
			if key == _string(n.This) {
				g.AddNodes(n)
			}
			if recurse {
				g.addEqualNodes(n, key, true)
			}
		}
	}
	return g
}

// Copy adds a copy of the graph given to the current graph.
//
// Warning (from the Go faq): Copying an interface value makes a copy of the
// thing stored in the interface value. If the interface value holds a struct,
// copying the interface value makes a copy of the struct. If the interface
// value holds a pointer, copying the interface value makes a copy of the
// pointer, but not the data it points to.
func (g *Graph) Copy(c *Graph) {
	if c == nil {
		return
	}
	for _, n := range c.Out {
		nn := g.Add(n.This)
		nn.Copy(n)
	}
}

// Clone returns a copy of the current graph.
//
// Warning (from the Go faq): Copying an interface value makes a copy of the
// thing stored in the interface value. If the interface value holds a struct,
// copying the interface value makes a copy of the struct. If the interface
// value holds a pointer, copying the interface value makes a copy of the
// pointer, but not the data it points to.
func (g *Graph) Clone() *Graph {
	if g == nil {
		return nil
	}

	c := New(nil)
	c.This = g.This

	for _, n := range g.Out {
		c.Out = append(c.Out, n.Clone())
	}
	return c
}

// Node returns the first subnode whose string value is equal to the given string.
// It returns nil if not found.
func (g *Graph) Node(s string) *Graph {
	if g == nil || g.Out == nil {
		return nil
	}
	for _, node := range g.Out {
		if s == _string(node.This) {
			return node
		}
	}

	return nil
}

// Create returns the first subnode whose string value is equal to the given string,
// with its subnodes deleted. If not found, the node is created and returned.
func (g *Graph) Create(s string) *Graph {
	n := g.Node(s)
	if n == nil {
		return g.Add(s)
	}
	n.Clear()
	return n
}

// GetAt returns a subnode by index, or nil if the index is out of range.
func (g *Graph) GetAt(i int) *Graph {
	if i >= len(g.Out) || i < 0 {
		return nil
	}

	return g.Out[i]
}

// Get recurses a Graph following a given path and returns the result.
//
// This function returns a *Graph in any condition. When there is nothing to
// return, a nil Graph is returned. This behavior is designed so that
// the next function in a chain never gets an invalid receiver, avoiding null
// pointer errors.
//
// OGDL Path:
// elements are separated by '.' or [] or {}
// index := [N]
// selector := {N}
// tokens can be quoted
//
func (g *Graph) Get(s string) *Graph {
	if g == nil {
		return nil
	}
	path := NewPath(s)
	g, _ = g.getPath(path)
	return g
}

// Delete removes all subnodes with the given content
func (g *Graph) Delete(n interface{}) {

	if g == nil {
		return
	}
	for i := 0; i < g.Len(); i++ {
		if g.Out[i].This == n {
			if i < (g.Len() - 1) {
				g.Out = append(g.Out[:i], g.Out[i+1:]...)
			} else {
				g.Out = g.Out[:i]
			}
			i--
		}
	}
}

// Clear removes all subnodes
func (g *Graph) Clear() {

	if g == nil || g.Out == nil {
		return
	}
	g.Out = nil
}

// DeleteAt removes a subnode by index
func (g *Graph) DeleteAt(i int) {
	if i < 0 || i >= g.Len() {
		return
	}
	if i < (g.Len() - 1) {
		g.Out = append(g.Out[:i], g.Out[i+1:]...)
	} else {
		g.Out = g.Out[:i]
	}
}

// Set sets the first occurrence of the given path to the value given.
func (g *Graph) Set(s string, val interface{}) *Graph {
	if g == nil {
		return nil
	}

	// Parse the input string into a Path graph.
	path := NewPath(s)

	if path == nil {
		return nil
	}
	return g.set(path, val)
}

// TODO: Clean this code:
func (g *Graph) set(path *Graph, val interface{}) *Graph {

	node := g

	i := 0
	var prev *Graph

	for ; i < len(path.Out); i++ {

		prev = node

		elem := path.Out[i]
		if elem.ThisString() == TypeIndex {
			i := elem.Int64()
			if len(node.Out) <= int(i) {
				o := make([]*Graph, i+1)
				for j, n := range node.Out {
					o[j] = n
				}
				node.Out = o
			}
			node.Out[i] = New(val)
			return node.Out[i]
		}
		node = node.Node(elem.ThisString())

		if node == nil {
			break
		}
	}

	if node == nil {
		node = prev

		for ; i < len(path.Out); i++ {
			elem := path.Out[i]

			if elem.ThisString() == TypeIndex {
				i := elem.Int64()
				if len(node.Out) <= int(i) {
					o := make([]*Graph, i+1)
					for j, n := range node.Out {
						o[j] = n
					}
					node.Out = o
				}
				node.Out[i] = New(val)
				return node.Out[i]
			}

			node = node.Add(elem.This)
		}
	}

	node.Out = nil

	return node.addNodes(val)
}

// Text is the OGDL text emitter. It converts a Graph into OGDL text.
//
// Strings are quoted if they contain spaces, newlines or special
// characters. Null elements are not printed, and act as transparent nodes.
func (g *Graph) Text() string {
	if g == nil {
		return ""
	}

	buffer := &bytes.Buffer{}

	// Do not print the 'root' node
	for _, node := range g.Out {
		node._text(0, buffer, false)
	}

	// remove trailing \n

	s := buffer.String()

	if len(s) == 0 {
		return ""
	}

	if s[len(s)-1] == '\n' {
		s = s[0 : len(s)-1]
	}

	// unquote

	if s[0] == '"' {
		s = s[1 : len(s)-1]
		// But then also replace \"
		s = strings.Replace(s, "\\\"", "\"", -1)
	}

	return s
}

// Show prints the Graph as text including this (the top) node.
func (g *Graph) Show() string {
	if g == nil {
		return ""
	}

	buffer := &bytes.Buffer{}

	g._text(0, buffer, true)

	// remove trailing \n

	s := buffer.String()

	if len(s) == 0 {
		return ""
	}

	if s[len(s)-1] == '\n' {
		s = s[0 : len(s)-1]
	}

	// unquote

	if s[0] == '"' {
		s = s[1 : len(s)-1]
		// But then also replace \"
		s = strings.Replace(s, "\\\"", "\"", -1)
	}

	return s
}

// _text is the private, lower level, implementation of Text().
// It takes two parameters, the level and a buffer to which the
// result is printed.
func (g *Graph) _text(n int, buffer *bytes.Buffer, show bool) {

	sp := ""
	for i := 0; i < n; i++ {
		sp += "  "
	}

	/*
	   When printing strings with newlines, there are two possibilities:
	   block or quoted. Block is cleaner, but limited to leaf nodes. If the node
	   is not leaf (it has subnodes), then we are forced to print a multiline
	   quoted string.

	   If the string has no newlines but spaces or special characters, then the
	   same rule applies: quote those nodes that are non-leaf, print a block
	   otherways.

	   [!] Cannot print blocks at level 0? Or can we?
	*/

	s := "_"
	if g != nil {
		s = _string(g.This)
	}

	if strings.ContainsAny(s, "\n\r \t'\",()") {

		// print quoted, but not at level 0
		// Do not convert " to \" below if level==0 !
		if n > 0 {
			buffer.WriteString(sp) /* [:len(sp)-1]) */
			buffer.WriteByte('"')
		}

		var c, cp byte

		cp = 0

		for i := 0; i < len(s); i++ {
			c = s[i] // byte, not rune
			if c == 13 {
				continue // ignore CR's
			} else if c == 10 {
				buffer.WriteByte('\n')
				buffer.WriteString(sp)
			} else if c == '"' && n > 0 {
				if cp != '\\' {
					buffer.WriteString("\\\"")
				}
			} else {
				buffer.WriteByte(c)
			}
			cp = c
		}

		if n > 0 {
			buffer.WriteString("\"")
		}
		buffer.WriteString("\n")
	} else {
		if len(s) == 0 && !show {
			n--
		} else {
			if len(s) == 0 && show {
				s = "_"
			}
			buffer.WriteString(sp)
			buffer.WriteString(s)
			buffer.WriteByte('\n')
		}
	}

	if g != nil {
		for i := 0; i < len(g.Out); i++ {
			node := g.Out[i]
			node._text(n+1, buffer, show)
		}
	}
}

// Substitute traverses the graph substituting all nodes with content
// equal to s by v.
func (g *Graph) Substitute(s string, v interface{}) {
	if g == nil || g.Out == nil {
		return
	}
	for _, n := range g.Out {
		if _string(n.This) == s {
			n.This = v
		}
		n.Substitute(s, v)
	}

}
<commit_msg>added NodeOrNew, name may change<commit_after>// Copyright 2012-2018, Rolf Veen and contributors.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ogdl

import (
	"bytes"
	"reflect"
	"strings"
)

// Graph is a node with outgoing pointers to other Graph objects.
// It is implemented as a named list.
type Graph struct {
	This interface{}
	Out  []*Graph
}

// New returns a pointer to Graph initialized to the object given.
func New(n interface{}) *Graph {
	return &Graph{n, nil}
}

// Len returns the number of subnodes (outgoing edges, out degree) of this node.
func (g *Graph) Len() int {
	if g == nil {
		return -1
	}
	return len(g.Out)
}

// ThisType returns the name of the native type contained in the current node.
func (g *Graph) ThisType() string {
	return reflect.TypeOf(g.This).String()
}

// Equals returns true if the given graph and the receiver graph are equal.
func (g *Graph) Equals(c *Graph) bool {

	if c.This != g.This {
		return false
	}
	if g.Len() != c.Len() {
		return false
	}

	for i := 0; i < g.Len(); i++ {
		if !g.Out[i].Equals(c.Out[i]) {
			return false
		}
	}
	return true
}

// Add adds a subnode to the current node.
func (g *Graph) Add(n interface{}) *Graph {

	if g == nil {
		return nil
	}

	if node, ok := n.(*Graph); ok && node != nil {
		g.Out = append(g.Out, node)
		return node
	}

	gg := Graph{n, nil}
	g.Out = append(g.Out, &gg)
	return &gg
}

// Add adds a subnode to the current node.
func (g *Graph) addNodes(n interface{}) *Graph {

	if g == nil {
		return nil
	}

	if node, ok := n.(*Graph); ok && node != nil {
		g.Out = append(g.Out, node.Out...)
		return node
	}

	gg := Graph{n, nil}
	g.Out = append(g.Out, &gg)
	return &gg
}

// AddNodes adds subnodes of the given Graph to the current node.
func (g *Graph) AddNodes(g2 *Graph) *Graph {

	if g == nil {
		return nil
	}

	if g2 != nil {
		g.Out = append(g.Out, g2.Out...)
	}
	return g
}

// addEqualNodes adds subnodes of the given Graph to the current node,
// if their content equals the given key. Optionally recurse into subnodes
// of the receiver graph.
func (g *Graph) addEqualNodes(g2 *Graph, key string, recurse bool) *Graph {
	if g2 != nil {
		for _, n := range g2.Out {
			if key == _string(n.This) {
				g.AddNodes(n)
			}
			if recurse {
				g.addEqualNodes(n, key, true)
			}
		}
	}
	return g
}

// Copy adds a copy of the graph given to the current graph.
//
// Warning (from the Go faq): Copying an interface value makes a copy of the
// thing stored in the interface value. If the interface value holds a struct,
// copying the interface value makes a copy of the struct. If the interface
// value holds a pointer, copying the interface value makes a copy of the
// pointer, but not the data it points to.
func (g *Graph) Copy(c *Graph) {
	if c == nil {
		return
	}
	for _, n := range c.Out {
		nn := g.Add(n.This)
		nn.Copy(n)
	}
}

// Clone returns a copy of the current graph.
//
// Warning (from the Go faq): Copying an interface value makes a copy of the
// thing stored in the interface value. If the interface value holds a struct,
// copying the interface value makes a copy of the struct. If the interface
// value holds a pointer, copying the interface value makes a copy of the
// pointer, but not the data it points to.
func (g *Graph) Clone() *Graph {
	if g == nil {
		return nil
	}

	c := New(nil)
	c.This = g.This

	for _, n := range g.Out {
		c.Out = append(c.Out, n.Clone())
	}
	return c
}

// Node returns the first subnode whose string value is equal to the given string.
// It returns nil if not found.
func (g *Graph) Node(s string) *Graph {
	if g == nil || g.Out == nil {
		return nil
	}
	for _, node := range g.Out {
		if s == _string(node.This) {
			return node
		}
	}

	return nil
}

// NodeOrNew returns the first subnode whose string value is equal to the given string.
// It creates the node if not found.
func (g *Graph) NodeOrNew(s string) *Graph {
	if g == nil || g.Out == nil {
		return nil
	}
	for _, node := range g.Out {
		if s == _string(node.This) {
			return node
		}
	}

	return g.Add(s)
}

// Create returns the first subnode whose string value is equal to the given string,
// with its subnodes deleted. If not found, the node is created and returned.
func (g *Graph) Create(s string) *Graph {
	n := g.Node(s)
	if n == nil {
		return g.Add(s)
	}
	n.Clear()
	return n
}

// GetAt returns a subnode by index, or nil if the index is out of range.
func (g *Graph) GetAt(i int) *Graph {
	if i >= len(g.Out) || i < 0 {
		return nil
	}

	return g.Out[i]
}

// Get recurses a Graph following a given path and returns the result.
//
// This function returns a *Graph in any condition. When there is nothing to
// return, a nil Graph is returned. This behavior is designed so that
// the next function in a chain never gets an invalid receiver, avoiding null
// pointer errors.
//
// OGDL Path:
// elements are separated by '.' or [] or {}
// index := [N]
// selector := {N}
// tokens can be quoted
//
func (g *Graph) Get(s string) *Graph {
	if g == nil {
		return nil
	}
	path := NewPath(s)
	g, _ = g.getPath(path)
	return g
}

// Delete removes all subnodes with the given content
func (g *Graph) Delete(n interface{}) {

	if g == nil {
		return
	}
	for i := 0; i < g.Len(); i++ {
		if g.Out[i].This == n {
			if i < (g.Len() - 1) {
				g.Out = append(g.Out[:i], g.Out[i+1:]...)
			} else {
				g.Out = g.Out[:i]
			}
			i--
		}
	}
}

// Clear removes all subnodes
func (g *Graph) Clear() {

	if g == nil || g.Out == nil {
		return
	}
	g.Out = nil
}

// DeleteAt removes a subnode by index
func (g *Graph) DeleteAt(i int) {
	if i < 0 || i >= g.Len() {
		return
	}
	if i < (g.Len() - 1) {
		g.Out = append(g.Out[:i], g.Out[i+1:]...)
	} else {
		g.Out = g.Out[:i]
	}
}

// Set sets the first occurrence of the given path to the value given.
func (g *Graph) Set(s string, val interface{}) *Graph {
	if g == nil {
		return nil
	}

	// Parse the input string into a Path graph.
	path := NewPath(s)

	if path == nil {
		return nil
	}
	return g.set(path, val)
}

// TODO: Clean this code:
func (g *Graph) set(path *Graph, val interface{}) *Graph {

	node := g

	i := 0
	var prev *Graph

	for ; i < len(path.Out); i++ {

		prev = node

		elem := path.Out[i]
		if elem.ThisString() == TypeIndex {
			i := elem.Int64()
			if len(node.Out) <= int(i) {
				o := make([]*Graph, i+1)
				for j, n := range node.Out {
					o[j] = n
				}
				node.Out = o
			}
			node.Out[i] = New(val)
			return node.Out[i]
		}
		node = node.Node(elem.ThisString())

		if node == nil {
			break
		}
	}

	if node == nil {
		node = prev

		for ; i < len(path.Out); i++ {
			elem := path.Out[i]

			if elem.ThisString() == TypeIndex {
				i := elem.Int64()
				if len(node.Out) <= int(i) {
					o := make([]*Graph, i+1)
					for j, n := range node.Out {
						o[j] = n
					}
					node.Out = o
				}
				node.Out[i] = New(val)
				return node.Out[i]
			}

			node = node.Add(elem.This)
		}
	}

	node.Out = nil

	return node.addNodes(val)
}

// Text is the OGDL text emitter. It converts a Graph into OGDL text.
//
// Strings are quoted if they contain spaces, newlines or special
// characters. Null elements are not printed, and act as transparent nodes.
func (g *Graph) Text() string {
	if g == nil {
		return ""
	}

	buffer := &bytes.Buffer{}

	// Do not print the 'root' node
	for _, node := range g.Out {
		node._text(0, buffer, false)
	}

	// remove trailing \n

	s := buffer.String()

	if len(s) == 0 {
		return ""
	}

	if s[len(s)-1] == '\n' {
		s = s[0 : len(s)-1]
	}

	// unquote

	if s[0] == '"' {
		s = s[1 : len(s)-1]
		// But then also replace \"
		s = strings.Replace(s, "\\\"", "\"", -1)
	}

	return s
}

// Show prints the Graph as text including this (the top) node.
func (g *Graph) Show() string {
	if g == nil {
		return ""
	}

	buffer := &bytes.Buffer{}

	g._text(0, buffer, true)

	// remove trailing \n

	s := buffer.String()

	if len(s) == 0 {
		return ""
	}

	if s[len(s)-1] == '\n' {
		s = s[0 : len(s)-1]
	}

	// unquote

	if s[0] == '"' {
		s = s[1 : len(s)-1]
		// But then also replace \"
		s = strings.Replace(s, "\\\"", "\"", -1)
	}

	return s
}

// _text is the private, lower level, implementation of Text().
// It takes two parameters, the level and a buffer to which the
// result is printed.
func (g *Graph) _text(n int, buffer *bytes.Buffer, show bool) {

	sp := ""
	for i := 0; i < n; i++ {
		sp += "  "
	}

	/*
	   When printing strings with newlines, there are two possibilities:
	   block or quoted. Block is cleaner, but limited to leaf nodes. If the node
	   is not leaf (it has subnodes), then we are forced to print a multiline
	   quoted string.

	   If the string has no newlines but spaces or special characters, then the
	   same rule applies: quote those nodes that are non-leaf, print a block
	   otherways.

	   [!] Cannot print blocks at level 0? Or can we?
	*/

	s := "_"
	if g != nil {
		s = _string(g.This)
	}

	if strings.ContainsAny(s, "\n\r \t'\",()") {

		// print quoted, but not at level 0
		// Do not convert " to \" below if level==0 !
		if n > 0 {
			buffer.WriteString(sp) /* [:len(sp)-1]) */
			buffer.WriteByte('"')
		}

		var c, cp byte

		cp = 0

		for i := 0; i < len(s); i++ {
			c = s[i] // byte, not rune
			if c == 13 {
				continue // ignore CR's
			} else if c == 10 {
				buffer.WriteByte('\n')
				buffer.WriteString(sp)
			} else if c == '"' && n > 0 {
				if cp != '\\' {
					buffer.WriteString("\\\"")
				}
			} else {
				buffer.WriteByte(c)
			}
			cp = c
		}

		if n > 0 {
			buffer.WriteString("\"")
		}
		buffer.WriteString("\n")
	} else {
		if len(s) == 0 && !show {
			n--
		} else {
			if len(s) == 0 && show {
				s = "_"
			}
			buffer.WriteString(sp)
			buffer.WriteString(s)
			buffer.WriteByte('\n')
		}
	}

	if g != nil {
		for i := 0; i < len(g.Out); i++ {
			node := g.Out[i]
			node._text(n+1, buffer, show)
		}
	}
}

// Substitute traverses the graph substituting all nodes with content
// equal to s by v.
func (g *Graph) Substitute(s string, v interface{}) {
	if g == nil || g.Out == nil {
		return
	}
	for _, n := range g.Out {
		if _string(n.This) == s {
			n.This = v
		}
		n.Substitute(s, v)
	}

}
<|endoftext|>


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

package modelmanager_test

import (
	"github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/controller/modelmanager"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	_ "github.com/juju/juju/provider/all"
	_ "github.com/juju/juju/provider/azure"
	_ "github.com/juju/juju/provider/dummy"
	_ "github.com/juju/juju/provider/ec2"
	_ "github.com/juju/juju/provider/joyent"
	_ "github.com/juju/juju/provider/maas"
	_ "github.com/juju/juju/provider/openstack"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/tools"
	"github.com/juju/juju/version"
)

type ModelConfigCreatorSuite struct {
	coretesting.BaseSuite
	creator    modelmanager.ModelConfigCreator
	baseConfig *config.Config
}

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

func (s *ModelConfigCreatorSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)
	s.creator = modelmanager.ModelConfigCreator{}
	baseConfig, err := config.New(
		config.UseDefaults,
		coretesting.FakeConfig().Merge(coretesting.Attrs{
			"type":          "fake",
			"restricted":    "area51",
			"agent-version": "2.0.0",
		}),
	)
	c.Assert(err, jc.ErrorIsNil)
	s.baseConfig = baseConfig
	fake.Reset()
}

func (s *ModelConfigCreatorSuite) newModelConfig(attrs map[string]interface{}) (*config.Config, error) {
	return s.creator.NewModelConfig(s.baseConfig, attrs)
}

func (s *ModelConfigCreatorSuite) TestCreateModelValidatesConfig(c *gc.C) {
	newModelUUID := utils.MustNewUUID().String()
	cfg, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":       "new-model",
		"additional": "value",
		"uuid":       newModelUUID,
	}))
	c.Assert(err, jc.ErrorIsNil)
	expected := s.baseConfig.AllAttrs()
	expected["name"] = "new-model"
	expected["additional"] = "value"
	expected["uuid"] = newModelUUID
	c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)

	fake.Stub.CheckCallNames(c,
		"RestrictedConfigAttributes",
		"PrepareForCreateEnvironment",
		"Validate",
	)
	validateCall := fake.Stub.Calls()[2]
	c.Assert(validateCall.Args, gc.HasLen, 2)
	c.Assert(validateCall.Args[0], gc.Equals, cfg)
	c.Assert(validateCall.Args[1], gc.IsNil)
}

func (s *ModelConfigCreatorSuite) TestCreateModelBadConfig(c *gc.C) {
	for i, test := range []struct {
		key      string
		value    interface{}
		errMatch string
	}{{
		key:      "type",
		value:    "dummy",
		errMatch: `specified type "dummy" does not match controller "fake"`,
	}, {
		key:      "state-port",
		value:    9876,
		errMatch: `specified state-port "9876" does not match controller "19034"`,
	}, {
		key:      "restricted",
		value:    51,
		errMatch: `specified restricted "51" does not match controller "area51"`,
	}} {
		c.Logf("%d: %s", i, test.key)
		_, err := s.newModelConfig(coretesting.Attrs(
			s.baseConfig.AllAttrs(),
		).Merge(coretesting.Attrs{
			test.key: test.value,
		}))
		c.Check(err, gc.ErrorMatches, test.errMatch)
	}
}

func (s *ModelConfigCreatorSuite) TestCreateModelSameAgentVersion(c *gc.C) {
	cfg, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name": "new-model",
		"uuid": utils.MustNewUUID().String(),
	}))
	c.Assert(err, jc.ErrorIsNil)

	baseAgentVersion, ok := s.baseConfig.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	agentVersion, ok := cfg.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	c.Assert(agentVersion, gc.Equals, baseAgentVersion)
}

func (s *ModelConfigCreatorSuite) TestCreateModelGreaterAgentVersion(c *gc.C) {
	_, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "2.0.1",
	}))
	c.Assert(err, gc.ErrorMatches,
		"agent-version .* cannot be greater than the controller .*")
}

func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionNoToolsFinder(c *gc.C) {
	_, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "1.9.9",
	}))
	c.Assert(err, gc.ErrorMatches,
		"agent-version does not match base config, and no tools-finder is supplied")
}

func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderFound(c *gc.C) {
	s.creator.FindTools = func(version.Number) (tools.List, error) {
		return tools.List{{ /*contents don't matter, just need a non-empty list*/ }}, nil
	}
	cfg, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "1.9.9",
	}))
	c.Assert(err, jc.ErrorIsNil)
	agentVersion, ok := cfg.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	c.Assert(agentVersion, gc.Equals, version.MustParse("1.9.9"))
}

func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderNotFound(c *gc.C) {
	s.creator.FindTools = func(version.Number) (tools.List, error) {
		return tools.List{}, nil
	}
	_, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "1.9.9",
	}))
	c.Assert(err, gc.ErrorMatches, "no tools found for version .*")
}

type RestrictedProviderFieldsSuite struct {
	coretesting.BaseSuite
}

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

func (*RestrictedProviderFieldsSuite) TestRestrictedProviderFields(c *gc.C) {
	for i, test := range []struct {
		provider string
		expected []string
	}{{
		provider: "azure",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"subscription-id", "tenant-id", "application-id", "application-password",
			"location", "controller-resource-group", "storage-account-type",
		},
	}, {
		provider: "dummy",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
		},
	}, {
		provider: "joyent",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
		},
	}, {
		provider: "maas",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"maas-server",
		},
	}, {
		provider: "openstack",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"region", "auth-url", "auth-mode",
		},
	}, {
		provider: "ec2",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"region",
		},
	}} {
		c.Logf("%d: %s provider", i, test.provider)
		fields, err := modelmanager.RestrictedProviderFields(test.provider)
		c.Check(err, jc.ErrorIsNil)
		c.Check(fields, jc.SameContents, test.expected)
	}
}

type fakeProvider struct {
	testing.Stub
	environs.EnvironProvider
	restrictedConfigAttributes []string
}

func (p *fakeProvider) Reset() {
	p.Stub.ResetCalls()
	p.restrictedConfigAttributes = []string{"restricted"}
}

func (p *fakeProvider) RestrictedConfigAttributes() []string {
	p.MethodCall(p, "RestrictedConfigAttributes")
	return p.restrictedConfigAttributes
}

func (p *fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
	p.MethodCall(p, "Validate", cfg, old)
	return cfg, p.NextErr()
}

func (p *fakeProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
	p.MethodCall(p, "PrepareForCreateEnvironment", cfg)
	return cfg, p.NextErr()
}

var fake fakeProvider

func init() {
	fake.Reset()
	environs.RegisterProvider("fake", &fake)
}
<commit_msg>Made code compatibile with go fmt 1.2 and 1.5<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package modelmanager_test

import (
	"github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/controller/modelmanager"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	_ "github.com/juju/juju/provider/all"
	_ "github.com/juju/juju/provider/azure"
	_ "github.com/juju/juju/provider/dummy"
	_ "github.com/juju/juju/provider/ec2"
	_ "github.com/juju/juju/provider/joyent"
	_ "github.com/juju/juju/provider/maas"
	_ "github.com/juju/juju/provider/openstack"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/tools"
	"github.com/juju/juju/version"
)

type ModelConfigCreatorSuite struct {
	coretesting.BaseSuite
	creator    modelmanager.ModelConfigCreator
	baseConfig *config.Config
}

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

func (s *ModelConfigCreatorSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)
	s.creator = modelmanager.ModelConfigCreator{}
	baseConfig, err := config.New(
		config.UseDefaults,
		coretesting.FakeConfig().Merge(coretesting.Attrs{
			"type":          "fake",
			"restricted":    "area51",
			"agent-version": "2.0.0",
		}),
	)
	c.Assert(err, jc.ErrorIsNil)
	s.baseConfig = baseConfig
	fake.Reset()
}

func (s *ModelConfigCreatorSuite) newModelConfig(attrs map[string]interface{}) (*config.Config, error) {
	return s.creator.NewModelConfig(s.baseConfig, attrs)
}

func (s *ModelConfigCreatorSuite) TestCreateModelValidatesConfig(c *gc.C) {
	newModelUUID := utils.MustNewUUID().String()
	cfg, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":       "new-model",
		"additional": "value",
		"uuid":       newModelUUID,
	}))
	c.Assert(err, jc.ErrorIsNil)
	expected := s.baseConfig.AllAttrs()
	expected["name"] = "new-model"
	expected["additional"] = "value"
	expected["uuid"] = newModelUUID
	c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)

	fake.Stub.CheckCallNames(c,
		"RestrictedConfigAttributes",
		"PrepareForCreateEnvironment",
		"Validate",
	)
	validateCall := fake.Stub.Calls()[2]
	c.Assert(validateCall.Args, gc.HasLen, 2)
	c.Assert(validateCall.Args[0], gc.Equals, cfg)
	c.Assert(validateCall.Args[1], gc.IsNil)
}

func (s *ModelConfigCreatorSuite) TestCreateModelBadConfig(c *gc.C) {
	for i, test := range []struct {
		key      string
		value    interface{}
		errMatch string
	}{{
		key:      "type",
		value:    "dummy",
		errMatch: `specified type "dummy" does not match controller "fake"`,
	}, {
		key:      "state-port",
		value:    9876,
		errMatch: `specified state-port "9876" does not match controller "19034"`,
	}, {
		key:      "restricted",
		value:    51,
		errMatch: `specified restricted "51" does not match controller "area51"`,
	}} {
		c.Logf("%d: %s", i, test.key)
		_, err := s.newModelConfig(coretesting.Attrs(
			s.baseConfig.AllAttrs(),
		).Merge(coretesting.Attrs{
			test.key: test.value,
		}))
		c.Check(err, gc.ErrorMatches, test.errMatch)
	}
}

func (s *ModelConfigCreatorSuite) TestCreateModelSameAgentVersion(c *gc.C) {
	cfg, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name": "new-model",
		"uuid": utils.MustNewUUID().String(),
	}))
	c.Assert(err, jc.ErrorIsNil)

	baseAgentVersion, ok := s.baseConfig.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	agentVersion, ok := cfg.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	c.Assert(agentVersion, gc.Equals, baseAgentVersion)
}

func (s *ModelConfigCreatorSuite) TestCreateModelGreaterAgentVersion(c *gc.C) {
	_, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "2.0.1",
	}))
	c.Assert(err, gc.ErrorMatches,
		"agent-version .* cannot be greater than the controller .*")
}

func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionNoToolsFinder(c *gc.C) {
	_, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "1.9.9",
	}))
	c.Assert(err, gc.ErrorMatches,
		"agent-version does not match base config, and no tools-finder is supplied")
}

func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderFound(c *gc.C) {
	s.creator.FindTools = func(version.Number) (tools.List, error) {
		return tools.List{
			{}, //contents don't matter, just need a non-empty list
		}, nil
	}
	cfg, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "1.9.9",
	}))
	c.Assert(err, jc.ErrorIsNil)
	agentVersion, ok := cfg.AgentVersion()
	c.Assert(ok, jc.IsTrue)
	c.Assert(agentVersion, gc.Equals, version.MustParse("1.9.9"))
}

func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderNotFound(c *gc.C) {
	s.creator.FindTools = func(version.Number) (tools.List, error) {
		return tools.List{}, nil
	}
	_, err := s.newModelConfig(coretesting.Attrs(
		s.baseConfig.AllAttrs(),
	).Merge(coretesting.Attrs{
		"name":          "new-model",
		"uuid":          utils.MustNewUUID().String(),
		"agent-version": "1.9.9",
	}))
	c.Assert(err, gc.ErrorMatches, "no tools found for version .*")
}

type RestrictedProviderFieldsSuite struct {
	coretesting.BaseSuite
}

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

func (*RestrictedProviderFieldsSuite) TestRestrictedProviderFields(c *gc.C) {
	for i, test := range []struct {
		provider string
		expected []string
	}{{
		provider: "azure",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"subscription-id", "tenant-id", "application-id", "application-password",
			"location", "controller-resource-group", "storage-account-type",
		},
	}, {
		provider: "dummy",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
		},
	}, {
		provider: "joyent",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
		},
	}, {
		provider: "maas",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"maas-server",
		},
	}, {
		provider: "openstack",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"region", "auth-url", "auth-mode",
		},
	}, {
		provider: "ec2",
		expected: []string{
			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
			"region",
		},
	}} {
		c.Logf("%d: %s provider", i, test.provider)
		fields, err := modelmanager.RestrictedProviderFields(test.provider)
		c.Check(err, jc.ErrorIsNil)
		c.Check(fields, jc.SameContents, test.expected)
	}
}

type fakeProvider struct {
	testing.Stub
	environs.EnvironProvider
	restrictedConfigAttributes []string
}

func (p *fakeProvider) Reset() {
	p.Stub.ResetCalls()
	p.restrictedConfigAttributes = []string{"restricted"}
}

func (p *fakeProvider) RestrictedConfigAttributes() []string {
	p.MethodCall(p, "RestrictedConfigAttributes")
	return p.restrictedConfigAttributes
}

func (p *fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
	p.MethodCall(p, "Validate", cfg, old)
	return cfg, p.NextErr()
}

func (p *fakeProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
	p.MethodCall(p, "PrepareForCreateEnvironment", cfg)
	return cfg, p.NextErr()
}

var fake fakeProvider

func init() {
	fake.Reset()
	environs.RegisterProvider("fake", &fake)
}
<|endoftext|>


<commit_before>// Copyright 2012 tsuru 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 main

import (
	"errors"
	"fmt"
	"github.com/fsouza/gogit/git"
	"regexp"
)

// AppGuesser is used to guess the name of an app based in a file path.
type AppGuesser interface {
	GuessName(path string) (string, error)
}

// GitGuesser uses git to guess the name of the app.
//
// It reads the "tsuru" remote from git config file. If the remote does not
// exist, or does not match the tsuru pattern (git@<something>:<app-name>.git),
// GuessName will return an error.
type GitGuesser struct{}

func (g GitGuesser) GuessName(path string) (string, error) {
	repoPath, err := git.DiscoverRepositoryPath(path)
	if err != nil {
		return "", fmt.Errorf("Git repository not found: %s.", err)
	}
	repo, err := git.OpenRepository(repoPath)
	if err != nil {
		return "", err
	}
	defer repo.Free()
	config, err := repo.Config()
	if err != nil {
		return "", err
	}
	remoteUrl, err := config.GetString("remote.tsuru.url")
	if err != nil {
		return "", errors.New("tsuru remote not declared.")
	}
	re := regexp.MustCompile(`^git@.*:(.*)\.git$`)
	matches := re.FindStringSubmatch(remoteUrl)
	if len(matches) < 2 {
		return "", fmt.Errorf(`"tsuru" remote did not match the pattern. Want something like git@<host>:<app-name>.git, got %s`, remoteUrl)
	}
	return matches[1], nil
}
<commit_msg>cmd/tsuru: free config on GitGuesser<commit_after>// Copyright 2012 tsuru 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 main

import (
	"errors"
	"fmt"
	"github.com/fsouza/gogit/git"
	"regexp"
)

// AppGuesser is used to guess the name of an app based in a file path.
type AppGuesser interface {
	GuessName(path string) (string, error)
}

// GitGuesser uses git to guess the name of the app.
//
// It reads the "tsuru" remote from git config file. If the remote does not
// exist, or does not match the tsuru pattern (git@<something>:<app-name>.git),
// GuessName will return an error.
type GitGuesser struct{}

func (g GitGuesser) GuessName(path string) (string, error) {
	repoPath, err := git.DiscoverRepositoryPath(path)
	if err != nil {
		return "", fmt.Errorf("Git repository not found: %s.", err)
	}
	repo, err := git.OpenRepository(repoPath)
	if err != nil {
		return "", err
	}
	defer repo.Free()
	config, err := repo.Config()
	if err != nil {
		return "", err
	}
	defer config.Free()
	remoteUrl, err := config.GetString("remote.tsuru.url")
	if err != nil {
		return "", errors.New("tsuru remote not declared.")
	}
	re := regexp.MustCompile(`^git@.*:(.*)\.git$`)
	matches := re.FindStringSubmatch(remoteUrl)
	if len(matches) < 2 {
		return "", fmt.Errorf(`"tsuru" remote did not match the pattern. Want something like git@<host>:<app-name>.git, got %s`, remoteUrl)
	}
	return matches[1], nil
}
<|endoftext|>


<commit_before>package fit_test

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sync"
	"testing"
	"time"

	"github.com/tormoder/fit"
)

var (
	update  = flag.Bool("update", false, "update .golden output and table for decode test files if their fingerprint differs")
	fupdate = flag.Bool("fupdate", false, "force regeneration of decode test files table")
)

func init() { flag.Parse() }

var (
	activitySmallMu   sync.Mutex
	activitySmallOnce sync.Once
	activitySmallData []byte
)

func activitySmall() []byte {
	activitySmallMu.Lock()
	defer activitySmallMu.Unlock()
	activitySmallOnce.Do(func() {
		asd, err := ioutil.ReadFile(activitySmallPath)
		if err != nil {
			errDesc := fmt.Sprintf("parseActivitySmallData failed: %v", err)
			panic(errDesc)
		}
		activitySmallData = asd
	})
	return activitySmallData
}

var (
	activitySmallPath      = filepath.Join(tdfolder, "me", "activity-small-fenix2-run.fit")
	activityLargePath      = filepath.Join(tdfolder, "me", "activity-large-fenxi2-multisport.fit")
	activityComponentsPath = filepath.Join(tdfolder, "dcrainmaker", "Edge810-Vector-2013-08-16-15-35-10.fit")
	monitoringPath         = filepath.Join(tdfolder, "fitsdk", "MonitoringFile.fit")
)

const (
	goldenSuffix  = ".golden"
	currentSuffix = ".current"
	gzSuffix      = ".gz"
	tdfolder      = "testdata"
)

func TestDecode(t *testing.T) {
	regenTestTable := struct {
		sync.Mutex // Protects val and decodeTestFiles slice in reader_util_test.go.
		val        bool
	}{}

	t.Run("Group", func(t *testing.T) {
		for i, file := range decodeTestFiles {
			i, file := i, file // Capture range variables.
			t.Run(fmt.Sprintf("%s/%s", file.folder, file.name), func(t *testing.T) {
				t.Parallel()
				fpath := filepath.Join(tdfolder, file.folder, file.name)
				data, err := ioutil.ReadFile(fpath)
				if err != nil {
					t.Fatalf("reading file failed: %v", err)
				}
				fitFile, err := fit.Decode(bytes.NewReader(data), file.dopts.opts()...)
				if !file.wantErr && err != nil {
					t.Fatalf("got error, want none; error is: %v", err)
				}
				if file.wantErr && err == nil {
					t.Fatalf("got no error, want error")
				}
				if file.fingerprint == 0 {
					return
				}
				fp := fitFingerprint(fitFile)
				if fp == file.fingerprint {
					return
				}
				t.Errorf("fit file fingerprint differs: got: %d, want: %d", fp, file.fingerprint)
				if !*update {
					fpath = fpath + currentSuffix
				} else {
					fpath = fpath + goldenSuffix
				}
				if file.compress {
					fpath = fpath + gzSuffix
				}
				err = fitUtterDump(fitFile, fpath, file.compress)
				if err != nil {
					t.Fatalf("error writing output: %v", err)
				}
				if !*update {
					t.Logf("current output written to: %s", fpath)
					t.Logf("use a diff tool to compare (e.g. zdiff if compressed)")
				} else {
					regenTestTable.Lock()
					regenTestTable.val = true
					decodeTestFiles[i].fingerprint = fp
					regenTestTable.Unlock()
					t.Logf("%q has been updated", fpath)
					t.Logf("new fingerprint is: %d, update test case in reader_test.go", fp)
				}
			})
		}
	})

	if regenTestTable.val || *fupdate {
		t.Logf("regenerating table for decode test files...")
		err := regenerateDecodeTestTable()
		if err != nil {
			t.Fatalf("error regenerating table for decode test files: %v", err)
		}
	}
}

func TestDecodeChained(t *testing.T) {
	chainedTestFiles := []struct {
		fpath   string
		dfiles  int
		wantErr bool
		desc    string
	}{
		{
			filepath.Join(tdfolder, "fitsdk", "Activity.fit"),
			1,
			false,
			"single valid fit file",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-settings.fit"),
			2,
			false,
			"two valid chained fit files",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-activity-filecrc.fit"),
			2,
			true,
			"one valid fit file + one fit file with wrong crc",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-settings-corruptheader.fit"),
			1,
			true,
			"one valid fit file + one fit file with corrupt header",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-settings-nodata.fit"),
			2,
			true,
			"one valid fit file + one fit file with ok header but no data",
		},
	}

	for _, ctf := range chainedTestFiles {
		ctf := ctf
		t.Run(ctf.fpath, func(t *testing.T) {
			t.Parallel()
			data, err := ioutil.ReadFile(ctf.fpath)
			if err != nil {
				t.Fatalf("reading file data failed: %v", err)
			}
			fitFiles, err := fit.DecodeChained(bytes.NewReader(data))
			if !ctf.wantErr && err != nil {
				t.Fatalf("got error, want none; error is: %v", err)
			}
			if ctf.wantErr && err == nil {
				t.Fatalf("got no error, want error")
			}
			if len(fitFiles) != ctf.dfiles {
				t.Fatalf("got %d decoded fit file(s), want %d", len(fitFiles), ctf.dfiles)
			}
		})
	}
}

func TestCheckIntegrity(t *testing.T) {
	t.Run("ActivitySmall", func(t *testing.T) {
		err := fit.CheckIntegrity(bytes.NewReader(activitySmall()), false)
		if err != nil {
			t.Errorf("%q: failed: %v", activitySmallPath, err)
		}
	})
	t.Run("ActivitySDK", func(t *testing.T) {
		fpath := filepath.Join(tdfolder, "fitsdk", "Activity.fit")
		data, err := ioutil.ReadFile(fpath)
		if err != nil {
			t.Fatalf("reading %q failed: %v", fpath, err)
		}
		err = fit.CheckIntegrity(bytes.NewReader(data), false)
		if err != nil {
			t.Errorf("%q: failed: %v", fpath, err)
		}
	})
}

func TestDecodeHeader(t *testing.T) {
	wantHeader := fit.Header{
		Size:            0xe,
		ProtocolVersion: 0x10,
		ProfileVersion:  0x457,
		DataSize:        0x1dbdf,
		DataType:        [4]uint8{0x2e, 0x46, 0x49, 0x54},
		CRC:             0x1ec4,
	}
	gotHeader, err := fit.DecodeHeader(bytes.NewReader(activitySmall()))
	if err != nil {
		t.Errorf("%q: failed: %v", activitySmallPath, err)
	}
	if gotHeader != wantHeader {
		t.Errorf("got header:\n%#v\nwant header: %#v", gotHeader, wantHeader)
	}
}

func TestDecodeHeaderAndFileID(t *testing.T) {
	wantHeader := fit.Header{
		Size:            0xe,
		ProtocolVersion: 0x10,
		ProfileVersion:  0x457,
		DataSize:        0x1dbdf,
		DataType:        [4]uint8{0x2e, 0x46, 0x49, 0x54},
		CRC:             0x1ec4,
	}
	tc := time.Unix(1439652761, 0)
	tc = tc.UTC()
	wantFileId := fit.FileIdMsg{
		Type:         0x4,
		Manufacturer: 0x1,
		Product:      0x7af,
		SerialNumber: 0xe762d9cf,
		Number:       0xffff,
		TimeCreated:  tc,
		ProductName:  "",
	}

	gotHeader, gotFileId, err := fit.DecodeHeaderAndFileID(bytes.NewReader(activitySmall()))
	if err != nil {
		t.Errorf("%q: failed: %v", activitySmallPath, err)
	}
	if gotHeader != wantHeader {
		t.Errorf("%q:\ngot header:\n%#v\nwant header:\n%#v", activitySmallPath, gotHeader, wantHeader)
	}
	if gotFileId != wantFileId {
		t.Errorf("%q:\ngot FileIdMsg:\n%v\nwant FileIdMsg:\n%v", activitySmallPath, gotFileId, wantFileId)
	}
}

func BenchmarkDecode(b *testing.B) {
	files := []struct {
		desc, path string
	}{
		{"ActivitySmall", activitySmallPath},
		{"ActivityLarge", activityLargePath},
		{"ActivityWithComponents", activityComponentsPath},
		{"MonitoringFile", monitoringPath},
	}
	for _, file := range files {
		b.Run(file.desc, func(b *testing.B) {
			data, err := ioutil.ReadFile(file.path)
			if err != nil {
				b.Fatalf("%q: error reading file: %v", file.path, err)
			}
			b.ReportAllocs()
			b.SetBytes(int64(len(data)))
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				_, err := fit.Decode(bytes.NewReader(data))
				if err != nil {
					b.Fatalf("%q: error decoding file: %v", file.path, err)
				}
			}
		})
	}
}

func BenchmarkDecodeActivityLargeParallel(b *testing.B) {
	data, err := ioutil.ReadFile(activityLargePath)
	if err != nil {
		b.Fatal(err)
	}
	b.ReportAllocs()
	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			_, err := fit.Decode(bytes.NewReader(data))
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkDecodeHeader(b *testing.B) {
	data := activitySmall()
	b.ReportAllocs()
	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := fit.DecodeHeader(bytes.NewReader(data))
		if err != nil {
			b.Fatalf("%q: error decoding header: %v", activitySmallPath, err)
		}
	}

}

func BenchmarkDecodeHeaderAndFileID(b *testing.B) {
	data := activitySmall()
	b.ReportAllocs()
	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _, err := fit.DecodeHeaderAndFileID(bytes.NewReader(data))
		if err != nil {
			b.Fatalf("%q: error decoding header/fileid: %v", activitySmallPath, err)
		}
	}
}
<commit_msg>reader_test: only perform golden part of Decode test for latest Go version or if forced<commit_after>package fit_test

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/tormoder/fit"
)

var (
	update  = flag.Bool("update", false, "update .golden output and table for decode test files if their fingerprint differs")
	fupdate = flag.Bool("fupdate", false, "force regeneration of decode test files table")
	fdecode = flag.Bool("fdecode", false, "force decode golden part of decode test irregardless of Go version")
)

func init() { flag.Parse() }

var (
	activitySmallMu   sync.Mutex
	activitySmallOnce sync.Once
	activitySmallData []byte
)

func activitySmall() []byte {
	activitySmallMu.Lock()
	defer activitySmallMu.Unlock()
	activitySmallOnce.Do(func() {
		asd, err := ioutil.ReadFile(activitySmallPath)
		if err != nil {
			errDesc := fmt.Sprintf("parseActivitySmallData failed: %v", err)
			panic(errDesc)
		}
		activitySmallData = asd
	})
	return activitySmallData
}

var (
	activitySmallPath      = filepath.Join(tdfolder, "me", "activity-small-fenix2-run.fit")
	activityLargePath      = filepath.Join(tdfolder, "me", "activity-large-fenxi2-multisport.fit")
	activityComponentsPath = filepath.Join(tdfolder, "dcrainmaker", "Edge810-Vector-2013-08-16-15-35-10.fit")
	monitoringPath         = filepath.Join(tdfolder, "fitsdk", "MonitoringFile.fit")
)

const (
	goldenSuffix  = ".golden"
	currentSuffix = ".current"
	gzSuffix      = ".gz"
	tdfolder      = "testdata"
)

func TestDecode(t *testing.T) {
	const goMajorVersionForDecodeGolden = "go1.8"
	testDecodeGolden := true
	goVersion := runtime.Version()
	goVersionOK := strings.HasPrefix(goVersion, goMajorVersionForDecodeGolden)
	switch {
	case !goVersionOK && !*fdecode:
		testDecodeGolden = false
		t.Logf(
			"skipping golden decode part of test due to Go version (enabled for %s.x, have %q)",
			goMajorVersionForDecodeGolden,
			goVersion,
		)
	case !goVersionOK && *fdecode:
		t.Logf(
			"override: performing golden decode part of test for Go version %q (default only for %s.x)",
			goVersion,
			goMajorVersionForDecodeGolden,
		)
	default:
	}

	regenTestTable := struct {
		sync.Mutex // Protects val and decodeTestFiles slice in reader_util_test.go.
		val        bool
	}{}

	t.Run("Group", func(t *testing.T) {
		for i, file := range decodeTestFiles {
			i, file := i, file // Capture range variables.
			t.Run(fmt.Sprintf("%s/%s", file.folder, file.name), func(t *testing.T) {
				t.Parallel()
				fpath := filepath.Join(tdfolder, file.folder, file.name)
				data, err := ioutil.ReadFile(fpath)
				if err != nil {
					t.Fatalf("reading file failed: %v", err)
				}
				fitFile, err := fit.Decode(bytes.NewReader(data), file.dopts.opts()...)
				if !file.wantErr && err != nil {
					t.Fatalf("got error, want none; error is: %v", err)
				}
				if file.wantErr && err == nil {
					t.Fatalf("got no error, want error")
				}
				if !testDecodeGolden {
					return
				}
				if file.fingerprint == 0 {
					return
				}
				fp := fitFingerprint(fitFile)
				if fp == file.fingerprint {
					return
				}
				t.Errorf("fit file fingerprint differs: got: %d, want: %d", fp, file.fingerprint)
				if !*update {
					fpath = fpath + currentSuffix
				} else {
					fpath = fpath + goldenSuffix
				}
				if file.compress {
					fpath = fpath + gzSuffix
				}
				err = fitUtterDump(fitFile, fpath, file.compress)
				if err != nil {
					t.Fatalf("error writing output: %v", err)
				}
				if !*update {
					t.Logf("current output written to: %s", fpath)
					t.Logf("use a diff tool to compare (e.g. zdiff if compressed)")
				} else {
					regenTestTable.Lock()
					regenTestTable.val = true
					decodeTestFiles[i].fingerprint = fp
					regenTestTable.Unlock()
					t.Logf("%q has been updated", fpath)
					t.Logf("new fingerprint is: %d, update test case in reader_test.go", fp)
				}
			})
		}
	})

	if regenTestTable.val || *fupdate {
		t.Logf("regenerating table for decode test files...")
		err := regenerateDecodeTestTable()
		if err != nil {
			t.Fatalf("error regenerating table for decode test files: %v", err)
		}
	}
}

func TestDecodeChained(t *testing.T) {
	chainedTestFiles := []struct {
		fpath   string
		dfiles  int
		wantErr bool
		desc    string
	}{
		{
			filepath.Join(tdfolder, "fitsdk", "Activity.fit"),
			1,
			false,
			"single valid fit file",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-settings.fit"),
			2,
			false,
			"two valid chained fit files",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-activity-filecrc.fit"),
			2,
			true,
			"one valid fit file + one fit file with wrong crc",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-settings-corruptheader.fit"),
			1,
			true,
			"one valid fit file + one fit file with corrupt header",
		},
		{
			filepath.Join(tdfolder, "chained", "activity-settings-nodata.fit"),
			2,
			true,
			"one valid fit file + one fit file with ok header but no data",
		},
	}

	for _, ctf := range chainedTestFiles {
		ctf := ctf
		t.Run(ctf.fpath, func(t *testing.T) {
			t.Parallel()
			data, err := ioutil.ReadFile(ctf.fpath)
			if err != nil {
				t.Fatalf("reading file data failed: %v", err)
			}
			fitFiles, err := fit.DecodeChained(bytes.NewReader(data))
			if !ctf.wantErr && err != nil {
				t.Fatalf("got error, want none; error is: %v", err)
			}
			if ctf.wantErr && err == nil {
				t.Fatalf("got no error, want error")
			}
			if len(fitFiles) != ctf.dfiles {
				t.Fatalf("got %d decoded fit file(s), want %d", len(fitFiles), ctf.dfiles)
			}
		})
	}
}

func TestCheckIntegrity(t *testing.T) {
	t.Run("ActivitySmall", func(t *testing.T) {
		err := fit.CheckIntegrity(bytes.NewReader(activitySmall()), false)
		if err != nil {
			t.Errorf("%q: failed: %v", activitySmallPath, err)
		}
	})
	t.Run("ActivitySDK", func(t *testing.T) {
		fpath := filepath.Join(tdfolder, "fitsdk", "Activity.fit")
		data, err := ioutil.ReadFile(fpath)
		if err != nil {
			t.Fatalf("reading %q failed: %v", fpath, err)
		}
		err = fit.CheckIntegrity(bytes.NewReader(data), false)
		if err != nil {
			t.Errorf("%q: failed: %v", fpath, err)
		}
	})
}

func TestDecodeHeader(t *testing.T) {
	wantHeader := fit.Header{
		Size:            0xe,
		ProtocolVersion: 0x10,
		ProfileVersion:  0x457,
		DataSize:        0x1dbdf,
		DataType:        [4]uint8{0x2e, 0x46, 0x49, 0x54},
		CRC:             0x1ec4,
	}
	gotHeader, err := fit.DecodeHeader(bytes.NewReader(activitySmall()))
	if err != nil {
		t.Errorf("%q: failed: %v", activitySmallPath, err)
	}
	if gotHeader != wantHeader {
		t.Errorf("got header:\n%#v\nwant header: %#v", gotHeader, wantHeader)
	}
}

func TestDecodeHeaderAndFileID(t *testing.T) {
	wantHeader := fit.Header{
		Size:            0xe,
		ProtocolVersion: 0x10,
		ProfileVersion:  0x457,
		DataSize:        0x1dbdf,
		DataType:        [4]uint8{0x2e, 0x46, 0x49, 0x54},
		CRC:             0x1ec4,
	}
	tc := time.Unix(1439652761, 0)
	tc = tc.UTC()
	wantFileId := fit.FileIdMsg{
		Type:         0x4,
		Manufacturer: 0x1,
		Product:      0x7af,
		SerialNumber: 0xe762d9cf,
		Number:       0xffff,
		TimeCreated:  tc,
		ProductName:  "",
	}

	gotHeader, gotFileId, err := fit.DecodeHeaderAndFileID(bytes.NewReader(activitySmall()))
	if err != nil {
		t.Errorf("%q: failed: %v", activitySmallPath, err)
	}
	if gotHeader != wantHeader {
		t.Errorf("%q:\ngot header:\n%#v\nwant header:\n%#v", activitySmallPath, gotHeader, wantHeader)
	}
	if gotFileId != wantFileId {
		t.Errorf("%q:\ngot FileIdMsg:\n%v\nwant FileIdMsg:\n%v", activitySmallPath, gotFileId, wantFileId)
	}
}

func BenchmarkDecode(b *testing.B) {
	files := []struct {
		desc, path string
	}{
		{"ActivitySmall", activitySmallPath},
		{"ActivityLarge", activityLargePath},
		{"ActivityWithComponents", activityComponentsPath},
		{"MonitoringFile", monitoringPath},
	}
	for _, file := range files {
		b.Run(file.desc, func(b *testing.B) {
			data, err := ioutil.ReadFile(file.path)
			if err != nil {
				b.Fatalf("%q: error reading file: %v", file.path, err)
			}
			b.ReportAllocs()
			b.SetBytes(int64(len(data)))
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				_, err := fit.Decode(bytes.NewReader(data))
				if err != nil {
					b.Fatalf("%q: error decoding file: %v", file.path, err)
				}
			}
		})
	}
}

func BenchmarkDecodeActivityLargeParallel(b *testing.B) {
	data, err := ioutil.ReadFile(activityLargePath)
	if err != nil {
		b.Fatal(err)
	}
	b.ReportAllocs()
	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			_, err := fit.Decode(bytes.NewReader(data))
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkDecodeHeader(b *testing.B) {
	data := activitySmall()
	b.ReportAllocs()
	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := fit.DecodeHeader(bytes.NewReader(data))
		if err != nil {
			b.Fatalf("%q: error decoding header: %v", activitySmallPath, err)
		}
	}

}

func BenchmarkDecodeHeaderAndFileID(b *testing.B) {
	data := activitySmall()
	b.ReportAllocs()
	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, _, err := fit.DecodeHeaderAndFileID(bytes.NewReader(data))
		if err != nil {
			b.Fatalf("%q: error decoding header/fileid: %v", activitySmallPath, err)
		}
	}
}
<|endoftext|>


<commit_before>package gocqltable

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/gocql/gocql"
)

var (
	defaultSession *gocql.Session
)

func SetDefaultSession(s *gocql.Session) {
	defaultSession = s
}

type KeyspaceInterface interface {
	Name() string
	Session() *gocql.Session
}

type Keyspace struct {
	name    string
	session *gocql.Session
}

func NewKeyspace(name string) Keyspace {
	return Keyspace{
		name:    name,
		session: defaultSession,
	}
}

func (ks Keyspace) Create(replication map[string]interface{}, durableWrites bool) error {

	if ks.session == nil {
		ks.session = defaultSession
	}

	replicationBytes, err := json.Marshal(replication)
	if err != nil {
		return err
	}

	replicationMap := strings.Replace(string(replicationBytes), `"`, `'`, -1)

	durableWritesString := "false"
	if durableWrites {
		durableWritesString = "true"
	}

	return ks.session.Query(fmt.Sprintf(`CREATE KEYSPACE %q WITH REPLICATION = %s AND DURABLE_WRITES = %s`, ks.Name(), replicationMap, durableWritesString)).Exec()

}

func (ks Keyspace) Drop() error {
	if ks.session == nil {
		ks.session = defaultSession
	}
	return ks.session.Query(fmt.Sprintf(`DROP KEYSPACE %q`, ks.Name())).Exec()
}

func (ks Keyspace) Tables() ([]string, error) {
	if ks.session == nil {
		ks.session = defaultSession
	}
	var name string
	var resultSet []string
	iterator := ks.session.Query(`SELECT columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?;`, ks.Name()).Iter()
	for iterator.Scan(&name) {
		resultSet = append(resultSet, name)
	}
	if err := iterator.Close(); err != nil {
		return nil, err
	}
	return resultSet, nil
}

func (ks Keyspace) NewTable(name string, rowKeys, rangeKeys []string, row interface{}) Table {
	if ks.session == nil {
		ks.session = defaultSession
	}
	return Table{
		name:      name,
		rowKeys:   rowKeys,
		rangeKeys: rangeKeys,
		row:       row,

		keyspace: ks,
		session:  ks.session,
	}
}

func (ks Keyspace) Name() string {
	return ks.name
}

func (ks Keyspace) Session() *gocql.Session {
	if ks.session == nil {
		ks.session = defaultSession
	}
	return ks.session
}
<commit_msg>Fixed: made it possible to set the session on the Keyspace struct in order to avoid using the default session when that's unwanted.<commit_after>package gocqltable

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/gocql/gocql"
)

var (
	defaultSession *gocql.Session
)

func SetDefaultSession(s *gocql.Session) {
	defaultSession = s
}

type KeyspaceInterface interface {
	Name() string
	Session() *gocql.Session
}

type Keyspace struct {
	name    string
	session *gocql.Session
}

func NewKeyspace(name string) Keyspace {
	return Keyspace{
		name:    name,
		session: defaultSession,
	}
}

func (ks Keyspace) Create(replication map[string]interface{}, durableWrites bool) error {

	if ks.session == nil {
		ks.session = defaultSession
	}

	replicationBytes, err := json.Marshal(replication)
	if err != nil {
		return err
	}

	replicationMap := strings.Replace(string(replicationBytes), `"`, `'`, -1)

	durableWritesString := "false"
	if durableWrites {
		durableWritesString = "true"
	}

	return ks.session.Query(fmt.Sprintf(`CREATE KEYSPACE %q WITH REPLICATION = %s AND DURABLE_WRITES = %s`, ks.Name(), replicationMap, durableWritesString)).Exec()

}

func (ks Keyspace) Drop() error {
	if ks.session == nil {
		ks.session = defaultSession
	}
	return ks.session.Query(fmt.Sprintf(`DROP KEYSPACE %q`, ks.Name())).Exec()
}

func (ks Keyspace) Tables() ([]string, error) {
	if ks.session == nil {
		ks.session = defaultSession
	}
	var name string
	var resultSet []string
	iterator := ks.session.Query(`SELECT columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?;`, ks.Name()).Iter()
	for iterator.Scan(&name) {
		resultSet = append(resultSet, name)
	}
	if err := iterator.Close(); err != nil {
		return nil, err
	}
	return resultSet, nil
}

func (ks Keyspace) NewTable(name string, rowKeys, rangeKeys []string, row interface{}) Table {
	if ks.session == nil {
		ks.session = defaultSession
	}
	return Table{
		name:      name,
		rowKeys:   rowKeys,
		rangeKeys: rangeKeys,
		row:       row,

		keyspace: ks,
		session:  ks.session,
	}
}

func (ks Keyspace) Name() string {
	return ks.name
}

func (ks Keyspace) Session() *gocql.Session {
	if ks.session == nil {
		ks.session = defaultSession
	}
	return ks.session
}

func (ks *Keyspace) SetSession(session *gocql.Session) {
	ks.session = session
}
<|endoftext|>


<commit_before>package peer

import (
	"image"
	"log"
	"time"

	"golang.org/x/mobile/asset"
	"golang.org/x/mobile/exp/app/debug"
	"golang.org/x/mobile/exp/f32"
	"golang.org/x/mobile/exp/gl/glutil"
	"golang.org/x/mobile/exp/sprite"
	"golang.org/x/mobile/exp/sprite/clock"
	"golang.org/x/mobile/exp/sprite/glsprite"
	"golang.org/x/mobile/gl"
)

var glPeer *GLPeer

var startTime = time.Now()

// GLPeer represents gl context.
// Singleton.
type GLPeer struct {
	glctx  gl.Context
	images *glutil.Images
	fps    *debug.FPS
	eng    sprite.Engine
	scene  *sprite.Node
}

// GetGLPeer returns a instance of GLPeer.
// Since GLPeer is singleton, it is necessary to
// call this function to get GLPeer instance.
func GetGLPeer() *GLPeer {
	LogDebug("IN")
	if glPeer == nil {
		glPeer = &GLPeer{}
	}
	LogDebug("OUT")
	return glPeer
}

// Initialize initializes GLPeer.
// This function must be called inadvance of using GLPeer
func (glpeer *GLPeer) Initialize(glctx gl.Context) {
	LogDebug("IN")
	glpeer.glctx = glctx

	// transparency of png
	glpeer.glctx.Enable(gl.BLEND)
	glpeer.glctx.BlendEquation(gl.FUNC_ADD)
	glpeer.glctx.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	glpeer.images = glutil.NewImages(glctx)
	glpeer.fps = debug.NewFPS(glpeer.images)
	glpeer.initEng()

	LogDebug("OUT")
}

func (glpeer *GLPeer) initEng() {
	if glpeer.eng != nil {
		glpeer.eng.Release()
	}
	glpeer.eng = glsprite.Engine(glpeer.images)
	glpeer.scene = &sprite.Node{}
	glpeer.eng.Register(glpeer.scene)
	glpeer.eng.SetTransform(glpeer.scene, f32.Affine{
		{1, 0, 0},
		{0, 1, 0},
	})
}

func (glpeer *GLPeer) newNode() *sprite.Node {
	n := &sprite.Node{}
	glpeer.eng.Register(n)
	glpeer.scene.AppendChild(n)
	return n
}

func (glpeer *GLPeer) appendChild(n *sprite.Node) {
	glpeer.scene.AppendChild(n)
}

func (glpeer *GLPeer) removeChild(n *sprite.Node) {
	glpeer.scene.RemoveChild(n)
}

// LoadTexture return texture that is loaded by the information of arguments.
// Loaded texture can assign using AddSprite function.
func (glpeer *GLPeer) LoadTexture(assetName string, rect image.Rectangle) sprite.SubTex {
	LogDebug("IN")
	a, err := asset.Open(assetName)
	if err != nil {
		log.Fatal(err)
	}
	defer a.Close()

	img, _, err := image.Decode(a)
	if err != nil {
		log.Fatal(err)
	}
	t, err := glpeer.eng.LoadTexture(img)
	if err != nil {
		log.Fatal(err)
	}

	LogDebug("OUT")
	return sprite.SubTex{T: t, R: rect}
}

// Finalize finalizes GLPeer.
// This is called at termination of application.
func (glpeer *GLPeer) Finalize() {
	LogDebug("IN")
	GetSpriteContainer().RemoveSprites()
	glpeer.eng.Release()
	glpeer.fps.Release()
	glpeer.images.Release()
	glpeer.glctx = nil
	LogDebug("OUT")
}

// Update updates screen.
// This is called 60 times per 1 sec.
func (glpeer *GLPeer) Update() {
	if glpeer.glctx == nil {
		return
	}
	glpeer.glctx.ClearColor(0, 0, 0, 1) // black background
	glpeer.glctx.Clear(gl.COLOR_BUFFER_BIT)
	now := clock.Time(time.Since(startTime) * 60 / time.Second)

	glpeer.apply()

	glpeer.eng.Render(glpeer.scene, now, sz)
	glpeer.fps.Draw(sz)
}

// Reset resets current gl context.
// All sprites are also cleaned.
// This is called at changing of scene, and
// this function is for clean previous scene.
func (glpeer *GLPeer) Reset() {
	LogDebug("IN")
	GetSpriteContainer().RemoveSprites()
	glpeer.initEng()
	LogDebug("OUT")
}

func (glpeer *GLPeer) apply() {

	snpairs := GetSpriteContainer().spriteNodePairs

	for i := range snpairs {
		sc := snpairs[i]
		if sc.sprite == nil || !sc.inuse {
			continue
		}

		affine := &f32.Affine{
			{1, 0, 0},
			{0, 1, 0},
		}
		affine.Translate(affine,
			sc.sprite.X*desiredScreenSize.scale-sc.sprite.W/2*desiredScreenSize.scale+desiredScreenSize.marginWidth/2,
			(desiredScreenSize.height-sc.sprite.Y)*desiredScreenSize.scale-sc.sprite.H/2*desiredScreenSize.scale+desiredScreenSize.marginHeight/2)
		if sc.sprite.R != 0 {
			affine.Translate(affine,
				0.5*sc.sprite.W*desiredScreenSize.scale,
				0.5*sc.sprite.H*desiredScreenSize.scale)
			affine.Rotate(affine, sc.sprite.R)
			affine.Translate(affine,
				-0.5*sc.sprite.W*desiredScreenSize.scale,
				-0.5*sc.sprite.H*desiredScreenSize.scale)
		}
		affine.Scale(affine,
			sc.sprite.W*desiredScreenSize.scale,
			sc.sprite.H*desiredScreenSize.scale)
		glpeer.eng.SetTransform(sc.node, *affine)
	}
}

type arrangerFunc func(e sprite.Engine, n *sprite.Node, t clock.Time)

func (a arrangerFunc) Arrange(e sprite.Engine, n *sprite.Node, t clock.Time) { a(e, n, t) }
<commit_msg>[#81] temporary commit. draw font<commit_after>package peer

import (
	"image"
	"image/draw"
	"log"
	"time"

	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
	//"golang.org/x/mobile/asset"
	"golang.org/x/mobile/exp/app/debug"
	"golang.org/x/mobile/exp/f32"
	mfont "golang.org/x/mobile/exp/font"
	"golang.org/x/mobile/exp/gl/glutil"
	"golang.org/x/mobile/exp/sprite"
	"golang.org/x/mobile/exp/sprite/clock"
	"golang.org/x/mobile/exp/sprite/glsprite"
	"golang.org/x/mobile/geom"
	"golang.org/x/mobile/gl"
)

var glPeer *GLPeer

var startTime = time.Now()

// GLPeer represents gl context.
// Singleton.
type GLPeer struct {
	glctx  gl.Context
	images *glutil.Images
	fps    *debug.FPS
	eng    sprite.Engine
	scene  *sprite.Node
}

// GetGLPeer returns a instance of GLPeer.
// Since GLPeer is singleton, it is necessary to
// call this function to get GLPeer instance.
func GetGLPeer() *GLPeer {
	LogDebug("IN")
	if glPeer == nil {
		glPeer = &GLPeer{}
	}
	LogDebug("OUT")
	return glPeer
}

// Initialize initializes GLPeer.
// This function must be called inadvance of using GLPeer
func (glpeer *GLPeer) Initialize(glctx gl.Context) {
	LogDebug("IN")
	glpeer.glctx = glctx

	// transparency of png
	glpeer.glctx.Enable(gl.BLEND)
	glpeer.glctx.BlendEquation(gl.FUNC_ADD)
	glpeer.glctx.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	glpeer.images = glutil.NewImages(glctx)
	glpeer.fps = debug.NewFPS(glpeer.images)
	glpeer.initEng()

	LogDebug("OUT")
}

func (glpeer *GLPeer) initEng() {
	if glpeer.eng != nil {
		glpeer.eng.Release()
	}
	glpeer.eng = glsprite.Engine(glpeer.images)
	glpeer.scene = &sprite.Node{}
	glpeer.eng.Register(glpeer.scene)
	glpeer.eng.SetTransform(glpeer.scene, f32.Affine{
		{1, 0, 0},
		{0, 1, 0},
	})
}

func (glpeer *GLPeer) newNode() *sprite.Node {
	n := &sprite.Node{}
	glpeer.eng.Register(n)
	glpeer.scene.AppendChild(n)
	return n
}

func (glpeer *GLPeer) appendChild(n *sprite.Node) {
	glpeer.scene.AppendChild(n)
}

func (glpeer *GLPeer) removeChild(n *sprite.Node) {
	glpeer.scene.RemoveChild(n)
}

// LoadTexture return texture that is loaded by the information of arguments.
// Loaded texture can assign using AddSprite function.
func (glpeer *GLPeer) LoadTexture(assetName string, rect image.Rectangle) sprite.SubTex {
	LogDebug("IN")
	//a, err := asset.Open(assetName)
	//if err != nil {
	//	log.Fatal(err)
	//}
	//defer a.Close()

	//img, _, err := image.Decode(a)
	//if err != nil {
	//	log.Fatal(err)
	//}
	//t, err := glpeer.eng.LoadTexture(img)
	//if err != nil {
	//	log.Fatal(err)
	//}

	//

	width := 400
	height := 30
	img := glpeer.images.NewImage(width, height)

	fg, bg := image.Black, image.White
	draw.Draw(img.RGBA, img.RGBA.Bounds(), bg, image.Point{}, draw.Src)

	// Draw the text.
	h := font.HintingNone
	//h = font.HintingFull

	monofontbytes := mfont.Monospace()
	monofont, _ := truetype.Parse(monofontbytes)

	d := &font.Drawer{
		Dst: img.RGBA,
		Src: fg,
		Face: truetype.NewFace(monofont, &truetype.Options{
			Size:    24,
			DPI:     72,
			Hinting: h,
		}),
	}

	d.Dot = fixed.Point26_6{
		X: fixed.I(10),
		Y: fixed.I(int(24 * 72 / 72)),
	}
	d.DrawString("hogehoge")

	img.Upload()
	img.Draw(
		sz,
		geom.Point{0, (sz.HeightPt - geom.Pt(height)/4)},
		geom.Point{geom.Pt(width) / 4, (sz.HeightPt - geom.Pt(height)/4)},
		geom.Point{0, (sz.HeightPt - geom.Pt(height)/4)},
		img.RGBA.Bounds().Inset(1),
	)

	t, err := glpeer.eng.LoadTexture(img.RGBA)
	if err != nil {
		log.Fatal(err)
	}

	LogDebug("OUT")
	return sprite.SubTex{T: t, R: rect}
}

// Finalize finalizes GLPeer.
// This is called at termination of application.
func (glpeer *GLPeer) Finalize() {
	LogDebug("IN")
	GetSpriteContainer().RemoveSprites()
	glpeer.eng.Release()
	glpeer.fps.Release()
	glpeer.images.Release()
	glpeer.glctx = nil
	LogDebug("OUT")
}

// Update updates screen.
// This is called 60 times per 1 sec.
func (glpeer *GLPeer) Update() {
	if glpeer.glctx == nil {
		return
	}
	glpeer.glctx.ClearColor(0, 0, 0, 1) // black background
	glpeer.glctx.Clear(gl.COLOR_BUFFER_BIT)
	now := clock.Time(time.Since(startTime) * 60 / time.Second)

	glpeer.apply()

	glpeer.eng.Render(glpeer.scene, now, sz)
	glpeer.fps.Draw(sz)
}

// Reset resets current gl context.
// All sprites are also cleaned.
// This is called at changing of scene, and
// this function is for clean previous scene.
func (glpeer *GLPeer) Reset() {
	LogDebug("IN")
	GetSpriteContainer().RemoveSprites()
	glpeer.initEng()
	LogDebug("OUT")
}

func (glpeer *GLPeer) apply() {

	snpairs := GetSpriteContainer().spriteNodePairs

	for i := range snpairs {
		sc := snpairs[i]
		if sc.sprite == nil || !sc.inuse {
			continue
		}

		affine := &f32.Affine{
			{1, 0, 0},
			{0, 1, 0},
		}
		affine.Translate(affine,
			sc.sprite.X*desiredScreenSize.scale-sc.sprite.W/2*desiredScreenSize.scale+desiredScreenSize.marginWidth/2,
			(desiredScreenSize.height-sc.sprite.Y)*desiredScreenSize.scale-sc.sprite.H/2*desiredScreenSize.scale+desiredScreenSize.marginHeight/2)
		if sc.sprite.R != 0 {
			affine.Translate(affine,
				0.5*sc.sprite.W*desiredScreenSize.scale,
				0.5*sc.sprite.H*desiredScreenSize.scale)
			affine.Rotate(affine, sc.sprite.R)
			affine.Translate(affine,
				-0.5*sc.sprite.W*desiredScreenSize.scale,
				-0.5*sc.sprite.H*desiredScreenSize.scale)
		}
		affine.Scale(affine,
			sc.sprite.W*desiredScreenSize.scale,
			sc.sprite.H*desiredScreenSize.scale)
		glpeer.eng.SetTransform(sc.node, *affine)
	}
}

type arrangerFunc func(e sprite.Engine, n *sprite.Node, t clock.Time)

func (a arrangerFunc) Arrange(e sprite.Engine, n *sprite.Node, t clock.Time) { a(e, n, t) }
<|endoftext|>


<commit_before>// Copyright 2019 Red Hat, 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 config

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/coreos/ignition/v2/config/util"
	v3_0 "github.com/coreos/ignition/v2/config/v3_0/types"
	v3_1 "github.com/coreos/ignition/v2/config/v3_1/types"
	v3_2 "github.com/coreos/ignition/v2/config/v3_2/types"
	v3_3 "github.com/coreos/ignition/v2/config/v3_3_experimental/types"
)

// helper to check whether a type and field matches a denylist of known problems
// examples are either structs or names of structs
func ignore(t reflect.Type, field reflect.StructField, fieldName string, examples ...interface{}) bool {
	if field.Name != fieldName {
		return false
	}
	for _, candidate := range examples {
		if reflect.TypeOf(candidate).Kind() == reflect.String {
			if t.Name() == candidate.(string) {
				return true
			}
		} else if t == reflect.TypeOf(candidate) {
			return true
		}
	}
	return false
}

// vary the specified field value and check the given key function to see
// whether the field seems to affect it
// this function's heuristic can be fooled by complex key functions but it
// should be fine for typical cases
func fieldAffectsKey(key func() string, v reflect.Value) bool {
	kind := v.Kind()
	switch {
	case util.IsPrimitive(kind):
		old := key()
		v.Set(util.NonZeroValue(v.Type()))
		new := key()
		v.Set(reflect.Zero(v.Type()))
		return old != new
	case kind == reflect.Ptr:
		null := key()
		v.Set(reflect.New(v.Type().Elem()))
		allocated := key()
		affectsKey := fieldAffectsKey(key, v.Elem())
		v.Set(reflect.Zero(v.Type()))
		return null != allocated || affectsKey
	case kind == reflect.Struct:
		ret := false
		for i := 0; i < v.NumField(); i++ {
			ret = ret || fieldAffectsKey(key, v.Field(i))
		}
		return ret
	case kind == reflect.Slice:
		if v.Len() > 0 {
			panic("Slice started with non-zero length")
		}
		v.Set(reflect.MakeSlice(v.Type(), 1, 1))
		ret := fieldAffectsKey(key, v.Index(0))
		v.SetLen(0)
		return ret
	default:
		panic(fmt.Sprintf("Unexpected value kind %v", kind.String()))
	}
}

// check the fields that affect the key function of a keyed struct
// to ensure that we're using pointer and non-pointer fields properly.
func checkStructFieldKey(t reflect.Type) error {
	v := reflect.New(t).Elem()
	// wrapper to get the current key of @v
	getKey := func() string {
		// outer function's caller should have ensured that type
		// implements Keyed
		return v.Interface().(util.Keyed).Key()
	}

	var haveNonPointerKey bool
	// check the fields of one struct
	var checkStruct func(t reflect.Type, v reflect.Value) error
	checkStruct = func(t reflect.Type, v reflect.Value) error {
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			affectsKey := fieldAffectsKey(getKey, v.Field(i))

			switch {
			case util.IsPrimitive(field.Type.Kind()):
				// non-pointer primitive; must affect key
				haveNonPointerKey = true
				if !affectsKey &&
					!ignore(t, field, "Target", v3_0.LinkEmbedded1{}, v3_1.LinkEmbedded1{}, v3_2.LinkEmbedded1{}, v3_3.LinkEmbedded1{}) &&
					!ignore(t, field, "Level", v3_0.Raid{}, v3_1.Raid{}, v3_2.Raid{}, v3_3.Raid{}) {
					return fmt.Errorf("Non-pointer %s.%s does not affect key", t.Name(), field.Name)
				}
			case field.Type.Kind() == reflect.Ptr && util.IsPrimitive(field.Type.Elem().Kind()):
				// pointer primitive; may affect key if there's also
				// a non-pointer key
			case field.Type.Kind() == reflect.Struct && field.Anonymous:
				// anonymous child struct; treat it as an extension of the
				// parent
				if err := checkStruct(field.Type, v.Field(i)); err != nil {
					return err
				}
			default:
				// slice, struct, or invalid type
				if affectsKey {
					return fmt.Errorf("Non-primitive %s.%s affects key", t.Name(), field.Name)
				}
			}
		}
		return nil
	}
	if err := checkStruct(t, v); err != nil {
		return err
	}

	// The Resource struct in spec >= 3.1 uses Source as the key, but
	// it's a pointer because in storage.files the source is optional.
	// Allow this special case, and the similar ConfigReference one in
	// 3.0.  This rule is a consistency guideline anyway; there's no
	// technical reason we can't have pointer keys.
	if !haveNonPointerKey &&
		t.Name() != "Resource" &&
		t != reflect.TypeOf(v3_0.ConfigReference{}) {
		return fmt.Errorf("No non-pointer key for %s", t.Name())
	}
	return nil
}

func testConfigType(t reflect.Type) error {
	k := t.Kind()
	switch {
	case util.IsInvalidInConfig(k):
		return fmt.Errorf("Type %s is of kind %s which is not valid in configs", t.Name(), k.String())
	case util.IsPrimitive(k):
		return nil
	case k == reflect.Ptr:
		pK := t.Elem().Kind()
		if util.IsPrimitive(pK) {
			return nil
		}
		switch t.Elem() {
		case reflect.TypeOf(v3_2.Clevis{}), reflect.TypeOf(v3_2.Custom{}):
			// these structs ended up with pointers; can't be helped now
			if err := testConfigType(t.Elem()); err != nil {
				return fmt.Errorf("Type %s has invalid children: %v", t.Elem().Name(), err)
			}
			return nil
		default:
			return fmt.Errorf("Type %s is a pointer that points to a non-primitive type", t.Name())
		}
	case k == reflect.Slice:
		eK := t.Elem().Kind()
		switch {
		case util.IsPrimitive(eK):
			return nil
		case eK == reflect.Struct:
			if err := testConfigType(t.Elem()); err != nil {
				return fmt.Errorf("Type %s has invalid children: %v", t.Name(), err)
			}
			return nil
		case eK == reflect.Slice:
			return fmt.Errorf("Type %s is a slice of slices", t.Name())
		case util.IsInvalidInConfig(eK):
			return fmt.Errorf("Type %s is a slice of invalid types", t.Name())
		default:
			return fmt.Errorf("Testing code encountered a failure at %s", t.Name())
		}
	case k == reflect.Struct:
		ignoredFields := map[string]struct{}{}
		if ignorer, ok := reflect.New(t).Interface().(util.IgnoresDups); ok {
			ignoredFields = ignorer.IgnoreDuplicates()
		}
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			if err := testConfigType(field.Type); err != nil {
				return fmt.Errorf("Type %s has invalid field %s: %v", t.Name(), field.Name, err)
			}
			if field.Type.Kind() == reflect.Slice && field.Type.Elem().Kind() != reflect.String {
				elemType := field.Type.Elem()
				if _, ignored := ignoredFields[field.Name]; !ignored {
					// check this here, rather than in checkStructFieldKey(),
					// so we can provide more context in the error
					keyed, ok := reflect.New(elemType).Interface().(util.Keyed)
					if !ok {
						return fmt.Errorf("Type %s has slice field %s without Key() defined on %s debug: %v", t.Name(), field.Name, field.Type.Elem().Name(), ignoredFields)
					}
					// explicitly check for nil pointer dereference when calling Key() on zero value
					keyed.Key()
					if err := checkStructFieldKey(elemType); err != nil {
						return fmt.Errorf("Type %s has invalid field %s: %v", t.Name(), field.Name, err)
					}
				}
			}
		}
		return nil
	default:
		return fmt.Errorf("Testing code encountered a failure at %s", t.Name())
	}
}

// TestConfigStructure walks the types of all our configs and ensures they don't contain
// anything the merge, translation, or validation logic doesn't know how to handle
func TestConfigStructure(t *testing.T) {
	configs := []reflect.Type{
		reflect.TypeOf(v3_0.Config{}),
		reflect.TypeOf(v3_1.Config{}),
		reflect.TypeOf(v3_2.Config{}),
		reflect.TypeOf(v3_3.Config{}),
	}

	for _, configType := range configs {
		if err := testConfigType(configType); err != nil {
			t.Errorf("Type %s/%s was invalid: %v", configType.PkgPath(), configType.Name(), err)
		}
	}
}
<commit_msg>config: test that fields of non-keyed structs are properly pointered<commit_after>// Copyright 2019 Red Hat, 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 config

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/coreos/ignition/v2/config/util"
	v3_0 "github.com/coreos/ignition/v2/config/v3_0/types"
	v3_1 "github.com/coreos/ignition/v2/config/v3_1/types"
	v3_2 "github.com/coreos/ignition/v2/config/v3_2/types"
	v3_3 "github.com/coreos/ignition/v2/config/v3_3_experimental/types"
)

type typeSet map[reflect.Type]struct{}

// helper to check whether a type and field matches a denylist of known problems
// examples are either structs or names of structs
func ignore(t reflect.Type, field reflect.StructField, fieldName string, examples ...interface{}) bool {
	if field.Name != fieldName {
		return false
	}
	for _, candidate := range examples {
		if reflect.TypeOf(candidate).Kind() == reflect.String {
			if t.Name() == candidate.(string) {
				return true
			}
		} else if t == reflect.TypeOf(candidate) {
			return true
		}
	}
	return false
}

// vary the specified field value and check the given key function to see
// whether the field seems to affect it
// this function's heuristic can be fooled by complex key functions but it
// should be fine for typical cases
func fieldAffectsKey(key func() string, v reflect.Value) bool {
	kind := v.Kind()
	switch {
	case util.IsPrimitive(kind):
		old := key()
		v.Set(util.NonZeroValue(v.Type()))
		new := key()
		v.Set(reflect.Zero(v.Type()))
		return old != new
	case kind == reflect.Ptr:
		null := key()
		v.Set(reflect.New(v.Type().Elem()))
		allocated := key()
		affectsKey := fieldAffectsKey(key, v.Elem())
		v.Set(reflect.Zero(v.Type()))
		return null != allocated || affectsKey
	case kind == reflect.Struct:
		ret := false
		for i := 0; i < v.NumField(); i++ {
			ret = ret || fieldAffectsKey(key, v.Field(i))
		}
		return ret
	case kind == reflect.Slice:
		if v.Len() > 0 {
			panic("Slice started with non-zero length")
		}
		v.Set(reflect.MakeSlice(v.Type(), 1, 1))
		ret := fieldAffectsKey(key, v.Index(0))
		v.SetLen(0)
		return ret
	default:
		panic(fmt.Sprintf("Unexpected value kind %v", kind.String()))
	}
}

// check the fields that affect the key function of a keyed struct
// to ensure that we're using pointer and non-pointer fields properly.
// add the type of the struct and any anonymous embedded structs to
// keyedStructs.
func checkStructFieldKey(t reflect.Type, keyedStructs typeSet) error {
	v := reflect.New(t).Elem()
	// wrapper to get the current key of @v
	getKey := func() string {
		// outer function's caller should have ensured that type
		// implements Keyed
		return v.Interface().(util.Keyed).Key()
	}

	var haveNonPointerKey bool
	// check the fields of one struct
	var checkStruct func(t reflect.Type, v reflect.Value) error
	checkStruct = func(t reflect.Type, v reflect.Value) error {
		keyedStructs[t] = struct{}{}
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			affectsKey := fieldAffectsKey(getKey, v.Field(i))

			switch {
			case util.IsPrimitive(field.Type.Kind()):
				// non-pointer primitive; must affect key
				haveNonPointerKey = true
				if !affectsKey &&
					!ignore(t, field, "Target", v3_0.LinkEmbedded1{}, v3_1.LinkEmbedded1{}, v3_2.LinkEmbedded1{}, v3_3.LinkEmbedded1{}) &&
					!ignore(t, field, "Level", v3_0.Raid{}, v3_1.Raid{}, v3_2.Raid{}, v3_3.Raid{}) {
					return fmt.Errorf("Non-pointer %s.%s does not affect key", t.Name(), field.Name)
				}
			case field.Type.Kind() == reflect.Ptr && util.IsPrimitive(field.Type.Elem().Kind()):
				// pointer primitive; may affect key if there's also
				// a non-pointer key
			case field.Type.Kind() == reflect.Struct && field.Anonymous:
				// anonymous child struct; treat it as an extension of the
				// parent
				if err := checkStruct(field.Type, v.Field(i)); err != nil {
					return err
				}
			default:
				// slice, struct, or invalid type
				if affectsKey {
					return fmt.Errorf("Non-primitive %s.%s affects key", t.Name(), field.Name)
				}
			}
		}
		return nil
	}
	if err := checkStruct(t, v); err != nil {
		return err
	}

	// The Resource struct in spec >= 3.1 uses Source as the key, but
	// it's a pointer because in storage.files the source is optional.
	// Allow this special case, and the similar ConfigReference one in
	// 3.0.  This rule is a consistency guideline anyway; there's no
	// technical reason we can't have pointer keys.
	if !haveNonPointerKey &&
		t.Name() != "Resource" &&
		t != reflect.TypeOf(v3_0.ConfigReference{}) {
		return fmt.Errorf("No non-pointer key for %s", t.Name())
	}
	return nil
}

// keyedStructs is a running set of visited struct types that are either
// keyed and in a list, or anonymously embedded in such a type
func testConfigType(t reflect.Type, keyedStructs typeSet) error {
	k := t.Kind()
	switch {
	case util.IsInvalidInConfig(k):
		return fmt.Errorf("Type %s is of kind %s which is not valid in configs", t.Name(), k.String())
	case util.IsPrimitive(k):
		return nil
	case k == reflect.Ptr:
		pK := t.Elem().Kind()
		if util.IsPrimitive(pK) {
			return nil
		}
		switch t.Elem() {
		case reflect.TypeOf(v3_2.Clevis{}), reflect.TypeOf(v3_2.Custom{}):
			// these structs ended up with pointers; can't be helped now
			if err := testConfigType(t.Elem(), keyedStructs); err != nil {
				return fmt.Errorf("Type %s has invalid children: %v", t.Elem().Name(), err)
			}
			return nil
		default:
			return fmt.Errorf("Type %s is a pointer that points to a non-primitive type", t.Name())
		}
	case k == reflect.Slice:
		eK := t.Elem().Kind()
		switch {
		case util.IsPrimitive(eK):
			return nil
		case eK == reflect.Struct:
			if err := testConfigType(t.Elem(), keyedStructs); err != nil {
				return fmt.Errorf("Type %s has invalid children: %v", t.Name(), err)
			}
			return nil
		case eK == reflect.Slice:
			return fmt.Errorf("Type %s is a slice of slices", t.Name())
		case util.IsInvalidInConfig(eK):
			return fmt.Errorf("Type %s is a slice of invalid types", t.Name())
		default:
			return fmt.Errorf("Testing code encountered a failure at %s", t.Name())
		}
	case k == reflect.Struct:
		ignoredFields := map[string]struct{}{}
		if ignorer, ok := reflect.New(t).Interface().(util.IgnoresDups); ok {
			ignoredFields = ignorer.IgnoreDuplicates()
		}
		for i := 0; i < t.NumField(); i++ {
			field := t.Field(i)
			if err := testConfigType(field.Type, keyedStructs); err != nil {
				return fmt.Errorf("Type %s has invalid field %s: %v", t.Name(), field.Name, err)
			}
			if field.Type.Kind() == reflect.Slice && field.Type.Elem().Kind() != reflect.String {
				elemType := field.Type.Elem()
				if _, ignored := ignoredFields[field.Name]; !ignored {
					// check this here, rather than in checkStructFieldKey(),
					// so we can provide more context in the error
					keyed, ok := reflect.New(elemType).Interface().(util.Keyed)
					if !ok {
						return fmt.Errorf("Type %s has slice field %s without Key() defined on %s debug: %v", t.Name(), field.Name, field.Type.Elem().Name(), ignoredFields)
					}
					// explicitly check for nil pointer dereference when calling Key() on zero value
					keyed.Key()
					if err := checkStructFieldKey(elemType, keyedStructs); err != nil {
						return fmt.Errorf("Type %s has invalid field %s: %v", t.Name(), field.Name, err)
					}
				}
			}
		}
		return nil
	default:
		return fmt.Errorf("Testing code encountered a failure at %s", t.Name())
	}
}

// Walk a struct hierarchy, checking every struct type not in ignoreTypes
// for non-pointer fields.  Return an error if any are found that aren't on
// an allowlist of known problems.  ignoreTypes is a set of struct types
// that have already been checked against the rules for typed structs, and
// shouldn't be checked against our stricter rules.
func checkNonKeyedStructFields(t reflect.Type, ignoreTypes typeSet) error {
	kind := t.Kind()
	switch {
	case util.IsPrimitive(kind):
		return nil
	case kind == reflect.Ptr:
		return checkNonKeyedStructFields(t.Elem(), ignoreTypes)
	case kind == reflect.Slice:
		return checkNonKeyedStructFields(t.Elem(), ignoreTypes)
	case kind == reflect.Struct:
		_, ignoreType := ignoreTypes[t]
		for i := 0; i < t.NumField(); i++ {
			f := t.Field(i)
			// ignition.version is allowed to be non-pointer in
			// every spec version
			if !ignoreType &&
				util.IsPrimitive(f.Type.Kind()) &&
				!ignore(t, f, "Version", "Ignition") &&
				!ignore(t, f, "Config", v3_2.Custom{}, v3_3.ClevisCustom{}) &&
				!ignore(t, f, "Pin", v3_2.Custom{}, v3_3.ClevisCustom{}) {
				return fmt.Errorf("Type %s has non-pointer primitive field %s", t.Name(), f.Name)
			}
			if err := checkNonKeyedStructFields(f.Type, ignoreTypes); err != nil {
				return fmt.Errorf("Type %s has invalid field %s: %v", t.Name(), f.Name, err)
			}
		}
		return nil
	default:
		panic(fmt.Sprintf("unexpected kind %s", kind))
	}
}

// TestConfigStructure walks the types of all our configs and ensures they don't contain
// anything the merge, translation, or validation logic doesn't know how to handle
func TestConfigStructure(t *testing.T) {
	configs := []reflect.Type{
		reflect.TypeOf(v3_0.Config{}),
		reflect.TypeOf(v3_1.Config{}),
		reflect.TypeOf(v3_2.Config{}),
		reflect.TypeOf(v3_3.Config{}),
	}

	for _, configType := range configs {
		keyedStructs := make(typeSet)
		if err := testConfigType(configType, keyedStructs); err != nil {
			t.Errorf("Type %s/%s was invalid: %v", configType.PkgPath(), configType.Name(), err)
		} else if err := checkNonKeyedStructFields(configType, keyedStructs); err != nil {
			t.Errorf("Type %s/%s was invalid: %v", configType.PkgPath(), configType.Name(), err)
		}
	}
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"net"
	"os"
	"runtime"
	"time"
	"errors"
)

const (
	vagabond_tz           string = "America/New_York"
	vagabond_machine_name string = "vagabond"
)

// Representation of the vagabond environment settings.
type Environment struct {
	Tz             string
	SitesDir       string
	DataDir        string
	MachineName    string
	DockerClientIp net.IP
	DockerDaemonIp net.IP
	UsersDir       string
}

// Create and prepopulate a new environment based on settings
func NewEnvironment() *Environment {
	var sitesDir, dataDir, tz, machineName string
	clientIp := net.ParseIP("127.0.0.1")
	daemonIp := net.ParseIP("127.0.0.1")

	tz, set := os.LookupEnv("DOCKER_TZ")
	if !set {
		tz = vagabond_tz
	}
	sitesDir, set = os.LookupEnv("VAGABOND_SITES_DIR")
	if !set {
		if runtime.GOOS == "darwin" {
			sitesDir = os.ExpandEnv("$HOME/Sites")
		} else {
			sitesDir = "/var/www"
		}
	}

	dataDir, set = os.LookupEnv("VAGABOND_DATA_DIR")
	if !set {
		if runtime.GOOS == "darwin" {
			dataDir = "/private/var/lib/dockerdata"
		} else {
			dataDir = "/var/lib/dockerdata"
		}
	}
	if runtime.GOOS == "darwin" {
		machineName = vagabond_machine_name
		machine := Machine{Name: machineName}
		if machine.IsBooted() {
			clientIp = machine.GetHostIp()
			daemonIp = machine.GetIp()
		}
	}

	return &Environment{
		Tz:          tz,
		SitesDir:    sitesDir,
		DataDir:     dataDir,
		MachineName: machineName,
		DockerDaemonIp:   daemonIp,
		DockerClientIp:      clientIp,
		UsersDir:    "/Users",
	}
}

// Verify that environment variables are set properly
func (e *Environment) Check() error {
	if _, err := time.LoadLocation(e.Tz); err != nil {
		return errors.New(fmt.Sprintf("Invalid timezone: %s", e.Tz))
	}
	if err := checkDir(e.SitesDir, "Sites directory"); err != nil {
		return err
	}
	if err := checkDir(e.DataDir, "Data directory"); err != nil {
		return err
	}
	return nil
}

func checkDir(dir string, name string) error {
	src, err := os.Stat(dir)
	if err != nil {
		return errors.New(fmt.Sprintf("%s does not exist: %s", name, dir))
	}
	if !src.IsDir() {
		return errors.New(fmt.Sprintf("%s is not a directory: ", name, dir))
	}
	return nil
}

// Assert whether the environment requires docker machine to run
func (e *Environment) RequiresMachine() bool {
	return runtime.GOOS == "darwin"
}

// Get the docker machine instance for the environment.
func (e *Environment) GetMachine() *Machine {
	return &Machine{Name: e.MachineName}
}
<commit_msg>Switch the location of the osx data dir<commit_after>package config

import (
	"fmt"
	"net"
	"os"
	"runtime"
	"time"
	"errors"
)

const (
	vagabond_tz           string = "America/New_York"
	vagabond_machine_name string = "vagabond"
)

// Representation of the vagabond environment settings.
type Environment struct {
	Tz             string
	SitesDir       string
	DataDir        string
	MachineName    string
	DockerClientIp net.IP
	DockerDaemonIp net.IP
	UsersDir       string
}

// Create and prepopulate a new environment based on settings
func NewEnvironment() *Environment {
	var sitesDir, dataDir, tz, machineName string
	clientIp := net.ParseIP("127.0.0.1")
	daemonIp := net.ParseIP("127.0.0.1")

	tz, set := os.LookupEnv("DOCKER_TZ")
	if !set {
		tz = vagabond_tz
	}
	sitesDir, set = os.LookupEnv("VAGABOND_SITES_DIR")
	if !set {
		if runtime.GOOS == "darwin" {
			sitesDir = os.ExpandEnv("$HOME/Sites")
		} else {
			sitesDir = "/var/www"
		}
	}

	dataDir, set = os.LookupEnv("VAGABOND_DATA_DIR")
	if !set {
		if runtime.GOOS == "darwin" {
			dataDir = os.ExpandEnv("$HOME/Library/Vagabond")
		} else {
			dataDir = "/var/lib/dockerdata"
		}
	}
	if runtime.GOOS == "darwin" {
		machineName = vagabond_machine_name
		machine := Machine{Name: machineName}
		if machine.IsBooted() {
			clientIp = machine.GetHostIp()
			daemonIp = machine.GetIp()
		}
	}

	return &Environment{
		Tz:          tz,
		SitesDir:    sitesDir,
		DataDir:     dataDir,
		MachineName: machineName,
		DockerDaemonIp:   daemonIp,
		DockerClientIp:      clientIp,
		UsersDir:    "/Users",
	}
}

// Verify that environment variables are set properly
func (e *Environment) Check() error {
	if _, err := time.LoadLocation(e.Tz); err != nil {
		return errors.New(fmt.Sprintf("Invalid timezone: %s", e.Tz))
	}
	if err := checkDir(e.SitesDir, "Sites directory"); err != nil {
		return err
	}
	if err := checkDir(e.DataDir, "Data directory"); err != nil {
		return err
	}
	return nil
}

func checkDir(dir string, name string) error {
	src, err := os.Stat(dir)
	if err != nil {
		return errors.New(fmt.Sprintf("%s does not exist: %s", name, dir))
	}
	if !src.IsDir() {
		return errors.New(fmt.Sprintf("%s is not a directory: ", name, dir))
	}
	return nil
}

// Assert whether the environment requires docker machine to run
func (e *Environment) RequiresMachine() bool {
	return runtime.GOOS == "darwin"
}

// Get the docker machine instance for the environment.
func (e *Environment) GetMachine() *Machine {
	return &Machine{Name: e.MachineName}
}
<|endoftext|>