Skip to content

Commit

Permalink
imp(report): Refactor nested report map (#7)
Browse files Browse the repository at this point in the history
* refactor the nested map for markdown and HTML reports

* add changelog entry

* add test CI workflow

* address linters
  • Loading branch information
MalteHerrmann authored May 8, 2024
1 parent 8562f35 commit 7badcbb
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 45 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Tests
on:
pull_request:
push:
branches:
- main
jobs:
tests:
name: Run tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
# Required: setup-go, for all versions v3.0.0+ of golangci-lint
- uses: actions/setup-go@v4
with:
go-version: '1.22'
check-latest: true
- uses: actions/checkout@v4
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- run: make test
# Check only if there are differences in the source code
if: "env.GIT_DIFF"
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

- (report) [#7](https://github.com/MalteHerrmann/ginkgo-parser/7) Refactor nested contents for Markdown and HTML reports.
- (cli) [#6](https://github.com/MalteHerrmann/ginkgo-parser/6) Use Cobra for CLI implementation.
- (ci) [#5](https://github.com/MalteHerrmann/ginkgo-parser/5) Add linter to CI.

Expand Down
50 changes: 5 additions & 45 deletions report/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package report
import (
"fmt"
"os"

ginkgotypes "github.com/onsi/ginkgo/v2/types"
)

// spacesPerIndentation defines the whitespace to be used per indentation level.
Expand All @@ -18,7 +16,7 @@ func ConvertGinkgoReportToMarkdown(jsonFile, markdownFile string) error {
return fmt.Errorf("error parsing JSON: %w", err)
}

spec, err := buildSpecMap(reports)
spec, err := BuildNestedContents(reports)
if err != nil {
return fmt.Errorf("error building spec map: %w", err)
}
Expand All @@ -33,51 +31,13 @@ func ConvertGinkgoReportToMarkdown(jsonFile, markdownFile string) error {
return nil
}

// buildSpecMap recursively builds a map of nested maps from the given Ginkgo reports.
// This is used to convert the typed structure of the Ginkgo reports
// to a nested Markdown structure.
func buildSpecMap(reports []ginkgotypes.Report) (map[string]interface{}, error) {
spec := make(map[string]interface{})

for _, report := range reports {
for _, specReport := range report.SpecReports {
containerHierarchy := specReport.ContainerHierarchyTexts

var leafNodeTypeStr string
leafNodeType := specReport.LeafNodeType
switch leafNodeType {
case ginkgotypes.NodeTypeIt:
leafNodeTypeStr = "it"
default:
return nil, fmt.Errorf("unknown leaf node type: %d", leafNodeType)
}

leafNodeText := specReport.LeafNodeText
cleanLeafNode := leafNodeTypeStr + " " + leafNodeText
containerHierarchy = append(containerHierarchy, cleanLeafNode)

currentSpec := spec
for _, item := range containerHierarchy {
// If the item is not yet in the map, create a new map for the underlying levels
// and add the item to the map.
if currentSpec[item] == nil {
currentSpec[item] = make(map[string]interface{})
}
currentSpec = currentSpec[item].(map[string]interface{})
}
}
}

return spec, nil
}

// buildMarkdown is a recursive function to build a markdown string from the given map of nested maps.
func buildMarkdown(contents map[string]interface{}, indentationLevel int) string {
func buildMarkdown(spec NestedContents, indentationLevel int) string {
markdown := ""
for key, value := range contents {
if value != nil {
for key, value := range spec.Contents {
if len(value.Contents) != 0 {
markdown += fmt.Sprintf("%s- %s\n", spaces(indentationLevel), key)
markdown += buildMarkdown(value.(map[string]interface{}), indentationLevel+1)
markdown += buildMarkdown(value, indentationLevel+1)
} else {
markdown += fmt.Sprintf("%s- %s\n", spaces(indentationLevel), key)
}
Expand Down
73 changes: 73 additions & 0 deletions report/nested_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package report

import (
"fmt"

ginkgotypes "github.com/onsi/ginkgo/v2/types"
)

type NestedContents struct {
HasSkipped bool
HasFailed bool
Contents map[string]NestedContents
}

func newNestedContents() NestedContents {
return NestedContents{
HasSkipped: false,
HasFailed: false,
Contents: make(map[string]NestedContents),
}
}

// BuildNestedContents recursively builds a map of nested maps from the given Ginkgo reports.
//
// This is used to convert the typed structure of the Ginkgo reports
// to a nested Markdown or HTML structure.
func BuildNestedContents(reports []ginkgotypes.Report) (NestedContents, error) {
spec := newNestedContents()

for _, report := range reports {
for _, specReport := range report.SpecReports {
containerHierarchy := specReport.ContainerHierarchyTexts

cleanLeafNode := getCleanLeafNodeText(specReport)
containerHierarchy = append(containerHierarchy, cleanLeafNode)

currentNestingLevel := spec
for _, item := range containerHierarchy {
// If the item is not yet in the map, create a new map for the underlying levels
// and add the item to the map.
content, found := currentNestingLevel.Contents[item]
if !found {
content = newNestedContents()
currentNestingLevel.Contents[item] = content
}
currentNestingLevel = content
}
}
}

return spec, nil
}

// getCleanLeafNodeText returns the clean leaf node text for the given Ginkgo spec report.
//
// Example: An It block with the text "should return the correct value" will be converted
// to "it should return the correct value".
func getCleanLeafNodeText(specReport ginkgotypes.SpecReport) string {
var leafNodeTypeStr string

leafNodeType := specReport.LeafNodeType
switch leafNodeType {
case ginkgotypes.NodeTypeIt:
leafNodeTypeStr = "it"
default:
panic(fmt.Sprintf("unknown leaf node type: %d", leafNodeType))
}

leafNodeText := specReport.LeafNodeText
cleanLeafNode := leafNodeTypeStr + " " + leafNodeText

return cleanLeafNode
}
55 changes: 55 additions & 0 deletions report/nested_map_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package report_test

import (
"github.com/MalteHerrmann/ginkgo-parser/report"
ginkgotypes "github.com/onsi/ginkgo/v2/types"

//nolint:revive // dot imports are okay for ginkgo
. "github.com/onsi/ginkgo/v2"
//nolint:revive // dot imports are okay for ginkgo
. "github.com/onsi/gomega"
)

var _ = Describe("Building the nested map", Ordered, func() {
var (
reports []ginkgotypes.Report
spec report.NestedContents
)

BeforeAll(func() {
// Load the example report from the testdata directory
var err error
reports, err = report.GetReportsFromJSON("testdata/example_report.json")
Expect(err).To(BeNil(), "expected no error parsing the report")
})

It("should build the nested map without error", func() {
var err error
spec, err = report.BuildNestedContents(reports)
Expect(err).To(BeNil(), "expected no error building the spec map")
Expect(spec).ToNot(BeNil(), "expected a non-nil spec map")
Expect(spec.HasFailed).To(BeFalse(), "expected no failed specs")
Expect(spec.HasSkipped).To(BeFalse(), "expected no skipped specs")
Expect(spec.Contents).To(HaveKey("Example"), "expected a different top-level key")
})

It("should have the correct hierarchy", func() {
Expect(spec.Contents["Example"].Contents).To(HaveKey("it should be true"), "expected key to be present")
Expect(spec.Contents["Example"].Contents).To(HaveKey("it should be false"), "expected key to be present")

Expect(spec.Contents["Example"].Contents).To(HaveKey("Nested table"), "expected key to be present")
Expect(spec.Contents["Example"].Contents["Nested table"].Contents).To(
HaveKey("it 1 is 1"),
"expected key to be present",
)

Expect(spec.Contents["Example"].Contents).To(
HaveKey("skipped tests"),
"expected key to be present",
)
Expect(spec.Contents["Example"].Contents["skipped tests"].Contents).To(
HaveKey("it should be skipped"),
"expected key to be present",
)
})
})

0 comments on commit 7badcbb

Please sign in to comment.