func registerTestSuite( makeDeps func(context.Context) BucketTestDeps, prototype bucketTestSetUpInterface) { suitePointerType := reflect.TypeOf(prototype) suiteType := suitePointerType.Elem() // We don't need anything fancy at the suite level. var ts ogletest.TestSuite ts.Name = getSuiteName(suiteType) // For each method, we create a test function. for _, method := range getTestMethods(suitePointerType) { var tf ogletest.TestFunction tf.Name = method.Name // Create an instance to be shared among SetUp and the test function itself. var instance reflect.Value = reflect.New(suiteType) // SetUp should create a bucket and then initialize the suite object, // remembering that the suite implements bucketTestSetUpInterface. var report reqtrace.ReportFunc tf.SetUp = func(*ogletest.TestInfo) { // Start tracing. var testCtx context.Context testCtx, report = reqtrace.Trace(context.Background(), "Overall test") // Set up the bucket and other dependencies. makeDepsCtx, makeDepsReport := reqtrace.StartSpan(testCtx, "Test setup") deps := makeDeps(makeDepsCtx) makeDepsReport(nil) // Hand off the dependencies and the context to the test. deps.ctx = testCtx instance.Interface().(bucketTestSetUpInterface).setUpBucketTest(deps) } // The test function itself should simply invoke the method. methodCopy := method tf.Run = func() { methodCopy.Func.Call([]reflect.Value{instance}) } // Report the test result. tf.TearDown = func() { report(errors.New( "TODO(jacobsa): Plumb through the test failure status. " + "Or offer tracing in ogletest itself.")) } // Save the test function. ts.TestFunctions = append(ts.TestFunctions, tf) } // Register the suite. ogletest.Register(ts) }
// Run a single test function, returning a slice of failure records. func runTestFunction(tf TestFunction) (failures []FailureRecord) { // Set up a clean slate for this test. Make sure to reset it after everything // below is finished, so we don't accidentally use it elsewhere. currentlyRunningTest = newTestInfo() defer func() { currentlyRunningTest = nil }() ti := currentlyRunningTest // Start a trace. var reportOutcome reqtrace.ReportFunc ti.Ctx, reportOutcome = reqtrace.Trace(ti.Ctx, tf.Name) // Run the SetUp function, if any, paying attention to whether it panics. setUpPanicked := false if tf.SetUp != nil { setUpPanicked = runWithProtection(func() { tf.SetUp(ti) }) } // Run the test function itself, but only if the SetUp function didn't panic. // (This includes AssertThat errors.) if !setUpPanicked { runWithProtection(tf.Run) } // Run the TearDown function, if any. if tf.TearDown != nil { runWithProtection(tf.TearDown) } // Tell the mock controller for the tests to report any errors it's sitting // on. ti.MockController.Finish() // Report the outcome to reqtrace. if len(ti.failureRecords) == 0 { reportOutcome(nil) } else { reportOutcome(fmt.Errorf("%v failure records", len(ti.failureRecords))) } return ti.failureRecords }