require File.expand_path('../../spec_helper', File.dirname(__FILE__))

describe JRuby::Rack::Logger do

  let(:real_logger) do
    org.jruby.rack.logging.BufferLogger.new
  end

  let(:servlet_context) do
    servlet_context = org.jruby.rack.mock.RackLoggingMockServletContext.new
    servlet_context.logger = real_logger
    servlet_context
  end

  let(:rack_config) do
    org.jruby.rack.servlet.ServletRackConfig.new(servlet_context)
  end

  let(:rack_context) do
    org.jruby.rack.servlet.DefaultServletRackContext.new(rack_config)
  end

  let(:level) { org.jruby.rack.RackLogger::Level }

  let(:logger) { JRuby::Rack::Logger.new real_logger }

  before { JRuby::Rack.context = rack_context }
  after { JRuby::Rack.context = nil }

  it 'works with a servlet context' do
    logger.debug?
    logger.debug 'hogy basza meg a zold tucsok!'
    expect(real_logger.logged_content).to match /^DEBUG.*hogy .* a zold tucsok!$/
  end

  it 'delegates to passed logger instance' do
    logger.debug 'debugging'
    expect(real_logger.logged_content).to match /^DEBUG.*debugging$/
    real_logger.reset
    logger.info 'infooo'
    expect(real_logger.logged_content).to match /^INFO.*infooo$/
    real_logger.reset
    logger.warn 'warning'
    expect(real_logger.logged_content).to match /^WARN.*warning$/
    real_logger.reset
    logger.error 'errored'
    expect(real_logger.logged_content).to match /^ERROR.*errored$/
    real_logger.reset
    logger.fatal 'totaal!'
    expect(real_logger.logged_content).to match /^FATAL.*totaal!$/
  end

  it 'uses JRuby::Rack.context when no initialize argument' do
    logger = JRuby::Rack::Logger.new
    logger.debug?
    logger.debug 'hogy basza meg a zold tucsok!'
    expect(logger.to_java(org.jruby.rack.RackLogger)).to be rack_context
  end

  it 'delegates level check (when level is not set)' do
    real_logger.level = level::INFO
    expect(logger.debug?).to be false
    expect(logger.info?).to be true
    real_logger.level = level::WARN
    expect(logger.info?).to be false
  end

  it 'uses level check when level is explicitly set' do
    real_logger.level = level::INFO
    logger.level = 2 # Logger.::WARN
    expect(logger.info?).to be false
    expect(logger.warn?).to be true
    logger.level = nil
    expect(logger.info?).to be true
  end

  it "combines level check with delegate's level" do
    real_logger.level = level::WARN
    logger.level = 1 # Logger.::INFO
    expect(logger.debug?).to be false
    expect(logger.info?).to be false
    expect(logger.warn?).to be true
    logger.level = nil
    expect(logger.info?).to be false
    expect(logger.debug?).to be false
    expect(logger.warn?).to be true
  end

  [:debug, :info, :warn, :error, :fatal].each do |level|
    it "logs at #{level} level" do
      logger.public_send(level, 'message')
      expect(real_logger.logged_content).to eql "#{level.to_s.upcase}: message\n"

      real_logger.reset
      logger.public_send(level, 'message') { 'ignored' }
      expect(real_logger.logged_content).to eql "#{level.to_s.upcase}: message\n"

      real_logger.reset
      logger.public_send(level, nil) { 'message' }
      expect(real_logger.logged_content).to eql "#{level.to_s.upcase}: message\n"


      real_logger.reset
      logger.public_send(level) { 'message' }
      expect(real_logger.logged_content).to eql "#{level.to_s.upcase}: message\n"
    end
  end

  it "disables real logger's formatting when formatter is set" do
    real_logger.formatting = true
    expect(real_logger.formatting?).to be true

    logger.formatter = Proc.new { |severity, timestamp, progname, msg| "#{severity[0, 1]} #{msg}" }
    logger.warn 'hogy basza meg a zold tucsok!'
    expect(real_logger.logged_content).to eql "W hogy basza meg a zold tucsok!\n"

    expect(real_logger.formatting?).to be false
  end

  it 'logs exception with trace when passed as argument' do
    begin
      raise IndexError.new('TEST')
    rescue => e
      logger.debug(e)
    end
    expect(real_logger.logged_content).to match /^DEBUG.*?IndexError.*?TEST.*?at.*?logger_spec.rb.*/m
  end

  it 'handles constant resolution (for Rails compatibility)' do
    expect(logger.class::DEBUG).to eql 0
    expect(logger.class::FATAL).to eql 4
  end

  describe JRuby::Rack::ServletLog do
    let(:servlet_context_logger) do
      org.jruby.rack.logging.ServletContextLogger.new(servlet_context)
    end

    it "writes messages to the servlet context" do
      JRuby::Rack.context = servlet_context_logger
      servlet_log = JRuby::Rack.send(:servlet_log)
      servlet_log.write "hello"
      expect(real_logger.logged_content).to match(/hello/)
      servlet_log.puts "hoja!hoj"
      expect(real_logger.logged_content).to match(/hoja!/)
      servlet_log.close
    end
  end
end