"""
Test Levels

- shown
- getLevel
- setLevel

"""

__RCSID__ = "$Id$"

import pytest

from DIRAC.FrameworkSystem.private.standardLogging.LogLevels import LogLevels
from DIRAC.FrameworkSystem.private.standardLogging.test.TestLogUtilities import gLogger, gLoggerReset, cleaningLog


def test_getAllPossibleLevels():
  """
  Make sure getAllPossibleLevels returns every existing level
  """
  _, log, sublog = gLoggerReset()
  levels = ["DEBUG", "VERBOSE", "INFO", "WARN", "NOTICE", "ERROR", "ALWAYS", "FATAL"]
  assert sorted(gLogger.getAllPossibleLevels()) == sorted(levels)
  assert sorted(log.getAllPossibleLevels()) == sorted(levels)
  assert sorted(sublog.getAllPossibleLevels()) == sorted(levels)


def test_setLevelInit():
  """
  Test setLevel and getLevel: initialization of gLogger
  """
  _, log, sublog = gLoggerReset()

  # make sure gLogger and its subloggers have a common level when initialized
  # we don't set the level of gLogger
  assert gLogger.getLevel() == 'NOTICE'
  assert log.getLevel() == 'NOTICE'
  assert sublog.getLevel() == 'NOTICE'


def test_setLevelgLogger():
  """
  Test setLevel and getLevel: set gLogger level
  """
  _, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  # as log and sublog levels has not been changed, they should inherit from the same level
  for level in levels:
    gLogger.setLevel(level)
    assert gLogger.getLevel() == level.upper()
    assert log.getLevel() == level.upper()
    assert sublog.getLevel() == level.upper()


def test_setLevelLog():
  """
  Test setLevel and getLevel: set log level
  """
  _, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  # set gLogger level
  gLogger.setLevel('notice')
  # by changing log level, gLogger should not be affected, subLogger should be
  for level in levels:
    log.setLevel(level)
    assert gLogger.getLevel() == 'NOTICE'
    assert log.getLevel() == level.upper()
    assert sublog.getLevel() == level.upper()


def test_setLevelSublog():
  """
  Test setLevel and getLevel: set sublog level
  """
  _, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  # set gLogger and log level
  gLogger.setLevel('notice')
  log.setLevel('warn')
  # by changing sublog level, gLogger and log should not be affected
  for level in levels:
    sublog.setLevel(level)
    assert gLogger.getLevel() == 'NOTICE'
    assert log.getLevel() == 'WARN'
    assert sublog.getLevel() == level.upper()


def test_setLevelStopPropagation():
  """
  Test setLevel and getLevel: set gLogger level while log and sublog have already be set
  """
  _, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  # by changing gLogger level, log and sublog should not be affected anymore as they have been changed manually
  log.setLevel('warn')
  sublog.setLevel('verbose')
  for level in levels:
    gLogger.setLevel(level)
    assert gLogger.getLevel() == level.upper()
    assert log.getLevel() == 'WARN'
    assert sublog.getLevel() == 'VERBOSE'


@pytest.mark.parametrize("loggerLevel, isSuperiorTo, logRecordLevel,", [
    ('debug', False, 'error'),
    ('error', True, 'debug'),
    ('info', False, 'info')
])
def test_setLevelShowngLogger(loggerLevel, isSuperiorTo, logRecordLevel):
  """
  Set gLogger level: check whether a log record should be displayed
  """
  capturedBackend, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  gLogger.setLevel(loggerLevel)

  # convert level name into its integer value
  logRecordLevelValue = LogLevels.getLevelValue(logRecordLevel)
  res = gLogger._createLogRecord(logRecordLevelValue, 'message', '')

  # clean the log to remove unecessary information
  logstring = cleaningLog(capturedBackend.getvalue())

  # if loggerLevel is superior to logRecordLevel then:
  # - log record should not appear
  # - shown should return False as the log doesn't appear
  # - value returned by createLogRecord should be False too
  isLoggerLvlSupToLogRecordLvl = LogLevels.getLevelValue(loggerLevel) > logRecordLevelValue
  assert isLoggerLvlSupToLogRecordLvl == isSuperiorTo

  if isLoggerLvlSupToLogRecordLvl:
    assert not gLogger.shown(logRecordLevel)
    assert not res
    assert logstring == ""
  else:
    assert gLogger.shown(logRecordLevel)
    assert res
    assert logstring == "Framework %s: message\n" % logRecordLevel.upper()
    capturedBackend.truncate(0)
    capturedBackend.seek(0)


@pytest.mark.parametrize("loggerLevel, isSuperiorTo, logRecordLevel,", [
    ('debug', False, 'error'),
    ('error', True, 'debug'),
    ('info', False, 'info')
])
def test_setLevelShownLog(loggerLevel, isSuperiorTo, logRecordLevel):
  """
  Set log level: check whether a log record should be displayed
  """
  capturedBackend, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  gLogger.setLevel('notice')
  log.setLevel(loggerLevel)

  # convert level name into its integer value
  logRecordLevelValue = LogLevels.getLevelValue(logRecordLevel)
  res = log._createLogRecord(logRecordLevelValue, 'message', '')

  # clean the log to remove unecessary information
  logstring = cleaningLog(capturedBackend.getvalue())

  # if loggLevel is superior to logRecordLevel then:
  # - log record should not appear
  # - shown should return False as the log doesn't appear
  # - value returned by createLogRecord should be False too
  isLoggerLvlSupToLogRecordLvl = LogLevels.getLevelValue(loggerLevel) > logRecordLevelValue
  assert isLoggerLvlSupToLogRecordLvl == isSuperiorTo

  if LogLevels.getLevelValue(loggerLevel) > logRecordLevelValue:
    assert not log.shown(logRecordLevel)
    assert not res
    assert logstring == ""
  else:
    assert log.shown(logRecordLevel)
    assert res
    assert logstring == "Framework/log %s: message\n" % logRecordLevel.upper()
    capturedBackend.truncate(0)
    capturedBackend.seek(0)


@pytest.mark.parametrize("loggerLevel, isSuperiorTo, logRecordLevel,", [
    ('debug', False, 'error'),
    ('error', True, 'debug'),
    ('info', False, 'info')
])
def test_setLevelShownSubLog(loggerLevel, isSuperiorTo, logRecordLevel):
  """
  Set sublog level: check whether a log record should be displayed
  """
  capturedBackend, log, sublog = gLoggerReset()
  levels = gLogger.getAllPossibleLevels()

  gLogger.setLevel('notice')
  log.setLevel('warn')
  sublog.setLevel(loggerLevel)

  # convert level name into its integer value
  logRecordLevelValue = LogLevels.getLevelValue(logRecordLevel)
  res = sublog._createLogRecord(logRecordLevelValue, 'message', '')

  # clean the log to remove unecessary information
  logstring = cleaningLog(capturedBackend.getvalue())

  # if logLevel is superior to logRecordLevel then:
  # - log record should not appear
  # - shown should return False as the log doesn't appear
  # - value returned by createLogRecord should be False too
  isLoggerLvlSupToLogRecordLvl = LogLevels.getLevelValue(loggerLevel) > logRecordLevelValue
  assert isLoggerLvlSupToLogRecordLvl == isSuperiorTo

  if LogLevels.getLevelValue(loggerLevel) > logRecordLevelValue:
    assert not sublog.shown(logRecordLevel)
    assert not res
    assert logstring == ""
  else:
    assert sublog.shown(logRecordLevel)
    assert res
    assert logstring == "Framework/log/sublog %s: message\n" % logRecordLevel.upper()
  capturedBackend.truncate(0)
  capturedBackend.seek(0)
