go vendor
This commit is contained in:
327
vendor/github.com/revel/modules/testrunner/app/controllers/testrunner.go
generated
vendored
Normal file
327
vendor/github.com/revel/modules/testrunner/app/controllers/testrunner.go
generated
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
// 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 controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/revel/revel"
|
||||
"github.com/revel/revel/testing"
|
||||
)
|
||||
|
||||
// TestRunner is a controller which is used for running application tests in browser.
|
||||
type TestRunner struct {
|
||||
*revel.Controller
|
||||
}
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
/*
|
||||
Controller's action methods are below.
|
||||
*/
|
||||
|
||||
// Index is an action which renders the full list of available test suites and their tests.
|
||||
func (c TestRunner) Index() revel.Result {
|
||||
c.ViewArgs["suiteFound"] = len(testSuites) > 0
|
||||
return c.Render(testSuites)
|
||||
}
|
||||
|
||||
// Suite method allows user to navigate to individual Test Suite and their tests
|
||||
func (c TestRunner) Suite(suite string) revel.Result {
|
||||
var foundTestSuites []TestSuiteDesc
|
||||
for _, testSuite := range testSuites {
|
||||
if strings.EqualFold(testSuite.Name, suite) {
|
||||
foundTestSuites = append(foundTestSuites, testSuite)
|
||||
}
|
||||
}
|
||||
|
||||
c.ViewArgs["testSuites"] = foundTestSuites
|
||||
c.ViewArgs["suiteFound"] = len(foundTestSuites) > 0
|
||||
c.ViewArgs["suiteName"] = suite
|
||||
|
||||
return c.RenderTemplate("TestRunner/Index.html")
|
||||
}
|
||||
|
||||
// Run runs a single test, given by the argument.
|
||||
func (c TestRunner) Run(suite, test string) revel.Result {
|
||||
// Check whether requested test exists.
|
||||
suiteIndex, ok := registeredTests[suite+"."+test]
|
||||
if !ok {
|
||||
return c.NotFound("Test %s.%s does not exist", suite, test)
|
||||
}
|
||||
|
||||
result := TestResult{Name: test}
|
||||
|
||||
// Found the suite, create a new instance and run the named method.
|
||||
t := testSuites[suiteIndex].Elem
|
||||
v := reflect.New(t)
|
||||
func() {
|
||||
// When the function stops executing try to recover from panic.
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
// If panic error is empty, exit.
|
||||
panicErr := revel.NewErrorFromPanic(err)
|
||||
if panicErr == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, prepare and format the response of server if possible.
|
||||
testSuite := v.Elem().FieldByName("TestSuite").Interface().(testing.TestSuite)
|
||||
res := formatResponse(testSuite)
|
||||
|
||||
// Render the error and save to the result structure.
|
||||
var buffer bytes.Buffer
|
||||
tmpl, _ := revel.MainTemplateLoader.TemplateLang("TestRunner/FailureDetail.html", "")
|
||||
_ = tmpl.Render(&buffer, map[string]interface{}{
|
||||
"error": panicErr,
|
||||
"response": res,
|
||||
"postfix": suite + "_" + test,
|
||||
})
|
||||
result.ErrorSummary = errorSummary(panicErr)
|
||||
result.ErrorHTML = template.HTML(buffer.String())
|
||||
}
|
||||
}()
|
||||
|
||||
// Initialize the test suite with a NewTestSuite()
|
||||
testSuiteInstance := v.Elem().FieldByName("TestSuite")
|
||||
testSuiteInstance.Set(reflect.ValueOf(testing.NewTestSuite()))
|
||||
|
||||
// Make sure After method will be executed at the end.
|
||||
if m := v.MethodByName("After"); m.IsValid() {
|
||||
defer m.Call(none)
|
||||
}
|
||||
|
||||
// Start from running Before method of test suite if exists.
|
||||
if m := v.MethodByName("Before"); m.IsValid() {
|
||||
m.Call(none)
|
||||
}
|
||||
|
||||
// Start the test method itself.
|
||||
v.MethodByName(test).Call(none)
|
||||
|
||||
// No panic means success.
|
||||
result.Passed = true
|
||||
}()
|
||||
|
||||
return c.RenderJSON(result)
|
||||
}
|
||||
|
||||
// List returns a JSON list of test suites and tests.
|
||||
// It is used by revel test command line tool.
|
||||
func (c TestRunner) List() revel.Result {
|
||||
return c.RenderJSON(testSuites)
|
||||
}
|
||||
|
||||
/*
|
||||
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 *revel.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
|
||||
}
|
||||
|
||||
// formatResponse gets *revel.TestSuite as input parameter and
|
||||
// transform response related info into a readable format.
|
||||
func formatResponse(t testing.TestSuite) map[string]string {
|
||||
if t.Response == nil {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// Since Go 1.6 http.Request struct contains `Cancel <-chan struct{}` which
|
||||
// results in `json: unsupported type: <-chan struct {}`
|
||||
// So pull out required things for Request and Response
|
||||
req := map[string]interface{}{
|
||||
"Method": t.Response.Request.Method,
|
||||
"URL": t.Response.Request.URL,
|
||||
"Proto": t.Response.Request.Proto,
|
||||
"ContentLength": t.Response.Request.ContentLength,
|
||||
"Header": t.Response.Request.Header,
|
||||
"Form": t.Response.Request.Form,
|
||||
"PostForm": t.Response.Request.PostForm,
|
||||
}
|
||||
|
||||
resp := map[string]interface{}{
|
||||
"Status": t.Response.Status,
|
||||
"StatusCode": t.Response.StatusCode,
|
||||
"Proto": t.Response.Proto,
|
||||
"Header": t.Response.Header,
|
||||
"ContentLength": t.Response.ContentLength,
|
||||
"TransferEncoding": t.Response.TransferEncoding,
|
||||
}
|
||||
|
||||
// Beautify the response JSON to make it human readable.
|
||||
respBytes, err := json.MarshalIndent(
|
||||
map[string]interface{}{
|
||||
"Response": resp,
|
||||
"Request": req,
|
||||
},
|
||||
"",
|
||||
" ")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Remove extra new line symbols so they do not take too much space on a result page.
|
||||
// Allow no more than 1 line break at a time.
|
||||
body := strings.Replace(string(t.ResponseBody), "\n\n", "\n", -1)
|
||||
body = strings.Replace(body, "\r\n\r\n", "\r\n", -1)
|
||||
|
||||
return map[string]string{
|
||||
"Headers": string(respBytes),
|
||||
"Body": strings.TrimSpace(body),
|
||||
}
|
||||
}
|
||||
|
||||
//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()
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Every time app is restarted convert the list of available test suites
|
||||
// provided by the revel testing package into a format which will be used by
|
||||
// the testrunner module and revel test cmd.
|
||||
revel.OnAppStart(func() {
|
||||
// Extracting info about available test suites from revel/testing package.
|
||||
registeredTests = map[string]int{}
|
||||
sort.Sort(sortBySuiteName(testing.TestSuites))
|
||||
for _, testSuite := range testing.TestSuites {
|
||||
testSuites = append(testSuites, describeSuite(testSuite))
|
||||
}
|
||||
})
|
||||
}
|
11
vendor/github.com/revel/modules/testrunner/app/plugin.go
generated
vendored
Normal file
11
vendor/github.com/revel/modules/testrunner/app/plugin.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
func init() {
|
||||
revel.OnAppStart(func() {
|
||||
revel.AppLog.Info("Go to /@tests to run the tests.")
|
||||
})
|
||||
}
|
45
vendor/github.com/revel/modules/testrunner/app/views/TestRunner/FailureDetail.html
generated
vendored
Normal file
45
vendor/github.com/revel/modules/testrunner/app/views/TestRunner/FailureDetail.html
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<b>{{.error.Description}}</b>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="active"><a href="#error_{{.postfix}}" role="tab" data-toggle="tab">Error</a></li>
|
||||
<li><a href="#stack_{{.postfix}}" role="tab" data-toggle="tab">Stack</a></li>
|
||||
{{if .response}}
|
||||
<li><a href="#headers_{{.postfix}}" role="tab" data-toggle="tab">Headers</a></li>
|
||||
<li><a href="#body_{{.postfix}}" role="tab" data-toggle="tab">Response Body</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="result_{{.postfix}}">
|
||||
<div class="tab-pane active" id="error_{{.postfix}}">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
In {{.error.Path}}{{if .error.Line}} (around {{if .error.Line}}line {{.error.Line}}{{end}}{{if .error.Column}} column {{.error.Column}}{{end}}){{end}}:
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{range .error.ContextSource}}
|
||||
{{if .IsError}}
|
||||
<pre><code class="go">{{.Source}}</code></pre>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="stack_{{.postfix}}">
|
||||
<pre><code class="bash">{{.error.Stack}}</code></pre>
|
||||
</div>
|
||||
{{if .response}}
|
||||
<div class="tab-pane" id="headers_{{.postfix}}">
|
||||
<pre><code class="json">{{.response.Headers}}</code></pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="body_{{.postfix}}">
|
||||
<pre><code class="html">{{.response.Body}}</code></pre>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
232
vendor/github.com/revel/modules/testrunner/app/views/TestRunner/Index.html
generated
vendored
Normal file
232
vendor/github.com/revel/modules/testrunner/app/views/TestRunner/Index.html
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Revel Test Runner</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link href="{{url `Root`}}/@tests/public/css/bootstrap.min.css" type="text/css" rel="stylesheet"></link>
|
||||
<link href="{{url `Root`}}/@tests/public/css/github.css" type="text/css" rel="stylesheet"></link>
|
||||
<script src="{{url `Root`}}/@tests/public/js/jquery-1.9.1.min.js" type="text/javascript"></script>
|
||||
<script src="{{url `Root`}}/@tests/public/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="{{url `Root`}}/@tests/public/js/highlight.pack.js" type="text/javascript"></script>
|
||||
<style>
|
||||
header { background-color:#ADD8E6 }
|
||||
header h1 {margin-top: 10px; margin-bottom:20px;}
|
||||
header table {margin-bottom: 0px }
|
||||
td .btn {margin-bottom: 1px; }
|
||||
button.file-test { margin-bottom: 0px; margin-left: 2px }
|
||||
table.tests tr { border-bottom: 1px solid #ddd; background-color: #f9f9f9; }
|
||||
.passed td { background-color: #90EE90 !important; }
|
||||
.failed td { background-color: #FFB6C1 !important; }
|
||||
td.result div.panel-default{ display:none; }
|
||||
td.result > a { color: red; }
|
||||
td.rightCol, td.leftCol { width: 40px; }
|
||||
pre { font-size:10px; white-space: pre; }
|
||||
.panel-heading {
|
||||
padding: 10px 5px 8px 5px
|
||||
}
|
||||
.name { width: 35%; }
|
||||
.w100 { width: 100%; }
|
||||
.logo, .logo:hover { text-decoration: none; color: inherit;}
|
||||
.pnt-triangle { color: #777; font-size: 18px;}
|
||||
.panel-group .panel-heading+.panel-collapse>.panel-body { border-top: none;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="container">
|
||||
<h1 class="pull-left">
|
||||
<a href="/@tests" class="logo">Test Runner</a> <small>- Run your application's tests here.</small>
|
||||
</h1>
|
||||
<div style="margin-top:16px" class="pull-right">
|
||||
<button class="btn btn-success {{if not .suiteFound}}disabled{{end}}" all-tests="">Run All Tests</button>
|
||||
<div><a class="small" href="#" id="allTestResults"></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="panel-group container">
|
||||
{{if not .suiteFound}}
|
||||
<div style="margin-top:20px;padding:15px;" class="panel panel-default">
|
||||
<span style="font-weight:bold;color:#777;">Suite "{{.suiteName}}" is not found.</span>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{range .testSuites}}
|
||||
{{ $testFile := .Name }}
|
||||
<div style="margin-top:20px;" class="panel panel-default">
|
||||
<div class="panel-heading collapseLnk" style="cursor:pointer" data-toggle="collapse" data-target="#{{.Name}}">
|
||||
<button id="suite{{.Name}}" class="btn btn-xs btn-success" test-file="{{.Name}}">Run</button>
|
||||
<span class="h5"> <a href="/@tests/{{ .Name }}">{{.Name}}</a></span>
|
||||
<span id="pointTriangle{{.Name}}" class="pnt-triangle pull-right" data-tri-open="open">▼</span>
|
||||
</div>
|
||||
<div id="{{.Name}}" class="panel-collapse collapse in">
|
||||
<table class="panel-body table table-condensed tests" suite="{{.Name}}">
|
||||
{{range .Tests}}
|
||||
<tr id="testRow{{.Name}}">
|
||||
<td class="leftCol"><button data-test-file="{{$testFile}}" test="{{.Name}}" class="leftbutton btn btn-success btn-xs">Run</button></td>
|
||||
<td class="name">{{ .Name }}</td>
|
||||
<td class="result"><a href="#"></a></td>
|
||||
<td class="rightCol"><button data-test-file="{{$testFile}}" test="{{.Name}}" class="pull-right btn btn-success btn-xs">Run</button></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var passCount = 0;
|
||||
var failCount = 0;
|
||||
var buttons = [];
|
||||
var running;
|
||||
|
||||
$(function() {
|
||||
var divId, visible;
|
||||
var oneOpened = false;
|
||||
var panels = $("div.panel-collapse");
|
||||
//close any panels that were previously closed.
|
||||
panels.each(function() {
|
||||
divId = "#" + $(this).attr("id");
|
||||
visible = parseBoolean(localStorage.getItem("testrunner_" + divId));
|
||||
if (visible) {
|
||||
togglePntTriangle(divId, visible);
|
||||
oneOpened = visible;
|
||||
} else {
|
||||
$(divId).css("height", "0").removeClass("in"); //this is the way bootstrap does it.
|
||||
$("div[data-target=" + divId + "]").addClass("collapsed");
|
||||
togglePntTriangle(divId, visible);
|
||||
}
|
||||
});
|
||||
|
||||
if (!oneOpened && panels.length > 0) {
|
||||
divId = "#" + panels[0].id;
|
||||
$(divId).collapse('show');
|
||||
togglePntTriangle(divId, true);
|
||||
}
|
||||
});
|
||||
|
||||
$(".fileTestLnk").click(function() {
|
||||
var tableId = $(this).attr("href");
|
||||
$(tableId).toggle();
|
||||
return false;
|
||||
});
|
||||
|
||||
$("#allTestResults").click(function() {
|
||||
var badRows = $("tr.failed");
|
||||
if (badRows.length >= 0) {
|
||||
badRows[0].scrollIntoView();
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$("button[test]").click(function() {
|
||||
$("#allTestResults").text("");
|
||||
var button = $(this).addClass("disabled").text("Running");
|
||||
$(this).closest("tr").removeClass("passed").removeClass("failed");
|
||||
addToQueue(button);
|
||||
});
|
||||
|
||||
$("td.result a").click(function() { //show/hide the extended error div
|
||||
$(this).siblings().toggle();
|
||||
return false;
|
||||
});
|
||||
|
||||
$("button[test-file]").click(function() {
|
||||
$("#allTestResults").text("");
|
||||
var testfile = $(this).attr('test-file');
|
||||
$("button").each(function() {
|
||||
if ($(this).data("test-file") == testfile)
|
||||
$(this).click();
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$("button[all-tests]").click(function() {
|
||||
$("tr").removeClass("passed").removeClass("failed");
|
||||
passCount = 0;
|
||||
failCount = 0;
|
||||
var button = $(this).addClass("disabled").text("Running");
|
||||
$("button.leftbutton[test]").click();
|
||||
});
|
||||
|
||||
$("div.collapseLnk").click(function() {
|
||||
var tableId = $(this).data("target");
|
||||
var visible = !$(tableId).is(":visible");
|
||||
localStorage.setItem("testrunner_" + tableId, visible);
|
||||
togglePntTriangle(tableId, visible);
|
||||
});
|
||||
|
||||
function togglePntTriangle(suiteId, visible) {
|
||||
if (suiteId.charAt(0) == '#') {
|
||||
suiteId = suiteId.substring(1);
|
||||
}
|
||||
$('#pointTriangle' + suiteId).html(visible ? '▼' : '▶');
|
||||
}
|
||||
|
||||
function parseBoolean(str) {
|
||||
return /^true$/i.test(str);
|
||||
}
|
||||
|
||||
function addToQueue(button) {
|
||||
buttons.push(button);
|
||||
if (!running) {
|
||||
running = true;
|
||||
nextTest();
|
||||
}
|
||||
}
|
||||
|
||||
function nextTest() {
|
||||
if (buttons.length == 0) {
|
||||
running = false;
|
||||
} else {
|
||||
var next = buttons.shift();
|
||||
runTest(next);
|
||||
}
|
||||
}
|
||||
|
||||
function runTest(button) {
|
||||
var suite = button.parents("table").attr("suite");
|
||||
var test = button.attr("test");
|
||||
var row = button.parents("tr");
|
||||
var resultCell = row.children(".result");
|
||||
$("a", resultCell).text("");
|
||||
$("div.panel-default", resultCell).remove();
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: "{{url `Root`}}/@tests/"+suite+"/"+test,
|
||||
success: function(result) {
|
||||
row.attr("class", result.Passed ? "passed" : "failed");
|
||||
if (result.Passed) {
|
||||
passCount++;
|
||||
} else {
|
||||
console.log("fail:", result.Name);
|
||||
failCount++;
|
||||
var resultLnk = $("a", resultCell);
|
||||
$(resultLnk).text(result.ErrorSummary);
|
||||
resultCell.append(result.ErrorHTML);
|
||||
|
||||
var pnlDiv = row.closest("div");
|
||||
if ($(pnlDiv).hasClass("in") == false) {
|
||||
$("#link-" + suite).click();
|
||||
}
|
||||
|
||||
$("#result_" + suite + "_" + test + " pre code").each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
button.removeClass("disabled").text("Run");
|
||||
var runAllBut = $("button[all-tests]");
|
||||
if (buttons.length == 0 && runAllBut.hasClass("disabled")) {
|
||||
runAllBut.removeClass("disabled").text("Run All Tests");
|
||||
var resMsg = passCount + " passed, " + failCount + " failed.";
|
||||
$("#allTestResults").text(resMsg);
|
||||
}
|
||||
nextTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
48
vendor/github.com/revel/modules/testrunner/app/views/TestRunner/SuiteResult.html
generated
vendored
Normal file
48
vendor/github.com/revel/modules/testrunner/app/views/TestRunner/SuiteResult.html
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Revel Test Runner</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333333;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
header { padding:20px 0; }
|
||||
header.passed { background-color: #90EE90 !important; }
|
||||
header.failed { background-color: #FFB6C1 !important; }
|
||||
table { margin-top: 20px; padding: 8px; line-height: 20px; }
|
||||
td { vertical-align: top; padding-right:20px; }
|
||||
a { color: #0088cc; }
|
||||
.container { margin-left: auto; margin-right: auto; width: 940px; overflow: hidden; }
|
||||
.result h2 { font-size: 16px; border-bottom: 1px solid #f0f0f0; padding-bottom: 0.2em; }
|
||||
.result.failed b { font-weight:bold; color: #C00; font-size: 14px; }
|
||||
.result.failed h2 { color: #C00; }
|
||||
.result .info { font-size: 12px; }
|
||||
.result .info pre { overflow: auto; background-color: #f0f0f0; width: 100%; max-height: 500px; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<header class="{{if .Passed}}passed{{else}}failed{{end}}">
|
||||
<div class="container">
|
||||
<h1>{{.Name}}</h1>
|
||||
<p>{{if .Passed}}PASSED{{else}}FAILED{{end}}</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
{{range .Results}}
|
||||
<div class="result {{if .Passed}}passed{{else}}failed{{end}}">
|
||||
<div><h2>{{.Name}}</h2></div>
|
||||
<div class="info">{{if .ErrorHTML}}{{.ErrorHTML}}{{else}}PASSED{{end}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
5
vendor/github.com/revel/modules/testrunner/conf/routes
generated
vendored
Normal file
5
vendor/github.com/revel/modules/testrunner/conf/routes
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
GET /@tests TestRunner.Index
|
||||
GET /@tests.list TestRunner.List
|
||||
GET /@tests/public/*filepath Static.ServeModule(testrunner,public)
|
||||
GET /@tests/:suite TestRunner.Suite
|
||||
GET /@tests/:suite/:test TestRunner.Run
|
5
vendor/github.com/revel/modules/testrunner/public/css/bootstrap.min.css
generated
vendored
Normal file
5
vendor/github.com/revel/modules/testrunner/public/css/bootstrap.min.css
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
127
vendor/github.com/revel/modules/testrunner/public/css/github.css
generated
vendored
Normal file
127
vendor/github.com/revel/modules/testrunner/public/css/github.css
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
color: #333;
|
||||
background: #f8f8f8;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-template_comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-javadoc {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.css .rule .hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.javascript .hljs-title,
|
||||
.nginx .hljs-title,
|
||||
.hljs-subst,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-hexcolor,
|
||||
.ruby .hljs-constant {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-phpdoc,
|
||||
.hljs-dartdoc,
|
||||
.tex .hljs-formula {
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-id,
|
||||
.scss .hljs-preprocessor {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.javascript .hljs-title,
|
||||
.hljs-list .hljs-keyword,
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-type,
|
||||
.vhdl .hljs-literal,
|
||||
.tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-tag .hljs-title,
|
||||
.hljs-rules .hljs-property,
|
||||
.django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.lisp .hljs-keyword,
|
||||
.clojure .hljs-keyword,
|
||||
.scheme .hljs-keyword,
|
||||
.tex .hljs-special,
|
||||
.hljs-prompt {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-pi,
|
||||
.hljs-doctype,
|
||||
.hljs-shebang,
|
||||
.hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #fdd;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #dfd;
|
||||
}
|
||||
|
||||
.diff .hljs-change {
|
||||
background: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-chunk {
|
||||
color: #aaa;
|
||||
}
|
BIN
vendor/github.com/revel/modules/testrunner/public/images/favicon.png
generated
vendored
Normal file
BIN
vendor/github.com/revel/modules/testrunner/public/images/favicon.png
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
6
vendor/github.com/revel/modules/testrunner/public/js/bootstrap.min.js
generated
vendored
Normal file
6
vendor/github.com/revel/modules/testrunner/public/js/bootstrap.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
vendor/github.com/revel/modules/testrunner/public/js/highlight.pack.js
generated
vendored
Normal file
1
vendor/github.com/revel/modules/testrunner/public/js/highlight.pack.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
5
vendor/github.com/revel/modules/testrunner/public/js/jquery-1.9.1.min.js
generated
vendored
Normal file
5
vendor/github.com/revel/modules/testrunner/public/js/jquery-1.9.1.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3
vendor/github.com/revel/modules/testrunner/testrunner.go
generated
vendored
Normal file
3
vendor/github.com/revel/modules/testrunner/testrunner.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package testrunner
|
||||
|
||||
// Required for vendoring see golang.org/issue/13832
|
Reference in New Issue
Block a user