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
|
package testfixtures
|
||||||
|
|
||||||
import "regexp"
|
import (
|
||||||
|
"errors"
|
||||||
var (
|
"time"
|
||||||
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")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func isDate(value interface{}) bool {
|
var timeFormats = []string{
|
||||||
str, isStr := value.(string)
|
"2006-01-02",
|
||||||
if !isStr {
|
"2006-01-02 15:04",
|
||||||
return false
|
"2006-01-02 15:04:05",
|
||||||
}
|
"20060102",
|
||||||
|
"20060102 15:04",
|
||||||
return regexpDate.MatchString(str)
|
"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 {
|
// ErrCouldNotConvertToTime is returns when a string is not a reconizable time format
|
||||||
str, isStr := value.(string)
|
var ErrCouldNotConvertToTime = errors.New("Could not convert string to time")
|
||||||
if !isStr {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return regexpDateTime.MatchString(str)
|
func tryStrToDate(s string) (time.Time, error) {
|
||||||
}
|
for _, f := range timeFormats {
|
||||||
|
t, err := time.ParseInLocation(f, s, time.Local)
|
||||||
func isTime(value interface{}) bool {
|
if err != nil {
|
||||||
str, isStr := value.(string)
|
continue
|
||||||
if !isStr {
|
}
|
||||||
return false
|
return t, nil
|
||||||
}
|
}
|
||||||
|
return time.Time{}, ErrCouldNotConvertToTime
|
||||||
return regexpTime.MatchString(str)
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue