Source file src/testing/example.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package testing
     6  
     7  import (
     8  	"fmt"
     9  	"slices"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  type InternalExample struct {
    15  	Name      string
    16  	F         func()
    17  	Output    string
    18  	Unordered bool
    19  }
    20  
    21  // RunExamples is an internal function but exported because it is cross-package;
    22  // it is part of the implementation of the "go test" command.
    23  func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
    24  	_, ok = runExamples(matchString, examples)
    25  	return ok
    26  }
    27  
    28  func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
    29  	ok = true
    30  
    31  	m := newMatcher(matchString, *match, "-test.run", *skip)
    32  
    33  	var eg InternalExample
    34  	for _, eg = range examples {
    35  		_, matched, _ := m.fullName(nil, eg.Name)
    36  		if !matched {
    37  			continue
    38  		}
    39  		ran = true
    40  		if !runExample(eg) {
    41  			ok = false
    42  		}
    43  	}
    44  
    45  	return ran, ok
    46  }
    47  
    48  func sortLines(output string) string {
    49  	lines := strings.Split(output, "\n")
    50  	slices.Sort(lines)
    51  	return strings.Join(lines, "\n")
    52  }
    53  
    54  // processRunResult computes a summary and status of the result of running an example test.
    55  // stdout is the captured output from stdout of the test.
    56  // recovered is the result of invoking recover after running the test, in case it panicked.
    57  //
    58  // If stdout doesn't match the expected output or if recovered is non-nil, it'll print the cause of failure to stdout.
    59  // If the test is chatty/verbose, it'll print a success message to stdout.
    60  // If recovered is non-nil, it'll panic with that value.
    61  // If the test panicked with nil, or invoked runtime.Goexit, it'll be
    62  // made to fail and panic with errNilPanicOrGoexit
    63  func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered any) (passed bool) {
    64  	passed = true
    65  	dstr := fmtDuration(timeSpent)
    66  	var fail string
    67  	got := strings.TrimSpace(stdout)
    68  	want := strings.TrimSpace(eg.Output)
    69  	if eg.Unordered {
    70  		if sortLines(got) != sortLines(want) && recovered == nil {
    71  			fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", stdout, eg.Output)
    72  		}
    73  	} else {
    74  		if got != want && recovered == nil {
    75  			fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
    76  		}
    77  	}
    78  	if fail != "" || !finished || recovered != nil {
    79  		fmt.Printf("%s--- FAIL: %s (%s)\n%s", chatty.prefix(), eg.Name, dstr, fail)
    80  		passed = false
    81  	} else if chatty.on {
    82  		fmt.Printf("%s--- PASS: %s (%s)\n", chatty.prefix(), eg.Name, dstr)
    83  	}
    84  
    85  	if chatty.on && chatty.json {
    86  		fmt.Printf("%s=== NAME   %s\n", chatty.prefix(), "")
    87  	}
    88  
    89  	if recovered != nil {
    90  		// Propagate the previously recovered result, by panicking.
    91  		panic(recovered)
    92  	} else if !finished {
    93  		panic(errNilPanicOrGoexit)
    94  	}
    95  
    96  	return
    97  }
    98  

View as plain text