<commit_before>package gotest

import (
	"testing"
	"os"
	"os/exec"
	"bytes"
	"strings"
)

func Test_C_Accepted(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."
	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/0.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()
	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=10000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerCmd.Run()

	result := containerStdout.String()
	if !strings.Contains(result, "\"status\":0") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Include_Leaks(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."

	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/1.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()

	if compilerStderr.Len() == 0 {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error missing")
	}

	if !strings.Contains(compilerStderr.String(), "/etc/shadow") {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error does not contain string `/etc/shadow`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Error(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."

	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/2.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()

	if compilerStderr.Len() == 0 {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error missing")
	}

	if !strings.Contains(compilerStderr.String(), "error") {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error does not contain string `error`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Bomb_0(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."

	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/3.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()

	if compilerStderr.Len() == 0 {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error missing")
	}

	if !strings.Contains(compilerStderr.String(), "signal: killed") {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error does not contain string `signal: killed`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Bomb_1(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."

	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/4.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()

	if compilerStderr.Len() == 0 {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error missing")
	}

	if !strings.Contains(compilerStderr.String(), "signal: killed") {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error does not contain string `signal: killed`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Bomb_2(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."

	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/5.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()

	if compilerStderr.Len() == 0 {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error missing")
	}

	if !strings.Contains(compilerStderr.String(), "signal: killed") {
		os.RemoveAll(baseDir + "/")
		t.Error("Compile error does not contain string `signal: killed`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Run_Infinite_Loop(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."
	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/6.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()
	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=10000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerCmd.Run()

	result := containerStdout.String()
	if !strings.Contains(result, "Runtime Error") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Run_Fork_Bomb(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."
	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/7.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()
	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=3000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerCmd.Run()

	result := containerStdout.String()
	if !strings.Contains(result, "Runtime Error") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Run_Cli(t *testing.T) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."
	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/8.in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()
	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("copy source file failed")
	}

	var compilerStderr bytes.Buffer
	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=10000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()
	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=10000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerCmd.Run()

	result := containerStdout.String()
	if !strings.Contains(result, "Runtime Error") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}<commit_msg>format c test cases<commit_after>package gotest

import (
	"testing"
	"os"
	"os/exec"
	"bytes"
	"strings"
)

// copy test source file to tmp dir
func copySourceFile(n string, t *testing.T) (string, string) {
	absPath, _ := os.Getwd()
	baseDir, projectDir := absPath + "/tmp", absPath + "/../.."
	os.MkdirAll(baseDir, os.ModePerm)

	cpCmd := exec.Command("cp", projectDir + "/src/resources/c/" + n + ".in", baseDir + "/Main.c")
	cpErr := cpCmd.Run()

	if cpErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error("Copy " + n + ".in failed")
	}

	return baseDir, projectDir
}

func Test_C_Accepted(t *testing.T) {
	baseDir, projectDir := copySourceFile("0", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=3000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerErr := containerCmd.Run()

	if containerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(containerErr.Error())
	}

	result := containerStdout.String()
	if !strings.Contains(result, "\"status\":0") {
		os.RemoveAll(baseDir + "/")
		t.Error(result + " => status != 0")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Include_Leaks(t *testing.T) {
	baseDir, projectDir := copySourceFile("1", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if !strings.Contains(compilerStderr.String(), "/etc/shadow") {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String() + " => Compile error does not contain string `/etc/shadow`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Error(t *testing.T) {
	baseDir, projectDir := copySourceFile("2", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if !strings.Contains(compilerStderr.String(), "error") {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String() + " => Compile error does not contain string `error`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Bomb_0(t *testing.T) {
	baseDir, projectDir := copySourceFile("3", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if !strings.Contains(compilerStderr.String(), "signal: killed") {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String() + " => Compile error does not contain string `signal: killed`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Bomb_1(t *testing.T) {
	baseDir, projectDir := copySourceFile("4", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if !strings.Contains(compilerStderr.String(), "signal: killed") {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String() + " => Compile error does not contain string `signal: killed`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Compiler_Bomb_2(t *testing.T) {
	baseDir, projectDir := copySourceFile("5", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if !strings.Contains(compilerStderr.String(), "signal: killed") {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String() + " => Compile error does not contain string `signal: killed`")
	}

	os.RemoveAll(baseDir + "/")
}

func Test_C_Run_Infinite_Loop(t *testing.T) {
	baseDir, projectDir := copySourceFile("6", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=3000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerErr := containerCmd.Run()

	if containerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(containerErr.Error())
	}

	result := containerStdout.String()
	if !strings.Contains(result, "Runtime Error") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}

/*func Test_C_Run_Fork_Bomb(t *testing.T) {
	baseDir, projectDir := copySourceFile("7", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerCmd.Run()
	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=3000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerCmd.Run()

	result := containerStdout.String()
	if !strings.Contains(result, "Runtime Error") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}*/

func Test_C_Run_Cli(t *testing.T) {
	baseDir, projectDir := copySourceFile("8", t)
	var compilerStderr bytes.Buffer

	compilerArgs := []string{"-compiler=/usr/bin/gcc", "-basedir=" + baseDir, "-timeout=3000"}
	compilerCmd := exec.Command(projectDir + "/bin/c_compiler", compilerArgs...)
	compilerCmd.Stderr = &compilerStderr
	compilerErr := compilerCmd.Run()

	if compilerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerErr.Error())
	}

	if compilerStderr.Len() > 0 {
		os.RemoveAll(baseDir + "/")
		t.Error(compilerStderr.String())
	}

	var containerStdout bytes.Buffer
	containerArgs := []string{"-basedir=" + baseDir, "-timeout=3000", "-input=10:10:23AM", "-expected=10:10:23"}
	containerCmd := exec.Command(projectDir + "/bin/c_container", containerArgs...)
	containerCmd.Stdout = &containerStdout
	containerErr := containerCmd.Run()

	if containerErr != nil {
		os.RemoveAll(baseDir + "/")
		t.Error(containerErr.Error())
	}

	result := containerStdout.String()
	if !strings.Contains(result, "\"status\":5") {
		os.RemoveAll(baseDir + "/")
		t.Error(result)
	}

	os.RemoveAll(baseDir + "/")
}<|endoftext|>


<commit_before>package cache

import (
	"strconv"
	"testing"
	"time"
)

func getIntCheck(t *testing.T, c *Cache, key string, expectedValue int) {
	v, ok := c.Get(key)
	if !ok {
		t.Fatalf("cache doesn't contain %q", key)
	}
	x, ok := v.(int)
	if !ok {
		t.Fatalf("retrieved value %v is not int", x)
	}
	if int(x) != expectedValue {
		t.Fatalf("wrong stored value: expected %d, got %d", expectedValue, x)
	}
}

func setInt(c *Cache, key string, value int) {
	c.Set(key, value, 0)
}

func TestMaxItems(t *testing.T) {
	c := New(Config{MaxItems: 3})
	setInt(c, "one", 1)
	setInt(c, "two", 2)
	setInt(c, "three", 3)

	// Try getting every, making sure we get "two" first,
	// so that it will later be pushed off the cache.

	getIntCheck(t, c, "two", 2)
	getIntCheck(t, c, "one", 1)
	getIntCheck(t, c, "three", 3)

	// Add new value, causing cache to drop "two".
	setInt(c, "four", 4)

	// Check that it was dropped...
	if v, ok := c.Get("two"); ok {
		t.Fatalf("cache didn't drop \"two\" (got %v)", v)
	}

	// ...and other elements are still there.
	getIntCheck(t, c, "one", 1)
	getIntCheck(t, c, "three", 3)
	getIntCheck(t, c, "four", 4)

	// Check that "one" is the oldest item.
	it, _ := c.OldestItem()
	if it.Key != "one" {
		t.Fatalf("oldest item is %s, expected %s", it.Key, "one")
	}

	// Replace element's value.
	setInt(c, "four", 100)
	getIntCheck(t, c, "four", 100)
}

func TestMaxBytes(t *testing.T) {
	removeCalled := 0
	c := New(Config{
		MaxBytes:      1000,
		RemoveHandler: func(it Item) { removeCalled++ },
	})
	b := make([]byte, 100)
	// Add 1100 bytes.
	for i := 0; i < 11; i++ {
		c.SetBytes(strconv.Itoa(i), b)
	}
	// Ensure there's no 0th item, as it should be dropped.
	if _, ok := c.GetBytes("0"); ok {
		t.Fatalf("cache didn't drop 0th item")
	}
	// Ensure items 1-10 exist.
	for i := 1; i < 11; i++ {
		if _, ok := c.GetBytes(strconv.Itoa(i)); !ok {
			t.Fatalf("cache item %d doesn't exist", i)
		}
	}
	if removeCalled != 1 {
		t.Fatalf("removeHandler was called %d times, expected %d", removeCalled, 1)
	}
}

func TestExpiration(t *testing.T) {
	c := New(Config{Expires: 1 * time.Millisecond})
	c.Set("hello", "world", 0)
	time.Sleep(2 * time.Millisecond)
	_, ok := c.Get("hello")
	if ok {
		t.Fatalf("didn't remove expired item")
	}
}

func benchSet(b *testing.B, config Config) {
	c := New(config)
	bs := make([]byte, 100)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.SetBytes(strconv.Itoa(i), bs)
	}
}

func BenchmarkSet(b *testing.B) {
	benchSet(b, Config{MaxItems: 1000})
}

func benchGet(b *testing.B, config Config) {
	c := New(config)
	c.SetBytes("test", make([]byte, 100))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.Get("test")
	}
}

func BenchmarkGet(b *testing.B) {
	benchGet(b, Config{MaxItems: 1000})
}

func BenchmarkGetTrackTime(b *testing.B) {
	benchGet(b, Config{MaxItems: 1000, TrackAccessTime: true})
}
<commit_msg>Add copyright header to test file.<commit_after>// Copyright 2013 Dmitry Chestnykh. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"strconv"
	"testing"
	"time"
)

func getIntCheck(t *testing.T, c *Cache, key string, expectedValue int) {
	v, ok := c.Get(key)
	if !ok {
		t.Fatalf("cache doesn't contain %q", key)
	}
	x, ok := v.(int)
	if !ok {
		t.Fatalf("retrieved value %v is not int", x)
	}
	if int(x) != expectedValue {
		t.Fatalf("wrong stored value: expected %d, got %d", expectedValue, x)
	}
}

func setInt(c *Cache, key string, value int) {
	c.Set(key, value, 0)
}

func TestMaxItems(t *testing.T) {
	c := New(Config{MaxItems: 3})
	setInt(c, "one", 1)
	setInt(c, "two", 2)
	setInt(c, "three", 3)

	// Try getting every, making sure we get "two" first,
	// so that it will later be pushed off the cache.

	getIntCheck(t, c, "two", 2)
	getIntCheck(t, c, "one", 1)
	getIntCheck(t, c, "three", 3)

	// Add new value, causing cache to drop "two".
	setInt(c, "four", 4)

	// Check that it was dropped...
	if v, ok := c.Get("two"); ok {
		t.Fatalf("cache didn't drop \"two\" (got %v)", v)
	}

	// ...and other elements are still there.
	getIntCheck(t, c, "one", 1)
	getIntCheck(t, c, "three", 3)
	getIntCheck(t, c, "four", 4)

	// Check that "one" is the oldest item.
	it, _ := c.OldestItem()
	if it.Key != "one" {
		t.Fatalf("oldest item is %s, expected %s", it.Key, "one")
	}

	// Replace element's value.
	setInt(c, "four", 100)
	getIntCheck(t, c, "four", 100)
}

func TestMaxBytes(t *testing.T) {
	removeCalled := 0
	c := New(Config{
		MaxBytes:      1000,
		RemoveHandler: func(it Item) { removeCalled++ },
	})
	b := make([]byte, 100)
	// Add 1100 bytes.
	for i := 0; i < 11; i++ {
		c.SetBytes(strconv.Itoa(i), b)
	}
	// Ensure there's no 0th item, as it should be dropped.
	if _, ok := c.GetBytes("0"); ok {
		t.Fatalf("cache didn't drop 0th item")
	}
	// Ensure items 1-10 exist.
	for i := 1; i < 11; i++ {
		if _, ok := c.GetBytes(strconv.Itoa(i)); !ok {
			t.Fatalf("cache item %d doesn't exist", i)
		}
	}
	if removeCalled != 1 {
		t.Fatalf("removeHandler was called %d times, expected %d", removeCalled, 1)
	}
}

func TestExpiration(t *testing.T) {
	c := New(Config{Expires: 1 * time.Millisecond})
	c.Set("hello", "world", 0)
	time.Sleep(2 * time.Millisecond)
	_, ok := c.Get("hello")
	if ok {
		t.Fatalf("didn't remove expired item")
	}
}

func benchSet(b *testing.B, config Config) {
	c := New(config)
	bs := make([]byte, 100)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.SetBytes(strconv.Itoa(i), bs)
	}
}

func BenchmarkSet(b *testing.B) {
	benchSet(b, Config{MaxItems: 1000})
}

func benchGet(b *testing.B, config Config) {
	c := New(config)
	c.SetBytes("test", make([]byte, 100))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.Get("test")
	}
}

func BenchmarkGet(b *testing.B) {
	benchGet(b, Config{MaxItems: 1000})
}

func BenchmarkGetTrackTime(b *testing.B) {
	benchGet(b, Config{MaxItems: 1000, TrackAccessTime: true})
}
<|endoftext|>


<commit_before>package meetup

import (
	"errors"
	"reflect"
	"strconv"
	"sync"
	"testing"
	"time"
)

var (
	fakeTimeMu sync.Mutex
	fakeTime   = time.Now()
)

func init() {
	now = func() time.Time {
		fakeTimeMu.Lock()
		t := fakeTime
		fakeTimeMu.Unlock()
		return t
	}
}

func advanceTime(d time.Duration) {
	fakeTimeMu.Lock()
	fakeTime = fakeTime.Add(d)
	fakeTimeMu.Unlock()
}

func mustGet(t *testing.T, c *Cache, key string, want interface{}) {
	v, err := c.Get(key)
	if err != nil {
		t.Errorf("Get(%#v) returned unexpected error %v", key, err)
	}
	if !reflect.DeepEqual(v, want) {
		t.Errorf("Get(%#v) = %#v, but wanted %#v", key, v, want)
	}
}

func TestCache(t *testing.T) {
	hits := 0
	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			hits++
			return key, nil
		},
	})
	defer c.Close()

	if hits != 0 {
		t.Fatalf("hits != 0 after init")
	}

	mustGet(t, c, "a", "a")
	if hits != 1 {
		t.Fatalf("hits != 1 after first use")
	}

	mustGet(t, c, "b", "b")
	if hits != 2 {
		t.Fatalf("hits = %v after second use", hits)
	}

	mustGet(t, c, "a", "a")
	if hits != 2 {
		t.Fatalf("hits != 2 after third use")
	}
}

func TestExpiry(t *testing.T) {
	var mu sync.Mutex
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			hits++
			mu.Unlock()
			return key, nil
		},
		ExpireAge: time.Second,
	})
	defer c.Close()

	mustGet(t, c, "a", "a")
	mu.Lock()
	if hits != 1 {
		t.Fatalf("hits = %v after first use", hits)
	}
	mu.Unlock()

	advanceTime(2 * time.Second)

	mustGet(t, c, "a", "a")
	mu.Lock()
	if hits != 2 {
		t.Fatalf("hits != 2 after second use")
	}
	mu.Unlock()

	advanceTime(time.Second / 2)

	mustGet(t, c, "a", "a")
	mu.Lock()
	if hits != 2 {
		t.Fatalf("hits = %v after third use", hits)
	}
	mu.Unlock()
}

func TestExpiryUsesStartTime(t *testing.T) {
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			advanceTime(time.Second)
			hits++
			return key, nil
		},
		ExpireAge: time.Second,
	})
	defer c.Close()

	mustGet(t, c, "a", "a")
	if hits != 1 {
		t.Fatalf("hits != 1 after first use")
	}

	mustGet(t, c, "a", "a")
	if hits != 2 {
		t.Fatalf("hits = %v after second use", hits)
	}
}

func TestMeetup(t *testing.T) {
	postGetCheckCh = make(chan struct{})
	defer func() { postGetCheckCh = nil }()

	const concurrency = 1000

	blockGets := newBoolWatcher(true)

	var mu sync.Mutex
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			blockGets.Wait(false)

			mu.Lock()
			c := hits
			hits++
			mu.Unlock()
			return c, nil
		},
	})
	defer c.Close()

	vals := make(chan interface{})
	for i := 0; i < concurrency; i++ {
		go func() {
			v, err := c.Get("a")
			if err != nil {
				t.Errorf(`c.Get("a") returned error %v`, err)
			}
			vals <- v
		}()
	}

	for i := 0; i < concurrency; i++ {
		<-postGetCheckCh
	}

	blockGets.Set(false)

	for i := 0; i < concurrency; i++ {
		v := <-vals
		if !reflect.DeepEqual(v, 0) {
			t.Errorf("Cache did not meet up. Wanted value %v, got %v", 0, v)
		}
	}
}

func TestConcurrencyLimit(t *testing.T) {
	blockGets := newBoolWatcher(true)

	const (
		workers = 1000
		limit   = 3
	)

	var mu sync.Mutex
	conc := 0
	maxConc := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			conc++
			if conc > maxConc {
				maxConc = conc
			}
			mu.Unlock()

			blockGets.Wait(false)

			mu.Lock()
			conc--
			mu.Unlock()

			return key, nil
		},
		Concurrency: limit,
	})
	defer c.Close()

	vals := make(chan interface{})

	for i := 0; i < workers; i++ {
		go func(i int) {
			k := strconv.FormatInt(int64(i), 10)
			v, _ := c.Get(k)
			vals <- v
		}(i)
	}

	blockGets.Set(false)

	for i := 0; i < workers; i++ {
		<-vals
	}

	if conc != 0 {
		t.Errorf("Options.Get still running after Cache.Get returned")
	}

	t.Logf("max concurrency seen was %v", maxConc)
	if maxConc > limit {
		t.Errorf("max concurrency of %v is over limit %v", maxConc, limit)
	}
}

func TestCacheDoesntKeepErrors(t *testing.T) {
	deliberateErr := errors.New("deliberate failure")

	hits := 0
	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			hits++
			return nil, deliberateErr
		},
	})
	defer c.Close()

	v, err := c.Get("a")
	if v != nil {
		t.Errorf("Got unexpected value %#v from c.Get", v)
	}
	if err != deliberateErr {
		t.Errorf("Got unexpected error %v from c.Get", err)
	}

	v, err = c.Get("a")
	if v != nil {
		t.Errorf("Got unexpected value %#v from c.Get", v)
	}
	if err != deliberateErr {
		t.Errorf("Got unexpected error %v from c.Get", err)
	}

	if hits != 2 {
		t.Errorf("Hits was %v, not 2", hits)
	}
}

func TestRevalidation(t *testing.T) {
	fillComplete = make(chan struct{})
	defer func() { fillComplete = nil }()

	blockGets := newBoolWatcher(false)
	var getReadyToBlock chan struct{}

	var mu sync.Mutex
	hits := 0
	finished := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			hits++
			myHits := hits
			mu.Unlock()
			if getReadyToBlock != nil {
				getReadyToBlock <- struct{}{}
			}
			blockGets.Wait(false)
			mu.Lock()
			finished++
			mu.Unlock()
			return myHits, nil
		},
		RevalidateAge: time.Second,
	})
	defer c.Close()

	mustGet(t, c, "a", 1)
	<-fillComplete
	if hits != 1 {
		t.Errorf("hits != 1")
	}

	blockGets.Set(true)
	advanceTime(time.Second)

	getReadyToBlock = make(chan struct{}, 1)
	mustGet(t, c, "a", 1) // NB: does not block with background revalidation
	<-getReadyToBlock
	mu.Lock()
	if hits != 2 {
		t.Errorf("hits = %v, wanted 2", hits)
	}
	if finished != 1 {
		t.Errorf("finished != 1")
	}
	mu.Unlock()

	blockGets.Set(false)
	<-fillComplete

	getReadyToBlock = nil
	mustGet(t, c, "a", 2)
}

func TestErrorCaching(t *testing.T) {
	deliberate := errors.New("deliberate failure")

	var mu sync.Mutex
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			hits++
			mu.Unlock()
			return nil, deliberate
		},
		ErrorAge: time.Second,
	})
	defer c.Close()

	_, err := c.Get("a")
	if err != deliberate {
		t.Errorf("Got unexpected error %v from Get", err)
	}

	_, err = c.Get("a")
	if err != deliberate {
		t.Errorf("Got unexpected error %v from Get", err)
	}

	if hits != 1 {
		t.Errorf("error was not cached")
	}

	advanceTime(time.Second)

	deliberate = errors.New("other deliberate failure")
	_, err = c.Get("a")
	if err != deliberate {
		t.Errorf("Got unexpected error %v from Get", err)
	}

	if hits != 2 {
		t.Errorf("hits = %v", hits)
	}
}
<commit_msg>add TestClosedGet, now 100% test coverage<commit_after>package meetup

import (
	"errors"
	"reflect"
	"strconv"
	"sync"
	"testing"
	"time"
)

var (
	fakeTimeMu sync.Mutex
	fakeTime   = time.Now()
)

func init() {
	now = func() time.Time {
		fakeTimeMu.Lock()
		t := fakeTime
		fakeTimeMu.Unlock()
		return t
	}
}

func advanceTime(d time.Duration) {
	fakeTimeMu.Lock()
	fakeTime = fakeTime.Add(d)
	fakeTimeMu.Unlock()
}

func mustGet(t *testing.T, c *Cache, key string, want interface{}) {
	v, err := c.Get(key)
	if err != nil {
		t.Errorf("Get(%#v) returned unexpected error %v", key, err)
	}
	if !reflect.DeepEqual(v, want) {
		t.Errorf("Get(%#v) = %#v, but wanted %#v", key, v, want)
	}
}

func TestCache(t *testing.T) {
	hits := 0
	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			hits++
			return key, nil
		},
	})
	defer c.Close()

	if hits != 0 {
		t.Fatalf("hits != 0 after init")
	}

	mustGet(t, c, "a", "a")
	if hits != 1 {
		t.Fatalf("hits != 1 after first use")
	}

	mustGet(t, c, "b", "b")
	if hits != 2 {
		t.Fatalf("hits = %v after second use", hits)
	}

	mustGet(t, c, "a", "a")
	if hits != 2 {
		t.Fatalf("hits != 2 after third use")
	}
}

func TestExpiry(t *testing.T) {
	var mu sync.Mutex
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			hits++
			mu.Unlock()
			return key, nil
		},
		ExpireAge: time.Second,
	})
	defer c.Close()

	mustGet(t, c, "a", "a")
	mu.Lock()
	if hits != 1 {
		t.Fatalf("hits = %v after first use", hits)
	}
	mu.Unlock()

	advanceTime(2 * time.Second)

	mustGet(t, c, "a", "a")
	mu.Lock()
	if hits != 2 {
		t.Fatalf("hits != 2 after second use")
	}
	mu.Unlock()

	advanceTime(time.Second / 2)

	mustGet(t, c, "a", "a")
	mu.Lock()
	if hits != 2 {
		t.Fatalf("hits = %v after third use", hits)
	}
	mu.Unlock()
}

func TestExpiryUsesStartTime(t *testing.T) {
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			advanceTime(time.Second)
			hits++
			return key, nil
		},
		ExpireAge: time.Second,
	})
	defer c.Close()

	mustGet(t, c, "a", "a")
	if hits != 1 {
		t.Fatalf("hits != 1 after first use")
	}

	mustGet(t, c, "a", "a")
	if hits != 2 {
		t.Fatalf("hits = %v after second use", hits)
	}
}

func TestMeetup(t *testing.T) {
	postGetCheckCh = make(chan struct{})
	defer func() { postGetCheckCh = nil }()

	const concurrency = 1000

	blockGets := newBoolWatcher(true)

	var mu sync.Mutex
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			blockGets.Wait(false)

			mu.Lock()
			c := hits
			hits++
			mu.Unlock()
			return c, nil
		},
	})
	defer c.Close()

	vals := make(chan interface{})
	for i := 0; i < concurrency; i++ {
		go func() {
			v, err := c.Get("a")
			if err != nil {
				t.Errorf(`c.Get("a") returned error %v`, err)
			}
			vals <- v
		}()
	}

	for i := 0; i < concurrency; i++ {
		<-postGetCheckCh
	}

	blockGets.Set(false)

	for i := 0; i < concurrency; i++ {
		v := <-vals
		if !reflect.DeepEqual(v, 0) {
			t.Errorf("Cache did not meet up. Wanted value %v, got %v", 0, v)
		}
	}
}

func TestConcurrencyLimit(t *testing.T) {
	blockGets := newBoolWatcher(true)

	const (
		workers = 1000
		limit   = 3
	)

	var mu sync.Mutex
	conc := 0
	maxConc := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			conc++
			if conc > maxConc {
				maxConc = conc
			}
			mu.Unlock()

			blockGets.Wait(false)

			mu.Lock()
			conc--
			mu.Unlock()

			return key, nil
		},
		Concurrency: limit,
	})
	defer c.Close()

	vals := make(chan interface{})

	for i := 0; i < workers; i++ {
		go func(i int) {
			k := strconv.FormatInt(int64(i), 10)
			v, _ := c.Get(k)
			vals <- v
		}(i)
	}

	blockGets.Set(false)

	for i := 0; i < workers; i++ {
		<-vals
	}

	if conc != 0 {
		t.Errorf("Options.Get still running after Cache.Get returned")
	}

	t.Logf("max concurrency seen was %v", maxConc)
	if maxConc > limit {
		t.Errorf("max concurrency of %v is over limit %v", maxConc, limit)
	}
}

func TestCacheDoesntKeepErrors(t *testing.T) {
	deliberateErr := errors.New("deliberate failure")

	hits := 0
	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			hits++
			return nil, deliberateErr
		},
	})
	defer c.Close()

	v, err := c.Get("a")
	if v != nil {
		t.Errorf("Got unexpected value %#v from c.Get", v)
	}
	if err != deliberateErr {
		t.Errorf("Got unexpected error %v from c.Get", err)
	}

	v, err = c.Get("a")
	if v != nil {
		t.Errorf("Got unexpected value %#v from c.Get", v)
	}
	if err != deliberateErr {
		t.Errorf("Got unexpected error %v from c.Get", err)
	}

	if hits != 2 {
		t.Errorf("Hits was %v, not 2", hits)
	}
}

func TestRevalidation(t *testing.T) {
	fillComplete = make(chan struct{})
	defer func() { fillComplete = nil }()

	blockGets := newBoolWatcher(false)
	var getReadyToBlock chan struct{}

	var mu sync.Mutex
	hits := 0
	finished := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			hits++
			myHits := hits
			mu.Unlock()
			if getReadyToBlock != nil {
				getReadyToBlock <- struct{}{}
			}
			blockGets.Wait(false)
			mu.Lock()
			finished++
			mu.Unlock()
			return myHits, nil
		},
		RevalidateAge: time.Second,
	})
	defer c.Close()

	mustGet(t, c, "a", 1)
	<-fillComplete
	if hits != 1 {
		t.Errorf("hits != 1")
	}

	blockGets.Set(true)
	advanceTime(time.Second)

	getReadyToBlock = make(chan struct{}, 1)
	mustGet(t, c, "a", 1) // NB: does not block with background revalidation
	<-getReadyToBlock
	mu.Lock()
	if hits != 2 {
		t.Errorf("hits = %v, wanted 2", hits)
	}
	if finished != 1 {
		t.Errorf("finished != 1")
	}
	mu.Unlock()

	blockGets.Set(false)
	<-fillComplete

	getReadyToBlock = nil
	mustGet(t, c, "a", 2)
}

func TestErrorCaching(t *testing.T) {
	deliberate := errors.New("deliberate failure")

	var mu sync.Mutex
	hits := 0

	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			mu.Lock()
			hits++
			mu.Unlock()
			return nil, deliberate
		},
		ErrorAge: time.Second,
	})
	defer c.Close()

	_, err := c.Get("a")
	if err != deliberate {
		t.Errorf("Got unexpected error %v from Get", err)
	}

	_, err = c.Get("a")
	if err != deliberate {
		t.Errorf("Got unexpected error %v from Get", err)
	}

	if hits != 1 {
		t.Errorf("error was not cached")
	}

	advanceTime(time.Second)

	deliberate = errors.New("other deliberate failure")
	_, err = c.Get("a")
	if err != deliberate {
		t.Errorf("Got unexpected error %v from Get", err)
	}

	if hits != 2 {
		t.Errorf("hits = %v", hits)
	}
}

func TestClosedGet(t *testing.T) {
	c := NewCache(Options{
		Get: func(key string) (interface{}, error) {
			return key, nil
		},
	})
	c.Close()

	_, err := c.Get("a")
	if err != ErrClosed {
		t.Errorf("Got unexpected error %v from Get", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    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 main

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

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

type fakeDevice struct {
	retReboot        error
	retInstallUpdate error
	retEnablePart    error
	retCommit        error
}

func (f fakeDevice) Reboot() error {
	return f.retReboot
}

func (f fakeDevice) InstallUpdate(io.ReadCloser, int64) error {
	return f.retInstallUpdate
}

func (f fakeDevice) EnableUpdatedPartition() error {
	return f.retEnablePart
}

func (f fakeDevice) CommitUpdate() error {
	return f.retCommit
}

type fakeUpdater struct {
	GetScheduledUpdateReturnIface interface{}
	GetScheduledUpdateReturnError error
	fetchUpdateReturnReadCloser   io.ReadCloser
	fetchUpdateReturnSize         int64
	fetchUpdateReturnError        error
}

func (f fakeUpdater) GetScheduledUpdate(process RequestProcessingFunc,
	url string, device string) (interface{}, error) {
	return f.GetScheduledUpdateReturnIface, f.GetScheduledUpdateReturnError
}
func (f fakeUpdater) FetchUpdate(url string) (io.ReadCloser, int64, error) {
	return f.fetchUpdateReturnReadCloser, f.fetchUpdateReturnSize, f.fetchUpdateReturnError
}

func fakeProcessUpdate(response *http.Response) (interface{}, error) {
	return nil, nil
}

func Test_checkUpdate_errorAskingForUpdate_returnsNoUpdate(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnError = errors.New("fake error")

	_, haveUpdate := checkScheduledUpdate(updater, fakeProcessUpdate, nil, "", "")
	assert.False(t, haveUpdate)
}

func Test_checkUpdate_askingForUpdateReturnsEmpty_returnsNoUpdate(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnIface = ""

	_, haveUpdate := checkScheduledUpdate(updater, fakeProcessUpdate, nil, "", "")
	assert.False(t, haveUpdate)
}

func Test_checkUpdate_askingForUpdateReturnsUpdate_returnsHaveUpdate(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnIface = UpdateResponse{}
	update := UpdateResponse{}

	_, haveUpdate := checkScheduledUpdate(updater, fakeProcessUpdate, &update, "", "")
	assert.True(t, haveUpdate)
}

func Test_fetchAndInstallUpdate_updateFetchError_returnsNotInstalled(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
	updater.fetchUpdateReturnError = errors.New("")
	daemon := menderDaemon{}
	daemon.Updater = updater

	assert.False(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
}

func Test_fetchAndInstallUpdate_installError_returnsNotInstalled(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
	device := fakeDevice{}
	device.retInstallUpdate = errors.New("")
	daemon := menderDaemon{}
	daemon.Updater = updater
	daemon.UInstallCommitRebooter = device

	assert.False(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
}

func Test_fetchAndInstallUpdate_updatePartitionError_returnsNotInstalled(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
	device := fakeDevice{}
	device.retEnablePart = errors.New("")
	daemon := menderDaemon{}
	daemon.Updater = updater
	daemon.UInstallCommitRebooter = device

	assert.False(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
}

func Test_fetchAndInstallUpdate_noErrors_returnsInstalled(t *testing.T) {
	updater := fakeUpdater{}
	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
	device := fakeDevice{}
	daemon := menderDaemon{}
	daemon.Updater = updater
	daemon.UInstallCommitRebooter = device

	assert.True(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
}

func Test_checkPeriodicDaemonUpdate_haveServerAndCorrectResponse_FetchesUpdate(t *testing.T) {

	if testing.Short() {
		t.Skip("skipping periodic update check in short tests")
	}

	reqHandlingCnt := 0
	pollInterval := time.Duration(10) * time.Millisecond

	// Test server that always responds with 200 code, and specific payload
	ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(204)
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, correctUpdateResponse)
		reqHandlingCnt++
	}))
	defer ts.Close()

	client, err := NewUpdateClient(httpsClientConfig{"client.crt", "client.key", "server.crt", true})
	assert.NotNil(t, client)
	assert.NoError(t, err)
	device := NewDevice(nil, nil, deviceConfig{"/dev/mmcblk0p2", "/dev/mmcblk0p3"})
	runner := newTestOSCalls("", 0)
	controler := newTestMender(&runner)
	if controler == nil {
		t.Fatalf("failed to create mender")
	}
	controler.changeState(MenderStateBootstrapped)

	daemon := NewDaemon(client, device, controler)
	daemon.config = daemonConfig{serverpollInterval: pollInterval, serverURL: ts.URL}

	go daemon.Run()

	timespolled := 5
	time.Sleep(time.Duration(timespolled) * pollInterval)
	daemon.StopDaemon()

	if reqHandlingCnt < (timespolled - 1) {
		assert.Fail(t, "Expected to receive at least %v requests - %v received",
			timespolled-1, reqHandlingCnt)
	}
}
<commit_msg>daemon: tests for daemon<commit_after>// Copyright 2016 Mender Software AS
//
//    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 main

import (
	// "errors"
	// "fmt"
	"io"
	"net/http"
	// "net/http/httptest"
	"testing"
	// "time"

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

type fakeDevice struct {
	retReboot        error
	retInstallUpdate error
	retEnablePart    error
	retCommit        error
}

func (f fakeDevice) Reboot() error {
	return f.retReboot
}

func (f fakeDevice) InstallUpdate(io.ReadCloser, int64) error {
	return f.retInstallUpdate
}

func (f fakeDevice) EnableUpdatedPartition() error {
	return f.retEnablePart
}

func (f fakeDevice) CommitUpdate() error {
	return f.retCommit
}

type fakeUpdater struct {
	GetScheduledUpdateReturnIface interface{}
	GetScheduledUpdateReturnError error
	fetchUpdateReturnReadCloser   io.ReadCloser
	fetchUpdateReturnSize         int64
	fetchUpdateReturnError        error
}

func (f fakeUpdater) GetScheduledUpdate(url string, device string) (interface{}, error) {
	return f.GetScheduledUpdateReturnIface, f.GetScheduledUpdateReturnError
}
func (f fakeUpdater) FetchUpdate(url string) (io.ReadCloser, int64, error) {
	return f.fetchUpdateReturnReadCloser, f.fetchUpdateReturnSize, f.fetchUpdateReturnError
}

func fakeProcessUpdate(response *http.Response) (interface{}, error) {
	return nil, nil
}

type fakePreDoneState struct {
	BaseState
}

func (f *fakePreDoneState) Handle(c Controller) (State, bool) {
	return doneState, false
}

func TestDaemon(t *testing.T) {
	mender := newDefaultTestMender()
	d := NewDaemon(mender)

	mender.SetState(&fakePreDoneState{
		BaseState{
			MenderStateInit,
		},
	})
	err := d.Run()
	assert.NoError(t, err)
}

// func Test_checkUpdate_errorAskingForUpdate_returnsNoUpdate(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnError = errors.New("fake error")

// 	_, haveUpdate := checkScheduledUpdate(updater, fakeProcessUpdate, nil, "", "")
// 	assert.False(t, haveUpdate)
// }

// func Test_checkUpdate_askingForUpdateReturnsEmpty_returnsNoUpdate(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnIface = ""

// 	_, haveUpdate := checkScheduledUpdate(updater, fakeProcessUpdate, nil, "", "")
// 	assert.False(t, haveUpdate)
// }

// func Test_checkUpdate_askingForUpdateReturnsUpdate_returnsHaveUpdate(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnIface = UpdateResponse{}
// 	update := UpdateResponse{}

// 	_, haveUpdate := checkScheduledUpdate(updater, fakeProcessUpdate, &update, "", "")
// 	assert.True(t, haveUpdate)
// }

// func Test_fetchAndInstallUpdate_updateFetchError_returnsNotInstalled(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
// 	updater.fetchUpdateReturnError = errors.New("")
// 	daemon := menderDaemon{}
// 	daemon.Updater = updater

// 	assert.False(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
// }

// func Test_fetchAndInstallUpdate_installError_returnsNotInstalled(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
// 	device := fakeDevice{}
// 	device.retInstallUpdate = errors.New("")
// 	daemon := menderDaemon{}
// 	daemon.Updater = updater
// 	daemon.UInstallCommitRebooter = device

// 	assert.False(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
// }

// func Test_fetchAndInstallUpdate_updatePartitionError_returnsNotInstalled(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
// 	device := fakeDevice{}
// 	device.retEnablePart = errors.New("")
// 	daemon := menderDaemon{}
// 	daemon.Updater = updater
// 	daemon.UInstallCommitRebooter = device

// 	assert.False(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
// }

// func Test_fetchAndInstallUpdate_noErrors_returnsInstalled(t *testing.T) {
// 	updater := fakeUpdater{}
// 	updater.GetScheduledUpdateReturnIface = new(UpdateResponse)
// 	device := fakeDevice{}
// 	daemon := menderDaemon{}
// 	daemon.Updater = updater
// 	daemon.UInstallCommitRebooter = device

// 	assert.True(t, fetchAndInstallUpdate(&daemon, UpdateResponse{}))
// }

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

// 	if testing.Short() {
// 		t.Skip("skipping periodic update check in short tests")
// 	}

// 	reqHandlingCnt := 0
// 	pollInterval := time.Duration(10) * time.Millisecond

// 	// Test server that always responds with 200 code, and specific payload
// 	ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 		w.WriteHeader(204)
// 		w.Header().Set("Content-Type", "application/json")
// 		fmt.Fprintln(w, correctUpdateResponse)
// 		reqHandlingCnt++
// 	}))
// 	defer ts.Close()

// 	client, err := NewUpdateClient(httpsClientConfig{"client.crt", "client.key", "server.crt", true})
// 	assert.NotNil(t, client)
// 	assert.NoError(t, err)

// 	device := NewDevice(nil, nil, "")
// 	runner := newTestOSCalls("", 0)
// 	controler := newTestMender(&runner)
// 	if controler == nil {
// 		t.Fatalf("failed to create mender")
// 	}
// 	controler.changeState(MenderStateBootstrapped)

// 	daemon := NewDaemon(client, device, controler)
// 	daemon.config = daemonConfig{serverpollInterval: pollInterval, serverURL: ts.URL}

// 	go daemon.Run()

// 	timespolled := 5
// 	time.Sleep(time.Duration(timespolled) * pollInterval)
// 	daemon.StopDaemon()

// 	if reqHandlingCnt < (timespolled - 1) {
// 		assert.Fail(t, "Expected to receive at least %v requests - %v received",
// 			timespolled-1, reqHandlingCnt)
// 	}
// }
<|endoftext|>


<commit_before>//CCMU Automatic Connector
//
//This tool provides automatic login feature for
//connect to the network authenticated by dr.com
//
//Author: ms2008vip@gmail.com at 2016/11/8 16:54:29
//

package main

import (
    "fmt"
    "net/http"
    "net/url"
    "os"
    "bufio"
    "io/ioutil"
    "strings"
    "math/rand"
    "time"
    l4g "github.com/alecthomas/log4go"
    "github.com/toqueteos/webbrowser"
)

const (
    URL = "http://192.168.161.2/"
    FILE = "ids.txt"
)

var log = make(l4g.Logger)
var buildstamp string = ""
var githash string = ""

func init() {
    log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
    log.AddFilter("file", l4g.ERROR, l4g.NewFileLogWriter("error.log", false))
}

func main() {
    defer log.Close()

    args := os.Args
    fmt.Println("os args:", os.Args)
    if len(args)==2 && (args[1]=="--version" || args[1] =="-v") {
        fmt.Printf("Git Commit Hash: %s\n", githash)
        fmt.Printf("UTC Build Time: %s\n", buildstamp)
        return
    }

    userList := fileTolines(FILE)
    rand.Seed(time.Now().Unix())
    //fmt.Println(userList)

    for {
        line := userList[rand.Intn(len(userList))]
        userInfo := strings.Split(line, "\t")
        account := userInfo[0]
        password := userInfo[3]
        //username := userInfo[1]

        //fmt.Println(account, password, username)
        //log.Info(line)
        if succ := checkPasswd(account, password); succ {
            balanceInfo := getBalance()
            fmt.Println(account, password, "Used Time:", balanceInfo[0], "Balance:", balanceInfo[1])

            if balanceInfo[0] >= 2400 && balanceInfo[1] == 0 {
                //fmt.Println(account, "time exceed!")
            } else {
                log.Info(account, password, "Used Time:", balanceInfo[0], "Balance:", balanceInfo[1])
                webbrowser.Open(URL)
                break
            }
        }
    }

    fmt.Println("看到这个，就是想证明下我不是个恶意程序，5s 之后就看不到我啦 :-)")
    <- time.After(5 * time.Second)
}

func fileTolines(filePath string) []string {
    f, err := os.Open(filePath)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    var lines []string
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }

    return lines
}

func chunkTolines(chunk string) []string {
    var lines []string
    lines = strings.Split(chunk, "\n")

    return lines
}

func checkPasswd(user, passwd string) bool {
	defer func() {
		if p := recover(); p != nil {
			err := p.(error)
			log.Critical("shit happens: %v [user: %s pass: %s]", err, user, passwd)
		}
	}()

    client := &http.Client{}

    // 构造认证请求
    form := url.Values{}
    form.Add("DDDDD", user)
    form.Add("upass", passwd)
    form.Add("0MKKey", "")

    req, err := http.NewRequest("POST", URL, strings.NewReader(form.Encode()))
    if err != nil {
        log.Error("failed to sent post request due to %s [user: %s pass: %s]", err, user, passwd)
        return false
    }

    // 防止被 dr.com banned
    req.Header.Set(`User-Agent`, `Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36`)
    req.Header.Set(`Referer`, URL)

    resp, err := client.Do(req)
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Error("failed to read login response body due to %s [user: %s pass: %s]", err, user, passwd)
        return false
    }
    //fmt.Println(string(body))

    // 判断认证是否通过
    line := chunkTolines(string(body))[5]
    if line[1] == "s" {
        // 认证通过
        return true
    } else if line[1] == "S" {
        return false
    } else {
        log.Warning("unexpected response! [user: %s pass: %s]", user, passwd)
        return false
    }
}

func getBalance() [2]int {
	defer func() {
		if p := recover(); p != nil {
			err := p.(error)
			log.Critical("shit happens: balance calc fauled %v", err)
		}
	}()

    balanceInfo := [2]int{0, 0}
    res, err := http.Get(URL)
    if err != nil {
        log.Error("failed to get balance info due to %s", err)
        return balanceInfo
    }

    result, err := ioutil.ReadAll(res.Body)
    defer res.Body.Close()
    if err != nil {
        log.Error("failed to read balance response body info due to %s", err)
        return balanceInfo
    }

    // 抓取已用时间
    line := chunkTolines(string(body))[6]
    re := regexp.MustCompile(`;time='(\d+) *';`)
    usedTime, _ := strconv.Atoi(re.FindStringSubmatch(line)[1])
    balanceInfo[0] = usedTime

    // 抓取余额
    re = regexp.MustCompile(`;fee='(\d+) *';`)
    fee, _ := strconv.Atoi(re.FindStringSubmatch(line)[1])
    amount := (fee - fee%100) / 10000
    balanceInfo[1] = amount

    return balanceInfo
}
<commit_msg>convert tabs to spaces<commit_after>//CCMU Automatic Connector
//
//This tool provides automatic login feature for
//connect to the network authenticated by dr.com
//
//Author: ms2008vip@gmail.com at 2016/11/8 16:54:29
//

package main

import (
    "fmt"
    "net/http"
    "net/url"
    "os"
    "bufio"
    "io/ioutil"
    "strings"
    "math/rand"
    "time"
    l4g "github.com/alecthomas/log4go"
    "github.com/toqueteos/webbrowser"
)

const (
    URL = "http://192.168.161.2/"
    FILE = "ids.txt"
)

var log = make(l4g.Logger)
var buildstamp string = ""
var githash string = ""

func init() {
    log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
    log.AddFilter("file", l4g.ERROR, l4g.NewFileLogWriter("error.log", false))
}

func main() {
    defer log.Close()

    args := os.Args
    fmt.Println("os args:", os.Args)
    if len(args)==2 && (args[1]=="--version" || args[1] =="-v") {
        fmt.Printf("Git Commit Hash: %s\n", githash)
        fmt.Printf("UTC Build Time: %s\n", buildstamp)
        return
    }

    userList := fileTolines(FILE)
    rand.Seed(time.Now().Unix())
    //fmt.Println(userList)

    for {
        line := userList[rand.Intn(len(userList))]
        userInfo := strings.Split(line, "\t")
        account := userInfo[0]
        password := userInfo[3]
        //username := userInfo[1]

        //fmt.Println(account, password, username)
        //log.Info(line)
        if succ := checkPasswd(account, password); succ {
            balanceInfo := getBalance()
            fmt.Println(account, password, "Used Time:", balanceInfo[0], "Balance:", balanceInfo[1])

            if balanceInfo[0] >= 2400 && balanceInfo[1] == 0 {
                //fmt.Println(account, "time exceed!")
            } else {
                log.Info(account, password, "Used Time:", balanceInfo[0], "Balance:", balanceInfo[1])
                webbrowser.Open(URL)
                break
            }
        }
    }

    fmt.Println("看到这个，就是想证明下我不是个恶意程序，5s 之后就看不到我啦 :-)")
    <- time.After(5 * time.Second)
}

func fileTolines(filePath string) []string {
    f, err := os.Open(filePath)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    var lines []string
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }

    return lines
}

func chunkTolines(chunk string) []string {
    var lines []string
    lines = strings.Split(chunk, "\n")

    return lines
}

func checkPasswd(user, passwd string) bool {
    defer func() {
        if p := recover(); p != nil {
            err := p.(error)
            log.Critical("shit happens: %v [user: %s pass: %s]", err, user, passwd)
        }
    }()

    client := &http.Client{}

    // 构造认证请求
    form := url.Values{}
    form.Add("DDDDD", user)
    form.Add("upass", passwd)
    form.Add("0MKKey", "")

    req, err := http.NewRequest("POST", URL, strings.NewReader(form.Encode()))
    if err != nil {
        log.Error("failed to sent post request due to %s [user: %s pass: %s]", err, user, passwd)
        return false
    }

    // 防止被 dr.com banned
    req.Header.Set(`User-Agent`, `Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36`)
    req.Header.Set(`Referer`, URL)

    resp, err := client.Do(req)
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Error("failed to read login response body due to %s [user: %s pass: %s]", err, user, passwd)
        return false
    }
    //fmt.Println(string(body))

    // 判断认证是否通过
    line := chunkTolines(string(body))[5]
    if line[1] == "s" {
        // 认证通过
        return true
    } else if line[1] == "S" {
        return false
    } else {
        log.Warning("unexpected response! [user: %s pass: %s]", user, passwd)
        return false
    }
}

func getBalance() [2]int {
    defer func() {
        if p := recover(); p != nil {
            err := p.(error)
            log.Critical("shit happens: balance calc fauled %v", err)
        }
    }()

    balanceInfo := [2]int{0, 0}
    res, err := http.Get(URL)
    if err != nil {
        log.Error("failed to get balance info due to %s", err)
        return balanceInfo
    }

    result, err := ioutil.ReadAll(res.Body)
    defer res.Body.Close()
    if err != nil {
        log.Error("failed to read balance response body info due to %s", err)
        return balanceInfo
    }

    // 抓取已用时间
    line := chunkTolines(string(body))[6]
    re := regexp.MustCompile(`;time='(\d+) *';`)
    usedTime, _ := strconv.Atoi(re.FindStringSubmatch(line)[1])
    balanceInfo[0] = usedTime

    // 抓取余额
    re = regexp.MustCompile(`;fee='(\d+) *';`)
    fee, _ := strconv.Atoi(re.FindStringSubmatch(line)[1])
    amount := (fee - fee%100) / 10000
    balanceInfo[1] = amount

    return balanceInfo
}
<|endoftext|>


<commit_before>package strrand

import (
	"math/rand"
	"strings"
	"time"
)

func makeRange(from rune, to rune) (r []string) {
	for i := from; i <= to; i++ {
		r = append(r, string(i))
	}
	return r
}

func concat(ss ...[]string) (r []string) {
	for _, s := range ss {
		r = append(r, s...)
	}
	return r
}

type picker []string

func (p picker) pick() string {
	// XXX care empty picker
	idx := rand.Intn(len(p))
	return p[idx]
}

var upper picker
var lower picker
var digit picker
var punct picker
var any picker
var salt picker
var binary picker

func init() {
	rand.Seed(time.Now().Unix())

	upper = makeRange('A', 'Z')
	lower = makeRange('a', 'z')
	digit = makeRange('0', '9')

	punct = concat(makeRange(33, 47), makeRange(58, 64), makeRange(91, 96), makeRange(123, 126))
	any = concat(upper, lower, digit, punct)
	salt = concat(upper, lower, digit, []string{".", "/"})
}

var patterns = map[string]picker{
	"d": picker(digit),
	"D": picker(concat(upper, lower, punct)),
	"w": picker(concat(upper, lower, digit, []string{"_"})),
	"W": picker(concat(makeRange(33, 47), makeRange(58, 64), makeRange(91, 94), makeRange(96, 96), makeRange(123, 126))),
	"s": picker([]string{" ", "\t"}),
	"S": picker(concat(upper, lower, digit, punct)),

	// these are translated to their double quoted equivalents.
	"t": picker([]string{"\t"}),
	"n": picker([]string{"\n"}),
	"r": picker([]string{"\r"}),
	"f": picker([]string{"\f"}),
	"a": picker([]string{"\a"}),
	"e": picker([]string{string(27)}), // escape character
}

type strrand struct {
}

func New() *strrand {
	return &strrand{}
}

func (sr *strrand) Randregex(pattern string) (string, error) {
	result := ""
	pickers, _ := sr.doRandregex(pattern)

	for _, p := range pickers {
		result += string(p.pick())
	}
	return result, nil
}

func (sr *strrand) doRandregex(pattern string) ([]picker, error) {
	pickers := []picker{}
	chars := func() *[]string {
		c := strings.Split(pattern, "")
		return &c
	}()

	for len(*chars) > 0 {
		chr := (*chars)[0]
		*chars = (*chars)[1:]

		switch chr {
		case "\\":
			p, _ := sr.handleEscape(chars)
			pickers = append(pickers, p)
		case ".":
			pickers = append(pickers, any)
		default:
			pickers = append(pickers, picker([]string{chr}))
		}
	}
	return pickers, nil
}

func (sr *strrand) handleEscape(chars *[]string) (picker, error) {
	chr := (*chars)[0]
	*chars = (*chars)[1:]

	return picker([]string{chr}), nil
}
<commit_msg>refactor<commit_after>package strrand

import (
	"math/rand"
	"strings"
	"time"
)

func makeRange(from rune, to rune) (r []string) {
	for i := from; i <= to; i++ {
		r = append(r, string(i))
	}
	return r
}

func concat(ss ...[]string) (r []string) {
	for _, s := range ss {
		r = append(r, s...)
	}
	return r
}

type picker []string

func (p picker) pick() string {
	if len(p) < 1 {
		return ""
	}
	idx := rand.Intn(len(p))
	return p[idx]
}

var upper picker
var lower picker
var digit picker
var punct picker
var any picker
var salt picker
var binary picker

func init() {
	rand.Seed(time.Now().Unix())

	upper = makeRange('A', 'Z')
	lower = makeRange('a', 'z')
	digit = makeRange('0', '9')

	punct = concat(makeRange(33, 47), makeRange(58, 64), makeRange(91, 96), makeRange(123, 126))
	any = concat(upper, lower, digit, punct)
	salt = concat(upper, lower, digit, []string{".", "/"})
}

var patterns = map[string]picker{
	"d": picker(digit),
	"D": picker(concat(upper, lower, punct)),
	"w": picker(concat(upper, lower, digit, []string{"_"})),
	"W": picker(concat(makeRange(33, 47), makeRange(58, 64), makeRange(91, 94), makeRange(96, 96), makeRange(123, 126))),
	"s": picker([]string{" ", "\t"}),
	"S": picker(concat(upper, lower, digit, punct)),

	// these are translated to their double quoted equivalents.
	"t": picker([]string{"\t"}),
	"n": picker([]string{"\n"}),
	"r": picker([]string{"\r"}),
	"f": picker([]string{"\f"}),
	"a": picker([]string{"\a"}),
	"e": picker([]string{string(27)}), // escape character
}

type strrand struct {
}

func New() *strrand {
	return &strrand{}
}

func (sr *strrand) Randregex(pattern string) (string, error) {
	result := ""
	pickers, _ := sr.doRandregex(pattern)

	for _, p := range pickers {
		result += p.pick()
	}
	return result, nil
}

func (sr *strrand) doRandregex(pattern string) ([]picker, error) {
	pickers := []picker{}
	chars := func() *[]string {
		c := strings.Split(pattern, "")
		return &c
	}()

	for len(*chars) > 0 {
		chr := (*chars)[0]
		*chars = (*chars)[1:]

		switch chr {
		case "\\":
			p, _ := sr.handleEscape(chars)
			pickers = append(pickers, p)
		case ".":
			pickers = append(pickers, any)
		default:
			pickers = append(pickers, picker([]string{chr}))
		}
	}
	return pickers, nil
}

func (sr *strrand) handleEscape(chars *[]string) (picker, error) {
	chr := (*chars)[0]
	*chars = (*chars)[1:]

	return picker([]string{chr}), nil
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains all structures for the discordgo package.  These
// may be moved about later into separate files but I find it easier to have
// them all located together.

package discordgo

import (
	"encoding/json"
	"reflect"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// A Session represents a connection to the Discord API.
type Session struct {
	sync.RWMutex

	// General configurable settings.

	// Authentication token for this session
	Token string

	// Debug for printing JSON request/responses
	Debug bool

	// Should the session reconnect the websocket on errors.
	ShouldReconnectOnError bool

	// Should the session request compressed websocket data.
	Compress bool

	// Should state tracking be enabled.
	// State tracking is the best way for getting the the users
	// active guilds and the members of the guilds.
	StateEnabled bool

	// Exposed but should not be modified by User.

	// Whether the Data Websocket is ready
	DataReady bool

	// Whether the Voice Websocket is ready
	VoiceReady bool

	// Whether the UDP Connection is ready
	UDPReady bool

	// Stores all details related to voice connections
	Voice *Voice

	// Managed state object, updated internally with events when
	// StateEnabled is true.
	State *State

	handlersMu sync.RWMutex
	// This is a mapping of event struct to a reflected value
	// for event handlers.
	// We store the reflected value instead of the function
	// reference as it is more performant, instead of re-reflecting
	// the function each event.
	handlers map[interface{}][]reflect.Value

	// The websocket connection.
	wsConn *websocket.Conn

	// When nil, the session is not listening.
	listening chan interface{}
}

// A VoiceRegion stores data for a specific voice region server.
type VoiceRegion struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Hostname string `json:"sample_hostname"`
	Port     int    `json:"sample_port"`
}

// A VoiceICE stores data for voice ICE servers.
type VoiceICE struct {
	TTL     string       `json:"ttl"`
	Servers []*ICEServer `json:"servers"`
}

// A ICEServer stores data for a specific voice ICE server.
type ICEServer struct {
	URL        string `json:"url"`
	Username   string `json:"username"`
	Credential string `json:"credential"`
}

// A Invite stores all data related to a specific Discord Guild or Channel invite.
type Invite struct {
	Guild     *Guild   `json:"guild"`
	Channel   *Channel `json:"channel"`
	Inviter   *User    `json:"inviter"`
	Code      string   `json:"code"`
	CreatedAt string   `json:"created_at"` // TODO make timestamp
	MaxAge    int      `json:"max_age"`
	Uses      int      `json:"uses"`
	MaxUses   int      `json:"max_uses"`
	XkcdPass  bool     `json:"xkcdpass"`
	Revoked   bool     `json:"revoked"`
	Temporary bool     `json:"temporary"`
}

// A Channel holds all data related to an individual Discord channel.
type Channel struct {
	ID                   string                 `json:"id"`
	GuildID              string                 `json:"guild_id"`
	Name                 string                 `json:"name"`
	Topic                string                 `json:"topic"`
	Position             int                    `json:"position"`
	Bitrate              int                    `json:"bitrate"`
	Type                 string                 `json:"type"`
	PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"`
	IsPrivate            bool                   `json:"is_private"`
	LastMessageID        string                 `json:"last_message_id"`
	Recipient            *User                  `json:"recipient"`
	Messages             []*Message             `json:"-"`
}

// A PermissionOverwrite holds permission overwrite data for a Channel
type PermissionOverwrite struct {
	ID    string `json:"id"`
	Type  string `json:"type"`
	Deny  int    `json:"deny"`
	Allow int    `json:"allow"`
}

// Emoji struct holds data related to Emoji's
type Emoji struct {
	ID            string   `json:"id"`
	Name          string   `json:"name"`
	Roles         []string `json:"roles"`
	Managed       bool     `json:"managed"`
	RequireColons bool     `json:"require_colons"`
}

// Custom VerificationLevel typedef for int
type VerificationLevel int

// Constants for VerificationLevel levels from 0 to 3 inclusive
const (
	VerificationLevelNone VerificationLevel = iota
	VerificationLevelLow
	VerificationLevelMedium
	VerificationLevelHigh
)

// A Guild holds all data related to a specific Discord Guild.  Guilds are also
// sometimes referred to as Servers in the Discord client.
type Guild struct {
	ID                string            `json:"id"`
	Name              string            `json:"name"`
	Icon              string            `json:"icon"`
	Region            string            `json:"region"`
	AfkChannelID      string            `json:"afk_channel_id"`
	EmbedChannelID    string            `json:"embed_channel_id"`
	OwnerID           string            `json:"owner_id"`
	JoinedAt          string            `json:"joined_at"` // make this a timestamp
	Splash            string            `json:"splash"`
	AfkTimeout        int               `json:"afk_timeout"`
	VerificationLevel VerificationLevel `json:"verification_level"`
	EmbedEnabled      bool              `json:"embed_enabled"`
	Large             bool              `json:"large"` // ??
	Roles             []*Role           `json:"roles"`
	Emojis            []*Emoji          `json:"emojis"`
	Members           []*Member         `json:"members"`
	Presences         []*Presence       `json:"presences"`
	Channels          []*Channel        `json:"channels"`
	VoiceStates       []*VoiceState     `json:"voice_states"`
}

// A GuildParams stores all the data needed to update discord guild settings
type GuildParams struct {
	Name              string             `json:"name"`
	Region            string             `json:"region"`
	VerificationLevel *VerificationLevel `json:"verification_level"`
}

// A Role stores information about Discord guild member roles.
type Role struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Managed     bool   `json:"managed"`
	Hoist       bool   `json:"hoist"`
	Color       int    `json:"color"`
	Position    int    `json:"position"`
	Permissions int    `json:"permissions"`
}

// A VoiceState stores the voice states of Guilds
type VoiceState struct {
	UserID    string `json:"user_id"`
	SessionID string `json:"session_id"`
	ChannelID string `json:"channel_id"`
	Suppress  bool   `json:"suppress"`
	SelfMute  bool   `json:"self_mute"`
	SelfDeaf  bool   `json:"self_deaf"`
	Mute      bool   `json:"mute"`
	Deaf      bool   `json:"deaf"`
}

// A Presence stores the online, offline, or idle and game status of Guild members.
type Presence struct {
	User   *User  `json:"user"`
	Status string `json:"status"`
	Game   *Game  `json:"game"`
}

// A Game struct holds the name of the "playing .." game for a user
type Game struct {
	Name string `json:"name"`
}

// A Member stores user information for Guild members.
type Member struct {
	GuildID  string   `json:"guild_id"`
	JoinedAt string   `json:"joined_at"`
	Deaf     bool     `json:"deaf"`
	Mute     bool     `json:"mute"`
	User     *User    `json:"user"`
	Roles    []string `json:"roles"`
}

// A User stores all data for an individual Discord user.
type User struct {
	ID            string `json:"id"`
	Email         string `json:"email"`
	Username      string `json:"username"`
	Avatar        string `json:"Avatar"`
	Verified      bool   `json:"verified"`
	Discriminator string `json:"discriminator"`
}

// A Settings stores data for a specific users Discord client settings.
type Settings struct {
	RenderEmbeds          bool     `json:"render_embeds"`
	InlineEmbedMedia      bool     `json:"inline_embed_media"`
	EnableTtsCommand      bool     `json:"enable_tts_command"`
	MessageDisplayCompact bool     `json:"message_display_compact"`
	ShowCurrentGame       bool     `json:"show_current_game"`
	Locale                string   `json:"locale"`
	Theme                 string   `json:"theme"`
	MutedChannels         []string `json:"muted_channels"`
}

// An Event provides a basic initial struct for all websocket event.
type Event struct {
	Type      string          `json:"t"`
	State     int             `json:"s"`
	Operation int             `json:"op"`
	Direction int             `json:"dir"`
	RawData   json.RawMessage `json:"d"`
}

// A Ready stores all data for the websocket READY event.
type Ready struct {
	Version           int           `json:"v"`
	SessionID         string        `json:"session_id"`
	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
	User              *User         `json:"user"`
	ReadState         []*ReadState  `json:"read_state"`
	PrivateChannels   []*Channel    `json:"private_channels"`
	Guilds            []*Guild      `json:"guilds"`
}

// A RateLimit struct holds information related to a specific rate limit.
type RateLimit struct {
	Bucket     string        `json:"bucket"`
	Message    string        `json:"message"`
	RetryAfter time.Duration `json:"retry_after"`
}

// A ReadState stores data on the read state of channels.
type ReadState struct {
	MentionCount  int    `json:"mention_count"`
	LastMessageID string `json:"last_message_id"`
	ID            string `json:"id"`
}

// A TypingStart stores data for the typing start websocket event.
type TypingStart struct {
	UserID    string `json:"user_id"`
	ChannelID string `json:"channel_id"`
	Timestamp int    `json:"timestamp"`
}

// A PresenceUpdate stores data for the pressence update websocket event.
type PresenceUpdate struct {
	User    *User    `json:"user"`
	Status  string   `json:"status"`
	Roles   []string `json:"roles"`
	GuildID string   `json:"guild_id"`
	Game    *Game    `json:"game"`
}

// A MessageAck stores data for the message ack websocket event.
type MessageAck struct {
	MessageID string `json:"message_id"`
	ChannelID string `json:"channel_id"`
}

// A GuildIntegrationsUpdate stores data for the guild integrations update
// websocket event.
type GuildIntegrationsUpdate struct {
	GuildID string `json:"guild_id"`
}

// A GuildRole stores data for guild role websocket events.
type GuildRole struct {
	Role    *Role  `json:"role"`
	GuildID string `json:"guild_id"`
}

// A GuildRoleDelete stores data for the guild role delete websocket event.
type GuildRoleDelete struct {
	RoleID  string `json:"role_id"`
	GuildID string `json:"guild_id"`
}

// A GuildBan stores data for a guild ban.
type GuildBan struct {
	User    *User  `json:"user"`
	GuildID string `json:"guild_id"`
}

// A GuildEmojisUpdate stores data for a guild emoji update event.
type GuildEmojisUpdate struct {
	GuildID string   `json:"guild_id"`
	Emojis  []*Emoji `json:"emojis"`
}

// A UserGuildSettingsChannelOverride stores data for a channel override for a users guild settings.
type UserGuildSettingsChannelOverride struct {
	Muted                bool   `json:"muted"`
	MessageNotifications int    `json:"message_notifications"`
	ChannelID            string `json:"channel_id"`
}

// A UserGuildSettings stores data for a users guild settings.
type UserGuildSettings struct {
	SupressEveryone      bool                                `json:"suppress_everyone"`
	Muted                bool                                `json:"muted"`
	MobilePush           bool                                `json:"mobile_push"`
	MessageNotifications int                                 `json:"message_notifications"`
	GuildID              string                              `json:"guild_id"`
	ChannelOverrides     []*UserGuildSettingsChannelOverride `json:"channel_overrides"`
}

// A State contains the current known state.
// As discord sends this in a READY blob, it seems reasonable to simply
// use that struct as the data store.
type State struct {
	sync.RWMutex
	Ready
	MaxMessageCount int
}

// Constants for the different bit offsets of text channel permissions
const (
	PermissionReadMessages = 1 << (iota + 10)
	PermissionSendMessages
	PermissionSendTTSMessages
	PermissionManageMessages
	PermissionEmbedLinks
	PermissionAttachFiles
	PermissionReadMessageHistory
	PermissionMentionEveryone
)

// Constants for the different bit offsets of voice permissions
const (
	PermissionVoiceConnect = 1 << (iota + 20)
	PermissionVoiceSpeak
	PermissionVoiceMuteMembers
	PermissionVoiceDeafenMembers
	PermissionVoiceMoveMembers
	PermissionVoiceUseVAD
)

// Constants for the different bit offsets of general permissions
const (
	PermissionCreateInstantInvite = 1 << iota
	PermissionKickMembers
	PermissionBanMembers
	PermissionManageRoles
	PermissionManageChannels
	PermissionManageServer

	PermissionAllChannel = PermissionReadMessages | PermissionSendMessages | PermissionSendTTSMessages | PermissionManageMessages | PermissionEmbedLinks | PermissionAttachFiles | PermissionReadMessageHistory | PermissionMentionEveryone | PermissionVoiceConnect | PermissionVoiceSpeak | PermissionVoiceMuteMembers | PermissionVoiceDeafenMembers | PermissionVoiceMoveMembers | PermissionVoiceUseVAD | PermissionCreateInstantInvite | PermissionManageRoles | PermissionManageChannels
	PermissionAll        = PermissionAllChannel | PermissionKickMembers | PermissionBanMembers | PermissionManageServer
)<commit_msg>Format the permission constants<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains all structures for the discordgo package.  These
// may be moved about later into separate files but I find it easier to have
// them all located together.

package discordgo

import (
	"encoding/json"
	"reflect"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// A Session represents a connection to the Discord API.
type Session struct {
	sync.RWMutex

	// General configurable settings.

	// Authentication token for this session
	Token string

	// Debug for printing JSON request/responses
	Debug bool

	// Should the session reconnect the websocket on errors.
	ShouldReconnectOnError bool

	// Should the session request compressed websocket data.
	Compress bool

	// Should state tracking be enabled.
	// State tracking is the best way for getting the the users
	// active guilds and the members of the guilds.
	StateEnabled bool

	// Exposed but should not be modified by User.

	// Whether the Data Websocket is ready
	DataReady bool

	// Whether the Voice Websocket is ready
	VoiceReady bool

	// Whether the UDP Connection is ready
	UDPReady bool

	// Stores all details related to voice connections
	Voice *Voice

	// Managed state object, updated internally with events when
	// StateEnabled is true.
	State *State

	handlersMu sync.RWMutex
	// This is a mapping of event struct to a reflected value
	// for event handlers.
	// We store the reflected value instead of the function
	// reference as it is more performant, instead of re-reflecting
	// the function each event.
	handlers map[interface{}][]reflect.Value

	// The websocket connection.
	wsConn *websocket.Conn

	// When nil, the session is not listening.
	listening chan interface{}
}

// A VoiceRegion stores data for a specific voice region server.
type VoiceRegion struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Hostname string `json:"sample_hostname"`
	Port     int    `json:"sample_port"`
}

// A VoiceICE stores data for voice ICE servers.
type VoiceICE struct {
	TTL     string       `json:"ttl"`
	Servers []*ICEServer `json:"servers"`
}

// A ICEServer stores data for a specific voice ICE server.
type ICEServer struct {
	URL        string `json:"url"`
	Username   string `json:"username"`
	Credential string `json:"credential"`
}

// A Invite stores all data related to a specific Discord Guild or Channel invite.
type Invite struct {
	Guild     *Guild   `json:"guild"`
	Channel   *Channel `json:"channel"`
	Inviter   *User    `json:"inviter"`
	Code      string   `json:"code"`
	CreatedAt string   `json:"created_at"` // TODO make timestamp
	MaxAge    int      `json:"max_age"`
	Uses      int      `json:"uses"`
	MaxUses   int      `json:"max_uses"`
	XkcdPass  bool     `json:"xkcdpass"`
	Revoked   bool     `json:"revoked"`
	Temporary bool     `json:"temporary"`
}

// A Channel holds all data related to an individual Discord channel.
type Channel struct {
	ID                   string                 `json:"id"`
	GuildID              string                 `json:"guild_id"`
	Name                 string                 `json:"name"`
	Topic                string                 `json:"topic"`
	Position             int                    `json:"position"`
	Bitrate              int                    `json:"bitrate"`
	Type                 string                 `json:"type"`
	PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"`
	IsPrivate            bool                   `json:"is_private"`
	LastMessageID        string                 `json:"last_message_id"`
	Recipient            *User                  `json:"recipient"`
	Messages             []*Message             `json:"-"`
}

// A PermissionOverwrite holds permission overwrite data for a Channel
type PermissionOverwrite struct {
	ID    string `json:"id"`
	Type  string `json:"type"`
	Deny  int    `json:"deny"`
	Allow int    `json:"allow"`
}

// Emoji struct holds data related to Emoji's
type Emoji struct {
	ID            string   `json:"id"`
	Name          string   `json:"name"`
	Roles         []string `json:"roles"`
	Managed       bool     `json:"managed"`
	RequireColons bool     `json:"require_colons"`
}

// Custom VerificationLevel typedef for int
type VerificationLevel int

// Constants for VerificationLevel levels from 0 to 3 inclusive
const (
	VerificationLevelNone VerificationLevel = iota
	VerificationLevelLow
	VerificationLevelMedium
	VerificationLevelHigh
)

// A Guild holds all data related to a specific Discord Guild.  Guilds are also
// sometimes referred to as Servers in the Discord client.
type Guild struct {
	ID                string            `json:"id"`
	Name              string            `json:"name"`
	Icon              string            `json:"icon"`
	Region            string            `json:"region"`
	AfkChannelID      string            `json:"afk_channel_id"`
	EmbedChannelID    string            `json:"embed_channel_id"`
	OwnerID           string            `json:"owner_id"`
	JoinedAt          string            `json:"joined_at"` // make this a timestamp
	Splash            string            `json:"splash"`
	AfkTimeout        int               `json:"afk_timeout"`
	VerificationLevel VerificationLevel `json:"verification_level"`
	EmbedEnabled      bool              `json:"embed_enabled"`
	Large             bool              `json:"large"` // ??
	Roles             []*Role           `json:"roles"`
	Emojis            []*Emoji          `json:"emojis"`
	Members           []*Member         `json:"members"`
	Presences         []*Presence       `json:"presences"`
	Channels          []*Channel        `json:"channels"`
	VoiceStates       []*VoiceState     `json:"voice_states"`
}

// A GuildParams stores all the data needed to update discord guild settings
type GuildParams struct {
	Name              string             `json:"name"`
	Region            string             `json:"region"`
	VerificationLevel *VerificationLevel `json:"verification_level"`
}

// A Role stores information about Discord guild member roles.
type Role struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Managed     bool   `json:"managed"`
	Hoist       bool   `json:"hoist"`
	Color       int    `json:"color"`
	Position    int    `json:"position"`
	Permissions int    `json:"permissions"`
}

// A VoiceState stores the voice states of Guilds
type VoiceState struct {
	UserID    string `json:"user_id"`
	SessionID string `json:"session_id"`
	ChannelID string `json:"channel_id"`
	Suppress  bool   `json:"suppress"`
	SelfMute  bool   `json:"self_mute"`
	SelfDeaf  bool   `json:"self_deaf"`
	Mute      bool   `json:"mute"`
	Deaf      bool   `json:"deaf"`
}

// A Presence stores the online, offline, or idle and game status of Guild members.
type Presence struct {
	User   *User  `json:"user"`
	Status string `json:"status"`
	Game   *Game  `json:"game"`
}

// A Game struct holds the name of the "playing .." game for a user
type Game struct {
	Name string `json:"name"`
}

// A Member stores user information for Guild members.
type Member struct {
	GuildID  string   `json:"guild_id"`
	JoinedAt string   `json:"joined_at"`
	Deaf     bool     `json:"deaf"`
	Mute     bool     `json:"mute"`
	User     *User    `json:"user"`
	Roles    []string `json:"roles"`
}

// A User stores all data for an individual Discord user.
type User struct {
	ID            string `json:"id"`
	Email         string `json:"email"`
	Username      string `json:"username"`
	Avatar        string `json:"Avatar"`
	Verified      bool   `json:"verified"`
	Discriminator string `json:"discriminator"`
}

// A Settings stores data for a specific users Discord client settings.
type Settings struct {
	RenderEmbeds          bool     `json:"render_embeds"`
	InlineEmbedMedia      bool     `json:"inline_embed_media"`
	EnableTtsCommand      bool     `json:"enable_tts_command"`
	MessageDisplayCompact bool     `json:"message_display_compact"`
	ShowCurrentGame       bool     `json:"show_current_game"`
	Locale                string   `json:"locale"`
	Theme                 string   `json:"theme"`
	MutedChannels         []string `json:"muted_channels"`
}

// An Event provides a basic initial struct for all websocket event.
type Event struct {
	Type      string          `json:"t"`
	State     int             `json:"s"`
	Operation int             `json:"op"`
	Direction int             `json:"dir"`
	RawData   json.RawMessage `json:"d"`
}

// A Ready stores all data for the websocket READY event.
type Ready struct {
	Version           int           `json:"v"`
	SessionID         string        `json:"session_id"`
	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
	User              *User         `json:"user"`
	ReadState         []*ReadState  `json:"read_state"`
	PrivateChannels   []*Channel    `json:"private_channels"`
	Guilds            []*Guild      `json:"guilds"`
}

// A RateLimit struct holds information related to a specific rate limit.
type RateLimit struct {
	Bucket     string        `json:"bucket"`
	Message    string        `json:"message"`
	RetryAfter time.Duration `json:"retry_after"`
}

// A ReadState stores data on the read state of channels.
type ReadState struct {
	MentionCount  int    `json:"mention_count"`
	LastMessageID string `json:"last_message_id"`
	ID            string `json:"id"`
}

// A TypingStart stores data for the typing start websocket event.
type TypingStart struct {
	UserID    string `json:"user_id"`
	ChannelID string `json:"channel_id"`
	Timestamp int    `json:"timestamp"`
}

// A PresenceUpdate stores data for the pressence update websocket event.
type PresenceUpdate struct {
	User    *User    `json:"user"`
	Status  string   `json:"status"`
	Roles   []string `json:"roles"`
	GuildID string   `json:"guild_id"`
	Game    *Game    `json:"game"`
}

// A MessageAck stores data for the message ack websocket event.
type MessageAck struct {
	MessageID string `json:"message_id"`
	ChannelID string `json:"channel_id"`
}

// A GuildIntegrationsUpdate stores data for the guild integrations update
// websocket event.
type GuildIntegrationsUpdate struct {
	GuildID string `json:"guild_id"`
}

// A GuildRole stores data for guild role websocket events.
type GuildRole struct {
	Role    *Role  `json:"role"`
	GuildID string `json:"guild_id"`
}

// A GuildRoleDelete stores data for the guild role delete websocket event.
type GuildRoleDelete struct {
	RoleID  string `json:"role_id"`
	GuildID string `json:"guild_id"`
}

// A GuildBan stores data for a guild ban.
type GuildBan struct {
	User    *User  `json:"user"`
	GuildID string `json:"guild_id"`
}

// A GuildEmojisUpdate stores data for a guild emoji update event.
type GuildEmojisUpdate struct {
	GuildID string   `json:"guild_id"`
	Emojis  []*Emoji `json:"emojis"`
}

// A UserGuildSettingsChannelOverride stores data for a channel override for a users guild settings.
type UserGuildSettingsChannelOverride struct {
	Muted                bool   `json:"muted"`
	MessageNotifications int    `json:"message_notifications"`
	ChannelID            string `json:"channel_id"`
}

// A UserGuildSettings stores data for a users guild settings.
type UserGuildSettings struct {
	SupressEveryone      bool                                `json:"suppress_everyone"`
	Muted                bool                                `json:"muted"`
	MobilePush           bool                                `json:"mobile_push"`
	MessageNotifications int                                 `json:"message_notifications"`
	GuildID              string                              `json:"guild_id"`
	ChannelOverrides     []*UserGuildSettingsChannelOverride `json:"channel_overrides"`
}

// A State contains the current known state.
// As discord sends this in a READY blob, it seems reasonable to simply
// use that struct as the data store.
type State struct {
	sync.RWMutex
	Ready
	MaxMessageCount int
}

// Constants for the different bit offsets of text channel permissions
const (
	PermissionReadMessages = 1 << (iota + 10)
	PermissionSendMessages
	PermissionSendTTSMessages
	PermissionManageMessages
	PermissionEmbedLinks
	PermissionAttachFiles
	PermissionReadMessageHistory
	PermissionMentionEveryone
)

// Constants for the different bit offsets of voice permissions
const (
	PermissionVoiceConnect = 1 << (iota + 20)
	PermissionVoiceSpeak
	PermissionVoiceMuteMembers
	PermissionVoiceDeafenMembers
	PermissionVoiceMoveMembers
	PermissionVoiceUseVAD
)

// Constants for the different bit offsets of general permissions
const (
	PermissionCreateInstantInvite = 1 << iota
	PermissionKickMembers
	PermissionBanMembers
	PermissionManageRoles
	PermissionManageChannels
	PermissionManageServer

	PermissionAllText    = PermissionReadMessages |
	                       PermissionSendMessages |
	                       PermissionSendTTSMessages |
	                       PermissionManageMessages |
	                       PermissionEmbedLinks |
	                       PermissionAttachFiles |
	                       PermissionReadMessageHistory |
	                       PermissionMentionEveryone
	PermissionAllVoice   = PermissionVoiceConnect |
	                       PermissionVoiceSpeak |
	                       PermissionVoiceMuteMembers |
	                       PermissionVoiceDeafenMembers |
	                       PermissionVoiceMoveMembers |
	                       PermissionVoiceUseVAD
	PermissionAllChannel = PermissionAllText |
	                       PermissionAllVoice |
	                       PermissionCreateInstantInvite |
	                       PermissionManageRoles |
	                       PermissionManageChannels
	PermissionAll        = PermissionAllChannel |
	                       PermissionKickMembers |
	                       PermissionBanMembers |
	                       PermissionManageServer
)
<|endoftext|>