# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Unit tests for tf_should_use."""

# pylint: disable=unused-import
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import contextlib
import gc
import sys

from tensorflow.python.framework import constant_op
from tensorflow.python.platform import test
from tensorflow.python.platform import tf_logging
from tensorflow.python.util import tf_should_use


@contextlib.contextmanager
def reroute_error():
  """Temporarily reroute errors written to tf_logging.error into `captured`."""
  with test.mock.patch.object(tf_should_use.tf_logging, 'error') as error:
    with test.mock.patch.object(tf_should_use.tf_logging, 'fatal') as fatal:
      yield error, fatal


class TfShouldUseTest(test.TestCase):

  def testAddShouldUseWarningWhenNotUsed(self):
    c = constant_op.constant(0, name='blah0')
    def in_this_function():
      h = tf_should_use._add_should_use_warning(c)
      del h
    with reroute_error() as (error, _):
      in_this_function()
    error.assert_called()
    msg = '\n'.join(error.call_args[0])
    self.assertIn('Object was never used', msg)
    self.assertIn('blah0:0', msg)
    self.assertIn('in_this_function', msg)
    self.assertFalse(gc.garbage)

  def testAddShouldUseFatalWhenNotUsed(self):
    c = constant_op.constant(0, name='blah0')
    def in_this_function():
      h = tf_should_use._add_should_use_warning(c, fatal_error=True)
      del h
    with reroute_error() as (_, fatal):
      in_this_function()
    fatal.assert_called()
    msg = '\n'.join(fatal.call_args[0])
    self.assertIn('Object was never used', msg)
    self.assertIn('blah0:0', msg)
    self.assertIn('in_this_function', msg)
    self.assertFalse(gc.garbage)

  def _testAddShouldUseWarningWhenUsed(self, fn, name):
    c = constant_op.constant(0, name=name)
    with reroute_error() as (error, fatal):
      h = tf_should_use._add_should_use_warning(c)
      fn(h)
      del h
    error.assert_not_called()
    fatal.assert_not_called()

  def testAddShouldUseWarningWhenUsedWithAdd(self):
    def add(h):
      _ = h + 1
    self._testAddShouldUseWarningWhenUsed(add, name='blah_add')
    gc.collect()
    self.assertFalse(gc.garbage)

  def testAddShouldUseWarningWhenUsedWithGetName(self):
    def get_name(h):
      _ = h.name
    self._testAddShouldUseWarningWhenUsed(get_name, name='blah_get_name')
    gc.collect()
    self.assertFalse(gc.garbage)

  def testShouldUseResult(self):
    @tf_should_use.should_use_result
    def return_const(value):
      return constant_op.constant(value, name='blah2')
    with reroute_error() as (error, _):
      return_const(0.0)
    error.assert_called()
    msg = '\n'.join(error.call_args[0])
    self.assertIn('Object was never used', msg)
    self.assertIn('blah2:0', msg)
    self.assertIn('return_const', msg)
    gc.collect()
    self.assertFalse(gc.garbage)

  def testShouldUseResultWhenNotReallyUsed(self):
    @tf_should_use.should_use_result
    def return_const(value):
      return constant_op.constant(value, name='blah3')
    with reroute_error() as (error, _):
      with self.test_session():
        return_const(0.0)
        # Creating another op and executing it does not mark the
        # unused op as being "used".
        v = constant_op.constant(1.0, name='meh')
        v.eval()
    error.assert_called()
    msg = '\n'.join(error.call_args[0])
    self.assertIn('Object was never used', msg)
    self.assertIn('blah3:0', msg)
    self.assertIn('return_const', msg)
    gc.collect()
    self.assertFalse(gc.garbage)

  # Tests that mark_used is available in the API.
  def testMarkUsed(self):
    @tf_should_use.should_use_result
    def return_const(value):
      return constant_op.constant(value, name='blah3')
    with self.test_session():
      return_const(0.0).mark_used()

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

[((4539, 4550), 'tensorflow.python.platform.test.main', 'test.main', ([], {}), '()\n', (4548, 4550), False, 'from tensorflow.python.platform import test\n'), ((1240, 1297), 'tensorflow.python.platform.test.mock.patch.object', 'test.mock.patch.object', (['tf_should_use.tf_logging', '"""error"""'], {}), "(tf_should_use.tf_logging, 'error')\n", (1262, 1297), False, 'from tensorflow.python.platform import test\n'), ((1507, 1544), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['(0)'], {'name': '"""blah0"""'}), "(0, name='blah0')\n", (1527, 1544), False, 'from tensorflow.python.framework import constant_op\n'), ((1980, 2017), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['(0)'], {'name': '"""blah0"""'}), "(0, name='blah0')\n", (2000, 2017), False, 'from tensorflow.python.framework import constant_op\n'), ((2481, 2515), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['(0)'], {'name': 'name'}), '(0, name=name)\n', (2501, 2515), False, 'from tensorflow.python.framework import constant_op\n'), ((2848, 2860), 'gc.collect', 'gc.collect', ([], {}), '()\n', (2858, 2860), False, 'import gc\n'), ((3067, 3079), 'gc.collect', 'gc.collect', ([], {}), '()\n', (3077, 3079), False, 'import gc\n'), ((3523, 3535), 'gc.collect', 'gc.collect', ([], {}), '()\n', (3533, 3535), False, 'import gc\n'), ((4199, 4211), 'gc.collect', 'gc.collect', ([], {}), '()\n', (4209, 4211), False, 'import gc\n'), ((1317, 1374), 'tensorflow.python.platform.test.mock.patch.object', 'test.mock.patch.object', (['tf_should_use.tf_logging', '"""fatal"""'], {}), "(tf_should_use.tf_logging, 'fatal')\n", (1339, 1374), False, 'from tensorflow.python.platform import test\n'), ((1583, 1623), 'tensorflow.python.util.tf_should_use._add_should_use_warning', 'tf_should_use._add_should_use_warning', (['c'], {}), '(c)\n', (1620, 1623), False, 'from tensorflow.python.util import tf_should_use\n'), ((2056, 2114), 'tensorflow.python.util.tf_should_use._add_should_use_warning', 'tf_should_use._add_should_use_warning', (['c'], {'fatal_error': '(True)'}), '(c, fatal_error=True)\n', (2093, 2114), False, 'from tensorflow.python.util import tf_should_use\n'), ((2570, 2610), 'tensorflow.python.util.tf_should_use._add_should_use_warning', 'tf_should_use._add_should_use_warning', (['c'], {}), '(c)\n', (2607, 2610), False, 'from tensorflow.python.util import tf_should_use\n'), ((3226, 3267), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['value'], {'name': '"""blah2"""'}), "(value, name='blah2')\n", (3246, 3267), False, 'from tensorflow.python.framework import constant_op\n'), ((3699, 3740), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['value'], {'name': '"""blah3"""'}), "(value, name='blah3')\n", (3719, 3740), False, 'from tensorflow.python.framework import constant_op\n'), ((4401, 4442), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['value'], {'name': '"""blah3"""'}), "(value, name='blah3')\n", (4421, 4442), False, 'from tensorflow.python.framework import constant_op\n'), ((3953, 3990), 'tensorflow.python.framework.constant_op.constant', 'constant_op.constant', (['(1.0)'], {'name': '"""meh"""'}), "(1.0, name='meh')\n", (3973, 3990), False, 'from tensorflow.python.framework import constant_op\n')]