diff --git a/vendor/github.com/openark/golib/README.md b/vendor/github.com/openark/golib/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ee0907e945e8eeb876caf4fd47d187794895df5c --- /dev/null +++ b/vendor/github.com/openark/golib/README.md @@ -0,0 +1,9 @@ +Common Go libraries + +To import & use: +``` +go get "github.com/openark/golib/math" +go get "github.com/openark/golib/sqlutils" +go get "github.com/openark/golib/tests" +... +``` diff --git a/vendor/github.com/openark/golib/log/log.go b/vendor/github.com/openark/golib/log/log.go new file mode 100644 index 0000000000000000000000000000000000000000..d3e9c596486d5ac7e53a1257cd68ca1e741c35d2 --- /dev/null +++ b/vendor/github.com/openark/golib/log/log.go @@ -0,0 +1,258 @@ +/* + Copyright 2014 Outbrain Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package log + +import ( + "errors" + "fmt" + "log/syslog" + "os" + "runtime/debug" + "time" +) + +// LogLevel indicates the severity of a log entry +type LogLevel int + +func (this LogLevel) String() string { + switch this { + case FATAL: + return "FATAL" + case CRITICAL: + return "CRITICAL" + case ERROR: + return "ERROR" + case WARNING: + return "WARNING" + case NOTICE: + return "NOTICE" + case INFO: + return "INFO" + case DEBUG: + return "DEBUG" + } + return "unknown" +} + +func LogLevelFromString(logLevelName string) (LogLevel, error) { + switch logLevelName { + case "FATAL": + return FATAL, nil + case "CRITICAL": + return CRITICAL, nil + case "ERROR": + return ERROR, nil + case "WARNING": + return WARNING, nil + case "NOTICE": + return NOTICE, nil + case "INFO": + return INFO, nil + case "DEBUG": + return DEBUG, nil + } + return 0, fmt.Errorf("Unknown LogLevel name: %+v", logLevelName) +} + +const ( + FATAL LogLevel = iota + CRITICAL + ERROR + WARNING + NOTICE + INFO + DEBUG +) + +const TimeFormat = "2006-01-02 15:04:05" + +// globalLogLevel indicates the global level filter for all logs (only entries with level equals or higher +// than this value will be logged) +var globalLogLevel LogLevel = DEBUG +var printStackTrace bool = false + +// syslogWriter is optional, and defaults to nil (disabled) +var syslogLevel LogLevel = ERROR +var syslogWriter *syslog.Writer + +// SetPrintStackTrace enables/disables dumping the stack upon error logging +func SetPrintStackTrace(shouldPrintStackTrace bool) { + printStackTrace = shouldPrintStackTrace +} + +// SetLevel sets the global log level. Only entries with level equals or higher than +// this value will be logged +func SetLevel(logLevel LogLevel) { + globalLogLevel = logLevel +} + +// GetLevel returns current global log level +func GetLevel() LogLevel { + return globalLogLevel +} + +// EnableSyslogWriter enables, if possible, writes to syslog. These will execute _in addition_ to normal logging +func EnableSyslogWriter(tag string) (err error) { + syslogWriter, err = syslog.New(syslog.LOG_ERR, tag) + if err != nil { + syslogWriter = nil + } + return err +} + +// SetSyslogLevel sets the minimal syslog level. Only entries with level equals or higher than +// this value will be logged. However, this is also capped by the global log level. That is, +// messages with lower level than global-log-level will be discarded at any case. +func SetSyslogLevel(logLevel LogLevel) { + syslogLevel = logLevel +} + +// logFormattedEntry nicely formats and emits a log entry +func logFormattedEntry(logLevel LogLevel, message string, args ...interface{}) string { + if logLevel > globalLogLevel { + return "" + } + msgArgs := fmt.Sprintf(message, args...) + entryString := fmt.Sprintf("%s %s %s", time.Now().Format(TimeFormat), logLevel, msgArgs) + fmt.Fprintln(os.Stderr, entryString) + + if syslogWriter != nil { + go func() error { + if logLevel > syslogLevel { + return nil + } + switch logLevel { + case FATAL: + return syslogWriter.Emerg(msgArgs) + case CRITICAL: + return syslogWriter.Crit(msgArgs) + case ERROR: + return syslogWriter.Err(msgArgs) + case WARNING: + return syslogWriter.Warning(msgArgs) + case NOTICE: + return syslogWriter.Notice(msgArgs) + case INFO: + return syslogWriter.Info(msgArgs) + case DEBUG: + return syslogWriter.Debug(msgArgs) + } + return nil + }() + } + return entryString +} + +// logEntry emits a formatted log entry +func logEntry(logLevel LogLevel, message string, args ...interface{}) string { + entryString := message + for _, s := range args { + entryString += fmt.Sprintf(" %s", s) + } + return logFormattedEntry(logLevel, entryString) +} + +// logErrorEntry emits a log entry based on given error object +func logErrorEntry(logLevel LogLevel, err error) error { + if err == nil { + // No error + return nil + } + entryString := fmt.Sprintf("%+v", err) + logEntry(logLevel, entryString) + if printStackTrace { + debug.PrintStack() + } + return err +} + +func Debug(message string, args ...interface{}) string { + return logEntry(DEBUG, message, args...) +} + +func Debugf(message string, args ...interface{}) string { + return logFormattedEntry(DEBUG, message, args...) +} + +func Info(message string, args ...interface{}) string { + return logEntry(INFO, message, args...) +} + +func Infof(message string, args ...interface{}) string { + return logFormattedEntry(INFO, message, args...) +} + +func Notice(message string, args ...interface{}) string { + return logEntry(NOTICE, message, args...) +} + +func Noticef(message string, args ...interface{}) string { + return logFormattedEntry(NOTICE, message, args...) +} + +func Warning(message string, args ...interface{}) error { + return errors.New(logEntry(WARNING, message, args...)) +} + +func Warningf(message string, args ...interface{}) error { + return errors.New(logFormattedEntry(WARNING, message, args...)) +} + +func Error(message string, args ...interface{}) error { + return errors.New(logEntry(ERROR, message, args...)) +} + +func Errorf(message string, args ...interface{}) error { + return errors.New(logFormattedEntry(ERROR, message, args...)) +} + +func Errore(err error) error { + return logErrorEntry(ERROR, err) +} + +func Critical(message string, args ...interface{}) error { + return errors.New(logEntry(CRITICAL, message, args...)) +} + +func Criticalf(message string, args ...interface{}) error { + return errors.New(logFormattedEntry(CRITICAL, message, args...)) +} + +func Criticale(err error) error { + return logErrorEntry(CRITICAL, err) +} + +// Fatal emits a FATAL level entry and exists the program +func Fatal(message string, args ...interface{}) error { + logEntry(FATAL, message, args...) + os.Exit(1) + return errors.New(logEntry(CRITICAL, message, args...)) +} + +// Fatalf emits a FATAL level entry and exists the program +func Fatalf(message string, args ...interface{}) error { + logFormattedEntry(FATAL, message, args...) + os.Exit(1) + return errors.New(logFormattedEntry(CRITICAL, message, args...)) +} + +// Fatale emits a FATAL level entry and exists the program +func Fatale(err error) error { + logErrorEntry(FATAL, err) + os.Exit(1) + return err +} diff --git a/vendor/github.com/openark/golib/math/math.go b/vendor/github.com/openark/golib/math/math.go new file mode 100644 index 0000000000000000000000000000000000000000..f1f2068e4e0cc9e7f1debc631e857b603b315974 --- /dev/null +++ b/vendor/github.com/openark/golib/math/math.go @@ -0,0 +1,119 @@ +/* + Copyright 2014 Shlomi Noach. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package math + +func MinInt(i1, i2 int) int { + if i1 < i2 { + return i1 + } + return i2 +} + +func MaxInt(i1, i2 int) int { + if i1 > i2 { + return i1 + } + return i2 +} + +func MinInt64(i1, i2 int64) int64 { + if i1 < i2 { + return i1 + } + return i2 +} + +func MaxInt64(i1, i2 int64) int64 { + if i1 > i2 { + return i1 + } + return i2 +} + +func MinUInt(i1, i2 uint) uint { + if i1 < i2 { + return i1 + } + return i2 +} + +func MaxUInt(i1, i2 uint) uint { + if i1 > i2 { + return i1 + } + return i2 +} + +func MinUInt64(i1, i2 uint64) uint64 { + if i1 < i2 { + return i1 + } + return i2 +} + +func MaxUInt64(i1, i2 uint64) uint64 { + if i1 > i2 { + return i1 + } + return i2 +} + +func MinString(i1, i2 string) string { + if i1 < i2 { + return i1 + } + return i2 +} + +func MaxString(i1, i2 string) string { + if i1 > i2 { + return i1 + } + return i2 +} + +// TernaryString acts like a "? :" C-style ternary operator for strings +func TernaryString(condition bool, resTrue string, resFalse string) string { + if condition { + return resTrue + } + return resFalse +} + +// TernaryString acts like a "? :" C-style ternary operator for ints +func TernaryInt(condition bool, resTrue int, resFalse int) int { + if condition { + return resTrue + } + return resFalse +} + +// AbsInt is an ABS function for int type +func AbsInt(i int) int { + if i >= 0 { + return i + } + return -i +} + +// AbsInt64 is an ABS function for int64 type +func AbsInt64(i int64) int64 { + if i >= 0 { + return i + } + return -i +} diff --git a/vendor/github.com/openark/golib/sqlutils/dialect.go b/vendor/github.com/openark/golib/sqlutils/dialect.go new file mode 100644 index 0000000000000000000000000000000000000000..5fce0b2a6294510d5e8103fbd8b7adc2f11167b0 --- /dev/null +++ b/vendor/github.com/openark/golib/sqlutils/dialect.go @@ -0,0 +1,63 @@ +/* + Copyright 2017 GitHub Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sqlutils + +import ( + "regexp" + "strings" +) + +type regexpMap struct { + r *regexp.Regexp + replacement string +} + +func (this *regexpMap) process(text string) (result string) { + return this.r.ReplaceAllString(text, this.replacement) +} + +var ( + createTableCharset = rmap(`(?i)varchar[\s]*[(][\s]*([0-9]+)[\s]*[)] (character set|charset) [\S]+`, `varchar(${1})`) +) + +var ( + identifyCreateStatement = regexp.MustCompile(regexpSpaces(`(?i)^[\s]*create table`)) +) + +func rmap(regexpExpression string, replacement string) regexpMap { + return regexpMap{ + r: regexp.MustCompile(regexpSpaces(regexpExpression)), + replacement: replacement, + } +} + +func regexpSpaces(statement string) string { + return strings.Replace(statement, " ", `[ ]+`, -1) +} + +func isCreateTable(statement string) bool { + return identifyCreateStatement.MatchString(statement) +} + +func ToSqlite3CreateTable(statement string) (string, error) { + statement = createTableCharset.process(statement) + return statement, nil +} + +func ToSqlite3Dialect(statement string) (translated string, err error) { + return statement, err +} diff --git a/vendor/github.com/openark/golib/sqlutils/dialect_test.go b/vendor/github.com/openark/golib/sqlutils/dialect_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6e93a44e308a43f24e7789d3c9774f503a1d2fdb --- /dev/null +++ b/vendor/github.com/openark/golib/sqlutils/dialect_test.go @@ -0,0 +1,58 @@ +/* + Copyright 2017 GitHub Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sqlutils + +import ( + "testing" + + test "github.com/openark/golib/tests" +) + +func init() { +} + +func TestIsCreateTable(t *testing.T) { + test.S(t).ExpectTrue(isCreateTable("create table t(id int)")) + test.S(t).ExpectTrue(isCreateTable(" create table t(id int)")) + test.S(t).ExpectTrue(isCreateTable("CREATE TABLE t(id int)")) + test.S(t).ExpectTrue(isCreateTable(` + create table t(id int) + `)) + test.S(t).ExpectFalse(isCreateTable("where create table t(id int)")) + test.S(t).ExpectFalse(isCreateTable("insert")) +} + +func TestToSqlite3CreateTable(t *testing.T) { + { + statement := "create table t(id int)" + result, err := ToSqlite3CreateTable(statement) + test.S(t).ExpectNil(err) + test.S(t).ExpectEquals(result, statement) + } + { + statement := "create table t(id int, v varchar(123) CHARACTER SET ascii NOT NULL default '')" + result, err := ToSqlite3CreateTable(statement) + test.S(t).ExpectNil(err) + test.S(t).ExpectEquals(result, "create table t(id int, v varchar(123) NOT NULL default '')") + } + { + statement := "create table t(id int, v varchar ( 123 ) CHARACTER SET ascii NOT NULL default '')" + result, err := ToSqlite3CreateTable(statement) + test.S(t).ExpectNil(err) + test.S(t).ExpectEquals(result, "create table t(id int, v varchar(123) NOT NULL default '')") + } +} diff --git a/vendor/github.com/openark/golib/sqlutils/sqlutils.go b/vendor/github.com/openark/golib/sqlutils/sqlutils.go new file mode 100644 index 0000000000000000000000000000000000000000..2348051f563622c9bb8bdcdcf49a29210c5804e9 --- /dev/null +++ b/vendor/github.com/openark/golib/sqlutils/sqlutils.go @@ -0,0 +1,333 @@ +/* + Copyright 2014 Outbrain Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sqlutils + +import ( + "database/sql" + "encoding/json" + "errors" + "fmt" + _ "github.com/go-sql-driver/mysql" + "github.com/openark/golib/log" + "strconv" + "strings" + "sync" +) + +// RowMap represents one row in a result set. Its objective is to allow +// for easy, typed getters by column name. +type RowMap map[string]CellData + +// Cell data is the result of a single (atomic) column in a single row +type CellData sql.NullString + +func (this *CellData) MarshalJSON() ([]byte, error) { + if this.Valid { + return json.Marshal(this.String) + } else { + return json.Marshal(nil) + } +} + +func (this *CellData) NullString() *sql.NullString { + return (*sql.NullString)(this) +} + +// RowData is the result of a single row, in positioned array format +type RowData []CellData + +// MarshalJSON will marshal this map as JSON +func (this *RowData) MarshalJSON() ([]byte, error) { + cells := make([](*CellData), len(*this), len(*this)) + for i, val := range *this { + d := CellData(val) + cells[i] = &d + } + return json.Marshal(cells) +} + +// ResultData is an ordered row set of RowData +type ResultData []RowData + +var EmptyResultData = ResultData{} + +func (this *RowMap) GetString(key string) string { + return (*this)[key].String +} + +// GetStringD returns a string from the map, or a default value if the key does not exist +func (this *RowMap) GetStringD(key string, def string) string { + if cell, ok := (*this)[key]; ok { + return cell.String + } + return def +} + +func (this *RowMap) GetInt64(key string) int64 { + res, _ := strconv.ParseInt(this.GetString(key), 10, 0) + return res +} + +func (this *RowMap) GetNullInt64(key string) sql.NullInt64 { + i, err := strconv.ParseInt(this.GetString(key), 10, 0) + if err == nil { + return sql.NullInt64{Int64: i, Valid: true} + } else { + return sql.NullInt64{Valid: false} + } +} + +func (this *RowMap) GetInt(key string) int { + res, _ := strconv.Atoi(this.GetString(key)) + return res +} + +func (this *RowMap) GetIntD(key string, def int) int { + res, err := strconv.Atoi(this.GetString(key)) + if err != nil { + return def + } + return res +} + +func (this *RowMap) GetUint(key string) uint { + res, _ := strconv.Atoi(this.GetString(key)) + return uint(res) +} + +func (this *RowMap) GetUintD(key string, def uint) uint { + res, err := strconv.Atoi(this.GetString(key)) + if err != nil { + return def + } + return uint(res) +} + +func (this *RowMap) GetBool(key string) bool { + return this.GetInt(key) != 0 +} + +// knownDBs is a DB cache by uri +var knownDBs map[string]*sql.DB = make(map[string]*sql.DB) +var knownDBsMutex = &sync.Mutex{} + +// GetDB returns a DB instance based on uri. +// bool result indicates whether the DB was returned from cache; err +func GetDB(mysql_uri string) (*sql.DB, bool, error) { + knownDBsMutex.Lock() + defer func() { + knownDBsMutex.Unlock() + }() + + var exists bool + if _, exists = knownDBs[mysql_uri]; !exists { + if db, err := sql.Open("mysql", mysql_uri); err == nil { + knownDBs[mysql_uri] = db + } else { + return db, exists, err + } + } + return knownDBs[mysql_uri], exists, nil +} + +// RowToArray is a convenience function, typically not called directly, which maps a +// single read database row into a NullString +func RowToArray(rows *sql.Rows, columns []string) []CellData { + buff := make([]interface{}, len(columns)) + data := make([]CellData, len(columns)) + for i, _ := range buff { + buff[i] = data[i].NullString() + } + rows.Scan(buff...) + return data +} + +// ScanRowsToArrays is a convenience function, typically not called directly, which maps rows +// already read from the databse into arrays of NullString +func ScanRowsToArrays(rows *sql.Rows, on_row func([]CellData) error) error { + columns, _ := rows.Columns() + for rows.Next() { + arr := RowToArray(rows, columns) + err := on_row(arr) + if err != nil { + return err + } + } + return nil +} + +func rowToMap(row []CellData, columns []string) map[string]CellData { + m := make(map[string]CellData) + for k, data_col := range row { + m[columns[k]] = data_col + } + return m +} + +// ScanRowsToMaps is a convenience function, typically not called directly, which maps rows +// already read from the databse into RowMap entries. +func ScanRowsToMaps(rows *sql.Rows, on_row func(RowMap) error) error { + columns, _ := rows.Columns() + err := ScanRowsToArrays(rows, func(arr []CellData) error { + m := rowToMap(arr, columns) + err := on_row(m) + if err != nil { + return err + } + return nil + }) + return err +} + +// QueryRowsMap is a convenience function allowing querying a result set while poviding a callback +// function activated per read row. +func QueryRowsMap(db *sql.DB, query string, on_row func(RowMap) error, args ...interface{}) error { + var err error + defer func() { + if derr := recover(); derr != nil { + err = errors.New(fmt.Sprintf("QueryRowsMap unexpected error: %+v", derr)) + } + }() + + rows, err := db.Query(query, args...) + defer rows.Close() + if err != nil && err != sql.ErrNoRows { + return log.Errore(err) + } + err = ScanRowsToMaps(rows, on_row) + return err +} + +// queryResultData returns a raw array of rows for a given query, optionally reading and returning column names +func queryResultData(db *sql.DB, query string, retrieveColumns bool, args ...interface{}) (ResultData, []string, error) { + var err error + defer func() { + if derr := recover(); derr != nil { + err = errors.New(fmt.Sprintf("QueryRowsMap unexpected error: %+v", derr)) + } + }() + + columns := []string{} + rows, err := db.Query(query, args...) + defer rows.Close() + if err != nil && err != sql.ErrNoRows { + return EmptyResultData, columns, log.Errore(err) + } + if retrieveColumns { + // Don't pay if you don't want to + columns, _ = rows.Columns() + } + resultData := ResultData{} + err = ScanRowsToArrays(rows, func(rowData []CellData) error { + resultData = append(resultData, rowData) + return nil + }) + return resultData, columns, err +} + +// QueryResultData returns a raw array of rows +func QueryResultData(db *sql.DB, query string, args ...interface{}) (ResultData, error) { + resultData, _, err := queryResultData(db, query, false, args...) + return resultData, err +} + +// QueryResultDataNamed returns a raw array of rows, with column names +func QueryResultDataNamed(db *sql.DB, query string, args ...interface{}) (ResultData, []string, error) { + return queryResultData(db, query, true, args...) +} + +// QueryRowsMapBuffered reads data from the database into a buffer, and only then applies the given function per row. +// This allows the application to take its time with processing the data, albeit consuming as much memory as required by +// the result set. +func QueryRowsMapBuffered(db *sql.DB, query string, on_row func(RowMap) error, args ...interface{}) error { + resultData, columns, err := queryResultData(db, query, true, args...) + if err != nil { + // Already logged + return err + } + for _, row := range resultData { + err = on_row(rowToMap(row, columns)) + if err != nil { + return err + } + } + return nil +} + +// ExecNoPrepare executes given query using given args on given DB, without using prepared statements. +func ExecNoPrepare(db *sql.DB, query string, args ...interface{}) (sql.Result, error) { + var err error + defer func() { + if derr := recover(); derr != nil { + err = errors.New(fmt.Sprintf("ExecNoPrepare unexpected error: %+v", derr)) + } + }() + + var res sql.Result + res, err = db.Exec(query, args...) + if err != nil { + log.Errore(err) + } + return res, err +} + +// ExecQuery executes given query using given args on given DB. It will safele prepare, execute and close +// the statement. +func execInternal(silent bool, db *sql.DB, query string, args ...interface{}) (sql.Result, error) { + var err error + defer func() { + if derr := recover(); derr != nil { + err = errors.New(fmt.Sprintf("execInternal unexpected error: %+v", derr)) + } + }() + + stmt, err := db.Prepare(query) + if err != nil { + return nil, err + } + defer stmt.Close() + var res sql.Result + res, err = stmt.Exec(args...) + if err != nil && !silent { + log.Errore(err) + } + return res, err +} + +// Exec executes given query using given args on given DB. It will safele prepare, execute and close +// the statement. +func Exec(db *sql.DB, query string, args ...interface{}) (sql.Result, error) { + return execInternal(false, db, query, args...) +} + +// ExecSilently acts like Exec but does not report any error +func ExecSilently(db *sql.DB, query string, args ...interface{}) (sql.Result, error) { + return execInternal(true, db, query, args...) +} + +func InClauseStringValues(terms []string) string { + quoted := []string{} + for _, s := range terms { + quoted = append(quoted, fmt.Sprintf("'%s'", strings.Replace(s, ",", "''", -1))) + } + return strings.Join(quoted, ", ") +} + +// Convert variable length arguments into arguments array +func Args(args ...interface{}) []interface{} { + return args +} diff --git a/vendor/github.com/openark/golib/tests/spec.go b/vendor/github.com/openark/golib/tests/spec.go new file mode 100644 index 0000000000000000000000000000000000000000..27b15b69420eb0d489f47ed80c0477cb6fd61776 --- /dev/null +++ b/vendor/github.com/openark/golib/tests/spec.go @@ -0,0 +1,76 @@ +package tests + +import ( + "testing" +) + +// Spec is an access point to test Expections +type Spec struct { + t *testing.T +} + +// S generates a spec. You will want to use it once in a test file, once in a test or once per each check +func S(t *testing.T) *Spec { + return &Spec{t: t} +} + +// ExpectNil expects given value to be nil, or errors +func (spec *Spec) ExpectNil(actual interface{}) { + if actual == nil { + return + } + spec.t.Errorf("Expected %+v to be nil", actual) +} + +// ExpectNotNil expects given value to be not nil, or errors +func (spec *Spec) ExpectNotNil(actual interface{}) { + if actual != nil { + return + } + spec.t.Errorf("Expected %+v to be not nil", actual) +} + +// ExpectEquals expects given values to be equal (comparison via `==`), or errors +func (spec *Spec) ExpectEquals(actual, value interface{}) { + if actual == value { + return + } + spec.t.Errorf("Expected %+v, got %+v", value, actual) +} + +// ExpectNotEquals expects given values to be nonequal (comparison via `==`), or errors +func (spec *Spec) ExpectNotEquals(actual, value interface{}) { + if !(actual == value) { + return + } + spec.t.Errorf("Expected not %+v", value) +} + +// ExpectEqualsAny expects given actual to equal (comparison via `==`) at least one of given values, or errors +func (spec *Spec) ExpectEqualsAny(actual interface{}, values ...interface{}) { + for _, value := range values { + if actual == value { + return + } + } + spec.t.Errorf("Expected %+v to equal any of given values", actual) +} + +// ExpectNotEqualsAny expects given actual to be nonequal (comparison via `==`)tp any of given values, or errors +func (spec *Spec) ExpectNotEqualsAny(actual interface{}, values ...interface{}) { + for _, value := range values { + if actual == value { + spec.t.Errorf("Expected not %+v", value) + } + } +} + +// ExpectFalse expects given values to be false, or errors +func (spec *Spec) ExpectFalse(actual interface{}) { + spec.ExpectEquals(actual, false) +} + +// ExpectTrue expects given values to be true, or errors +func (spec *Spec) ExpectTrue(actual interface{}) { + spec.ExpectEquals(actual, true) +} diff --git a/vendor/github.com/openark/golib/util/text.go b/vendor/github.com/openark/golib/util/text.go new file mode 100644 index 0000000000000000000000000000000000000000..9155ba366a1779f9b0562feaeade8965dd2a8c01 --- /dev/null +++ b/vendor/github.com/openark/golib/util/text.go @@ -0,0 +1,50 @@ +/* + Copyright 2015 Shlomi Noach. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "errors" + "fmt" + "regexp" + "strconv" +) + +// ParseSimpleTime parses input in the format 7s, 55m, 3h, 31d, 4w (second, minute, hour, day, week) +// The time.ParseDuration() function should have done this, but it does not support "d" and "w" extensions. +func SimpleTimeToSeconds(simpleTime string) (int, error) { + if matched, _ := regexp.MatchString("^[0-9]+s$", simpleTime); matched { + i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1]) + return i, nil + } + if matched, _ := regexp.MatchString("^[0-9]+m$", simpleTime); matched { + i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1]) + return i * 60, nil + } + if matched, _ := regexp.MatchString("^[0-9]+h$", simpleTime); matched { + i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1]) + return i * 60 * 60, nil + } + if matched, _ := regexp.MatchString("^[0-9]+d$", simpleTime); matched { + i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1]) + return i * 60 * 60 * 24, nil + } + if matched, _ := regexp.MatchString("^[0-9]+w$", simpleTime); matched { + i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1]) + return i * 60 * 60 * 24 * 7, nil + } + return 0, errors.New(fmt.Sprintf("Cannot parse simple time: %s", simpleTime)) +}