package integration_test

import (
	"fmt"
	"os"
	"strings"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/ginkgo/v2/internal/test_helpers"
	"github.com/onsi/ginkgo/v2/reporters"
	"github.com/onsi/ginkgo/v2/types"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("Reporting", func() {
	BeforeEach(func() {
		fm.MountFixture("reporting")
	})

	Describe("in-suite reporting with ReportBeforeEach, ReportAfterEach, ReportBeforeSuite and ReportAfterSuite", func() {
		It("preview thes uite via ReportBeforeSuite", func() {
			session := startGinkgo(fm.PathTo("reporting"), "--no-color", "--seed=17", "--procs=2")
			Eventually(session).Should(gexec.Exit(1))

			report, err := os.ReadFile(fm.PathTo("reporting", "report-before-suite-1.out"))
			Ω(err).ShouldNot(HaveOccurred())
			lines := strings.Split(string(report), "\n")
			Ω(lines).Should(ConsistOf(
				"ReportingFixture Suite - 17",
				"7 of 8",
			))
		})

		It("reports on each test via ReportBeforeEach", func() {
			session := startGinkgo(fm.PathTo("reporting"), "--no-color")
			Eventually(session).Should(gexec.Exit(1))

			report, err := os.ReadFile(fm.PathTo("reporting", "report-before-each.out"))
			Ω(err).ShouldNot(HaveOccurred())
			lines := strings.Split(string(report), "\n")
			Ω(lines).Should(ConsistOf(
				"passes - INVALID SPEC STATE",
				"is labelled - INVALID SPEC STATE",
				"fails - INVALID SPEC STATE",
				"panics - INVALID SPEC STATE",
				"has a progress report - INVALID SPEC STATE",
				"is pending - pending",
				"is skipped - INVALID SPEC STATE",
				"times out and fails during cleanup - INVALID SPEC STATE",
				"",
			))
		})

		It("reports on each test via ReportAfterEach", func() {
			session := startGinkgo(fm.PathTo("reporting"), "--no-color")
			Eventually(session).Should(gexec.Exit(1))

			report, err := os.ReadFile(fm.PathTo("reporting", "report-after-each.out"))
			Ω(err).ShouldNot(HaveOccurred())
			lines := strings.Split(string(report), "\n")
			Ω(lines).Should(ConsistOf(
				"passes - passed",
				"is labelled - passed",
				"fails - failed",
				"panics - panicked",
				"has a progress report - passed",
				"is pending - pending",
				"is skipped - skipped",
				"times out and fails during cleanup - timedout",
				"",
			))
		})

		It("reports on all the tests via ReportAfterSuite", func() {
			session := startGinkgo(fm.PathTo("reporting"), "--no-color", "--seed=17")
			Eventually(session).Should(gexec.Exit(1))

			report, err := os.ReadFile(fm.PathTo("reporting", "report-after-suite.out"))
			Ω(err).ShouldNot(HaveOccurred())
			lines := strings.Split(string(report), "\n")
			Ω(lines).Should(ConsistOf(
				"ReportingFixture Suite - 17",
				"1: [ReportBeforeSuite] - passed",
				"1: [BeforeSuite] - passed",
				"passes - passed",
				"is labelled - passed",
				"fails - failed",
				"panics - panicked",
				"has a progress report - passed",
				"is pending - pending",
				"is skipped - skipped",
				"times out and fails during cleanup - timedout",
				"1: [DeferCleanup (Suite)] - passed",
				"1: [DeferCleanup (Suite)] - passed",
				"",
			))
		})

		Context("when running in parallel", func() {
			It("reports only runs ReportBeforeSuite on proc 1 and reports on all the tests via ReportAfterSuite", func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "--seed=17", "--procs=2")
				Eventually(session).Should(gexec.Exit(1))

				By("validating the ReportBeforeSuite report")
				report, err := os.ReadFile(fm.PathTo("reporting", "report-before-suite-1.out"))
				Ω(err).ShouldNot(HaveOccurred())
				lines := strings.Split(string(report), "\n")
				Ω(lines).Should(ConsistOf(
					"ReportingFixture Suite - 17",
					"7 of 8",
				))

				By("ensuring there is only one ReportBeforeSuite report")
				Ω(fm.PathTo("reporting", "report-before-suite-2.out")).ShouldNot(BeARegularFile())

				By("validating the ReportAfterSuite report")
				report, err = os.ReadFile(fm.PathTo("reporting", "report-after-suite.out"))
				Ω(err).ShouldNot(HaveOccurred())
				lines = strings.Split(string(report), "\n")
				Ω(lines).Should(ConsistOf(
					"ReportingFixture Suite - 17",
					"1: [ReportBeforeSuite] - passed",
					"1: [BeforeSuite] - passed",
					"2: [BeforeSuite] - passed",
					"passes - passed",
					"is labelled - passed",
					"fails - failed",
					"panics - panicked",
					"has a progress report - passed",
					"is pending - pending",
					"is skipped - skipped",
					"times out and fails during cleanup - timedout",
					"1: [DeferCleanup (Suite)] - passed",
					"1: [DeferCleanup (Suite)] - passed",
					"2: [DeferCleanup (Suite)] - passed",
					"2: [DeferCleanup (Suite)] - passed",
					"",
				))
			})
		})

		Context("when a ReportAfterSuite node fails", func() {
			It("reports on it", func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "--seed=17", "--procs=2")
				Eventually(session).Should(gexec.Exit(1))

				Ω(string(session.Out.Contents())).Should(ContainSubstring("[ReportAfterSuite] my report"))
				Ω(string(session.Out.Contents())).Should(ContainSubstring("fail!\n  In [ReportAfterSuite] at:"))
			})
		})
	})

	Describe("JSON and JUnit reporting", func() {
		checkJSONReport := func(report types.Report) {
			Ω(report.SuitePath).Should(Equal(fm.AbsPathTo("reporting")))
			Ω(report.SuiteDescription).Should(Equal("ReportingFixture Suite"))
			Ω(report.SuiteConfig.ParallelTotal).Should(Equal(2))
			Ω(report.SpecReports).Should(HaveLen(16)) //8 tests + (1 before-suite + 2 defercleanup after-suite)*2(nodes) + 1 report-before-suite + 1 report-after-suite

			specReports := Reports(report.SpecReports)
			Ω(specReports.WithLeafNodeType(types.NodeTypeIt)).Should(HaveLen(8))
			Ω(specReports.Find("passes")).Should(HavePassed())
			Ω(specReports.Find("is labelled")).Should(HavePassed())
			Ω(specReports.Find("is labelled").Labels()).Should(Equal([]string{"dog", "cat"}))
			Ω(specReports.Find("fails")).Should(HaveFailed("fail!", types.FailureNodeIsLeafNode, CapturedGinkgoWriterOutput("some ginkgo-writer output")))
			Ω(specReports.Find("panics")).Should(HavePanicked("boom"))
			Ω(specReports.Find("is pending")).Should(BePending())
			Ω(specReports.Find("is skipped").State).Should(Equal(types.SpecStateSkipped))
			Ω(specReports.Find("times out and fails during cleanup")).Should(HaveTimedOut("A node timeout occurred"))
			Ω(specReports.Find("times out and fails during cleanup").AdditionalFailures[0].Failure.Message).Should(Equal("double-whammy"))
			Ω(specReports.Find("times out and fails during cleanup").AdditionalFailures[0].Failure.FailureNodeType).Should(Equal(types.NodeTypeCleanupAfterEach))
			Ω(specReports.FindByLeafNodeType(types.NodeTypeReportBeforeSuite)).Should(HavePassed())
			Ω(specReports.Find("my report")).Should(HaveFailed("fail!", types.FailureNodeIsLeafNode, types.NodeTypeReportAfterSuite))
			Ω(specReports.FindByLeafNodeType(types.NodeTypeBeforeSuite)).Should(HavePassed())
			Ω(specReports.FindByLeafNodeType(types.NodeTypeCleanupAfterSuite)).Should(HavePassed())

			//check that progress reporst are correctly embedded
			Ω(specReports.Find("passes").ProgressReports).Should(BeEmpty())
			Ω(specReports.Find("has a progress report").ProgressReports).ShouldNot(BeEmpty())
			var highlightedFunction types.FunctionCall
			for _, functionCall := range specReports.Find("has a progress report").ProgressReports[0].SpecGoroutine().Stack {
				if functionCall.Highlight {
					highlightedFunction = functionCall
					break
				}
			}
			Ω(highlightedFunction).ShouldNot(BeZero())
			Ω(highlightedFunction.Source[highlightedFunction.SourceHighlight]).Should(ContainSubstring("time.Sleep("))
		}

		checkJSONSubpackageReport := func(report types.Report) {
			Ω(report.SuitePath).Should(Equal(fm.AbsPathTo("reporting", "reporting_sub_package")))
			Ω(report.SuiteDescription).Should(Equal("Reporting SubPackage Suite"))
			Ω(report.SuiteConfig.ParallelTotal).Should(Equal(2))
			Ω(report.SpecReports).Should(HaveLen(3))

			specReports := Reports(report.SpecReports)
			Ω(specReports.Find("passes here too")).Should(HavePassed())
			Ω(specReports.Find("fails here too")).Should(HaveFailed("fail!", types.FailureNodeIsLeafNode, CapturedStdOutput("some std output")))
			Ω(specReports.Find("panics here too")).Should(HavePanicked("bam!"))
		}

		checkJSONFailedCompilationReport := func(report types.Report) {
			Ω(report.SuitePath).Should(Equal(fm.AbsPathTo("reporting", "malformed_sub_package")))
			Ω(report.SuiteDescription).Should(Equal(""))
			Ω(report.SuiteConfig.RandomSeed).Should(Equal(int64(17)))
			Ω(report.SpecialSuiteFailureReasons).Should(ContainElement(ContainSubstring("Failed to compile malformed_sub_package:")))
			Ω(report.SpecReports).Should(HaveLen(0))
		}

		getTestCase := func(name string, tests []reporters.JUnitTestCase) reporters.JUnitTestCase {
			for _, test := range tests {
				if test.Name == name {
					return test
				}
			}

			return reporters.JUnitTestCase{}
		}

		checkJUnitReport := func(suite reporters.JUnitTestSuite) {
			Ω(suite.Name).Should(Equal("ReportingFixture Suite"))
			Ω(suite.Package).Should(Equal(fm.AbsPathTo("reporting")))
			Ω(suite.Tests).Should(Equal(16))
			Ω(suite.Disabled).Should(Equal(1))
			Ω(suite.Skipped).Should(Equal(1))
			Ω(suite.Errors).Should(Equal(1))
			Ω(suite.Failures).Should(Equal(3))
			Ω(suite.Properties.WithName("SuiteSucceeded")).Should(Equal("false"))
			Ω(suite.Properties.WithName("RandomSeed")).Should(Equal("17"))
			Ω(suite.Properties.WithName("ParallelTotal")).Should(Equal("2"))
			Ω(getTestCase("[ReportBeforeSuite]", suite.TestCases).Status).Should(Equal("passed"))
			Ω(getTestCase("[BeforeSuite]", suite.TestCases).Status).Should(Equal("passed"))
			Ω(getTestCase("[It] reporting test passes", suite.TestCases).Classname).Should(Equal("ReportingFixture Suite"))
			Ω(getTestCase("[It] reporting test passes", suite.TestCases).Status).Should(Equal("passed"))
			Ω(getTestCase("[It] reporting test passes", suite.TestCases).Failure).Should(BeNil())
			Ω(getTestCase("[It] reporting test passes", suite.TestCases).Error).Should(BeNil())
			Ω(getTestCase("[It] reporting test passes", suite.TestCases).Skipped).Should(BeNil())

			Ω(getTestCase("[It] reporting test labelled tests is labelled [dog, cat]", suite.TestCases).Status).Should(Equal("passed"))

			Ω(getTestCase("[It] reporting test panics", suite.TestCases).Status).Should(Equal("panicked"))
			Ω(getTestCase("[It] reporting test panics", suite.TestCases).Error.Message).Should(Equal("boom"))
			Ω(getTestCase("[It] reporting test panics", suite.TestCases).Error.Type).Should(Equal("panicked"))

			Ω(getTestCase("[It] reporting test fails", suite.TestCases).Failure.Message).Should(Equal("fail!"))
			Ω(getTestCase("[It] reporting test fails", suite.TestCases).Status).Should(Equal("failed"))
			Ω(getTestCase("[It] reporting test fails", suite.TestCases).SystemErr).Should(ContainSubstring("some ginkgo-writer output"))

			Ω(getTestCase("[It] reporting test is pending", suite.TestCases).Status).Should(Equal("pending"))
			Ω(getTestCase("[It] reporting test is pending", suite.TestCases).Skipped.Message).Should(Equal("pending"))

			Ω(getTestCase("[DeferCleanup (Suite)]", suite.TestCases).Status).Should(Equal("passed"))
			Ω(getTestCase("[ReportAfterSuite] my report", suite.TestCases).Status).Should(Equal("failed"))

			Ω(getTestCase("[It] reporting test is skipped", suite.TestCases).Status).Should(Equal("skipped"))
			Ω(getTestCase("[It] reporting test is skipped", suite.TestCases).Skipped.Message).Should(Equal("skipped - skip"))

			Ω(getTestCase("[It] reporting test times out and fails during cleanup", suite.TestCases).Status).Should(Equal("timedout"))
			Ω(getTestCase("[It] reporting test times out and fails during cleanup", suite.TestCases).Failure.Message).Should(Equal("A node timeout occurred"))
			Ω(getTestCase("[It] reporting test times out and fails during cleanup", suite.TestCases).Failure.Description).Should(ContainSubstring("<-ctx.Done()"))
			Ω(getTestCase("[It] reporting test times out and fails during cleanup", suite.TestCases).Failure.Description).Should(ContainSubstring("[FAILED] A node timeout occurred and then the following failure was recorded in the timedout node before it exited:\nfailure-after-timeout"))
			Ω(getTestCase("[It] reporting test times out and fails during cleanup", suite.TestCases).SystemErr).Should(ContainSubstring("[FAILED] double-whammy"))

			buf := gbytes.NewBuffer()
			fmt.Fprintf(buf, getTestCase("[It] reporting test has a progress report", suite.TestCases).SystemErr)
			Ω(buf).Should(gbytes.Say(`some ginkgo-writer preamble`))
			Ω(buf).Should(gbytes.Say(`reporting test has a progress report \(Spec Runtime:`))
			Ω(buf).Should(gbytes.Say(`goroutine \d+ \[sleep\]`))
			Ω(buf).Should(gbytes.Say(`>\s*time\.Sleep\(`))
			Ω(buf).Should(gbytes.Say(`some ginkgo-writer postamble`))
		}

		checkJUnitSubpackageReport := func(suite reporters.JUnitTestSuite) {
			Ω(suite.Name).Should(Equal("Reporting SubPackage Suite"))
			Ω(suite.Package).Should(Equal(fm.AbsPathTo("reporting", "reporting_sub_package")))
			Ω(suite.Tests).Should(Equal(3))
			Ω(suite.Errors).Should(Equal(1))
			Ω(suite.Failures).Should(Equal(1))
		}

		checkJUnitFailedCompilationReport := func(suite reporters.JUnitTestSuite) {
			Ω(suite.Name).Should(Equal(""))
			Ω(suite.Package).Should(Equal(fm.AbsPathTo("reporting", "malformed_sub_package")))
			Ω(suite.Properties.WithName("SpecialSuiteFailureReason")).Should(ContainSubstring("Failed to compile malformed_sub_package:"))
		}

		checkUnifiedJUnitReport := func(report reporters.JUnitTestSuites) {
			Ω(report.TestSuites).Should(HaveLen(3))
			Ω(report.Tests).Should(Equal(19))
			Ω(report.Disabled).Should(Equal(2))
			Ω(report.Errors).Should(Equal(2))
			Ω(report.Failures).Should(Equal(4))

			checkJUnitReport(report.TestSuites[0])
			checkJUnitFailedCompilationReport(report.TestSuites[1])
			checkJUnitSubpackageReport(report.TestSuites[2])
		}

		checkTeamcityReport := func(data string) {
			lines := strings.Split(data, "\n")
			Ω(lines).Should(ContainElement("##teamcity[testSuiteStarted name='ReportingFixture Suite']"))

			Ω(lines).Should(ContainElement("##teamcity[testStarted name='|[BeforeSuite|]']"))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFinished name='|[BeforeSuite|]'")))

			Ω(lines).Should(ContainElement("##teamcity[testStarted name='|[It|] reporting test passes']"))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFinished name='|[It|] reporting test passes'")))

			Ω(lines).Should(ContainElement("##teamcity[testStarted name='|[It|] reporting test panics']"))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFailed name='|[It|] reporting test panics' message='panicked - boom'")))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFinished name='|[It|] reporting test panics'")))

			Ω(lines).Should(ContainElement("##teamcity[testStarted name='|[It|] reporting test fails']"))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFailed name='|[It|] reporting test fails' message='failed - fail!'")))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testStdErr name='|[It|] reporting test fails' out='> Enter")))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFinished name='|[It|] reporting test fails'")))

			Ω(lines).Should(ContainElement("##teamcity[testStarted name='|[It|] reporting test is pending']"))
			Ω(lines).Should(ContainElement("##teamcity[testIgnored name='|[It|] reporting test is pending' message='pending']"))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFinished name='|[It|] reporting test is pending'")))

			Ω(lines).Should(ContainElement("##teamcity[testStarted name='|[It|] reporting test is skipped']"))
			Ω(lines).Should(ContainElement("##teamcity[testIgnored name='|[It|] reporting test is skipped' message='skipped - skip']"))
			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFailed name='|[It|] reporting test times out and fails during cleanup' message='timedout")))

			Ω(lines).Should(ContainElement(HavePrefix("##teamcity[testFinished name='|[It|] reporting test is skipped'")))

			Ω(lines).Should(ContainElement("##teamcity[testSuiteFinished name='ReportingFixture Suite']"))
		}

		checkTeamcitySubpackageReport := func(data string) {
			lines := strings.Split(data, "\n")
			Ω(lines).Should(ContainElement("##teamcity[testSuiteStarted name='Reporting SubPackage Suite']"))
			Ω(lines).Should(ContainElement("##teamcity[testSuiteFinished name='Reporting SubPackage Suite']"))
		}

		checkTeamcityFailedCompilationReport := func(data string) {
			lines := strings.Split(data, "\n")
			Ω(lines).Should(ContainElement("##teamcity[testSuiteStarted name='']"))
			Ω(lines).Should(ContainElement("##teamcity[testSuiteFinished name='']"))
		}

		Context("the default behavior", func() {
			BeforeEach(func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "-r", "--keep-going", "--procs=2", "--json-report=out.json", "--junit-report=out.xml", "--teamcity-report=out.tc", "-seed=17")
				Eventually(session).Should(gexec.Exit(1))
				Ω(session).ShouldNot(gbytes.Say("Could not open"))
			})

			It("generates single unified json and junit reports", func() {
				reports := fm.LoadJSONReports("reporting", "out.json")
				Ω(reports).Should(HaveLen(3))
				checkJSONReport(reports[0])
				checkJSONFailedCompilationReport(reports[1])
				checkJSONSubpackageReport(reports[2])

				junitReport := fm.LoadJUnitReport("reporting", "out.xml")
				checkUnifiedJUnitReport(junitReport)

				checkTeamcityReport(fm.ContentOf("reporting", "out.tc"))
				checkTeamcitySubpackageReport(fm.ContentOf("reporting", "out.tc"))
				checkTeamcityFailedCompilationReport(fm.ContentOf("reporting", "out.tc"))
			})
		})

		Context("with -output-dir", func() {
			BeforeEach(func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "-r", "--keep-going", "--procs=2", "--json-report=out.json", "--junit-report=out.xml", "--teamcity-report=out.tc", "--output-dir=./reports", "-seed=17")
				Eventually(session).Should(gexec.Exit(1))
				Ω(session).ShouldNot(gbytes.Say("Could not open"))
			})

			It("places the single unified json and junit reports in output-dir", func() {
				reports := fm.LoadJSONReports("reporting", "reports/out.json")
				Ω(reports).Should(HaveLen(3))
				checkJSONReport(reports[0])
				checkJSONFailedCompilationReport(reports[1])
				checkJSONSubpackageReport(reports[2])

				junitReport := fm.LoadJUnitReport("reporting", "reports/out.xml")
				checkUnifiedJUnitReport(junitReport)

				checkTeamcityReport(fm.ContentOf("reporting", "reports/out.tc"))
				checkTeamcitySubpackageReport(fm.ContentOf("reporting", "reports/out.tc"))
				checkTeamcityFailedCompilationReport(fm.ContentOf("reporting", "reports/out.tc"))
			})
		})

		Context("with -keep-separate-reports", func() {
			BeforeEach(func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "-r", "--keep-going", "--procs=2", "--json-report=out.json", "--junit-report=out.xml", "--teamcity-report=out.tc", "--keep-separate-reports", "-seed=17")
				Eventually(session).Should(gexec.Exit(1))
				Ω(session).ShouldNot(gbytes.Say("Could not open"))
			})

			It("keeps the separate reports in their respective packages", func() {
				reports := fm.LoadJSONReports("reporting", "out.json")
				Ω(reports).Should(HaveLen(1))
				checkJSONReport(reports[0])
				checkJUnitReport(fm.LoadJUnitReport("reporting", "out.xml").TestSuites[0])
				checkTeamcityReport(fm.ContentOf("reporting", "out.tc"))

				reports = fm.LoadJSONReports("reporting", "reporting_sub_package/out.json")
				Ω(reports).Should(HaveLen(1))
				checkJSONSubpackageReport(reports[0])
				checkJUnitSubpackageReport(fm.LoadJUnitReport("reporting", "reporting_sub_package/out.xml").TestSuites[0])
				checkTeamcitySubpackageReport(fm.ContentOf("reporting", "reporting_sub_package/out.tc"))

				reports = fm.LoadJSONReports("reporting", "malformed_sub_package/out.json")
				Ω(reports).Should(HaveLen(1))
				checkJSONFailedCompilationReport(reports[0])
				checkJUnitFailedCompilationReport(fm.LoadJUnitReport("reporting", "malformed_sub_package/out.xml").TestSuites[0])
				checkTeamcityFailedCompilationReport(fm.ContentOf("reporting", "malformed_sub_package/out.tc"))

				Ω(fm.PathTo("reporting", "nonginkgo_sub_package/out.json")).ShouldNot(BeAnExistingFile())
				Ω(fm.PathTo("reporting", "nonginkgo_sub_package/out.xml")).ShouldNot(BeAnExistingFile())
				Ω(fm.PathTo("reporting", "nonginkgo_sub_package/out.tc")).ShouldNot(BeAnExistingFile())
			})
		})

		Context("with -keep-separate-reports and -output-dir", func() {
			BeforeEach(func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "-r", "--keep-going", "--procs=2", "--json-report=out.json", "--junit-report=out.xml", "--teamcity-report=out.tc", "--keep-separate-reports", "--output-dir=./reports", "-seed=17")
				Eventually(session).Should(gexec.Exit(1))
				Ω(session).ShouldNot(gbytes.Say("Could not open"))
			})

			It("places the separate reports in the -output-dir", func() {
				reports := fm.LoadJSONReports("reporting", "reports/reporting_out.json")
				Ω(reports).Should(HaveLen(1))
				checkJSONReport(reports[0])
				checkJUnitReport(fm.LoadJUnitReport("reporting", "reports/reporting_out.xml").TestSuites[0])
				checkTeamcityReport(fm.ContentOf("reporting", "reports/reporting_out.tc"))

				reports = fm.LoadJSONReports("reporting", "reports/reporting_sub_package_out.json")
				Ω(reports).Should(HaveLen(1))
				checkJSONSubpackageReport(reports[0])
				checkJUnitSubpackageReport(fm.LoadJUnitReport("reporting", "reports/reporting_sub_package_out.xml").TestSuites[0])
				checkTeamcitySubpackageReport(fm.ContentOf("reporting", "reports/reporting_sub_package_out.tc"))

				reports = fm.LoadJSONReports("reporting", "reports/malformed_sub_package_out.json")
				Ω(reports).Should(HaveLen(1))
				checkJSONFailedCompilationReport(reports[0])
				checkJUnitFailedCompilationReport(fm.LoadJUnitReport("reporting", "reports/malformed_sub_package_out.xml").TestSuites[0])
				checkTeamcityFailedCompilationReport(fm.ContentOf("reporting", "reports/malformed_sub_package_out.tc"))

				Ω(fm.PathTo("reporting", "reports/nonginkgo_sub_package_out.json")).ShouldNot(BeAnExistingFile())
			})
		})

		Context("when keep-going is not set and a suite fails", func() {
			BeforeEach(func() {
				session := startGinkgo(fm.PathTo("reporting"), "--no-color", "-r", "--procs=2", "--json-report=out.json", "--junit-report=out.xml", "--teamcity-report=out.tc", "-coverprofile=cover.out", "-cpuprofile=cpu.out", "-seed=17", "--output-dir=./reports")
				Eventually(session).Should(gexec.Exit(1))
				Ω(session).ShouldNot(gbytes.Say("Could not open"))
			})

			It("reports about the suites that did not run", func() {
				reports := fm.LoadJSONReports("reporting", "reports/out.json")
				Ω(reports).Should(HaveLen(3))
				checkJSONReport(reports[0])
				Ω(reports[1].SpecialSuiteFailureReasons).Should(ContainElement(ContainSubstring("Failed to compile malformed_sub_package")))
				Ω(reports[2].SpecialSuiteFailureReasons).Should(ContainElement("Suite did not run because prior suites failed and --keep-going is not set"))
			})
		})
	})
})
