#!/usr/bin/env python3
#
# Copyright 2022 The Fuchsia Authors
#
# 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.

import os
import re
import sys
import uuid

if sys.version_info < (3, ):
    import warnings

    with warnings.catch_warnings():
        warnings.filterwarnings('ignore', category=PendingDeprecationWarning)
        import imp

    import importlib
    import unittest2 as unittest

    def import_module(name, path):
        return imp.load_source(name, path)

    def import_acts():
        return importlib.import_module('antlion')
else:
    import importlib.machinery
    import unittest

    def import_module(name, path):
        return importlib.machinery.SourceFileLoader(name, path).load_module()

    def import_acts():
        return importlib.import_module('antlion')


PY_FILE_REGEX = re.compile('.+\.py$')

DENYLIST = [
    'antlion/controllers/rohdeschwarz_lib/contest.py',
    'antlion/controllers/native.py',
    'antlion/controllers/native_android_device.py',
    'antlion/controllers/packet_sender.py',
    'antlion/controllers/buds_lib/dev_utils/proto/gen/nanopb_pb2.py'
]

DENYLIST_DIRECTORIES = [
    'antlion/controllers/buds_lib'
]


class ActsImportUnitTest(unittest.TestCase):
    """Test that all acts framework imports work."""

    def test_import_acts_successful(self):
        """Test that importing ACTS works."""
        acts = import_acts()
        self.assertIsNotNone(acts)

    # TODO(b/190659975): Re-enable once permission issue is resolved.
    @unittest.skip("Permission error: b/190659975")
    def test_import_framework_successful(self):
        """Dynamically test all imports from the framework."""
        acts = import_acts()
        if hasattr(acts, '__path__') and len(antlion.__path__) > 0:
            acts_path = antlion.__path__[0]
        else:
            acts_path = os.path.dirname(antlion.__file__)

        for root, _, files in os.walk(acts_path):
            for f in files:
                full_path = os.path.join(root, f)
                if (any(full_path.endswith(e) for e in DENYLIST)
                        or any(e in full_path
                               for e in DENYLIST_DIRECTORIES)):
                    continue

                path = os.path.relpath(os.path.join(root, f), os.getcwd())

                if PY_FILE_REGEX.match(full_path):
                    with self.subTest(msg='import %s' % path):
                        fake_module_name = str(uuid.uuid4())
                        module = import_module(fake_module_name, path)
                        self.assertIsNotNone(module)


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