<commit_before>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"encoding/json"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

var authKey = []byte("somesecretauth")
var store sessions.Store
var pool *Pool
var clients map[int64]*Client

var db *sql.DB
// var tv syscall.Timeval

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      int64
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 8)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 8 {
			return
		}
		crId, _ := binary.Varint(b)

		room := &Room{crId, c1, c2}

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	fmt.Println(session.Values)
	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

type IdQuery struct {
    Id            int64      `json:"id"`

}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

  	fmt.Println("uid: ", uid)
	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	fmt.Println("added ", uid, " to queue")
	chatroom := <- retChan

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":", chatroom.id, "}")
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	fmt.Fprint(w, uid)
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println(uid)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}-", message)
	} else {
		fmt.Fprint(w, "{\"status\":\"failure\"}-", message)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	client := clients[uid]

	if client != nil {
		fmt.Println("client found")
		select {
		case message, ok := <- clients[uid].in:
			fmt.Println("message pulled from channel")
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Fprint(w, "")
			}
		default:
			fmt.Println("")
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Println("client not found")
		fmt.Fprint(w, "")
	}
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		iq := new(IdQuery)
		err := row.Scan(&iq.Id)

		if err != nil {
			_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, "{\"status\":\"failure\"}")
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&iq.Id)
				if err != nil {
					fmt.Fprint(w, "{\"status\":\"failure\"}")
					return
				}
			}

		}

		fmt.Println("session-id: ", iq.Id)

		session, _ := store.Get(r, "session")
		session.Values["userid"] = iq.Id
		session.Save(r, w)

		fmt.Println(session.Values)

		fmt.Fprint(w, "{\"status\":\"success\"}")

	// 	if err == nil {
	// 		fmt.Fprint(w, "{\"status\":\"success\",\"uid\":", iq.Id, "}")
	// 	} else {
	// 		_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
	// 		if err == nil {
	// 			row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
	// 			err = row.Scan(&iq.Id)
	// 			if err == nil {
	// 				fmt.Fprint(w, "{\"status\":\"success\"},\"uid\":", iq.Id, "}")
	// 			} else {
	// 				fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 			}
	// 		} else {
	// 			fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 		}
	// 	}
	// } else {
	// 	fmt.Fprint(w, "{\"status\":\"failure\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>index.html<commit_after>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"encoding/json"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	// id      int64
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		// b := make([]byte, 8)
		// n, err := io.ReadFull(rand.Reader, b)
		// if err != nil || n != 8 {
		// 	return
		// }
		// crId, _ := binary.Varint(b)

		// fmt.Print

		room := &Room{c1, c2}

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	fmt.Println(session.Values)
	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

type IdQuery struct {
    Id            int64      `json:"id"`

}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

  	fmt.Println("uid: ", uid)
	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	fmt.Println("added ", uid, " to queue")
	chatroom := <- retChan

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":", chatroom.id, "}")
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	fmt.Fprint(w, uid)
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println(uid)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}-", message)
	} else {
		fmt.Fprint(w, "{\"status\":\"failure\"}-", message)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	client := clients[uid]

	if client != nil {
		fmt.Println("client found")
		select {
		case message, ok := <- clients[uid].in:
			fmt.Println("message pulled from channel")
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Fprint(w, "")
			}
		default:
			fmt.Println("")
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Println("client not found")
		fmt.Fprint(w, "")
	}
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		iq := new(IdQuery)
		err := row.Scan(&iq.Id)

		if err != nil {
			_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, "{\"status\":\"failure\"}")
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&iq.Id)
				if err != nil {
					fmt.Fprint(w, "{\"status\":\"failure\"}")
					return
				}
			}

		}

		fmt.Println("session-id: ", iq.Id)

		session, _ := store.Get(r, "session")
		session.Values["userid"] = iq.Id
		session.Save(r, w)

		fmt.Println(session.Values)

		fmt.Fprint(w, "{\"status\":\"success\"}")

	// 	if err == nil {
	// 		fmt.Fprint(w, "{\"status\":\"success\",\"uid\":", iq.Id, "}")
	// 	} else {
	// 		_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
	// 		if err == nil {
	// 			row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
	// 			err = row.Scan(&iq.Id)
	// 			if err == nil {
	// 				fmt.Fprint(w, "{\"status\":\"success\"},\"uid\":", iq.Id, "}")
	// 			} else {
	// 				fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 			}
	// 		} else {
	// 			fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 		}
	// 	}
	// } else {
	// 	fmt.Fprint(w, "{\"status\":\"failure\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>package s3sig

import (
	"os"
	"http"
	"time"
	"sort"
	"strings"
	"encoding/base64"
	"crypto/hmac"
)

var amzQueryParams = map[string]bool{
	"acl":                          true,
	"location":                     true,
	"logging":                      true,
	"notification":                 true,
	"partNumber":                   true,
	"policy":                       true,
	"requestPayment":               true,
	"torrent":                      true,
	"uploadId":                     true,
	"uploads":                      true,
	"versionId":                    true,
	"versioning":                   true,
	"versions":                     true,
	"website":                      true,
	"response-content-type":        true,
	"response-content-language":    true,
	"response-expires":             true,
	"response-cache-control":       true,
	"response-content-disposition": true,
	"response-content-encoding":    true,
}

func canonicalizedResource(url *http.URL) string {
	var res string

	// Strip any port declaration (443/80/8080/...)
	host := first(strings.SplitN(url.Host, ":", 2))

	if strings.HasSuffix(host, ".amazonaws.com") {
		// Hostname bucket style, ignore (s3-eu-west.|s3.)amazonaws.com
		parts := strings.SplitN(host, ".", -1)
		if len(parts) > 3 {
			res = res + "/" + strings.Join(parts[:len(parts)-3], ".")
		}
	} else if len(host) > 0 {
		// CNAME bucket style
		res = res + "/" + host
	} else {
		// Bucket as root element in path already
	}

	// RawPath will include the bucket if not in the host
	res = res + strings.SplitN(url.RawPath, "?", 2)[0]

	// Include a sorted list of query parameters that have
	// special meaning to aws.  These should stay decoded for
	// the canonical resource.
	var amz []string
	for key, values := range url.Query() {
		if amzQueryParams[key] {
			for _, value := range values {
				if value != "" {
					amz = append(amz, key+"="+value)
				} else {
					amz = append(amz, key)
				}
			}
		}
	}

	if len(amz) > 0 {
		sort.Strings(amz)
		res = res + "?" + strings.Join(amz, "&")
	}

	// All done.
	return res
}

func first(s []string) string {
	if len(s) > 0 {
		return s[0]
	}
	return ""
}

/*
	Creates the StringToSign string for either query string
	or Authorization header based authentication.
*/
func StringToSign(method string, url *http.URL, requestHeaders http.Header, expires string) string {
	// Positional headers are optional but should be captured
	var contentMD5, contentType, date, amzDate string
	var headers []string

	// Build the named, and capture the positional headers
	for name, values := range requestHeaders {
		name = strings.ToLower(name)

		switch name {
		case "date":
			date = first(values)
		case "content-type":
			contentType = first(values)
		case "content-md5":
			contentMD5 = first(values)
		default:
			if strings.HasPrefix(name, "x-amz-") {
				// Capture the x-amz-date header
				// Note: undefined behavior if there are more than
				// one of these headers
				if name == "x-amz-date" {
					amzDate = first(values)
				}

				// Assuming any rfc822 unfolding has happened already
				headers = append(headers, name+":"+strings.Join(values, ",")+"\n")
			}
		}
	}

	sort.Strings(headers)

	// overrideDate is used for query string "expires" auth
	// and is a unix timestamp
	switch {
	case expires != "":
		date = expires
	case amzDate != "":
		date = ""
	default:
		// Don't break referential transparency here by injecting
		// the date when the Date is empty.  Rather we assume the
		// caller knows what she is doing.
	}

	return method + "\n" +
		contentMD5 + "\n" +
		contentType + "\n" +
		date + "\n" +
		strings.Join(headers, "") +
		canonicalizedResource(url)
}

// Returns the signature to be used in the query string or Authorization header
func Signature(secret, toSign string) string {
	// Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of( YourSecretAccessKeyID, StringToSign ) ) );
	// Need to confirm what encoding go strings are when converted to []byte
	hmac := hmac.NewSHA1([]byte(secret))
	hmac.Write([]byte(toSign))

	return base64.StdEncoding.EncodeToString(hmac.Sum())
}

func Authorization(req *http.Request, key, secret string) string {
	return "AWS " + key + ":" + Signature(secret, StringToSign(req.Method, req.URL, req.Header, ""))
}

// Assumes no custom headers are sent so only needs access to a URL.
// If you plan on sending x-amz-* headers with a query string authorization
// you can use Signature(secret, StringToSign(url, headers, expires)) instead
// Returns an http.URL struct constructed from the Raw URL with the AWS
// query parameters appended at the end.
// Assumes any fragments are not included in url.Raw
func URL(url *http.URL, key, secret, method, expires string) (*http.URL, os.Error) {
	sig := Signature(secret, StringToSign(method, url, http.Header{}, expires))
	raw := url.Raw
	parts := strings.SplitN(raw, "?", 2)
	params := parts[1:]
	params = append(params, "AWSAccessKeyId="+key)
	params = append(params, "Expires="+expires)
	params = append(params, "Signature="+sig)
	signed := strings.Join(append(parts[:1], strings.Join(params, "&")), "?")

	return http.ParseURL(signed)
}

// Authorizes an http.Request pointer in place by in-place replacing the
// header of the provided request:
//
//	Authorization: AWS ACCOUNT SIGNATURE
//
// If the x-amz-date and Date headers are missing, this adds UTC current
// time in RFC1123 format inplace to the Date header:
//
//	Date: Mon, 02 Jan 2006 15:04:05 UTC
//
// If the Host does not appear in the req.URL, then it will be assigned
// from req.Host
func Authorize(req *http.Request, key, secret string) {
	var header string

	if req.URL.Host == "" {
		req.URL.Host = req.Host
	}

	if header = req.Header.Get("Date"); len(header) == 0 {
		if header = req.Header.Get("X-Amz-Date"); len(header) == 0 {
			req.Header.Set("Date", time.UTC().Format(time.RFC1123))
		}
	}

	req.Header.Set("Authorization", Authorization(req, key, secret))
}
<commit_msg>Go 0.60 compat with url package<commit_after>package s3sig

import (
	"os"
	"url"
	"http"
	"time"
	"sort"
	"strings"
	"encoding/base64"
	"crypto/hmac"
)

var amzQueryParams = map[string]bool{
	"acl":                          true,
	"location":                     true,
	"logging":                      true,
	"notification":                 true,
	"partNumber":                   true,
	"policy":                       true,
	"requestPayment":               true,
	"torrent":                      true,
	"uploadId":                     true,
	"uploads":                      true,
	"versionId":                    true,
	"versioning":                   true,
	"versions":                     true,
	"website":                      true,
	"response-content-type":        true,
	"response-content-language":    true,
	"response-expires":             true,
	"response-cache-control":       true,
	"response-content-disposition": true,
	"response-content-encoding":    true,
}

func canonicalizedResource(url *url.URL) string {
	var res string

	// Strip any port declaration (443/80/8080/...)
	host := first(strings.SplitN(url.Host, ":", 2))

	if strings.HasSuffix(host, ".amazonaws.com") {
		// Hostname bucket style, ignore (s3-eu-west.|s3.)amazonaws.com
		parts := strings.SplitN(host, ".", -1)
		if len(parts) > 3 {
			res = res + "/" + strings.Join(parts[:len(parts)-3], ".")
		}
	} else if len(host) > 0 {
		// CNAME bucket style
		res = res + "/" + host
	} else {
		// Bucket as root element in path already
	}

	// RawPath will include the bucket if not in the host
	res = res + strings.SplitN(url.RawPath, "?", 2)[0]

	// Include a sorted list of query parameters that have
	// special meaning to aws.  These should stay decoded for
	// the canonical resource.
	var amz []string
	for key, values := range url.Query() {
		if amzQueryParams[key] {
			for _, value := range values {
				if value != "" {
					amz = append(amz, key+"="+value)
				} else {
					amz = append(amz, key)
				}
			}
		}
	}

	if len(amz) > 0 {
		sort.Strings(amz)
		res = res + "?" + strings.Join(amz, "&")
	}

	// All done.
	return res
}

func first(s []string) string {
	if len(s) > 0 {
		return s[0]
	}
	return ""
}

/*
	Creates the StringToSign string for either query string
	or Authorization header based authentication.
*/
func StringToSign(method string, url *url.URL, requestHeaders http.Header, expires string) string {
	// Positional headers are optional but should be captured
	var contentMD5, contentType, date, amzDate string
	var headers []string

	// Build the named, and capture the positional headers
	for name, values := range requestHeaders {
		name = strings.ToLower(name)

		switch name {
		case "date":
			date = first(values)
		case "content-type":
			contentType = first(values)
		case "content-md5":
			contentMD5 = first(values)
		default:
			if strings.HasPrefix(name, "x-amz-") {
				// Capture the x-amz-date header
				// Note: undefined behavior if there are more than
				// one of these headers
				if name == "x-amz-date" {
					amzDate = first(values)
				}

				// Assuming any rfc822 unfolding has happened already
				headers = append(headers, name+":"+strings.Join(values, ",")+"\n")
			}
		}
	}

	sort.Strings(headers)

	// overrideDate is used for query string "expires" auth
	// and is a unix timestamp
	switch {
	case expires != "":
		date = expires
	case amzDate != "":
		date = ""
	default:
		// Don't break referential transparency here by injecting
		// the date when the Date is empty.  Rather we assume the
		// caller knows what she is doing.
	}

	return method + "\n" +
		contentMD5 + "\n" +
		contentType + "\n" +
		date + "\n" +
		strings.Join(headers, "") +
		canonicalizedResource(url)
}

// Returns the signature to be used in the query string or Authorization header
func Signature(secret, toSign string) string {
	// Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of( YourSecretAccessKeyID, StringToSign ) ) );
	// Need to confirm what encoding go strings are when converted to []byte
	hmac := hmac.NewSHA1([]byte(secret))
	hmac.Write([]byte(toSign))

	return base64.StdEncoding.EncodeToString(hmac.Sum())
}

func Authorization(req *http.Request, key, secret string) string {
	return "AWS " + key + ":" + Signature(secret, StringToSign(req.Method, req.URL, req.Header, ""))
}

// Assumes no custom headers are sent so only needs access to a URL.
// If you plan on sending x-amz-* headers with a query string authorization
// you can use Signature(secret, StringToSign(url, headers, expires)) instead
// Returns an url.URL struct constructed from the Raw URL with the AWS
// query parameters appended at the end.
// Assumes any fragments are not included in url.Raw
func URL(url *url.URL, key, secret, method, expires string) (*url.URL, os.Error) {
	sig := Signature(secret, StringToSign(method, url, http.Header{}, expires))
	raw := url.Raw
	parts := strings.SplitN(raw, "?", 2)
	params := parts[1:]
	params = append(params, "AWSAccessKeyId="+key)
	params = append(params, "Expires="+expires)
	params = append(params, "Signature="+sig)
	signed := strings.Join(append(parts[:1], strings.Join(params, "&")), "?")

	return url.Parse(signed)
}

// Authorizes an http.Request pointer in place by in-place replacing the
// header of the provided request:
//
//	Authorization: AWS ACCOUNT SIGNATURE
//
// If the x-amz-date and Date headers are missing, this adds UTC current
// time in RFC1123 format inplace to the Date header:
//
//	Date: Mon, 02 Jan 2006 15:04:05 UTC
//
// If the Host does not appear in the req.URL, then it will be assigned
// from req.Host
func Authorize(req *http.Request, key, secret string) {
	var header string

	if req.URL.Host == "" {
		req.URL.Host = req.Host
	}

	if header = req.Header.Get("Date"); len(header) == 0 {
		if header = req.Header.Get("X-Amz-Date"); len(header) == 0 {
			req.Header.Set("Date", time.UTC().Format(time.RFC1123))
		}
	}

	req.Header.Set("Authorization", Authorization(req, key, secret))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/ogier/pflag"
	"github.com/tidwall/gjson"
)

var listenPort uint
var consulAddressAndPort string

func init() {
	pflag.UintVarP(&listenPort, "port", "p", 31998, "siok listening port")
	pflag.StringVarP(&consulAddressAndPort, "agent", "a", "127.0.0.1:8500", "Consul Agent IP:port")
	pflag.Parse()
}

// getChecks creates an aggregate check output related
func getChecks(serviceID string) []Check {

	var checks []Check

	res, err := http.Get(fmt.Sprintf("http://%v/v1/agent/checks", consulAddressAndPort))
	if err != nil {
		// failure to connect to local agent should return critical
		checks = append(checks, Check{Output: err.Error(), Notes: "Consul Agent unavailable", Status: "critical"})
		return checks
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		// failure to parse the response from the local agent should return critical
		checks = append(checks, Check{Output: err.Error(), Notes: "Failed to parse the response from the Consul Agent", Status: "critical"})
		return checks
	}

	serviceExists := false
	result := gjson.ParseBytes(body)
	result.ForEach(func(_, value gjson.Result) bool {
		jsonServiceID := value.Get("ServiceID").String()

		if jsonServiceID == serviceID {
			serviceExists = true
		}

		// Reminder: if there is no service ID, that means the check/maint is node related
		if (jsonServiceID == serviceID) || (jsonServiceID == "") {
			var check Check

			check.ServiceID = jsonServiceID
			check.Name = value.Get("Name").String()
			check.Notes = value.Get("Notes").String()
			check.Output = value.Get("Output").String()
			check.Status = value.Get("Status").String()
			check.CheckID = value.Get("CheckID").String()

			checks = append(checks, check)
		}
		return true
	})

	if !serviceExists {
		checks = append(checks, Check{ServiceID: serviceID, Output: "No such service or no check associated with it", Status: "critical"})

	}
	return checks
}

// parseChecks returns the status, in the following order: critical > warning > passing
func parseChecks(checks []Check) string {
	var passing, warning, critical bool

	for _, check := range checks {
		switch check.Status {
		case "passing":
			passing = true
		case "warning":
			warning = true
		case "critical":
			critical = true
		default:
			passing = true
		}
	}

	switch {
	case critical:
		return "critical"
	case warning:
		return "warning"
	case passing:
		return "passing"
	default:
		return "passing"
	}
}

func getServiceHealth(c *gin.Context) {

	var service Service
	var warn Warn
	c.BindQuery(&service)
	c.BindQuery(&warn)
	warnEnabled := parseBoolValue(warn.warn)

	checks := getChecks(service.ID)

	aggregatedStatus := parseChecks(checks)

	// converting checks to an interface to be used by c.JSON
	var interfaceSlice = make([]interface{}, len(checks))
	for i, check := range checks {
		interfaceSlice[i] = check
	}

	switch aggregatedStatus {
	case "passing":
		c.JSON(200, interfaceSlice)
	case "warning":
		if warnEnabled {
			c.Header("Warning", "Some Consul checks failed, please investigate")
			c.JSON(200, interfaceSlice)
		} else {
			c.JSON(503, interfaceSlice)
		}
	case "critical":
		c.JSON(503, interfaceSlice)
	}
}

func parseBoolValue(val string) bool {
	if val == "true" {
		return true
	}
	return false
}

func main() {
	gin.SetMode(gin.ReleaseMode)
	route := gin.Default()
	route.GET("/health", getServiceHealth)
	log.Printf("Running siok on port %v...", listenPort)
	err := route.Run(fmt.Sprintf(":%v", listenPort))
	if err != nil {
		log.Printf("siok failed to start: %v", err.Error())
		os.Exit(1)
	}
}

// Service defines the data parsed from URL's querystring
type Service struct {
	ID string `form:"service"`
}

// Warn defines the data parsed from URL's querystring
type Warn struct {
	warn string `form:"warn"`
}

// Check defines the check data to be returned via the API's JSON response
type Check struct {
	CheckID   string `json:"CheckID"`
	Name      string `json:"Name"`
	Notes     string `json:"Notes"`
	Output    string `json:"Output"`
	ServiceID string `json:"ServiceID"`
	Status    string `json:"Status"`
}
<commit_msg>Tidying up.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/ogier/pflag"
	"github.com/tidwall/gjson"
)

var listenPort uint
var consulAddressAndPort string

func init() {
	pflag.UintVarP(&listenPort, "port", "p", 31998, "siok listening port")
	pflag.StringVarP(&consulAddressAndPort, "agent", "a", "127.0.0.1:8500", "Consul Agent IP:port")
	pflag.Parse()
}

// getChecks creates an aggregate check output related
func getChecks(serviceID string) []Check {

	var checks []Check

	res, err := http.Get(fmt.Sprintf("http://%v/v1/agent/checks", consulAddressAndPort))
	if err != nil {
		// failure to connect to local agent should return critical
		checks = append(checks, Check{Output: err.Error(), Notes: "Consul Agent unavailable", Status: "critical"})
		return checks
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		// failure to parse the response from the local agent should return critical
		checks = append(checks, Check{Output: err.Error(), Notes: "Failed to parse the response from the Consul Agent", Status: "critical"})
		return checks
	}

	serviceExists := false
	result := gjson.ParseBytes(body)
	result.ForEach(func(_, value gjson.Result) bool {
		jsonServiceID := value.Get("ServiceID").String()

		if jsonServiceID == serviceID {
			serviceExists = true
		}

		// Reminder: if there is no service ID, that means the check/maint is node related
		if (jsonServiceID == serviceID) || (jsonServiceID == "") {
			var check Check

			check.ServiceID = jsonServiceID
			check.Name = value.Get("Name").String()
			check.Notes = value.Get("Notes").String()
			check.Output = value.Get("Output").String()
			check.Status = value.Get("Status").String()
			check.CheckID = value.Get("CheckID").String()

			checks = append(checks, check)
		}
		return true
	})

	if !serviceExists {
		checks = append(checks, Check{ServiceID: serviceID, Output: "No such service or no check associated with it", Status: "critical"})

	}
	return checks
}

// parseChecks returns the status, in the following order: critical > warning > passing
func parseChecks(checks []Check) string {
	var passing, warning, critical bool

	for _, check := range checks {
		switch check.Status {
		case "passing":
			passing = true
		case "warning":
			warning = true
		case "critical":
			critical = true
		default:
			passing = true
		}
	}

	switch {
	case critical:
		return "critical"
	case warning:
		return "warning"
	case passing:
		return "passing"
	default:
		return "passing"
	}
}

func getServiceHealth(c *gin.Context) {

	var queryString QueryString
	c.BindQuery(&queryString)
	warnEnabled := parseBoolValue(queryString.Warn)

	checks := getChecks(queryString.ServiceID)

	aggregatedStatus := parseChecks(checks)

	// converting checks to an interface to be used by c.JSON
	var interfaceSlice = make([]interface{}, len(checks))
	for i, check := range checks {
		interfaceSlice[i] = check
	}

	switch aggregatedStatus {
	case "passing":
		c.JSON(200, interfaceSlice)
	case "warning":
		if warnEnabled {
			c.Header("Warning", "Some Consul checks failed, please investigate")
			c.JSON(200, interfaceSlice)
		} else {
			c.JSON(503, interfaceSlice)
		}
	case "critical":
		c.JSON(503, interfaceSlice)
	}
}

func parseBoolValue(val string) bool {
	if val == "true" {
		return true
	}
	return false
}

func main() {
	gin.SetMode(gin.ReleaseMode)
	route := gin.Default()
	route.GET("/health", getServiceHealth)
	log.Printf("Running siok on port %v...", listenPort)
	err := route.Run(fmt.Sprintf(":%v", listenPort))
	if err != nil {
		log.Printf("siok failed to start: %v", err.Error())
		os.Exit(1)
	}
}

// QueryString defines the data parsed from URL's querystring
type QueryString struct {
	ServiceID string `form:"service"`
	Warn      string `form:"warn"`
}

// Check defines the check data to be returned via the API's JSON response
type Check struct {
	CheckID   string `json:"CheckID"`
	Name      string `json:"Name"`
	Notes     string `json:"Notes"`
	Output    string `json:"Output"`
	ServiceID string `json:"ServiceID"`
	Status    string `json:"Status"`
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"sort"
	"text/tabwriter"
)

const VERSION = `0.1.1`

var languages = []Language{
	Language{"Thrift", mExt(".thrift"), cComments},

	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Scala", mExt(".scala"), cComments},
	Language{"Java", mExt(".java"), cComments},

	Language{"Haskell", mExt(".hs", ".lhs"), hsComments},
	Language{"Perl", mExt(".pl", ".pm"), shComments},

	Language{"Shell", mExt(".sh"), shComments},
	Language{"Bash", mExt(".bash"), shComments},

	Language{"Ruby", mExt(".rb"), shComments},
	Language{"Python", mExt(".py"), pyComments},
	Language{"Assembly", mExt(".asm", ".s"), semiComments},
	Language{"Lisp", mExt(".lsp", ".lisp"), semiComments},
	Language{"Scheme", mExt(".scm", ".scheme"), semiComments},

	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"Jam", mName("Jamfile", "Jamrules"), shComments},

	Language{"Markdown", mExt(".md"), noComments},

	Language{"HAML", mExt(".haml"), noComments},
	Language{"SASS", mExt(".sass"), cssComments},
	Language{"SCSS", mExt(".scss"), cssComments},

	Language{"HTML", mExt(".htm", ".html", ".xhtml"), xmlComments},
	Language{"XML", mExt(".xml"), xmlComments},
	Language{"CSS", mExt(".css"), cssComments},
	Language{"JavaScript", mExt(".js"), cComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments = Commenter{"\000", "\000", "\000", false}
	xmlComments = Commenter{"\000", `<!--`, `-->`, false}
	cComments  = Commenter{`//`, `/*`, `*/`, false}
	cssComments  = Commenter{"\000", `/*`, `*/`, false}
	shComments = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
	hsComments  = Commenter{`--`, `{-`, `-}`, true}
	pyComments = Commenter{`#`, `"""`, `"""`, false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

// TODO work properly with unicode
func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if inComment == 0 && b == lc[lp] {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else { lp = 0 }
		if !inLComment && b == sc[sp] {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else { sp = 0 }
		if !inLComment && inComment > 0 && b == ec[ep] {
			ep++
			if ep == len(ec) {
				if inComment > 0 { inComment-- }
				ep = 0
			}
		} else { ep = 0 }

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// BUG(srl): lines with comment don't count towards code
		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if inComment > 0 || inLComment {
				inLComment = false
				s.CommentLines++
			} else if blank {
				s.BlankLines++
			} else { s.CodeLines++ }
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFile(fname string) {
	var l Language
	ok := false
	for _, lang := range languages {
		if lang.Match(fname) {
			ok = true
			l = lang
			break
		}
	}
	if !ok {
		return // ignore this file
	}
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

type LData []LResult

func (d LData) Len() int { return len(d) }

func (d LData) Less(i, j int) bool {
	if d[i].CodeLines == d[j].CodeLines {
		return d[i].Name > d[j].Name
	}
	return d[i].CodeLines > d[j].CodeLines
}

func (d LData) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

type LResult struct {
	Name string
	FileCount int
	CodeLines int
	CommentLines int
	BlankLines int
	TotalLines int
}

func (r *LResult) Add(a LResult) {
	r.FileCount += a.FileCount
	r.CodeLines += a.CodeLines
	r.CommentLines += a.CommentLines
	r.BlankLines += a.BlankLines
	r.TotalLines += a.TotalLines
}

func printJSON() {
	bs, err := json.MarshalIndent(info, "", "  ")
	if err != nil { panic(err) }
	fmt.Println(string(bs))
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	d := LData([]LResult{})
	total := &LResult{}
	total.Name = "Total"
	for n, i := range info {
		r := LResult{
			n,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines,
		}
		d = append(d, r)
		total.Add(r)
	}
	d = append(d, *total)
	sort.Sort(d)
	//d[0].Name = "Total"
	for _, i := range d {
		fmt.Fprintf(
			w,
			"%s\t%d\t%d\t%d\t%d\t%d\t\n",
			i.Name,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines)
	}

	w.Flush()
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	useJson = flag.Bool("json", false, "JSON-format output")
	version = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}

	if *useJson {
		printJSON()
	} else {
		printInfo()
	}
}
<commit_msg>Adding cmake<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"sort"
	"text/tabwriter"
)

const VERSION = `0.1.1`

var languages = []Language{
	Language{"Thrift", mExt(".thrift"), cComments},

	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Scala", mExt(".scala"), cComments},
	Language{"Java", mExt(".java"), cComments},

	Language{"Haskell", mExt(".hs", ".lhs"), hsComments},
	Language{"Perl", mExt(".pl", ".pm"), shComments},

	Language{"Shell", mExt(".sh"), shComments},
	Language{"Bash", mExt(".bash"), shComments},

	Language{"Ruby", mExt(".rb"), shComments},
	Language{"Python", mExt(".py"), pyComments},
	Language{"Assembly", mExt(".asm", ".s"), semiComments},
	Language{"Lisp", mExt(".lsp", ".lisp"), semiComments},
	Language{"Scheme", mExt(".scm", ".scheme"), semiComments},

	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"CMake", mName("CMakeLists.txt"), shComments},
	Language{"Jam", mName("Jamfile", "Jamrules"), shComments},

	Language{"Markdown", mExt(".md"), noComments},

	Language{"HAML", mExt(".haml"), noComments},
	Language{"SASS", mExt(".sass"), cssComments},
	Language{"SCSS", mExt(".scss"), cssComments},

	Language{"HTML", mExt(".htm", ".html", ".xhtml"), xmlComments},
	Language{"XML", mExt(".xml"), xmlComments},
	Language{"CSS", mExt(".css"), cssComments},
	Language{"JavaScript", mExt(".js"), cComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments = Commenter{"\000", "\000", "\000", false}
	xmlComments = Commenter{"\000", `<!--`, `-->`, false}
	cComments  = Commenter{`//`, `/*`, `*/`, false}
	cssComments  = Commenter{"\000", `/*`, `*/`, false}
	shComments = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
	hsComments  = Commenter{`--`, `{-`, `-}`, true}
	pyComments = Commenter{`#`, `"""`, `"""`, false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

// TODO work properly with unicode
func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if inComment == 0 && b == lc[lp] {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else { lp = 0 }
		if !inLComment && b == sc[sp] {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else { sp = 0 }
		if !inLComment && inComment > 0 && b == ec[ep] {
			ep++
			if ep == len(ec) {
				if inComment > 0 { inComment-- }
				ep = 0
			}
		} else { ep = 0 }

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// BUG(srl): lines with comment don't count towards code
		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if inComment > 0 || inLComment {
				inLComment = false
				s.CommentLines++
			} else if blank {
				s.BlankLines++
			} else { s.CodeLines++ }
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFile(fname string) {
	var l Language
	ok := false
	for _, lang := range languages {
		if lang.Match(fname) {
			ok = true
			l = lang
			break
		}
	}
	if !ok {
		return // ignore this file
	}
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

type LData []LResult

func (d LData) Len() int { return len(d) }

func (d LData) Less(i, j int) bool {
	if d[i].CodeLines == d[j].CodeLines {
		return d[i].Name > d[j].Name
	}
	return d[i].CodeLines > d[j].CodeLines
}

func (d LData) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

type LResult struct {
	Name string
	FileCount int
	CodeLines int
	CommentLines int
	BlankLines int
	TotalLines int
}

func (r *LResult) Add(a LResult) {
	r.FileCount += a.FileCount
	r.CodeLines += a.CodeLines
	r.CommentLines += a.CommentLines
	r.BlankLines += a.BlankLines
	r.TotalLines += a.TotalLines
}

func printJSON() {
	bs, err := json.MarshalIndent(info, "", "  ")
	if err != nil { panic(err) }
	fmt.Println(string(bs))
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	d := LData([]LResult{})
	total := &LResult{}
	total.Name = "Total"
	for n, i := range info {
		r := LResult{
			n,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines,
		}
		d = append(d, r)
		total.Add(r)
	}
	d = append(d, *total)
	sort.Sort(d)
	//d[0].Name = "Total"
	for _, i := range d {
		fmt.Fprintf(
			w,
			"%s\t%d\t%d\t%d\t%d\t%d\t\n",
			i.Name,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines)
	}

	w.Flush()
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	useJson = flag.Bool("json", false, "JSON-format output")
	version = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}

	if *useJson {
		printJSON()
	} else {
		printInfo()
	}
}
<|endoftext|>


<commit_before>// Package smaz is an implementation of the smaz library (https://github.com/antirez/smaz) for compressing
// small strings.
package smaz

import (
	"bytes"
	"errors"

	"github.com/cespare/go-smaz/trie"
)

var codeStrings = []string{" ",
	"the", "e", "t", "a", "of", "o", "and", "i", "n", "s", "e ", "r", " th",
	" t", "in", "he", "th", "h", "he ", "to", "\r\n", "l", "s ", "d", " a", "an",
	"er", "c", " o", "d ", "on", " of", "re", "of ", "t ", ", ", "is", "u", "at",
	"   ", "n ", "or", "which", "f", "m", "as", "it", "that", "\n", "was", "en",
	"  ", " w", "es", " an", " i", "\r", "f ", "g", "p", "nd", " s", "nd ", "ed ",
	"w", "ed", "http://", "for", "te", "ing", "y ", "The", " c", "ti", "r ", "his",
	"st", " in", "ar", "nt", ",", " to", "y", "ng", " h", "with", "le", "al", "to ",
	"b", "ou", "be", "were", " b", "se", "o ", "ent", "ha", "ng ", "their", "\"",
	"hi", "from", " f", "in ", "de", "ion", "me", "v", ".", "ve", "all", "re ",
	"ri", "ro", "is ", "co", "f t", "are", "ea", ". ", "her", " m", "er ", " p",
	"es ", "by", "they", "di", "ra", "ic", "not", "s, ", "d t", "at ", "ce", "la",
	"h ", "ne", "as ", "tio", "on ", "n t", "io", "we", " a ", "om", ", a", "s o",
	"ur", "li", "ll", "ch", "had", "this", "e t", "g ", "e\r\n", " wh", "ere",
	" co", "e o", "a ", "us", " d", "ss", "\n\r\n", "\r\n\r", "=\"", " be", " e",
	"s a", "ma", "one", "t t", "or ", "but", "el", "so", "l ", "e s", "s,", "no",
	"ter", " wa", "iv", "ho", "e a", " r", "hat", "s t", "ns", "ch ", "wh", "tr",
	"ut", "/", "have", "ly ", "ta", " ha", " on", "tha", "-", " l", "ati", "en ",
	"pe", " re", "there", "ass", "si", " fo", "wa", "ec", "our", "who", "its", "z",
	"fo", "rs", ">", "ot", "un", "<", "im", "th ", "nc", "ate", "><", "ver", "ad",
	" we", "ly", "ee", " n", "id", " cl", "ac", "il", "</", "rt", " wi", "div",
	"e, ", " it", "whi", " ma", "ge", "x", "e c", "men", ".com",
}

var codes = make([][]byte, len(codeStrings))
var codeTrie = trie.New()

func init() {
	for i, code := range codeStrings {
		codes[i] = []byte(code)
		codeTrie.Put([]byte(code), i)
	}
}

func flushVerb(outBuf, verbBuf *bytes.Buffer) {
	// We can write a max of 255 continuous verbatim characters, because the length of the continous verbatim
	// section is represented by a single byte.
	for verbBuf.Len() > 0 {
		chunk := verbBuf.Next(255)
		if len(chunk) == 1 {
			// 254 is code for a single verbatim byte
			outBuf.WriteByte(byte(254))
		} else {
			// 255 is code for a verbatim string. It is followed by a byte containing the length of the string.
			outBuf.WriteByte(byte(255))
			outBuf.WriteByte(byte(len(chunk)))
		}
		outBuf.Write(chunk)
	}
	verbBuf.Reset()
}

// Compress compresses a byte slice and returns the compressed data.
func Compress(input []byte) []byte {
	var outBuf bytes.Buffer
	var verbBuf bytes.Buffer
	root := codeTrie.Root()

	for len(input) > 0 {
		prefixLen := 0
		code := 0
		node := root
		for i, c := range input {
			next, ok := node.Walk(c)
			if !ok {
				break
			}
			node = next
			if node.Terminal() {
				prefixLen = i + 1
				code = node.Val()
			}
		}

		if prefixLen > 0 {
			input = input[prefixLen:]
			flushVerb(&outBuf, &verbBuf)
			outBuf.WriteByte(byte(code))
		} else {
			verbBuf.WriteByte(input[0])
			input = input[1:]
		}
	}
	flushVerb(&outBuf, &verbBuf)

	return outBuf.Bytes()
}

// DecompressionError is returned when decompressing invalid smaz-encoded data.
var DecompressionError = errors.New("Invalid or corrupted compressed data.")

// Decompress decompresses a smaz-compressed byte slice and return a new slice with the decompressed data. err
// is nil if and only if decompression fails for any reason (e.g., corrupted data).
func Decompress(compressed []byte) ([]byte, error) {
	decompressed := bytes.NewBuffer(make([]byte, 0, len(compressed))) // Estimate initial size

	for len(compressed) > 0 {
		switch compressed[0] {
		case 254: // Verbatim byte
			if len(compressed) < 2 {
				return nil, DecompressionError
			}
			decompressed.WriteByte(compressed[1])
			compressed = compressed[2:]
		case 255: // Verbatim string
			if len(compressed) < 2 {
				return nil, DecompressionError
			}
			n := int(compressed[1])
			if len(compressed) < n+2 {
				return nil, DecompressionError
			}
			decompressed.Write(compressed[2 : n+2])
			compressed = compressed[n+2:]
		default: // Look up encoded value
			decompressed.Write(codes[int(compressed[0])])
			compressed = compressed[1:]
		}
	}

	return decompressed.Bytes(), nil
}
<commit_msg>Lint pass<commit_after>// Package smaz is an implementation of the smaz library (https://github.com/antirez/smaz) for compressing
// small strings.
package smaz

import (
	"bytes"
	"errors"

	"github.com/cespare/go-smaz/trie"
)

var codeStrings = []string{" ",
	"the", "e", "t", "a", "of", "o", "and", "i", "n", "s", "e ", "r", " th",
	" t", "in", "he", "th", "h", "he ", "to", "\r\n", "l", "s ", "d", " a", "an",
	"er", "c", " o", "d ", "on", " of", "re", "of ", "t ", ", ", "is", "u", "at",
	"   ", "n ", "or", "which", "f", "m", "as", "it", "that", "\n", "was", "en",
	"  ", " w", "es", " an", " i", "\r", "f ", "g", "p", "nd", " s", "nd ", "ed ",
	"w", "ed", "http://", "for", "te", "ing", "y ", "The", " c", "ti", "r ", "his",
	"st", " in", "ar", "nt", ",", " to", "y", "ng", " h", "with", "le", "al", "to ",
	"b", "ou", "be", "were", " b", "se", "o ", "ent", "ha", "ng ", "their", "\"",
	"hi", "from", " f", "in ", "de", "ion", "me", "v", ".", "ve", "all", "re ",
	"ri", "ro", "is ", "co", "f t", "are", "ea", ". ", "her", " m", "er ", " p",
	"es ", "by", "they", "di", "ra", "ic", "not", "s, ", "d t", "at ", "ce", "la",
	"h ", "ne", "as ", "tio", "on ", "n t", "io", "we", " a ", "om", ", a", "s o",
	"ur", "li", "ll", "ch", "had", "this", "e t", "g ", "e\r\n", " wh", "ere",
	" co", "e o", "a ", "us", " d", "ss", "\n\r\n", "\r\n\r", "=\"", " be", " e",
	"s a", "ma", "one", "t t", "or ", "but", "el", "so", "l ", "e s", "s,", "no",
	"ter", " wa", "iv", "ho", "e a", " r", "hat", "s t", "ns", "ch ", "wh", "tr",
	"ut", "/", "have", "ly ", "ta", " ha", " on", "tha", "-", " l", "ati", "en ",
	"pe", " re", "there", "ass", "si", " fo", "wa", "ec", "our", "who", "its", "z",
	"fo", "rs", ">", "ot", "un", "<", "im", "th ", "nc", "ate", "><", "ver", "ad",
	" we", "ly", "ee", " n", "id", " cl", "ac", "il", "</", "rt", " wi", "div",
	"e, ", " it", "whi", " ma", "ge", "x", "e c", "men", ".com",
}

var codes = make([][]byte, len(codeStrings))
var codeTrie = trie.New()

func init() {
	for i, code := range codeStrings {
		codes[i] = []byte(code)
		codeTrie.Put([]byte(code), i)
	}
}

func flushVerb(outBuf, verbBuf *bytes.Buffer) {
	// We can write a max of 255 continuous verbatim characters, because the length of the continous verbatim
	// section is represented by a single byte.
	for verbBuf.Len() > 0 {
		chunk := verbBuf.Next(255)
		if len(chunk) == 1 {
			// 254 is code for a single verbatim byte
			outBuf.WriteByte(byte(254))
		} else {
			// 255 is code for a verbatim string. It is followed by a byte containing the length of the string.
			outBuf.WriteByte(byte(255))
			outBuf.WriteByte(byte(len(chunk)))
		}
		outBuf.Write(chunk)
	}
	verbBuf.Reset()
}

// Compress compresses a byte slice and returns the compressed data.
func Compress(input []byte) []byte {
	var outBuf bytes.Buffer
	var verbBuf bytes.Buffer
	root := codeTrie.Root()

	for len(input) > 0 {
		prefixLen := 0
		code := 0
		node := root
		for i, c := range input {
			next, ok := node.Walk(c)
			if !ok {
				break
			}
			node = next
			if node.Terminal() {
				prefixLen = i + 1
				code = node.Val()
			}
		}

		if prefixLen > 0 {
			input = input[prefixLen:]
			flushVerb(&outBuf, &verbBuf)
			outBuf.WriteByte(byte(code))
		} else {
			verbBuf.WriteByte(input[0])
			input = input[1:]
		}
	}
	flushVerb(&outBuf, &verbBuf)

	return outBuf.Bytes()
}

// ErrDecompression is returned when decompressing invalid smaz-encoded data.
var ErrDecompression = errors.New("invalid or corrupted compressed data")

// Decompress decompresses a smaz-compressed byte slice and return a new slice with the decompressed data. err
// is nil if and only if decompression fails for any reason (e.g., corrupted data).
func Decompress(compressed []byte) ([]byte, error) {
	decompressed := bytes.NewBuffer(make([]byte, 0, len(compressed))) // Estimate initial size

	for len(compressed) > 0 {
		switch compressed[0] {
		case 254: // Verbatim byte
			if len(compressed) < 2 {
				return nil, ErrDecompression
			}
			decompressed.WriteByte(compressed[1])
			compressed = compressed[2:]
		case 255: // Verbatim string
			if len(compressed) < 2 {
				return nil, ErrDecompression
			}
			n := int(compressed[1])
			if len(compressed) < n+2 {
				return nil, ErrDecompression
			}
			decompressed.Write(compressed[2 : n+2])
			compressed = compressed[n+2:]
		default: // Look up encoded value
			decompressed.Write(codes[int(compressed[0])])
			compressed = compressed[1:]
		}
	}

	return decompressed.Bytes(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/lomik/carbon-clickhouse/carbon"
	"github.com/lomik/carbon-clickhouse/helper/RowBinary"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"

	_ "net/http/pprof"
)

// Version of carbon-clickhouse
const Version = "0.11.1"

func httpServe(addr string) (func(), error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return nil, err
	}

	go http.Serve(listener, nil)
	return func() { listener.Close() }, nil
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/carbon-clickhouse/carbon-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	printVersion := flag.Bool("version", false, "Print version")
	cat := flag.String("cat", "", "Print RowBinary file in TabSeparated format")
	bincat := flag.String("recover", "", "Read all good records from corrupted data file. Write binary data to stdout")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *cat != "" {
		reader, err := RowBinary.NewReader(*cat, false)
		if err != nil {
			log.Fatal(err)
		}

		for {
			metric, err := reader.ReadRecord()
			if err != nil {
				if err == io.EOF {
					return
				}
				log.Fatal(err)
			}

			fmt.Printf("%s\t%#v\t%d\t%s\t%d\n",
				string(metric),
				reader.Value(),
				reader.Timestamp(),
				reader.DaysString(),
				reader.Version(),
			)
		}
	}

	if *bincat != "" {
		reader, err := RowBinary.NewReader(*bincat, false)
		if err != nil {
			log.Fatal(err)
		}

		io.Copy(os.Stdout, reader)
		return
	}

	if *printDefaultConfig {
		if err = carbon.PrintDefaultConfig(); err != nil {
			log.Fatal(err)
		}
		return
	}

	app := carbon.New(*configFile)

	if err = app.ParseConfig(); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	cfg := app.Config

	if err = zapwriter.ApplyConfig(cfg.Logging); err != nil {
		log.Fatal(err)
	}

	mainLogger := zapwriter.Logger("main")

	/* CONFIG end */

	// pprof
	if cfg.Pprof.Enabled {
		_, err = httpServe(cfg.Pprof.Listen)
		if err != nil {
			mainLogger.Fatal("pprof listen failed", zap.Error(err))
		}
	}

	if err = app.Start(); err != nil {
		mainLogger.Fatal("app start failed", zap.Error(err))
	} else {
		mainLogger.Info("app started")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP)

		for {
			s := <-c
			switch s {
			case syscall.SIGUSR1:
				mainLogger.Info("SIGUSR1 received. Clear tree cache")
				app.Reset()
			case syscall.SIGUSR2:
				mainLogger.Info("SIGUSR2 received. Ignoring")
			case syscall.SIGHUP:
				mainLogger.Info("SIGHUP received. Ignoring")
			}
		}
	}()

	app.Loop()

	mainLogger.Info("app stopped")
}
<commit_msg>AD-12849 rolled back version change<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/lomik/carbon-clickhouse/carbon"
	"github.com/lomik/carbon-clickhouse/helper/RowBinary"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"

	_ "net/http/pprof"
)

// Version of carbon-clickhouse
const Version = "0.11.0"

func httpServe(addr string) (func(), error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return nil, err
	}

	go http.Serve(listener, nil)
	return func() { listener.Close() }, nil
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/carbon-clickhouse/carbon-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	printVersion := flag.Bool("version", false, "Print version")
	cat := flag.String("cat", "", "Print RowBinary file in TabSeparated format")
	bincat := flag.String("recover", "", "Read all good records from corrupted data file. Write binary data to stdout")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *cat != "" {
		reader, err := RowBinary.NewReader(*cat, false)
		if err != nil {
			log.Fatal(err)
		}

		for {
			metric, err := reader.ReadRecord()
			if err != nil {
				if err == io.EOF {
					return
				}
				log.Fatal(err)
			}

			fmt.Printf("%s\t%#v\t%d\t%s\t%d\n",
				string(metric),
				reader.Value(),
				reader.Timestamp(),
				reader.DaysString(),
				reader.Version(),
			)
		}
	}

	if *bincat != "" {
		reader, err := RowBinary.NewReader(*bincat, false)
		if err != nil {
			log.Fatal(err)
		}

		io.Copy(os.Stdout, reader)
		return
	}

	if *printDefaultConfig {
		if err = carbon.PrintDefaultConfig(); err != nil {
			log.Fatal(err)
		}
		return
	}

	app := carbon.New(*configFile)

	if err = app.ParseConfig(); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	cfg := app.Config

	if err = zapwriter.ApplyConfig(cfg.Logging); err != nil {
		log.Fatal(err)
	}

	mainLogger := zapwriter.Logger("main")

	/* CONFIG end */

	// pprof
	if cfg.Pprof.Enabled {
		_, err = httpServe(cfg.Pprof.Listen)
		if err != nil {
			mainLogger.Fatal("pprof listen failed", zap.Error(err))
		}
	}

	if err = app.Start(); err != nil {
		mainLogger.Fatal("app start failed", zap.Error(err))
	} else {
		mainLogger.Info("app started")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP)

		for {
			s := <-c
			switch s {
			case syscall.SIGUSR1:
				mainLogger.Info("SIGUSR1 received. Clear tree cache")
				app.Reset()
			case syscall.SIGUSR2:
				mainLogger.Info("SIGUSR2 received. Ignoring")
			case syscall.SIGHUP:
				mainLogger.Info("SIGHUP received. Ignoring")
			}
		}
	}()

	app.Loop()

	mainLogger.Info("app stopped")
}
<|endoftext|>


<commit_before>package model

import (
	"testing"

	"fmt"

	"strings"

	"github.com/evandroflores/claimr/messages"
	"github.com/stretchr/testify/assert"
)

func TestGetContainerNoTeam(t *testing.T) {
	container, err := GetContainer("", "", "")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestGetContainerNoChannel(t *testing.T) {
	container, err := GetContainer("TestTeam", "", "")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestGetContainerNoName(t *testing.T) {
	container, err := GetContainer("TestTeam", "TestChannel", "")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestGetContainerBigName(t *testing.T) {
	container, err := GetContainer("TestTeam", "TestChannel",
		"LoremIpsumDolorSitAmetConsecteturAdipiscingElit")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-name-too-big"), MaxNameSize))
}

func TestGetContainerNotFound(t *testing.T) {
	containerName := "TestDoesNotExist"
	container, err := GetContainer("TestTeam", "TestChannel", containerName)

	assert.ObjectsAreEqual(Container{}, container)
	assert.NoError(t, err, fmt.Sprintf("Container %s not found", containerName))
}

func TestGetContainerIgnoreCase(t *testing.T) {
	containerName := "UPPERCASE_NAME"
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: containerName}
	err := container.Add()
	assert.NoError(t, err)

	containerFromDB, err2 := GetContainer("TestTeam", "TestChannel", containerName)

	assert.NoError(t, err2)
	assert.Equal(t, containerFromDB.Name, strings.ToLower(containerName))

	container.Delete()
}

func TestAddContainer(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Add()
	assert.NoError(t, err)

	containerFromDB, err2 := GetContainer("TestTeam", "TestChannel", "Name")

	assert.NoError(t, err2)
	assert.ObjectsAreEqual(container, containerFromDB)
}

func TestAddContainerValidateTeamID(t *testing.T) {
	container := Container{TeamID: "", ChannelID: "", Name: ""}
	err := container.Add()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestAddContainerValidateChannelID(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "", Name: ""}
	err := container.Add()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestAddContainerValidateName(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: ""}
	err := container.Add()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestAddContainerDuplicate(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Add()
	assert.EqualError(t, err, messages.Get("same-name"))
}

func TestDeleteContainer(t *testing.T) {
	container, err := GetContainer("TestTeam", "TestChannel", "Name")
	assert.NoError(t, err)

	err2 := container.Delete()
	assert.NoError(t, err2)
}

func TestDeleteContainerValidateTeamID(t *testing.T) {
	container := Container{TeamID: "", ChannelID: "", Name: ""}
	err := container.Delete()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestDeleteContainerValidateChannelID(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "", Name: ""}
	err := container.Delete()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestDeleteContainerValidateName(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: ""}
	err := container.Delete()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestDeleteContainerNotFound(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Delete()
	assert.EqualError(t, err, messages.Get("container-not-found"))

}

func TestUpdateContainer(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Add()
	assert.NoError(t, err)

	container.InUseBy = "me"
	err2 := container.Update()
	assert.NoError(t, err2)

	containerUpdated := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}

	assert.ObjectsAreEqual(containerUpdated.InUseBy, "me")
	assert.ObjectsAreEqual(container, containerUpdated)
	container.Delete()
}

func TestUpdateContainerValidateTeamID(t *testing.T) {
	container := Container{TeamID: "", ChannelID: "", Name: ""}
	err := container.Update()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestUpdateContainerValidateChannelID(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "", Name: ""}
	err := container.Update()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestUpdateContainerValidateName(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: ""}
	err := container.Update()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestUpdateContainerNotFound(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Update()
	assert.EqualError(t, err, messages.Get("container-not-found"))
}

func TestListContainers(t *testing.T) {
	names := [4]string{"A", "B", "C", "D"}
	for _, name := range names {
		container := Container{TeamID: "TestList", ChannelID: "TestChannel", Name: name}
		err := container.Add()
		assert.NoError(t, err)
	}

	containers, err2 := GetContainers("TestList", "TestChannel")
	assert.NoError(t, err2)

	assert.Len(t, containers, len(names))
	for idx, container := range containers {
		assert.ObjectsAreEqual(container.Name, names[idx])
		container.Delete()
	}
}

func TestListContainersValidateTeamID(t *testing.T) {
	containers, err := GetContainers("", "")
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
	assert.ObjectsAreEqual(containers, []Container{})
}

func TestListContainersValidateChannelID(t *testing.T) {
	containers, err := GetContainers("TestTeam", "")
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
	assert.ObjectsAreEqual(containers, []Container{})
}

func TestRemoveInUseData(t *testing.T) {
	team := "TestTeam"
	channel := "TestChannel"
	containerName := "name"
	user := "User"
	reason := "testing"

	container := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: user, InUseForReason: reason}
	err := container.Add()
	assert.NoError(t, err)

	err2 := container.ClearInUse()
	assert.NoError(t, err2)

	containerExpected := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: "", InUseForReason: ""}
	containerFromDB, err3 := GetContainer(team, channel, containerName)
	assert.NoError(t, err3)

	// Ignoring the difference for this fields
	containerExpected.ID = containerFromDB.ID
	containerExpected.CreatedAt = containerFromDB.CreatedAt
	containerExpected.UpdatedAt = containerFromDB.UpdatedAt
	containerExpected.DeletedAt = containerFromDB.DeletedAt

	assert.Empty(t, containerFromDB.InUseBy)
	assert.Empty(t, containerFromDB.InUseForReason)
	assert.Equal(t, containerExpected, containerFromDB)
	container.Delete()
}

func TestSetInUseData(t *testing.T) {
	team := "TestTeam"
	channel := "TestChannel"
	containerName := "name"
	user := "User"
	reason := "testing"

	container := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: "", InUseForReason: ""}
	err := container.Add()
	assert.NoError(t, err)

	err2 := container.SetInUse(user, reason)
	assert.NoError(t, err2)

	containerExpected := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: user, InUseForReason: reason}
	containerFromDB, err3 := GetContainer(team, channel, containerName)
	assert.NoError(t, err3)

	// Ignoring the difference for this fields
	containerExpected.ID = containerFromDB.ID
	containerExpected.CreatedAt = containerFromDB.CreatedAt
	containerExpected.UpdatedAt = containerFromDB.UpdatedAt
	containerExpected.DeletedAt = containerFromDB.DeletedAt

	assert.Equal(t, containerExpected, containerFromDB)
	container.Delete()
}

func TestInUseTextInvalid(t *testing.T) {
	container := Container{}
	assert.Equal(t, messages.Get("in-use-text-invalid"), container.InUseText("whatever"))
}
<commit_msg>InUseText Simple Available test<commit_after>package model

import (
	"testing"

	"fmt"

	"strings"

	"github.com/evandroflores/claimr/messages"
	"github.com/stretchr/testify/assert"
)

func TestGetContainerNoTeam(t *testing.T) {
	container, err := GetContainer("", "", "")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestGetContainerNoChannel(t *testing.T) {
	container, err := GetContainer("TestTeam", "", "")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestGetContainerNoName(t *testing.T) {
	container, err := GetContainer("TestTeam", "TestChannel", "")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestGetContainerBigName(t *testing.T) {
	container, err := GetContainer("TestTeam", "TestChannel",
		"LoremIpsumDolorSitAmetConsecteturAdipiscingElit")

	assert.ObjectsAreEqual(Container{}, container)
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-name-too-big"), MaxNameSize))
}

func TestGetContainerNotFound(t *testing.T) {
	containerName := "TestDoesNotExist"
	container, err := GetContainer("TestTeam", "TestChannel", containerName)

	assert.ObjectsAreEqual(Container{}, container)
	assert.NoError(t, err, fmt.Sprintf("Container %s not found", containerName))
}

func TestGetContainerIgnoreCase(t *testing.T) {
	containerName := "UPPERCASE_NAME"
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: containerName}
	err := container.Add()
	assert.NoError(t, err)

	containerFromDB, err2 := GetContainer("TestTeam", "TestChannel", containerName)

	assert.NoError(t, err2)
	assert.Equal(t, containerFromDB.Name, strings.ToLower(containerName))

	container.Delete()
}

func TestAddContainer(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Add()
	assert.NoError(t, err)

	containerFromDB, err2 := GetContainer("TestTeam", "TestChannel", "Name")

	assert.NoError(t, err2)
	assert.ObjectsAreEqual(container, containerFromDB)
}

func TestAddContainerValidateTeamID(t *testing.T) {
	container := Container{TeamID: "", ChannelID: "", Name: ""}
	err := container.Add()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestAddContainerValidateChannelID(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "", Name: ""}
	err := container.Add()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestAddContainerValidateName(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: ""}
	err := container.Add()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestAddContainerDuplicate(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Add()
	assert.EqualError(t, err, messages.Get("same-name"))
}

func TestDeleteContainer(t *testing.T) {
	container, err := GetContainer("TestTeam", "TestChannel", "Name")
	assert.NoError(t, err)

	err2 := container.Delete()
	assert.NoError(t, err2)
}

func TestDeleteContainerValidateTeamID(t *testing.T) {
	container := Container{TeamID: "", ChannelID: "", Name: ""}
	err := container.Delete()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestDeleteContainerValidateChannelID(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "", Name: ""}
	err := container.Delete()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestDeleteContainerValidateName(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: ""}
	err := container.Delete()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestDeleteContainerNotFound(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Delete()
	assert.EqualError(t, err, messages.Get("container-not-found"))

}

func TestUpdateContainer(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Add()
	assert.NoError(t, err)

	container.InUseBy = "me"
	err2 := container.Update()
	assert.NoError(t, err2)

	containerUpdated := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}

	assert.ObjectsAreEqual(containerUpdated.InUseBy, "me")
	assert.ObjectsAreEqual(container, containerUpdated)
	container.Delete()
}

func TestUpdateContainerValidateTeamID(t *testing.T) {
	container := Container{TeamID: "", ChannelID: "", Name: ""}
	err := container.Update()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
}

func TestUpdateContainerValidateChannelID(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "", Name: ""}
	err := container.Update()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
}

func TestUpdateContainerValidateName(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: ""}
	err := container.Update()
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "container name"))
}

func TestUpdateContainerNotFound(t *testing.T) {
	container := Container{TeamID: "TestTeam", ChannelID: "TestChannel", Name: "Name"}
	err := container.Update()
	assert.EqualError(t, err, messages.Get("container-not-found"))
}

func TestListContainers(t *testing.T) {
	names := [4]string{"A", "B", "C", "D"}
	for _, name := range names {
		container := Container{TeamID: "TestList", ChannelID: "TestChannel", Name: name}
		err := container.Add()
		assert.NoError(t, err)
	}

	containers, err2 := GetContainers("TestList", "TestChannel")
	assert.NoError(t, err2)

	assert.Len(t, containers, len(names))
	for idx, container := range containers {
		assert.ObjectsAreEqual(container.Name, names[idx])
		container.Delete()
	}
}

func TestListContainersValidateTeamID(t *testing.T) {
	containers, err := GetContainers("", "")
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "teamID"))
	assert.ObjectsAreEqual(containers, []Container{})
}

func TestListContainersValidateChannelID(t *testing.T) {
	containers, err := GetContainers("TestTeam", "")
	assert.EqualError(t, err, fmt.Sprintf(messages.Get("field-required"), "channelID"))
	assert.ObjectsAreEqual(containers, []Container{})
}

func TestRemoveInUseData(t *testing.T) {
	team := "TestTeam"
	channel := "TestChannel"
	containerName := "name"
	user := "User"
	reason := "testing"

	container := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: user, InUseForReason: reason}
	err := container.Add()
	assert.NoError(t, err)

	err2 := container.ClearInUse()
	assert.NoError(t, err2)

	containerExpected := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: "", InUseForReason: ""}
	containerFromDB, err3 := GetContainer(team, channel, containerName)
	assert.NoError(t, err3)

	// Ignoring the difference for this fields
	containerExpected.ID = containerFromDB.ID
	containerExpected.CreatedAt = containerFromDB.CreatedAt
	containerExpected.UpdatedAt = containerFromDB.UpdatedAt
	containerExpected.DeletedAt = containerFromDB.DeletedAt

	assert.Empty(t, containerFromDB.InUseBy)
	assert.Empty(t, containerFromDB.InUseForReason)
	assert.Equal(t, containerExpected, containerFromDB)
	container.Delete()
}

func TestSetInUseData(t *testing.T) {
	team := "TestTeam"
	channel := "TestChannel"
	containerName := "name"
	user := "User"
	reason := "testing"

	container := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: "", InUseForReason: ""}
	err := container.Add()
	assert.NoError(t, err)

	err2 := container.SetInUse(user, reason)
	assert.NoError(t, err2)

	containerExpected := Container{TeamID: team, ChannelID: channel, Name: containerName, InUseBy: user, InUseForReason: reason}
	containerFromDB, err3 := GetContainer(team, channel, containerName)
	assert.NoError(t, err3)

	// Ignoring the difference for this fields
	containerExpected.ID = containerFromDB.ID
	containerExpected.CreatedAt = containerFromDB.CreatedAt
	containerExpected.UpdatedAt = containerFromDB.UpdatedAt
	containerExpected.DeletedAt = containerFromDB.DeletedAt

	assert.Equal(t, containerExpected, containerFromDB)
	container.Delete()
}

func TestInUseTextInvalid(t *testing.T) {
	container := Container{}
	assert.Equal(t, messages.Get("in-use-text-invalid"), container.InUseText("whatever"))
}

func TestInUseTextSimpleAvailable(t *testing.T) {
	container := Container{InUseBy: ""}
	assert.Equal(t, available, container.InUseText("simple"))
}
<|endoftext|>


<commit_before>// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com

package page

import (
	"fmt"
)

// Numberize calculates numbers for pages, e.g. 1, 1.1, 2.2.1
// for the document's Table of Contents.
func Numberize(pages []Page) {
	var prevPageLevel uint64
	parts := []int{1} // we store 1, 1, 2, and then generate numbering as "1.1.2"

	for i, p := range pages {
		// handle bad data
		if p.Level == 0 {
			p.Level = 1
		}

		if i != 0 {
			// we ...
			if p.Level > prevPageLevel {
				parts = append(parts, 1)
			}

			if p.Level == prevPageLevel {
				j := len(parts) - 1
				if j >= 0 {
					parts[j]++
				}
			}

			if p.Level < prevPageLevel {
				end := (prevPageLevel - p.Level)
				if int(end) > len(parts) {
					end = uint64(len(parts))
				}
				parts = parts[0 : len(parts)-int(end)]

				i := len(parts) - 1
				if i < 0 {
					i = 0
				}
				if i >= 0 && i < len(parts) {
					parts[i]++
				}
			}
		}

		// generate numbering for page using parts array
		numbering := ""
		for i, v := range parts {
			dot := ""
			if i != len(parts)-1 {
				dot = "."
			}
			numbering = fmt.Sprintf("%s%d%s", numbering, v, dot)
		}
		pages[i].Numbering = numbering

		// Troubleshooting help
		if len(numbering) == 0 {
			fmt.Printf("No number allocated to page %s ('%s')",
				pages[i].RefID, pages[i].Title)
		}

		// update state
		prevPageLevel = p.Level
	}
}

// Levelize ensure page level increments are consistent
// after a page is inserted or removed.
//
// Valid: 1, 2, 3, 4, 4, 4, 2, 1
// Invalid: 1, 2, 4, 4, 2, 1 (note the jump from 2 --> 4)
//
// Rules:
// 1. levels can increase by 1 only (e.g. from 1 to 2 to 3 to 4)
// 2. levels can decrease by any amount (e.g. drop from 4 to 1)
func Levelize(pages []Page) {
	var prevLevel uint64
	prevLevel = 1

	for i := 0; i < len(pages); i++ {
		currLevel := pages[i].Level

		// handle deprecated level value of 0
		if pages[i].Level == 0 {
			pages[i].Level = 1
		}

		// first time thru
		if i == 0 {
			// first time thru
			pages[i].Level = 1
			prevLevel = 1
			continue
		}

		if currLevel == prevLevel {
			// nothing doing
			continue
		}

		if currLevel > prevLevel+1 {
			// bad data detected e.g. prevLevel=1 and pages[i].Level=3
			// so we re-level to pages[i].Level=2 and all child pages
			// and then increment i to correct point
			prevLevel++
			pages[i].Level = prevLevel

			// safety check before entering loop and renumbering child pages
			if i+1 <= len(pages) {

				for j := i + 1; j < len(pages); j++ {
					if pages[j].Level < prevLevel {
						i = j
						break
					}

					if pages[j].Level == currLevel {
						pages[j].Level = prevLevel
					} else if (pages[j].Level - prevLevel) > 1 {
						currLevel = pages[j].Level
						prevLevel++
						pages[j].Level = prevLevel
					}

					i = j
				}
			}
			continue
		}

		prevLevel = currLevel
	}
}

// Sequenize will re-generate page sequence numbers for a document
func Sequenize(p []Page) {
	var seq float64
	seq = 2048
	for i := range p {
		p[i].Sequence = seq
		seq = seq * 2
	}
}
<commit_msg>Format diagnostic message<commit_after>// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com

package page

import (
	"fmt"
)

// Numberize calculates numbers for pages, e.g. 1, 1.1, 2.2.1
// for the document's Table of Contents.
func Numberize(pages []Page) {
	var prevPageLevel uint64
	parts := []int{1} // we store 1, 1, 2, and then generate numbering as "1.1.2"

	for i, p := range pages {
		// handle bad data
		if p.Level == 0 {
			p.Level = 1
		}

		if i != 0 {
			// we ...
			if p.Level > prevPageLevel {
				parts = append(parts, 1)
			}

			if p.Level == prevPageLevel {
				j := len(parts) - 1
				if j >= 0 {
					parts[j]++
				}
			}

			if p.Level < prevPageLevel {
				end := (prevPageLevel - p.Level)
				if int(end) > len(parts) {
					end = uint64(len(parts))
				}
				parts = parts[0 : len(parts)-int(end)]

				i := len(parts) - 1
				if i < 0 {
					i = 0
				}
				if i >= 0 && i < len(parts) {
					parts[i]++
				}
			}
		}

		// generate numbering for page using parts array
		numbering := ""
		for i, v := range parts {
			dot := ""
			if i != len(parts)-1 {
				dot = "."
			}
			numbering = fmt.Sprintf("%s%d%s", numbering, v, dot)
		}
		pages[i].Numbering = numbering

		// Troubleshooting help
		if len(numbering) == 0 {
			fmt.Println(fmt.Sprintf("No number allocated to page %s ('%s')",
				pages[i].RefID, pages[i].Title))
		}

		// update state
		prevPageLevel = p.Level
	}
}

// Levelize ensure page level increments are consistent
// after a page is inserted or removed.
//
// Valid: 1, 2, 3, 4, 4, 4, 2, 1
// Invalid: 1, 2, 4, 4, 2, 1 (note the jump from 2 --> 4)
//
// Rules:
// 1. levels can increase by 1 only (e.g. from 1 to 2 to 3 to 4)
// 2. levels can decrease by any amount (e.g. drop from 4 to 1)
func Levelize(pages []Page) {
	var prevLevel uint64
	prevLevel = 1

	for i := 0; i < len(pages); i++ {
		currLevel := pages[i].Level

		// handle deprecated level value of 0
		if pages[i].Level == 0 {
			pages[i].Level = 1
		}

		// first time thru
		if i == 0 {
			// first time thru
			pages[i].Level = 1
			prevLevel = 1
			continue
		}

		if currLevel == prevLevel {
			// nothing doing
			continue
		}

		if currLevel > prevLevel+1 {
			// bad data detected e.g. prevLevel=1 and pages[i].Level=3
			// so we re-level to pages[i].Level=2 and all child pages
			// and then increment i to correct point
			prevLevel++
			pages[i].Level = prevLevel

			// safety check before entering loop and renumbering child pages
			if i+1 <= len(pages) {

				for j := i + 1; j < len(pages); j++ {
					if pages[j].Level < prevLevel {
						i = j
						break
					}

					if pages[j].Level == currLevel {
						pages[j].Level = prevLevel
					} else if (pages[j].Level - prevLevel) > 1 {
						currLevel = pages[j].Level
						prevLevel++
						pages[j].Level = prevLevel
					}

					i = j
				}
			}
			continue
		}

		prevLevel = currLevel
	}
}

// Sequenize will re-generate page sequence numbers for a document
func Sequenize(p []Page) {
	var seq float64
	seq = 2048
	for i := range p {
		p[i].Sequence = seq
		seq = seq * 2
	}
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var _ = Describe("IntervalDao", func() {
	var (
		collection *mgo.Collection
		dao        *IntervalDao
	)

	BeforeEach(func() {
		session, err := createSession()
		Expect(err).To(BeNil(), "All tests need a connection to a mongodb.")

		collection = getCollection(session, "timetracker", "intervals")

		cleanCollection(collection)

		dao = NewIntervalDao(session, "timetracker")
	})

	It("should save an interval.", func() {
		userID := bson.NewObjectId()
		start := time.Now()
		stop := time.Now()

		Expect(dao.Save(NewInterval(userID, start, stop))).To(Succeed())

		var interval Interval
		findErr := collection.Find(bson.M{"userid": userID}).One(&interval)
		Expect(findErr).To(BeNil())
		Expect(interval.Start.Unix()).To(Equal(start.Unix()))
		Expect(interval.Stop.Unix()).To(Equal(stop.Unix()))
		Expect(interval.UserID).To(Equal(userID))
		Expect(interval.ID.Valid()).To(BeTrue())
	})

	It("should find all by userID.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(bson.NewObjectId(), time.Now()))

		intervals, err := dao.FindByUserID(userID)

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(2))
		Expect(intervals[0].UserID).To(Equal(userID))
		Expect(intervals[1].UserID).To(Equal(userID))
	})

	It("should return an empty array when no intervals found.", func() {
		intervals, err := dao.FindByUserID(bson.NewObjectId())

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(0))
	})

	It("should find a not working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeFalse())
	})

	It("should find a working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeTrue())
	})

	It("should start a new interval with current start time.", func() {
		userID := bson.NewObjectId()

		Expect(dao.Start(userID)).To(Succeed())

		intervals, findErr := dao.FindByUserID(userID)
		Expect(findErr).To(BeNil())
		Expect(intervals[0].Stop).To(BeZero())
		Expect(intervals[0].Start).NotTo(BeZero())
	})

	It("should return all open intervals", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		openIntervals, err := dao.FindOpenIntervals(userID)

		Expect(err).To(BeNil())
		Expect(openIntervals).To(HaveLen(2))
		Expect(openIntervals[0].Stop).To(BeZero())
		Expect(openIntervals[1].Stop).To(BeZero())
	})

	It("should return an error when stop does not find an open interval.", func() {
		userID := bson.NewObjectId()

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("user is not working"))
	})

	It("should return an error when stop finds more than one open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("more than one open interval"))
	})

	FIt("should stop open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		var intervals []Interval
		collection.Find(nil).All(&intervals)
		fmt.Printf("intervals: %v", intervals)

		Expect(dao.Stop(userID)).To(Succeed())

		intervals, err := dao.FindByUserID(userID)
		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(1))
		Expect(intervals[0].Stop).ToNot(BeZero())
	})

	//	PIt("should return all intervals in a given range.")
})
<commit_msg>display all existing intervals to find the problem<commit_after>package models

import (
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var _ = Describe("IntervalDao", func() {
	var (
		collection *mgo.Collection
		dao        *IntervalDao
	)

	BeforeEach(func() {
		session, err := createSession()
		Expect(err).To(BeNil(), "All tests need a connection to a mongodb.")

		collection = getCollection(session, "timetracker", "intervals")

		cleanCollection(collection)

		dao = NewIntervalDao(session, "timetracker")
	})

	It("should save an interval.", func() {
		userID := bson.NewObjectId()
		start := time.Now()
		stop := time.Now()

		Expect(dao.Save(NewInterval(userID, start, stop))).To(Succeed())

		var interval Interval
		findErr := collection.Find(bson.M{"userid": userID}).One(&interval)
		Expect(findErr).To(BeNil())
		Expect(interval.Start.Unix()).To(Equal(start.Unix()))
		Expect(interval.Stop.Unix()).To(Equal(stop.Unix()))
		Expect(interval.UserID).To(Equal(userID))
		Expect(interval.ID.Valid()).To(BeTrue())
	})

	It("should find all by userID.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(userID, time.Now()))
		dao.Save(NewIntervalWithStart(bson.NewObjectId(), time.Now()))

		intervals, err := dao.FindByUserID(userID)

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(2))
		Expect(intervals[0].UserID).To(Equal(userID))
		Expect(intervals[1].UserID).To(Equal(userID))
	})

	It("should return an empty array when no intervals found.", func() {
		intervals, err := dao.FindByUserID(bson.NewObjectId())

		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(0))
	})

	It("should find a not working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeFalse())
	})

	It("should find a working user.", func() {
		userID := bson.NewObjectId()
		dao.Save(NewIntervalWithStart(userID, time.Now()))

		working, err := dao.IsUserWorking(userID)

		Expect(err).To(BeNil())
		Expect(working).To(BeTrue())
	})

	It("should start a new interval with current start time.", func() {
		userID := bson.NewObjectId()

		Expect(dao.Start(userID)).To(Succeed())

		intervals, findErr := dao.FindByUserID(userID)
		Expect(findErr).To(BeNil())
		Expect(intervals[0].Stop).To(BeZero())
		Expect(intervals[0].Start).NotTo(BeZero())
	})

	It("should return all open intervals", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)
		dao.Save(NewInterval(userID, time.Now(), time.Now()))

		openIntervals, err := dao.FindOpenIntervals(userID)

		Expect(err).To(BeNil())
		Expect(openIntervals).To(HaveLen(2))
		Expect(openIntervals[0].Stop).To(BeZero())
		Expect(openIntervals[1].Stop).To(BeZero())
	})

	It("should return an error when stop does not find an open interval.", func() {
		userID := bson.NewObjectId()

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("user is not working"))
	})

	It("should return an error when stop finds more than one open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		dao.Start(userID)

		err := dao.Stop(userID)

		Expect(err.Error()).To(Equal("more than one open interval"))
	})

	FIt("should stop open interval.", func() {
		userID := bson.NewObjectId()
		dao.Start(userID)
		var intervals []Interval
		collection.Find(nil).All(&intervals)
		fmt.Printf("\nintervals before: %v\n", intervals)

		Expect(dao.Stop(userID)).To(Succeed())

		collection.Find(nil).All(&intervals)
		fmt.Printf("intervals after:  %v", intervals)

		intervals, err := dao.FindByUserID(userID)
		Expect(err).To(BeNil())
		Expect(intervals).To(HaveLen(1))
		Expect(intervals[0].Stop).ToNot(BeZero())
	})

	//	PIt("should return all intervals in a given range.")
})
<|endoftext|>