1
0
mirror of https://github.com/rs/zerolog synced 2026-06-08 17:13:30 +00:00
Files
Marc Brooks f6fbd330be Test coverage improvements (#748)
* Test coverage improvements

Implements #397 and #591, might help with #473
Test coverage for core is 97.6% with only real fringe cases remaining.
Improve `Fields` `isNilValue()` portability.
Added a new global handler `FatalExitFunc` to allow intercepting `Fatal()` messages.
Fixed CBOR float constants (removed the CBOR prefix)

Added tests for:
  - global `FatalExitFunc` to allow intercepting Fatal messages (both for testing and public use).
  - `Logger`
    -  `DisableSampling`
    -  `.With()` copying existing context if present.
    -  `.With().Fields()` all forms of `ErrorStackMarshaler` returns.
    - `.WithLevel()` for `FatalLevel`, `PanicLevel`, and `DisabledLevel`.
    - `.Err()` with `nil` and non-`nil` `error` and test the resulting log level.
    - `.should()` covering `nil` writer.
    - `.Output()` gets context values.
    - `.UpdateContext()` on a disabled logger doesn't panic and is a nop.
    - `.With()` all forms of `ErrorStackMarshaler` returns.
  - with a `nil`writer.
  - `.Hook()` passing no hooks.
- `Array`
  - `.MarshalZerologArray` is a nop that won't panic.
- `Context`
  - ` .Err()` and `.AnErr()` for `nil` errors and all forms of `ErrorStackMarshaler` returns.
  - `Event`
    - `.Caller()` to ensure we don't panic or add invalid information if `runtime.Caller()` fails
    -` .Err()` and `.AnErr()` for `nil` errors and all forms of `ErrorStackMarshaler` returns.
  - `Fields`
    - ` .appendFields()`  all forms of `ErrorStackMarshaler` returns.
  - `HookLevel`
    - `.Run()` methods.
  - `LevelSampler`
    - `.Sample() methods.
  - `Syslog`
    - `.Write()`, `.WriteLevel()`, and `.Close()` methods.
    - `.WriteLevel()` with an `InvalidLevel`.
  - `Writer`
    - `.Write()` short write and error cases.
    - `MultiLevelWriter` `.WriteLevel()` and for `.Write()` error and  `.Close()` cases.
  - test of unmarshalling a level byte returns correct error.
  - CBOR decodeStream
    - `.decodeFloat()`, `.binaryFmt()`, `.DecodeIfBinaryToString()`, `.DecodeObjectToStr()`, `.DecodeIfBinaryToBytes()`, `.decodeTagData()`, and `.decodeSimpleFloat()`
    - handling of invalid UTF-8 sequences
    - handling of UTC times.
    - handling of timestamps
    - handling of various map lengths

Restructure `Event` `.caller()` so we test for ok and eliminate untestable coverage hole.

Restructure `Context` `.Err()` when the `ErrorStackMarshaler` returns a `nil` so there's code to cover.

Inverted logic for`Event` `.Caller()`'s call to `runtime.Caller()` for simpler testing.

Inverted logic for `Array` `.putArray()` and `Event` `.putEvent()` so there isn't uncoverable code.

Restructure `Field` `.appendFieldList()` to early return when `ErrorStackMarshaler` returns a `nil`

Added comments for things we can't get coverage on.

Did a go fmt ./...

Coverage of core is now 100% on `Array`, `Context`, `Ctx`, `Event`, `Field`, `Hook`, and `Syslog`.

Coverage of `Globals`, `Log`, `Sampler`, and `Writer` is almost all except some real edge-cases.

JSON encoder coverage is 100%

CBOR encoder coverage is 96.3% with base, cbor, string, time and types at 100% and decode_stream (which is lacks coverage on some panic states, and two incorrect coverage-tool lapses)

* Fix CBOR tests for StackMarshaler

Forgot to use the `decodeIfBinaryToString()`
2026-01-12 15:03:52 +00:00

103 lines
2.9 KiB
Go

// Package cbor provides primitives for storing different data
// in the CBOR (binary) format. CBOR is defined in RFC7049.
package cbor
import "time"
const (
majorOffset = 5
additionalMax = 23
// Non Values.
additionalTypeBoolFalse byte = 20
additionalTypeBoolTrue byte = 21
additionalTypeNull byte = 22
// Integer (+ve and -ve) Sub-types.
additionalTypeIntUint8 byte = 24
additionalTypeIntUint16 byte = 25
additionalTypeIntUint32 byte = 26
additionalTypeIntUint64 byte = 27
// Float Sub-types.
additionalTypeFloat16 byte = 25
additionalTypeFloat32 byte = 26
additionalTypeFloat64 byte = 27
additionalTypeBreak byte = 31
// Tag Sub-types.
additionalTypeTimestamp byte = 01
additionalTypeEmbeddedCBOR byte = 63
// Extended Tags - from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
additionalTypeTagNetworkAddr uint16 = 260
additionalTypeTagNetworkPrefix uint16 = 261
additionalTypeEmbeddedJSON uint16 = 262
additionalTypeTagHexString uint16 = 263
// Unspecified number of elements.
additionalTypeInfiniteCount byte = 31
)
const (
majorTypeUnsignedInt byte = iota << majorOffset // Major type 0
majorTypeNegativeInt // Major type 1
majorTypeByteString // Major type 2
majorTypeUtf8String // Major type 3
majorTypeArray // Major type 4
majorTypeMap // Major type 5
majorTypeTags // Major type 6
majorTypeSimpleAndFloat // Major type 7
)
const (
maskOutAdditionalType byte = (7 << majorOffset)
maskOutMajorType byte = 31
)
const (
float32Nan = "\x7f\xc0\x00\x00"
float32PosInfinity = "\x7f\x80\x00\x00"
float32NegInfinity = "\xff\x80\x00\x00"
float64Nan = "\x7f\xf8\x00\x00\x00\x00\x00\x00"
float64PosInfinity = "\x7f\xf0\x00\x00\x00\x00\x00\x00"
float64NegInfinity = "\xff\xf0\x00\x00\x00\x00\x00\x00"
)
// IntegerTimeFieldFormat indicates the format of timestamp decoded
// from an integer (time in seconds).
var IntegerTimeFieldFormat = time.RFC3339
// NanoTimeFieldFormat indicates the format of timestamp decoded
// from a float value (time in seconds and nanoseconds).
var NanoTimeFieldFormat = time.RFC3339Nano
func appendCborTypePrefix(dst []byte, major byte, number uint64) []byte {
var byteCount int
var minor byte
switch {
case number < 256:
byteCount = 1
minor = additionalTypeIntUint8
case number < 65536:
byteCount = 2
minor = additionalTypeIntUint16
case number < 4294967296:
byteCount = 4
minor = additionalTypeIntUint32
default:
byteCount = 8
minor = additionalTypeIntUint64
}
dst = append(dst, major|minor)
byteCount--
for ; byteCount >= 0; byteCount-- {
dst = append(dst, byte(number>>(uint(byteCount)*8)))
}
return dst
}