launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/testing/checkers/log.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package checkers
     5  
     6  import (
     7  	"fmt"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"github.com/loggo/loggo"
    12  	gc "launchpad.net/gocheck"
    13  )
    14  
    15  type SimpleMessage struct {
    16  	Level   loggo.Level
    17  	Message string
    18  }
    19  
    20  type SimpleMessages []SimpleMessage
    21  
    22  func (s SimpleMessage) String() string {
    23  	return fmt.Sprintf("%s %s", s.Level, s.Message)
    24  }
    25  
    26  func (s SimpleMessages) GoString() string {
    27  	out := make([]string, len(s))
    28  	for i, m := range s {
    29  		out[i] = m.String()
    30  	}
    31  	return fmt.Sprintf("SimpleMessages{\n%s\n}", strings.Join(out, "\n"))
    32  }
    33  
    34  func logToSimpleMessages(log []loggo.TestLogValues) SimpleMessages {
    35  	out := make(SimpleMessages, len(log))
    36  	for i, val := range log {
    37  		out[i].Level = val.Level
    38  		out[i].Message = val.Message
    39  	}
    40  	return out
    41  }
    42  
    43  type logMatches struct {
    44  	*gc.CheckerInfo
    45  }
    46  
    47  func (checker *logMatches) Check(params []interface{}, names []string) (result bool, error string) {
    48  	var obtained SimpleMessages
    49  	switch params[0].(type) {
    50  	case []loggo.TestLogValues:
    51  		obtained = logToSimpleMessages(params[0].([]loggo.TestLogValues))
    52  	default:
    53  		return false, "Obtained value must be of type []loggo.TestLogValues or SimpleMessage"
    54  	}
    55  
    56  	var expected SimpleMessages
    57  	switch param := params[1].(type) {
    58  	case []SimpleMessage:
    59  		expected = SimpleMessages(param)
    60  	case SimpleMessages:
    61  		expected = param
    62  	case []string:
    63  		expected = make(SimpleMessages, len(param))
    64  		for i, s := range param {
    65  			expected[i] = SimpleMessage{
    66  				Message: s,
    67  				Level:   loggo.UNSPECIFIED,
    68  			}
    69  		}
    70  	default:
    71  		return false, "Expected value must be of type []string or []SimpleMessage"
    72  	}
    73  
    74  	obtainedSinceLastMatch := obtained
    75  	for len(expected) > 0 && len(obtained) >= len(expected) {
    76  		var msg SimpleMessage
    77  		msg, obtained = obtained[0], obtained[1:]
    78  		expect := expected[0]
    79  		if expect.Level != loggo.UNSPECIFIED && msg.Level != expect.Level {
    80  			continue
    81  		}
    82  		matched, err := regexp.MatchString(expect.Message, msg.Message)
    83  		if err != nil {
    84  			return false, fmt.Sprintf("bad message regexp %q: %v", expect.Message, err)
    85  		} else if !matched {
    86  			continue
    87  		}
    88  		expected = expected[1:]
    89  		obtainedSinceLastMatch = obtained
    90  	}
    91  	if len(obtained) < len(expected) {
    92  		params[0] = obtainedSinceLastMatch
    93  		params[1] = expected
    94  		return false, ""
    95  	}
    96  	return true, ""
    97  }
    98  
    99  // LogMatches checks whether a given TestLogValues actually contains the log
   100  // messages we expected. If you compare it against a list of strings, we only
   101  // compare that the strings in the messages are correct. You can alternatively
   102  // pass a slice of SimpleMessage and we will check that the log levels are
   103  // also correct.
   104  //
   105  // The log may contain additional messages before and after each of the specified
   106  // expected messages.
   107  var LogMatches gc.Checker = &logMatches{
   108  	&gc.CheckerInfo{Name: "LogMatches", Params: []string{"obtained", "expected"}},
   109  }