diff --git a/htmltest/htmltest.go b/htmltest/htmltest.go
index 8bed808..a1c8c09 100644
--- a/htmltest/htmltest.go
+++ b/htmltest/htmltest.go
@@ -278,3 +278,8 @@ func (hT *HTMLTest) CountErrors() int {
func (hT *HTMLTest) CountDocuments() int {
return len(hT.documentStore.Documents)
}
+
+// CountDocuments : Return number of documents in hT document store
+func (hT *HTMLTest) FormatIssueStats() string {
+ return hT.issueStore.FormatIssueStats()
+}
diff --git a/issues/issue_store.go b/issues/issue_store.go
index f572417..92fc60f 100644
--- a/issues/issue_store.go
+++ b/issues/issue_store.go
@@ -7,6 +7,7 @@ import (
"github.com/wjdp/htmltest/htmldoc"
"github.com/wjdp/htmltest/output"
"io/ioutil"
+ "sort"
"strings"
"sync"
)
@@ -125,3 +126,68 @@ func (iS *IssueStore) DumpIssues(force bool) {
}
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>")
}
+
+type IssueStats struct {
+ // How many issues of each level
+ TotalByLevel map[int]int
+ // Collect errors against count
+ ErrorsByMessage map[string]int
+ // Collect warnings against count
+ WarningsByMessage map[string]int
+}
+
+// GetIssueStats : Get stats on issues in the store.
+func (iS *IssueStore) GetIssueStats() IssueStats {
+ stats := IssueStats{TotalByLevel: make(map[int]int), ErrorsByMessage: make(map[string]int), WarningsByMessage: make(map[string]int)}
+ for _, issue := range iS.issues {
+ stats.TotalByLevel[issue.Level]++
+ if issue.Level == LevelError {
+ stats.ErrorsByMessage[issue.Message]++
+ }
+ if issue.Level == LevelWarning {
+ stats.WarningsByMessage[issue.Message]++
+ }
+ }
+ return stats
+}
+
+func formatMessageCounts(messageCounts map[string]int) string {
+ keySlice := make([]string, 0)
+ for key, _ := range messageCounts {
+ keySlice = append(keySlice, key)
+ }
+ sort.Strings(keySlice)
+
+ var s string
+ for _, message := range keySlice {
+ s += fmt.Sprintf(" %d \"%s\"\n", messageCounts[message], message)
+ }
+ return s
+}
+
+// FormatIssueStats : Return formatted stats on issues in the store.
+func (iS *IssueStore) FormatIssueStats() string {
+ formattedStats := ""
+ stats := iS.GetIssueStats()
+ if iS.logLevel <= LevelError {
+ formattedStats += fmt.Sprintln(" Errors: ", stats.TotalByLevel[LevelError])
+ }
+ if iS.logLevel <= LevelWarning {
+ formattedStats += fmt.Sprintln(" Warnings:", stats.TotalByLevel[LevelWarning])
+ }
+ if iS.logLevel <= LevelInfo {
+ formattedStats += fmt.Sprintln(" Infos: ", stats.TotalByLevel[LevelInfo])
+ }
+ if iS.logLevel <= LevelDebug {
+ formattedStats += fmt.Sprintln(" Debugs: ", stats.TotalByLevel[LevelDebug])
+ }
+ if (iS.logLevel <= LevelError) && (len(stats.ErrorsByMessage) > 0) {
+ formattedStats += fmt.Sprintln(" Errors by message:")
+ formattedStats += formatMessageCounts(stats.ErrorsByMessage)
+ }
+ if (iS.logLevel <= LevelWarning) && (len(stats.WarningsByMessage) > 0) {
+ formattedStats += fmt.Sprintln(" Warnings by message:")
+ formattedStats += formatMessageCounts(stats.WarningsByMessage)
+ }
+ return formattedStats
+}
diff --git a/issues/issue_store_test.go b/issues/issue_store_test.go
index 4f65af6..7c751e9 100644
--- a/issues/issue_store_test.go
+++ b/issues/issue_store_test.go
@@ -1,10 +1,12 @@
package issues
import (
+ "fmt"
"github.com/daviddengcn/go-assert"
"github.com/wjdp/htmltest/htmldoc"
"io/ioutil"
"os"
+ "reflect"
"strings"
"testing"
)
@@ -140,3 +142,111 @@ func ExampleIssueStorePrintDocumentIssuesEmpty() {
iS.PrintDocumentIssues(&doc)
// Output:
}
+
+func TestGetIssueStats_None(t *testing.T) {
+ iS := NewIssueStore(LevelError, false)
+ stats := iS.GetIssueStats()
+ assert.IsTrue(t, "TotalByLevel", reflect.DeepEqual(stats.TotalByLevel, map[int]int{}))
+ assert.IsTrue(t, "ErrorsByMessage", reflect.DeepEqual(stats.ErrorsByMessage, map[string]int{}))
+ assert.IsTrue(t, "WarningsByMessage", reflect.DeepEqual(stats.WarningsByMessage, map[string]int{}))
+}
+
+func addOneError(iS *IssueStore) {
+ iS.AddIssue(Issue{
+ Level: LevelError,
+ Message: "test",
+ })
+}
+
+func addMultipleIssues(iS *IssueStore) {
+ iS.AddIssue(Issue{
+ Level: LevelError,
+ Message: "test1",
+ })
+ iS.AddIssue(Issue{
+ Level: LevelWarning,
+ Message: "test1",
+ })
+ iS.AddIssue(Issue{
+ Level: LevelInfo,
+ Message: "test1",
+ })
+ iS.AddIssue(Issue{
+ Level: LevelDebug,
+ Message: "test1",
+ })
+ iS.AddIssue(Issue{
+ Level: LevelError,
+ Message: "test2",
+ })
+ iS.AddIssue(Issue{
+ Level: LevelError,
+ Message: "test2",
+ })
+}
+
+func TestGetIssueStats_OneError(t *testing.T) {
+ iS := NewIssueStore(LevelError, false)
+ addOneError(&iS)
+ stats := iS.GetIssueStats()
+ assert.Equals(
+ t, "TotalByLevel",
+ fmt.Sprint(stats.TotalByLevel),
+ fmt.Sprint(map[int]int{LevelError: 1}),
+ )
+ assert.Equals(
+ t, "ErrorsByMessage",
+ fmt.Sprint(stats.ErrorsByMessage),
+ fmt.Sprint(map[string]int{"test": 1}),
+ )
+}
+
+func TestGetIssueStats_MultipleIssues(t *testing.T) {
+ iS := NewIssueStore(LevelError, false)
+ addMultipleIssues(&iS)
+ stats := iS.GetIssueStats()
+ assert.Equals(t,
+ "TotalByLevel",
+ fmt.Sprint(stats.TotalByLevel),
+ fmt.Sprint(map[int]int{LevelError: 3, LevelWarning: 1, LevelInfo: 1, LevelDebug: 1}))
+ assert.Equals(
+ t, "ErrorsByMessage",
+ fmt.Sprint(stats.ErrorsByMessage),
+ fmt.Sprint(map[string]int{"test1": 1, "test2": 2}),
+ )
+ assert.Equals(
+ t, "WarningsByMessage",
+ fmt.Sprint(stats.WarningsByMessage),
+ fmt.Sprint(map[string]int{"test1": 1}),
+ )
+}
+
+func TestFormatIssueStats_None(t *testing.T) {
+ iS := NewIssueStore(LevelError, false)
+ assert.Equals(t, "FormatIssueStats", iS.FormatIssueStats(), " Errors: 0\n")
+}
+
+func TestFormatIssueStats_Multiple_AtLogLevelError(t *testing.T) {
+ iS := NewIssueStore(LevelError, false)
+ addMultipleIssues(&iS)
+ const expected = ` Errors: 3
+ Errors by message:
+ 1 "test1"
+ 2 "test2"
+`
+ assert.Equals(t, "FormatIssueStats", iS.FormatIssueStats(), expected)
+}
+
+func TestFormatIssueStats_Multiple_AtLogLevelWarning(t *testing.T) {
+ iS := NewIssueStore(LevelWarning, false)
+ addMultipleIssues(&iS)
+ const expected = ` Errors: 3
+ Warnings: 1
+ Errors by message:
+ 1 "test1"
+ 2 "test2"
+ Warnings by message:
+ 1 "test1"
+`
+ assert.Equals(t, "FormatIssueStats", iS.FormatIssueStats(), expected)
+}
diff --git a/main.go b/main.go
index 5c54fad..406a9b5 100644
--- a/main.go
+++ b/main.go
@@ -169,25 +169,36 @@ func run(options optsMap) int {
timeEnd := time.Now()
numErrors := hT.CountErrors()
+ documentCount := hT.CountDocuments()
+
+ if !fileMode && documentCount == 0 {
+ color.Set(color.FgHiYellow)
+ fmt.Printf("No documents found in '%s'\n", options["DirectoryPath"])
+ color.Unset()
+ return 2
+ }
if numErrors == 0 {
color.Set(color.FgHiGreen)
fmt.Println("✔✔✔ passed in", timeEnd.Sub(timeStart))
if !fileMode {
- fmt.Println("tested", hT.CountDocuments(), "documents")
+ fmt.Println("tested", documentCount, "documents")
}
color.Unset()
return 0
}
- color.Set(color.FgHiRed)
fmt.Println(cmdSeparator)
+ color.Set(color.FgHiRed)
fmt.Println("✘✘✘ failed in", timeEnd.Sub(timeStart))
- if fileMode {
- fmt.Println(numErrors, "errors")
- } else {
- fmt.Println(numErrors, "errors in", hT.CountDocuments(), "documents")
+ if !fileMode {
+ fmt.Println(output.Pluralise(
+ documentCount,
+ fmt.Sprint("tested ", documentCount, " document"),
+ fmt.Sprint("tested ", documentCount, " documents"),
+ ))
}
+ fmt.Printf(hT.FormatIssueStats())
color.Unset()
return 1
diff --git a/output/strings.go b/output/strings.go
new file mode 100644
index 0000000..0207c99
--- /dev/null
+++ b/output/strings.go
@@ -0,0 +1,9 @@
+package output
+
+// Pluralise: a dumb pluraliser that only works for English.
+func Pluralise(n int, singular string, plural string) string {
+ if n == 1 {
+ return singular
+ }
+ return plural
+}
diff --git a/output/strings_test.go b/output/strings_test.go
new file mode 100644
index 0000000..16a68b0
--- /dev/null
+++ b/output/strings_test.go
@@ -0,0 +1,11 @@
+package output
+
+import (
+ "github.com/daviddengcn/go-assert"
+ "testing"
+)
+
+func TestPluralise(t *testing.T) {
+ assert.Equals(t, "singular", Pluralise(1, "1 apple", "2 apples"), "1 apple")
+ assert.Equals(t, "plural", Pluralise(2, "1 apple", "2 apples"), "2 apples")
+}