diff --git a/ginkgo/main.go b/ginkgo/main.go index f60c48a72..ac725bf40 100644 --- a/ginkgo/main.go +++ b/ginkgo/main.go @@ -111,6 +111,11 @@ will output an executable file named `package.test`. This can be run directly o ginkgo + +To print an outline of Ginkgo specs and containers in a file: + + gingko outline + To print out Ginkgo's version: ginkgo version @@ -172,6 +177,7 @@ func init() { Commands = append(Commands, BuildUnfocusCommand()) Commands = append(Commands, BuildVersionCommand()) Commands = append(Commands, BuildHelpCommand()) + Commands = append(Commands, BuildOutlineCommand()) } func main() { diff --git a/ginkgo/outline/_testdata/alias_test.go b/ginkgo/outline/_testdata/alias_test.go new file mode 100644 index 000000000..bf9a29075 --- /dev/null +++ b/ginkgo/outline/_testdata/alias_test.go @@ -0,0 +1,49 @@ +package example_test + +import ( + fooginkgo "github.com/onsi/ginkgo" +) + +var _ = fooginkgo.Describe("NodotFixture", func() { + fooginkgo.Describe("normal", func() { + fooginkgo.It("normal", func() { + fooginkgo.By("normal") + fooginkgo.By("normal") + + }) + }) + + fooginkgo.Context("normal", func() { + fooginkgo.It("normal", func() { + + }) + }) + + fooginkgo.When("normal", func() { + fooginkgo.It("normal", func() { + + }) + }) + + fooginkgo.It("normal", func() { + + }) + + fooginkgo.Specify("normal", func() { + + }) + + fooginkgo.Measure("normal", func(b Benchmarker) { + + }, 2) + + fooginkgo.DescribeTable("normal", + func() {}, + fooginkgo.Entry("normal"), + ) + + fooginkgo.DescribeTable("normal", + func() {}, + fooginkgo.Entry("normal"), + ) +}) diff --git a/ginkgo/outline/_testdata/alias_test.go.csv b/ginkgo/outline/_testdata/alias_test.go.csv new file mode 100644 index 000000000..267f905a1 --- /dev/null +++ b/ginkgo/outline/_testdata/alias_test.go.csv @@ -0,0 +1,13 @@ +Name,Text,Start,End,Spec,Focused,Pending +Describe,NodotFixture,79,728,false,false,false +Describe,normal,124,257,false,false,false +It,normal,164,253,true,false,false +By,normal,199,221,false,false,false +By,normal,225,247,false,false,false +Context,normal,260,340,false,false,false +It,normal,299,336,true,false,false +When,normal,343,420,false,false,false +It,normal,379,416,true,false,false +It,normal,423,459,true,false,false +Specify,normal,462,503,true,false,false +Measure,normal,506,563,true,false,false diff --git a/ginkgo/outline/_testdata/alias_test.go.json b/ginkgo/outline/_testdata/alias_test.go.json new file mode 100644 index 000000000..885de0a80 --- /dev/null +++ b/ginkgo/outline/_testdata/alias_test.go.json @@ -0,0 +1 @@ +[{"name":"Describe","text":"NodotFixture","start":79,"end":728,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"Describe","text":"normal","start":124,"end":257,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":164,"end":253,"spec":true,"focused":false,"pending":false,"nodes":[{"name":"By","text":"normal","start":199,"end":221,"spec":false,"focused":false,"pending":false},{"name":"By","text":"normal","start":225,"end":247,"spec":false,"focused":false,"pending":false}]}]},{"name":"Context","text":"normal","start":260,"end":340,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":299,"end":336,"spec":true,"focused":false,"pending":false}]},{"name":"When","text":"normal","start":343,"end":420,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":379,"end":416,"spec":true,"focused":false,"pending":false}]},{"name":"It","text":"normal","start":423,"end":459,"spec":true,"focused":false,"pending":false},{"name":"Specify","text":"normal","start":462,"end":503,"spec":true,"focused":false,"pending":false},{"name":"Measure","text":"normal","start":506,"end":563,"spec":true,"focused":false,"pending":false}]}] diff --git a/ginkgo/outline/_testdata/create_result.sh b/ginkgo/outline/_testdata/create_result.sh new file mode 100644 index 000000000..357690cf3 --- /dev/null +++ b/ginkgo/outline/_testdata/create_result.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -o errexit +set -o nounset + +GINKGO=${GINKGO:-ginkgo} + +input=${1:-""} +for format in "csv" "json"; do + set -o xtrace + output="$(dirname $input)/$(basename $input).$format" + tmp=$(mktemp ginkgo-outline-test.XXX) + if "$GINKGO" outline --format="$format" "$input" 1>"$tmp" + then mv "$tmp" "$output" + else rm "$tmp" + set +o xtrace + fi +done diff --git a/ginkgo/outline/_testdata/focused_test.go b/ginkgo/outline/_testdata/focused_test.go new file mode 100644 index 000000000..e9f5a5d52 --- /dev/null +++ b/ginkgo/outline/_testdata/focused_test.go @@ -0,0 +1,49 @@ +package example_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" +) + +var _ = Describe("unfocused", func() { + FDescribe("focused", func() { + It("focused", func() { + By("focused") + By("focused") + }) + }) + + FContext("focused", func() { + It("focused", func() { + + }) + }) + + FWhen("focused", func() { + It("focused", func() { + + }) + }) + + FIt("focused", func() { + + }) + + FSpecify("focused", func() { + + }) + + FMeasure("focused", func(b Benchmarker) { + + }, 2) + + FDescribeTable("focused", + func() {}, + Entry("focused"), + ) + + DescribeTable("focused", + func() {}, + FEntry("focused"), + ) +}) diff --git a/ginkgo/outline/_testdata/focused_test.go.csv b/ginkgo/outline/_testdata/focused_test.go.csv new file mode 100644 index 000000000..d49522daf --- /dev/null +++ b/ginkgo/outline/_testdata/focused_test.go.csv @@ -0,0 +1,13 @@ +Name,Text,Start,End,Spec,Focused,Pending +Describe,unfocused,116,624,false,false,false +FDescribe,focused,148,245,false,true,false +It,focused,180,241,true,true,false +By,focused,206,219,false,true,false +By,focused,223,236,false,true,false +FContext,focused,248,311,false,true,false +It,focused,279,307,true,true,false +FWhen,focused,314,374,false,true,false +It,focused,342,370,true,true,false +FIt,focused,377,405,true,true,false +FSpecify,focused,408,441,true,true,false +FMeasure,focused,444,493,true,true,false diff --git a/ginkgo/outline/_testdata/focused_test.go.json b/ginkgo/outline/_testdata/focused_test.go.json new file mode 100644 index 000000000..2c042225d --- /dev/null +++ b/ginkgo/outline/_testdata/focused_test.go.json @@ -0,0 +1 @@ +[{"name":"Describe","text":"unfocused","start":116,"end":624,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"FDescribe","text":"focused","start":148,"end":245,"spec":false,"focused":true,"pending":false,"nodes":[{"name":"It","text":"focused","start":180,"end":241,"spec":true,"focused":true,"pending":false,"nodes":[{"name":"By","text":"focused","start":206,"end":219,"spec":false,"focused":true,"pending":false},{"name":"By","text":"focused","start":223,"end":236,"spec":false,"focused":true,"pending":false}]}]},{"name":"FContext","text":"focused","start":248,"end":311,"spec":false,"focused":true,"pending":false,"nodes":[{"name":"It","text":"focused","start":279,"end":307,"spec":true,"focused":true,"pending":false}]},{"name":"FWhen","text":"focused","start":314,"end":374,"spec":false,"focused":true,"pending":false,"nodes":[{"name":"It","text":"focused","start":342,"end":370,"spec":true,"focused":true,"pending":false}]},{"name":"FIt","text":"focused","start":377,"end":405,"spec":true,"focused":true,"pending":false},{"name":"FSpecify","text":"focused","start":408,"end":441,"spec":true,"focused":true,"pending":false},{"name":"FMeasure","text":"focused","start":444,"end":493,"spec":true,"focused":true,"pending":false}]}] diff --git a/ginkgo/outline/_testdata/mixed_test.go b/ginkgo/outline/_testdata/mixed_test.go new file mode 100644 index 000000000..6e91303f2 --- /dev/null +++ b/ginkgo/outline/_testdata/mixed_test.go @@ -0,0 +1,45 @@ +package example_test + +import ( + . "github.com/onsi/ginkgo" +) + +var _ = FDescribe("unfocused", func() { + FContext("unfocused", func() { + It("unfocused", func() { + + }) + FIt("focused", func() { + + }) + }) + + Context("unfocused", func() { + FIt("focused", func() { + + }) + It("unfocused", func() { + + }) + }) + + FContext("focused", func() { + It("focused", func() { + + }) + It("focused", func() { + + }) + }) + + PContext("unfocused", func() { + FIt("unfocused", func() { + By("unfocused") + By("unfocused") + }) + It("unfocused", func() { + By("unfocused") + By("unfocused") + }) + }) +}) diff --git a/ginkgo/outline/_testdata/mixed_test.go.csv b/ginkgo/outline/_testdata/mixed_test.go.csv new file mode 100644 index 000000000..819c222a1 --- /dev/null +++ b/ginkgo/outline/_testdata/mixed_test.go.csv @@ -0,0 +1,18 @@ +Name,Text,Start,End,Spec,Focused,Pending +FDescribe,unfocused,71,582,false,false,false +FContext,unfocused,104,203,false,false,false +It,unfocused,137,167,true,false,false +FIt,focused,170,199,true,true,false +Context,unfocused,206,304,false,false,false +FIt,focused,238,267,true,true,false +It,unfocused,270,300,true,false,false +FContext,focused,307,401,false,true,false +It,focused,338,366,true,true,false +It,focused,369,397,true,true,false +PContext,unfocused,404,579,false,false,true +FIt,unfocused,437,505,true,false,true +By,unfocused,466,481,false,false,true +By,unfocused,485,500,false,false,true +It,unfocused,508,575,true,false,true +By,unfocused,536,551,false,false,true +By,unfocused,555,570,false,false,true diff --git a/ginkgo/outline/_testdata/mixed_test.go.json b/ginkgo/outline/_testdata/mixed_test.go.json new file mode 100644 index 000000000..9db2e1271 --- /dev/null +++ b/ginkgo/outline/_testdata/mixed_test.go.json @@ -0,0 +1 @@ +[{"name":"FDescribe","text":"unfocused","start":71,"end":582,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"FContext","text":"unfocused","start":104,"end":203,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"unfocused","start":137,"end":167,"spec":true,"focused":false,"pending":false},{"name":"FIt","text":"focused","start":170,"end":199,"spec":true,"focused":true,"pending":false}]},{"name":"Context","text":"unfocused","start":206,"end":304,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"FIt","text":"focused","start":238,"end":267,"spec":true,"focused":true,"pending":false},{"name":"It","text":"unfocused","start":270,"end":300,"spec":true,"focused":false,"pending":false}]},{"name":"FContext","text":"focused","start":307,"end":401,"spec":false,"focused":true,"pending":false,"nodes":[{"name":"It","text":"focused","start":338,"end":366,"spec":true,"focused":true,"pending":false},{"name":"It","text":"focused","start":369,"end":397,"spec":true,"focused":true,"pending":false}]},{"name":"PContext","text":"unfocused","start":404,"end":579,"spec":false,"focused":false,"pending":true,"nodes":[{"name":"FIt","text":"unfocused","start":437,"end":505,"spec":true,"focused":false,"pending":true,"nodes":[{"name":"By","text":"unfocused","start":466,"end":481,"spec":false,"focused":false,"pending":true},{"name":"By","text":"unfocused","start":485,"end":500,"spec":false,"focused":false,"pending":true}]},{"name":"It","text":"unfocused","start":508,"end":575,"spec":true,"focused":false,"pending":true,"nodes":[{"name":"By","text":"unfocused","start":536,"end":551,"spec":false,"focused":false,"pending":true},{"name":"By","text":"unfocused","start":555,"end":570,"spec":false,"focused":false,"pending":true}]}]}]}] diff --git a/ginkgo/outline/_testdata/nestedfocused_test.go b/ginkgo/outline/_testdata/nestedfocused_test.go new file mode 100644 index 000000000..905b1c864 --- /dev/null +++ b/ginkgo/outline/_testdata/nestedfocused_test.go @@ -0,0 +1,36 @@ +package example_test + +import ( + . "github.com/onsi/ginkgo" +) + +var _ = FDescribe("unfocused", func() { + FContext("unfocused", func() { + It("unfocused", func() { + By("unfocused") + By("unfocused") + }) + FIt("focused", func() { + By("focused") + By("focused") + }) + }) + + Context("unfocused", func() { + FIt("focused", func() { + + }) + It("unfocused", func() { + + }) + }) + + FContext("focused", func() { + It("focused", func() { + + }) + It("focused", func() { + + }) + }) +}) diff --git a/ginkgo/outline/_testdata/nestedfocused_test.go.csv b/ginkgo/outline/_testdata/nestedfocused_test.go.csv new file mode 100644 index 000000000..b91cfa0dd --- /dev/null +++ b/ginkgo/outline/_testdata/nestedfocused_test.go.csv @@ -0,0 +1,15 @@ +Name,Text,Start,End,Spec,Focused,Pending +FDescribe,unfocused,71,474,false,false,false +FContext,unfocused,104,273,false,false,false +It,unfocused,137,204,true,false,false +By,unfocused,165,180,false,false,false +By,unfocused,184,199,false,false,false +FIt,focused,207,269,true,true,false +By,focused,234,247,false,true,false +By,focused,251,264,false,true,false +Context,unfocused,276,374,false,false,false +FIt,focused,308,337,true,true,false +It,unfocused,340,370,true,false,false +FContext,focused,377,471,false,true,false +It,focused,408,436,true,true,false +It,focused,439,467,true,true,false diff --git a/ginkgo/outline/_testdata/nestedfocused_test.go.json b/ginkgo/outline/_testdata/nestedfocused_test.go.json new file mode 100644 index 000000000..86e0ba4a6 --- /dev/null +++ b/ginkgo/outline/_testdata/nestedfocused_test.go.json @@ -0,0 +1 @@ +[{"name":"FDescribe","text":"unfocused","start":71,"end":474,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"FContext","text":"unfocused","start":104,"end":273,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"unfocused","start":137,"end":204,"spec":true,"focused":false,"pending":false,"nodes":[{"name":"By","text":"unfocused","start":165,"end":180,"spec":false,"focused":false,"pending":false},{"name":"By","text":"unfocused","start":184,"end":199,"spec":false,"focused":false,"pending":false}]},{"name":"FIt","text":"focused","start":207,"end":269,"spec":true,"focused":true,"pending":false,"nodes":[{"name":"By","text":"focused","start":234,"end":247,"spec":false,"focused":true,"pending":false},{"name":"By","text":"focused","start":251,"end":264,"spec":false,"focused":true,"pending":false}]}]},{"name":"Context","text":"unfocused","start":276,"end":374,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"FIt","text":"focused","start":308,"end":337,"spec":true,"focused":true,"pending":false},{"name":"It","text":"unfocused","start":340,"end":370,"spec":true,"focused":false,"pending":false}]},{"name":"FContext","text":"focused","start":377,"end":471,"spec":false,"focused":true,"pending":false,"nodes":[{"name":"It","text":"focused","start":408,"end":436,"spec":true,"focused":true,"pending":false},{"name":"It","text":"focused","start":439,"end":467,"spec":true,"focused":true,"pending":false}]}]}] diff --git a/ginkgo/outline/_testdata/nodot_test.go b/ginkgo/outline/_testdata/nodot_test.go new file mode 100644 index 000000000..13525db75 --- /dev/null +++ b/ginkgo/outline/_testdata/nodot_test.go @@ -0,0 +1,48 @@ +package example_test + +import ( + "github.com/onsi/ginkgo" +) + +var _ = ginkgo.Describe("NodotFixture", func() { + ginkgo.Describe("normal", func() { + ginkgo.It("normal", func() { + ginkgo.By("normal") + ginkgo.By("normal") + }) + }) + + ginkgo.Context("normal", func() { + ginkgo.It("normal", func() { + + }) + }) + + ginkgo.When("normal", func() { + ginkgo.It("normal", func() { + + }) + }) + + ginkgo.It("normal", func() { + + }) + + ginkgo.Specify("normal", func() { + + }) + + ginkgo.Measure("normal", func(b Benchmarker) { + + }, 2) + + ginkgo.DescribeTable("normal", + func() {}, + ginkgo.Entry("normal"), + ) + + ginkgo.DescribeTable("normal", + func() {}, + ginkgo.Entry("normal"), + ) +}) diff --git a/ginkgo/outline/_testdata/nodot_test.go.csv b/ginkgo/outline/_testdata/nodot_test.go.csv new file mode 100644 index 000000000..eecd3b9d5 --- /dev/null +++ b/ginkgo/outline/_testdata/nodot_test.go.csv @@ -0,0 +1,13 @@ +Name,Text,Start,End,Spec,Focused,Pending +Describe,NodotFixture,69,669,false,false,false +Describe,normal,111,231,false,false,false +It,normal,148,227,true,false,false +By,normal,180,199,false,false,false +By,normal,203,222,false,false,false +Context,normal,234,308,false,false,false +It,normal,270,304,true,false,false +When,normal,311,382,false,false,false +It,normal,344,378,true,false,false +It,normal,385,418,true,false,false +Specify,normal,421,459,true,false,false +Measure,normal,462,516,true,false,false diff --git a/ginkgo/outline/_testdata/nodot_test.go.json b/ginkgo/outline/_testdata/nodot_test.go.json new file mode 100644 index 000000000..d476b820c --- /dev/null +++ b/ginkgo/outline/_testdata/nodot_test.go.json @@ -0,0 +1 @@ +[{"name":"Describe","text":"NodotFixture","start":69,"end":669,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"Describe","text":"normal","start":111,"end":231,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":148,"end":227,"spec":true,"focused":false,"pending":false,"nodes":[{"name":"By","text":"normal","start":180,"end":199,"spec":false,"focused":false,"pending":false},{"name":"By","text":"normal","start":203,"end":222,"spec":false,"focused":false,"pending":false}]}]},{"name":"Context","text":"normal","start":234,"end":308,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":270,"end":304,"spec":true,"focused":false,"pending":false}]},{"name":"When","text":"normal","start":311,"end":382,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":344,"end":378,"spec":true,"focused":false,"pending":false}]},{"name":"It","text":"normal","start":385,"end":418,"spec":true,"focused":false,"pending":false},{"name":"Specify","text":"normal","start":421,"end":459,"spec":true,"focused":false,"pending":false},{"name":"Measure","text":"normal","start":462,"end":516,"spec":true,"focused":false,"pending":false}]}] diff --git a/ginkgo/outline/_testdata/normal_test.go b/ginkgo/outline/_testdata/normal_test.go new file mode 100644 index 000000000..8d8758120 --- /dev/null +++ b/ginkgo/outline/_testdata/normal_test.go @@ -0,0 +1,49 @@ +package example_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" +) + +var _ = Describe("NormalFixture", func() { + Describe("normal", func() { + It("normal", func() { + By("step 1") + By("step 2") + }) + }) + + Context("normal", func() { + It("normal", func() { + + }) + }) + + When("normal", func() { + It("normal", func() { + + }) + }) + + It("normal", func() { + + }) + + Specify("normal", func() { + + }) + + Measure("normal", func(b Benchmarker) { + + }, 2) + + DescribeTable("normal", + func() {}, + Entry("normal"), + ) + + DescribeTable("normal", + func() {}, + Entry("normal"), + ) +}) diff --git a/ginkgo/outline/_testdata/normal_test.go.csv b/ginkgo/outline/_testdata/normal_test.go.csv new file mode 100644 index 000000000..569f336cf --- /dev/null +++ b/ginkgo/outline/_testdata/normal_test.go.csv @@ -0,0 +1,13 @@ +Name,Text,Start,End,Spec,Focused,Pending +Describe,NormalFixture,116,605,false,false,false +Describe,normal,152,244,false,false,false +It,normal,182,240,true,false,false +By,step 1,207,219,false,false,false +By,step 2,223,235,false,false,false +Context,normal,247,307,false,false,false +It,normal,276,303,true,false,false +When,normal,310,367,false,false,false +It,normal,336,363,true,false,false +It,normal,370,396,true,false,false +Specify,normal,399,430,true,false,false +Measure,normal,433,480,true,false,false diff --git a/ginkgo/outline/_testdata/normal_test.go.json b/ginkgo/outline/_testdata/normal_test.go.json new file mode 100644 index 000000000..43b97a2b9 --- /dev/null +++ b/ginkgo/outline/_testdata/normal_test.go.json @@ -0,0 +1 @@ +[{"name":"Describe","text":"NormalFixture","start":116,"end":605,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"Describe","text":"normal","start":152,"end":244,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":182,"end":240,"spec":true,"focused":false,"pending":false,"nodes":[{"name":"By","text":"step 1","start":207,"end":219,"spec":false,"focused":false,"pending":false},{"name":"By","text":"step 2","start":223,"end":235,"spec":false,"focused":false,"pending":false}]}]},{"name":"Context","text":"normal","start":247,"end":307,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":276,"end":303,"spec":true,"focused":false,"pending":false}]},{"name":"When","text":"normal","start":310,"end":367,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"It","text":"normal","start":336,"end":363,"spec":true,"focused":false,"pending":false}]},{"name":"It","text":"normal","start":370,"end":396,"spec":true,"focused":false,"pending":false},{"name":"Specify","text":"normal","start":399,"end":430,"spec":true,"focused":false,"pending":false},{"name":"Measure","text":"normal","start":433,"end":480,"spec":true,"focused":false,"pending":false}]}] diff --git a/ginkgo/outline/_testdata/pending_test.go b/ginkgo/outline/_testdata/pending_test.go new file mode 100644 index 000000000..b4dd53ee2 --- /dev/null +++ b/ginkgo/outline/_testdata/pending_test.go @@ -0,0 +1,49 @@ +package example_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" +) + +var _ = Describe("PendingFixture", func() { + PDescribe("pending", func() { + It("pending", func() { + By("pending") + By("pending") + }) + }) + + PContext("pending", func() { + It("pending", func() { + + }) + }) + + PWhen("pending", func() { + It("pending", func() { + + }) + }) + + PIt("pending", func() { + + }) + + PSpecify("pending", func() { + + }) + + PMeasure("pending", func(b Benchmarker) { + + }, 2) + + PDescribeTable("pending", + func() {}, + Entry("pending"), + ) + + DescribeTable("pending", + func() {}, + PEntry("pending"), + ) +}) diff --git a/ginkgo/outline/_testdata/pending_test.go.csv b/ginkgo/outline/_testdata/pending_test.go.csv new file mode 100644 index 000000000..831c8d9da --- /dev/null +++ b/ginkgo/outline/_testdata/pending_test.go.csv @@ -0,0 +1,13 @@ +Name,Text,Start,End,Spec,Focused,Pending +Describe,PendingFixture,116,629,false,false,false +PDescribe,pending,153,250,false,false,true +It,pending,185,246,true,false,true +By,pending,211,224,false,false,true +By,pending,228,241,false,false,true +PContext,pending,253,316,false,false,true +It,pending,284,312,true,false,true +PWhen,pending,319,379,false,false,true +It,pending,347,375,true,false,true +PIt,pending,382,410,true,false,true +PSpecify,pending,413,446,true,false,true +PMeasure,pending,449,498,true,false,true diff --git a/ginkgo/outline/_testdata/pending_test.go.json b/ginkgo/outline/_testdata/pending_test.go.json new file mode 100644 index 000000000..0014d4a2c --- /dev/null +++ b/ginkgo/outline/_testdata/pending_test.go.json @@ -0,0 +1 @@ +[{"name":"Describe","text":"PendingFixture","start":116,"end":629,"spec":false,"focused":false,"pending":false,"nodes":[{"name":"PDescribe","text":"pending","start":153,"end":250,"spec":false,"focused":false,"pending":true,"nodes":[{"name":"It","text":"pending","start":185,"end":246,"spec":true,"focused":false,"pending":true,"nodes":[{"name":"By","text":"pending","start":211,"end":224,"spec":false,"focused":false,"pending":true},{"name":"By","text":"pending","start":228,"end":241,"spec":false,"focused":false,"pending":true}]}]},{"name":"PContext","text":"pending","start":253,"end":316,"spec":false,"focused":false,"pending":true,"nodes":[{"name":"It","text":"pending","start":284,"end":312,"spec":true,"focused":false,"pending":true}]},{"name":"PWhen","text":"pending","start":319,"end":379,"spec":false,"focused":false,"pending":true,"nodes":[{"name":"It","text":"pending","start":347,"end":375,"spec":true,"focused":false,"pending":true}]},{"name":"PIt","text":"pending","start":382,"end":410,"spec":true,"focused":false,"pending":true},{"name":"PSpecify","text":"pending","start":413,"end":446,"spec":true,"focused":false,"pending":true},{"name":"PMeasure","text":"pending","start":449,"end":498,"spec":true,"focused":false,"pending":true}]}] diff --git a/ginkgo/outline/_testdata/suite_test.go b/ginkgo/outline/_testdata/suite_test.go new file mode 100644 index 000000000..e28786a5a --- /dev/null +++ b/ginkgo/outline/_testdata/suite_test.go @@ -0,0 +1,13 @@ +package example_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestExample(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Example Suite") +} diff --git a/ginkgo/outline/_testdata/suite_test.go.csv b/ginkgo/outline/_testdata/suite_test.go.csv new file mode 100644 index 000000000..c85a82705 --- /dev/null +++ b/ginkgo/outline/_testdata/suite_test.go.csv @@ -0,0 +1 @@ +Name,Text,Start,End,Spec,Focused,Pending diff --git a/ginkgo/outline/_testdata/suite_test.go.json b/ginkgo/outline/_testdata/suite_test.go.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/ginkgo/outline/_testdata/suite_test.go.json @@ -0,0 +1 @@ +[] diff --git a/ginkgo/outline/ginkgo.go b/ginkgo/outline/ginkgo.go new file mode 100644 index 000000000..2256a2cca --- /dev/null +++ b/ginkgo/outline/ginkgo.go @@ -0,0 +1,209 @@ +package outline + +import ( + "go/ast" + "go/token" + "strconv" +) + +const ( + // undefinedTextAlt is used if the spec/container text cannot be derived + undefinedTextAlt = "undefined" +) + +// ginkgoMetadata holds useful bits of information for every entry in the outline +type ginkgoMetadata struct { + // Name is the spec or container function name, e.g. `Describe` or `It` + Name string `json:"name"` + + // Text is the `text` argument passed to specs, and some containers + Text string `json:"text"` + + // Start is the position of first character of the spec or container block + Start token.Pos `json:"start"` + + // End is the position of first character immediately after the spec or container block + End token.Pos `json:"end"` + + Spec bool `json:"spec"` + Focused bool `json:"focused"` + Pending bool `json:"pending"` +} + +// ginkgoNode is used to construct the outline as a tree +type ginkgoNode struct { + ginkgoMetadata + Nodes []*ginkgoNode `json:"nodes,omitempty"` +} + +type walkFunc func(n *ginkgoNode) + +func (n *ginkgoNode) PreOrder(f walkFunc) { + f(n) + for _, m := range n.Nodes { + m.PreOrder(f) + } +} + +func (n *ginkgoNode) PostOrder(f walkFunc) { + for _, m := range n.Nodes { + m.PostOrder(f) + } + f(n) +} + +func (n *ginkgoNode) Walk(pre, post walkFunc) { + pre(n) + for _, m := range n.Nodes { + m.Walk(pre, post) + } + post(n) +} + +// PropagateInheritedProperties propagates the Pending and Focused properties +// through the subtree rooted at n. +func (n *ginkgoNode) PropagateInheritedProperties() { + n.PreOrder(func(thisNode *ginkgoNode) { + for _, descendantNode := range thisNode.Nodes { + if thisNode.Pending { + descendantNode.Pending = true + descendantNode.Focused = false + } + if thisNode.Focused && !descendantNode.Pending { + descendantNode.Focused = true + } + } + }) +} + +// BackpropagateUnfocus propagates the Focused property through the subtree +// rooted at n. It applies the rule described in the Ginkgo docs: +// > Nested programmatically focused specs follow a simple rule: if a +// > leaf-node is marked focused, any of its ancestor nodes that are marked +// > focus will be unfocused. +func (n *ginkgoNode) BackpropagateUnfocus() { + focusedSpecInSubtreeStack := []bool{} + n.PostOrder(func(thisNode *ginkgoNode) { + if thisNode.Spec { + focusedSpecInSubtreeStack = append(focusedSpecInSubtreeStack, thisNode.Focused) + return + } + focusedSpecInSubtree := false + for range thisNode.Nodes { + focusedSpecInSubtree = focusedSpecInSubtree || focusedSpecInSubtreeStack[len(focusedSpecInSubtreeStack)-1] + focusedSpecInSubtreeStack = focusedSpecInSubtreeStack[0 : len(focusedSpecInSubtreeStack)-1] + } + focusedSpecInSubtreeStack = append(focusedSpecInSubtreeStack, focusedSpecInSubtree) + if focusedSpecInSubtree { + thisNode.Focused = false + } + }) + +} + +func ginkgoIdentNameFromCallExpr(ce *ast.CallExpr, ginkgoImportName string) (string, bool) { + switch ex := ce.Fun.(type) { + case *ast.Ident: + if ginkgoImportName != "." { + return "", false + } + return ex.Name, true + case *ast.SelectorExpr: + pkgID, ok := ex.X.(*ast.Ident) + if !ok { + return "", false + } + // A package identifier is top-level, so Obj must be nil + if pkgID.Obj != nil { + return "", false + } + if ginkgoImportName != pkgID.Name { + return "", false + } + if ex.Sel == nil { + return "", false + } + return ex.Sel.Name, true + default: + return "", false + } +} + +// ginkgoNodeFromCallExpr derives an outline entry from a go AST subtree +// corresponding to a Ginkgo container or spec. +func ginkgoNodeFromCallExpr(ce *ast.CallExpr, ginkgoImportName string) (*ginkgoNode, bool) { + identName, ok := ginkgoIdentNameFromCallExpr(ce, ginkgoImportName) + if !ok { + return nil, false + } + + n := ginkgoNode{} + n.Name = identName + n.Start = ce.Pos() + n.End = ce.End() + + switch identName { + case "It", "Measure", "Specify": + n.Spec = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "FIt", "FMeasure", "FSpecify": + n.Spec = true + n.Focused = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "PIt", "PMeasure", "PSpecify", "XIt", "XMeasure", "XSpecify": + n.Spec = true + n.Pending = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "Context", "Describe", "When": + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "FContext", "FDescribe", "FWhen": + n.Focused = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "PContext", "PDescribe", "PWhen", "XContext", "XDescribe", "XWhen": + n.Pending = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "By": + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + case "AfterEach", "BeforeEach": + case "JustAfterEach", "JustBeforeEach": + case "AfterSuite", "BeforeSuite": + case "SynchronizedAfterSuite", "SynchronizedBeforeSuite": + default: + return nil, false + } + return &n, true +} + +// textOrAltFromCallExpr tries to derive the "text" of a Ginkgo spec or +// container. If it cannot derive it, it returns the alt text. +func textOrAltFromCallExpr(ce *ast.CallExpr, alt string) string { + text, defined := textFromCallExpr(ce) + if !defined { + return alt + } + return text +} + +// textFromCallExpr tries to derive the "text" of a Ginkgo spec or container. If +// it cannot derive it, it returns false. +func textFromCallExpr(ce *ast.CallExpr) (string, bool) { + if len(ce.Args) < 1 { + return "", false + } + text, ok := ce.Args[0].(*ast.BasicLit) + if !ok { + return "", false + } + switch text.Kind { + case token.CHAR, token.STRING: + // For token.CHAR and token.STRING, Value is quoted + unquoted, err := strconv.Unquote(text.Value) + if err != nil { + // If unquoting fails, just use the raw Value + return text.Value, true + } + return unquoted, true + default: + return text.Value, true + } +} diff --git a/ginkgo/outline/import.go b/ginkgo/outline/import.go new file mode 100644 index 000000000..9b869cf46 --- /dev/null +++ b/ginkgo/outline/import.go @@ -0,0 +1,61 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Most of the required functions were available in the +// "golang.org/x/tools/go/ast/astutil" package, but not exported. +// They were copied from https://github.com/golang/tools/blob/2b0845dc783e36ae26d683f4915a5840ef01ab0f/go/ast/astutil/imports.go + +package outline + +import ( + "go/ast" + "strconv" + "strings" +) + +// importNameForPackage returns the import name for the package. If the package +// is not imported, it returns false. Examples: +// How package is imported -> Import Name +// "import example.com/pkg/foo" -> "foo" +// "import fooalias example.com/pkg/foo" -> "fooalias" +// "import . example.com/pkg/foo" -> "." +func importNameForPackage(f *ast.File, path string) (string, bool) { + spec := importSpec(f, path) + if spec == nil { + return "", false + } + name := spec.Name.String() + if name == "" { + // If the package name is not explicitly specified, + // make an educated guess. This is not guaranteed to be correct. + lastSlash := strings.LastIndex(path, "/") + if lastSlash == -1 { + name = path + } else { + name = path[lastSlash+1:] + } + } + return name, true +} + +// importSpec returns the import spec if f imports path, +// or nil otherwise. +func importSpec(f *ast.File, path string) *ast.ImportSpec { + for _, s := range f.Imports { + if importPath(s) == path { + return s + } + } + return nil +} + +// importPath returns the unquoted import path of s, +// or "" if the path is not properly quoted. +func importPath(s *ast.ImportSpec) string { + t, err := strconv.Unquote(s.Path.Value) + if err != nil { + return "" + } + return t +} diff --git a/ginkgo/outline/outline.go b/ginkgo/outline/outline.go new file mode 100644 index 000000000..200afd39e --- /dev/null +++ b/ginkgo/outline/outline.go @@ -0,0 +1,102 @@ +package outline + +import ( + "encoding/json" + "fmt" + "go/ast" + "strings" + + "golang.org/x/tools/go/ast/inspector" +) + +const ( + // ginkgoImportPath is the well-known ginkgo import path + ginkgoImportPath = "github.com/onsi/ginkgo" +) + +// FromASTFile returns an outline for a Ginkgo test source file +func FromASTFile(src *ast.File) (*outline, error) { + ginkgoImportName, ok := importNameForPackage(src, ginkgoImportPath) + if !ok { + return nil, fmt.Errorf("file does not import %s", ginkgoImportPath) + } + root := ginkgoNode{ + Nodes: []*ginkgoNode{}, + } + stack := []*ginkgoNode{&root} + + ispr := inspector.New([]*ast.File{src}) + ispr.Nodes([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node, push bool) bool { + if push { + // Pre-order traversal + ce, ok := node.(*ast.CallExpr) + if !ok { + // Because `Nodes` calls this function only when the node is an + // ast.CallExpr, this should never happen + panic(fmt.Errorf("node starting at %d, ending at %d is not an *ast.CallExpr", node.Pos(), node.End())) + } + gn, ok := ginkgoNodeFromCallExpr(ce, ginkgoImportName) + if !ok { + // Node is not a Ginkgo spec or container, continue + return true + } + + parent := stack[len(stack)-1] + parent.Nodes = append(parent.Nodes, gn) + + stack = append(stack, gn) + return true + } + // Post-order traversal + lastVisitedGinkgoNode := stack[len(stack)-1] + if node.Pos() != lastVisitedGinkgoNode.Start || node.End() != lastVisitedGinkgoNode.End { + // Node is not a Ginkgo spec or container, so it was not pushed onto the stack, continue + return true + } + stack = stack[0 : len(stack)-1] + return true + }) + + // Derive the final focused property for all nodes. This must be done + // _before_ propagating the inherited focused property. + root.BackpropagateUnfocus() + // Now, propagate inherited properties, including focused and pending. + root.PropagateInheritedProperties() + + return &outline{root}, nil +} + +type outline struct { + ginkgoNode +} + +func (o *outline) MarshalJSON() ([]byte, error) { + return json.Marshal(o.Nodes) +} + +// String returns a CSV-formatted outline. Spec or container are output in +// depth-first order. +func (o *outline) String() string { + return o.StringIndent(0) +} + +// StringIndent returns a CSV-formated outline, but every line is indented by +// one 'width' of spaces for every level of nesting. +func (o *outline) StringIndent(width int) string { + var b strings.Builder + b.WriteString("Name,Text,Start,End,Spec,Focused,Pending\n") + + currentIndent := 0 + pre := func(n *ginkgoNode) { + b.WriteString(fmt.Sprintf("%*s", currentIndent, "")) + b.WriteString(fmt.Sprintf("%s,%s,%d,%d,%t,%t,%t\n", n.Name, n.Text, n.Start, n.End, n.Spec, n.Focused, n.Pending)) + currentIndent += width + } + post := func(n *ginkgoNode) { + currentIndent -= width + } + for _, n := range o.Nodes { + n.Walk(pre, post) + } + return b.String() +} diff --git a/ginkgo/outline/outline_suite_test.go b/ginkgo/outline/outline_suite_test.go new file mode 100644 index 000000000..4cceae9f6 --- /dev/null +++ b/ginkgo/outline/outline_suite_test.go @@ -0,0 +1,13 @@ +package outline_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestOutline(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Outline Suite") +} diff --git a/ginkgo/outline/outline_test.go b/ginkgo/outline/outline_test.go new file mode 100644 index 000000000..b5746c81c --- /dev/null +++ b/ginkgo/outline/outline_test.go @@ -0,0 +1,59 @@ +package outline + +import ( + "encoding/json" + "go/parser" + "go/token" + "io/ioutil" + "log" + "path/filepath" + + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +var _ = DescribeTable("Validate outline from file with", + func(srcFilename, jsonOutlineFilename, csvOutlineFilename string) { + fset := token.NewFileSet() + astFile, err := parser.ParseFile(fset, filepath.Join("_testdata", srcFilename), nil, 0) + Expect(err).To(BeNil(), "error parsing source: %s", err) + + if err != nil { + log.Fatalf("error parsing source: %s", err) + } + + o, err := FromASTFile(astFile) + Expect(err).To(BeNil(), "error creating outline: %s", err) + + gotJSON, err := json.MarshalIndent(o, "", " ") + Expect(err).To(BeNil(), "error marshalling outline to json: %s", err) + + wantJSON, err := ioutil.ReadFile(filepath.Join("_testdata", jsonOutlineFilename)) + Expect(err).To(BeNil(), "error reading JSON outline fixture: %s", err) + + Expect(gotJSON).To(MatchJSON(wantJSON)) + + gotCSV := o.String() + + wantCSV, err := ioutil.ReadFile(filepath.Join("_testdata", csvOutlineFilename)) + Expect(err).To(BeNil(), "error reading CSV outline fixture: %s", err) + + Expect(gotCSV).To(Equal(string(wantCSV))) + }, + // To add a test: + // 1. Create the input, e.g., `myspecialcase_test.go` + // 2. Create the sample CSV and JSON results: Run `bash ./_testdata/create_result.sh ./_testdata/myspecialcase_test.go` + // 3. Add an Entry below, by copying an existing one, and substituting `myspecialcase` where needed. + // To re-create the sample results for a test: + // 1. Run `bash ./_testdata/create_result.sh ./testdata/myspecialcase_test.go` + // To re-create the sample results for all tests: + // 1. Run `for name in ./_testdata/*_test.go; do bash ./_testdata/create_result.sh $name; done` + Entry("normal import of ginkgo package (no dot, no alias), normal container and specs", "nodot_test.go", "nodot_test.go.json", "nodot_test.go.csv"), + Entry("aliased import of ginkgo package, normal container and specs", "alias_test.go", "alias_test.go.json", "alias_test.go.csv"), + Entry("normal containers and specs", "normal_test.go", "normal_test.go.json", "normal_test.go.csv"), + Entry("focused containers and specs", "focused_test.go", "focused_test.go.json", "focused_test.go.csv"), + Entry("pending containers and specs", "pending_test.go", "pending_test.go.json", "pending_test.go.csv"), + Entry("nested focused containers and specs", "nestedfocused_test.go", "nestedfocused_test.go.json", "nestedfocused_test.go.csv"), + Entry("mixed focused containers and specs", "mixed_test.go", "mixed_test.go.json", "mixed_test.go.csv"), + Entry("suite setup", "suite_test.go", "suite_test.go.json", "suite_test.go.csv"), +) diff --git a/ginkgo/outline_command.go b/ginkgo/outline_command.go new file mode 100644 index 000000000..6b57bb095 --- /dev/null +++ b/ginkgo/outline_command.go @@ -0,0 +1,77 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "go/parser" + "go/token" + "os" + + "github.com/onsi/ginkgo/ginkgo/outline" +) + +const ( + // indentWidth is the width used by the 'indent' output + indentWidth = 4 +) + +func BuildOutlineCommand() *Command { + const defaultFormat = "csv" + var format string + flagSet := flag.NewFlagSet("outline", flag.ExitOnError) + flagSet.StringVar(&format, "format", defaultFormat, "Format of outline. Accepted: 'csv', 'indent', 'json'") + return &Command{ + Name: "outline", + FlagSet: flagSet, + UsageCommand: "ginkgo outline ", + Usage: []string{ + "Outline of Ginkgo symbols for the file", + }, + Command: func(args []string, additionalArgs []string) { + outlineFile(args, format) + }, + } +} + +func outlineFile(args []string, format string) { + if len(args) != 1 { + println("usage: ginkgo outline ") + os.Exit(1) + } + + filename := args[0] + fset := token.NewFileSet() + + src, err := parser.ParseFile(fset, filename, nil, 0) + if err != nil { + println(fmt.Sprintf("error parsing source: %s", err)) + os.Exit(1) + } + + o, err := outline.FromASTFile(src) + if err != nil { + println(fmt.Sprintf("error creating outline: %s", err)) + os.Exit(1) + } + + var oerr error + switch format { + case "csv": + _, oerr = fmt.Print(o) + case "indent": + _, oerr = fmt.Print(o.StringIndent(indentWidth)) + case "json": + b, err := json.Marshal(o) + if err != nil { + println(fmt.Sprintf("error marshalling to json: %s", err)) + } + _, oerr = fmt.Println(string(b)) + default: + complainAndQuit(fmt.Sprintf("format %s not accepted", format)) + } + if oerr != nil { + println(fmt.Sprintf("error writing outline: %s", oerr)) + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index 1f7125228..f6a09193a 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/nxadm/tail v1.4.4 github.com/onsi/gomega v1.10.1 - golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 - golang.org/x/text v0.3.2 // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f + golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e ) go 1.13 diff --git a/go.sum b/go.sum index e14753507..56b1f9db1 100644 --- a/go.sum +++ b/go.sum @@ -21,25 +21,41 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=