Skip to content

Commit

Permalink
Add tests for common types (#11)
Browse files Browse the repository at this point in the history
This PR adds tests for common types to ensure that they are being
encoded
  • Loading branch information
nhairs authored May 5, 2024
1 parent 390b356 commit 59439e9
Showing 1 changed file with 133 additions and 16 deletions.
149 changes: 133 additions & 16 deletions tests/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
## Standard Library
from dataclasses import dataclass
import datetime
import enum
import io
import json
import logging
import sys
import traceback
from types import TracebackType
from typing import Any, Generator
import uuid

## Installed
from freezegun import freeze_time
Expand Down Expand Up @@ -81,6 +84,34 @@ def get_traceback_from_exception_followed_by_log_call(env_: LoggingEnvironment)
return str_traceback


class SomeClass:
def __init__(self, thing: int):
self.thing = thing
return


@dataclass
class SomeDataclass:
things: str
stuff: int
junk: bool


try:
raise ValueError
except ValueError as e:
STATIC_TRACEBACK = e.__traceback__
del e


class MultiEnum(enum.Enum):
NONE = None
BOOL = False
STR = "somestring"
INT = 99
BYTES = b"somebytes"


### TESTS
### ============================================================================
def test_merge_record_extra():
Expand Down Expand Up @@ -344,13 +375,114 @@ def test_default_encoder_with_timestamp(env: LoggingEnvironment, class_: type[Ba
env.set_formatter(class_(timestamp=True))

env.logger.info("Hello")
print(env.buffer.getvalue())
log_json = env.load_json()

assert log_json["timestamp"] == "2017-07-14T02:40:00+00:00"
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
@pytest.mark.parametrize(
["obj", "type_"],
[
("somestring", str),
(1234, int),
(1234.5, float),
(False, bool),
(None, type(None)),
(b"somebytes", str),
(datetime.time(16, 45, 30, 100), str),
(datetime.date.today(), str),
(datetime.datetime.utcnow(), str),
(uuid.uuid4(), str),
(Exception, str),
(Exception("Foo occurred"), str),
(BaseException, str),
(BaseException("BaseFoo occurred"), str),
(STATIC_TRACEBACK, str),
(SomeDataclass(things="le_things", stuff=99, junk=False), dict),
(SomeDataclass, str),
(SomeClass, str),
(SomeClass(1234), str),
(MultiEnum.NONE, type(None)),
(MultiEnum.BOOL, bool),
(MultiEnum.STR, str),
(MultiEnum.INT, int),
(MultiEnum.BYTES, str),
(MultiEnum, str),
],
)
def test_common_types_encoded(
env: LoggingEnvironment, class_: type[BaseJsonFormatter], obj: object, type_: type
):
## Known bad cases
if class_ is JsonFormatter:
if obj is SomeDataclass or isinstance(obj, SomeDataclass) or isinstance(obj, enum.Enum):
pytest.xfail()

if pythonjsonlogger.ORJSON_AVAILABLE and class_ is OrjsonFormatter:
if (
obj is Exception
or obj is BaseException
or isinstance(obj, BaseException)
or obj is SomeDataclass
or obj is SomeClass
or isinstance(obj, SomeClass)
or isinstance(obj, bytes)
or isinstance(obj, TracebackType)
or isinstance(obj, enum.EnumMeta)
or obj is MultiEnum.BYTES
):
pytest.xfail()

if pythonjsonlogger.MSGSPEC_AVAILABLE and class_ is MsgspecFormatter:
if (
obj is Exception
or obj is BaseException
or isinstance(obj, BaseException)
or obj is SomeDataclass
or obj is SomeClass
or isinstance(obj, SomeClass)
or isinstance(obj, TracebackType)
or isinstance(obj, enum.EnumMeta)
or (
isinstance(obj, enum.Enum)
and obj in {MultiEnum.BYTES, MultiEnum.NONE, MultiEnum.BOOL}
)
):
pytest.xfail()

## Test
env.set_formatter(class_())
extra = {
"extra": obj,
"extra_dict": {"item": obj},
"extra_list": [obj],
}
env.logger.info("hello", extra=extra)
log_json = env.load_json()

assert isinstance(log_json["extra"], type_)
assert isinstance(log_json["extra_dict"]["item"], type_)
assert isinstance(log_json["extra_list"][0], type_)
return


@pytest.mark.parametrize("class_", ALL_FORMATTERS)
def test_custom_default(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
def custom_default(obj):
if isinstance(obj, SomeClass):
return {"TYPE": obj.thing}
return None

env.set_formatter(class_(json_default=custom_default)) # type: ignore[call-arg]
env.logger.info("hello", extra={"extra": SomeClass(999)})
log_json = env.load_json()

assert log_json["extra"] == {"TYPE": 999}
return


## JsonFormatter Specific
## -----------------------------------------------------------------------------
def test_json_default_encoder(env: LoggingEnvironment):
Expand All @@ -372,21 +504,6 @@ def test_json_default_encoder(env: LoggingEnvironment):
return


def test_json_custom_default(env: LoggingEnvironment):
def custom(o):
return "very custom"

env.set_formatter(JsonFormatter(json_default=custom))

msg = {"adate": datetime.datetime(1999, 12, 31, 23, 59), "normal": "value"}
env.logger.info(msg)
log_json = env.load_json()

assert log_json["adate"] == "very custom"
assert log_json["normal"] == "value"
return


def test_json_ensure_ascii_true(env: LoggingEnvironment):
env.set_formatter(JsonFormatter())
env.logger.info("Привет")
Expand Down

0 comments on commit 59439e9

Please sign in to comment.