// This test shows unexpected behaviour for log4js.configure() in log4js-node@0.4.3 and earlier:
// 1) log4js.configure(), log4js.configure(null), log4js.configure({}), log4js.configure(<some object with no levels prop>)
// all set all loggers levels to trace, even if they were previously set to something else.
// 2) log4js.configure({levels:{}}), log4js.configure({levels: {foo: bar}}) leaves previously set logger levels intact.
//

// Basic set up
var vows = require('vows');
var assert = require('assert');
var toLevel = require('../lib/levels').toLevel;

// uncomment one or other of the following to see progress (or not) while running the tests
// var showProgress = console.log;
var showProgress = function() {};


// Define the array of levels as string to iterate over.
var strLevels= ['Trace','Debug','Info','Warn','Error','Fatal'];

// setup the configurations we want to test
var configs = {
  'nop': 'nop', // special case where the iterating vows generator will not call log4js.configure
  'is undefined': undefined,
  'is null': null,
  'is empty': {},
  'has no levels': {foo: 'bar'},
  'has null levels': {levels: null},
  'has empty levels': {levels: {}},
  'has random levels': {levels: {foo: 'bar'}},
  'has some valid levels': {levels: {A: 'INFO'}}
}

// Set up the basic vows batches for this test
var batches = [];


function getLoggerName(level) {
  return level+'-logger';
}

// the common vows top-level context, whether log4js.configure is called or not
// just making sure that the code is common,
// so that there are no spurious errors in the tests themselves.
function getTopLevelContext(nop, configToTest, name) {
  return {
    topic: function() {
      var log4js = require('../lib/log4js');
      // create loggers for each level,
      // keeping the level in the logger's name for traceability
      strLevels.forEach(function(l) {
        log4js.getLogger(getLoggerName(l)).setLevel(l);
      });

      if (!nop) {
        showProgress('** Configuring log4js with', configToTest);
        log4js.configure(configToTest);
      }
      else {
        showProgress('** Not configuring log4js');
      }
      return log4js;
    }
  }
};

showProgress('Populating batch object...');

// Populating the batches programmatically,
// as there are (configs.length x strLevels.length x strLevels.length) = 324 possible test combinations
for (var cfg in configs) {
  var configToTest = configs[cfg];
  var nop = configToTest === 'nop';
  var context;
  if (nop) {
    context = 'Setting up loggers with initial levels, then NOT setting a configuration,';
  }
  else {
    context = 'Setting up loggers with initial levels, then setting a configuration which '+cfg+',';
  }

  showProgress('Setting up the vows batch and context for '+context);
  // each config to be tested has its own vows batch with a single top-level context
  var batch={};
  batch[context]= getTopLevelContext(nop, configToTest, context);
  batches.push(batch);

  // each top-level context has strLevels sub-contexts, one per logger which has set to a specific level in the top-level context's topic
  strLevels.forEach(function (baseLevel) {
    var baseLevelSubContext = 'and checking the logger whose level was set to '+baseLevel ;
    batch[context][baseLevelSubContext] = {topic: baseLevel};

    // each logging level has strLevels sub-contexts,
    // to exhaustively test all the combinations of setLevel(baseLevel) and isLevelEnabled(comparisonLevel) per config
    strLevels.forEach(function (comparisonLevel) {
      var comparisonLevelSubContext = 'with isLevelEnabled('+comparisonLevel+')';

      // calculate this independently of log4js, but we'll add a vow later on to check that we're not mismatched with log4js
      var expectedResult = strLevels.indexOf(baseLevel) <= strLevels.indexOf(comparisonLevel);

      // the topic simply gathers all the parameters for the vow into an object, to simplify the vow's work.
      batch[context][baseLevelSubContext][comparisonLevelSubContext] = {topic: function(baseLevel, log4js){
        return {comparisonLevel: comparisonLevel, baseLevel: baseLevel, log4js: log4js, expectedResult: expectedResult};
      }};

      var vow = 'should return '+expectedResult;
      batch[context][baseLevelSubContext][comparisonLevelSubContext][vow] = function(topic){
        var result = topic.log4js.getLogger(getLoggerName(topic.baseLevel)).isLevelEnabled(topic.log4js.levels.toLevel(topic.comparisonLevel));
        assert.equal(result, topic.expectedResult, 'Failed: '+getLoggerName(topic.baseLevel)+'.isLevelEnabled( '+topic.comparisonLevel+' ) returned '+result);
      };

      // the extra vow to check the comparison between baseLevel and comparisonLevel we performed earlier matches log4js' comparison too
      batch[context][baseLevelSubContext][comparisonLevelSubContext]['finally checking for comparison mismatch with log4js'] = function(topic){
        var er = topic.log4js.levels.toLevel(topic.baseLevel).isLessThanOrEqualTo(topic.log4js.levels.toLevel(topic.comparisonLevel));
        assert.equal(er, topic.expectedResult, 'Mismatch: for setLevel('+topic.baseLevel+') was expecting a comparison with '+topic.comparisonLevel+' to be '+topic.expectedResult);
      };
    });
  });
};

showProgress('Running tests');
var v = vows.describe('log4js.configure(), with or without a "levels" property');

batches.forEach(function(batch) {v=v.addBatch(batch)});

v.export(module);

