text: # Copyright 2013 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 unittest
  
  from telemetry import story
  from telemetry import page as page_module
  from telemetry import value
  from telemetry.value import improvement_direction
  from telemetry.value import list_of_scalar_values
  from telemetry.value import none_values
  
  
  class StatisticComputationTest(unittest.TestCase):
    def testVariance(self):
      self.assertAlmostEqual(
          list_of_scalar_values.Variance([]), 0)
      self.assertAlmostEqual(
          list_of_scalar_values.Variance([3]), 0)
      self.assertAlmostEqual(
          list_of_scalar_values.Variance([600, 470, 170, 430, 300]), 27130)
  
    def testStandardDeviation(self):
      self.assertAlmostEqual(
          list_of_scalar_values.StandardDeviation([]), 0)
      self.assertAlmostEqual(
          list_of_scalar_values.StandardDeviation([1]), 0)
      self.assertAlmostEqual(
          list_of_scalar_values.StandardDeviation([600, 470, 170, 430, 300]),
          164.71186, places=4)
  
    def testPooledVariance(self):
      self.assertAlmostEqual(
          list_of_scalar_values.PooledStandardDeviation([[], [], []]), 0)
      self.assertAlmostEqual(
          list_of_scalar_values.PooledStandardDeviation([[1], [], [3], []]), 0)
      self.assertAlmostEqual(
          list_of_scalar_values.PooledStandardDeviation([[1], [2], [3], [4]]), 0)
      self.assertAlmostEqual(list_of_scalar_values.PooledStandardDeviation(
          [[600, 470, 170, 430, 300],           # variance = 27130, std = 164.7
          [4000, 4020, 4230],                   # variance = 16233, std = 127.41
          [260, 700, 800, 900, 0, 120, 150]]),  # variance = 136348, std = 369.2
          282.7060,  # SQRT((27130 4 + 16233*2 + 136348*6)/12)
          places=4)
      self.assertAlmostEqual(list_of_scalar_values.PooledStandardDeviation(
          [[600, 470, 170, 430, 300],
           [4000, 4020, 4230],
           [260, 700, 800, 900, 0, 120, 150]],
          list_of_variances=[100000, 200000, 300000]),
          465.47466,  # SQRT((100000*4 + 200000* 2 + 300000*6)/12)
          places=4)
  
  
  class TestBase(unittest.TestCase):
    def setUp(self):
      story_set = story.StorySet(base_dir=os.path.dirname(__file__))
      story_set.AddStory(
          page_module.Page('http://www.bar.com/', story_set, story_set.base_dir))
      story_set.AddStory(
          page_module.Page('http://www.baz.com/', story_set, story_set.base_dir))
      story_set.AddStory(
          page_module.Page('http://www.foo.com/', story_set, story_set.base_dir))
      self.story_set = story_set
  
    @property
    def pages(self):
      return self.story_set.stories
  
  class ValueTest(TestBase):
    def testRepr(self):
      page = self.pages[0]
      v = list_of_scalar_values.ListOfScalarValues(
          page, 'x', 'unit', [10, 9, 9, 7], important=True, description='desc',
          tir_label='my_ir', std=42,
          improvement_direction=improvement_direction.DOWN)
  
      expected = ('ListOfScalarValues(http://www.bar.com/, x, unit, '
                  '[10, 9, 9, 7], important=True, description=desc, '
                  'tir_label=my_ir, std=42, '
                  'improvement_direction=down, grouping_keys={})')
  
      self.assertEquals(expected, str(v))
  
    def testListSamePageMerging(self):
      page0 = self.pages[0]
      v0 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          [10, 9, 9, 7], description='list-based metric',
          improvement_direction=improvement_direction.DOWN)
      v1 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          [300, 302, 303, 304], description='list-based metric',
          improvement_direction=improvement_direction.DOWN)
      self.assertTrue(v1.IsMergableWith(v0))
  
      vM = (list_of_scalar_values.ListOfScalarValues.
            MergeLikeValuesFromSamePage([v0, v1]))
      self.assertEquals(page0, vM.page)
      self.assertEquals('x', vM.name)
      self.assertEquals('unit', vM.units)
      self.assertEquals(True, vM.important)
      self.assertEquals([10, 9, 9, 7, 300, 302, 303, 304], vM.values)
      # Values from the same page use regular standard deviation.
      self.assertAlmostEqual(156.88849, vM.std, places=4)
      self.assertEquals('list-based metric', vM.description)
      self.assertEquals(improvement_direction.DOWN, vM.improvement_direction)
  
    def testListDifferentPageMerging(self):
      page0 = self.pages[0]
      page1 = self.pages[1]
      v0 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          [10, 9, 9, 7], improvement_direction=improvement_direction.DOWN)
      v1 = list_of_scalar_values.ListOfScalarValues(
          page1, 'x', 'unit',
          [300, 302, 303, 304], improvement_direction=improvement_direction.DOWN)
      self.assertTrue(v1.IsMergableWith(v0))
  
      vM = (list_of_scalar_values.ListOfScalarValues.
            MergeLikeValuesFromDifferentPages([v0, v1]))
      self.assertEquals(None, vM.page)
      self.assertEquals('x', vM.name)
      self.assertEquals('unit', vM.units)
      self.assertEquals(True, vM.important)
      self.assertEquals([10, 9, 9, 7, 300, 302, 303, 304], vM.values)
      # Values from different pages use pooled standard deviation.
      # SQRT((19/12 * 3 + 35/12 * 3)/6) = 1.5
      self.assertAlmostEqual(1.5, vM.std)
      self.assertEquals(improvement_direction.DOWN, vM.improvement_direction)
  
    def testListWithNoneValueMerging(self):
      page0 = self.pages[0]
      v0 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          [1, 2], improvement_direction=improvement_direction.UP)
      v1 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          None, none_value_reason='n',
          improvement_direction=improvement_direction.UP)
      self.assertTrue(v1.IsMergableWith(v0))
  
      vM = (list_of_scalar_values.ListOfScalarValues.
            MergeLikeValuesFromSamePage([v0, v1]))
      self.assertEquals(None, vM.values)
      expected_none_value_reason = (
          'Merging values containing a None value results in a None value. '
          'None values: [ListOfScalarValues(http://www.bar.com/, x, unit, None, '
          'important=True, description=None, tir_label=None, std=None,'
          ' improvement_direction=up, grouping_keys={})]')
      self.assertEquals(expected_none_value_reason, vM.none_value_reason)
      self.assertEquals(improvement_direction.UP, vM.improvement_direction)
  
    def testListWithNoneValueMustHaveNoneReason(self):
      page0 = self.pages[0]
      self.assertRaises(none_values.NoneValueMissingReason,
                        lambda: list_of_scalar_values.ListOfScalarValues(
                            page0, 'x', 'unit', None,
                            improvement_direction=improvement_direction.DOWN))
  
    def testListWithNoneReasonMustHaveNoneValue(self):
      page0 = self.pages[0]
      self.assertRaises(none_values.ValueMustHaveNoneValue,
                        lambda: list_of_scalar_values.ListOfScalarValues(
                            page0, 'x', 'unit', [1, 2],
                            none_value_reason='n',
                            improvement_direction=improvement_direction.UP))
  
    def testAsDict(self):
      v = list_of_scalar_values.ListOfScalarValues(
          None, 'x', 'unit', [1, 2],
          important=False, improvement_direction=improvement_direction.DOWN)
      d = v.AsDictWithoutBaseClassEntries()
  
      self.assertEquals(d['values'], [1, 2])
      self.assertAlmostEqual(d['std'], 0.7071, places=4)
  
    def testMergedValueAsDict(self):
      page0 = self.pages[0]
      v0 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          [10, 9, 9, 7], improvement_direction=improvement_direction.DOWN)
      v1 = list_of_scalar_values.ListOfScalarValues(
          page0, 'x', 'unit',
          [300, 302, 303, 304], improvement_direction=improvement_direction.DOWN)
      self.assertTrue(v1.IsMergableWith(v0))
  
      vM = (list_of_scalar_values.ListOfScalarValues.
            MergeLikeValuesFromSamePage([v0, v1]))
      d = vM.AsDict()
      self.assertEquals(d['values'], [10, 9, 9, 7, 300, 302, 303, 304])
      # Values from the same page use regular standard deviation.
      self.assertAlmostEqual(d['std'], 156.88849, places=4)
  
  
    def testNoneValueAsDict(self):
      v = list_of_scalar_values.ListOfScalarValues(
          None, 'x', 'unit', None,
          important=False, none_value_reason='n',
          improvement_direction=improvement_direction.UP)
      d = v.AsDictWithoutBaseClassEntries()
  
      self.assertEquals(d, {
            'values': None,
            'none_value_reason': 'n',
            'std': None
          })
  
    def testFromDictInts(self):
      d = {
        'type': 'list_of_scalar_values',
        'name': 'x',
        'units': 'unit',
        'values': [1, 2],
        'std': 0.7071,
        'improvement_direction': improvement_direction.DOWN
      }
      v = value.Value.FromDict(d, {})
  
      self.assertTrue(isinstance(v, list_of_scalar_values.ListOfScalarValues))
      self.assertEquals(v.values, [1, 2])
      self.assertEquals(v.std, 0.7071)
      self.assertEquals(improvement_direction.DOWN, v.improvement_direction)
  
    def testFromDictFloats(self):
      d = {
        'type': 'list_of_scalar_values',
        'name': 'x',
        'units': 'unit',
        'values': [1.3, 2.7, 4.5, 2.1, 3.4],
        'std': 0.901,
        'improvement_direction': improvement_direction.UP
      }
      v = value.Value.FromDict(d, {})
  
      self.assertTrue(isinstance(v, list_of_scalar_values.ListOfScalarValues))
      self.assertEquals(v.values, [1.3, 2.7, 4.5, 2.1, 3.4])
      self.assertEquals(v.std, 0.901)
  
    def testFromDictWithoutImprovementDirection(self):
      d = {
        'type': 'list_of_scalar_values',
        'name': 'x',
        'units': 'unit',
        'values': [1, 2],
        'std': 0.7071,
      }
      v = value.Value.FromDict(d, {})
  
      self.assertTrue(isinstance(v, list_of_scalar_values.ListOfScalarValues))
      self.assertIsNone(v.improvement_direction)
  
    def testFromDictNoneValue(self):
      d = {
        'type': 'list_of_scalar_values',
        'name': 'x',
        'units': 'unit',
        'values': None,
        'std': None,
        'none_value_reason': 'n',
        'improvement_direction': improvement_direction.DOWN
      }
      v = value.Value.FromDict(d, {})
  
      self.assertTrue(isinstance(v, list_of_scalar_values.ListOfScalarValues))
      self.assertEquals(v.values, None)
      self.assertEquals(v.none_value_reason, 'n')
  