# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import re
import unittest

import PRESUBMIT

class MockInputApi(object):
  def __init__(self):
    self.re = re
    self.os_path = os.path
    self.files = []
    self.is_committing = False

  def AffectedFiles(self):
    return self.files

  def AffectedSourceFiles(self, fn):
    # we'll just pretend everything is a source file for the sake of simplicity
    return self.files

  def ReadFile(self, f):
    return f.NewContents()


class MockOutputApi(object):
  class PresubmitResult(object):
    def __init__(self, message, items=None, long_text=''):
      self.message = message
      self.items = items
      self.long_text = long_text

  class PresubmitError(PresubmitResult):
    def __init__(self, message, items, long_text=''):
      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
      self.type = 'error'

  class PresubmitPromptWarning(PresubmitResult):
    def __init__(self, message, items, long_text=''):
      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
      self.type = 'warning'

  class PresubmitNotifyResult(PresubmitResult):
    def __init__(self, message, items, long_text=''):
      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
      self.type = 'notify'

  class PresubmitPromptOrNotify(PresubmitResult):
    def __init__(self, message, items, long_text=''):
      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
      self.type = 'promptOrNotify'


class MockFile(object):
  def __init__(self, local_path, new_contents):
    self._local_path = local_path
    self._new_contents = new_contents
    self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]

  def ChangedContents(self):
    return self._changed_contents

  def NewContents(self):
    return self._new_contents

  def LocalPath(self):
    return self._local_path


class MockChange(object):
  def __init__(self, changed_files):
    self._changed_files = changed_files

  def LocalPaths(self):
    return self._changed_files


class HistogramOffByOneTest(unittest.TestCase):

  # Take an input and make sure the problems found equals the expectation.
  def simpleCheck(self, contents, expected_errors):
    input_api = MockInputApi()
    input_api.files.append(MockFile('test.cc', contents))
    results = PRESUBMIT._CheckForHistogramOffByOne(input_api, MockOutputApi())
    if expected_errors:
      self.assertEqual(1, len(results))
      self.assertEqual(expected_errors, len(results[0].items))
    else:
      self.assertEqual(0, len(results))

  def testValid(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);', 0)

  def testValidComments(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/ kFoo, /*...*/'
                     'kFooMax + 1);', 0)

  def testValidMultiLine(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n'
                     '                          kFoo,\n'
                     '                          kFooMax + 1);', 0)

  def testValidMultiLineComments(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",  // This is the name\n'
                     '                          kFoo,  /* The value */\n'
                     '                          kFooMax + 1 /* The max */ );',
                     0)

  def testNoPlusOne(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax);', 1)

  def testInvalidWithIgnore(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax); '
                     '// PRESUBMIT_IGNORE_UMA_MAX', 0)

  def testNoMax(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo + 1);', 1)

  def testNoMaxNoPlusOne(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);', 1)

  def testMultipleErrors(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n'
                     'printf("hello, world!");\n'
                     'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2)

  def testValidAndInvalid(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n'
                     'UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);'
                     'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2)

  def testInvalidMultiLine(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n'
                     '                          kFoo,\n'
                     '                          kFooMax + 2);', 1)

  def testInvalidComments(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/, val, /*...*/,'
                     'Max);\n', 1)

  def testInvalidMultiLineComments(self):
    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",  // This is the name\n'
                     '                          kFoo,  /* The value */\n'
                     '                          kFooMax + 2 /* The max */ );',
                     1)

if __name__ == '__main__':
  unittest.main()
