mirror of https://github.com/go-gitea/gitea.git
Upgrade gopkg.in/testfixtures.v2 (#4999)
parent
b8d048fa0d
commit
dba955be7c
@ -0,0 +1,41 @@
|
||||
package testfixtures
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWrongCastNotAMap is returned when a map is not a map[interface{}]interface{}
|
||||
ErrWrongCastNotAMap = errors.New("Could not cast record: not a map[interface{}]interface{}")
|
||||
|
||||
// ErrFileIsNotSliceOrMap is returned the the fixture file is not a slice or map.
|
||||
ErrFileIsNotSliceOrMap = errors.New("The fixture file is not a slice or map")
|
||||
|
||||
// ErrKeyIsNotString is returned when a record is not of type string
|
||||
ErrKeyIsNotString = errors.New("Record map key is not string")
|
||||
|
||||
// ErrNotTestDatabase is returned when the database name doesn't contains "test"
|
||||
ErrNotTestDatabase = errors.New(`Loading aborted because the database name does not contains "test"`)
|
||||
)
|
||||
|
||||
// InsertError will be returned if any error happens on database while
|
||||
// inserting the record
|
||||
type InsertError struct {
|
||||
Err error
|
||||
File string
|
||||
Index int
|
||||
SQL string
|
||||
Params []interface{}
|
||||
}
|
||||
|
||||
func (e *InsertError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"testfixtures: error inserting record: %v, on file: %s, index: %d, sql: %s, params: %v",
|
||||
e.Err,
|
||||
e.File,
|
||||
e.Index,
|
||||
e.SQL,
|
||||
e.Params,
|
||||
)
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package testfixtures
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"unicode/utf8"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// TableInfo is settings for generating a fixture for table.
|
||||
type TableInfo struct {
|
||||
Name string // Table name
|
||||
Where string // A condition for extracting records. If this value is empty, extracts all records.
|
||||
}
|
||||
|
||||
func (ti *TableInfo) whereClause() string {
|
||||
if ti.Where == "" {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf(" WHERE %s", ti.Where)
|
||||
}
|
||||
|
||||
// GenerateFixtures generates fixtures for the current contents of a database, and saves
|
||||
// them to the specified directory
|
||||
func GenerateFixtures(db *sql.DB, helper Helper, dir string) error {
|
||||
tables, err := helper.tableNames(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, table := range tables {
|
||||
filename := path.Join(dir, table+".yml")
|
||||
if err := generateFixturesForTable(db, helper, &TableInfo{Name: table}, filename); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateFixturesForTables generates fixtures for the current contents of specified tables in a database, and saves
|
||||
// them to the specified directory
|
||||
func GenerateFixturesForTables(db *sql.DB, tables []*TableInfo, helper Helper, dir string) error {
|
||||
for _, table := range tables {
|
||||
filename := path.Join(dir, table.Name+".yml")
|
||||
if err := generateFixturesForTable(db, helper, table, filename); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateFixturesForTable(db *sql.DB, h Helper, table *TableInfo, filename string) error {
|
||||
query := fmt.Sprintf("SELECT * FROM %s%s", h.quoteKeyword(table.Name), table.whereClause())
|
||||
rows, err := db.Query(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fixtures := make([]interface{}, 0, 10)
|
||||
for rows.Next() {
|
||||
entries := make([]interface{}, len(columns))
|
||||
entryPtrs := make([]interface{}, len(entries))
|
||||
for i := range entries {
|
||||
entryPtrs[i] = &entries[i]
|
||||
}
|
||||
if err := rows.Scan(entryPtrs...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entryMap := make(map[string]interface{}, len(entries))
|
||||
for i, column := range columns {
|
||||
entryMap[column] = convertValue(entries[i])
|
||||
}
|
||||
fixtures = append(fixtures, entryMap)
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
marshaled, err := yaml.Marshal(fixtures)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(marshaled)
|
||||
return err
|
||||
}
|
||||
|
||||
func convertValue(value interface{}) interface{} {
|
||||
switch v := value.(type) {
|
||||
case []byte:
|
||||
if utf8.Valid(v) {
|
||||
return string(v)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package testfixtures
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var (
|
||||
_ driver.Valuer = jsonArray{}
|
||||
_ driver.Valuer = jsonMap{}
|
||||
)
|
||||
|
||||
type jsonArray []interface{}
|
||||
|
||||
func (a jsonArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
||||
type jsonMap map[string]interface{}
|
||||
|
||||
func (m jsonMap) Value() (driver.Value, error) {
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
// Go refuses to convert map[interface{}]interface{} to JSON because JSON only support string keys
|
||||
// So it's necessary to recursively convert all map[interface]interface{} to map[string]interface{}
|
||||
func recursiveToJSON(v interface{}) (r interface{}) {
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
for i, e := range v {
|
||||
v[i] = recursiveToJSON(e)
|
||||
}
|
||||
r = jsonArray(v)
|
||||
case map[interface{}]interface{}:
|
||||
newMap := make(map[string]interface{}, len(v))
|
||||
for k, e := range v {
|
||||
newMap[k.(string)] = recursiveToJSON(e)
|
||||
}
|
||||
r = jsonMap(newMap)
|
||||
default:
|
||||
r = v
|
||||
}
|
||||
return
|
||||
}
|
@ -1,36 +1,34 @@
|
||||
package testfixtures
|
||||
|
||||
import "regexp"
|
||||
|
||||
var (
|
||||
regexpDate = regexp.MustCompile("\\d\\d\\d\\d-\\d\\d-\\d\\d")
|
||||
regexpDateTime = regexp.MustCompile("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d")
|
||||
regexpTime = regexp.MustCompile("\\d\\d:\\d\\d:\\d\\d")
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
func isDate(value interface{}) bool {
|
||||
str, isStr := value.(string)
|
||||
if !isStr {
|
||||
return false
|
||||
}
|
||||
|
||||
return regexpDate.MatchString(str)
|
||||
var timeFormats = []string{
|
||||
"2006-01-02",
|
||||
"2006-01-02 15:04",
|
||||
"2006-01-02 15:04:05",
|
||||
"20060102",
|
||||
"20060102 15:04",
|
||||
"20060102 15:04:05",
|
||||
"02/01/2006",
|
||||
"02/01/2006 15:04",
|
||||
"02/01/2006 15:04:05",
|
||||
"2006-01-02T15:04-07:00",
|
||||
"2006-01-02T15:04:05-07:00",
|
||||
}
|
||||
|
||||
func isDateTime(value interface{}) bool {
|
||||
str, isStr := value.(string)
|
||||
if !isStr {
|
||||
return false
|
||||
}
|
||||
// ErrCouldNotConvertToTime is returns when a string is not a reconizable time format
|
||||
var ErrCouldNotConvertToTime = errors.New("Could not convert string to time")
|
||||
|
||||
return regexpDateTime.MatchString(str)
|
||||
}
|
||||
|
||||
func isTime(value interface{}) bool {
|
||||
str, isStr := value.(string)
|
||||
if !isStr {
|
||||
return false
|
||||
func tryStrToDate(s string) (time.Time, error) {
|
||||
for _, f := range timeFormats {
|
||||
t, err := time.ParseInLocation(f, s, time.Local)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
return regexpTime.MatchString(str)
|
||||
return time.Time{}, ErrCouldNotConvertToTime
|
||||
}
|
||||
|
Loading…
Reference in New Issue