mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +00:00
Reformat of code Allow user to use a mix of command line arguments and flags Enhance the import tool to detect missing packages in the modules side Added test cases for all commands
157 lines
4.4 KiB
Go
157 lines
4.4 KiB
Go
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
|
|
// Revel Framework source code and usage is governed by a MIT style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package tests
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/revel/cmd/utils"
|
|
)
|
|
|
|
// TestSuiteDesc is used for storing information about a single test suite.
|
|
// This structure is required by revel test cmd.
|
|
type TestSuiteDesc struct {
|
|
Name string
|
|
Tests []TestDesc
|
|
|
|
// Elem is reflect.Type which can be used for accessing methods
|
|
// of the test suite.
|
|
Elem reflect.Type
|
|
}
|
|
|
|
// TestDesc is used for describing a single test of some test suite.
|
|
// This structure is required by revel test cmd.
|
|
type TestDesc struct {
|
|
Name string
|
|
}
|
|
|
|
// TestSuiteResult stores the results the whole test suite.
|
|
// This structure is required by revel test cmd.
|
|
type TestSuiteResult struct {
|
|
Name string
|
|
Passed bool
|
|
Results []TestResult
|
|
}
|
|
|
|
// TestResult represents the results of running a single test of some test suite.
|
|
// This structure is required by revel test cmd.
|
|
type TestResult struct {
|
|
Name string
|
|
Passed bool
|
|
ErrorHTML template.HTML
|
|
ErrorSummary string
|
|
}
|
|
|
|
var (
|
|
testSuites []TestSuiteDesc // A list of all available tests.
|
|
|
|
none = []reflect.Value{} // It is used as input for reflect call in a few places.
|
|
|
|
// registeredTests simplifies the search of test suites by their name.
|
|
// "TestSuite.TestName" is used as a key. Value represents index in testSuites.
|
|
registeredTests map[string]int
|
|
)
|
|
|
|
/*
|
|
Below are helper functions.
|
|
*/
|
|
|
|
// describeSuite expects testsuite interface as input parameter
|
|
// and returns its description in a form of TestSuiteDesc structure.
|
|
func describeSuite(testSuite interface{}) TestSuiteDesc {
|
|
t := reflect.TypeOf(testSuite)
|
|
|
|
// Get a list of methods of the embedded test type.
|
|
// It will be used to make sure the same tests are not included in multiple test suites.
|
|
super := t.Elem().Field(0).Type
|
|
superMethods := map[string]bool{}
|
|
for i := 0; i < super.NumMethod(); i++ {
|
|
// Save the current method's name.
|
|
superMethods[super.Method(i).Name] = true
|
|
}
|
|
|
|
// Get a list of methods on the test suite that take no parameters, return
|
|
// no results, and were not part of the embedded type's method set.
|
|
var tests []TestDesc
|
|
for i := 0; i < t.NumMethod(); i++ {
|
|
m := t.Method(i)
|
|
mt := m.Type
|
|
|
|
// Make sure the test method meets the criterias:
|
|
// - method of testSuite without input parameters;
|
|
// - nothing is returned;
|
|
// - has "Test" prefix;
|
|
// - doesn't belong to the embedded structure.
|
|
methodWithoutParams := (mt.NumIn() == 1 && mt.In(0) == t)
|
|
nothingReturned := (mt.NumOut() == 0)
|
|
hasTestPrefix := (strings.HasPrefix(m.Name, "Test"))
|
|
if methodWithoutParams && nothingReturned && hasTestPrefix && !superMethods[m.Name] {
|
|
// Register the test suite's index so we can quickly find it by test's name later.
|
|
registeredTests[t.Elem().Name()+"."+m.Name] = len(testSuites)
|
|
|
|
// Add test to the list of tests.
|
|
tests = append(tests, TestDesc{m.Name})
|
|
}
|
|
}
|
|
|
|
return TestSuiteDesc{
|
|
Name: t.Elem().Name(),
|
|
Tests: tests,
|
|
Elem: t.Elem(),
|
|
}
|
|
}
|
|
|
|
// errorSummary gets an error and returns its summary in human readable format.
|
|
func errorSummary(err *utils.Error) (message string) {
|
|
expectedPrefix := "(expected)"
|
|
actualPrefix := "(actual)"
|
|
errDesc := err.Description
|
|
//strip the actual/expected stuff to provide more condensed display.
|
|
if strings.Index(errDesc, expectedPrefix) == 0 {
|
|
errDesc = errDesc[len(expectedPrefix):]
|
|
}
|
|
if strings.LastIndex(errDesc, actualPrefix) > 0 {
|
|
errDesc = errDesc[0 : len(errDesc)-len(actualPrefix)]
|
|
}
|
|
|
|
errFile := err.Path
|
|
slashIdx := strings.LastIndex(errFile, "/")
|
|
if slashIdx > 0 {
|
|
errFile = errFile[slashIdx+1:]
|
|
}
|
|
|
|
message = fmt.Sprintf("%s %s#%d", errDesc, errFile, err.Line)
|
|
|
|
/*
|
|
// If line of error isn't known return the message as is.
|
|
if err.Line == 0 {
|
|
return
|
|
}
|
|
|
|
// Otherwise, include info about the line number and the relevant
|
|
// source code lines.
|
|
message += fmt.Sprintf(" (around line %d): ", err.Line)
|
|
for _, line := range err.ContextSource() {
|
|
if line.IsError {
|
|
message += line.Source
|
|
}
|
|
}
|
|
*/
|
|
|
|
return
|
|
}
|
|
|
|
//sortbySuiteName sorts the testsuites by name.
|
|
type sortBySuiteName []interface{}
|
|
|
|
func (a sortBySuiteName) Len() int { return len(a) }
|
|
func (a sortBySuiteName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
func (a sortBySuiteName) Less(i, j int) bool {
|
|
return reflect.TypeOf(a[i]).Elem().Name() < reflect.TypeOf(a[j]).Elem().Name()
|
|
}
|