...

Source file src/go.uber.org/zap/zapcore/level_test.go

Documentation: go.uber.org/zap/zapcore

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all 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,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package zapcore
    22  
    23  import (
    24  	"bytes"
    25  	"flag"
    26  	"strings"
    27  	"testing"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func TestLevelString(t *testing.T) {
    33  	tests := map[Level]string{
    34  		DebugLevel:   "debug",
    35  		InfoLevel:    "info",
    36  		WarnLevel:    "warn",
    37  		ErrorLevel:   "error",
    38  		DPanicLevel:  "dpanic",
    39  		PanicLevel:   "panic",
    40  		FatalLevel:   "fatal",
    41  		Level(-42):   "Level(-42)",
    42  		InvalidLevel: "Level(6)", // InvalidLevel does not have a name
    43  	}
    44  
    45  	for lvl, stringLevel := range tests {
    46  		assert.Equal(t, stringLevel, lvl.String(), "Unexpected lowercase level string.")
    47  		assert.Equal(t, strings.ToUpper(stringLevel), lvl.CapitalString(), "Unexpected all-caps level string.")
    48  	}
    49  }
    50  
    51  func TestLevelText(t *testing.T) {
    52  	tests := []struct {
    53  		text  string
    54  		level Level
    55  	}{
    56  		{"debug", DebugLevel},
    57  		{"info", InfoLevel},
    58  		{"", InfoLevel}, // make the zero value useful
    59  		{"warn", WarnLevel},
    60  		{"error", ErrorLevel},
    61  		{"dpanic", DPanicLevel},
    62  		{"panic", PanicLevel},
    63  		{"fatal", FatalLevel},
    64  	}
    65  	for _, tt := range tests {
    66  		if tt.text != "" {
    67  			lvl := tt.level
    68  			marshaled, err := lvl.MarshalText()
    69  			assert.NoError(t, err, "Unexpected error marshaling level %v to text.", &lvl)
    70  			assert.Equal(t, tt.text, string(marshaled), "Marshaling level %v to text yielded unexpected result.", &lvl)
    71  		}
    72  
    73  		var unmarshaled Level
    74  		err := unmarshaled.UnmarshalText([]byte(tt.text))
    75  		assert.NoError(t, err, `Unexpected error unmarshaling text %q to level.`, tt.text)
    76  		assert.Equal(t, tt.level, unmarshaled, `Text %q unmarshaled to an unexpected level.`, tt.text)
    77  	}
    78  }
    79  
    80  func TestParseLevel(t *testing.T) {
    81  	tests := []struct {
    82  		text  string
    83  		level Level
    84  		err   string
    85  	}{
    86  		{"info", InfoLevel, ""},
    87  		{"DEBUG", DebugLevel, ""},
    88  		{"FOO", 0, `unrecognized level: "FOO"`},
    89  	}
    90  	for _, tt := range tests {
    91  		parsedLevel, err := ParseLevel(tt.text)
    92  		if len(tt.err) == 0 {
    93  			assert.NoError(t, err)
    94  			assert.Equal(t, tt.level, parsedLevel)
    95  		} else {
    96  			assert.ErrorContains(t, err, tt.err)
    97  		}
    98  	}
    99  }
   100  
   101  func TestCapitalLevelsParse(t *testing.T) {
   102  	tests := []struct {
   103  		text  string
   104  		level Level
   105  	}{
   106  		{"DEBUG", DebugLevel},
   107  		{"INFO", InfoLevel},
   108  		{"WARN", WarnLevel},
   109  		{"ERROR", ErrorLevel},
   110  		{"DPANIC", DPanicLevel},
   111  		{"PANIC", PanicLevel},
   112  		{"FATAL", FatalLevel},
   113  	}
   114  	for _, tt := range tests {
   115  		var unmarshaled Level
   116  		err := unmarshaled.UnmarshalText([]byte(tt.text))
   117  		assert.NoError(t, err, `Unexpected error unmarshaling text %q to level.`, tt.text)
   118  		assert.Equal(t, tt.level, unmarshaled, `Text %q unmarshaled to an unexpected level.`, tt.text)
   119  	}
   120  }
   121  
   122  func TestWeirdLevelsParse(t *testing.T) {
   123  	tests := []struct {
   124  		text  string
   125  		level Level
   126  	}{
   127  		// I guess...
   128  		{"Debug", DebugLevel},
   129  		{"Info", InfoLevel},
   130  		{"Warn", WarnLevel},
   131  		{"Error", ErrorLevel},
   132  		{"Dpanic", DPanicLevel},
   133  		{"Panic", PanicLevel},
   134  		{"Fatal", FatalLevel},
   135  
   136  		// What even is...
   137  		{"DeBuG", DebugLevel},
   138  		{"InFo", InfoLevel},
   139  		{"WaRn", WarnLevel},
   140  		{"ErRor", ErrorLevel},
   141  		{"DpAnIc", DPanicLevel},
   142  		{"PaNiC", PanicLevel},
   143  		{"FaTaL", FatalLevel},
   144  	}
   145  	for _, tt := range tests {
   146  		var unmarshaled Level
   147  		err := unmarshaled.UnmarshalText([]byte(tt.text))
   148  		assert.NoError(t, err, `Unexpected error unmarshaling text %q to level.`, tt.text)
   149  		assert.Equal(t, tt.level, unmarshaled, `Text %q unmarshaled to an unexpected level.`, tt.text)
   150  	}
   151  }
   152  
   153  func TestLevelNils(t *testing.T) {
   154  	var l *Level
   155  
   156  	// The String() method will not handle nil level properly.
   157  	assert.Panics(t, func() {
   158  		assert.Equal(t, "Level(nil)", l.String(), "Unexpected result stringifying nil *Level.")
   159  	}, "Level(nil).String() should panic")
   160  
   161  	assert.Panics(t, func() {
   162  		_, _ = l.MarshalText() // should panic
   163  	}, "Expected to panic when marshalling a nil level.")
   164  
   165  	err := l.UnmarshalText([]byte("debug"))
   166  	assert.Equal(t, errUnmarshalNilLevel, err, "Expected to error unmarshalling into a nil Level.")
   167  }
   168  
   169  func TestLevelUnmarshalUnknownText(t *testing.T) {
   170  	var l Level
   171  	err := l.UnmarshalText([]byte("foo"))
   172  	assert.ErrorContains(t, err, "unrecognized level", "Expected unmarshaling arbitrary text to fail.")
   173  }
   174  
   175  func TestLevelAsFlagValue(t *testing.T) {
   176  	var (
   177  		buf bytes.Buffer
   178  		lvl Level
   179  	)
   180  	fs := flag.NewFlagSet("levelTest", flag.ContinueOnError)
   181  	fs.SetOutput(&buf)
   182  	fs.Var(&lvl, "level", "log level")
   183  
   184  	for _, expected := range []Level{DebugLevel, InfoLevel, WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, FatalLevel} {
   185  		assert.NoError(t, fs.Parse([]string{"-level", expected.String()}))
   186  		assert.Equal(t, expected, lvl, "Unexpected level after parsing flag.")
   187  		assert.Equal(t, expected, lvl.Get(), "Unexpected output using flag.Getter API.")
   188  		assert.Empty(t, buf.String(), "Unexpected error output parsing level flag.")
   189  		buf.Reset()
   190  	}
   191  
   192  	assert.Error(t, fs.Parse([]string{"-level", "nope"}))
   193  	assert.Equal(
   194  		t,
   195  		`invalid value "nope" for flag -level: unrecognized level: "nope"`,
   196  		strings.Split(buf.String(), "\n")[0], // second line is help message
   197  		"Unexpected error output from invalid flag input.",
   198  	)
   199  }
   200  
   201  // enablerWithCustomLevel is a LevelEnabler that implements a custom Level
   202  // method.
   203  type enablerWithCustomLevel struct{ lvl Level }
   204  
   205  var _ leveledEnabler = (*enablerWithCustomLevel)(nil)
   206  
   207  func (l *enablerWithCustomLevel) Enabled(lvl Level) bool {
   208  	return l.lvl.Enabled(lvl)
   209  }
   210  
   211  func (l *enablerWithCustomLevel) Level() Level {
   212  	return l.lvl
   213  }
   214  
   215  func TestLevelOf(t *testing.T) {
   216  	tests := []struct {
   217  		desc string
   218  		give LevelEnabler
   219  		want Level
   220  	}{
   221  		{desc: "debug", give: DebugLevel, want: DebugLevel},
   222  		{desc: "info", give: InfoLevel, want: InfoLevel},
   223  		{desc: "warn", give: WarnLevel, want: WarnLevel},
   224  		{desc: "error", give: ErrorLevel, want: ErrorLevel},
   225  		{desc: "dpanic", give: DPanicLevel, want: DPanicLevel},
   226  		{desc: "panic", give: PanicLevel, want: PanicLevel},
   227  		{desc: "fatal", give: FatalLevel, want: FatalLevel},
   228  		{
   229  			desc: "leveledEnabler",
   230  			give: &enablerWithCustomLevel{lvl: InfoLevel},
   231  			want: InfoLevel,
   232  		},
   233  		{
   234  			desc: "noop",
   235  			give: NewNopCore(), // always disabled
   236  			want: InvalidLevel,
   237  		},
   238  	}
   239  
   240  	for _, tt := range tests {
   241  		tt := tt
   242  		t.Run(tt.desc, func(t *testing.T) {
   243  			t.Parallel()
   244  
   245  			assert.Equal(t, tt.want, LevelOf(tt.give), "Reported level did not match.")
   246  		})
   247  	}
   248  }
   249  

View as plain text