#!/usr/bin/env python2.7

## LICENSE_BEGIN
#
#     MIT License
#
#     SPDX:MIT
#
#     https://spdx.org/licenses/MIT
#
#     See LICENSE.txt file in the top level directory.
#
## LICENSE_END


import os
import shutil
import unittest

import catalog
import config
import builder
import fabricator
import manifest
import localtest


class FakeTarget(object):
  def __init__(self, name, deps=None):
    self.name = name
    if deps is None:
      deps = []
    self.deps = deps


class TargetFabricatorTestCase(unittest.TestCase):
  def setUp(self):
    self.dev_null = file('/dev/null', 'w+')
    self.cat = catalog.TargetCatalog()
    self.bld = builder.TargetBuilder(self.cat)
    self.mrdr = manifest.ManifestReader(self.bld)
    self.mrdr.LoadAllManifestFiles(localtest.SrcDataDir())
    self.assertTrue(self.bld.AutoResolveUnresolvedDependencies())

    self.fab = fabricator.TargetFabricator(self.cat)

  def tearDown(self):
    self.dev_null.close()
    if os.path.isdir(config.GetConfig().OutputDir):
      shutil.rmtree(config.GetConfig().OutputDir)

  def testNeedsBuild(self):
    fab = fabricator.TargetFabricator({})
    self.assertTrue(fab.NeedsBuild(0, []))
    self.assertTrue(fab.NeedsBuild(0, [0]))
    self.assertTrue(fab.NeedsBuild(0, [1, 2, 3, 4]))
    self.assertTrue(fab.NeedsBuild(1, [1, 2, 3, 4]))
    self.assertTrue(fab.NeedsBuild(2, [1, 2, 3, 4]))
    self.assertTrue(fab.NeedsBuild(3, [1, 2, 3, 4]))
    self.assertFalse(fab.NeedsBuild(4, [1, 2, 3, 4]))
    self.assertFalse(fab.NeedsBuild(5, [1, 2, 3, 4]))

  def testFabricateHelloWorldPiecemeal(self):
    #self.cat.PrettyPrintDepTree('helloworld')

    t_hello = self.cat['helloworld']
    bin_dir = self.cat.config.BinDir
    cc_obj = 'dir2/helloworld.o'
    out_dir2 = os.path.join(self.cat.config.ObjBaseDir, 'dir2')
    src_file = os.path.join(self.cat.config.SourceDir, 'dir2', 'helloworld.cc')

    self.assertEquals(sorted([bin_dir, cc_obj]), t_hello.deps)
    self.assertEquals(set([bin_dir, out_dir2, src_file, cc_obj]),
                      self.cat.GetUniqueDependencies('helloworld'))

    self.assertEquals(0, t_hello.LastBuilt())
    self.assertEquals(sorted([0, 0, 0, os.stat(src_file).st_mtime]),
                      sorted(self.fab.GetAllDependencyTimes('helloworld')))
    self.assertTrue(self.fab.TargetNeedsBuild('helloworld'))

    # Checks for the src_file target.
    self.assertEquals(os.stat(src_file).st_mtime,
                      self.cat[src_file].LastBuilt())
    self.assertFalse(self.fab.TargetNeedsBuild(src_file))
    self.assertTrue(self.fab.DoBuild(src_file, self.dev_null))
    self.assertEquals(os.stat(src_file).st_mtime,
                      self.cat[src_file].LastBuilt())
    self.assertFalse(self.fab.TargetNeedsBuild(src_file))
    self.assertTrue(self.fab.TargetNeedsBuild('helloworld'))

    # Checks for the out_dir2 target.
    self.assertEquals(0, self.cat[out_dir2].LastBuilt())
    self.assertTrue(self.fab.TargetNeedsBuild(out_dir2))
    self.assertTrue(self.fab.DoBuild(out_dir2, self.dev_null))
    self.assertNotEquals(0, self.cat[out_dir2].LastBuilt())
    self.assertFalse(self.fab.TargetNeedsBuild(out_dir2))
    self.assertTrue(self.fab.TargetNeedsBuild('helloworld'))

    # Checks for the cc_obj target.
    self.assertEquals(0, self.cat[cc_obj].LastBuilt())
    self.assertTrue(self.fab.TargetNeedsBuild(cc_obj))
    self.assertTrue(self.fab.DoBuild(cc_obj, self.dev_null))
    self.assertNotEquals(0, self.cat[cc_obj].LastBuilt())
    self.assertFalse(self.fab.TargetNeedsBuild(cc_obj))
    self.assertTrue(self.fab.TargetNeedsBuild('helloworld'))

    # Checks for the bin_dir target.
    self.assertEquals(0, self.cat[bin_dir].LastBuilt())
    self.assertTrue(self.fab.TargetNeedsBuild(bin_dir))
    self.assertTrue(self.fab.DoBuild(bin_dir, self.dev_null))
    self.assertNotEquals(0, self.cat[bin_dir].LastBuilt())
    self.assertFalse(self.fab.TargetNeedsBuild(bin_dir))
    self.assertTrue(self.fab.TargetNeedsBuild('helloworld'))

    # Checks for the final binary target.
    self.assertEquals(0, t_hello.LastBuilt())
    self.assertTrue(self.fab.DoBuild('helloworld', self.dev_null))
    self.assertFalse(self.fab.TargetNeedsBuild('helloworld'))

  def testFabricateHelloWorldOneshot(self):
    t_hello = self.cat['helloworld']
    bin_dir = self.cat.config.BinDir
    cc_obj = 'dir2/helloworld.o'
    out_dir2 = os.path.join(self.cat.config.ObjBaseDir, 'dir2')
    src_file = os.path.join(self.cat.config.SourceDir, 'dir2', 'helloworld.cc')

    self.assertFalse(self.fab.TargetNeedsBuild(src_file))
    self.assertTrue(self.fab.TargetNeedsBuild(out_dir2))
    self.assertTrue(self.fab.TargetNeedsBuild(cc_obj))
    self.assertTrue(self.fab.TargetNeedsBuild(bin_dir))
    self.assertEquals(0, t_hello.LastBuilt())
    self.assertTrue(self.fab.TargetNeedsBuild('helloworld'))

    self.assertTrue(self.fab.Fabricate('helloworld', self.dev_null))

    self.assertFalse(self.fab.TargetNeedsBuild(src_file))
    self.assertFalse(self.fab.TargetNeedsBuild(out_dir2))
    self.assertFalse(self.fab.TargetNeedsBuild(cc_obj))
    self.assertFalse(self.fab.TargetNeedsBuild(bin_dir))
    self.assertNotEquals(0, t_hello.LastBuilt())
    self.assertFalse(self.fab.TargetNeedsBuild('helloworld'))


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