text: # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
  # Licensed under the Apache License, Version 2.0 (see LICENSE).
  
  import unittest
  
  from pants.engine.addressable import (
      MutationError,
      NotSerializableError,
      addressable,
      addressable_dict,
      addressable_list,
  )
  from pants.engine.objects import Resolvable, Serializable
  from pants.util.objects import Exactly, TypeConstraintError
  
  
  class SimpleSerializable(Serializable):
      def __init__(self, **kwargs):
          self._kwargs = kwargs
  
      def _asdict(self):
          return self._kwargs
  
  
  class CountingResolvable(Resolvable):
      def __init__(self, address, value):
          self._address = address
          self._value = value
          self._resolutions = 0
  
      @property
      def address(self):
          return self._address
  
      def resolve(self):
          try:
              return self._value
          finally:
              self._resolutions += 1
  
      @property
      def resolutions(self):
          return self._resolutions
  
  
  class AddressableDescriptorTest(unittest.TestCase):
      def test_inappropriate_application(self):
          class NotSerializable:
              def __init__(self, count):
                  super().__init__()
                  self.count = count
  
              @addressable(Exactly(int))
              def count(self):
                  pass
  
          with self.assertRaises(NotSerializableError):
              NotSerializable(42)
  
  
  class AddressableTest(unittest.TestCase):
      class Person(SimpleSerializable):
          def __init__(self, age):
              super(AddressableTest.Person, self).__init__()
              self.age = age
  
          @addressable(Exactly(int))
          def age(self):
              """Return the person's age in years.
  
              :rtype int
              """
  
      def test_none(self):
          person = self.Person(None)
  
          self.assertIsNone(person.age, None)
  
      def test_value(self):
          person = self.Person(42)
  
          self.assertEqual(42, person.age)
  
      def test_address(self):
          person = self.Person("//:meaning-of-life")
  
          self.assertEqual("//:meaning-of-life", person.age)
  
      def test_resolvable(self):
          resolvable_age = CountingResolvable("//:meaning-of-life", 42)
          person = self.Person(resolvable_age)
  
          self.assertEqual(0, resolvable_age.resolutions)
  
          self.assertEqual(42, person.age)
          self.assertEqual(1, resolvable_age.resolutions)
  
          self.assertEqual(42, person.age)
          self.assertEqual(2, resolvable_age.resolutions)
  
      def test_type_mismatch_value(self):
          with self.assertRaises(TypeConstraintError):
              self.Person(42.0)
  
      def test_type_mismatch_resolvable(self):
          resolvable_age = CountingResolvable("//:meaning-of-life", 42.0)
          person = self.Person(resolvable_age)
  
          with self.assertRaises(TypeConstraintError):
              person.age
  
      def test_single_assignment(self):
          person = self.Person(42)
          with self.assertRaises(MutationError):
              person.age = 37
  
  
  class AddressableListTest(unittest.TestCase):
      class Series(SimpleSerializable):
          def __init__(self, values):
              super(AddressableListTest.Series, self).__init__()
              self.values = values
  
          @addressable_list(Exactly(int, float))
          def values(self):
              """Return this series' values.
  
              :rtype list of int or float
              """
  
      def test_none(self):
          series = self.Series(None)
  
          self.assertEqual([], series.values)
  
      def test_values(self):
          series = self.Series([42, 1 / 137.0])
  
          self.assertEqual([42, 1 / 137.0], series.values)
  
      def test_addresses(self):
          series = self.Series(["//:meaning-of-life"])
  
          self.assertEqual(["//:meaning-of-life"], series.values)
  
      def test_resolvables(self):
          resolvable_value = CountingResolvable("//:fine-structure-constant", 1 / 137.0)
          series = self.Series([resolvable_value])
  
          self.assertEqual([1 / 137.0], series.values)
          self.assertEqual(1, resolvable_value.resolutions)
  
          self.assertEqual(1 / 137.0, series.values[0])
          self.assertEqual(2, resolvable_value.resolutions)
  
      def test_mixed(self):
          resolvable_value = CountingResolvable("//:fine-structure-constant", 1 / 137.0)
          series = self.Series([42, "//:meaning-of-life", resolvable_value])
  
          self.assertEqual(0, resolvable_value.resolutions)
  
          self.assertEqual([42, "//:meaning-of-life", 1 / 137.0], series.values)
          self.assertEqual(1, resolvable_value.resolutions)
  
          self.assertEqual(1 / 137.0, series.values[2])
          self.assertEqual(2, resolvable_value.resolutions)
  
      def test_type_mismatch_container(self):
          with self.assertRaises(TypeError):
              self.Series({42, 1 / 137.0})
  
      def test_type_mismatch_value(self):
          with self.assertRaises(TypeConstraintError):
              self.Series([42, False])
  
      def test_type_mismatch_resolvable(self):
          resolvable_value = CountingResolvable("//:meaning-of-life", True)
          series = self.Series([42, resolvable_value])
  
          with self.assertRaises(TypeConstraintError):
              series.values
  
      def test_single_assignment(self):
          series = self.Series([42])
          with self.assertRaises(MutationError):
              series.values = [37]
  
  
  class AddressableDictTest(unittest.TestCase):
      class Varz(SimpleSerializable):
          def __init__(self, varz):
              super(AddressableDictTest.Varz, self).__init__()
              self.varz = varz
  
          @addressable_dict(Exactly(int, float))
          def varz(self):
              """Return a snapshot of the current /varz.
  
              :rtype dict of string -> int or float
              """
  
      def test_none(self):
          varz = self.Varz(None)
  
          self.assertEqual({}, varz.varz)
  
      def test_values(self):
          varz = self.Varz({"meaning of life": 42, "fine structure constant": 1 / 137.0})
  
          self.assertEqual({"meaning of life": 42, "fine structure constant": 1 / 137.0}, varz.varz)
  
      def test_addresses(self):
          varz = self.Varz({"meaning of life": "//:meaning-of-life"})
  
          self.assertEqual({"meaning of life": "//:meaning-of-life"}, varz.varz)
  
      def test_resolvables(self):
          resolvable_value = CountingResolvable("//:fine-structure-constant", 1 / 137.0)
          varz = self.Varz({"fine structure constant": resolvable_value})
  
          self.assertEqual({"fine structure constant": 1 / 137.0}, varz.varz)
          self.assertEqual(1, resolvable_value.resolutions)
  
          self.assertEqual(1 / 137.0, varz.varz["fine structure constant"])
          self.assertEqual(2, resolvable_value.resolutions)
  
      def test_mixed(self):
          resolvable_value = CountingResolvable("//:fine-structure-constant", 1 / 137.0)
          varz = self.Varz(
              {
                  "prime": 37,
                  "meaning of life": "//:meaning-of-life",
                  "fine structure constant": resolvable_value,
              }
          )
  
          self.assertEqual(0, resolvable_value.resolutions)
  
          self.assertEqual(
              {
                  "prime": 37,
                  "meaning of life": "//:meaning-of-life",
                  "fine structure constant": 1 / 137.0,
              },
              varz.varz,
          )
          self.assertEqual(1, resolvable_value.resolutions)
  
          self.assertEqual(1 / 137.0, varz.varz["fine structure constant"])
          self.assertEqual(2, resolvable_value.resolutions)
  
      def test_type_mismatch_container(self):
          with self.assertRaises(TypeError):
              self.Varz([42, 1 / 137.0])
  
      def test_type_mismatch_value(self):
          with self.assertRaises(TypeConstraintError):
              self.Varz({"meaning of life": 42, "fine structure constant": False})
  
      def test_type_mismatch_resolvable(self):
          resolvable_item = CountingResolvable("//:fine-structure-constant", True)
          varz = self.Varz({"meaning of life": 42, "fine structure constant": resolvable_item})
  
          with self.assertRaises(TypeConstraintError):
              varz.varz
  
      def test_single_assignment(self):
          varz = self.Varz({"meaning of life": 42})
          with self.assertRaises(MutationError):
              varz.varz = {"fine structure constant": 1 / 137.0}
  