<commit_before>package v3

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
	. "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	archive_helpers "github.com/pivotal-golang/archiver/extractor/test_helper"
)

var _ = Describe("buildpack", func() {
	var (
		appName       string
		appGuid       string
		buildpackName string
		buildpackGuid string
		packageGuid   string
		spaceGuid     string
		token         string
	)

	BeforeEach(func() {
		appName = generator.PrefixedRandomName("CATS-APP-")
		spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space)
		appGuid = CreateApp(appName, spaceGuid, "{}")
		packageGuid = CreatePackage(appGuid)
		token = GetAuthToken()
		uploadUrl := fmt.Sprintf("%s/v3/packages/%s/upload", config.ApiEndpoint, packageGuid)
		UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token)
		WaitForPackageToBeReady(packageGuid)

		buildpackName = generator.PrefixedRandomName("CATS-BP-")
		buildpackZip := createBuildpack()

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})

		session := cf.Cf("curl", fmt.Sprintf("/v2/buildpacks?q=name:%s", buildpackName))
		bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
		var buildpack struct {
			Resources []struct {
				Metadata struct {
					Guid string `json:"guid"`
				} `json:"metadata"`
			} `json:"resources"`
		}
		json.Unmarshal(bytes, &buildpack)
		buildpackGuid = buildpack.Resources[0].Metadata.Guid
	})

	AfterEach(func() {
		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
	})

	XIt("Stages with a user specified admin buildpack", func() {
		dropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			return session
		}, 1*time.Minute, 10*time.Second).Should(Say("STAGED WITH CUSTOM BUILDPACK"))
	})

	XIt("Stages with a user specified github buildpack", func() {
		dropletGuid := StagePackage(packageGuid, `{"buildpack":"http://github.com/cloudfoundry/go-buildpack"}`)

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			fmt.Println(string(session.Out.Contents()))
			return session
		}, 3*time.Minute, 10*time.Second).Should(Say("Cloning into"))
	})

	It("uses buildpack cache for staging", func() {
		firstDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))
		dropletPath := fmt.Sprintf("/v3/droplets/%s", firstDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - cache not found"))

		// Wait for buildpack cache to be uploaded to blobstore.
		time.Sleep(DEFAULT_TIMEOUT)

		secondDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))
		dropletPath = fmt.Sprintf("/v3/droplets/%s", secondDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			if strings.Contains(string(result.Out.Contents()), "cache not found") {
				Fail("cache was not found")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - here's a cache"))

		Expect(secondDropletGuid).NotTo(Equal(firstDropletGuid))
	})
})

func createBuildpack() string {
	tmpPath, err := ioutil.TempDir("", "buildpack-cats")
	Expect(err).ToNot(HaveOccurred())

	buildpackArchivePath := path.Join(tmpPath, "buildpack.zip")

	archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
		{
			Name: "bin/compile",
			Body: `#!/usr/bin/env bash

echo "STAGED WITH CUSTOM BUILDPACK"

mkdir -p $1 $2
if [ -f "$2/cached-file" ]; then
cp $2/cached-file $1/content
else
echo "cache not found" > $1/content
fi

content=$(cat $1/content)
echo "web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done" > $1/Procfile

echo "here's a cache" > $2/cached-file
`,
		},
		{
			Name: "bin/detect",
			Body: `#!/bin/bash
echo no
exit 1
`,
		},
		{
			Name: "bin/release",
			Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
PATH: bin:/usr/local/bin:/usr/bin:/bin
FROM_BUILD_PACK: "yes"
default_process_types:
web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done
EOF
`,
		},
	})

	return buildpackArchivePath
}
<commit_msg>update test buildpack to output proper yml in the release<commit_after>package v3

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
	. "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	archive_helpers "github.com/pivotal-golang/archiver/extractor/test_helper"
)

var _ = Describe("buildpack", func() {
	var (
		appName       string
		appGuid       string
		buildpackName string
		buildpackGuid string
		packageGuid   string
		spaceGuid     string
		token         string
	)

	BeforeEach(func() {
		appName = generator.PrefixedRandomName("CATS-APP-")
		spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space)
		appGuid = CreateApp(appName, spaceGuid, "{}")
		packageGuid = CreatePackage(appGuid)
		token = GetAuthToken()
		uploadUrl := fmt.Sprintf("%s/v3/packages/%s/upload", config.ApiEndpoint, packageGuid)
		UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token)
		WaitForPackageToBeReady(packageGuid)

		buildpackName = generator.PrefixedRandomName("CATS-BP-")
		buildpackZip := createBuildpack()

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})

		session := cf.Cf("curl", fmt.Sprintf("/v2/buildpacks?q=name:%s", buildpackName))
		bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
		var buildpack struct {
			Resources []struct {
				Metadata struct {
					Guid string `json:"guid"`
				} `json:"metadata"`
			} `json:"resources"`
		}
		json.Unmarshal(bytes, &buildpack)
		buildpackGuid = buildpack.Resources[0].Metadata.Guid
	})

	AfterEach(func() {
		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
	})

	XIt("Stages with a user specified admin buildpack", func() {
		dropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			return session
		}, 1*time.Minute, 10*time.Second).Should(Say("STAGED WITH CUSTOM BUILDPACK"))
	})

	XIt("Stages with a user specified github buildpack", func() {
		dropletGuid := StagePackage(packageGuid, `{"buildpack":"http://github.com/cloudfoundry/go-buildpack"}`)

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			fmt.Println(string(session.Out.Contents()))
			return session
		}, 3*time.Minute, 10*time.Second).Should(Say("Cloning into"))
	})

	It("uses buildpack cache for staging", func() {
		firstDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))
		dropletPath := fmt.Sprintf("/v3/droplets/%s", firstDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - cache not found"))

		// Wait for buildpack cache to be uploaded to blobstore.
		time.Sleep(DEFAULT_TIMEOUT)

		secondDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))
		dropletPath = fmt.Sprintf("/v3/droplets/%s", secondDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			if strings.Contains(string(result.Out.Contents()), "cache not found") {
				Fail("cache was not found")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - here's a cache"))

		Expect(secondDropletGuid).NotTo(Equal(firstDropletGuid))
	})
})

func createBuildpack() string {
	tmpPath, err := ioutil.TempDir("", "buildpack-cats")
	Expect(err).ToNot(HaveOccurred())

	buildpackArchivePath := path.Join(tmpPath, "buildpack.zip")

	archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
		{
			Name: "bin/compile",
			Body: `#!/usr/bin/env bash

echo "STAGED WITH CUSTOM BUILDPACK"

mkdir -p $1 $2
if [ -f "$2/cached-file" ]; then
cp $2/cached-file $1/content
else
echo "cache not found" > $1/content
fi

content=$(cat $1/content)
echo "web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done" > $1/Procfile

echo "here's a cache" > $2/cached-file
`,
		},
		{
			Name: "bin/detect",
			Body: `#!/bin/bash
echo no
exit 1
`,
		},
		{
			Name: "bin/release",
			Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done
EOF
`,
		},
	})

	return buildpackArchivePath
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
// Package: easygen
// Purpose: Easy to use universal code/text generator
// Authors: Tong Sun (c) 2015-17, All rights reserved
////////////////////////////////////////////////////////////////////////////

/*

Package easygen is an easy to use universal code/text generator library.

It can be used as a text or html generator for arbitrary purposes with arbitrary data and templates.

It can be used as a code generator, or anything that is structurally repetitive. Some command line parameter handling code generator are provided as examples, including the Go's built-in flag package, and the viper & cobra package.

Many examples have been provided to showcase its functionality, and different ways to use it.

*/
package easygen

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	tt "text/template"

	"gopkg.in/yaml.v2"
)

////////////////////////////////////////////////////////////////////////////
// Constant and data type/structure definitions

////////////////////////////////////////////////////////////////////////////
// Global variables definitions

// EgData -- EasyGen driven Data
type EgData map[interface{}]interface{}

// Opts holds the actual values from the command line parameters
var Opts = Options{ExtYaml: ".yaml", ExtTmpl: ".tmpl"}

////////////////////////////////////////////////////////////////////////////
// Function definitions

// Generate2 will produce output according to the given template and driving data files,
// specified via fileNameTempl and fileNames (for data) respectively.
func Generate2(HTML bool, fileNameTempl string, fileNames ...string) (ret string) {
	Opts.TemplateFile = fileNameTempl

	for _, fileName := range fileNames {
		ret += Generate(HTML, fileName)
	}
	Opts.TemplateFile = ""
	return ret
}

// Generate0 will produce output according from driving data without a template file, using the string from strTempl as the template
func Generate0(HTML bool, strTempl string, fileName string) string {
	Opts.TemplateStr = strTempl
	ret := Generate(HTML, fileName)
	Opts.TemplateStr = ""
	return ret
}

// Generate will produce output from the template according to the corresponding driving data, fileName is for both template and data file name
func Generate(HTML bool, fileName string) string {
	var templates []string

	// Allow to use fileName with and without the @Opts.ExtYaml suffix.
	// If both <file>.yaml and <file> exist, prefer <file>.yaml.
	if _, err := os.Stat(fileName + Opts.ExtYaml); err == nil {
		fileName += Opts.ExtYaml
	} else if _, err = os.Stat(fileName); os.IsNotExist(err) {
		fileName += Opts.ExtYaml
	}

	// Allow to use @Opts.TemplateFile without the @Opts.ExtTmpl suffix.
	if len(Opts.TemplateFile) > 0 {
		for _, template := range strings.Split(Opts.TemplateFile, ",") {
			if _, err := os.Stat(template); os.IsNotExist(err) {
				template += Opts.ExtTmpl
			}
			templates = append(templates, template)
		}
	} else if idx := strings.LastIndex(fileName, "."); idx > 0 {
		templates = []string{fileName[:idx] + Opts.ExtTmpl}
	} else {
		templates = []string{fileName + Opts.ExtTmpl}
	}

	m := ReadYamlFile(fileName)

	env := make(map[string]string)
	for _, e := range os.Environ() {
		sep := strings.Index(e, "=")
		env[e[0:sep]] = e[sep+1:]
	}
	m["ENV"] = env
	//fmt.Printf("] %+v\n", m)

	buf := new(bytes.Buffer)
	for _, template := range templates {
		t, err := ParseFiles(HTML, template)
		checkError(err)

		err = t.Execute(buf, m)
		checkError(err)
	}
	return buf.String()
}

// ParseFiles wraps parsing text or HTML template files into a single
// function, dictated by the first parameter "HTML".
// By Matt Harden @gmail.com
func ParseFiles(HTML bool, filenames ...string) (Template, error) {
	var tname string

	if len(Opts.TemplateStr) > 0 {
		tname = "TT"
	} else if len(filenames) == 0 {
		return nil, fmt.Errorf("ParseFiles called without template filename")
	} else {
		tname = filepath.Base(filenames[0])
	}

	textTemplate := tt.New(tname).Funcs(tt.FuncMap{
		"eqf":      strings.EqualFold,
		"split":    strings.Fields,
		"minus1":   minus1,
		"dateI":    dateI,
		"year4":    year4,
		"replace":  replace,
		"replacec": replacec,
	})

	if len(Opts.TemplateStr) > 0 {
		return textTemplate.Parse(Opts.TemplateStr)
	}
	return textTemplate.ParseFiles(filenames...)
}

////////////////////////////////////////////////////////////////////////////
// Version 2 Function definitions

// ReadDataFile reads in the driving data from the given file, which can
// be optionally without the defined extension
func ReadDataFile(fileName string) EgData {
	if IsExist(fileName + Opts.ExtYaml) {
		return ReadYamlFile(fileName + Opts.ExtYaml)
	} else if IsExist(fileName) {
		return ReadYamlFile(fileName)
	} else {
		checkError(errors.
			New(fmt.Sprintf("DataFile '%s' cannot be found", fileName)))
	}
	return make(EgData)
}

// ReadYamlFile reads given YAML file as EgData
func ReadYamlFile(fileName string) EgData {
	source, err := ioutil.ReadFile(fileName)
	checkError(err)

	m := make(EgData)

	err = yaml.Unmarshal(source, &m)
	checkError(err)

	return m
}

// IsExist checks if the given file exist
func IsExist(fileName string) bool {
	//fmt.Printf("] Checking %s\n", fileName)
	_, err := os.Stat(fileName)
	return err == nil || os.IsExist(err)
	// CAUTION! os.IsExist(err) != !os.IsNotExist(err)
	// https://gist.github.com/mastef/05f46d3ab2f5ed6a6787#file-isexist_vs_isnotexist-go-L35-L56
}

// GetEnv returns the Environment variables in a map
func GetEnv() map[string]string {
	env := make(map[string]string)
	for _, e := range os.Environ() {
		sep := strings.Index(e, "=")
		env[e[0:sep]] = e[sep+1:]
	}
	return env
}

// Process will process the standard easygen input: the `fileName` is for both template and data file names, and produce output from the template according to the corresponding driving data.
func Process(t Template, wr io.Writer, fileNames ...string) error {
	return Process2(t, wr, fileNames[0], fileNames...)
}

// Process2 will process the case that *both* template and data file names are given, and produce output according to the given template and driving data files,
// specified via fileNameTempl and fileNames respectively.
// fileNameTempl can be a comma-separated string giving many template files
func Process2(t Template, wr io.Writer, fileNameTempl string, fileNames ...string) error {
	if len(Opts.TemplateFile) > 0 {
		fileNameTempl = Opts.TemplateFile
	}
	for _, dataFn := range fileNames {
		for _, templateFn := range strings.Split(fileNameTempl, ",") {
			err := Process1(t, wr, templateFn, dataFn)
			checkError(err)
		}
	}
	return nil
}

// Process1 will process a *single* case where both template and data file names are given, and produce output according to the given template and driving data files,
// specified via fileNameTempl and fileName respectively.
// fileNameTempl is not a comma-separated string, but for a single template file.
func Process1(t Template, wr io.Writer, fileNameTempl string, fileName string) error {
	m := ReadDataFile(fileName)
	m["ENV"] = GetEnv()
	//fmt.Printf("] %+v\n", m)

	// template file
	fileName = fileNameTempl
	fileNameT := fileNameTempl
	if IsExist(fileName + Opts.ExtTmpl) {
		fileNameT = fileName + Opts.ExtTmpl
	} else {
		// guard against that fileNameTempl passed with Opts.ExtYaml extension
		if fileName[len(fileName)-len(Opts.ExtYaml):] == Opts.ExtYaml {
			idx := strings.LastIndex(fileName, ".")
			fileName = fileName[:idx]
			if IsExist(fileName + Opts.ExtTmpl) {
				fileNameT = fileName + Opts.ExtTmpl
			}
		} else if IsExist(fileName) {
			// fileNameTempl passed with Opts.ExtTmpl already
			fileNameT = fileName
		}
	}
	// catch all
	if !IsExist(fileNameT) {
		checkError(errors.
			New(fmt.Sprintf("Template file '%s' cannot be found", fileNameTempl)))
	}

	tn, err := t.ParseFiles(fileNameT)
	checkError(err)

	return tn.ExecuteTemplate(wr, filepath.Base(fileNameT), m)
}

// Process0 will produce output according to the driving data *without* a template file, using the string from strTempl as the template
func Process0(t Template, wr io.Writer, strTempl string, fileNames ...string) error {
	fileName := fileNames[0]
	m := ReadDataFile(fileName)
	m["ENV"] = GetEnv()

	tmpl, err := t.Parse(strTempl)
	checkError(err)
	return tmpl.Execute(wr, m)
}

////////////////////////////////////////////////////////////////////////////
// Support Function definitions

// Exit if error occurs
func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "[%s] Fatal error - %s\n", progname, err)
		os.Exit(1)
	}
}
<commit_msg>- [*] fixing for golint, use fmt.Errorf() to replace errors.New(fmt.Sprintf())<commit_after>////////////////////////////////////////////////////////////////////////////
// Package: easygen
// Purpose: Easy to use universal code/text generator
// Authors: Tong Sun (c) 2015-17, All rights reserved
////////////////////////////////////////////////////////////////////////////

/*

Package easygen is an easy to use universal code/text generator library.

It can be used as a text or html generator for arbitrary purposes with arbitrary data and templates.

It can be used as a code generator, or anything that is structurally repetitive. Some command line parameter handling code generator are provided as examples, including the Go's built-in flag package, and the viper & cobra package.

Many examples have been provided to showcase its functionality, and different ways to use it.

*/
package easygen

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	tt "text/template"

	"gopkg.in/yaml.v2"
)

////////////////////////////////////////////////////////////////////////////
// Constant and data type/structure definitions

////////////////////////////////////////////////////////////////////////////
// Global variables definitions

// EgData -- EasyGen driven Data
type EgData map[interface{}]interface{}

// Opts holds the actual values from the command line parameters
var Opts = Options{ExtYaml: ".yaml", ExtTmpl: ".tmpl"}

////////////////////////////////////////////////////////////////////////////
// Function definitions

// Generate2 will produce output according to the given template and driving data files,
// specified via fileNameTempl and fileNames (for data) respectively.
func Generate2(HTML bool, fileNameTempl string, fileNames ...string) (ret string) {
	Opts.TemplateFile = fileNameTempl

	for _, fileName := range fileNames {
		ret += Generate(HTML, fileName)
	}
	Opts.TemplateFile = ""
	return ret
}

// Generate0 will produce output according from driving data without a template file, using the string from strTempl as the template
func Generate0(HTML bool, strTempl string, fileName string) string {
	Opts.TemplateStr = strTempl
	ret := Generate(HTML, fileName)
	Opts.TemplateStr = ""
	return ret
}

// Generate will produce output from the template according to the corresponding driving data, fileName is for both template and data file name
func Generate(HTML bool, fileName string) string {
	var templates []string

	// Allow to use fileName with and without the @Opts.ExtYaml suffix.
	// If both <file>.yaml and <file> exist, prefer <file>.yaml.
	if _, err := os.Stat(fileName + Opts.ExtYaml); err == nil {
		fileName += Opts.ExtYaml
	} else if _, err = os.Stat(fileName); os.IsNotExist(err) {
		fileName += Opts.ExtYaml
	}

	// Allow to use @Opts.TemplateFile without the @Opts.ExtTmpl suffix.
	if len(Opts.TemplateFile) > 0 {
		for _, template := range strings.Split(Opts.TemplateFile, ",") {
			if _, err := os.Stat(template); os.IsNotExist(err) {
				template += Opts.ExtTmpl
			}
			templates = append(templates, template)
		}
	} else if idx := strings.LastIndex(fileName, "."); idx > 0 {
		templates = []string{fileName[:idx] + Opts.ExtTmpl}
	} else {
		templates = []string{fileName + Opts.ExtTmpl}
	}

	m := ReadYamlFile(fileName)

	env := make(map[string]string)
	for _, e := range os.Environ() {
		sep := strings.Index(e, "=")
		env[e[0:sep]] = e[sep+1:]
	}
	m["ENV"] = env
	//fmt.Printf("] %+v\n", m)

	buf := new(bytes.Buffer)
	for _, template := range templates {
		t, err := ParseFiles(HTML, template)
		checkError(err)

		err = t.Execute(buf, m)
		checkError(err)
	}
	return buf.String()
}

// ParseFiles wraps parsing text or HTML template files into a single
// function, dictated by the first parameter "HTML".
// By Matt Harden @gmail.com
func ParseFiles(HTML bool, filenames ...string) (Template, error) {
	var tname string

	if len(Opts.TemplateStr) > 0 {
		tname = "TT"
	} else if len(filenames) == 0 {
		return nil, fmt.Errorf("ParseFiles called without template filename")
	} else {
		tname = filepath.Base(filenames[0])
	}

	textTemplate := tt.New(tname).Funcs(tt.FuncMap{
		"eqf":      strings.EqualFold,
		"split":    strings.Fields,
		"minus1":   minus1,
		"dateI":    dateI,
		"year4":    year4,
		"replace":  replace,
		"replacec": replacec,
	})

	if len(Opts.TemplateStr) > 0 {
		return textTemplate.Parse(Opts.TemplateStr)
	}
	return textTemplate.ParseFiles(filenames...)
}

////////////////////////////////////////////////////////////////////////////
// Version 2 Function definitions

// ReadDataFile reads in the driving data from the given file, which can
// be optionally without the defined extension
func ReadDataFile(fileName string) EgData {
	if IsExist(fileName + Opts.ExtYaml) {
		return ReadYamlFile(fileName + Opts.ExtYaml)
	} else if IsExist(fileName) {
		return ReadYamlFile(fileName)
	} else {
		checkError(fmt.Errorf("DataFile '%s' cannot be found", fileName))
	}
	return make(EgData)
}

// ReadYamlFile reads given YAML file as EgData
func ReadYamlFile(fileName string) EgData {
	source, err := ioutil.ReadFile(fileName)
	checkError(err)

	m := make(EgData)

	err = yaml.Unmarshal(source, &m)
	checkError(err)

	return m
}

// IsExist checks if the given file exist
func IsExist(fileName string) bool {
	//fmt.Printf("] Checking %s\n", fileName)
	_, err := os.Stat(fileName)
	return err == nil || os.IsExist(err)
	// CAUTION! os.IsExist(err) != !os.IsNotExist(err)
	// https://gist.github.com/mastef/05f46d3ab2f5ed6a6787#file-isexist_vs_isnotexist-go-L35-L56
}

// GetEnv returns the Environment variables in a map
func GetEnv() map[string]string {
	env := make(map[string]string)
	for _, e := range os.Environ() {
		sep := strings.Index(e, "=")
		env[e[0:sep]] = e[sep+1:]
	}
	return env
}

// Process will process the standard easygen input: the `fileName` is for both template and data file names, and produce output from the template according to the corresponding driving data.
func Process(t Template, wr io.Writer, fileNames ...string) error {
	return Process2(t, wr, fileNames[0], fileNames...)
}

// Process2 will process the case that *both* template and data file names are given, and produce output according to the given template and driving data files,
// specified via fileNameTempl and fileNames respectively.
// fileNameTempl can be a comma-separated string giving many template files
func Process2(t Template, wr io.Writer, fileNameTempl string, fileNames ...string) error {
	if len(Opts.TemplateFile) > 0 {
		fileNameTempl = Opts.TemplateFile
	}
	for _, dataFn := range fileNames {
		for _, templateFn := range strings.Split(fileNameTempl, ",") {
			err := Process1(t, wr, templateFn, dataFn)
			checkError(err)
		}
	}
	return nil
}

// Process1 will process a *single* case where both template and data file names are given, and produce output according to the given template and driving data files,
// specified via fileNameTempl and fileName respectively.
// fileNameTempl is not a comma-separated string, but for a single template file.
func Process1(t Template, wr io.Writer, fileNameTempl string, fileName string) error {
	m := ReadDataFile(fileName)
	m["ENV"] = GetEnv()
	//fmt.Printf("] %+v\n", m)

	// template file
	fileName = fileNameTempl
	fileNameT := fileNameTempl
	if IsExist(fileName + Opts.ExtTmpl) {
		fileNameT = fileName + Opts.ExtTmpl
	} else {
		// guard against that fileNameTempl passed with Opts.ExtYaml extension
		if fileName[len(fileName)-len(Opts.ExtYaml):] == Opts.ExtYaml {
			idx := strings.LastIndex(fileName, ".")
			fileName = fileName[:idx]
			if IsExist(fileName + Opts.ExtTmpl) {
				fileNameT = fileName + Opts.ExtTmpl
			}
		} else if IsExist(fileName) {
			// fileNameTempl passed with Opts.ExtTmpl already
			fileNameT = fileName
		}
	}
	// catch all
	if !IsExist(fileNameT) {
		checkError(fmt.Errorf("Template file '%s' cannot be found", fileNameTempl))
	}

	tn, err := t.ParseFiles(fileNameT)
	checkError(err)

	return tn.ExecuteTemplate(wr, filepath.Base(fileNameT), m)
}

// Process0 will produce output according to the driving data *without* a template file, using the string from strTempl as the template
func Process0(t Template, wr io.Writer, strTempl string, fileNames ...string) error {
	fileName := fileNames[0]
	m := ReadDataFile(fileName)
	m["ENV"] = GetEnv()

	tmpl, err := t.Parse(strTempl)
	checkError(err)
	return tmpl.Execute(wr, m)
}

////////////////////////////////////////////////////////////////////////////
// Support Function definitions

// Exit if error occurs
func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "[%s] Fatal error - %s\n", progname, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package stash

import (
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/BurntSushi/toml"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite" // Needed for GORM
	homedir "github.com/mitchellh/go-homedir"
)

const (
	confFile = "stash.conf"
	dbFile   = "index.db"

	logDir  = ".cache/stash/logs"
	confDir = ".config/stash"
)

// Stash stashes a file or directory by wrapping it into a compressed tar archive.
func Stash(db *gorm.DB, source string, destination string) error {
	if source == "" || destination == "" {
		return fmt.Errorf("\"%v\" or \"%v\" is not a valid path", source, destination)
	}

	if db == nil {
		return fmt.Errorf("DB was nil")
	}

	//NOTE: Destination must always be a directory.

	absPath, err := filepath.Abs(source)
	if err != nil {
		return err
	}

	entry := &Entry{}
	db.Where("path = ?", absPath).First(entry)
	if entry.ID != 0 {
		return errors.New("Entry exist already in database")
	}

	hasher := sha1.New()
	log.Printf("Using path: %v\n", absPath)
	file, err := os.Create(filepath.Join(destination, encodeChecksum(computeChecksum(absPath, hasher), base64.URLEncoding)) + ".tar.gz")
	if err != nil {
		return err
	}

	if err := Pack(source, file); err != nil {
		return err
	}

	entry = &Entry{Path: absPath}
	db.Create(entry)

	workingDir, err := os.Getwd()
	if err != nil {
		return err
	}

	if err := os.Chdir(filepath.Dir(absPath)); err != nil {
		return err
	}
	if err := os.RemoveAll(source); err != nil {
		return err
	}
	if err := os.Chdir(workingDir); err != nil {
		return err
	}

	return nil
}

// Release gets a file or directory from the stash and writes it to destination.
func Release(db *gorm.DB, source string, target string, destination string) error {
	if source == "" || destination == "" || target == "" {
		return fmt.Errorf("\"%v\" or \"%v\" or \"%v\" is not a valid path", source, destination, target)
	}

	absPath, err := filepath.Abs(target)
	if err != nil {
		return err
	}

	hasher := sha1.New()
	log.Printf("Using path: %v\n", absPath)
	file, err := os.Open(filepath.Join(source, encodeChecksum(computeChecksum(absPath, hasher), base64.URLEncoding)) + ".tar.gz")
	if err != nil {
		return err
	}

	if err := Unpack(destination, file); err != nil {
		return err
	}

	db.Where("path = ?", absPath).Delete(&Entry{})

	return nil
}

// List lists all stashed objects that match the source path.
func List(db *gorm.DB, source string) error {
	if db == nil {
		return fmt.Errorf("Db was nil")
	}

	absPath, err := filepath.Abs(source)
	if err != nil {
		return err
	}

	entries := []Entry{}
	db.Where("path LIKE ?", fmt.Sprintf("%s%%", absPath)).Find(&entries)

	for _, entry := range entries {
		fmt.Printf("%v\n", entry.Path)
	}
	return nil
}

// Init initalizes the environment by creating directories, databases and configuration files
// needed by the application.
func Init(path string) error {
	if path == "" {
		return fmt.Errorf("You have specified an invalid directory")
	}

	// Get the absolute path to our target directory and create any directories that are missing.
	absPath, err := filepath.Abs(path)
	if err != nil {
		log.Printf("%v\n", err)
		return fmt.Errorf("Can not find absolute path of \"%v\"", path)
	}

	if err := os.MkdirAll(absPath, 0644); err != nil {
		log.Printf("%v\n", err)
		return fmt.Errorf("Can not create directory")
	}

	// Create the database in the newly created directory.
	dbPath := filepath.Join(absPath, dbFile)
	db, err := gorm.Open("sqlite3", dbPath)
	if err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not create database file")
	}

	if !db.HasTable(&Entry{}) {
		db.CreateTable(&Entry{})
	}

	// Create the log file directory
	homePath, err := homedir.Dir()
	logPath := filepath.Join(homePath, logDir)
	if err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not retrieve home directory for current user")
	}

	if err := os.MkdirAll(logPath, 0755); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not create log directory")
	}

	config := Config{
		DataDir: absPath,
		LogDir:  logPath,
	}

	var buffer bytes.Buffer
	encoder := toml.NewEncoder(&buffer)
	if err := encoder.Encode(&config); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Could not encode configuration file to TOML.")
	}

	confPath := filepath.Join(homePath, confDir)
	if err := os.MkdirAll(confPath, 0755); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not create config directory")
	}

	confPath = filepath.Join(confPath, confFile)
	if err := ioutil.WriteFile(confPath, buffer.Bytes(), 0644); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not write to configuration file")
	}

	return nil
}
<commit_msg>Refine list output<commit_after>package stash

import (
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/BurntSushi/toml"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite" // Needed for GORM
	homedir "github.com/mitchellh/go-homedir"
)

const (
	confFile = "stash.conf"
	dbFile   = "index.db"

	logDir  = ".cache/stash/logs"
	confDir = ".config/stash"
)

// Stash stashes a file or directory by wrapping it into a compressed tar archive.
func Stash(db *gorm.DB, source string, destination string) error {
	if source == "" || destination == "" {
		return fmt.Errorf("\"%v\" or \"%v\" is not a valid path", source, destination)
	}

	if db == nil {
		return fmt.Errorf("DB was nil")
	}

	//NOTE: Destination must always be a directory.

	absPath, err := filepath.Abs(source)
	if err != nil {
		return err
	}

	entry := &Entry{}
	db.Where("path = ?", absPath).First(entry)
	if entry.ID != 0 {
		return errors.New("Entry exist already in database")
	}

	hasher := sha1.New()
	log.Printf("Using path: %v\n", absPath)
	file, err := os.Create(filepath.Join(destination, encodeChecksum(computeChecksum(absPath, hasher), base64.URLEncoding)) + ".tar.gz")
	if err != nil {
		return err
	}

	if err := Pack(source, file); err != nil {
		return err
	}

	entry = &Entry{Path: absPath}
	db.Create(entry)

	workingDir, err := os.Getwd()
	if err != nil {
		return err
	}

	if err := os.Chdir(filepath.Dir(absPath)); err != nil {
		return err
	}
	if err := os.RemoveAll(source); err != nil {
		return err
	}
	if err := os.Chdir(workingDir); err != nil {
		return err
	}

	return nil
}

// Release gets a file or directory from the stash and writes it to destination.
func Release(db *gorm.DB, source string, target string, destination string) error {
	if source == "" || destination == "" || target == "" {
		return fmt.Errorf("\"%v\" or \"%v\" or \"%v\" is not a valid path", source, destination, target)
	}

	absPath, err := filepath.Abs(target)
	if err != nil {
		return err
	}

	hasher := sha1.New()
	log.Printf("Using path: %v\n", absPath)
	file, err := os.Open(filepath.Join(source, encodeChecksum(computeChecksum(absPath, hasher), base64.URLEncoding)) + ".tar.gz")
	if err != nil {
		return err
	}

	if err := Unpack(destination, file); err != nil {
		return err
	}

	db.Where("path = ?", absPath).Delete(&Entry{})

	return nil
}

// List lists all stashed objects that match the source path.
func List(db *gorm.DB, source string) error {
	if db == nil {
		return fmt.Errorf("Db was nil")
	}

	absPath, err := filepath.Abs(source)
	if err != nil {
		return err
	}

	entries := []Entry{}
	db.Where("path LIKE ?", fmt.Sprintf("%s%%", absPath)).Find(&entries)

	if len(entries) == 0 {
		fmt.Printf("No entries found.\n")
		return nil
	}

	fmt.Printf("The following entries were found: \n")
	for i, entry := range entries {
		name := filepath.Base(entry.Path)
		date := entry.CreatedAt.Format("2006-01-02 15:04")
		fmt.Printf("%v: %v\t%v\n", i, name, date)
	}
	return nil
}

// Init initalizes the environment by creating directories, databases and configuration files
// needed by the application.
func Init(path string) error {
	if path == "" {
		return fmt.Errorf("You have specified an invalid directory")
	}

	// Get the absolute path to our target directory and create any directories that are missing.
	absPath, err := filepath.Abs(path)
	if err != nil {
		log.Printf("%v\n", err)
		return fmt.Errorf("Can not find absolute path of \"%v\"", path)
	}

	if err := os.MkdirAll(absPath, 0644); err != nil {
		log.Printf("%v\n", err)
		return fmt.Errorf("Can not create directory")
	}

	// Create the database in the newly created directory.
	dbPath := filepath.Join(absPath, dbFile)
	db, err := gorm.Open("sqlite3", dbPath)
	if err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not create database file")
	}

	if !db.HasTable(&Entry{}) {
		db.CreateTable(&Entry{})
	}

	// Create the log file directory
	homePath, err := homedir.Dir()
	logPath := filepath.Join(homePath, logDir)
	if err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not retrieve home directory for current user")
	}

	if err := os.MkdirAll(logPath, 0755); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not create log directory")
	}

	config := Config{
		DataDir: absPath,
		LogDir:  logPath,
	}

	var buffer bytes.Buffer
	encoder := toml.NewEncoder(&buffer)
	if err := encoder.Encode(&config); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Could not encode configuration file to TOML.")
	}

	confPath := filepath.Join(homePath, confDir)
	if err := os.MkdirAll(confPath, 0755); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not create config directory")
	}

	confPath = filepath.Join(confPath, confFile)
	if err := ioutil.WriteFile(confPath, buffer.Bytes(), 0644); err != nil {
		log.Printf("Init: %v\n", err)
		return fmt.Errorf("Can not write to configuration file")
	}

	return nil
}
<|endoftext|>


<commit_before>package re_test

import (
	"fmt"
	"re"
	"regexp"
	"strconv"
	"time"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func ExampleFind() {
	// A regexp that matches a line of simplified ls -l output.
	r := regexp.MustCompile(`^(.{10}) +(\d+) +(\w+) +(\w+) +(\d+) +(\S+) +(\S+)`)
	var s struct {
		mode, user, group, date, name string
		nlinks, size                  int64
	}
	err := re.Find(r, []byte("-rwxr-xr-x 1 root root 110080 2014-03-24  /bin/ls"),
		&s.mode, &s.nlinks, &s.user, &s.group, &s.size, &s.date, &s.name)
	check(err)
	fmt.Printf("%+v\n", s)
	// Output:
	// {mode:-rwxr-xr-x user:root group:root date:2014-03-24 name:/bin/ls nlinks:1 size:110080}
}

func ExampleFind_customParsing() {
	// Define a function that parses a number in binary.
	var number uint64
	parseBinary := func(b []byte) (err error) {
		number, err = strconv.ParseUint(string(b), 2, 64)
		return err
	}

	r := regexp.MustCompile(`([01]+)`)
	err := re.Find(r, []byte("1001"), parseBinary)
	check(err)
	fmt.Println(number)
	// Output:
	// 9
}

func ExampleFind_supportNewType() {
	// A function that returns a custom parser that parses into
	// the specified *time.Duration.
	parseDuration := func(d *time.Duration) func([]byte) error {
		return func(b []byte) (err error) {
			*d, err = time.ParseDuration(string(b))
			return err
		}
	}

	r := regexp.MustCompile(`(.*)`)
	var interval time.Duration
	err := re.Find(r, []byte("3m20s"), parseDuration(&interval))
	check(err)
	fmt.Println(interval)
	// Output:
	// 3m20s
}
<commit_msg>small tweaks<commit_after>package re_test

import (
	"fmt"
	"re"
	"regexp"
	"strconv"
	"time"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

// Parse a line of ls -l output into its fields.
func ExampleFind() {
	var f struct {
		mode, user, group, date, name string
		nlinks, size                  int64
	}
	// A regexp that matches a line of simplified ls -l output.
	r := regexp.MustCompile(`^(.{10}) +(\d+) +(\w+) +(\w+) +(\d+) +(\S+) +(\S+)`)
	err := re.Find(r, []byte("-rwxr-xr-x 1 root root 110080 2014-03-24  /bin/ls"),
		&f.mode, &f.nlinks, &f.user, &f.group, &f.size, &f.date, &f.name)
	check(err)
	fmt.Printf("%+v\n", f)
	// Output:
	// {mode:-rwxr-xr-x user:root group:root date:2014-03-24 name:/bin/ls nlinks:1 size:110080}
}

// Use a custom parsing function that parses a number in binary.
func ExampleFind_customParsing() {
	var number uint64
	parseBinary := func(b []byte) (err error) {
		number, err = strconv.ParseUint(string(b), 2, 64)
		return err
	}

	r := regexp.MustCompile(`([01]+)`)
	err := re.Find(r, []byte("1001"), parseBinary)
	check(err)
	fmt.Println(number)
	// Output:
	// 9
}

// Define a reusable mechanism for parsing time.Duration and use it.
func ExampleFind_supportNewType() {
	parseDuration := func(d *time.Duration) func([]byte) error {
		return func(b []byte) (err error) {
			*d, err = time.ParseDuration(string(b))
			return err
		}
	}

	r := regexp.MustCompile(`(.*)`)
	var interval time.Duration
	err := re.Find(r, []byte("3m20s"), parseDuration(&interval))
	check(err)
	fmt.Println(interval)
	// Output:
	// 3m20s
}
<|endoftext|>


<commit_before>package s3

import (
	"net/http"
	"net/url"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/graymeta/stow"
	"github.com/pkg/errors"
)

// Kind represents the name of the location/storage type.
const Kind = "s3"

const (
	// ConfigAuthType is an optional argument that defines whether to use an IAM role or access key based auth
	ConfigAuthType = "auth_type"

	// ConfigAccessKeyID is one key of a pair of AWS credentials.
	ConfigAccessKeyID = "access_key_id"

	// ConfigSecretKey is one key of a pair of AWS credentials.
	ConfigSecretKey = "secret_key"

	// ConfigToken is an optional argument which is required when providing
	// credentials with temporary access.
	// ConfigToken = "token"

	// ConfigRegion represents the region/availability zone of the session.
	ConfigRegion = "region"

	// ConfigEndpoint is optional config value for changing s3 endpoint
	// used for e.g. minio.io
	ConfigEndpoint = "endpoint"

	// ConfigDisableSSL is optional config value for disabling SSL support on custom endpoints
	// Its default value is "false", to disable SSL set it to "true".
	ConfigDisableSSL = "disable_ssl"
)

func init() {

	makefn := func(config stow.Config) (stow.Location, error) {

		authType, ok := config.Config(ConfigAuthType)
		if !ok || authType == "" {
			authType = "accesskey"
		}

		if !(authType == "accesskey" || authType == "iam") {
			return nil, errors.New("invalid auth_type")
		}

		if authType == "accesskey" {
			_, ok := config.Config(ConfigAccessKeyID)
			if !ok {
				return nil, errors.New("missing Access Key ID")
			}

			_, ok = config.Config(ConfigSecretKey)
			if !ok {
				return nil, errors.New("missing Secret Key")
			}
		}

		_, ok = config.Config(ConfigRegion)
		if !ok {
			return nil, errors.New("missing Region")
		}

		// Create a new client (s3 session)
		client, err := newS3Client(config)
		if err != nil {
			return nil, err
		}

		// Create a location with given config and client (s3 session).
		loc := &location{
			config: config,
			client: client,
		}

		return loc, nil
	}

	kindfn := func(u *url.URL) bool {
		return u.Scheme == Kind
	}

	stow.Register(Kind, makefn, kindfn)
}

// Attempts to create a session based on the information given.
func newS3Client(config stow.Config) (*s3.S3, error) {
	authType, _ := config.Config(ConfigAuthType)
	accessKeyID, _ := config.Config(ConfigAccessKeyID)
	secretKey, _ := config.Config(ConfigSecretKey)
	//	token, _ := config.Config(ConfigToken)
	region, _ := config.Config(ConfigRegion)

	if authType == "" {
		authType = "accesskey"
	}

	awsConfig := aws.NewConfig().
		WithRegion(region).
		WithHTTPClient(http.DefaultClient).
		WithMaxRetries(aws.UseServiceDefaultRetries).
		WithLogger(aws.NewDefaultLogger()).
		WithLogLevel(aws.LogOff).
		WithSleepDelay(time.Sleep)

	if authType == "accesskey" {
		awsConfig.WithCredentials(credentials.NewStaticCredentials(accessKeyID, secretKey, ""))
	}

	endpoint, ok := config.Config(ConfigEndpoint)
	if ok {
		awsConfig.WithEndpoint(endpoint).
			WithS3ForcePathStyle(true)
	}

	disableSSL, ok := config.Config(ConfigDisableSSL)
	if ok && disableSSL == "true" {
		awsConfig.WithDisableSSL(true)
	}

	sess := session.New(awsConfig)
	if sess == nil {
		return nil, errors.New("creating the S3 session")
	}

	s3Client := s3.New(sess)

	return s3Client, nil
}
<commit_msg>Don't validate on region for s3<commit_after>package s3

import (
	"net/http"
	"net/url"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/graymeta/stow"
	"github.com/pkg/errors"
)

// Kind represents the name of the location/storage type.
const Kind = "s3"

const (
	// ConfigAuthType is an optional argument that defines whether to use an IAM role or access key based auth
	ConfigAuthType = "auth_type"

	// ConfigAccessKeyID is one key of a pair of AWS credentials.
	ConfigAccessKeyID = "access_key_id"

	// ConfigSecretKey is one key of a pair of AWS credentials.
	ConfigSecretKey = "secret_key"

	// ConfigToken is an optional argument which is required when providing
	// credentials with temporary access.
	// ConfigToken = "token"

	// ConfigRegion represents the region/availability zone of the session.
	ConfigRegion = "region"

	// ConfigEndpoint is optional config value for changing s3 endpoint
	// used for e.g. minio.io
	ConfigEndpoint = "endpoint"

	// ConfigDisableSSL is optional config value for disabling SSL support on custom endpoints
	// Its default value is "false", to disable SSL set it to "true".
	ConfigDisableSSL = "disable_ssl"
)

func init() {

	makefn := func(config stow.Config) (stow.Location, error) {

		authType, ok := config.Config(ConfigAuthType)
		if !ok || authType == "" {
			authType = "accesskey"
		}

		if !(authType == "accesskey" || authType == "iam") {
			return nil, errors.New("invalid auth_type")
		}

		if authType == "accesskey" {
			_, ok := config.Config(ConfigAccessKeyID)
			if !ok {
				return nil, errors.New("missing Access Key ID")
			}

			_, ok = config.Config(ConfigSecretKey)
			if !ok {
				return nil, errors.New("missing Secret Key")
			}
		}

		// Create a new client (s3 session)
		client, err := newS3Client(config)
		if err != nil {
			return nil, err
		}

		// Create a location with given config and client (s3 session).
		loc := &location{
			config: config,
			client: client,
		}

		return loc, nil
	}

	kindfn := func(u *url.URL) bool {
		return u.Scheme == Kind
	}

	stow.Register(Kind, makefn, kindfn)
}

// Attempts to create a session based on the information given.
func newS3Client(config stow.Config) (*s3.S3, error) {
	authType, _ := config.Config(ConfigAuthType)
	accessKeyID, _ := config.Config(ConfigAccessKeyID)
	secretKey, _ := config.Config(ConfigSecretKey)
	//	token, _ := config.Config(ConfigToken)

	if authType == "" {
		authType = "accesskey"
	}

	awsConfig := aws.NewConfig().
		WithHTTPClient(http.DefaultClient).
		WithMaxRetries(aws.UseServiceDefaultRetries).
		WithLogger(aws.NewDefaultLogger()).
		WithLogLevel(aws.LogOff).
		WithSleepDelay(time.Sleep)

	if region, ok := config.Config(ConfigRegion); ok {
		awsConfig.WithRegion(region)
	}

	if authType == "accesskey" {
		awsConfig.WithCredentials(credentials.NewStaticCredentials(accessKeyID, secretKey, ""))
	}

	endpoint, ok := config.Config(ConfigEndpoint)
	if ok {
		awsConfig.WithEndpoint(endpoint).
			WithS3ForcePathStyle(true)
	}

	disableSSL, ok := config.Config(ConfigDisableSSL)
	if ok && disableSSL == "true" {
		awsConfig.WithDisableSSL(true)
	}

	sess := session.New(awsConfig)
	if sess == nil {
		return nil, errors.New("creating the S3 session")
	}

	s3Client := s3.New(sess)

	return s3Client, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/balanceinfo"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingcredit"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/trades"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux"
)

func main() {
	m := mux.New().
		TransformRaw().
		WithAPIKEY("YOUR_API_KEY").
		WithAPISEC("YOUR_API_SECRET").
		Start()

	crash := make(chan error)

	go func() {
		crash <- m.Listen(func(msg interface{}, err error) {
			if err != nil {
				log.Printf("error received: %s\n", err)
			}

			switch v := msg.(type) {
			case event.Info:
				log.Printf("%T: %+v\n", v, v)
			case order.New:
				log.Printf("%T: %+v\n", v, v)
			case *order.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case order.Update:
				log.Printf("%T: %+v\n", v, v)
			case order.Cancel:
				log.Printf("%T: %+v\n", v, v)
			case wallet.Update:
				log.Printf("%T: %+v\n", v, v)
			case *wallet.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case balanceinfo.Update:
				log.Printf("%T: %+v\n", v, v)
			case fundingoffer.New:
				log.Printf("%T: %+v\n", v, v)
			case fundingoffer.Cancel:
				log.Printf("%T: %+v\n", v, v)
			case *fundingoffer.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case fundingcredit.New:
				log.Printf("%T: %+v\n", v, v)
			case fundingcredit.Update:
				log.Printf("%T: %+v\n", v, v)
			case fundingcredit.Cancel:
				log.Printf("%T: %+v\n", v, v)
			case trades.AuthFundingTradeUpdate:
				log.Printf("%T: %+v\n", v, v)
			case trades.AuthFundingTradeExecuted:
				log.Printf("%T: %+v\n", v, v)
			case *fundingcredit.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			default:
				log.Printf("raw/unhandled: %T: %+v\n", v, v)
			}
		})
	}()

	log.Fatal(<-crash)
}
<commit_msg>updating authenticated feed ingest example<commit_after>package main

import (
	"log"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/balanceinfo"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingcredit"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingloan"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/position"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/trades"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux"
)

func main() {
	m := mux.New().
		TransformRaw().
		WithAPIKEY("YOUR_API_KEY").
		WithAPISEC("YOUR_API_SECRET").
		Start()

	crash := make(chan error)

	go func() {
		crash <- m.Listen(func(msg interface{}, err error) {
			if err != nil {
				log.Printf("error received: %s\n", err)
			}

			switch v := msg.(type) {
			case event.Info:
				log.Printf("%T: %+v\n", v, v)
			case order.New:
				log.Printf("%T: %+v\n", v, v)
			case *order.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case order.Update:
				log.Printf("%T: %+v\n", v, v)
			case order.Cancel:
				log.Printf("%T: %+v\n", v, v)
			case wallet.Update:
				log.Printf("%T: %+v\n", v, v)
			case *wallet.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case balanceinfo.Update:
				log.Printf("%T: %+v\n", v, v)
			case fundingoffer.New:
				log.Printf("%T: %+v\n", v, v)
			case fundingoffer.Cancel:
				log.Printf("%T: %+v\n", v, v)
			case fundingoffer.Update:
				log.Printf("%T: %+v\n", v, v)
			case *fundingoffer.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case fundingcredit.New:
				log.Printf("%T: %+v\n", v, v)
			case fundingcredit.Update:
				log.Printf("%T: %+v\n", v, v)
			case fundingcredit.Cancel:
				log.Printf("%T: %+v\n", v, v)
			case trades.AuthFundingTradeUpdate:
				log.Printf("%T: %+v\n", v, v)
			case trades.AuthFundingTradeExecuted:
				log.Printf("%T: %+v\n", v, v)
			case *fundingcredit.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case *position.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case *fundingloan.Snapshot:
				log.Printf("%T: %+v\n", v, v)
				for _, ss := range v.Snapshot {
					log.Printf("%T item: %+v\n", ss, ss)
				}
			case fundingloan.New:
				log.Printf("%T: %+v\n", v, v)
			case fundingloan.Update:
				log.Printf("%T: %+v\n", v, v)
			case fundingloan.Cancel:
				log.Printf("%T: %+v\n", v, v)
			default:
				log.Printf("raw/unhandled: %T: %+v\n", v, v)
			}
		})
	}()

	log.Fatal(<-crash)
}
<|endoftext|>


<commit_before>package isbn

import (
	"testing"
)

func TestIsValidISBN(t *testing.T) {
	for _, test := range testCases {
		observed := IsValidISBN(test.isbn)
		if observed != test.expected {
			t.Errorf("FAIL: %s\nIsValidISBN(%q)\nExpected: %t, Actual: %t",
				test.description, test.isbn, test.expected, observed)
		}
		t.Logf("PASS: %s", test.description)
	}
}
<commit_msg>fix test to show pass messages only when passed<commit_after>package isbn

import (
	"testing"
)

func TestIsValidISBN(t *testing.T) {
	for _, test := range testCases {
		observed := IsValidISBN(test.isbn)
		if observed != test.expected {
			t.Errorf("FAIL: %s\nIsValidISBN(%q)\nExpected: %t, Actual: %t",
				test.description, test.isbn, test.expected, observed)
		} else {
			t.Logf("PASS: %s", test.description)
		}
	}
}
<|endoftext|>


<commit_before>package sudoku

import (
	"testing"
)

func TestForcingChains(t *testing.T) {

	//Steps to test this:
	//* In the forcing chain helper, calculate the steps once, then
	//pass them in each time in a list of ~10 calls to solveTechniqueTEstHelper that we know are valid here.
	//* VERIFY MANUALLY that each step that is returned is actually a valid application of forcingchains.

	options := solveTechniqueTestHelperOptions{
		checkAllSteps: true,
	}

	grid, solver, steps := humanSolveTechniqueTestHelperStepGenerator(t,
		"forcingchain_test1.sdk", "Forcing Chain", options)

	options.stepsToCheck.grid = grid
	options.stepsToCheck.solver = solver
	options.stepsToCheck.steps = steps

	//OK, now we'll walk through all of the options in a loop and make sure they all show
	//up in the solve steps.

	type loopOptions struct {
		targetCells  []cellRef
		targetNums   IntSlice
		pointerCells []cellRef
		pointerNums  IntSlice
		description  string
	}

	//Tester puzzle: http://www.komoroske.com/sudoku/index.php?puzzle=Q6Ur5iYGINSUFcyocqaY6G91DpttiqYzs

	tests := []loopOptions{
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{1, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
			description:  "cell (1,0) only has two options, 1 and 2, and if you put either one in and see the chain of implications it leads to, both ones end up with 7 in cell (0,1), so we can just fill that number in",
		},
		//This next one's particularly long implication chain
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{4, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
			//Explicitly don't test description after the first one.
		},
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 1}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 4}},
			pointerNums:  IntSlice([]int{2, 3}),
		},
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 7}},
			pointerNums:  IntSlice([]int{1, 3}),
		},
		{
			targetCells:  []cellRef{{0, 6}},
			targetNums:   IntSlice([]int{3}),
			pointerCells: []cellRef{{1, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{0, 6}},
			targetNums:   IntSlice([]int{3}),
			pointerCells: []cellRef{{5, 1}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		//Another particularly long one
		{
			targetCells:  []cellRef{{1, 0}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 1}},
			pointerNums:  IntSlice([]int{2, 7}),
		},
		{
			targetCells:  []cellRef{{1, 0}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 6}},
			pointerNums:  IntSlice([]int{3, 7}),
		},
		{
			targetCells:  []cellRef{{1, 8}},
			targetNums:   IntSlice([]int{4}),
			pointerCells: []cellRef{{1, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{1, 8}},
			targetNums:   IntSlice([]int{4}),
			pointerCells: []cellRef{{4, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{5, 1}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 1}},
			pointerNums:  IntSlice([]int{2, 7}),
		},
		{
			targetCells:  []cellRef{{5, 1}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 6}},
			pointerNums:  IntSlice([]int{3, 7}),
		},
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 4}},
			pointerNums:  IntSlice([]int{2, 3}),
		},
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 7}},
			pointerNums:  IntSlice([]int{1, 3}),
		},
		//Another particularly long one
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{7, 8}},
			pointerNums:  IntSlice([]int{2, 7}),
		},
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{8, 7}},
			pointerNums:  IntSlice([]int{1, 2}),
		},

		/*
			Steps that are valid, but that we don't expect the technique to find
			right now.
			{
				targetCells:  []cellRef{{0, 1}},
				targetNums:   IntSlice([]int{7}),
				pointerCells: []cellRef{{1, 0}},
				pointerNums:  IntSlice([]int{1, 2}),
			},
			//Another particularly long one
			{
				targetCells:  []cellRef{{5, 1}},
				targetNums:   IntSlice([]int{1}),
				pointerCells: []cellRef{{0, 6}},
				pointerNums:  IntSlice([]int{3, 7}),
			},
			//Another particularly long one
			{
				targetCells:  []cellRef{{1, 0}},
				targetNums:   IntSlice([]int{1}),
				pointerCells: []cellRef{{0, 6}},
				pointerNums:  IntSlice([]int{3, 7}),
			},
			//Another particularly long one
			{
				targetCells:  []cellRef{{5, 1}},
				targetNums:   IntSlice([]int{1}),
				pointerCells: []cellRef{{0, 6}},
				pointerNums:  IntSlice([]int{3, 7}),
			},

			{
				targetCells:  []cellRef{{8, 3}},
				targetNums:   IntSlice([]int{7}),
				pointerCells: []cellRef{{5, 7}},
				pointerNums:  IntSlice([]int{1, 3}),
			},
		*/
	}

	/*
		//Temp code that helps debug why the test isn't passing

		var stepDescriptions []string

		for _, step := range steps {
			stepDescriptions = append(stepDescriptions, fmt.Sprint(step.TargetCells.Description(), step.TargetNums.Description(), step.PointerCells.Description(), step.PointerNums.Description()))
		}

		sort.Strings(stepDescriptions)

		for _, str := range stepDescriptions {
			fmt.Println(str)
		}
	*/

	for _, test := range tests {

		options.targetCells = test.targetCells
		options.targetNums = test.targetNums
		options.pointerCells = test.pointerCells
		options.pointerNums = test.pointerNums
		options.description = test.description

		humanSolveTechniqueTestHelper(t, "forcingchain_test1.sdk", "Forcing Chain", options)
	}

	if len(tests) != len(steps) {
		t.Error("We didn't have enough tests for all of the steps that forcing chains returned. Got", len(tests), "expected", len(steps))
	}

	//TODO: test all other valid steps that could be found at this grid state for this technique.

}
<commit_msg>Removed an unnecessary comment<commit_after>package sudoku

import (
	"testing"
)

func TestForcingChains(t *testing.T) {

	options := solveTechniqueTestHelperOptions{
		checkAllSteps: true,
	}

	grid, solver, steps := humanSolveTechniqueTestHelperStepGenerator(t,
		"forcingchain_test1.sdk", "Forcing Chain", options)

	options.stepsToCheck.grid = grid
	options.stepsToCheck.solver = solver
	options.stepsToCheck.steps = steps

	//OK, now we'll walk through all of the options in a loop and make sure they all show
	//up in the solve steps.

	type loopOptions struct {
		targetCells  []cellRef
		targetNums   IntSlice
		pointerCells []cellRef
		pointerNums  IntSlice
		description  string
	}

	//Tester puzzle: http://www.komoroske.com/sudoku/index.php?puzzle=Q6Ur5iYGINSUFcyocqaY6G91DpttiqYzs

	tests := []loopOptions{
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{1, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
			description:  "cell (1,0) only has two options, 1 and 2, and if you put either one in and see the chain of implications it leads to, both ones end up with 7 in cell (0,1), so we can just fill that number in",
		},
		//This next one's particularly long implication chain
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{4, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
			//Explicitly don't test description after the first one.
		},
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 1}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 4}},
			pointerNums:  IntSlice([]int{2, 3}),
		},
		{
			targetCells:  []cellRef{{0, 1}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 7}},
			pointerNums:  IntSlice([]int{1, 3}),
		},
		{
			targetCells:  []cellRef{{0, 6}},
			targetNums:   IntSlice([]int{3}),
			pointerCells: []cellRef{{1, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{0, 6}},
			targetNums:   IntSlice([]int{3}),
			pointerCells: []cellRef{{5, 1}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		//Another particularly long one
		{
			targetCells:  []cellRef{{1, 0}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 1}},
			pointerNums:  IntSlice([]int{2, 7}),
		},
		{
			targetCells:  []cellRef{{1, 0}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 6}},
			pointerNums:  IntSlice([]int{3, 7}),
		},
		{
			targetCells:  []cellRef{{1, 8}},
			targetNums:   IntSlice([]int{4}),
			pointerCells: []cellRef{{1, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{1, 8}},
			targetNums:   IntSlice([]int{4}),
			pointerCells: []cellRef{{4, 0}},
			pointerNums:  IntSlice([]int{1, 2}),
		},
		{
			targetCells:  []cellRef{{5, 1}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 1}},
			pointerNums:  IntSlice([]int{2, 7}),
		},
		{
			targetCells:  []cellRef{{5, 1}},
			targetNums:   IntSlice([]int{1}),
			pointerCells: []cellRef{{0, 6}},
			pointerNums:  IntSlice([]int{3, 7}),
		},
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 4}},
			pointerNums:  IntSlice([]int{2, 3}),
		},
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{5, 7}},
			pointerNums:  IntSlice([]int{1, 3}),
		},
		//Another particularly long one
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{7, 8}},
			pointerNums:  IntSlice([]int{2, 7}),
		},
		{
			targetCells:  []cellRef{{8, 3}},
			targetNums:   IntSlice([]int{7}),
			pointerCells: []cellRef{{8, 7}},
			pointerNums:  IntSlice([]int{1, 2}),
		},

		/*
			Steps that are valid, but that we don't expect the technique to find
			right now.
			{
				targetCells:  []cellRef{{0, 1}},
				targetNums:   IntSlice([]int{7}),
				pointerCells: []cellRef{{1, 0}},
				pointerNums:  IntSlice([]int{1, 2}),
			},
			//Another particularly long one
			{
				targetCells:  []cellRef{{5, 1}},
				targetNums:   IntSlice([]int{1}),
				pointerCells: []cellRef{{0, 6}},
				pointerNums:  IntSlice([]int{3, 7}),
			},
			//Another particularly long one
			{
				targetCells:  []cellRef{{1, 0}},
				targetNums:   IntSlice([]int{1}),
				pointerCells: []cellRef{{0, 6}},
				pointerNums:  IntSlice([]int{3, 7}),
			},
			//Another particularly long one
			{
				targetCells:  []cellRef{{5, 1}},
				targetNums:   IntSlice([]int{1}),
				pointerCells: []cellRef{{0, 6}},
				pointerNums:  IntSlice([]int{3, 7}),
			},

			{
				targetCells:  []cellRef{{8, 3}},
				targetNums:   IntSlice([]int{7}),
				pointerCells: []cellRef{{5, 7}},
				pointerNums:  IntSlice([]int{1, 3}),
			},
		*/
	}

	/*
		//Temp code that helps debug why the test isn't passing

		var stepDescriptions []string

		for _, step := range steps {
			stepDescriptions = append(stepDescriptions, fmt.Sprint(step.TargetCells.Description(), step.TargetNums.Description(), step.PointerCells.Description(), step.PointerNums.Description()))
		}

		sort.Strings(stepDescriptions)

		for _, str := range stepDescriptions {
			fmt.Println(str)
		}
	*/

	for _, test := range tests {

		options.targetCells = test.targetCells
		options.targetNums = test.targetNums
		options.pointerCells = test.pointerCells
		options.pointerNums = test.pointerNums
		options.description = test.description

		humanSolveTechniqueTestHelper(t, "forcingchain_test1.sdk", "Forcing Chain", options)
	}

	if len(tests) != len(steps) {
		t.Error("We didn't have enough tests for all of the steps that forcing chains returned. Got", len(tests), "expected", len(steps))
	}

	//TODO: test all other valid steps that could be found at this grid state for this technique.

}
<|endoftext|>


<commit_before>package libvirt

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccLibvirtNetworkDataSource_DNSHostTemplate(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{

			{
				Config: `data "libvirt_network_dns_host_template" "bootstrap" {
  count = 2
  ip = "1.1.1.${count.index}"
  hostname = "myhost${count.index}"
}`,
				Check: resource.ComposeTestCheckFunc(
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.0", "ip", "1.1.1.0"),
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.0", "hostname", "myhost0"),
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.1", "ip", "1.1.1.1"),
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.1", "hostname", "myhost1"),
				),
			},
		},
	})
}

func checkTemplate(id, name, value string) resource.TestCheckFunc {
	return func(state *terraform.State) error {

		rs, err := getResourceFromTerraformState(id, state)
		if err != nil {
			return err
		}

		v := rs.Primary.Attributes[name]
		if v != value {
			return fmt.Errorf(
				"Value for %s is %s, not %s", name, v, value)
		}

		return nil
	}
}

func TestAccLibvirtNetworkDataSource_DNSSRVTemplate(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{

			{
				Config: `data "libvirt_network_dns_srv_template" "etcd_cluster" {
  count = 2
  service = etcd-server-ssl
  protocol = tcp
  target = "my-etcd-${count.index}.tt.testing"
}`,
				Check: resource.ComposeTestCheckFunc(
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.0", "target", "my-etcd-0.tt.testing"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.0", "service", "etcd-server-ssl"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.0", "protocol", "tcp"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.1", "target", "my-etcd-1.tt.testing"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.1", "service", "etcd-server-ssl"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.1", "protocol", "tcp"),
				),
			},
		},
	})
}
<commit_msg>Fix broken acceptance tests from 460<commit_after>package libvirt

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccLibvirtNetworkDataSource_DNSHostTemplate(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{

			{
				Config: `data "libvirt_network_dns_host_template" "bootstrap" {
  count = 2
  ip = "1.1.1.${count.index}"
  hostname = "myhost${count.index}"
}`,
				Check: resource.ComposeTestCheckFunc(
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.0", "ip", "1.1.1.0"),
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.0", "hostname", "myhost0"),
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.1", "ip", "1.1.1.1"),
					checkTemplate("data.libvirt_network_dns_host_template.bootstrap.1", "hostname", "myhost1"),
				),
			},
		},
	})
}

func checkTemplate(id, name, value string) resource.TestCheckFunc {
	return func(state *terraform.State) error {

		rs, err := getResourceFromTerraformState(id, state)
		if err != nil {
			return err
		}

		v := rs.Primary.Attributes[name]
		if v != value {
			return fmt.Errorf(
				"Value for %s is %s, not %s", name, v, value)
		}

		return nil
	}
}

func TestAccLibvirtNetworkDataSource_DNSSRVTemplate(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{

			{
				Config: `data "libvirt_network_dns_srv_template" "etcd_cluster" {
  count = 2
  service = "etcd-server-ssl"
  protocol = "tcp"
  target = "my-etcd-${count.index}.tt.testing"
}`,
				Check: resource.ComposeTestCheckFunc(
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.0", "target", "my-etcd-0.tt.testing"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.0", "service", "etcd-server-ssl"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.0", "protocol", "tcp"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.1", "target", "my-etcd-1.tt.testing"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.1", "service", "etcd-server-ssl"),
					checkTemplate("data.libvirt_network_dns_srv_template.etcd_cluster.1", "protocol", "tcp"),
				),
			},
		},
	})
}
<|endoftext|>


<commit_before>package ast

import (
	"fmt"

	"github.com/elpinal/coco3/extra/types"
)

type Command struct {
	Name string
	Args []Expr
}

type Expr interface {
	Expr()
	Type() types.Type
}

func (_ *String) Expr() {}
func (_ *Int) Expr()    {}
func (_ *Ident) Expr()  {}
func (_ *Empty) Expr()  {}
func (_ *Cons) Expr()   {}

type String struct {
	Lit string
}

func (s *String) Type() types.Type {
	return types.String
}

type Int struct {
	Lit string
}

func (s *Int) Type() types.Type {
	return types.Int
}

type Ident struct {
	Lit string
}

func (_ *Ident) Type() types.Type {
	return types.Ident
}

func (id *Ident) String() string {
	return fmt.Sprintf("%q", id.Lit)
}

type List interface {
	Length() int
	Expr
}

type Empty struct{}

func (e *Empty) Type() types.Type {
	return types.StringList
}

func (e *Empty) Length() int {
	return 0
}

type Cons struct {
	Head string
	Tail List
}

func (c *Cons) Type() types.Type {
	return types.StringList
}

func (c *Cons) Length() int {
	return 1 + c.Tail.Length()
}
<commit_msg>Clean up AST package<commit_after>package ast

import (
	"fmt"

	"github.com/elpinal/coco3/extra/types"
)

type Command struct {
	Name string
	Args []Expr
}

// Expressions

type Expr interface {
	Expr()
	Type() types.Type
}

func (_ *String) Expr() {}
func (_ *Int) Expr()    {}
func (_ *Ident) Expr()  {}
func (_ *Empty) Expr()  {}
func (_ *Cons) Expr()   {}

// Simple types

type (
	String struct {
		Lit string
	}

	Int struct {
		Lit string
	}

	Ident struct {
		Lit string
	}
)

func (_ *String) Type() types.Type {
	return types.String
}

func (_ *Int) Type() types.Type {
	return types.Int
}

func (_ *Ident) Type() types.Type {
	return types.Ident
}

func (s *String) String() string {
	return fmt.Sprintf("%q", s.Lit)
}

func (i *Int) String() string {
	return i.Lit
}

func (id *Ident) String() string {
	return fmt.Sprintf("%q", id.Lit)
}

// Lists

type List interface {
	Length() int
	Expr
}

type (
	Cons struct {
		Head string
		Tail List
	}

	Empty struct{}
)

func (e *Empty) Type() types.Type {
	return types.StringList
}

func (c *Cons) Type() types.Type {
	return types.StringList
}

func (e *Empty) Length() int {
	return 0
}

func (c *Cons) Length() int {
	return 1 + c.Tail.Length()
}
<|endoftext|>


<commit_before>package main

type element struct {
	Name  string
	Links []*element
}

var (
	air, earth, fire, ice                      element
	dust, lava, water, steam, mist, smoke, mud element
	time, gravity, electric, light, dark       element
	void, spiritual, chaotic, illusion         element
)

type Element uint8

const (
	Air Element = iota
	Earth
	Fire
	Ice
	Dust
	Lava
	Water
	Steam
	Mist
	Smoke
	Mud
	Time
	Gravity
	Electric
	Light
	Dark
	Void
	Spiritual
	Chaotic
	Illusion

	elementCount
)

var elements [elementCount]*element

func init() {
	air = element{
		Name:  "Air",
		Links: []*element{&smoke, &dust, &mist},
	}
	earth = element{
		Name:  "Earth",
		Links: []*element{&dust, &mud, &lava},
	}
	fire = element{
		Name:  "Fire",
		Links: []*element{&smoke, &lava, &steam},
	}
	ice = element{
		Name:  "Ice",
		Links: []*element{&water, &mist},
	}
	dust = element{
		Name:  "Dust",
		Links: []*element{&earth, &air},
	}
	lava = element{
		Name:  "Lava",
		Links: []*element{&earth, &fire},
	}
	water = element{
		Name:  "Water",
		Links: []*element{&mist, &steam, &mud, &ice},
	}
	steam = element{
		Name:  "Steam",
		Links: []*element{&water, &fire},
	}
	mist = element{
		Name:  "Mist",
		Links: []*element{&air, &water},
	}
	smoke = element{
		Name:  "Smoke",
		Links: []*element{&air, &fire},
	}
	mud = element{
		Name:  "Mud",
		Links: []*element{&water, &earth},
	}
	time = element{
		Name:  "Time",
		Links: []*element{&earth, &gravity, &void},
	}
	gravity = element{
		Name:  "Gravity",
		Links: []*element{&earth, &water, &time},
	}
	electric = element{
		Name:  "Electric",
		Links: []*element{&air, &light, &void},
	}
	light = element{
		Name:  "Light",
		Links: []*element{&air, &water, &electric},
	}
	dark = element{
		Name:  "Dark",
		Links: []*element{&fire, &smoke, &void},
	}
	void = element{
		Name:  "Void",
		Links: []*element{&dark, &time, &illusion},
	}
	spiritual = element{
		Name:  "Spiritual",
		Links: []*element{&air, &mist, &time},
	}
	chaotic = element{
		Name:  "Chaotic",
		Links: []*element{&light, &dark, &void},
	}
	illusion = element{
		Name:  "Illusion",
		Links: []*element{&void, &time, &gravity},
	}
	elements[Air] = &air
	// TODO: other elements
}
<commit_msg>add nature<commit_after>package main

type element struct {
	Name  string
	Links []*element
}

var (
	air, earth, fire, ice, nature              element
	dust, lava, water, steam, mist, smoke, mud element
	time, gravity, electric, light, dark       element
	void, spiritual, chaotic, illusion         element
)

type Element uint8

const (
	Air Element = iota
	Earth
	Fire
	Ice
	Nature
	Dust
	Lava
	Water
	Steam
	Mist
	Smoke
	Mud
	Time
	Gravity
	Electric
	Light
	Dark
	Void
	Spiritual
	Chaotic
	Illusion

	elementCount
)

var elements [elementCount]*element

func init() {
	air = element{
		Name:  "Air",
		Links: []*element{&smoke, &dust, &mist},
	}
	elements[Air] = &air
	earth = element{
		Name:  "Earth",
		Links: []*element{&dust, &mud, &lava},
	}
	elements[Earth] = &earth
	fire = element{
		Name:  "Fire",
		Links: []*element{&smoke, &lava, &steam},
	}
	elements[Fire] = &fire
	ice = element{
		Name:  "Ice",
		Links: []*element{&water, &mist},
	}
	nature = element{
		Name:  "Nature",
		Links: []*element{&earth, &air, &water},
	}
	elements[Nature] = &nature
	elements[Ice] = &ice
	dust = element{
		Name:  "Dust",
		Links: []*element{&earth, &air},
	}
	elements[Dust] = &dust
	lava = element{
		Name:  "Lava",
		Links: []*element{&earth, &fire},
	}
	elements[Lava] = &lava
	water = element{
		Name:  "Water",
		Links: []*element{&mist, &steam, &mud, &ice},
	}
	elements[Water] = &water
	steam = element{
		Name:  "Steam",
		Links: []*element{&water, &fire},
	}
	elements[Steam] = &steam
	mist = element{
		Name:  "Mist",
		Links: []*element{&air, &water},
	}
	elements[Mist] = &mist
	smoke = element{
		Name:  "Smoke",
		Links: []*element{&air, &fire},
	}
	elements[Smoke] = &smoke
	mud = element{
		Name:  "Mud",
		Links: []*element{&water, &earth},
	}
	elements[Mud] = &mud
	time = element{
		Name:  "Time",
		Links: []*element{&earth, &gravity, &void},
	}
	elements[Time] = &time
	gravity = element{
		Name:  "Gravity",
		Links: []*element{&earth, &water, &time},
	}
	elements[Gravity] = &gravity
	electric = element{
		Name:  "Electric",
		Links: []*element{&air, &light, &void},
	}
	elements[Electric] = &electric
	light = element{
		Name:  "Light",
		Links: []*element{&air, &water, &electric},
	}
	elements[Light] = &light
	dark = element{
		Name:  "Dark",
		Links: []*element{&fire, &smoke, &void},
	}
	elements[Dark] = &dark
	void = element{
		Name:  "Void",
		Links: []*element{&dark, &time, &illusion},
	}
	elements[Void] = &void
	spiritual = element{
		Name:  "Spiritual",
		Links: []*element{&air, &mist, &time},
	}
	elements[Spiritual] = &spiritual
	chaotic = element{
		Name:  "Chaotic",
		Links: []*element{&light, &dark, &void},
	}
	elements[Chaotic] = &chaotic
	illusion = element{
		Name:  "Illusion",
		Links: []*element{&void, &time, &gravity},
	}
	elements[Illusion] = &illusion
}
<|endoftext|>


<commit_before>// Copyright 2017 The Hugo Authors. All rights reserved.
//
// 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 hugolib

import (
	"path/filepath"
	"strings"
	"testing"

	"fmt"

	"github.com/spf13/hugo/output"
)

func TestPageTargetPath(t *testing.T) {

	pathSpec := newTestDefaultPathSpec()

	for _, langPrefix := range []string{"", "no"} {
		t.Run(fmt.Sprintf("langPrefix=%q", langPrefix), func(t *testing.T) {
			for _, uglyURLs := range []bool{false, true} {
				t.Run(fmt.Sprintf("uglyURLs=%t", uglyURLs), func(t *testing.T) {

					tests := []struct {
						name     string
						d        targetPathDescriptor
						expected string
					}{
						{"JSON home", targetPathDescriptor{Kind: KindHome, Type: output.JSONFormat}, "/index.json"},
						{"AMP home", targetPathDescriptor{Kind: KindHome, Type: output.AMPFormat}, "/amp/index.html"},
						{"HTML home", targetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: output.HTMLFormat}, "/index.html"},
						{"HTML section list", targetPathDescriptor{
							Kind:     KindSection,
							Sections: []string{"sect1"},
							BaseName: "_index",
							Type:     output.HTMLFormat}, "/sect1/index.html"},
						{"HTML taxonomy list", targetPathDescriptor{
							Kind:     KindTaxonomy,
							Sections: []string{"tags", "hugo"},
							BaseName: "_index",
							Type:     output.HTMLFormat}, "/tags/hugo/index.html"},
						{"HTML taxonomy term", targetPathDescriptor{
							Kind:     KindTaxonomy,
							Sections: []string{"tags"},
							BaseName: "_index",
							Type:     output.HTMLFormat}, "/tags/index.html"},
						{
							"HTML page", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "mypage",
								Sections: []string{"a"},
								Type:     output.HTMLFormat}, "/a/b/mypage/index.html"},

						{
							// Issue #3396
							"HTML page with index as base", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "index",
								Sections: []string{"a"},
								Type:     output.HTMLFormat}, "/a/b/index.html"},

						{
							"HTML page with special chars", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "My Page!",
								Type:     output.HTMLFormat}, "/a/b/My-Page/index.html"},
						{"RSS home", targetPathDescriptor{Kind: kindRSS, Type: output.RSSFormat}, "/index.xml"},
						{"RSS section list", targetPathDescriptor{
							Kind:     kindRSS,
							Sections: []string{"sect1"},
							Type:     output.RSSFormat}, "/sect1/index.xml"},
						{
							"AMP page", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b/c",
								BaseName: "myamp",
								Type:     output.AMPFormat}, "/amp/a/b/c/myamp/index.html"},
						{
							"AMP page with URL with suffix", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/sect/",
								BaseName: "mypage",
								URL:      "/some/other/url.xhtml",
								Type:     output.HTMLFormat}, "/some/other/url.xhtml"},
						{
							"JSON page with URL without suffix", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/sect/",
								BaseName: "mypage",
								URL:      "/some/other/path/",
								Type:     output.JSONFormat}, "/some/other/path/index.json"},
						{
							"JSON page with URL without suffix and no trailing slash", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/sect/",
								BaseName: "mypage",
								URL:      "/some/other/path",
								Type:     output.JSONFormat}, "/some/other/path/index.json"},
						{
							"HTML page with expanded permalink", targetPathDescriptor{
								Kind:              KindPage,
								Dir:               "/a/b",
								BaseName:          "mypage",
								ExpandedPermalink: "/2017/10/my-title",
								Type:              output.HTMLFormat}, "/2017/10/my-title/index.html"},
						{
							"Paginated HTML home", targetPathDescriptor{
								Kind:     KindHome,
								BaseName: "_index",
								Type:     output.HTMLFormat,
								Addends:  "page/3"}, "/page/3/index.html"},
						{
							"Paginated Taxonomy list", targetPathDescriptor{
								Kind:     KindTaxonomy,
								BaseName: "_index",
								Sections: []string{"tags", "hugo"},
								Type:     output.HTMLFormat,
								Addends:  "page/3"}, "/tags/hugo/page/3/index.html"},
						{
							"Regular page with addend", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "mypage",
								Addends:  "c/d/e",
								Type:     output.HTMLFormat}, "/a/b/mypage/c/d/e/index.html"},
					}

					for i, test := range tests {
						test.d.PathSpec = pathSpec
						test.d.UglyURLs = uglyURLs
						test.d.LangPrefix = langPrefix
						test.d.Dir = filepath.FromSlash(test.d.Dir)
						isUgly := uglyURLs && !test.d.Type.NoUgly

						expected := test.expected

						// TODO(bep) simplify
						if test.d.BaseName == test.d.Type.BaseName {

						} else if test.d.Kind == KindHome && test.d.Type.Path != "" {
						} else if (!strings.HasPrefix(expected, "/index") || test.d.Addends != "") && test.d.URL == "" && isUgly {
							expected = strings.Replace(expected,
								"/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.Suffix,
								"."+test.d.Type.MediaType.Suffix, -1)
						}

						if test.d.LangPrefix != "" && !(test.d.Kind == KindPage && test.d.URL != "") {
							expected = "/" + test.d.LangPrefix + expected
						}

						expected = filepath.FromSlash(expected)

						pagePath := createTargetPath(test.d)

						if pagePath != expected {
							t.Fatalf("[%d] [%s] targetPath expected %q, got: %q", i, test.name, expected, pagePath)
						}
					}
				})
			}
		})
	}

}
<commit_msg>hubolib: Narrow a test assertion<commit_after>// Copyright 2017 The Hugo Authors. All rights reserved.
//
// 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 hugolib

import (
	"path/filepath"
	"strings"
	"testing"

	"fmt"

	"github.com/spf13/hugo/output"
)

func TestPageTargetPath(t *testing.T) {

	pathSpec := newTestDefaultPathSpec()

	for _, langPrefix := range []string{"", "no"} {
		t.Run(fmt.Sprintf("langPrefix=%q", langPrefix), func(t *testing.T) {
			for _, uglyURLs := range []bool{false, true} {
				t.Run(fmt.Sprintf("uglyURLs=%t", uglyURLs), func(t *testing.T) {

					tests := []struct {
						name     string
						d        targetPathDescriptor
						expected string
					}{
						{"JSON home", targetPathDescriptor{Kind: KindHome, Type: output.JSONFormat}, "/index.json"},
						{"AMP home", targetPathDescriptor{Kind: KindHome, Type: output.AMPFormat}, "/amp/index.html"},
						{"HTML home", targetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: output.HTMLFormat}, "/index.html"},
						{"HTML section list", targetPathDescriptor{
							Kind:     KindSection,
							Sections: []string{"sect1"},
							BaseName: "_index",
							Type:     output.HTMLFormat}, "/sect1/index.html"},
						{"HTML taxonomy list", targetPathDescriptor{
							Kind:     KindTaxonomy,
							Sections: []string{"tags", "hugo"},
							BaseName: "_index",
							Type:     output.HTMLFormat}, "/tags/hugo/index.html"},
						{"HTML taxonomy term", targetPathDescriptor{
							Kind:     KindTaxonomy,
							Sections: []string{"tags"},
							BaseName: "_index",
							Type:     output.HTMLFormat}, "/tags/index.html"},
						{
							"HTML page", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "mypage",
								Sections: []string{"a"},
								Type:     output.HTMLFormat}, "/a/b/mypage/index.html"},

						{
							// Issue #3396
							"HTML page with index as base", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "index",
								Sections: []string{"a"},
								Type:     output.HTMLFormat}, "/a/b/index.html"},

						{
							"HTML page with special chars", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "My Page!",
								Type:     output.HTMLFormat}, "/a/b/My-Page/index.html"},
						{"RSS home", targetPathDescriptor{Kind: kindRSS, Type: output.RSSFormat}, "/index.xml"},
						{"RSS section list", targetPathDescriptor{
							Kind:     kindRSS,
							Sections: []string{"sect1"},
							Type:     output.RSSFormat}, "/sect1/index.xml"},
						{
							"AMP page", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b/c",
								BaseName: "myamp",
								Type:     output.AMPFormat}, "/amp/a/b/c/myamp/index.html"},
						{
							"AMP page with URL with suffix", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/sect/",
								BaseName: "mypage",
								URL:      "/some/other/url.xhtml",
								Type:     output.HTMLFormat}, "/some/other/url.xhtml"},
						{
							"JSON page with URL without suffix", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/sect/",
								BaseName: "mypage",
								URL:      "/some/other/path/",
								Type:     output.JSONFormat}, "/some/other/path/index.json"},
						{
							"JSON page with URL without suffix and no trailing slash", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/sect/",
								BaseName: "mypage",
								URL:      "/some/other/path",
								Type:     output.JSONFormat}, "/some/other/path/index.json"},
						{
							"HTML page with expanded permalink", targetPathDescriptor{
								Kind:              KindPage,
								Dir:               "/a/b",
								BaseName:          "mypage",
								ExpandedPermalink: "/2017/10/my-title",
								Type:              output.HTMLFormat}, "/2017/10/my-title/index.html"},
						{
							"Paginated HTML home", targetPathDescriptor{
								Kind:     KindHome,
								BaseName: "_index",
								Type:     output.HTMLFormat,
								Addends:  "page/3"}, "/page/3/index.html"},
						{
							"Paginated Taxonomy list", targetPathDescriptor{
								Kind:     KindTaxonomy,
								BaseName: "_index",
								Sections: []string{"tags", "hugo"},
								Type:     output.HTMLFormat,
								Addends:  "page/3"}, "/tags/hugo/page/3/index.html"},
						{
							"Regular page with addend", targetPathDescriptor{
								Kind:     KindPage,
								Dir:      "/a/b",
								BaseName: "mypage",
								Addends:  "c/d/e",
								Type:     output.HTMLFormat}, "/a/b/mypage/c/d/e/index.html"},
					}

					for i, test := range tests {
						test.d.PathSpec = pathSpec
						test.d.UglyURLs = uglyURLs
						test.d.LangPrefix = langPrefix
						test.d.Dir = filepath.FromSlash(test.d.Dir)
						isUgly := uglyURLs && !test.d.Type.NoUgly

						expected := test.expected

						// TODO(bep) simplify
						if test.d.Kind == KindPage && test.d.BaseName == test.d.Type.BaseName {

						} else if test.d.Kind == KindHome && test.d.Type.Path != "" {
						} else if (!strings.HasPrefix(expected, "/index") || test.d.Addends != "") && test.d.URL == "" && isUgly {
							expected = strings.Replace(expected,
								"/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.Suffix,
								"."+test.d.Type.MediaType.Suffix, -1)
						}

						if test.d.LangPrefix != "" && !(test.d.Kind == KindPage && test.d.URL != "") {
							expected = "/" + test.d.LangPrefix + expected
						}

						expected = filepath.FromSlash(expected)

						pagePath := createTargetPath(test.d)

						if pagePath != expected {
							t.Fatalf("[%d] [%s] targetPath expected %q, got: %q", i, test.name, expected, pagePath)
						}
					}
				})
			}
		})
	}

}
<|endoftext|>