├── .gitattributes ├── .gitignore ├── .travis.yml ├── ChangeLog ├── LICENSE.txt ├── Makefile ├── README.md ├── _data ├── README.md ├── in │ ├── gocheck-empty.out │ ├── gocheck-fail.out │ ├── gocheck-nofiles.out │ ├── gocheck-panic.out │ ├── gocheck-pass.out │ ├── gocheck-setup-miss.out │ ├── gotest-0.out │ ├── gotest-1.5.out │ ├── gotest-1.6.out │ ├── gotest-1.7.out │ ├── gotest-buildfailed.out │ ├── gotest-datarace.out │ ├── gotest-empty.out │ ├── gotest-escaped.out │ ├── gotest-fail.out │ ├── gotest-fatal-nosummary.out │ ├── gotest-last-suite.out │ ├── gotest-log.out │ ├── gotest-multi.out │ ├── gotest-multierror.out │ ├── gotest-negative-duration.out │ ├── gotest-nofiles.out │ ├── gotest-nosummary.out │ ├── gotest-num.out │ ├── gotest-panic.out │ ├── gotest-pass.out │ ├── gotest-print.out │ ├── gotest-simple-and-suite-tests.out │ ├── gotest-testify-suite.out │ └── gotest.out ├── nosetests.xml ├── out │ ├── xunit.net │ │ ├── gocheck-empty.out.xml │ │ ├── gocheck-fail.out.xml │ │ ├── gocheck-nofiles.out.xml │ │ ├── gocheck-panic.out.xml │ │ ├── gocheck-pass.out.xml │ │ ├── gocheck-setup-miss.out.xml │ │ ├── gotest-0.out.xml │ │ ├── gotest-1.5.out.xml │ │ ├── gotest-1.6.out.xml │ │ ├── gotest-1.7.out.xml │ │ ├── gotest-buildfailed.out.xml │ │ ├── gotest-datarace.out.xml │ │ ├── gotest-empty.out.xml │ │ ├── gotest-escaped.out.xml │ │ ├── gotest-fail.out.xml │ │ ├── gotest-fatal-nosummary.out.xml │ │ ├── gotest-last-suite.out.xml │ │ ├── gotest-log.out.xml │ │ ├── gotest-multi.out.xml │ │ ├── gotest-multierror.out.xml │ │ ├── gotest-negative-duration.out.xml │ │ ├── gotest-nofiles.out.xml │ │ ├── gotest-nosummary.out.xml │ │ ├── gotest-num.out.xml │ │ ├── gotest-panic.out.xml │ │ ├── gotest-pass.out.xml │ │ ├── gotest-print.out.xml │ │ ├── gotest-simple-and-suite-tests.out.xml │ │ ├── gotest-testify-suite.out.xml │ │ └── gotest.out.xml │ └── xunit │ │ ├── gocheck-empty.out.xml │ │ ├── gocheck-fail.out.xml │ │ ├── gocheck-nofiles.out.xml │ │ ├── gocheck-panic.out.xml │ │ ├── gocheck-pass.out.xml │ │ ├── gocheck-setup-miss.out.xml │ │ ├── gotest-0.out.xml │ │ ├── gotest-1.5.out.xml │ │ ├── gotest-1.6.out.xml │ │ ├── gotest-1.7.out.xml │ │ ├── gotest-buildfailed.out.xml │ │ ├── gotest-datarace.out.xml │ │ ├── gotest-empty.out.xml │ │ ├── gotest-escaped.out.xml │ │ ├── gotest-fail.out.xml │ │ ├── gotest-fatal-nosummary.out.xml │ │ ├── gotest-last-suite.out.xml │ │ ├── gotest-log.out.xml │ │ ├── gotest-multi.out.xml │ │ ├── gotest-multierror.out.xml │ │ ├── gotest-negative-duration.out.xml │ │ ├── gotest-nofiles.out.xml │ │ ├── gotest-nosummary.out.xml │ │ ├── gotest-num.out.xml │ │ ├── gotest-panic.out.xml │ │ ├── gotest-pass.out.xml │ │ ├── gotest-print.out.xml │ │ ├── gotest-simple-and-suite-tests.out.xml │ │ ├── gotest-testify-suite.out.xml │ │ └── gotest.out.xml ├── run-tests.sh └── test_xunit.py ├── _demos ├── gocheck │ ├── README.md │ ├── jenkins.sh │ ├── mmath.go │ ├── mmath_test.go │ └── run-jenkins.sh ├── gotest │ ├── README.md │ ├── gotest-1.6.out │ ├── jenkins.sh │ ├── mmath.go │ ├── mmath_test.go │ ├── run-jenkins.sh │ └── screenshots │ │ ├── build-overrview.png │ │ ├── build-tests.png │ │ └── config.png └── testify │ ├── README.md │ ├── jenkins.sh │ ├── mmath.go │ ├── mmath_test.go │ └── screenshots │ ├── build-overrview.png │ ├── build-tests.png │ └── config.png ├── cmdline.go ├── gen-out.sh ├── go.mod ├── lib ├── lex.go ├── lex_test.go ├── lib_test.go ├── options.go ├── parsers.go ├── parsers2.go ├── types.go ├── types_test.go └── xmlout.go ├── main.go └── regression_test.go /.gitattributes: -------------------------------------------------------------------------------- 1 | # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html 2 | 3 | *.out eol=lf 4 | *.xml eol=lf 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | go2xunit 2 | go2xunit-*amd64* 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.11 5 | - tip 6 | script: make test 7 | after_success: make binaries 8 | deploy: 9 | provider: releases 10 | skip_cleanup: true 11 | api_key: 12 | secure: Ozy4WioriKnHz2ZC4isU/JqujtFlNkc9AOB92N7wLCuYll1mBW5o6bjYEZTvPq6FAVWlrhBHfKI8oTpVEZNZaL6LyvIeCFioTlDPE4OjihCGs9B8pwrxnY7sSt6WQQ/hCmm4fGoliDlQ7gv2bHrm54PUZOrMydXyHBOsYhS9/Lc= 13 | file: 14 | - go2xunit-linux-amd64 15 | - go2xunit-darwin-amd64 16 | - go2xunit-windows-amd64.exe 17 | on: 18 | repo: tebeka/go2xunit 19 | branch: master 20 | tags: true 21 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2018-12-17 version 1.4.10 2 | * Fix suite regular expression to support "(cached)" 3 | 4 | 2018-12-13 version 1.4.9 5 | * Handle dangling suite (issue #63) 6 | 7 | 2018-02-01 version 1.4.8 8 | * Fix appending of output and errors (@teodorst in PR #57) 9 | 10 | 2017-09-24 version 1.4.6 11 | * Use 0 instead of N/A for missing time (issue #54) 12 | 13 | 2017-09-24 version 1.4.5 14 | * Support long lines (@jaytaylor in PR #51 & #52) 15 | 16 | 2017-03-21 version 1.4.4 17 | * Escape user-provided strings in XML output (@xperimental in PR #47) 18 | 19 | 2016-11-23 version 1.4.3 20 | * Experimental gotest lexer 21 | 22 | 2016-11-23 version 1.4.2 23 | * Fix bug when tests ends with fatal (@tamird in PR #42) 24 | 25 | 2016-11-22 version 1.4.1 26 | * Allow negative times (@jordanlewis in PR #43) 27 | 28 | 2016-10-16 version 1.4.0 29 | * Code reorg (@amibiz in PR #36) 30 | * Expose library (issue #39) 31 | 32 | 2016-09-15 version 1.3.1 33 | * Support runners that don't print a per-suite summary (@benley in PR #34) 34 | 35 | 2016-08-21 version 1.3.0 36 | * Support go 1.7 subtests (@aprice in github PR #28) 37 | 38 | 2016-02-17 version 1.2.4 39 | * Support prints in output (@davars in PR #7) 40 | 41 | 2015-12-29 version 1.2.3 42 | * Split to files and some cleanup 43 | 44 | 2015-07-18 version 1.2.2 45 | * Support go 1.5 test output (github issue #23) 46 | 47 | 2015-06-25 version 1.2.1 48 | * Ignore SetUpTest and TearDownTest (@pippio in github PR #22) 49 | 50 | 2015-06-16 version 1.2.0 51 | * Support xunit.net (@tischda in github PR #21) 52 | * More testing (@tischda in github PR #21) 53 | 54 | 2014-12-16 version 1.1.1 55 | * Better error message (github issue #19) 56 | 57 | 2014-08-21 version 1.1.0 58 | * Support for testify (Joakim Lundborg PR #6) 59 | 60 | 2014-08-21 version 1.0.0 61 | * Bumping to 1.0.0, it's been long enough :) 62 | 63 | 2014-08-14 version 0.3.1 64 | * Fixed two small errors found by "go vet" 65 | 66 | 2014-06-04 version 0.3.0 67 | * Option to fail on data races (Jiri Sima in bitbucket PR #5) 68 | 69 | 2014-06-04 version 0.2.12 70 | * Handle 0 time tests (github issue #16) 71 | 72 | 2014-05-13 version 0.2.11 73 | * Add skipped to XML output (John Khvatov, github pull #15) 74 | 75 | 2014-04-22 version 0.2.10 76 | * Handle empty directories and panic in tests (Jiri Sima PR #4) 77 | 78 | 2014-02-19 version 0.2.9 79 | * More permissive test names (github #13) 80 | 81 | 2014-02-19 version 0.2.8 82 | * Fixed running examples (Luke Curley, github #11) 83 | 84 | 2014-02-19 version 0.2.7 85 | * Handle build failures (John Khvatov, github pull #9) 86 | 87 | 2014-01-17 version 0.2.6 88 | * Handle error in last test (Daniel Speed, github pull #4) 89 | 90 | 2013-10-21 version 0.2.5 91 | * Handle SKIP (Yukinari Toyota) 92 | 93 | 2013-10-21 version 0.2.4 94 | * Handle passing suites (cee-dub in github pull #3) 95 | 96 | 2013-09-27 version 0.2.3 97 | * Handle [no test files] (issue #4) 98 | 99 | 2013-09-17 version 0.2.2 100 | * Add "testsuites" when multiple (issue #3) 101 | 102 | 2013-09-14 version 0.2.1 103 | * More code cleanup 104 | 105 | 2013-09-14 version 0.2.0 106 | * gocheck support 107 | * Some cleanup 108 | 109 | 2013-07-29 version 0.1.3 110 | * suites added (using package name as suite name) 111 | 112 | 2013-06-18 version 0.1.2 113 | * testcases node added for bamboo compatibility, some dummy change. 114 | * xml generation now use template engine 115 | 116 | 2012-07-23 version 0.1.1 117 | * Fix edge case with FAIL (thanks Thomas Pelletier) 118 | 119 | 2012-04-06 version 0.1.0 120 | * Initial release 121 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Miki Tebeka . 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: lint test 2 | 3 | test: 4 | go test -v ./... 5 | 6 | lint: 7 | golint -set_exit_status ./... 8 | 9 | publish: 10 | git tag v$(shell perl -ne 'print "$$1\n" if /Version = "(.*)"/' main.go) 11 | git push 12 | git push --tags 13 | 14 | binaries: 15 | GOARCH=amd64 GOOS=linux go build -o go2xunit-linux-amd64 16 | GOARCH=amd64 GOOS=darwin go build -o go2xunit-darwin-amd64 17 | GOARCH=amd64 GOOS=windows go build -o go2xunit-windows-amd64.exe 18 | 19 | .PHONY: test lib 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go2xunit 2 | 3 | [![Travis](https://travis-ci.org/tebeka/go2xunit.svg?branch=master)](https://travis-ci.org/tebeka/go2xunit) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 5 | 6 | **DORMANT: This package is currently unmaintained. I (Miki) might invest some time on it in the future - but currently I don't plan to.** 7 | Have a look at [go-gunit-report](https://github.com/jstemmer/go-junit-report) for a possible replacement. 8 | 9 | Converts `go test -v` (or `gocheck -vv`) output to xunit or [xunit.net][xnet] 10 | compatible XML output (used in [Jenkins][jenkins]/[Hudson][hudson]). 11 | 12 | Currently in Jenkins please pick `Publish JUnit test result report` (not 13 | `XUnit`). We're working to make the results compatible with XUnit. 14 | 15 | 16 | # Install 17 | 18 | go get github.com/tebeka/go2xunit 19 | 20 | 21 | # Usage 22 | By default `go2xunit` reads data from standard input and emits XML to standard 23 | output. However you can use `-input` and `-output` flags to change this. 24 | 25 | The `-fail` switch will cause `go2xunit` to exit with non zero status if there 26 | are failed tests. 27 | 28 | 2>&1 go test -v | go2xunit -output tests.xml 29 | 30 | `go2xunit` also works with [gocheck][gocheck], and [testify][testify]. 31 | 32 | 2>&1 go test -gocheck.vv | go2xunit -gocheck -output tests.xml 33 | 34 | Here's an example script (`run-tests.sh`) that can be used with [Jenkins][jenkins]/[Hudson][hudson]. 35 | 36 | #!/bin/bash 37 | 38 | outfile=gotest.out 39 | 40 | 2>&1 go test -v | tee $outfile 41 | go2xunit -fail -input $outfile -output tests.xml 42 | 43 | 44 | # Examples 45 | 46 | * [go test](_demos/gotest/) 47 | * [gocheck](_demos/gocheck/) 48 | * [testify](_demos/testify/) 49 | 50 | 51 | # Related 52 | 53 | * [testing: add -json flag for json 54 | results](https://github.com/golang/go/issues/2981) open bug 55 | 56 | # Contact 57 | Miki Tebeka 58 | 59 | Bug reports go [here][bugs]. 60 | 61 | 62 | [jenkins]: http://jenkins-ci.org/ 63 | [hudson]: http://hudson-ci.org/ 64 | [gocheck]: http://labix.org/gocheck 65 | [testify]: http://godoc.org/github.com/stretchr/testify 66 | [bugs]: https://github.com/tebeka/go2xunit/issues 67 | [xnet]: https://xunit.codeplex.com/wikipage?title=XmlFormat 68 | -------------------------------------------------------------------------------- /_data/README.md: -------------------------------------------------------------------------------- 1 | # Regression Test Files 2 | 3 | The file name should be in the following convention: 4 | 5 | -.out 6 | 7 | Where `kind` is either `gotest` or `gocheck`. 8 | Example: `gocheck-nofiles.out` 9 | 10 | If the there are errors in the output (failed tests ...) add `-fail` suffix to 11 | the file name. 12 | Example: `gotest-fail.out` 13 | 14 | Each of these files should have corresponding XMLs in `xml/xunit` and `xml/xunit.net/` which has the same file name with `.xml` suffix. 15 | Example: `xml/xunit/gotest-fail.out.xml` 16 | -------------------------------------------------------------------------------- /_data/in/gocheck-empty.out: -------------------------------------------------------------------------------- 1 | PASS 2 | ok github.com/tischda/mmath 0.039s 3 | -------------------------------------------------------------------------------- /_data/in/gocheck-fail.out: -------------------------------------------------------------------------------- 1 | START: mmath_test.go:16: MySuite1.TestAdd 2 | PASS: mmath_test.go:16: MySuite1.TestAdd 0.000s 3 | 4 | START: mmath_test.go:35: MySuite.TestDiv 5 | mmath_test.go:38: 6 | c.Assert(z, Equals, float64(x)/float64(y)) 7 | ... obtained int = 0 8 | ... expected float64 = 0.6666666666666666 9 | 10 | FAIL: mmath_test.go:35: MySuite.TestDiv 11 | 12 | START: mmath_test.go:29: MySuite.TestMul 13 | PASS: mmath_test.go:29: MySuite.TestMul 0.000s 14 | 15 | START: mmath_test.go:22: MySuite.TestSub 16 | PASS: mmath_test.go:22: MySuite.TestSub 0.000s 17 | 18 | --- FAIL: Test (0.00 seconds) 19 | FAIL 20 | exit status 1 21 | FAIL go2xunit/demo-gocheck 0.008s 22 | -------------------------------------------------------------------------------- /_data/in/gocheck-nofiles.out: -------------------------------------------------------------------------------- 1 | ? github.com/tischda/mmath [no test files] 2 | -------------------------------------------------------------------------------- /_data/in/gocheck-panic.out: -------------------------------------------------------------------------------- 1 | START: mmath_test.go:22: MySuite.TestAdd 2 | PASS: mmath_test.go:22: MySuite.TestAdd 0.001s 3 | 4 | START: mmath_test.go:42: MySuite.TestDiv 5 | mmath_test.go:45: 6 | c.Assert(z, Equals, float64(x)/float64(y)) 7 | ... obtained int = 0 8 | ... expected float64 = 0.6666666666666666 9 | 10 | FAIL: mmath_test.go:42: MySuite.TestDiv 11 | 12 | START: mmath_test.go:35: MySuite.TestMul 13 | SKIP: mmath_test.go:35: MySuite.TestMul (not implemented) 14 | 15 | START: mmath_test.go:17: MySuite.TestPanic 16 | ... Panic: (PC=0x42546C) 17 | 18 | c:/go/src/runtime/asm_amd64.s:401 19 | in call16 20 | c:/go/src/runtime/panic.go:387 21 | in gopanic 22 | c:/go/src/log/log.go:307 23 | in Panic 24 | mmath.go:22 25 | in Panic 26 | mmath_test.go:18 27 | in MySuite.TestPanic 28 | c:/go/src/runtime/asm_amd64.s:401 29 | in call16 30 | c:/go/src/reflect/value.go:419 31 | in Value.call 32 | c:/go/src/reflect/value.go:296 33 | in Value.Call 34 | c:/go/src/runtime/asm_amd64.s:2232 35 | in goexit 36 | PANIC: mmath_test.go:17: MySuite.TestPanic 37 | 38 | START: mmath_test.go:28: MySuite.TestSub 39 | PASS: mmath_test.go:28: MySuite.TestSub 0.000s 40 | 41 | --- FAIL: Test (0.00s) 42 | FAIL 43 | exit status 1 44 | FAIL github.com/tischda/mmath 0.040s 45 | -------------------------------------------------------------------------------- /_data/in/gocheck-pass.out: -------------------------------------------------------------------------------- 1 | START: mmath_test.go:16: MySuite.TestAdd 2 | PASS: mmath_test.go:16: MySuite.TestAdd 0.000s 3 | 4 | START: mmath_test.go:29: MySuite.TestMul 5 | PASS: mmath_test.go:29: MySuite.TestMul 0.000s 6 | 7 | START: mmath_test.go:22: MySuite.TestSub 8 | PASS: mmath_test.go:22: MySuite.TestSub 0.000s 9 | 10 | PASS 11 | ok go2xunit/demo-gocheck 0.008s 12 | -------------------------------------------------------------------------------- /_data/in/gocheck-setup-miss.out: -------------------------------------------------------------------------------- 1 | === RUN Test 2 | START: foobar_test.go:17: FoobarSuite.SetUpSuite 3 | foobar_test.go:19: 4 | c.Assert(err, gc.IsNil) 5 | ... value *os.PathError = &os.PathError{Op:"stat", Path:"testdata/regexes.yaml", Err:0x2} ("stat testdata/regexes.yaml: no such file or directory") 6 | 7 | FAIL: foobar_test.go:17: FoobarSuite.SetUpSuite 8 | 9 | START: foobar_test.go:79: FoobarSuite.TestFrob 10 | MISS: foobar_test.go:79: FoobarSuite.TestFrob 11 | 12 | START: foobar_test.go:102: FoobarSuite.TestThing 13 | MISS: foobar_test.go:102: FoobarSuite.TestThing 14 | 15 | OOPS: 82 passed, 1 FAILED, 2 MISSED 16 | --- FAIL: Test (2.37s) 17 | FAIL 18 | FAIL github.com/you/yourproject/foobar 2.383s 19 | -------------------------------------------------------------------------------- /_data/in/gotest-0.out: -------------------------------------------------------------------------------- 1 | === RUN ExampleA 2 | --- PASS: ExampleA (4.0003ms) 3 | === RUN: ExampleOp 4 | --- PASS: ExampleOp (0) 5 | PASS 6 | ok package 0.194s 7 | -------------------------------------------------------------------------------- /_data/in/gotest-1.5.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00s) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00s) 5 | === RUN TestMul 6 | --- PASS: TestMul (0.00s) 7 | === RUN TestDiv 8 | --- FAIL: TestDiv (0.00s) 9 | mmath_test.go:35: 2/3 != 0.666667 10 | FAIL 11 | exit status 1 12 | FAIL _/home/miki/Projects/go/src/bitbucket.org/tebeka/go2xunit/demo 0.002s 13 | -------------------------------------------------------------------------------- /_data/in/gotest-1.6.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00s) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00s) 5 | === RUN TestMul 6 | --- PASS: TestMul (0.00s) 7 | === RUN TestDiv 8 | --- FAIL: TestDiv (0.00s) 9 | mmath_test.go:35: 2/3 != 0.666667 10 | FAIL 11 | exit status 1 12 | FAIL bitbucket.org/tebeka/go2xunit/demo 0.002s 13 | -------------------------------------------------------------------------------- /_data/in/gotest-1.7.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00s) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00s) 5 | === RUN TestMul 6 | --- PASS: TestMul (0.00s) 7 | === RUN TestDiv 8 | --- FAIL: TestDiv (0.00s) 9 | mmath_test.go:35: 2/3 != 0.666667 10 | === RUN TestSquare 11 | === RUN TestSquare/x=1 12 | === RUN TestSquare/x=2 13 | --- PASS: TestSquare (0.00s) 14 | --- PASS: TestSquare/x=1 (0.00s) 15 | --- PASS: TestSquare/x=2 (0.00s) 16 | FAIL 17 | exit status 1 18 | FAIL github.com/tebeka/go2xunit/demo 0.070s 19 | -------------------------------------------------------------------------------- /_data/in/gotest-buildfailed.out: -------------------------------------------------------------------------------- 1 | === RUN TestUrlJoin 2 | --- PASS: TestUrlJoin (0.00 seconds) 3 | PASS 4 | ok common 0.002s 5 | FAIL node/config [build failed] 6 | -------------------------------------------------------------------------------- /_data/in/gotest-datarace.out: -------------------------------------------------------------------------------- 1 | === RUN TestDataRace 2 | WARNING: DATA RACE 3 | --- PASS: TestDataRace (0.00 seconds) 4 | PASS 5 | FAIL go2xunit/demo 0.006s 6 | -------------------------------------------------------------------------------- /_data/in/gotest-empty.out: -------------------------------------------------------------------------------- 1 | testing: warning: no tests to run 2 | PASS 3 | ok go2xunit/demo 0.021s 4 | -------------------------------------------------------------------------------- /_data/in/gotest-escaped.out: -------------------------------------------------------------------------------- 1 | === RUN TestEscapedChars 2 | === RUN TestEscapedChars/no_special_chars 3 | === RUN TestEscapedChars/"needs_escape" 4 | === RUN TestEscapedChars/reserved_ 5 | --- PASS: TestEscapedChars (0.00s) 6 | --- PASS: TestEscapedChars/no_special_chars (0.00s) 7 | --- PASS: TestEscapedChars/"needs_escape" (0.00s) 8 | --- PASS: TestEscapedChars/reserved_ (0.00s) 9 | PASS 10 | ok _/go/src/github.com/tebeka/go2xunit/data 0.005s 11 | -------------------------------------------------------------------------------- /_data/in/gotest-fail.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00 seconds) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00 seconds) 5 | === RUN TestSubFail 6 | --- FAIL: TestSubFail (0.00 seconds) 7 | xunit_test.go:22: 3-1 != 3 8 | Some newline goes here 9 | === RUN TestSubOK 10 | --- PASS: TestSubOK (0.00 seconds) 11 | FAIL 12 | exit status 1 13 | FAIL _/home/miki/Projects/goroot/src/xunit 0.004s 14 | -------------------------------------------------------------------------------- /_data/in/gotest-fatal-nosummary.out: -------------------------------------------------------------------------------- 1 | === RUN TestPanic 2 | fatal error: all goroutines are asleep - deadlock! 3 | ... 4 | -------------------------------------------------------------------------------- /_data/in/gotest-last-suite.out: -------------------------------------------------------------------------------- 1 | ? sisu.sh/go/code/catalog [no test files] 2 | ? sisu.sh/go/code/catalog/client [no test files] 3 | ? sisu.sh/go/code/catalog/cmd/catalog-service [no test files] 4 | ? sisu.sh/go/code/catalog/handler [no test files] 5 | ? sisu.sh/go/code/catalog/handler/validator [no test files] 6 | ? sisu.sh/go/code/catalog/info [no test files] 7 | === RUN TestFail 8 | --- FAIL: TestFail (0.00s) 9 | localizer_test.go:15: YO IM FAILING! 10 | === RUN TestCurrencyMap 11 | --- PASS: TestCurrencyMap (0.00s) 12 | === RUN TestCountryMap 13 | --- PASS: TestCountryMap (0.00s) 14 | === RUN TestLanguagesByCountry 15 | --- PASS: TestLanguagesByCountry (0.00s) 16 | === RUN TestCountryLanguageCombinations 17 | --- PASS: TestCountryLanguageCombinations (0.00s) 18 | FAIL 19 | FAIL sisu.sh/go/code/catalog/localizer 0.004s 20 | === RUN TestNameIsGeneratedCorrectly 21 | --- PASS: TestNameIsGeneratedCorrectly (0.00s) 22 | PASS 23 | ok sisu.sh/go/code/catalog/name (cached) 24 | ? sisu.sh/go/code/catalog/store [no test files] 25 | ? sisu.sh/go/code/catalog/store/postgres [no test files] 26 | === RUN TestExtractNumericIds 27 | --- PASS: TestExtractNumericIds (0.00s) 28 | === RUN TestExtractStringIds 29 | --- PASS: TestExtractStringIds (0.00s) 30 | === RUN TestIntSliceToStringSlice 31 | --- PASS: TestIntSliceToStringSlice (0.00s) 32 | === RUN TestGetKeys 33 | --- PASS: TestGetKeys (0.00s) 34 | === RUN TestProtoEnumToStringSlice 35 | --- PASS: TestProtoEnumToStringSlice (0.00s) 36 | PASS 37 | ok sisu.sh/go/code/catalog/transformer (cached) 38 | -------------------------------------------------------------------------------- /_data/in/gotest-log.out: -------------------------------------------------------------------------------- 1 | === RUN TestLogOutput 2 | Log output. 3 | --- PASS: TestLogOutput (0.00 seconds) 4 | PASS 5 | ok go2xunit/demo 0.006s 6 | -------------------------------------------------------------------------------- /_data/in/gotest-multi.out: -------------------------------------------------------------------------------- 1 | ? alipay [no test files] 2 | ? config [no test files] 3 | === RUN TestApp_AssetPath 4 | --- PASS: TestApp_AssetPath (0.00 seconds) 5 | === RUN TestTrimTransferCeil 6 | --- PASS: TestTrimTransferCeil (0.00 seconds) 7 | === RUN TestStatusDescription 8 | --- PASS: TestStatusDescription (0.00 seconds) 9 | === RUN TestCode 10 | --- PASS: TestCode (0.00 seconds) 11 | PASS 12 | ok controllers 0.024s 13 | ? controllers/api [no test files] 14 | ? controllers/bucket [no test files] 15 | ? mail [no test files] 16 | ? models [no test files] 17 | ? plugins [no test files] 18 | ? templatefunc [no test files] 19 | ? utils [no test files] 20 | ? website [no test files] 21 | -------------------------------------------------------------------------------- /_data/in/gotest-multierror.out: -------------------------------------------------------------------------------- 1 | === RUN TestError1 2 | --- FAIL: TestError1 (0.00 seconds) 3 | main_test.go:10: something went wrong 4 | === RUN TestError2 5 | --- FAIL: TestError2 (0.00 seconds) 6 | main_test.go:14: something new went wrong 7 | FAIL 8 | exit status 1 9 | FAIL skeleton 0.047s 10 | -------------------------------------------------------------------------------- /_data/in/gotest-negative-duration.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (-0.01 seconds) 3 | PASS 4 | ok go2xunit/demo -0.012s 5 | -------------------------------------------------------------------------------- /_data/in/gotest-nofiles.out: -------------------------------------------------------------------------------- 1 | ? alipay [no test files] 2 | ? config [no test files] 3 | === RUN TestApp_AssetPath 4 | --- PASS: TestApp_AssetPath (0.00 seconds) 5 | === RUN TestTrimTransferCeil 6 | --- PASS: TestTrimTransferCeil (0.00 seconds) 7 | === RUN TestStatusDescription 8 | --- PASS: TestStatusDescription (0.00 seconds) 9 | === RUN TestCode 10 | --- PASS: TestCode (0.00 seconds) 11 | PASS 12 | ok controllers 0.024s 13 | ? controllers/api [no test files] 14 | ? controllers/bucket [no test files] 15 | ? mail [no test files] 16 | ? models [no test files] 17 | ? plugins [no test files] 18 | ? templatefunc [no test files] 19 | ? utils [no test files] 20 | ? website [no test files] 21 | -------------------------------------------------------------------------------- /_data/in/gotest-nosummary.out: -------------------------------------------------------------------------------- 1 | === RUN TestMeaning 2 | --- PASS: TestMeaning (0.00s) 3 | === RUN TestAddTwoNumbers 4 | 2 + 3 = 5 5 | --- FAIL: TestAddTwoNumbers (0.00s) 6 | lib_test.go:30: failing just because 7 | FAIL 8 | -------------------------------------------------------------------------------- /_data/in/gotest-num.out: -------------------------------------------------------------------------------- 1 | === RUN TestBasic-8 2 | --- PASS: TestBasic-8 (0.00 seconds) 3 | ok qbox.us/largefile 0.012s 4 | -------------------------------------------------------------------------------- /_data/in/gotest-panic.out: -------------------------------------------------------------------------------- 1 | === RUN TestPanic 2 | fatal error: all goroutines are asleep - deadlock! 3 | ... 4 | exit status 2 5 | FAIL go2xunit/demo 0.020s 6 | -------------------------------------------------------------------------------- /_data/in/gotest-pass.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00 seconds) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00 seconds) 5 | === RUN TestMul 6 | --- PASS: TestMul (0.00 seconds) 7 | PASS 8 | ok go2xunit/demo 0.006s 9 | -------------------------------------------------------------------------------- /_data/in/gotest-print.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00 seconds) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00 seconds) 5 | === RUN TestSubFail 6 | --- FAIL: TestSubFail (0.00 seconds) 7 | xunit_test.go:22: 3-1 != 3 8 | Some newline goes here 9 | === RUN TestSubOK 10 | --- PASS: TestSubOK (0.00 seconds) 11 | === RUN TestSubSkip 12 | --- SKIP: TestSubSkip (0.00 seconds) 13 | FAIL 14 | exit status 1 15 | FAIL _/home/miki/Projects/goroot/src/xunit 0.004s 16 | === RUN TestAdd 17 | --- PASS: TestAdd (0.00 seconds) 18 | ok _/home/miki/Projects/goroot/src/anotherTest 0.000s 19 | PASS 20 | -------------------------------------------------------------------------------- /_data/in/gotest-simple-and-suite-tests.out: -------------------------------------------------------------------------------- 1 | === RUN TestSampleSuccessful 2 | This test should success 3 | --- PASS: TestSampleSuccessful (0.00s) 4 | === RUN TestSampleFail 5 | This test should fail 6 | --- FAIL: TestSampleFail (0.00s) 7 | Error Trace: samples_test.go:27 8 | Error: Should be true 9 | Messages: Should be true 10 | === RUN TestSampleSuccessful2 11 | This test should success again 12 | --- PASS: TestSampleSuccessful2 (0.00s) 13 | === RUN TestSampleFail2 14 | This test should fail again 15 | --- FAIL: TestSampleFail2 (0.00s) 16 | Error Trace: samples_test.go:37 17 | Error: Should be true 18 | Messages: Should be true again 19 | === RUN TestSampleSuite1 20 | === RUN TestSampleSuite1/TestSuiteSampleFail1 21 | This test from suite should fail1 22 | === RUN TestSampleSuite1/TestSuiteSampleSuccessful1 23 | This test from suite should success1 24 | --- FAIL: TestSampleSuite1 (0.00s) 25 | --- FAIL: TestSampleSuite1/TestSuiteSampleFail1 (0.00s) 26 | Error Trace: samples_test.go:47 27 | Error: Should be true 28 | Messages: Should be true1 29 | --- PASS: TestSampleSuite1/TestSuiteSampleSuccessful1 (0.00s) 30 | === RUN TestSampleSuite2 31 | === RUN TestSampleSuite2/TestSuiteSampleFail2 32 | This test from suite should fail2 33 | === RUN TestSampleSuite2/TestSuiteSampleSuccessful2 34 | This test from suite should success2 35 | --- FAIL: TestSampleSuite2 (0.01s) 36 | --- FAIL: TestSampleSuite2/TestSuiteSampleFail2 (0.00s) 37 | Error Trace: samples_test.go:61 38 | Error: Should be true 39 | Messages: Should be true2 40 | --- PASS: TestSampleSuite2/TestSuiteSampleSuccessful2 (0.00s) 41 | FAIL 42 | exit status 1 43 | FAIL _/Users/Teodor/go2xunit_samples 0.028s -------------------------------------------------------------------------------- /_data/in/gotest-testify-suite.out: -------------------------------------------------------------------------------- 1 | === RUN TestSuite 2 | === RUN TestA 3 | --- PASS: TestA (0.01 seconds) 4 | === RUN TestB 5 | --- PASS: TestB (0.02 seconds) 6 | --- PASS: TestSuite (0.03 seconds) 7 | === RUN TestC 8 | --- PASS: TestC (0.04 seconds) 9 | PASS 10 | ok testify-suite 0.071s 11 | -------------------------------------------------------------------------------- /_data/in/gotest.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00 seconds) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00 seconds) 5 | === RUN TestSubFail 6 | --- FAIL: TestSubFail (0.00 seconds) 7 | xunit_test.go:22: 3-1 != 3 8 | Some newline goes here 9 | === RUN TestSubOK 10 | --- PASS: TestSubOK (0.00 seconds) 11 | === RUN TestSubSkip 12 | --- SKIP: TestSubSkip (0.00 seconds) 13 | FAIL 14 | exit status 1 15 | FAIL _/home/miki/Projects/goroot/src/xunit 0.004s 16 | === RUN TestAdd 17 | --- PASS: TestAdd (0.00 seconds) 18 | ok _/home/miki/Projects/goroot/src/anotherTest 0.000s 19 | PASS 20 | -------------------------------------------------------------------------------- /_data/nosetests.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gocheck-empty.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gocheck-fail.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 34 | 35 | 40 | 41 | 46 | 47 | 48 | 49 | 54 | 55 | 56 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gocheck-nofiles.out.xml: -------------------------------------------------------------------------------- 1 | error: no tests found -------------------------------------------------------------------------------- /_data/out/xunit.net/gocheck-panic.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 53 | 54 | 74 | 75 | 76 | 77 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gocheck-pass.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gocheck-setup-miss.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 30 | 31 | 32 | 33 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-0.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-1.5.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-1.6.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-1.7.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | 56 | 57 | 58 | 63 | 64 | 65 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-buildfailed.out.xml: -------------------------------------------------------------------------------- 1 | error: 5: package build failed: FAIL node/config [build failed] 2 | exit status 1 3 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-datarace.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-empty.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-escaped.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-fail.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 42 | 43 | 44 | 45 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-fatal-nosummary.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-last-suite.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 37 | 42 | 43 | 44 | 49 | 50 | 51 | 56 | 57 | 58 | 59 | 60 | 65 | 66 | 71 | 72 | 73 | 74 | 75 | 80 | 81 | 86 | 87 | 88 | 93 | 94 | 95 | 100 | 101 | 102 | 107 | 108 | 109 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-log.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-multi.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-multierror.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-negative-duration.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-nofiles.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-nosummary.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-num.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-panic.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-pass.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-print.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 42 | 43 | 44 | 45 | 50 | 51 | 52 | 57 | 58 | 59 | 60 | 61 | 66 | 67 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-simple-and-suite-tests.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 52 | 53 | 57 | 58 | 59 | 60 | 65 | 66 | 67 | 68 | 69 | 70 | 75 | 76 | 79 | 80 | 81 | 82 | 87 | 88 | 89 | 94 | 95 | 96 | 97 | 98 | 99 | 104 | 105 | 108 | 109 | 110 | 111 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest-testify-suite.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 35 | 36 | 41 | 42 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /_data/out/xunit.net/gotest.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 42 | 43 | 44 | 45 | 50 | 51 | 52 | 57 | 58 | 59 | 60 | 61 | 66 | 67 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /_data/out/xunit/gocheck-empty.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /_data/out/xunit/gocheck-fail.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /_data/out/xunit/gocheck-nofiles.out.xml: -------------------------------------------------------------------------------- 1 | error: no tests found -------------------------------------------------------------------------------- /_data/out/xunit/gocheck-panic.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /_data/out/xunit/gocheck-pass.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /_data/out/xunit/gocheck-setup-miss.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-0.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-1.5.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-1.6.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-1.7.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-buildfailed.out.xml: -------------------------------------------------------------------------------- 1 | error: 5: package build failed: FAIL node/config [build failed] 2 | exit status 1 3 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-datarace.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-empty.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-escaped.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-fail.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-fatal-nosummary.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-last-suite.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-log.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-multi.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-multierror.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-negative-duration.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-nofiles.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-nosummary.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-num.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-panic.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-pass.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-print.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-simple-and-suite-tests.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest-testify-suite.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /_data/out/xunit/gotest.out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_data/run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export GOPATH=$(dirname $(dirname $PWD)) 4 | outfile=gotest.out 5 | 6 | 2>&1 go test -v | tee $outfile 7 | go2xunit -fail -input $outfile -output tests.xml 8 | -------------------------------------------------------------------------------- /_data/test_xunit.py: -------------------------------------------------------------------------------- 1 | def test_add(): 2 | assert 1 + 2 == 3, "bad add" 3 | 4 | def test_sub(): 5 | assert 2 - 1 == 1, "bad sub" 6 | 7 | def test_sub_fail(): 8 | assert 2 - 2 == 1, "bad sub" 9 | -------------------------------------------------------------------------------- /_demos/gocheck/README.md: -------------------------------------------------------------------------------- 1 | # Demo Project for Using go2xunit 2 | 3 | Install `go2xunit` with `go get github.com/tebeka/go2xunit` 4 | 5 | Use run-jenkins.sh to run Jenkins (see Jenkins download instructions in the script). 6 | 7 | Then configure Jenkins like the configuration screen below, note the 8 | "Execute Shell" and "Publish JUnit test result report" sections. 9 | 10 | You after running, you should see test results like the below. 11 | 12 | 13 | ## Configuration Screen 14 | 15 | ![Configuration Screen](screenshots/config.png) 16 | 17 | ## Test Results - Overview 18 | 19 | ![Tests Overview](screenshots/build-overrview.png) 20 | 21 | ## Test Results - Detailed 22 | 23 | ![Tests Detailed](screenshots/build-tests.png) 24 | 25 | -------------------------------------------------------------------------------- /_demos/gocheck/jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Test script run by jenkins 3 | 4 | outfile=gotest.out 5 | 6 | 2>&1 go test -gocheck.vv | tee $outfile 7 | go2xunit -gocheck -fail -input $outfile -output tests.xml 8 | -------------------------------------------------------------------------------- /_demos/gocheck/mmath.go: -------------------------------------------------------------------------------- 1 | package mmath 2 | 3 | func Add(x, y int) int { 4 | return x + y 5 | } 6 | 7 | func Sub(x, y int) int { 8 | return x - y 9 | } 10 | 11 | func Mul(x, y int) int { 12 | return x * y 13 | } 14 | 15 | func Div(x, y int) int { 16 | return x / y 17 | } 18 | -------------------------------------------------------------------------------- /_demos/gocheck/mmath_test.go: -------------------------------------------------------------------------------- 1 | package mmath 2 | 3 | import ( 4 | . "launchpad.net/gocheck" 5 | "testing" 6 | ) 7 | 8 | type MySuite struct{} 9 | var _ = Suite(&MySuite{}) 10 | 11 | // Hook up gocheck into the "go test" runner. 12 | func Test(t *testing.T) { 13 | TestingT(t) 14 | } 15 | 16 | func (s *MySuite) TestAdd(c *C) { 17 | x, y := 1, 2 18 | z := Add(x, y) 19 | c.Assert(z, Equals, x+y) 20 | } 21 | 22 | func (s *MySuite) TestSub(c *C) { 23 | x, y := 1, 2 24 | z := Sub(x, y) 25 | 26 | c.Assert(z, Equals, x-y) 27 | } 28 | 29 | func (s *MySuite) TestMul(c *C) { 30 | x, y := 2, 3 31 | z := Mul(x, y) 32 | c.Assert(z, Equals, x*y) 33 | } 34 | 35 | func (s *MySuite) TestDiv(c *C) { 36 | x, y := 2, 3 37 | z := Div(x, y) 38 | c.Assert(z, Equals, float64(x)/float64(y)) 39 | } 40 | -------------------------------------------------------------------------------- /_demos/gocheck/run-jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Run Jenkins as daemon on port 8000 3 | 4 | # You can download jenkins.war from http://mirrors.jenkins-ci.org/war/latest/jenkins.war 5 | 6 | java -jar jenkins.war \ 7 | --logfile=${PWD}/jenkins.log \ 8 | --httpPort=8000 \ 9 | --daemon 10 | -------------------------------------------------------------------------------- /_demos/gotest/README.md: -------------------------------------------------------------------------------- 1 | # Demo Project for Using go2xunit 2 | 3 | Install `go2xunit` with `go get github.com/tebeka/go2xunit` 4 | 5 | Use run-jenkins.sh to run Jenkins (see Jenkins download instructions in the script). 6 | 7 | Then configure Jenkins like the configuration screen below, note the 8 | "Execute Shell" and "Publish JUnit test result report" sections. 9 | 10 | You after running, you should see test results like the below. 11 | 12 | 13 | ## Configuration Screen 14 | 15 | ![Configuration Screen](screenshots/config.png) 16 | 17 | ## Test Results - Overview 18 | 19 | ![Tests Overview](screenshots/build-overrview.png) 20 | 21 | ## Test Results - Detailed 22 | 23 | ![Tests Detailed](screenshots/build-tests.png) 24 | 25 | -------------------------------------------------------------------------------- /_demos/gotest/gotest-1.6.out: -------------------------------------------------------------------------------- 1 | === RUN TestAdd 2 | --- PASS: TestAdd (0.00s) 3 | === RUN TestSub 4 | --- PASS: TestSub (0.00s) 5 | === RUN TestMul 6 | --- PASS: TestMul (0.00s) 7 | === RUN TestDiv 8 | --- FAIL: TestDiv (0.00s) 9 | mmath_test.go:35: 2/3 != 0.666667 10 | FAIL 11 | exit status 1 12 | FAIL bitbucket.org/tebeka/go2xunit/demo 0.002s 13 | -------------------------------------------------------------------------------- /_demos/gotest/jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Test script run by jenkins 3 | 4 | outfile=gotest.out 5 | 6 | 2>&1 go test -v | tee $outfile 7 | go2xunit -fail -input $outfile -output tests.xml 8 | -------------------------------------------------------------------------------- /_demos/gotest/mmath.go: -------------------------------------------------------------------------------- 1 | package mmath 2 | 3 | func Add(x, y int) int { 4 | return x + y 5 | } 6 | 7 | func Sub(x, y int) int { 8 | return x - y 9 | } 10 | 11 | func Mul(x, y int) int { 12 | return x * y 13 | } 14 | 15 | func Div(x, y int) int { 16 | return x / y 17 | } 18 | -------------------------------------------------------------------------------- /_demos/gotest/mmath_test.go: -------------------------------------------------------------------------------- 1 | package mmath 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestAdd(t *testing.T) { 8 | x, y := 1, 2 9 | z := Add(x, y) 10 | if z != x+y { 11 | t.Fatalf("%d + %d != %d\n", x, y, x+y) 12 | } 13 | } 14 | 15 | func TestSub(t *testing.T) { 16 | x, y := 1, 2 17 | z := Sub(x, y) 18 | if z != x-y { 19 | t.Fatalf("%d-%d != %d\n", x, y, x-y) 20 | } 21 | } 22 | 23 | func TestMul(t *testing.T) { 24 | x, y := 2, 3 25 | z := Mul(x, y) 26 | if z != x*y { 27 | t.Fatalf("%d*%d != %d\n", x, y, x*y) 28 | } 29 | } 30 | 31 | func TestDiv(t *testing.T) { 32 | x, y := 2, 3 33 | z := Div(x, y) 34 | if float64(z) != float64(x)/float64(y) { 35 | t.Fatalf("%d/%d != %f\n", x, y, float64(x)/float64(y)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /_demos/gotest/run-jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Run Jenkins as daemon on port 8000 3 | 4 | # You can download jenkins.war from http://mirrors.jenkins-ci.org/war/latest/jenkins.war 5 | 6 | java -jar jenkins.war \ 7 | --logfile=${PWD}/jenkins.log \ 8 | --httpPort=8000 \ 9 | --daemon 10 | -------------------------------------------------------------------------------- /_demos/gotest/screenshots/build-overrview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tebeka/go2xunit/b376d08e02f1416eb9d30b12786f7e2a5ceb5b0e/_demos/gotest/screenshots/build-overrview.png -------------------------------------------------------------------------------- /_demos/gotest/screenshots/build-tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tebeka/go2xunit/b376d08e02f1416eb9d30b12786f7e2a5ceb5b0e/_demos/gotest/screenshots/build-tests.png -------------------------------------------------------------------------------- /_demos/gotest/screenshots/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tebeka/go2xunit/b376d08e02f1416eb9d30b12786f7e2a5ceb5b0e/_demos/gotest/screenshots/config.png -------------------------------------------------------------------------------- /_demos/testify/README.md: -------------------------------------------------------------------------------- 1 | # Demo Project for Using go2xunit with testify 2 | 3 | Install `go2xunit` with `go get github.com/tebeka/go2xunit` 4 | 5 | Then configure Jenkins like the configuration screen below, note the 6 | "Execute Shell" and "Publish JUnit test result report" sections. 7 | 8 | You after running, you should see test results like the below. 9 | 10 | 11 | ## Configuration Screen 12 | 13 | ![Configuration Screen](screenshots/config.png) 14 | 15 | ## Test Results - Overview 16 | 17 | ![Tests Overview](screenshots/build-overrview.png) 18 | 19 | ## Test Results - Detailed 20 | 21 | ![Tests Detailed](screenshots/build-tests.png) 22 | 23 | -------------------------------------------------------------------------------- /_demos/testify/jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Test script run by jenkins 3 | 4 | outfile=gotest.out 5 | 6 | 2>&1 go test -v | tee $outfile 7 | go2xunit -fail -input $outfile -output tests.xml 8 | -------------------------------------------------------------------------------- /_demos/testify/mmath.go: -------------------------------------------------------------------------------- 1 | package mmath 2 | 3 | func Add(x, y int) int { 4 | return x + y 5 | } 6 | 7 | func Sub(x, y int) int { 8 | return x - y 9 | } 10 | 11 | func Mul(x, y int) int { 12 | return x * y 13 | } 14 | 15 | func Div(x, y int) int { 16 | return x / y 17 | } 18 | -------------------------------------------------------------------------------- /_demos/testify/mmath_test.go: -------------------------------------------------------------------------------- 1 | package mmath 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestAdd(t *testing.T) { 10 | x, y := 1, 2 11 | z := Add(x, y) 12 | assert.Equal(t, z, x+y, "%d + %d != %d\n", x, y, x+y) 13 | } 14 | 15 | func TestSub(t *testing.T) { 16 | x, y := 1, 2 17 | z := Sub(x, y) 18 | assert.Equal(t, z, x-y, "%d-%d != %d\n", x, y, x-y) 19 | } 20 | 21 | func TestMul(t *testing.T) { 22 | x, y := 2, 3 23 | z := Mul(x, y) 24 | assert.Equal(t, z, x*y, "%d*%d != %d\n", x, y, x*y) 25 | } 26 | 27 | func TestDiv(t *testing.T) { 28 | x, y := 2, 3 29 | z := Div(x, y) 30 | quot := float64(x) / float64(y) 31 | assert.Equal(t, float64(z), quot, "%d/%d != %f\n", x, y, quot) 32 | } 33 | -------------------------------------------------------------------------------- /_demos/testify/screenshots/build-overrview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tebeka/go2xunit/b376d08e02f1416eb9d30b12786f7e2a5ceb5b0e/_demos/testify/screenshots/build-overrview.png -------------------------------------------------------------------------------- /_demos/testify/screenshots/build-tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tebeka/go2xunit/b376d08e02f1416eb9d30b12786f7e2a5ceb5b0e/_demos/testify/screenshots/build-tests.png -------------------------------------------------------------------------------- /_demos/testify/screenshots/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tebeka/go2xunit/b376d08e02f1416eb9d30b12786f7e2a5ceb5b0e/_demos/testify/screenshots/config.png -------------------------------------------------------------------------------- /cmdline.go: -------------------------------------------------------------------------------- 1 | // Command line parsing 2 | package main 3 | 4 | import ( 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/tebeka/go2xunit/lib" 10 | ) 11 | 12 | var args struct { 13 | inFile string 14 | outFile string 15 | fail bool 16 | showVersion bool 17 | bambooOut bool 18 | xunitnetOut bool 19 | isGocheck bool 20 | suitePrefix string 21 | } 22 | 23 | func init() { 24 | flag.StringVar(&args.inFile, "input", "", "input file (default to stdin)") 25 | flag.StringVar(&args.outFile, "output", "", "output file (default to stdout)") 26 | flag.BoolVar(&args.fail, "fail", false, "fail (non zero exit) if any test failed") 27 | flag.BoolVar(&args.showVersion, "version", false, "print version and exit") 28 | flag.BoolVar(&args.bambooOut, "bamboo", false, 29 | "xml compatible with Atlassian's Bamboo") 30 | flag.BoolVar(&args.xunitnetOut, "xunitnet", false, "xml compatible with xunit.net") 31 | flag.BoolVar(&args.isGocheck, "gocheck", false, "parse gocheck output") 32 | flag.BoolVar(&lib.Options.FailOnRace, "fail-on-race", false, 33 | "mark test as failing if it exposes a data race") 34 | flag.StringVar(&args.suitePrefix, "suite-name-prefix", "", 35 | "prefix to include before all suite names") 36 | 37 | flag.Parse() 38 | } 39 | 40 | // validateArgs validates command line arguments 41 | func validateArgs() error { 42 | if flag.NArg() > 0 { 43 | return fmt.Errorf("%s does not take parameters (did you mean -input?)", os.Args[0]) 44 | } 45 | 46 | if args.bambooOut && args.xunitnetOut { 47 | return fmt.Errorf("-bamboo and -xunitnet are mutually exclusive") 48 | } 49 | 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /gen-out.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | case $1 in 4 | -h | --help ) echo "usage: $(basename $0) FILE [FILE...]"; exit;; 5 | esac 6 | 7 | if [ $# -lt 1 ]; then 8 | 1>&2 echo "error: wrong number of arguments" 9 | exit 1 10 | fi 11 | 12 | for name in $@; do 13 | if [ ! -f "${name}" ]; then 14 | 1>&2 echo "error: ${name} - no such file" 15 | exit 1 16 | fi 17 | 18 | out=_data/out/xunit/$(basename ${name}).xml 19 | echo "${name} -> ${out}" 20 | go run . -input ${name} -output ${out} 21 | out=_data/out/xunit.net/$(basename ${name}).xml 22 | echo "${name} -> ${out}" 23 | go run . -input ${name} -output ${out} -xunitnet 24 | done 25 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tebeka/go2xunit 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /lib/lex.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "regexp" 8 | ) 9 | 10 | var ( 11 | // gotest regular expressions 12 | 13 | // === RUN TestAdd 14 | gtStartRE = regexp.MustCompile( 15 | "^=== RUN:?[[:space:]]+([a-zA-Z_][^[:space:]]*)") 16 | 17 | // --- PASS: TestSub (0.00 seconds) 18 | // --- FAIL: TestSubFail (0.00 seconds) 19 | // --- SKIP: TestSubSkip (0.00 seconds) 20 | gtEndRE = regexp.MustCompile( 21 | "--- (PASS|FAIL|SKIP):[[:space:]]+([a-zA-Z_][^[:space:]]*) " + 22 | "\\((-?\\d+(.\\d+)?)") 23 | 24 | // FAIL _/home/miki/Projects/goroot/src/xunit 0.004s 25 | // ok _/home/miki/Projects/goroot/src/anotherTest 0.000s 26 | gtSuiteRE = regexp.MustCompile( 27 | "^(ok|FAIL)[ \t]+([^ \t]+)[ \t]+((-?\\d+.\\d+)|\\(cached\\))") 28 | 29 | // ? alipay [no test files] 30 | gtNoFilesRE = regexp.MustCompile("^\\?.*\\[no test files\\]$") 31 | // FAIL node/config [build failed] 32 | gtBuildFailedRE = regexp.MustCompile(`^FAIL.*\[(build|setup) failed\]$`) 33 | 34 | // exit status - 0 35 | gtExitRE = regexp.MustCompile("^exit status -?\\d+") 36 | 37 | // gocheck regular expressions 38 | 39 | // START: mmath_test.go:16: MySuite.TestAdd 40 | gcStartRE = regexp.MustCompile( 41 | "START: [^:]+:[^:]+: ([A-Za-z_][[:word:]]*).([A-Za-z_][[:word:]]*)") 42 | 43 | // PASS: mmath_test.go:16: MySuite.TestAdd 0.000s 44 | // FAIL: mmath_test.go:35: MySuite.TestDiv 45 | gcEndRE = regexp.MustCompile( 46 | "(PASS|FAIL|SKIP|PANIC|MISS): [^:]+:[^:]+: " + 47 | "([A-Za-z_][[:word:]]*).([A-Za-z_][[:word:]]*)" + 48 | "[[:space:]]?(-?[0-9]+.[0-9]+)?") 49 | 50 | // FAIL go2xunit/demo-gocheck 0.008s 51 | // ok go2xunit/demo-gocheck 0.008s 52 | // ok sisu.sh/go/code/catalog/transformer (cached) 53 | gcSuiteRE = regexp.MustCompile("^(ok|FAIL)[ \t]+([^ \t]+)[ \t]+(-?\\d+.\\d+)") 54 | 55 | // Match error output from tests 56 | // Error Trace: samples_test.go:27 57 | // Error: Should be true 58 | // Messages: Should be true 59 | gcTestErrorRE = regexp.MustCompile("(?s).*Error Trace:.*\\.go.*Error:.*Messages:.*") 60 | ) 61 | 62 | // LineScanner scans lines and keep track of line numbers 63 | type LineScanner struct { 64 | *bufio.Reader 65 | lnum int // Current line number. 66 | text []byte // Content of current line of text. 67 | err error // Error from latest operation. 68 | } 69 | 70 | // NewLineScanner creates a new line scanner from r 71 | func NewLineScanner(r io.Reader) *LineScanner { 72 | br := bufio.NewReader(r) 73 | ls := &LineScanner{ 74 | Reader: br, 75 | } 76 | return ls 77 | } 78 | 79 | // Scan advances to next line. 80 | func (ls *LineScanner) Scan() bool { 81 | if ls.text, _, ls.err = ls.Reader.ReadLine(); ls.err != nil { 82 | if ls.err == io.EOF { 83 | ls.err = nil 84 | } 85 | return false 86 | } 87 | ls.lnum++ 88 | return true 89 | } 90 | 91 | // Text returns the current line 92 | func (ls *LineScanner) Text() string { 93 | return string(ls.text) 94 | } 95 | 96 | // Err returns the current error (nil if no error) 97 | func (ls *LineScanner) Err() error { 98 | return ls.err 99 | } 100 | 101 | // Line returns the current line number 102 | func (ls *LineScanner) Line() int { 103 | return ls.lnum 104 | } 105 | 106 | // TokenType is the type of token 107 | type TokenType int 108 | 109 | // Token types 110 | const ( 111 | StartToken TokenType = iota 112 | EndToken 113 | SuiteToken 114 | NoFilesToken 115 | BuildFailedToken 116 | ExitToken 117 | DataToken 118 | ) 119 | 120 | // Token is a lex token (line oriented) 121 | type Token struct { 122 | Line int 123 | Type TokenType 124 | Data string 125 | // Error error 126 | } 127 | 128 | func (typ TokenType) String() string { 129 | switch typ { 130 | case StartToken: 131 | return "Start" 132 | case EndToken: 133 | return "End" 134 | case SuiteToken: 135 | return "Suite" 136 | case NoFilesToken: 137 | return "NoFiles" 138 | case BuildFailedToken: 139 | return "BuildFailed" 140 | case DataToken: 141 | return "Data" 142 | case ExitToken: 143 | return "Exit" 144 | } 145 | 146 | return "???" 147 | } 148 | 149 | func (tok *Token) String() string { 150 | return fmt.Sprintf("<%s Token line:%03d>", tok.Type, tok.Line) 151 | } 152 | 153 | // Lexer generates tokens 154 | type Lexer interface { 155 | Scan() bool 156 | Token() *Token 157 | Err() error 158 | } 159 | 160 | var gtTypes = []struct { 161 | typ TokenType 162 | re *regexp.Regexp 163 | }{ 164 | {StartToken, gtStartRE}, 165 | {EndToken, gtEndRE}, 166 | {SuiteToken, gtSuiteRE}, 167 | {NoFilesToken, gtNoFilesRE}, 168 | {BuildFailedToken, gtBuildFailedRE}, 169 | {ExitToken, gtExitRE}, 170 | } 171 | 172 | // GotestLexer is a lexer for gotest output 173 | type GotestLexer struct { 174 | scanner *LineScanner 175 | tok *Token 176 | err error 177 | } 178 | 179 | // Scan scans the next token. Return true if there's a new one 180 | func (lex *GotestLexer) Scan() bool { 181 | if !lex.scanner.Scan() { 182 | return false 183 | } 184 | if lex.scanner.Err() != nil { 185 | return false 186 | } 187 | 188 | line := lex.scanner.Text() 189 | lnum := lex.scanner.Line() 190 | found := false 191 | for _, typ := range gtTypes { 192 | if typ.re.MatchString(line) { 193 | found = true 194 | lex.tok = &Token{lnum, typ.typ, line} 195 | break 196 | } 197 | } 198 | if !found { 199 | lex.tok = &Token{lnum, DataToken, line} 200 | } 201 | 202 | return true 203 | } 204 | 205 | // Token returns the current Token 206 | func (lex *GotestLexer) Token() *Token { 207 | return lex.tok 208 | } 209 | 210 | // Err returns the current error (if any) 211 | func (lex *GotestLexer) Err() error { 212 | if lex.err != nil { 213 | return lex.err 214 | } 215 | return lex.scanner.Err() 216 | } 217 | 218 | // NewGotestLexer returns a new lexer for gotest files 219 | func NewGotestLexer(in io.Reader) Lexer { 220 | return &GotestLexer{ 221 | scanner: NewLineScanner(in), 222 | tok: nil, 223 | err: nil, 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /lib/lex_test.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | const testLog = `{"Packages":[{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/cloudinit","Functions":[{"Name":"ParseOutputLog","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cloudinit/output_log.go","Start":1137,"End":2183,"Statements":[{"Start":1196,"End":2145,"Reached":1},{"Start":1259,"End":1315,"Reached":1},{"Start":1318,"End":1489,"Reached":1},{"Start":1403,"End":1485,"Reached":0},{"Start":1493,"End":1531,"Reached":1},{"Start":1535,"End":1708,"Reached":1},{"Start":1622,"End":1704,"Reached":0},{"Start":1712,"End":1753,"Reached":1},{"Start":1762,"End":1785,"Reached":1},{"Start":1789,"End":1848,"Reached":1},{"Start":1824,"End":1843,"Reached":1},{"Start":1852,"End":1887,"Reached":1},{"Start":1891,"End":1932,"Reached":1},{"Start":1936,"End":1977,"Reached":1},{"Start":1981,"End":2020,"Reached":1},{"Start":2024,"End":2113,"Reached":1},{"Start":2093,"End":2108,"Reached":0},{"Start":2121,"End":2142,"Reached":1},{"Start":2147,"End":2181,"Reached":0}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil","Functions":[{"Name":"New","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":1346,"End":1404,"Statements":[{"Start":1372,"End":1391,"Reached":0},{"Start":1393,"End":1402,"Reached":0}]},{"Name":"DockerUtil.NewCmd","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":1406,"End":4680,"Statements":[{"Start":1453,"End":4666,"Reached":0},{"Start":4668,"End":4678,"Reached":0}]},{"Name":"@75:13","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":2050,"End":2246,"Statements":[{"Start":2086,"End":2125,"Reached":0},{"Start":2131,"End":2170,"Reached":0},{"Start":2153,"End":2163,"Reached":0},{"Start":2176,"End":2223,"Reached":0},{"Start":2230,"End":2240,"Reached":0}]},{"Name":"@97:13","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":2661,"End":3255,"Statements":[{"Start":2737,"End":2767,"Reached":0},{"Start":2773,"End":3233,"Reached":0},{"Start":2831,"End":2841,"Reached":0},{"Start":2854,"End":3233,"Reached":0},{"Start":2873,"End":2946,"Reached":0},{"Start":2953,"End":3092,"Reached":0},{"Start":3023,"End":3084,"Reached":0},{"Start":3099,"End":3155,"Reached":0},{"Start":3176,"End":3226,"Reached":0},{"Start":3239,"End":3249,"Reached":0}]},{"Name":"@127:13","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":3775,"End":3938,"Statements":[{"Start":3811,"End":3916,"Reached":0},{"Start":3844,"End":3909,"Reached":0},{"Start":3922,"End":3932,"Reached":0}]},{"Name":"@147:13","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":4467,"End":4630,"Statements":[{"Start":4503,"End":4608,"Reached":0},{"Start":4536,"End":4601,"Reached":0},{"Start":4614,"End":4624,"Reached":0}]},{"Name":"DockerUtil.Before","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":4744,"End":5149,"Statements":[{"Start":4800,"End":4813,"Reached":0},{"Start":4815,"End":4923,"Reached":0},{"Start":4910,"End":4920,"Reached":0},{"Start":4962,"End":5039,"Reached":0},{"Start":5026,"End":5036,"Reached":0},{"Start":5041,"End":5075,"Reached":0},{"Start":5077,"End":5135,"Reached":0},{"Start":5122,"End":5132,"Reached":0},{"Start":5137,"End":5147,"Reached":0}]},{"Name":"DockerUtil.save","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":5151,"End":6892,"Statements":[{"Start":5205,"End":5331,"Reached":0},{"Start":5246,"End":5328,"Reached":0},{"Start":5334,"End":5370,"Reached":0},{"Start":5372,"End":5403,"Reached":0},{"Start":5390,"End":5400,"Reached":0},{"Start":5406,"End":5608,"Reached":0},{"Start":5611,"End":6570,"Reached":0},{"Start":5642,"End":5664,"Reached":0},{"Start":5667,"End":5728,"Reached":0},{"Start":5731,"End":6567,"Reached":0},{"Start":6573,"End":6627,"Reached":0},{"Start":6630,"End":6653,"Reached":0},{"Start":6656,"End":6725,"Reached":0},{"Start":6712,"End":6722,"Reached":0},{"Start":6728,"End":6752,"Reached":0},{"Start":6755,"End":6877,"Reached":0},{"Start":6880,"End":6890,"Reached":0}]},{"Name":"@198:3","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":5731,"End":6554,"Statements":[{"Start":5767,"End":6521,"Reached":0},{"Start":6525,"End":6550,"Reached":0}]},{"Name":"@199:10","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":5773,"End":6521,"Statements":[{"Start":5792,"End":5814,"Reached":0},{"Start":5819,"End":5925,"Reached":0},{"Start":5861,"End":5919,"Reached":0},{"Start":5882,"End":5912,"Reached":0},{"Start":5930,"End":5994,"Reached":0},{"Start":5999,"End":6448,"Reached":0},{"Start":6020,"End":6397,"Reached":0},{"Start":6128,"End":6265,"Reached":0},{"Start":6272,"End":6290,"Reached":0},{"Start":6297,"End":6320,"Reached":0},{"Start":6327,"End":6390,"Reached":0},{"Start":6403,"End":6442,"Reached":0},{"Start":6425,"End":6435,"Reached":0},{"Start":6453,"End":6462,"Reached":0},{"Start":6467,"End":6485,"Reached":0},{"Start":6490,"End":6501,"Reached":0},{"Start":6506,"End":6516,"Reached":0}]},{"Name":"genHostAllocator","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":7081,"End":7762,"Statements":[{"Start":7145,"End":7233,"Reached":0},{"Start":7320,"End":7730,"Reached":0},{"Start":7733,"End":7760,"Reached":0}]},{"Name":"@254:13","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":7331,"End":7730,"Statements":[{"Start":7360,"End":7373,"Reached":0},{"Start":7376,"End":7385,"Reached":0},{"Start":7388,"End":7659,"Reached":0},{"Start":7431,"End":7440,"Reached":0},{"Start":7444,"End":7470,"Reached":0},{"Start":7474,"End":7485,"Reached":0},{"Start":7489,"End":7590,"Reached":0},{"Start":7502,"End":7516,"Reached":0},{"Start":7521,"End":7530,"Reached":0},{"Start":7535,"End":7559,"Reached":0},{"Start":7564,"End":7575,"Reached":0},{"Start":7580,"End":7585,"Reached":0},{"Start":7594,"End":7655,"Reached":0},{"Start":7624,"End":7638,"Reached":0},{"Start":7643,"End":7650,"Reached":0},{"Start":7662,"End":7671,"Reached":0},{"Start":7674,"End":7696,"Reached":0},{"Start":7699,"End":7710,"Reached":0},{"Start":7713,"End":7727,"Reached":0}]},{"Name":"DockerUtil.retrieve","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":7821,"End":9775,"Statements":[{"Start":7917,"End":8062,"Reached":0},{"Start":8126,"End":8156,"Reached":0},{"Start":8159,"End":8664,"Reached":0},{"Start":8266,"End":8340,"Reached":0},{"Start":8350,"End":8664,"Reached":0},{"Start":8369,"End":8391,"Reached":0},{"Start":8395,"End":8490,"Reached":0},{"Start":8415,"End":8485,"Reached":0},{"Start":8494,"End":8660,"Reached":0},{"Start":8517,"End":8637,"Reached":0},{"Start":8642,"End":8655,"Reached":0},{"Start":8670,"End":8891,"Reached":0},{"Start":8893,"End":8977,"Reached":0},{"Start":8911,"End":8974,"Reached":0},{"Start":8979,"End":9096,"Reached":0},{"Start":9099,"End":9124,"Reached":0},{"Start":9127,"End":9144,"Reached":0},{"Start":9146,"End":9165,"Reached":0},{"Start":9168,"End":9232,"Reached":0},{"Start":9234,"End":9384,"Reached":0},{"Start":9270,"End":9381,"Reached":0},{"Start":9386,"End":9456,"Reached":0},{"Start":9459,"End":9479,"Reached":0},{"Start":9481,"End":9506,"Reached":0},{"Start":9550,"End":9630,"Reached":0},{"Start":9632,"End":9755,"Reached":0},{"Start":9685,"End":9752,"Reached":0},{"Start":9757,"End":9773,"Reached":0}]},{"Name":"@314:8","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":8985,"End":9094,"Statements":[{"Start":8996,"End":9091,"Reached":0},{"Start":9036,"End":9087,"Reached":0}]},{"Name":"DockerUtil.distribute","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":9777,"End":10499,"Statements":[{"Start":9837,"End":9966,"Reached":0},{"Start":9878,"End":9963,"Reached":0},{"Start":9969,"End":10033,"Reached":0},{"Start":10036,"End":10094,"Reached":0},{"Start":10096,"End":10160,"Reached":0},{"Start":10147,"End":10157,"Reached":0},{"Start":10162,"End":10242,"Reached":0},{"Start":10245,"End":10414,"Reached":0},{"Start":10276,"End":10411,"Reached":0},{"Start":10416,"End":10485,"Reached":0},{"Start":10472,"End":10482,"Reached":0},{"Start":10487,"End":10497,"Reached":0}]},{"Name":"@359:3","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":10276,"End":10405,"Statements":[{"Start":10299,"End":10372,"Reached":0},{"Start":10376,"End":10401,"Reached":0}]},{"Name":"@360:10","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":10305,"End":10372,"Statements":[{"Start":10320,"End":10370,"Reached":0}]},{"Name":"DockerUtil.distributeTo","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":10501,"End":10925,"Statements":[{"Start":10574,"End":10637,"Reached":0},{"Start":10639,"End":10777,"Reached":0},{"Start":10779,"End":10911,"Reached":0},{"Start":10831,"End":10908,"Reached":0},{"Start":10913,"End":10923,"Reached":0}]},{"Name":"DockerUtil.load","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":10927,"End":12007,"Statements":[{"Start":10981,"End":11104,"Reached":0},{"Start":11106,"End":11210,"Reached":0},{"Start":11124,"End":11207,"Reached":0},{"Start":11250,"End":11270,"Reached":0},{"Start":11273,"End":11391,"Reached":0},{"Start":11303,"End":11387,"Reached":0},{"Start":11350,"End":11382,"Reached":0},{"Start":11394,"End":11409,"Reached":0},{"Start":11415,"End":11922,"Reached":0},{"Start":11446,"End":11919,"Reached":0},{"Start":11924,"End":11993,"Reached":0},{"Start":11980,"End":11990,"Reached":0},{"Start":11995,"End":12005,"Reached":0}]},{"Name":"@401:3","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":11446,"End":11913,"Statements":[{"Start":11469,"End":11880,"Reached":0},{"Start":11884,"End":11909,"Reached":0}]},{"Name":"@402:10","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":11475,"End":11880,"Statements":[{"Start":11494,"End":11511,"Reached":0},{"Start":11516,"End":11843,"Reached":0},{"Start":11548,"End":11837,"Reached":0},{"Start":11628,"End":11652,"Reached":0},{"Start":11659,"End":11729,"Reached":0},{"Start":11750,"End":11830,"Reached":0},{"Start":11848,"End":11875,"Reached":0}]},{"Name":"DockerUtil.loadTo","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":12086,"End":14409,"Statements":[{"Start":12163,"End":12215,"Reached":0},{"Start":12218,"End":12351,"Reached":0},{"Start":12353,"End":12466,"Reached":0},{"Start":12388,"End":12426,"Reached":0},{"Start":12429,"End":12445,"Reached":0},{"Start":12448,"End":12463,"Reached":0},{"Start":12578,"End":12617,"Reached":0},{"Start":12620,"End":12705,"Reached":0},{"Start":12639,"End":12701,"Reached":0},{"Start":12708,"End":12926,"Reached":0},{"Start":12742,"End":12922,"Reached":0},{"Start":12783,"End":12917,"Reached":0},{"Start":12813,"End":12895,"Reached":0},{"Start":12901,"End":12911,"Reached":0},{"Start":12932,"End":12992,"Reached":0},{"Start":12995,"End":13367,"Reached":0},{"Start":13370,"End":13389,"Reached":0},{"Start":13391,"End":13410,"Reached":0},{"Start":13413,"End":13547,"Reached":0},{"Start":13449,"End":13544,"Reached":0},{"Start":13550,"End":13602,"Reached":0},{"Start":13604,"End":13739,"Reached":0},{"Start":13622,"End":13736,"Reached":0},{"Start":13741,"End":13751,"Reached":0},{"Start":13754,"End":13836,"Reached":0},{"Start":13838,"End":13878,"Reached":0},{"Start":13881,"End":14047,"Reached":0},{"Start":13936,"End":14044,"Reached":0},{"Start":14092,"End":14156,"Reached":0},{"Start":14159,"End":14332,"Reached":0},{"Start":14214,"End":14329,"Reached":0},{"Start":14335,"End":14395,"Reached":0},{"Start":14397,"End":14407,"Reached":0}]},{"Name":"DockerUtil.findDockerImages","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":14484,"End":15472,"Statements":[{"Start":14562,"End":14640,"Reached":0},{"Start":14642,"End":15320,"Reached":0},{"Start":14686,"End":15317,"Reached":0},{"Start":14799,"End":15313,"Reached":0},{"Start":15323,"End":15452,"Reached":0},{"Start":15379,"End":15449,"Reached":0},{"Start":15455,"End":15470,"Reached":0}]},{"Name":"@506:4","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":14799,"End":15310,"Statements":[{"Start":14827,"End":15275,"Reached":0},{"Start":15280,"End":15305,"Reached":0}]},{"Name":"@507:11","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":14833,"End":15275,"Statements":[{"Start":14853,"End":14956,"Reached":0},{"Start":14962,"End":15016,"Reached":0},{"Start":15022,"End":15148,"Reached":0},{"Start":15044,"End":15141,"Reached":0},{"Start":15154,"End":15163,"Reached":0},{"Start":15169,"End":15236,"Reached":0},{"Start":15198,"End":15229,"Reached":0},{"Start":15242,"End":15253,"Reached":0},{"Start":15259,"End":15269,"Reached":0}]},{"Name":"DockerUtil.checkCloudInit","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":15474,"End":16457,"Statements":[{"Start":15535,"End":15560,"Reached":0},{"Start":15562,"End":16372,"Reached":0},{"Start":15593,"End":16369,"Reached":0},{"Start":16374,"End":16443,"Reached":0},{"Start":16430,"End":16440,"Reached":0},{"Start":16445,"End":16455,"Reached":0}]},{"Name":"@535:3","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":15593,"End":16363,"Statements":[{"Start":15616,"End":16330,"Reached":0},{"Start":16334,"End":16359,"Reached":0}]},{"Name":"@536:10","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":15622,"End":16330,"Statements":[{"Start":15641,"End":15788,"Reached":0},{"Start":15794,"End":15813,"Reached":0},{"Start":15818,"End":15837,"Reached":0},{"Start":15843,"End":15995,"Reached":0},{"Start":15882,"End":15989,"Reached":0},{"Start":16000,"End":16053,"Reached":0},{"Start":16058,"End":16156,"Reached":0},{"Start":16079,"End":16150,"Reached":0},{"Start":16161,"End":16310,"Reached":0},{"Start":16196,"End":16304,"Reached":0},{"Start":16315,"End":16325,"Reached":0}]},{"Name":"cleanImageName","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":16545,"End":16663,"Statements":[{"Start":16588,"End":16661,"Reached":0}]},{"Name":"restoreImageName","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/dockerutil.go","Start":16746,"End":16868,"Statements":[{"Start":16792,"End":16866,"Reached":0}]},{"Name":"NewImageSet","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":432,"End":496,"Statements":[{"Start":464,"End":482,"Reached":3},{"Start":484,"End":494,"Reached":3}]},{"Name":"ImageSet.Add","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":562,"End":871,"Statements":[{"Start":622,"End":726,"Reached":10},{"Start":653,"End":723,"Reached":9},{"Start":683,"End":709,"Reached":5},{"Start":713,"End":719,"Reached":5},{"Start":728,"End":841,"Reached":5},{"Start":843,"End":869,"Reached":5}]},{"Name":"ImageSet.Remove","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":968,"End":1188,"Statements":[{"Start":1016,"End":1038,"Reached":3},{"Start":1041,"End":1168,"Reached":3},{"Start":1072,"End":1165,"Reached":4},{"Start":1127,"End":1161,"Reached":2},{"Start":1171,"End":1186,"Reached":3}]},{"Name":"ImageSet.Contains","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":1334,"End":1509,"Statements":[{"Start":1389,"End":1493,"Reached":8},{"Start":1420,"End":1490,"Reached":15},{"Start":1475,"End":1486,"Reached":2},{"Start":1495,"End":1507,"Reached":6}]},{"Name":"ImageSet.Find","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":1608,"End":1790,"Statements":[{"Start":1653,"End":1776,"Reached":18},{"Start":1683,"End":1773,"Reached":12},{"Start":1756,"End":1769,"Reached":6},{"Start":1778,"End":1788,"Reached":12}]},{"Name":"ImageSet.IDs","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":1854,"End":2020,"Statements":[{"Start":1892,"End":1926,"Reached":0},{"Start":1928,"End":1981,"Reached":0},{"Start":1958,"End":1978,"Reached":0},{"Start":1983,"End":2003,"Reached":0},{"Start":2005,"End":2018,"Reached":0}]},{"Name":"ImageSet.Names","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":2086,"End":2256,"Statements":[{"Start":2126,"End":2160,"Reached":0},{"Start":2162,"End":2217,"Reached":0},{"Start":2192,"End":2214,"Reached":0},{"Start":2219,"End":2239,"Reached":0},{"Start":2241,"End":2254,"Reached":0}]},{"Name":"ImageSet.ContainerIDs","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/cmd/dockerutil/image.go","Start":2339,"End":2569,"Statements":[{"Start":2386,"End":2406,"Reached":0},{"Start":2408,"End":2530,"Reached":0},{"Start":2438,"End":2527,"Reached":0},{"Start":2486,"End":2523,"Reached":0},{"Start":2532,"End":2552,"Reached":0},{"Start":2554,"End":2567,"Reached":0}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/iamlib","Functions":[{"Name":"doDestructiveAction","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/destruct.go","Start":128,"End":790,"Statements":[{"Start":223,"End":259,"Reached":0},{"Start":261,"End":292,"Reached":0},{"Start":279,"End":289,"Reached":0},{"Start":294,"End":326,"Reached":0},{"Start":328,"End":359,"Reached":0},{"Start":346,"End":356,"Reached":0},{"Start":378,"End":413,"Reached":0},{"Start":415,"End":446,"Reached":0},{"Start":449,"End":776,"Reached":0},{"Start":512,"End":773,"Reached":0},{"Start":541,"End":577,"Reached":0},{"Start":581,"End":672,"Reached":0},{"Start":614,"End":667,"Reached":0},{"Start":676,"End":710,"Reached":0},{"Start":725,"End":769,"Reached":0},{"Start":778,"End":788,"Reached":0}]},{"Name":"confirmActionStd","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/destruct.go","Start":792,"End":925,"Statements":[{"Start":853,"End":908,"Reached":0},{"Start":910,"End":923,"Reached":0}]},{"Name":"confirmAction","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/destruct.go","Start":1136,"End":1805,"Statements":[{"Start":1220,"End":1257,"Reached":0},{"Start":1243,"End":1254,"Reached":0},{"Start":1259,"End":1803,"Reached":0},{"Start":1267,"End":1336,"Reached":0},{"Start":1339,"End":1367,"Reached":0},{"Start":1370,"End":1800,"Reached":0},{"Start":1428,"End":1497,"Reached":0},{"Start":1512,"End":1550,"Reached":0},{"Start":1554,"End":1796,"Reached":0},{"Start":1592,"End":1603,"Reached":0},{"Start":1614,"End":1796,"Reached":0},{"Start":1652,"End":1689,"Reached":0},{"Start":1694,"End":1706,"Reached":0},{"Start":1723,"End":1791,"Reached":0}]},{"Name":"Groups.Load","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":202,"End":484,"Statements":[{"Start":255,"End":437,"Reached":0},{"Start":439,"End":470,"Reached":0},{"Start":457,"End":467,"Reached":0},{"Start":472,"End":482,"Reached":0}]},{"Name":"@18:56","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":309,"End":436,"Statements":[{"Start":368,"End":419,"Reached":0},{"Start":422,"End":433,"Reached":0}]},{"Name":"Groups.String","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":486,"End":716,"Statements":[{"Start":526,"End":562,"Reached":0},{"Start":564,"End":641,"Reached":0},{"Start":611,"End":638,"Reached":0},{"Start":643,"End":662,"Reached":0},{"Start":664,"End":699,"Reached":0},{"Start":701,"End":714,"Reached":0}]},{"Name":"Groups.Filter","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":717,"End":1056,"Statements":[{"Start":773,"End":872,"Reached":0},{"Start":874,"End":905,"Reached":0},{"Start":892,"End":902,"Reached":0},{"Start":907,"End":1023,"Reached":0},{"Start":941,"End":1020,"Reached":0},{"Start":984,"End":1016,"Reached":0},{"Start":1025,"End":1042,"Reached":0},{"Start":1044,"End":1054,"Reached":0}]},{"Name":"Groups.Destroy","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":1058,"End":1875,"Statements":[{"Start":1131,"End":1249,"Reached":0},{"Start":1193,"End":1246,"Reached":0},{"Start":1252,"End":1298,"Reached":0},{"Start":1301,"End":1861,"Reached":0},{"Start":1334,"End":1822,"Reached":0},{"Start":1825,"End":1858,"Reached":0},{"Start":1844,"End":1854,"Reached":0},{"Start":1863,"End":1873,"Reached":0}]},{"Name":"@62:89","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":1420,"End":1821,"Statements":[{"Start":1437,"End":1542,"Reached":0},{"Start":1546,"End":1803,"Reached":0},{"Start":1566,"End":1798,"Reached":0},{"Start":1648,"End":1741,"Reached":0},{"Start":1724,"End":1734,"Reached":0},{"Start":1747,"End":1763,"Reached":0},{"Start":1782,"End":1792,"Reached":0},{"Start":1807,"End":1817,"Reached":0}]},{"Name":"Groups.detachGroupPolicies","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":1877,"End":3484,"Statements":[{"Start":1988,"End":2095,"Reached":0},{"Start":2098,"End":2716,"Reached":0},{"Start":2719,"End":2752,"Reached":0},{"Start":2738,"End":2748,"Reached":0},{"Start":2762,"End":2861,"Reached":0},{"Start":2864,"End":3430,"Reached":0},{"Start":3433,"End":3466,"Reached":0},{"Start":3452,"End":3462,"Reached":0},{"Start":3472,"End":3482,"Reached":0}]},{"Name":"@95:54","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":2149,"End":2715,"Statements":[{"Start":2224,"End":2690,"Reached":0},{"Start":2285,"End":2648,"Reached":0},{"Start":2653,"End":2685,"Reached":0},{"Start":2674,"End":2679,"Reached":0},{"Start":2694,"End":2711,"Reached":0}]},{"Name":"@97:132","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":2412,"End":2647,"Statements":[{"Start":2432,"End":2580,"Reached":0},{"Start":2586,"End":2625,"Reached":0},{"Start":2608,"End":2618,"Reached":0},{"Start":2631,"End":2641,"Reached":0}]},{"Name":"@125:46","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":2907,"End":3429,"Statements":[{"Start":2974,"End":3404,"Reached":0},{"Start":3026,"End":3362,"Reached":0},{"Start":3367,"End":3399,"Reached":0},{"Start":3388,"End":3393,"Reached":0},{"Start":3408,"End":3425,"Reached":0}]},{"Name":"@127:117","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/groups.go","Start":3138,"End":3361,"Statements":[{"Start":3158,"End":3294,"Reached":0},{"Start":3300,"End":3339,"Reached":0},{"Start":3322,"End":3332,"Reached":0},{"Start":3345,"End":3355,"Reached":0}]},{"Name":"Policies.Load","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":205,"End":592,"Statements":[{"Start":305,"End":501,"Reached":0},{"Start":503,"End":534,"Reached":0},{"Start":521,"End":531,"Reached":0},{"Start":580,"End":590,"Reached":0}]},{"Name":"@19:60","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":363,"End":500,"Statements":[{"Start":424,"End":483,"Reached":0},{"Start":486,"End":497,"Reached":0}]},{"Name":"Policies.String","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":594,"End":836,"Statements":[{"Start":638,"End":676,"Reached":0},{"Start":678,"End":761,"Reached":0},{"Start":729,"End":758,"Reached":0},{"Start":763,"End":782,"Reached":0},{"Start":784,"End":819,"Reached":0},{"Start":821,"End":834,"Reached":0}]},{"Name":"Policies.Filter","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":838,"End":1195,"Statements":[{"Start":898,"End":1003,"Reached":0},{"Start":1005,"End":1036,"Reached":0},{"Start":1023,"End":1033,"Reached":0},{"Start":1038,"End":1160,"Reached":0},{"Start":1075,"End":1157,"Reached":0},{"Start":1120,"End":1153,"Reached":0},{"Start":1162,"End":1181,"Reached":0},{"Start":1183,"End":1193,"Reached":0}]},{"Name":"Policies.Destroy","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":1197,"End":2290,"Statements":[{"Start":1274,"End":1394,"Reached":0},{"Start":1336,"End":1391,"Reached":0},{"Start":1397,"End":1447,"Reached":0},{"Start":1450,"End":2276,"Reached":0},{"Start":1486,"End":2273,"Reached":0},{"Start":1515,"End":1639,"Reached":0},{"Start":1552,"End":1634,"Reached":0},{"Start":1618,"End":1628,"Reached":0},{"Start":1673,"End":1761,"Reached":0},{"Start":1746,"End":1756,"Reached":0},{"Start":1765,"End":2167,"Reached":0},{"Start":1875,"End":1963,"Reached":0},{"Start":1968,"End":2080,"Reached":0},{"Start":1989,"End":2058,"Reached":0},{"Start":2064,"End":2074,"Reached":0},{"Start":2085,"End":2162,"Reached":0},{"Start":2182,"End":2269,"Reached":0},{"Start":2278,"End":2288,"Reached":0}]},{"Name":"Policies.deleteVersions","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":2292,"End":3143,"Statements":[{"Start":2396,"End":2486,"Reached":0},{"Start":2488,"End":3096,"Reached":0},{"Start":3098,"End":3129,"Reached":0},{"Start":3116,"End":3126,"Reached":0},{"Start":3131,"End":3141,"Reached":0}]},{"Name":"@99:46","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":2532,"End":3095,"Statements":[{"Start":2599,"End":3072,"Reached":0},{"Start":2644,"End":3068,"Reached":0},{"Start":2680,"End":3026,"Reached":0},{"Start":3031,"End":3063,"Reached":0},{"Start":3052,"End":3057,"Reached":0},{"Start":3075,"End":3092,"Reached":0}]},{"Name":"@102:123","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":2798,"End":3025,"Statements":[{"Start":2818,"End":2958,"Reached":0},{"Start":2964,"End":3003,"Reached":0},{"Start":2986,"End":2996,"Reached":0},{"Start":3009,"End":3019,"Reached":0}]},{"Name":"Policies.detach","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":3145,"End":4763,"Statements":[{"Start":3241,"End":3334,"Reached":0},{"Start":3336,"End":4716,"Reached":0},{"Start":4718,"End":4749,"Reached":0},{"Start":4736,"End":4746,"Reached":0},{"Start":4751,"End":4761,"Reached":0}]},{"Name":"@132:49","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":3383,"End":4715,"Statements":[{"Start":3453,"End":3870,"Reached":0},{"Start":3500,"End":3832,"Reached":0},{"Start":3836,"End":3866,"Reached":0},{"Start":3856,"End":3861,"Reached":0},{"Start":3873,"End":4281,"Reached":0},{"Start":3918,"End":4243,"Reached":0},{"Start":4247,"End":4277,"Reached":0},{"Start":4267,"End":4272,"Reached":0},{"Start":4284,"End":4692,"Reached":0},{"Start":4329,"End":4654,"Reached":0},{"Start":4658,"End":4688,"Reached":0},{"Start":4678,"End":4683,"Reached":0},{"Start":4695,"End":4712,"Reached":0}]},{"Name":"@134:123","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":3619,"End":3831,"Statements":[{"Start":3638,"End":3769,"Reached":0},{"Start":3774,"End":3811,"Reached":0},{"Start":3795,"End":3805,"Reached":0},{"Start":3816,"End":3826,"Reached":0}]},{"Name":"@149:120","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":4034,"End":4242,"Statements":[{"Start":4053,"End":4180,"Reached":0},{"Start":4185,"End":4222,"Reached":0},{"Start":4206,"End":4216,"Reached":0},{"Start":4227,"End":4237,"Reached":0}]},{"Name":"@164:120","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policies.go","Start":4445,"End":4653,"Statements":[{"Start":4464,"End":4591,"Reached":0},{"Start":4596,"End":4633,"Reached":0},{"Start":4617,"End":4627,"Reached":0},{"Start":4638,"End":4648,"Reached":0}]},{"Name":"PolicyARNLookup.Init","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/policy_arn_lookup.go","Start":156,"End":553,"Statements":[{"Start":220,"End":270,"Reached":0},{"Start":257,"End":267,"Reached":0},{"Start":272,"End":314,"Reached":0},{"Start":316,"End":347,"Reached":0},{"Start":349,"End":419,"Reached":0},{"Start":406,"End":416,"Reached":0},{"Start":421,"End":539,"Reached":0},{"Start":482,"End":536,"Reached":0},{"Start":541,"End":551,"Reached":0}]},{"Name":"Roles.Load","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":200,"End":473,"Statements":[{"Start":251,"End":426,"Reached":0},{"Start":428,"End":459,"Reached":0},{"Start":446,"End":456,"Reached":0},{"Start":461,"End":471,"Reached":0}]},{"Name":"@18:54","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":303,"End":425,"Statements":[{"Start":361,"End":408,"Reached":0},{"Start":411,"End":422,"Reached":0}]},{"Name":"Roles.String","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":474,"End":696,"Statements":[{"Start":512,"End":547,"Reached":0},{"Start":549,"End":621,"Reached":0},{"Start":593,"End":618,"Reached":0},{"Start":623,"End":642,"Reached":0},{"Start":644,"End":679,"Reached":0},{"Start":681,"End":694,"Reached":0}]},{"Name":"Roles.Filter","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":697,"End":1025,"Statements":[{"Start":751,"End":847,"Reached":0},{"Start":849,"End":880,"Reached":0},{"Start":867,"End":877,"Reached":0},{"Start":882,"End":993,"Reached":0},{"Start":914,"End":990,"Reached":0},{"Start":955,"End":986,"Reached":0},{"Start":995,"End":1011,"Reached":0},{"Start":1013,"End":1023,"Reached":0}]},{"Name":"Roles.Destroy","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":1027,"End":1939,"Statements":[{"Start":1098,"End":1215,"Reached":0},{"Start":1160,"End":1212,"Reached":0},{"Start":1218,"End":1262,"Reached":0},{"Start":1265,"End":1925,"Reached":0},{"Start":1296,"End":1320,"Reached":0},{"Start":1324,"End":1886,"Reached":0},{"Start":1889,"End":1922,"Reached":0},{"Start":1908,"End":1918,"Reached":0},{"Start":1927,"End":1937,"Reached":0}]},{"Name":"@63:86","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":1407,"End":1885,"Statements":[{"Start":1424,"End":1523,"Reached":0},{"Start":1527,"End":1828,"Reached":0},{"Start":1547,"End":1823,"Reached":0},{"Start":1649,"End":1739,"Reached":0},{"Start":1722,"End":1732,"Reached":0},{"Start":1745,"End":1767,"Reached":0},{"Start":1773,"End":1788,"Reached":0},{"Start":1807,"End":1817,"Reached":0},{"Start":1832,"End":1867,"Reached":0},{"Start":1852,"End":1862,"Reached":0},{"Start":1871,"End":1881,"Reached":0}]},{"Name":"Roles.detachRolePolicies","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":1941,"End":4564,"Statements":[{"Start":2065,"End":2168,"Reached":0},{"Start":2171,"End":2231,"Reached":0},{"Start":2234,"End":2907,"Reached":0},{"Start":2910,"End":2943,"Reached":0},{"Start":2929,"End":2939,"Reached":0},{"Start":2974,"End":3069,"Reached":0},{"Start":3072,"End":3676,"Reached":0},{"Start":3679,"End":3712,"Reached":0},{"Start":3698,"End":3708,"Reached":0},{"Start":3745,"End":3851,"Reached":0},{"Start":3854,"End":4510,"Reached":0},{"Start":4513,"End":4546,"Reached":0},{"Start":4532,"End":4542,"Reached":0},{"Start":4552,"End":4562,"Reached":0}]},{"Name":"@101:53","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":2284,"End":2906,"Statements":[{"Start":2358,"End":2881,"Reached":0},{"Start":2419,"End":2839,"Reached":0},{"Start":2844,"End":2876,"Reached":0},{"Start":2865,"End":2870,"Reached":0},{"Start":2885,"End":2902,"Reached":0}]},{"Name":"@103:137","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":2551,"End":2838,"Statements":[{"Start":2571,"End":2621,"Reached":0},{"Start":2627,"End":2771,"Reached":0},{"Start":2777,"End":2816,"Reached":0},{"Start":2799,"End":2809,"Reached":0},{"Start":2822,"End":2832,"Reached":0}]},{"Name":"@133:45","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":3114,"End":3675,"Statements":[{"Start":3180,"End":3650,"Reached":0},{"Start":3232,"End":3267,"Reached":0},{"Start":3272,"End":3608,"Reached":0},{"Start":3613,"End":3645,"Reached":0},{"Start":3634,"End":3639,"Reached":0},{"Start":3654,"End":3671,"Reached":0}]},{"Name":"@136:121","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":3388,"End":3607,"Statements":[{"Start":3408,"End":3540,"Reached":0},{"Start":3546,"End":3585,"Reached":0},{"Start":3568,"End":3578,"Reached":0},{"Start":3591,"End":3601,"Reached":0}]},{"Name":"@165:56","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":3907,"End":4509,"Statements":[{"Start":3984,"End":4484,"Reached":0},{"Start":4046,"End":4479,"Reached":0},{"Start":4488,"End":4505,"Reached":0}]},{"Name":"@167:149","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/roles.go","Start":4190,"End":4478,"Statements":[{"Start":4210,"End":4411,"Reached":0},{"Start":4417,"End":4456,"Reached":0},{"Start":4439,"End":4449,"Reached":0},{"Start":4462,"End":4472,"Reached":0}]},{"Name":"activeTense","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/string_manip.go","Start":79,"End":274,"Statements":[{"Start":128,"End":180,"Reached":2},{"Start":182,"End":217,"Reached":2},{"Start":200,"End":214,"Reached":0},{"Start":219,"End":255,"Reached":2},{"Start":257,"End":272,"Reached":2}]},{"Name":"pastTense","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/string_manip.go","Start":276,"End":468,"Statements":[{"Start":323,"End":375,"Reached":2},{"Start":377,"End":412,"Reached":2},{"Start":395,"End":409,"Reached":0},{"Start":414,"End":449,"Reached":2},{"Start":451,"End":466,"Reached":2}]},{"Name":"capitalize","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/iamlib/string_manip.go","Start":470,"End":668,"Statements":[{"Start":506,"End":666,"Reached":4},{"Start":533,"End":541,"Reached":1},{"Start":553,"End":578,"Reached":1},{"Start":591,"End":663,"Reached":2}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/ldifs","Functions":[{"Name":"LDIFApplicator.Apply","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/ldifs/add_to_mesos_container.go","Start":237,"End":318,"Statements":[{"Start":285,"End":302,"Reached":0},{"Start":305,"End":316,"Reached":0}]},{"Name":"NewChangeTypeInjector","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/ldifs/change_type_injector.go","Start":321,"End":527,"Statements":[{"Start":403,"End":508,"Reached":5},{"Start":510,"End":525,"Reached":5}]},{"Name":"ChangeTypeInjector.Read","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/ldifs/change_type_injector.go","Start":529,"End":1489,"Statements":[{"Start":597,"End":633,"Reached":189},{"Start":617,"End":630,"Reached":0},{"Start":636,"End":651,"Reached":189},{"Start":654,"End":787,"Reached":189},{"Start":684,"End":711,"Reached":12},{"Start":714,"End":734,"Reached":12},{"Start":737,"End":784,"Reached":12},{"Start":790,"End":833,"Reached":189},{"Start":836,"End":867,"Reached":189},{"Start":870,"End":1071,"Reached":189},{"Start":914,"End":988,"Reached":8},{"Start":959,"End":984,"Reached":1},{"Start":991,"End":1068,"Reached":8},{"Start":1074,"End":1192,"Reached":189},{"Start":1195,"End":1206,"Reached":189},{"Start":1208,"End":1359,"Reached":189},{"Start":1277,"End":1305,"Reached":12},{"Start":1308,"End":1356,"Reached":12},{"Start":1361,"End":1472,"Reached":189},{"Start":1460,"End":1469,"Reached":0},{"Start":1474,"End":1487,"Reached":189}]},{"Name":"@55:10","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/ldifs/change_type_injector.go","Start":1082,"End":1192,"Statements":[{"Start":1097,"End":1106,"Reached":189},{"Start":1109,"End":1178,"Reached":189},{"Start":1159,"End":1174,"Reached":205101},{"Start":1181,"End":1189,"Reached":189}]},{"Name":"Split","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/ldifs/split.go","Start":51,"End":833,"Statements":[{"Start":111,"End":147,"Reached":5},{"Start":149,"End":175,"Reached":5},{"Start":178,"End":694,"Reached":5},{"Start":186,"End":227,"Reached":207},{"Start":230,"End":300,"Reached":207},{"Start":249,"End":282,"Reached":4},{"Start":272,"End":277,"Reached":4},{"Start":286,"End":296,"Reached":0},{"Start":342,"End":524,"Reached":203},{"Start":386,"End":442,"Reached":2},{"Start":427,"End":437,"Reached":1},{"Start":446,"End":461,"Reached":1},{"Start":471,"End":524,"Reached":201},{"Start":512,"End":520,"Reached":3},{"Start":527,"End":624,"Reached":199},{"Start":553,"End":620,"Reached":193},{"Start":605,"End":615,"Reached":0},{"Start":627,"End":691,"Reached":199},{"Start":677,"End":687,"Reached":0},{"Start":697,"End":818,"Reached":4},{"Start":795,"End":815,"Reached":3},{"Start":821,"End":831,"Reached":4}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/mesos","Functions":[{"Name":"File.Name","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/file.go","Start":402,"End":488,"Statements":[{"Start":436,"End":473,"Reached":0},{"Start":475,"End":486,"Reached":0}]},{"Name":"Files.String","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/file.go","Start":490,"End":645,"Statements":[{"Start":528,"End":559,"Reached":0},{"Start":561,"End":613,"Reached":0},{"Start":592,"End":610,"Reached":0},{"Start":615,"End":643,"Reached":0}]},{"Name":"Resources.Add","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/resources.go","Start":15,"End":282,"Statements":[{"Start":75,"End":280,"Reached":0}]},{"Name":"Task.Uptime","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/task.go","Start":141,"End":397,"Statements":[{"Start":184,"End":385,"Reached":3},{"Start":225,"End":382,"Reached":2},{"Start":266,"End":316,"Reached":1},{"Start":320,"End":361,"Reached":1},{"Start":365,"End":378,"Reached":1},{"Start":387,"End":395,"Reached":2}]},{"Name":"TaskStates","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/task_state.go","Start":619,"End":979,"Statements":[{"Start":649,"End":958,"Reached":0},{"Start":960,"End":977,"Reached":0}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil","Functions":[{"Name":"NewAutoDiscoveryAddressesProvider","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/auto_discovery_addresses_provider.go","Start":578,"End":857,"Statements":[{"Start":681,"End":844,"Reached":0},{"Start":846,"End":855,"Reached":0}]},{"Name":"AutoDiscoveryAddressesProvider.Addresses","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/auto_discovery_addresses_provider.go","Start":989,"End":2516,"Statements":[{"Start":1063,"End":1232,"Reached":0},{"Start":1235,"End":1329,"Reached":0},{"Start":1266,"End":1326,"Reached":0},{"Start":1332,"End":1358,"Reached":0},{"Start":1361,"End":2452,"Reached":0},{"Start":1408,"End":2449,"Reached":0},{"Start":2455,"End":2464,"Reached":0},{"Start":2467,"End":2494,"Reached":0},{"Start":2497,"End":2514,"Reached":0}]},{"Name":"@52:6","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/auto_discovery_addresses_provider.go","Start":1411,"End":2435,"Statements":[{"Start":1442,"End":1457,"Reached":0},{"Start":1462,"End":1517,"Reached":0},{"Start":1521,"End":1611,"Reached":0},{"Start":1541,"End":1550,"Reached":0},{"Start":1555,"End":1579,"Reached":0},{"Start":1584,"End":1595,"Reached":0},{"Start":1600,"End":1606,"Reached":0},{"Start":1616,"End":1643,"Reached":0},{"Start":1647,"End":1801,"Reached":0},{"Start":1690,"End":1796,"Reached":0},{"Start":1760,"End":1779,"Reached":0},{"Start":1785,"End":1790,"Reached":0},{"Start":1805,"End":2227,"Reached":0},{"Start":1828,"End":1837,"Reached":0},{"Start":1842,"End":1952,"Reached":0},{"Start":1957,"End":1968,"Reached":0},{"Start":1973,"End":1979,"Reached":0},{"Start":1990,"End":2227,"Reached":0},{"Start":2041,"End":2050,"Reached":0},{"Start":2055,"End":2195,"Reached":0},{"Start":2200,"End":2211,"Reached":0},{"Start":2216,"End":2222,"Reached":0},{"Start":2232,"End":2431,"Reached":0},{"Start":2294,"End":2360,"Reached":0},{"Start":2365,"End":2374,"Reached":0},{"Start":2379,"End":2410,"Reached":0},{"Start":2415,"End":2426,"Reached":0}]},{"Name":"Capacity.Remaining","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/capacity.go","Start":528,"End":842,"Statements":[{"Start":584,"End":822,"Reached":1},{"Start":824,"End":840,"Reached":1}]},{"Name":"Capacities.Slice","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/capacity.go","Start":1007,"End":1259,"Statements":[{"Start":1065,"End":1093,"Reached":0},{"Start":1095,"End":1243,"Reached":0},{"Start":1141,"End":1212,"Reached":0},{"Start":1215,"End":1240,"Reached":0},{"Start":1245,"End":1257,"Reached":0}]},{"Name":"Capacities.RenderHTML","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/capacity.go","Start":1303,"End":1503,"Statements":[{"Start":1364,"End":1386,"Reached":0},{"Start":1388,"End":1475,"Reached":0},{"Start":1458,"End":1472,"Reached":0},{"Start":1477,"End":1501,"Reached":0}]},{"Name":"Capacities.RenderASCII","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/capacity.go","Start":1556,"End":1889,"Statements":[{"Start":1618,"End":1640,"Reached":0},{"Start":1642,"End":1729,"Reached":0},{"Start":1712,"End":1726,"Reached":0},{"Start":1731,"End":1785,"Reached":0},{"Start":1787,"End":1833,"Reached":0},{"Start":1835,"End":1870,"Reached":0},{"Start":1853,"End":1867,"Reached":0},{"Start":1872,"End":1887,"Reached":0}]},{"Name":"NodeMembershipType","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/node_membership_type.go","Start":201,"End":502,"Statements":[{"Start":256,"End":482,"Reached":0},{"Start":310,"End":329,"Reached":0},{"Start":338,"End":482,"Reached":0},{"Start":389,"End":405,"Reached":0},{"Start":414,"End":482,"Reached":0},{"Start":464,"End":479,"Reached":0},{"Start":484,"End":500,"Reached":0}]},{"Name":"NewStateCollector","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":1260,"End":1883,"Statements":[{"Start":1417,"End":1459,"Reached":0},{"Start":1462,"End":1605,"Reached":0},{"Start":1502,"End":1546,"Reached":0},{"Start":1559,"End":1602,"Reached":0},{"Start":1608,"End":1870,"Reached":0},{"Start":1872,"End":1881,"Reached":0}]},{"Name":"StateCollector.Refresh","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":1949,"End":2183,"Statements":[{"Start":1994,"End":2181,"Reached":0}]},{"Name":"@72:22","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":2014,"End":2180,"Statements":[{"Start":2031,"End":2096,"Reached":0},{"Start":2082,"End":2092,"Reached":0},{"Start":2099,"End":2164,"Reached":0},{"Start":2150,"End":2160,"Reached":0},{"Start":2167,"End":2177,"Reached":0}]},{"Name":"StateCollector.RefreshSlaveStates","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":2297,"End":2956,"Statements":[{"Start":2353,"End":2954,"Reached":0}]},{"Name":"@86:22","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":2373,"End":2953,"Statements":[{"Start":2390,"End":2442,"Reached":0},{"Start":2446,"End":2480,"Reached":0},{"Start":2484,"End":2859,"Reached":0},{"Start":2533,"End":2855,"Reached":0},{"Start":2862,"End":2871,"Reached":0},{"Start":2875,"End":2937,"Reached":0},{"Start":2923,"End":2933,"Reached":0},{"Start":2940,"End":2950,"Reached":0}]},{"Name":"@95:7","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":2536,"End":2848,"Statements":[{"Start":2566,"End":2581,"Reached":0},{"Start":2587,"End":2653,"Reached":0},{"Start":2659,"End":2699,"Reached":0},{"Start":2704,"End":2716,"Reached":0},{"Start":2721,"End":2824,"Reached":0},{"Start":2742,"End":2775,"Reached":0},{"Start":2794,"End":2818,"Reached":0},{"Start":2829,"End":2843,"Reached":0}]},{"Name":"StateCollector.RefreshMasterState","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":3071,"End":3897,"Statements":[{"Start":3127,"End":3171,"Reached":0},{"Start":3173,"End":3285,"Reached":0},{"Start":3272,"End":3282,"Reached":0},{"Start":3288,"End":3895,"Reached":0}]},{"Name":"@128:22","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":3308,"End":3894,"Statements":[{"Start":3325,"End":3433,"Reached":0},{"Start":3437,"End":3663,"Reached":0},{"Start":3469,"End":3659,"Reached":0},{"Start":3667,"End":3891,"Reached":0},{"Start":3676,"End":3887,"Reached":0},{"Start":3720,"End":3742,"Reached":0},{"Start":3747,"End":3757,"Reached":0},{"Start":3789,"End":3882,"Reached":0},{"Start":3849,"End":3876,"Reached":0}]},{"Name":"@136:7","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":3472,"End":3653,"Statements":[{"Start":3497,"End":3533,"Reached":0},{"Start":3538,"End":3624,"Reached":0},{"Start":3559,"End":3606,"Reached":0},{"Start":3612,"End":3618,"Reached":0},{"Start":3629,"End":3648,"Reached":0}]},{"Name":"StateCollector.mesosStateFor","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":3966,"End":4609,"Statements":[{"Start":4048,"End":4063,"Reached":0},{"Start":4065,"End":4097,"Reached":0},{"Start":4082,"End":4094,"Reached":0},{"Start":4099,"End":4162,"Reached":0},{"Start":4164,"End":4199,"Reached":0},{"Start":4201,"End":4285,"Reached":0},{"Start":4287,"End":4352,"Reached":0},{"Start":4334,"End":4349,"Reached":0},{"Start":4354,"End":4489,"Reached":0},{"Start":4390,"End":4486,"Reached":0},{"Start":4491,"End":4514,"Reached":0},{"Start":4516,"End":4588,"Reached":0},{"Start":4570,"End":4585,"Reached":0},{"Start":4590,"End":4607,"Reached":0}]},{"Name":"StateCollector.Containers","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":4696,"End":4896,"Statements":[{"Start":4775,"End":4832,"Reached":0},{"Start":4834,"End":4870,"Reached":0},{"Start":4852,"End":4867,"Reached":0},{"Start":4872,"End":4894,"Reached":0}]},{"Name":"StateCollector.withProxy","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":4898,"End":5360,"Statements":[{"Start":4960,"End":4973,"Reached":0},{"Start":4975,"End":4996,"Reached":0},{"Start":4998,"End":5013,"Reached":0},{"Start":5016,"End":5045,"Reached":0},{"Start":5031,"End":5042,"Reached":0},{"Start":5048,"End":5060,"Reached":0},{"Start":5062,"End":5079,"Reached":0},{"Start":5081,"End":5095,"Reached":0},{"Start":5097,"End":5169,"Reached":0},{"Start":5172,"End":5358,"Reached":0}]},{"Name":"@206:8","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":5103,"End":5167,"Statements":[{"Start":5114,"End":5126,"Reached":0},{"Start":5129,"End":5147,"Reached":0},{"Start":5150,"End":5164,"Reached":0}]},{"Name":"@212:46","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":5216,"End":5357,"Statements":[{"Start":5252,"End":5275,"Reached":0},{"Start":5278,"End":5296,"Reached":0},{"Start":5299,"End":5340,"Reached":0},{"Start":5343,"End":5354,"Reached":0}]},{"Name":"@215:9","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":5305,"End":5338,"Statements":[{"Start":5314,"End":5336,"Reached":0}]},{"Name":"StateCollector.CommandFor","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":5434,"End":6656,"Statements":[{"Start":5526,"End":5543,"Reached":0},{"Start":5545,"End":6599,"Reached":0},{"Start":6601,"End":6637,"Reached":0},{"Start":6619,"End":6634,"Reached":0},{"Start":6639,"End":6654,"Reached":0}]},{"Name":"@223:9","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":5552,"End":6597,"Statements":[{"Start":5601,"End":5684,"Reached":0},{"Start":5687,"End":6271,"Reached":0},{"Start":6274,"End":6307,"Reached":0},{"Start":6293,"End":6303,"Reached":0},{"Start":6310,"End":6420,"Reached":0},{"Start":6335,"End":6416,"Reached":0},{"Start":6423,"End":6518,"Reached":0},{"Start":6521,"End":6581,"Reached":0},{"Start":6584,"End":6594,"Reached":0}]},{"Name":"@230:15","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":5699,"End":6270,"Statements":[{"Start":5787,"End":6266,"Reached":0},{"Start":5930,"End":5962,"Reached":0},{"Start":5967,"End":6261,"Reached":0},{"Start":6042,"End":6231,"Reached":0},{"Start":6124,"End":6224,"Reached":0},{"Start":6237,"End":6255,"Reached":0}]},{"Name":"StateCollector.Capacities","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":6709,"End":7885,"Statements":[{"Start":6761,"End":6797,"Reached":0},{"Start":6800,"End":6941,"Reached":0},{"Start":6829,"End":6918,"Reached":0},{"Start":6921,"End":6938,"Reached":0},{"Start":6944,"End":7559,"Reached":0},{"Start":6992,"End":7556,"Reached":0},{"Start":7013,"End":7069,"Reached":0},{"Start":7073,"End":7108,"Reached":0},{"Start":7112,"End":7193,"Reached":0},{"Start":7155,"End":7188,"Reached":0},{"Start":7197,"End":7282,"Reached":0},{"Start":7286,"End":7362,"Reached":0},{"Start":7366,"End":7454,"Reached":0},{"Start":7458,"End":7552,"Reached":0},{"Start":7562,"End":7863,"Reached":0},{"Start":7866,"End":7883,"Reached":0}]},{"Name":"@281:14","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":7574,"End":7862,"Statements":[{"Start":7676,"End":7737,"Reached":0},{"Start":7740,"End":7775,"Reached":0},{"Start":7778,"End":7859,"Reached":0}]},{"Name":"membershipMapping.Slice","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":8007,"End":8265,"Statements":[{"Start":8062,"End":8094,"Reached":0},{"Start":8096,"End":8244,"Reached":0},{"Start":8131,"End":8200,"Reached":0},{"Start":8203,"End":8241,"Reached":0},{"Start":8246,"End":8263,"Reached":0}]},{"Name":"StateCollector.SegmentMembership","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":8333,"End":8740,"Statements":[{"Start":8398,"End":8422,"Reached":0},{"Start":8424,"End":8708,"Reached":0},{"Start":8472,"End":8705,"Reached":0},{"Start":8493,"End":8549,"Reached":0},{"Start":8553,"End":8588,"Reached":0},{"Start":8592,"End":8659,"Reached":0},{"Start":8626,"End":8654,"Reached":0},{"Start":8663,"End":8701,"Reached":0},{"Start":8710,"End":8726,"Reached":0},{"Start":8728,"End":8738,"Reached":0}]},{"Name":"StateCollector.DetachedSlaves","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":9020,"End":9915,"Statements":[{"Start":9106,"End":9284,"Reached":0},{"Start":9287,"End":9509,"Reached":0},{"Start":9326,"End":9387,"Reached":0},{"Start":9390,"End":9506,"Reached":0},{"Start":9456,"End":9502,"Reached":0},{"Start":9512,"End":9525,"Reached":0},{"Start":9527,"End":9548,"Reached":0},{"Start":9551,"End":9641,"Reached":0},{"Start":9599,"End":9638,"Reached":0},{"Start":9643,"End":9841,"Reached":0},{"Start":9700,"End":9774,"Reached":0},{"Start":9740,"End":9770,"Reached":0},{"Start":9777,"End":9838,"Reached":0},{"Start":9844,"End":9899,"Reached":0},{"Start":9901,"End":9913,"Reached":0}]},{"Name":"StateCollector.toDetachedStates","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":10036,"End":10914,"Statements":[{"Start":10195,"End":10487,"Reached":0},{"Start":10490,"End":10897,"Reached":0},{"Start":10532,"End":10638,"Reached":0},{"Start":10641,"End":10861,"Reached":0},{"Start":10675,"End":10726,"Reached":0},{"Start":10730,"End":10793,"Reached":0},{"Start":10768,"End":10788,"Reached":0},{"Start":10797,"End":10857,"Reached":0},{"Start":10864,"End":10894,"Reached":0},{"Start":10899,"End":10912,"Reached":0}]},{"Name":"@370:15","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":10215,"End":10453,"Statements":[{"Start":10260,"End":10299,"Reached":0},{"Start":10303,"End":10437,"Reached":0},{"Start":10351,"End":10432,"Reached":0},{"Start":10404,"End":10426,"Reached":0},{"Start":10441,"End":10449,"Reached":0}]},{"Name":"StateCollector.ActiveSlaves","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":10975,"End":11191,"Statements":[{"Start":11041,"End":11074,"Reached":0},{"Start":11076,"End":11175,"Reached":0},{"Start":11124,"End":11172,"Reached":0},{"Start":11145,"End":11168,"Reached":0},{"Start":11177,"End":11189,"Reached":0}]},{"Name":"StateCollector.EachTask","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":11282,"End":11614,"Statements":[{"Start":11421,"End":11612,"Reached":0}]},{"Name":"@413:18","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":11437,"End":11611,"Statements":[{"Start":11522,"End":11608,"Reached":0},{"Start":11563,"End":11604,"Reached":0}]},{"Name":"StateCollector.EachExecutor","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":11713,"End":12011,"Statements":[{"Start":11839,"End":12009,"Reached":0}]},{"Name":"@423:19","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":11856,"End":12008,"Statements":[{"Start":11916,"End":12005,"Reached":0},{"Start":11966,"End":12001,"Reached":0}]},{"Name":"StateCollector.EachFramework","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":12112,"End":12353,"Statements":[{"Start":12214,"End":12351,"Reached":0}]},{"Name":"@433:20","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":12232,"End":12350,"Statements":[{"Start":12265,"End":12347,"Reached":0},{"Start":12318,"End":12343,"Reached":0}]},{"Name":"StateCollector.EachSlaveState","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":12458,"End":12599,"Statements":[{"Start":12534,"End":12597,"Reached":0},{"Start":12580,"End":12594,"Reached":0}]},{"Name":"WithStateCollector","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/state_collector.go","Start":12653,"End":13272,"Statements":[{"Start":12844,"End":12886,"Reached":0},{"Start":12888,"End":12919,"Reached":0},{"Start":12906,"End":12916,"Reached":0},{"Start":12921,"End":12976,"Reached":0},{"Start":12963,"End":12973,"Reached":0},{"Start":12979,"End":13122,"Reached":0},{"Start":13124,"End":13188,"Reached":0},{"Start":13175,"End":13185,"Reached":0},{"Start":13190,"End":13258,"Reached":0},{"Start":13245,"End":13255,"Reached":0},{"Start":13260,"End":13270,"Reached":0}]},{"Name":"NewStaticAddressesProvider","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/static_addresses_provider.go","Start":249,"End":388,"Statements":[{"Start":325,"End":375,"Reached":0},{"Start":377,"End":386,"Reached":0}]},{"Name":"StaticAddressesProvider.Addresses","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/static_addresses_provider.go","Start":445,"End":625,"Statements":[{"Start":512,"End":550,"Reached":0},{"Start":552,"End":604,"Reached":0},{"Start":586,"End":601,"Reached":0},{"Start":606,"End":623,"Reached":0}]},{"Name":"TaskContainers.ForTask","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/task_container.go","Start":266,"End":458,"Statements":[{"Start":337,"End":444,"Reached":0},{"Start":371,"End":441,"Reached":0},{"Start":420,"End":437,"Reached":0},{"Start":446,"End":456,"Reached":0}]},{"Name":"TaskContainer.BelongsTo","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/mesos/mesosutil/task_container.go","Start":496,"End":665,"Statements":[{"Start":555,"End":649,"Reached":0},{"Start":587,"End":646,"Reached":0},{"Start":631,"End":642,"Reached":0},{"Start":651,"End":663,"Reached":0}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/sessionlib","Functions":[{"Name":"NewAuto","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/sessionlib/sessionlib.go","Start":822,"End":1230,"Statements":[{"Start":883,"End":1144,"Reached":3},{"Start":930,"End":969,"Reached":0},{"Start":972,"End":1047,"Reached":0},{"Start":1028,"End":1043,"Reached":0},{"Start":1050,"End":1112,"Reached":0},{"Start":1092,"End":1108,"Reached":0},{"Start":1147,"End":1172,"Reached":3},{"Start":1174,"End":1210,"Reached":3},{"Start":1192,"End":1207,"Reached":0},{"Start":1212,"End":1228,"Reached":3}]},{"Name":"NewFromEnv","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/sessionlib/sessionlib.go","Start":1381,"End":2082,"Statements":[{"Start":1428,"End":1483,"Reached":5},{"Start":1485,"End":1521,"Reached":5},{"Start":1503,"End":1518,"Reached":1},{"Start":1524,"End":1542,"Reached":4},{"Start":1544,"End":1912,"Reached":4},{"Start":1571,"End":1602,"Reached":4},{"Start":1605,"End":1705,"Reached":4},{"Start":1718,"End":1806,"Reached":0},{"Start":1809,"End":1909,"Reached":0},{"Start":1915,"End":2024,"Reached":4},{"Start":2026,"End":2062,"Reached":4},{"Start":2044,"End":2059,"Reached":0},{"Start":2064,"End":2080,"Reached":4}]},{"Name":"NewFromProfile","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/sessionlib/sessionlib.go","Start":2250,"End":3207,"Statements":[{"Start":2315,"End":2333,"Reached":5},{"Start":2336,"End":3017,"Reached":5},{"Start":2404,"End":2419,"Reached":0},{"Start":2428,"End":3017,"Reached":5},{"Start":2438,"End":2479,"Reached":5},{"Start":2482,"End":2520,"Reached":5},{"Start":2501,"End":2516,"Reached":0},{"Start":2523,"End":2562,"Reached":5},{"Start":2565,"End":2696,"Reached":5},{"Start":2584,"End":2692,"Reached":2},{"Start":2699,"End":2735,"Reached":3},{"Start":2738,"End":2813,"Reached":3},{"Start":2757,"End":2809,"Reached":0},{"Start":2816,"End":2849,"Reached":3},{"Start":2852,"End":2963,"Reached":3},{"Start":2976,"End":3014,"Reached":0},{"Start":3020,"End":3149,"Reached":3},{"Start":3151,"End":3187,"Reached":3},{"Start":3169,"End":3184,"Reached":0},{"Start":3189,"End":3205,"Reached":3}]}]},{"Name":"github.standard.com/standard/maestro-aws-tools/pkg/tailer","Functions":[{"Name":"AppInstance.String","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":1188,"End":1327,"Statements":[{"Start":1238,"End":1315,"Reached":0},{"Start":1317,"End":1325,"Reached":0}]},{"Name":"AppInstance.Files","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":1329,"End":1970,"Statements":[{"Start":1392,"End":1459,"Reached":0},{"Start":1461,"End":1497,"Reached":0},{"Start":1479,"End":1494,"Reached":0},{"Start":1500,"End":1553,"Reached":0},{"Start":1555,"End":1639,"Reached":0},{"Start":1641,"End":1706,"Reached":0},{"Start":1688,"End":1703,"Reached":0},{"Start":1708,"End":1849,"Reached":0},{"Start":1744,"End":1846,"Reached":0},{"Start":1851,"End":1873,"Reached":0},{"Start":1875,"End":1948,"Reached":0},{"Start":1930,"End":1945,"Reached":0},{"Start":1951,"End":1968,"Reached":0}]},{"Name":"AppInstance.CurrentOffset","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":2028,"End":3070,"Statements":[{"Start":2108,"End":2141,"Reached":0},{"Start":2143,"End":2178,"Reached":0},{"Start":2161,"End":2175,"Reached":0},{"Start":2180,"End":3010,"Reached":0},{"Start":2211,"End":3007,"Reached":0},{"Start":2243,"End":2357,"Reached":0},{"Start":2361,"End":2432,"Reached":0},{"Start":2436,"End":2538,"Reached":0},{"Start":2456,"End":2533,"Reached":0},{"Start":2542,"End":2571,"Reached":0},{"Start":2575,"End":2628,"Reached":0},{"Start":2632,"End":2720,"Reached":0},{"Start":2724,"End":2833,"Reached":0},{"Start":2773,"End":2828,"Reached":0},{"Start":2837,"End":2974,"Reached":0},{"Start":2875,"End":2969,"Reached":0},{"Start":2978,"End":3003,"Reached":0},{"Start":3012,"End":3068,"Reached":0}]},{"Name":"AppInstance.ReadSegment","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":3136,"End":3688,"Statements":[{"Start":3254,"End":3287,"Reached":0},{"Start":3289,"End":3325,"Reached":0},{"Start":3307,"End":3322,"Reached":0},{"Start":3327,"End":3630,"Reached":0},{"Start":3358,"End":3627,"Reached":0},{"Start":3390,"End":3513,"Reached":0},{"Start":3517,"End":3557,"Reached":0},{"Start":3561,"End":3601,"Reached":0},{"Start":3581,"End":3596,"Reached":0},{"Start":3605,"End":3623,"Reached":0},{"Start":3632,"End":3686,"Reached":0}]},{"Name":"AppInstance.Stream","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":3735,"End":5960,"Statements":[{"Start":3840,"End":3915,"Reached":0},{"Start":3917,"End":3950,"Reached":0},{"Start":3952,"End":3988,"Reached":0},{"Start":3970,"End":3985,"Reached":0},{"Start":3990,"End":5902,"Reached":0},{"Start":4021,"End":5899,"Reached":0},{"Start":4053,"End":4080,"Reached":0},{"Start":4085,"End":4313,"Reached":0},{"Start":4318,"End":4594,"Reached":0},{"Start":4374,"End":4399,"Reached":0},{"Start":4404,"End":4428,"Reached":0},{"Start":4475,"End":4515,"Reached":0},{"Start":4520,"End":4562,"Reached":0},{"Start":4541,"End":4556,"Reached":0},{"Start":4567,"End":4589,"Reached":0},{"Start":4599,"End":5872,"Reached":0},{"Start":5877,"End":5895,"Reached":0},{"Start":5904,"End":5958,"Reached":0}]},{"Name":"@159:7","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":4602,"End":5870,"Statements":[{"Start":4615,"End":4635,"Reached":0},{"Start":4641,"End":4737,"Reached":0},{"Start":4743,"End":5865,"Reached":0},{"Start":4754,"End":4778,"Reached":0},{"Start":4784,"End":4817,"Reached":0},{"Start":4824,"End":4864,"Reached":0},{"Start":4870,"End":5045,"Reached":0},{"Start":4892,"End":4919,"Reached":0},{"Start":4926,"End":5003,"Reached":0},{"Start":5010,"End":5023,"Reached":0},{"Start":5030,"End":5038,"Reached":0},{"Start":5087,"End":5155,"Reached":0},{"Start":5111,"End":5133,"Reached":0},{"Start":5140,"End":5148,"Reached":0},{"Start":5162,"End":5245,"Reached":0},{"Start":5195,"End":5223,"Reached":0},{"Start":5230,"End":5238,"Reached":0},{"Start":5252,"End":5419,"Reached":0},{"Start":5319,"End":5399,"Reached":0},{"Start":5406,"End":5412,"Reached":0},{"Start":5425,"End":5458,"Reached":0},{"Start":5464,"End":5837,"Reached":0},{"Start":5511,"End":5664,"Reached":0},{"Start":5551,"End":5571,"Reached":0},{"Start":5579,"End":5656,"Reached":0},{"Start":5620,"End":5647,"Reached":0},{"Start":5677,"End":5837,"Reached":0},{"Start":5720,"End":5740,"Reached":0},{"Start":5747,"End":5830,"Reached":0},{"Start":5791,"End":5822,"Reached":0},{"Start":5843,"End":5859,"Reached":0}]},{"Name":"AppInstance.stream","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":6038,"End":6801,"Statements":[{"Start":6136,"End":6207,"Reached":0},{"Start":6209,"End":6308,"Reached":0},{"Start":6227,"End":6305,"Reached":0},{"Start":6361,"End":6390,"Reached":0},{"Start":6392,"End":6445,"Reached":0},{"Start":6447,"End":6535,"Reached":0},{"Start":6537,"End":6643,"Reached":0},{"Start":6584,"End":6640,"Reached":0},{"Start":6645,"End":6779,"Reached":0},{"Start":6681,"End":6776,"Reached":0},{"Start":6781,"End":6799,"Reached":0}]},{"Name":"AppInstance.renderTemplate","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":6803,"End":7186,"Statements":[{"Start":6923,"End":6978,"Reached":0},{"Start":6943,"End":6975,"Reached":0},{"Start":6980,"End":7014,"Reached":0},{"Start":7017,"End":7039,"Reached":0},{"Start":7042,"End":7109,"Reached":0},{"Start":7092,"End":7106,"Reached":0},{"Start":7112,"End":7131,"Reached":0},{"Start":7169,"End":7184,"Reached":0}]},{"Name":"newStrategy","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/app_instance.go","Start":7188,"End":7488,"Statements":[{"Start":7226,"End":7269,"Reached":0},{"Start":7271,"End":7320,"Reached":0},{"Start":7322,"End":7361,"Reached":0},{"Start":7363,"End":7388,"Reached":0},{"Start":7390,"End":7424,"Reached":0},{"Start":7426,"End":7468,"Reached":0},{"Start":7471,"End":7486,"Reached":0}]},{"Name":"New","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":839,"End":1555,"Statements":[{"Start":922,"End":985,"Reached":0},{"Start":967,"End":982,"Reached":0},{"Start":988,"End":1037,"Reached":0},{"Start":1039,"End":1075,"Reached":0},{"Start":1057,"End":1072,"Reached":0},{"Start":1078,"End":1219,"Reached":0},{"Start":1101,"End":1175,"Reached":0},{"Start":1178,"End":1216,"Reached":0},{"Start":1197,"End":1212,"Reached":0},{"Start":1222,"End":1534,"Reached":0},{"Start":1537,"End":1553,"Reached":0}]},{"Name":"AWSMesosTailer.Run","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":1557,"End":5010,"Statements":[{"Start":1600,"End":1704,"Reached":0},{"Start":1641,"End":1701,"Reached":0},{"Start":1707,"End":1769,"Reached":0},{"Start":1756,"End":1766,"Reached":0},{"Start":1772,"End":1836,"Reached":0},{"Start":1813,"End":1833,"Reached":0},{"Start":1838,"End":1906,"Reached":0},{"Start":1881,"End":1903,"Reached":0},{"Start":1909,"End":4963,"Reached":0},{"Start":4965,"End":4996,"Reached":0},{"Start":4983,"End":4993,"Reached":0},{"Start":4998,"End":5008,"Reached":0}]},{"Name":"@85:38","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":1945,"End":4962,"Statements":[{"Start":1981,"End":2006,"Reached":0},{"Start":2009,"End":2052,"Reached":0},{"Start":2055,"End":2075,"Reached":0},{"Start":2079,"End":2161,"Reached":0},{"Start":2147,"End":2157,"Reached":0},{"Start":2165,"End":2205,"Reached":0},{"Start":2208,"End":2241,"Reached":0},{"Start":2227,"End":2237,"Reached":0},{"Start":2244,"End":2324,"Reached":0},{"Start":2310,"End":2320,"Reached":0},{"Start":2328,"End":2490,"Reached":0},{"Start":2494,"End":4555,"Reached":0},{"Start":2540,"End":2555,"Reached":0},{"Start":2559,"End":4551,"Reached":0},{"Start":4559,"End":4574,"Reached":0},{"Start":4578,"End":4626,"Reached":0},{"Start":4630,"End":4698,"Reached":0},{"Start":4684,"End":4694,"Reached":0},{"Start":4702,"End":4926,"Reached":0},{"Start":4930,"End":4945,"Reached":0},{"Start":4949,"End":4959,"Reached":0}]},{"Name":"@87:9","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":2015,"End":2050,"Statements":[{"Start":2024,"End":2048,"Reached":0}]},{"Name":"@113:7","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":2562,"End":4538,"Statements":[{"Start":2599,"End":2620,"Reached":0},{"Start":2626,"End":4433,"Reached":0},{"Start":4438,"End":4533,"Reached":0},{"Start":4459,"End":4468,"Reached":0},{"Start":4474,"End":4510,"Reached":0},{"Start":4516,"End":4527,"Reached":0}]},{"Name":"@116:12","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":2633,"End":4420,"Statements":[{"Start":2677,"End":2710,"Reached":0},{"Start":2716,"End":2755,"Reached":0},{"Start":2738,"End":2748,"Reached":0},{"Start":2761,"End":4398,"Reached":0},{"Start":2796,"End":4343,"Reached":0},{"Start":4350,"End":4391,"Reached":0},{"Start":4373,"End":4383,"Reached":0},{"Start":4404,"End":4414,"Reached":0}]},{"Name":"@122:14","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":2803,"End":4337,"Statements":[{"Start":2840,"End":4311,"Reached":0},{"Start":2879,"End":2891,"Reached":0},{"Start":2900,"End":2920,"Reached":0},{"Start":2930,"End":3563,"Reached":0},{"Start":2976,"End":3148,"Reached":0},{"Start":3175,"End":3303,"Reached":0},{"Start":3313,"End":3414,"Reached":0},{"Start":3424,"End":3530,"Reached":0},{"Start":3450,"End":3519,"Reached":0},{"Start":3540,"End":3553,"Reached":0},{"Start":3573,"End":3640,"Reached":0},{"Start":3649,"End":3694,"Reached":0},{"Start":3674,"End":3684,"Reached":0},{"Start":3703,"End":3718,"Reached":0},{"Start":3727,"End":4302,"Reached":0},{"Start":4319,"End":4329,"Reached":0}]},{"Name":"@130:24","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":3063,"End":3136,"Statements":[{"Start":3079,"End":3134,"Reached":0}]},{"Name":"@146:12","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":3730,"End":4300,"Statements":[{"Start":3748,"End":3769,"Reached":0},{"Start":3780,"End":4290,"Reached":0},{"Start":3796,"End":3817,"Reached":0},{"Start":3828,"End":4076,"Reached":0},{"Start":3882,"End":3906,"Reached":0},{"Start":3918,"End":3927,"Reached":0},{"Start":3939,"End":4023,"Reached":0},{"Start":4035,"End":4046,"Reached":0},{"Start":4058,"End":4064,"Reached":0},{"Start":4087,"End":4279,"Reached":0},{"Start":4251,"End":4267,"Reached":0}]},{"Name":"@190:9","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":4708,"End":4924,"Statements":[{"Start":4720,"End":4920,"Reached":0},{"Start":4775,"End":4792,"Reached":0},{"Start":4797,"End":4845,"Reached":0},{"Start":4827,"End":4839,"Reached":0},{"Start":4850,"End":4915,"Reached":0}]},{"Name":"AWSMesosTailer.Include","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":5113,"End":5339,"Statements":[{"Start":5174,"End":5224,"Reached":0},{"Start":5210,"End":5221,"Reached":0},{"Start":5226,"End":5323,"Reached":0},{"Start":5275,"End":5320,"Reached":0},{"Start":5305,"End":5316,"Reached":0},{"Start":5325,"End":5337,"Reached":0}]},{"Name":"AWSMesosTailer.Matches","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":5341,"End":5796,"Statements":[{"Start":5402,"End":5427,"Reached":0},{"Start":5429,"End":5554,"Reached":0},{"Start":5483,"End":5551,"Reached":0},{"Start":5515,"End":5538,"Reached":0},{"Start":5542,"End":5547,"Reached":0},{"Start":5557,"End":5779,"Reached":0},{"Start":5618,"End":5776,"Reached":0},{"Start":5673,"End":5772,"Reached":0},{"Start":5756,"End":5767,"Reached":0},{"Start":5782,"End":5794,"Reached":0}]},{"Name":"AWSMesosTailer.EachFilename","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":5898,"End":6426,"Statements":[{"Start":5991,"End":6013,"Reached":0},{"Start":6015,"End":6321,"Reached":0},{"Start":6050,"End":6080,"Reached":0},{"Start":6093,"End":6126,"Reached":0},{"Start":6129,"End":6237,"Reached":0},{"Start":6148,"End":6233,"Reached":0},{"Start":6240,"End":6318,"Reached":0},{"Start":6272,"End":6314,"Reached":0},{"Start":6323,"End":6412,"Reached":0},{"Start":6362,"End":6409,"Reached":0},{"Start":6393,"End":6405,"Reached":0},{"Start":6414,"End":6424,"Reached":0}]},{"Name":"AWSMesosTailer.AppInstances","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":6428,"End":7748,"Statements":[{"Start":6498,"End":6530,"Reached":0},{"Start":6532,"End":7682,"Reached":0},{"Start":7684,"End":7720,"Reached":0},{"Start":7702,"End":7717,"Reached":0},{"Start":7722,"End":7746,"Reached":0}]},{"Name":"@269:38","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":6568,"End":7681,"Statements":[{"Start":6604,"End":6629,"Reached":0},{"Start":6632,"End":6675,"Reached":0},{"Start":6678,"End":6698,"Reached":0},{"Start":6702,"End":6746,"Reached":0},{"Start":6749,"End":6768,"Reached":0},{"Start":6771,"End":6834,"Reached":0},{"Start":6805,"End":6830,"Reached":0},{"Start":6838,"End":6888,"Reached":0},{"Start":6874,"End":6884,"Reached":0},{"Start":6892,"End":6974,"Reached":0},{"Start":6960,"End":6970,"Reached":0},{"Start":6978,"End":7005,"Reached":0},{"Start":7008,"End":7665,"Reached":0},{"Start":7668,"End":7678,"Reached":0}]},{"Name":"@271:9","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":6638,"End":6673,"Statements":[{"Start":6647,"End":6671,"Reached":0}]},{"Name":"@289:32","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":7037,"End":7664,"Statements":[{"Start":7131,"End":7660,"Reached":0},{"Start":7159,"End":7341,"Reached":0},{"Start":7346,"End":7394,"Reached":0},{"Start":7399,"End":7655,"Reached":0}]},{"Name":"AWSMesosTailer.prepDestination","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/aws_mesos_tailer.go","Start":7750,"End":8374,"Statements":[{"Start":7805,"End":8360,"Reached":0},{"Start":7844,"End":7901,"Reached":0},{"Start":7904,"End":8021,"Reached":0},{"Start":7923,"End":8017,"Reached":0},{"Start":8024,"End":8149,"Reached":0},{"Start":8040,"End":8145,"Reached":0},{"Start":8130,"End":8140,"Reached":0},{"Start":8152,"End":8209,"Reached":0},{"Start":8212,"End":8245,"Reached":0},{"Start":8231,"End":8241,"Reached":0},{"Start":8248,"End":8357,"Reached":0},{"Start":8263,"End":8353,"Reached":0},{"Start":8362,"End":8372,"Reached":0}]},{"Name":"Options.Validate","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/options.go","Start":457,"End":1162,"Statements":[{"Start":500,"End":804,"Reached":0},{"Start":806,"End":981,"Reached":0},{"Start":855,"End":978,"Reached":0},{"Start":964,"End":974,"Reached":0},{"Start":983,"End":1148,"Reached":0},{"Start":1032,"End":1145,"Reached":0},{"Start":1131,"End":1141,"Reached":0},{"Start":1150,"End":1160,"Reached":0}]},{"Name":"@26:20","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/options.go","Start":518,"End":804,"Statements":[{"Start":588,"End":692,"Reached":0},{"Start":638,"End":688,"Reached":0},{"Start":673,"End":683,"Reached":0},{"Start":695,"End":801,"Reached":0}]},{"Name":"prefixedLineWriter.Write","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/prefixed_line_writer.go","Start":455,"End":1330,"Statements":[{"Start":519,"End":532,"Reached":0},{"Start":534,"End":555,"Reached":0},{"Start":558,"End":612,"Reached":0},{"Start":614,"End":663,"Reached":0},{"Start":639,"End":660,"Reached":0},{"Start":665,"End":714,"Reached":0},{"Start":690,"End":711,"Reached":0},{"Start":717,"End":829,"Reached":0},{"Start":765,"End":783,"Reached":0},{"Start":786,"End":826,"Reached":0},{"Start":831,"End":991,"Reached":0},{"Start":881,"End":909,"Reached":0},{"Start":912,"End":943,"Reached":0},{"Start":956,"End":988,"Reached":0},{"Start":993,"End":1055,"Reached":0},{"Start":1057,"End":1131,"Reached":0},{"Start":1133,"End":1238,"Reached":0},{"Start":1165,"End":1205,"Reached":0},{"Start":1208,"End":1235,"Reached":0},{"Start":1240,"End":1278,"Reached":0},{"Start":1280,"End":1313,"Reached":0},{"Start":1299,"End":1310,"Reached":0},{"Start":1315,"End":1328,"Reached":0}]},{"Name":"prefixedLineWriter.Close","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/prefixed_line_writer.go","Start":1332,"End":1457,"Statements":[{"Start":1380,"End":1443,"Reached":0},{"Start":1430,"End":1440,"Reached":0},{"Start":1445,"End":1455,"Reached":0}]},{"Name":"NewStandalone","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":868,"End":1841,"Statements":[{"Start":958,"End":1021,"Reached":0},{"Start":1003,"End":1018,"Reached":0},{"Start":1024,"End":1073,"Reached":0},{"Start":1075,"End":1111,"Reached":0},{"Start":1093,"End":1108,"Reached":0},{"Start":1114,"End":1393,"Reached":0},{"Start":1395,"End":1499,"Reached":0},{"Start":1436,"End":1496,"Reached":0},{"Start":1501,"End":1609,"Reached":0},{"Start":1612,"End":1654,"Reached":0},{"Start":1656,"End":1692,"Reached":0},{"Start":1674,"End":1689,"Reached":0},{"Start":1694,"End":1733,"Reached":0},{"Start":1736,"End":1821,"Reached":0},{"Start":1803,"End":1818,"Reached":0},{"Start":1823,"End":1839,"Reached":0}]},{"Name":"StandaloneMesosTailer.fetchMesosMasterState","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":1843,"End":3096,"Statements":[{"Start":1927,"End":2002,"Reached":0},{"Start":2004,"End":2778,"Reached":0},{"Start":2047,"End":2775,"Reached":0},{"Start":2780,"End":2816,"Reached":0},{"Start":2888,"End":2973,"Reached":0},{"Start":2906,"End":2970,"Reached":0},{"Start":2975,"End":3075,"Reached":0},{"Start":2995,"End":3072,"Reached":0},{"Start":3077,"End":3094,"Reached":0}]},{"Name":"@82:3","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":2047,"End":2769,"Statements":[{"Start":2070,"End":2736,"Reached":0},{"Start":2740,"End":2765,"Reached":0}]},{"Name":"@83:10","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":2076,"End":2736,"Statements":[{"Start":2095,"End":2142,"Reached":0},{"Start":2147,"End":2223,"Reached":0},{"Start":2228,"End":2272,"Reached":0},{"Start":2277,"End":2315,"Reached":0},{"Start":2320,"End":2386,"Reached":0},{"Start":2370,"End":2380,"Reached":0},{"Start":2391,"End":2515,"Reached":0},{"Start":2426,"End":2509,"Reached":0},{"Start":2520,"End":2529,"Reached":0},{"Start":2534,"End":2551,"Reached":0},{"Start":2556,"End":2716,"Reached":0},{"Start":2579,"End":2601,"Reached":0},{"Start":2607,"End":2710,"Reached":0},{"Start":2665,"End":2686,"Reached":0},{"Start":2693,"End":2703,"Reached":0},{"Start":2721,"End":2731,"Reached":0}]},{"Name":"StandaloneMesosTailer.Run","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":3098,"End":5705,"Statements":[{"Start":3148,"End":3188,"Reached":0},{"Start":3190,"End":3221,"Reached":0},{"Start":3208,"End":3218,"Reached":0},{"Start":3224,"End":3302,"Reached":0},{"Start":3289,"End":3299,"Reached":0},{"Start":3305,"End":3460,"Reached":0},{"Start":3463,"End":5314,"Reached":0},{"Start":3508,"End":3523,"Reached":0},{"Start":3526,"End":5311,"Reached":0},{"Start":5317,"End":5332,"Reached":0},{"Start":5335,"End":5384,"Reached":0},{"Start":5387,"End":5453,"Reached":0},{"Start":5440,"End":5450,"Reached":0},{"Start":5456,"End":5672,"Reached":0},{"Start":5675,"End":5690,"Reached":0},{"Start":5693,"End":5703,"Reached":0}]},{"Name":"@139:6","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":3529,"End":5298,"Statements":[{"Start":3565,"End":3586,"Reached":0},{"Start":3591,"End":5199,"Reached":0},{"Start":5203,"End":5294,"Reached":0},{"Start":5223,"End":5232,"Reached":0},{"Start":5237,"End":5273,"Reached":0},{"Start":5278,"End":5289,"Reached":0}]},{"Name":"@142:11","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":3598,"End":5186,"Statements":[{"Start":3641,"End":3674,"Reached":0},{"Start":3679,"End":3716,"Reached":0},{"Start":3700,"End":3710,"Reached":0},{"Start":3721,"End":5166,"Reached":0},{"Start":3755,"End":5115,"Reached":0},{"Start":5121,"End":5160,"Reached":0},{"Start":5143,"End":5153,"Reached":0},{"Start":5171,"End":5181,"Reached":0}]},{"Name":"@148:13","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":3762,"End":5109,"Statements":[{"Start":3798,"End":5085,"Reached":0},{"Start":3836,"End":3848,"Reached":0},{"Start":3856,"End":3876,"Reached":0},{"Start":3885,"End":4355,"Reached":0},{"Start":3930,"End":3948,"Reached":0},{"Start":3973,"End":4101,"Reached":0},{"Start":4110,"End":4211,"Reached":0},{"Start":4220,"End":4324,"Reached":0},{"Start":4245,"End":4314,"Reached":0},{"Start":4333,"End":4346,"Reached":0},{"Start":4364,"End":4431,"Reached":0},{"Start":4439,"End":4482,"Reached":0},{"Start":4463,"End":4473,"Reached":0},{"Start":4490,"End":4505,"Reached":0},{"Start":4513,"End":5077,"Reached":0},{"Start":5092,"End":5102,"Reached":0}]},{"Name":"@169:11","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":4516,"End":5075,"Statements":[{"Start":4533,"End":4554,"Reached":0},{"Start":4564,"End":5066,"Reached":0},{"Start":4579,"End":4600,"Reached":0},{"Start":4610,"End":4857,"Reached":0},{"Start":4663,"End":4692,"Reached":0},{"Start":4703,"End":4712,"Reached":0},{"Start":4723,"End":4807,"Reached":0},{"Start":4818,"End":4829,"Reached":0},{"Start":4840,"End":4846,"Reached":0},{"Start":4867,"End":5056,"Reached":0},{"Start":5029,"End":5045,"Reached":0}]},{"Name":"@213:8","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":5462,"End":5670,"Statements":[{"Start":5473,"End":5667,"Reached":0},{"Start":5527,"End":5544,"Reached":0},{"Start":5548,"End":5594,"Reached":0},{"Start":5577,"End":5589,"Reached":0},{"Start":5598,"End":5663,"Reached":0}]},{"Name":"StandaloneMesosTailer.AppInstances","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":5707,"End":6690,"Statements":[{"Start":5784,"End":5828,"Reached":0},{"Start":5830,"End":5850,"Reached":0},{"Start":5852,"End":5914,"Reached":0},{"Start":5885,"End":5911,"Reached":0},{"Start":5917,"End":5949,"Reached":0},{"Start":5951,"End":5979,"Reached":0},{"Start":5981,"End":6662,"Reached":0},{"Start":6664,"End":6688,"Reached":0}]},{"Name":"@237:31","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":6010,"End":6661,"Statements":[{"Start":6103,"End":6658,"Reached":0},{"Start":6130,"End":6341,"Reached":0},{"Start":6345,"End":6393,"Reached":0},{"Start":6397,"End":6654,"Reached":0}]},{"Name":"StandaloneMesosTailer.EachFilename","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":6785,"End":7320,"Statements":[{"Start":6885,"End":6907,"Reached":0},{"Start":6909,"End":7215,"Reached":0},{"Start":6944,"End":6974,"Reached":0},{"Start":6987,"End":7020,"Reached":0},{"Start":7023,"End":7131,"Reached":0},{"Start":7042,"End":7127,"Reached":0},{"Start":7134,"End":7212,"Reached":0},{"Start":7166,"End":7208,"Reached":0},{"Start":7217,"End":7306,"Reached":0},{"Start":7256,"End":7303,"Reached":0},{"Start":7287,"End":7299,"Reached":0},{"Start":7308,"End":7318,"Reached":0}]},{"Name":"StandaloneMesosTailer.Include","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":7423,"End":7656,"Statements":[{"Start":7491,"End":7541,"Reached":0},{"Start":7527,"End":7538,"Reached":0},{"Start":7543,"End":7640,"Reached":0},{"Start":7592,"End":7637,"Reached":0},{"Start":7622,"End":7633,"Reached":0},{"Start":7642,"End":7654,"Reached":0}]},{"Name":"StandaloneMesosTailer.Matches","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":7657,"End":8119,"Statements":[{"Start":7725,"End":7750,"Reached":0},{"Start":7752,"End":7877,"Reached":0},{"Start":7806,"End":7874,"Reached":0},{"Start":7838,"End":7861,"Reached":0},{"Start":7865,"End":7870,"Reached":0},{"Start":7880,"End":8102,"Reached":0},{"Start":7941,"End":8099,"Reached":0},{"Start":7996,"End":8095,"Reached":0},{"Start":8079,"End":8090,"Reached":0},{"Start":8105,"End":8117,"Reached":0}]},{"Name":"passthroughTopologyInteractor.Init","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8275,"End":8376,"Statements":[{"Start":8364,"End":8374,"Reached":0}]},{"Name":"passthroughTopologyInteractor.Command","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8377,"End":8478,"Statements":[{"Start":8466,"End":8476,"Reached":0}]},{"Name":"passthroughTopologyInteractor.ControllerIPs","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8479,"End":8580,"Statements":[{"Start":8568,"End":8578,"Reached":0}]},{"Name":"passthroughTopologyInteractor.AddrToName","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8581,"End":8681,"Statements":[{"Start":8670,"End":8679,"Reached":0}]},{"Name":"passthroughTopologyInteractor.ComputeResources","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8682,"End":8783,"Statements":[{"Start":8771,"End":8781,"Reached":0}]},{"Name":"passthroughTopologyInteractor.Containers","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8784,"End":8895,"Statements":[{"Start":8878,"End":8893,"Reached":0}]},{"Name":"passthroughTopologyInteractor.ApplyWithProxy","File":"/Users/anonymous/go/src/github.standard.com/standard/maestro-aws-tools/pkg/tailer/standalone_tailer.go","Start":8896,"End":9016,"Statements":[{"Start":8998,"End":9014,"Reached":0}]}]}]}` 9 | 10 | func TestLineScannerLongLine(t *testing.T) { 11 | var ( 12 | r = bytes.NewBufferString(testLog) 13 | ls = NewLineScanner(r) 14 | ) 15 | 16 | for ls.Scan() { 17 | token := ls.Text() 18 | if len(token) == 0 { 19 | t.Error("Got empty token") 20 | } 21 | } 22 | 23 | if err := ls.Err(); err != nil { 24 | t.Fatal(err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/lib_test.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func loadGotest(filename string, t *testing.T) ([]*Suite, error) { 9 | file, err := os.Open(filename) 10 | if err != nil { 11 | t.Fatalf("can't open %s - %s", filename, err) 12 | } 13 | 14 | return ParseGotest(file, "") 15 | } 16 | 17 | /* FIXME 18 | func Test_parseBadOutput(t *testing.T) { 19 | filename := "parsers.go" 20 | if _, err := loadGotest(filename, t); err == nil { 21 | t.Fatalf("managed to find suites in junk") 22 | } 23 | } 24 | */ 25 | 26 | func Test_ignoreDatarace(t *testing.T) { 27 | filename := "../_data/in/gotest-datarace.out" 28 | suites, err := loadGotest(filename, t) 29 | if err != nil { 30 | t.Fatalf("error loading %s - %s", filename, err) 31 | } 32 | 33 | suite := suites[0] 34 | tests := suite.Tests 35 | numTests := 1 36 | if len(tests) != numTests { 37 | t.Fatalf("got %d tests instead of %d", len(tests), numTests) 38 | } 39 | 40 | expectedMessage := "WARNING: DATA RACE" 41 | for i, test := range suite.Tests { 42 | if test.Message != expectedMessage { 43 | t.Errorf( 44 | "test %v message does not match expected result:\n\tGot: \"%v\"\n\tExpected: \"%v\"\n", 45 | i, 46 | test.Message, 47 | expectedMessage) 48 | } 49 | } 50 | numFailed := 0 51 | if suite.NumFailed() != numFailed { 52 | t.Fatalf("wrong number of failed %d, should be %d", suite.NumFailed(), numFailed) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/options.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | // Options is library options 4 | var Options struct { 5 | // FailOnRace will mark test a failed if there is a race 6 | FailOnRace bool 7 | } 8 | -------------------------------------------------------------------------------- /lib/parsers.go: -------------------------------------------------------------------------------- 1 | // Package lib is exposing parsers and output generation 2 | package lib 3 | 4 | import ( 5 | "fmt" 6 | "io" 7 | "regexp" 8 | "strings" 9 | ) 10 | 11 | var ( 12 | matchDatarace = regexp.MustCompile("^WARNING: DATA RACE$").MatchString 13 | ) 14 | 15 | // hasDatarace checks if there's a data race warning in the line 16 | func hasDatarace(lines []string) bool { 17 | for _, line := range lines { 18 | if matchDatarace(line) { 19 | return true 20 | } 21 | } 22 | return false 23 | } 24 | 25 | // Token2Status return matching status for token 26 | func Token2Status(token string) Status { 27 | switch token { 28 | case "FAIL", "PANIC": 29 | return Failed 30 | case "PASS": 31 | return Passed 32 | case "SKIP", "MISS": 33 | return Skipped 34 | } 35 | return UnknownStatus 36 | } 37 | 38 | // Returns previous test in a suite, for a given test. Returns error if previous 39 | // test doesn't exist. 40 | func getPreviousFailTest(suite *Suite, curTest *Test) (*Test, error) { 41 | previousFailTestIndex := -1 42 | for testIndex, test := range suite.Tests { 43 | if test.Name == curTest.Name { 44 | break 45 | } else { 46 | if test.Status == Failed { 47 | previousFailTestIndex = testIndex 48 | } 49 | } 50 | } 51 | 52 | if previousFailTestIndex >= 0 { 53 | return suite.Tests[previousFailTestIndex], nil 54 | } 55 | return nil, fmt.Errorf("Not found previous test of %s in suite %s", curTest.Name, suite.Name) 56 | } 57 | 58 | // ParseGocheck parses output of "go test -gocheck.vv", returns a list of tests 59 | // See data/gocheck.out for an example 60 | // TODO: Refactor to shorter ones 61 | func ParseGocheck(rd io.Reader, suitePrefix string) (Suites, error) { 62 | findStart := gcStartRE.FindStringSubmatch 63 | findEnd := gcEndRE.FindStringSubmatch 64 | findSuite := gcSuiteRE.FindStringSubmatch 65 | 66 | scanner := NewLineScanner(rd) 67 | var suites = make([]*Suite, 0) 68 | var suiteName string 69 | var suite *Suite 70 | 71 | var testName string 72 | var out []string 73 | 74 | for scanner.Scan() { 75 | line := scanner.Text() 76 | 77 | tokens := findStart(line) 78 | if len(tokens) > 0 { 79 | if tokens[2] == "SetUpTest" || tokens[2] == "TearDownTest" { 80 | continue 81 | } 82 | if testName != "" { 83 | return nil, fmt.Errorf("%d: start in middle of test", scanner.Line()) 84 | } 85 | suiteName = tokens[1] 86 | testName = tokens[2] 87 | out = []string{} 88 | continue 89 | } 90 | 91 | tokens = findEnd(line) 92 | if len(tokens) > 0 { 93 | if tokens[3] == "SetUpTest" || tokens[3] == "TearDownTest" { 94 | continue 95 | } 96 | if testName == "" { 97 | return nil, fmt.Errorf("%d: orphan end", scanner.Line()) 98 | } 99 | if (tokens[2] != suiteName) || (tokens[3] != testName) { 100 | return nil, fmt.Errorf("%d: suite/name mismatch", scanner.Line()) 101 | } 102 | test := &Test{Name: testName} 103 | test.Message = strings.Join(out, "\n") 104 | test.Time = tokens[4] 105 | test.Status = Token2Status(tokens[1]) 106 | if test.Status == UnknownStatus { 107 | return nil, fmt.Errorf("%d: unknown status %s", scanner.Line(), tokens[1]) 108 | } 109 | 110 | if suite == nil || suite.Name != suiteName { 111 | suite = &Suite{Name: suitePrefix + suiteName} 112 | suites = append(suites, suite) 113 | } 114 | suite.Tests = append(suite.Tests, test) 115 | 116 | testName = "" 117 | suiteName = "" 118 | out = []string{} 119 | 120 | continue 121 | } 122 | 123 | // last "suite" is test summary 124 | tokens = findSuite(line) 125 | if tokens != nil { 126 | if suite == nil { 127 | suite = &Suite{Name: tokens[2], Status: tokens[1], Time: tokens[3]} 128 | suites = append(suites, suite) 129 | } else { 130 | suite.Status = tokens[1] 131 | suite.Time = tokens[3] 132 | } 133 | 134 | testName = "" 135 | suiteName = "" 136 | out = []string{} 137 | 138 | continue 139 | } 140 | 141 | if testName != "" { 142 | out = append(out, line) 143 | } 144 | } 145 | 146 | if err := scanner.Err(); err != nil { 147 | return nil, err 148 | } 149 | 150 | return Suites(suites), nil 151 | } 152 | 153 | // ParseGotest parser output of gotest 154 | // TODO: Make it shorter 155 | func ParseGotest(rd io.Reader, suitePrefix string) (Suites, error) { 156 | findStart := gtStartRE.FindStringSubmatch 157 | findEnd := gtEndRE.FindStringSubmatch 158 | findSuite := gtSuiteRE.FindStringSubmatch 159 | isNoFiles := gtNoFilesRE.MatchString 160 | isBuildFailed := gtBuildFailedRE.MatchString 161 | isExit := gtExitRE.MatchString 162 | isErrorOutput := gcTestErrorRE.MatchString 163 | 164 | suites := []*Suite{} 165 | subTests := map[string]*Test{} 166 | var parentTest *Test 167 | var curTest *Test 168 | var curSuite *Suite 169 | var out []string 170 | suiteStack := SuiteStack{} 171 | 172 | // Handles a test that ended with a panic. 173 | handlePanic := func() { 174 | curTest.Status = Failed 175 | curTest.Time = "0" 176 | curSuite.Tests = append(curSuite.Tests, curTest) 177 | curTest = nil 178 | } 179 | 180 | // Appends output to the last test. 181 | appendError := func() { 182 | if len(out) > 0 && curSuite != nil && len(curSuite.Tests) > 0 { 183 | message := strings.Join(out, "\n") 184 | test := curSuite.Tests[len(curSuite.Tests)-1] 185 | if test.isParentTest == false { 186 | if test.Message == "" { 187 | test.Message = message 188 | } else { 189 | test.Message += "\n" + message 190 | } 191 | test.AppendedErrorOutput = isErrorOutput(message) 192 | } 193 | } 194 | out = []string{} 195 | } 196 | 197 | scanner := NewLineScanner(rd) 198 | for scanner.Scan() { 199 | line := scanner.Text() 200 | 201 | // TODO: Only outside a suite/test, report as empty suite? 202 | if isNoFiles(line) { 203 | continue 204 | } 205 | 206 | if isBuildFailed(line) { 207 | return nil, fmt.Errorf("%d: package build failed: %s", scanner.Line(), line) 208 | } 209 | 210 | if curSuite == nil { 211 | curSuite = &Suite{} 212 | } 213 | tokens := findStart(line) 214 | if tokens != nil { 215 | subTest := false 216 | if curTest != nil { 217 | // This occurs when the last test ended with a panic, or when subtests are found 218 | if parentTest == nil && strings.HasPrefix(tokens[1], curTest.Name+"/") { 219 | // First subtest after parent 220 | parentTest = curTest 221 | curSuite.Tests = append(curSuite.Tests, curTest) 222 | subTests = map[string]*Test{} 223 | subTest = true 224 | } else if parentTest != nil && strings.HasPrefix(tokens[1], parentTest.Name+"/") { 225 | parentTest.isParentTest = true 226 | parentTest.AppendedErrorOutput = true 227 | subTest = true 228 | } else if suiteStack.count == 0 { 229 | suiteStack.Push(curSuite) 230 | curSuite = &Suite{Name: curTest.Name} 231 | } else { 232 | handlePanic() 233 | } 234 | } 235 | appendError() 236 | curTest = &Test{ 237 | Name: tokens[1], 238 | } 239 | if subTest { 240 | curSuite.Tests = append(curSuite.Tests, curTest) 241 | subTests[curTest.Name] = curTest 242 | } 243 | continue 244 | } 245 | 246 | tokens = findEnd(line) 247 | if tokens != nil { 248 | appendTest := true 249 | if parentTest != nil && tokens[2] == parentTest.Name { 250 | curTest = parentTest 251 | parentTest = nil 252 | appendTest = false 253 | } else if subTest, ok := subTests[tokens[2]]; ok { 254 | curTest = subTest 255 | appendTest = false 256 | } else { 257 | parentTest = nil 258 | subTests = map[string]*Test{} 259 | if curTest == nil { 260 | if suiteStack.count > 0 { 261 | prevSuite := suiteStack.Pop() 262 | suites = append(suites, curSuite) 263 | curSuite = prevSuite 264 | continue 265 | } else { 266 | return nil, fmt.Errorf("%d: orphan end test", scanner.Line()) 267 | } 268 | } 269 | if tokens[2] != curTest.Name { 270 | err := fmt.Errorf("%d: name mismatch (try disabling parallel mode)", scanner.Line()) 271 | return nil, err 272 | } 273 | } 274 | curTest.Status = Token2Status(tokens[1]) 275 | if curTest.Status == UnknownStatus { 276 | return nil, fmt.Errorf("%d: unknown status - %s", scanner.Line(), tokens[1]) 277 | } 278 | if Options.FailOnRace && hasDatarace(out) { 279 | curTest.Status = Failed 280 | } 281 | curTest.Time = tokens[3] 282 | 283 | if len(out) > 0 { 284 | message := strings.Join(out, "\n") 285 | prevTest, err := getPreviousFailTest(curSuite, curTest) 286 | var test *Test 287 | if err == nil && prevTest.AppendedErrorOutput == false { 288 | test = prevTest 289 | } else { 290 | test = curTest 291 | } 292 | if test.isParentTest == false { 293 | test.Message += message 294 | test.AppendedErrorOutput = isErrorOutput(message) 295 | } 296 | } 297 | 298 | if appendTest { 299 | curSuite.Tests = append(curSuite.Tests, curTest) 300 | } 301 | curTest = nil 302 | out = []string{} 303 | continue 304 | } 305 | 306 | tokens = findSuite(line) 307 | if tokens != nil { 308 | if curTest != nil { 309 | // This occurs when the last test ended with a panic. 310 | handlePanic() 311 | } 312 | appendError() 313 | curSuite.Name = suitePrefix + tokens[2] 314 | curSuite.Time = tokens[3] 315 | suites = append(suites, curSuite) 316 | curSuite = nil 317 | continue 318 | } 319 | 320 | if isExit(line) || (line == "FAIL") || (line == "PASS") { 321 | continue 322 | } 323 | 324 | out = append(out, line) 325 | } 326 | 327 | if err := scanner.Err(); err != nil { 328 | return nil, err 329 | } 330 | 331 | if curTest != nil { 332 | // This occurs when the last test fatal'd outside of the `go test` runner. 333 | handlePanic() 334 | } 335 | 336 | // If there were no suites found, but everything else went OK, return a 337 | // generic suite. 338 | if len(suites) == 0 && curSuite != nil { 339 | if curSuite.Name == "" { 340 | curSuite.Name = suitePrefix 341 | } 342 | // Catch any post-failure messages from the last test 343 | appendError() 344 | } 345 | 346 | if curSuite != nil && len(curSuite.Tests) > 0 { 347 | suites = append(suites, curSuite) 348 | } 349 | 350 | return Suites(suites), nil 351 | } 352 | -------------------------------------------------------------------------------- /lib/parsers2.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import "io" 4 | 5 | // Parser generates suites 6 | type Parser interface { 7 | Scan() bool 8 | Suite() *Suite 9 | Err() error 10 | } 11 | 12 | // GtParser is a gotest output parser 13 | type GtParser struct { 14 | suite *Suite 15 | tests map[string]*Test 16 | lex Lexer 17 | } 18 | 19 | // Scan scans for the next suite 20 | func (gtp *GtParser) Scan() bool { 21 | return true 22 | } 23 | 24 | // Suite is the current suite 25 | func (gtp *GtParser) Suite() *Suite { 26 | return nil 27 | } 28 | 29 | // Err is the current error 30 | func (gtp *GtParser) Err() error { 31 | return nil 32 | } 33 | 34 | // NewGtParser return a new gotest parser 35 | func NewGtParser(in io.Reader) Parser { 36 | return &GtParser{ 37 | suite: nil, 38 | tests: make(map[string]*Test), 39 | lex: NewGotestLexer(in), 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/types.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | // Status is test status 4 | type Status int 5 | 6 | // Test statuses 7 | const ( 8 | UnknownStatus Status = iota 9 | Failed 10 | Skipped 11 | Passed 12 | ) 13 | 14 | // Test data structure 15 | type Test struct { 16 | Name, Time, Message string 17 | Status Status 18 | AppendedErrorOutput bool 19 | isParentTest bool 20 | } 21 | 22 | // Suite of tests (found in some unit testing frameworks) 23 | type Suite struct { 24 | Name string 25 | Time string 26 | Status string 27 | Tests []*Test 28 | } 29 | 30 | // NumPassed return number of passed tests in the suite 31 | func (suite *Suite) NumPassed() int { 32 | return suite.numStatus(Passed) 33 | } 34 | 35 | // NumSkipped return number of skipped tests in suite 36 | func (suite *Suite) NumSkipped() int { 37 | return suite.numStatus(Skipped) 38 | } 39 | 40 | // NumFailed return number of failed tests in suite 41 | func (suite *Suite) NumFailed() int { 42 | return suite.numStatus(Failed) 43 | } 44 | 45 | // numStatus returns the number of tests in status 46 | func (suite *Suite) numStatus(status Status) int { 47 | count := 0 48 | for _, test := range suite.Tests { 49 | if test.Status == status { 50 | count++ 51 | } 52 | } 53 | return count 54 | } 55 | 56 | // Len return the number of tests in the suite 57 | func (suite *Suite) Len() int { 58 | return len(suite.Tests) 59 | } 60 | 61 | // Suites is a list of suites 62 | type Suites []*Suite 63 | 64 | // HasFailures return true is there's at least one failing suite 65 | func (s Suites) HasFailures() bool { 66 | for _, suite := range s { 67 | if suite.NumFailed() > 0 { 68 | return true 69 | } 70 | } 71 | return false 72 | } 73 | 74 | // SuiteStack is a stack of test suites 75 | type SuiteStack struct { 76 | nodes []*Suite 77 | count int 78 | } 79 | 80 | // Push adds a node to the stack. 81 | func (s *SuiteStack) Push(n *Suite) { 82 | s.nodes = append(s.nodes[:s.count], n) 83 | s.count++ 84 | } 85 | 86 | // Pop removes and returns a node from the stack in last to first order. 87 | func (s *SuiteStack) Pop() *Suite { 88 | if s.count == 0 { 89 | return nil 90 | } 91 | s.count-- 92 | return s.nodes[s.count] 93 | } 94 | -------------------------------------------------------------------------------- /lib/types_test.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import "testing" 4 | 5 | func TestEmptySuite(t *testing.T) { 6 | suite := Suite{} 7 | t.Run("NumberOfTests", func(t *testing.T) { 8 | if count := suite.Len(); count != 0 { 9 | t.Fatal("Expected 0 tests; got:", count) 10 | } 11 | }) 12 | t.Run("NumberOfPassed", func(t *testing.T) { 13 | if passed := suite.NumPassed(); passed != 0 { 14 | t.Fatal("Expected 0 passed, got:", passed) 15 | } 16 | }) 17 | t.Run("NumberOfSkipped", func(t *testing.T) { 18 | if skipped := suite.NumSkipped(); skipped != 0 { 19 | t.Fatal("Expected 0 skipped, got:", skipped) 20 | } 21 | }) 22 | t.Run("NumberOfFailed", func(t *testing.T) { 23 | if failures := suite.NumFailed(); failures != 0 { 24 | t.Fatal("Expected 0 failures, got:", failures) 25 | } 26 | }) 27 | } 28 | 29 | func TestMixedSuite(t *testing.T) { 30 | suite := &Suite{ 31 | Tests: []*Test{ 32 | {Status: Skipped}, 33 | {Status: Failed}, 34 | {Status: Passed}, 35 | {Status: Skipped}, 36 | {Status: Failed}, 37 | {Status: Passed}, 38 | }, 39 | } 40 | t.Run("NumberOfTests", func(t *testing.T) { 41 | if count := suite.Len(); count != 6 { 42 | t.Fatal("Expected 6 tests; got:", count) 43 | } 44 | }) 45 | t.Run("NumberOfPassed", func(t *testing.T) { 46 | if passed := suite.NumPassed(); passed != 2 { 47 | t.Fatal("Expected 1 passed, got:", passed) 48 | } 49 | }) 50 | t.Run("NumberOfSkipped", func(t *testing.T) { 51 | if skipped := suite.NumSkipped(); skipped != 2 { 52 | t.Fatal("Expected 1 skipped, got:", skipped) 53 | } 54 | }) 55 | t.Run("NumberOfFailed", func(t *testing.T) { 56 | if failures := suite.NumFailed(); failures != 2 { 57 | t.Fatal("Expected 1 failures, got:", failures) 58 | } 59 | }) 60 | } 61 | 62 | func TestMultipleSuits(t *testing.T) { 63 | empty := Suite{} 64 | passed := Suite{Tests: []*Test{{Status: Passed}}} 65 | skipped := Suite{Tests: []*Test{{Status: Skipped}}} 66 | failed := Suite{Tests: []*Test{{Status: Failed}}} 67 | golden := Suites([]*Suite{&empty, &passed, &skipped}) 68 | 69 | t.Run("WithoutFailures", func(t *testing.T) { 70 | suites := golden 71 | if suites.HasFailures() { 72 | t.Fatal("Expected false, got: true") 73 | } 74 | }) 75 | t.Run("WithFailures", func(t *testing.T) { 76 | suites := append(golden, &failed) 77 | if !suites.HasFailures() { 78 | t.Fatal("Expected true, got: false") 79 | } 80 | }) 81 | } 82 | -------------------------------------------------------------------------------- /lib/xmlout.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | // XML output 4 | import ( 5 | "bytes" 6 | "encoding/xml" 7 | "fmt" 8 | "io" 9 | "strconv" 10 | "text/template" 11 | "time" 12 | ) 13 | 14 | const ( 15 | // XUnitTemplate is XML template for xunit style reporting 16 | XUnitTemplate string = ` 17 | {{range $suite := .Suites}} 18 | {{range $test := $suite.Tests}} 19 | {{if eq $test.Status $.Skipped }} {{end}} 20 | {{if eq $test.Status $.Failed }} 21 | 22 | {{end}} 23 | {{end}} 24 | {{end}}` 25 | 26 | // XMLMultiTemplate is template when we have multiple suites 27 | XMLMultiTemplate string = ` 28 | ` + XUnitTemplate + ` 29 | ` 30 | 31 | // XUnitNetTemplate is XML template for xunit.net 32 | // see https://xunit.codeplex.com/wikipage?title=XmlFormat 33 | XUnitNetTemplate string = ` 34 | 44 | {{range $suite := .Suites}} 45 | 50 | {{range $test := $suite.Tests}} 51 | 56 | {{if eq $test.Status $.Failed }} 57 | 58 | 59 | {{end}} 60 | {{end}} 61 | 62 | {{end}} 63 | 64 | ` 65 | ) 66 | 67 | // TestResults is passed to XML template 68 | type TestResults struct { 69 | Suites []*Suite 70 | Assembly string 71 | RunDate string 72 | RunTime string 73 | Time string 74 | Len int 75 | NumPassed int 76 | NumFailed int 77 | NumSkipped int 78 | 79 | Skipped Status 80 | Passed Status 81 | Failed Status 82 | } 83 | 84 | // calcTotals calculates grand total for all suites 85 | func (r *TestResults) calcTotals() { 86 | totalTime, _ := strconv.ParseFloat(r.Time, 64) 87 | for _, suite := range r.Suites { 88 | r.NumPassed += suite.NumPassed() 89 | r.NumFailed += suite.NumFailed() 90 | r.NumSkipped += suite.NumSkipped() 91 | 92 | suiteTime, _ := strconv.ParseFloat(suite.Time, 64) 93 | totalTime += suiteTime 94 | r.Time = fmt.Sprintf("%.3f", totalTime) 95 | } 96 | r.Len = r.NumPassed + r.NumSkipped + r.NumFailed 97 | } 98 | 99 | func escapeForXML(in string) (string, error) { 100 | w := &bytes.Buffer{} 101 | if err := xml.EscapeText(w, []byte(in)); err != nil { 102 | return "", fmt.Errorf("error escaping text: %s", err) 103 | } 104 | return w.String(), nil 105 | } 106 | 107 | // WriteXML exits xunit XML of tests to out 108 | func WriteXML(suites []*Suite, out io.Writer, xmlTemplate string, testTime time.Time) { 109 | testsResult := TestResults{ 110 | Suites: suites, 111 | Assembly: suites[len(suites)-1].Name, 112 | RunDate: testTime.Format("2006-01-02"), 113 | RunTime: testTime.Format("15:04:05"), 114 | Skipped: Skipped, 115 | Passed: Passed, 116 | Failed: Failed, 117 | } 118 | testsResult.calcTotals() 119 | t := template.New("test template").Funcs(template.FuncMap{ 120 | "escape": escapeForXML, 121 | }) 122 | 123 | t, err := t.Parse(xml.Header + xmlTemplate) 124 | if err != nil { 125 | fmt.Printf("Error in parse %v\n", err) 126 | return 127 | } 128 | err = t.Execute(out, testsResult) 129 | if err != nil { 130 | fmt.Printf("Error in execute %v\n", err) 131 | return 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "os" 8 | "time" 9 | 10 | "github.com/tebeka/go2xunit/lib" 11 | ) 12 | 13 | const ( 14 | // Version is the current version 15 | Version = "1.4.10" 16 | ) 17 | 18 | // getInput return input io.File from file name, if file name is - it will 19 | // return os.Stdin 20 | func getInput(filename string) (*os.File, error) { 21 | if filename == "-" || filename == "" { 22 | return os.Stdin, nil 23 | } 24 | 25 | return os.Open(filename) 26 | } 27 | 28 | // getInput return output io.File from file name, if file name is - it will 29 | // return os.Stdout 30 | func getOutput(filename string) (*os.File, error) { 31 | if filename == "-" || filename == "" { 32 | return os.Stdout, nil 33 | } 34 | 35 | return os.Create(filename) 36 | } 37 | 38 | // getIO returns input and output streams from file names 39 | func getIO(inFile, outFile string) (*os.File, io.Writer, error) { 40 | input, err := getInput(inFile) 41 | if err != nil { 42 | return nil, nil, fmt.Errorf("can't open %s for reading: %s", inFile, err) 43 | } 44 | 45 | output, err := getOutput(outFile) 46 | if err != nil { 47 | return nil, nil, fmt.Errorf("can't open %s for writing: %s", outFile, err) 48 | } 49 | 50 | return input, output, nil 51 | } 52 | 53 | func main() { 54 | if args.showVersion { 55 | fmt.Printf("go2xunit %s\n", Version) 56 | os.Exit(0) 57 | } 58 | 59 | // No time ... prefix for error messages 60 | log.SetFlags(0) 61 | 62 | if err := validateArgs(); err != nil { 63 | log.Fatalf("error: %s", err) 64 | } 65 | 66 | input, output, err := getIO(args.inFile, args.outFile) 67 | if err != nil { 68 | log.Fatalf("error: %s", err) 69 | } 70 | 71 | // We'd like the test time to be the time of the generated file 72 | var testTime time.Time 73 | stat, err := input.Stat() 74 | if err != nil { 75 | testTime = time.Now() 76 | } else { 77 | testTime = stat.ModTime() 78 | } 79 | 80 | var parse func(rd io.Reader, suiteName string) (lib.Suites, error) 81 | 82 | if args.isGocheck { 83 | parse = lib.ParseGocheck 84 | } else { 85 | parse = lib.ParseGotest 86 | } 87 | 88 | suites, err := parse(input, args.suitePrefix) 89 | if err != nil { 90 | log.Fatalf("error: %s", err) 91 | } 92 | if len(suites) == 0 { 93 | log.Fatalf("error: no tests found") 94 | os.Exit(1) 95 | } 96 | 97 | xmlTemplate := lib.XUnitTemplate 98 | if args.xunitnetOut { 99 | xmlTemplate = lib.XUnitNetTemplate 100 | } else if args.bambooOut || (len(suites) > 1) { 101 | xmlTemplate = lib.XMLMultiTemplate 102 | } 103 | 104 | lib.WriteXML(suites, output, xmlTemplate, testTime) 105 | if args.fail && suites.HasFailures() { 106 | os.Exit(1) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /regression_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "os/exec" 9 | "path/filepath" 10 | "regexp" 11 | "testing" 12 | ) 13 | 14 | var ( 15 | // FIXME 16 | ignored = map[string]bool{ 17 | "gotest-buildfailed.out": true, 18 | "gocheck-nofiles.out": true, 19 | } 20 | 21 | xTimeRe = regexp.MustCompile(`run-date="[^"]+" run-time="[^"]+"`) 22 | xTime = []byte(`run-date="2015-06-05" run-time="18:34:41"`) 23 | ) 24 | 25 | type fixFunc func([]byte) []byte 26 | 27 | func fixXUnit(in []byte) []byte { 28 | return xTimeRe.ReplaceAll(in, xTime) 29 | } 30 | 31 | func checkRegression(t *testing.T, inFile, outFile string, args []string, fixer fixFunc) { 32 | stdin, err := os.Open(inFile) 33 | if err != nil { 34 | t.Fatalf("can't open %s - %s", inFile, err) 35 | } 36 | defer stdin.Close() 37 | cmd := exec.Command("./go2xunit", args...) 38 | cmd.Stdin = stdin 39 | out, err := cmd.Output() 40 | // TODO: Use -fail 41 | if err != nil { 42 | t.Fatalf("error running on %s - %s", inFile, err) 43 | } 44 | 45 | expected, err := ioutil.ReadFile(outFile) 46 | if err != nil { 47 | t.Fatalf("can't read %s - %s", outFile, err) 48 | } 49 | if fixer != nil { 50 | out = fixer(out) 51 | expected = fixer(expected) 52 | } 53 | 54 | if !bytes.Equal(out, expected) { 55 | diff := runDiff(out, expected) 56 | t.Fatalf("%s - output mismatch\n\n%s", inFile, diff) 57 | } 58 | 59 | } 60 | 61 | func runDiff(out, expected []byte) string { 62 | left, right := "/tmp/go2xunit-expected", "/tmp/go2xunit-out" 63 | ioutil.WriteFile(left, out, 0600) 64 | ioutil.WriteFile(right, expected, 0600) 65 | diffOut, _ := exec.Command("diff", left, right).Output() 66 | return string(diffOut) 67 | } 68 | 69 | const dataPath = "_data" 70 | 71 | func iterCheck(t *testing.T, inType, outType string, args []string, fixer fixFunc) { 72 | pat := fmt.Sprintf(dataPath+"/in/%s*.out", inType) 73 | files, err := filepath.Glob(pat) 74 | if err != nil { 75 | t.Fatalf("no files matching %q", pat) 76 | } 77 | 78 | for _, inFile := range files { 79 | base := filepath.Base(inFile) 80 | if ignored[base] { 81 | continue 82 | } 83 | outFile := fmt.Sprintf(dataPath+"/out/%s/%s.xml", outType, base) 84 | name := fmt.Sprintf("%s-%s", outType, inFile) 85 | t.Run(name, func(t *testing.T) { 86 | checkRegression(t, inFile, outFile, args, fixer) 87 | }) 88 | } 89 | } 90 | 91 | func TestRegression(t *testing.T) { 92 | cmd := exec.Command("go", "build") 93 | if err := cmd.Run(); err != nil { 94 | t.Fatalf("can't build - %s", err) 95 | } 96 | 97 | iterCheck(t, "gotest", "xunit", nil, nil) 98 | iterCheck(t, "gocheck", "xunit", []string{"-gocheck"}, nil) 99 | iterCheck(t, "gotest", "xunit.net", []string{"-xunitnet"}, fixXUnit) 100 | iterCheck(t, "gocheck", "xunit.net", []string{"-gocheck", "-xunitnet"}, fixXUnit) 101 | } 102 | --------------------------------------------------------------------------------