# Copyright 2017 Google Inc. All Rights Reserved.
# Modifications Copyright 2022-2023 Aerleon Project 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.

"""Unittest for Aruba acl rendering module."""

import datetime
import textwrap
from unittest import mock

from absl.testing import absltest

from aerleon.lib import aclgenerator, aruba, naming, policy
from tests.regression_utils import capture

GOOD_HEADER_V4 = """
header {
  target:: aruba test-filter
}
"""

GOOD_HEADER_V6 = """
header {
  target:: aruba test-filter inet6
}
"""

GOOD_HEADER_NOVERBOSE = """
header {
  target:: aruba test-filter noverbose
}
"""

EXPIRED_TERM = """
term is-expired {
  expiration:: 2010-01-01
  action:: accept
}
"""

EXPIRING_TERM = """
term is-expiring {
  expiration:: %s
  action:: accept
}
"""

GOOD_TERM_SIMPLE = """
term good-term-simple {
  action:: accept
}
"""

GOOD_TERM_SHORT_COMMENT = """
term good-term-short-comment {
  comment:: "Some short comment."
  owner:: someowner
  action:: deny
}
"""

GOOD_TERM_LONG_COMMENT = """
term good-term-long-comment {
  comment:: "Two households, both alike in dignity,"
  comment:: "In fair Verona, where we lay our scene,"
  comment:: "From ancient grudge break to new mutiny, Where civil blood makes civil hands unclean."
  owner:: wshakespeare
  action:: accept
}
"""

GOOD_TERM_VERBATIM = """
term much-verbatim {
  verbatim:: aruba "aruba uses some odd ACL format"
  verbatim:: aruba "which is kinda like, weird"
  verbatim:: aruba ""
  verbatim:: cisco "But Cisco's format is Ok, tho."
  verbatim:: juniper "And Juniper's is the best!"
}
"""

GOOD_TERM_ALLOW_ANY_ANY = """
term good-term-allow-any-any {
  action:: accept
}
"""

GOOD_TERM_DENY_ANY_ANY = """
term good-term-deny-any-any {
  action:: deny
}
"""

GOOD_TERM_SINGLE_NETDESTINATION = """
term gt-one-netd {
  source-address:: SINGLE_HOST
  protocol:: icmp
  action:: accept
}
"""

GOOD_TERM_TWO_NETDESTINATIONS = """
term gt-two-netd {
  source-address:: SINGLE_HOST
  destination-address:: SINGLE_HOST
  protocol:: icmp
  action:: accept
}
"""

GOOD_TERM_TWO_NETWORK_NETDESTINATIONS = """
term gt-mix-netd {
  source-address:: SOME_NETWORK
  destination-address:: SOME_NETWORK
  protocol:: icmp
  action:: accept
}
"""

GOOD_TERM_COMBINED_NETDESTINATIONS = """
term good-term-combined-netdestinations {
  source-address:: MIXED_HOSTS
  protocol:: tcp
  destination-port:: HTTP
  action:: deny
}
"""

GOOD_TERMS_COMBINED_SINGLE_CASE = """
term good-terms-combined-1 {
  source-address:: SOME_HOST
  destination-address:: SOME_HOST
  protocol:: udp
  destination-port:: TFTP
  action:: accept
}

term good-terms-combined-2 {
  action:: deny
}
"""

GOOD_TERM_SOURCE_IS_USER = """
term good-term-source-is-user {
  destination-address:: SOME_NETWORK
  protocol:: tcp
  destination-port:: DNS
  action:: accept
  option:: source-is-user
}
"""

GOOD_TERM_DESTINATION_IS_USER = """
term good-term-destination-is-user {
  source-address:: SOME_NETWORK
  protocol:: tcp
  destination-port:: DNS
  action:: accept
  option:: destination-is-user
}
"""

GOOD_TERM_NEGATE_1 = """
term good-term-negate {
  source-address:: SOME_NETWORK
  action:: deny
  option:: negate
}
"""

GOOD_TERM_NEGATE_2 = """
term good-term-negate {
  action:: accept
  option:: negate
}
"""

GOOD_TERM_PROTOCOL_MAP = """
term allow-icmp {
  protocol:: icmp
  action:: accept
}

term allow-gre {
  protocol:: gre
  action:: accept
}

term allow-esp {
  protocol:: esp
  action:: accept
}
"""

PLATFORM_EXCLUDE_TERM = """
term platform-exclude-term {
  protocol:: icmp
  platform-exclude:: aruba
  action:: accept
}
"""

MISSING_PLATFORM_TERM = """
term platform-term {
  protocol:: icmp
  platform:: juniper
  action:: accept
}
"""

PLATFORM_TERM = """
term platform-term {
  protocol:: icmp
  platform:: aruba juniper
  action:: accept
}
"""

SUPPORTED_TOKENS = frozenset(
    {
        'action',
        'comment',
        'destination_address',
        'destination_port',
        'expiration',
        'stateless_reply',
        'name',
        'option',
        'platform',
        'platform_exclude',
        'protocol',
        'source_address',
        'translated',
        'verbatim',
    }
)

SUPPORTED_SUB_TOKENS = {
    'action': {
        'accept',
        'deny',
    },
    'option': {
        'source-is-user',
        'destination-is-user',
        'negate',
    },
}

# Print a info message when a term is set to expire in that many weeks.
# This is normally passed from command line.
EXP_INFO = 2


class ArubaTest(absltest.TestCase):
    def setUp(self):
        super().setUp()
        self.naming = naming.Naming()

    def testBuildTokens(self):
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_SIMPLE, self.naming), EXP_INFO
        )
        st, sst = aru._BuildTokens()
        self.assertEqual(SUPPORTED_TOKENS, st)
        self.assertEqual(SUPPORTED_SUB_TOKENS, sst)

    @mock.patch.object(aclgenerator.logging, 'warning')
    def testExpiredTerm(self, mock_warn):
        aruba.Aruba(policy.ParsePolicy(GOOD_HEADER_V4 + EXPIRED_TERM, self.naming), EXP_INFO)
        mock_warn.assert_called_once_with(
            'WARNING: Term %s in policy %s is expired and will not be rendered.',
            'is-expired',
            'test-filter',
        )

    @mock.patch.object(aclgenerator.logging, 'info')
    def testExpiringTerm(self, mock_info):
        exp_date = datetime.date.today() + datetime.timedelta(weeks=EXP_INFO)
        aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V4 + EXPIRING_TERM % exp_date.strftime('%Y-%m-%d'), self.naming
            ),
            EXP_INFO,
        )
        mock_info.assert_called_once_with(
            'INFO: Term %s in policy %s expires in ' 'less than two weeks.',
            'is-expiring',
            'test-filter',
        )

    @capture.stdout
    def testSimpleTerm(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      any any any permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_SIMPLE, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testShortComment(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      # Some short comment.
      # Owner: someowner
      any any any deny
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_SHORT_COMMENT, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testNoVerbose(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      any any any deny
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_NOVERBOSE + GOOD_TERM_SHORT_COMMENT, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testLongWrappedComment(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      # Two households, both alike in dignity,
      # In fair Verona, where we lay our scene,
      # From ancient grudge break to new mutiny, Where civil blood makes civil
      # hands unclean.
      # Owner: wshakespeare
      any any any permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_LONG_COMMENT, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testVerbatim(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      aruba uses some odd ACL format
      which is kinda like, weird
      any any any permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V4 + GOOD_TERM_VERBATIM + GOOD_TERM_ALLOW_ANY_ANY, self.naming
            ),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testMultipleCallsSingleOwnerLine(self):
        expected_result = textwrap.dedent(
            """\
        # $Id:$
        # $Date:$
        # $Revision:$
        ip access-list session test-filter
          # Two households, both alike in dignity,
          # In fair Verona, where we lay our scene,
          # From ancient grudge break to new mutiny, Where civil blood makes civil
          # hands unclean.
          # Owner: wshakespeare
          any any any permit
        !
        """
        )
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_LONG_COMMENT, self.naming), EXP_INFO
        )
        self.assertEqual(expected_result, str(aru))
        self.assertEqual(expected_result, str(aru))
        print(aru)

    @capture.stdout
    def testTermAllowAnyAnyIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      any any any permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_ALLOW_ANY_ANY, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTermAllowAnyAnyIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      ipv6 any any any permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_ALLOW_ANY_ANY, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTermDenyAnyAnyIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      any any any deny
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_DENY_ANY_ANY, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTermDenyAnyAnyIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      ipv6 any any any deny
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_DENY_ANY_ANY, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testMultipleCallsSingleNetdestinationsBlock(self):
        expected_result = textwrap.dedent(
            """\
        # $Id:$
        # $Date:$
        # $Revision:$
        netdestination gt-one-netd_src
          host 10.1.1.1
        !

        ip access-list session test-filter
          alias gt-one-netd_src any 1 permit
        !
        """
        )
        self.naming._ParseLine('SINGLE_HOST = 10.1.1.1/32', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_SINGLE_NETDESTINATION, self.naming),
            EXP_INFO,
        )
        self.assertEqual(expected_result, str(aru))
        self.assertEqual(expected_result, str(aru))
        print(aru)

    @capture.stdout
    def testSingleNetdestinationIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination gt-one-netd_src
      host 10.1.1.1
    !

    ip access-list session test-filter
      alias gt-one-netd_src any 1 permit
    !
    """
        self.naming._ParseLine('SINGLE_HOST = 10.1.1.1/32', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_SINGLE_NETDESTINATION, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testSingleNetdestinationIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination6 gt-one-netd_src
      host 2001::
    !

    ip access-list session test-filter
      ipv6 alias gt-one-netd_src any 1 permit
    !
    """
        self.naming._ParseLine('SINGLE_HOST = 2001::/128', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_SINGLE_NETDESTINATION, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTwoNetdestinationsIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination gt-two-netd_src
      host 10.1.1.1
    !

    netdestination gt-two-netd_dst
      host 10.1.1.1
    !

    ip access-list session test-filter
      alias gt-two-netd_src alias gt-two-netd_dst 1 permit
    !
    """
        self.naming._ParseLine('SINGLE_HOST = 10.1.1.1/32', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_TWO_NETDESTINATIONS, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTwoNetdestinationsIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination6 gt-two-netd_src
      host 2001::
    !

    netdestination6 gt-two-netd_dst
      host 2001::
    !

    ip access-list session test-filter
      ipv6 alias gt-two-netd_src alias gt-two-netd_dst 1 permit
    !
    """
        self.naming._ParseLine('SINGLE_HOST = 2001::/128', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_TWO_NETDESTINATIONS, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTwoNetworkNetdestinationsIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination gt-mix-netd_src
      network 10.0.0.0 255.0.0.0
    !

    netdestination gt-mix-netd_dst
      network 10.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      alias gt-mix-netd_src alias gt-mix-netd_dst 1 permit
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 10.0.0.0/8', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V4 + GOOD_TERM_TWO_NETWORK_NETDESTINATIONS, self.naming
            ),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testTwoNetworkNetdestinationsIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination6 gt-mix-netd_src
      network 2001::/64
    !

    netdestination6 gt-mix-netd_dst
      network 2001::/64
    !

    ip access-list session test-filter
      ipv6 alias gt-mix-netd_src alias gt-mix-netd_dst 1 permit
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 2001::/64', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V6 + GOOD_TERM_TWO_NETWORK_NETDESTINATIONS, self.naming
            ),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testCombinedNetdestinationsIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-term-combined-netdestinations_src
      host 10.0.0.1
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      alias good-term-combined-netdestinations_src any tcp 80 deny
    !
    """
        self.naming._ParseLine('MIXED_HOSTS = 100.0.0.0/8 10.0.0.1/32', 'networks')
        self.naming._ParseLine('HTTP = 80/tcp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_COMBINED_NETDESTINATIONS, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testCombinedNetdestinationsIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination6 good-term-combined-netdestinations_src
      host 2001::
      network 2002::/64
    !

    ip access-list session test-filter
      ipv6 alias good-term-combined-netdestinations_src any tcp 80 deny
    !
    """
        self.naming._ParseLine('MIXED_HOSTS = 2002::/64 2001::/128', 'networks')
        self.naming._ParseLine('HTTP = 80/tcp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERM_COMBINED_NETDESTINATIONS, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testMultipleTermsIPv4(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-terms-combined-1_src
      host 10.0.0.1
      network 100.0.0.0 255.0.0.0
    !

    netdestination good-terms-combined-1_dst
      host 10.0.0.1
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      alias good-terms-combined-1_src alias good-terms-combined-1_dst udp 69 permit
      any any any deny
    !
    """
        self.naming._ParseLine('SOME_HOST = 100.0.0.0/8 10.0.0.1/32', 'networks')
        self.naming._ParseLine('TFTP = 69/udp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERMS_COMBINED_SINGLE_CASE, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testMultipleTermsIPv6(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination6 good-terms-combined-1_src
      host 2001::
      network 2002::/64
    !

    netdestination6 good-terms-combined-1_dst
      host 2001::
      network 2002::/64
    !

    ip access-list session test-filter
      ipv6 alias good-terms-combined-1_src alias good-terms-combined-1_dst udp 69 permit
      ipv6 any any any deny
    !
    """
        self.naming._ParseLine('SOME_HOST = 2002::/64 2001::/128', 'networks')
        self.naming._ParseLine('TFTP = 69/udp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V6 + GOOD_TERMS_COMBINED_SINGLE_CASE, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testSourceIsUser(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-term-source-is-user_dst
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      user alias good-term-source-is-user_dst tcp 53 permit
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 100.0.0.0/8', 'networks')
        self.naming._ParseLine('DNS = 53/tcp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_SOURCE_IS_USER, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testDestinationIsUser(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-term-destination-is-user_src
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      alias good-term-destination-is-user_src user tcp 53 permit
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 100.0.0.0/8', 'networks')
        self.naming._ParseLine('DNS = 53/tcp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_DESTINATION_IS_USER, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testProtocolIsContiguousRange(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-term-destination-is-user_src
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      alias good-term-destination-is-user_src user tcp 53 55 permit
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 100.0.0.0/8', 'networks')
        self.naming._ParseLine('DNS = 53-55/tcp 54/tcp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_DESTINATION_IS_USER, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testProtocolIsDiscontiguousRange(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-term-destination-is-user_src
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      alias good-term-destination-is-user_src user tcp 1 permit
      alias good-term-destination-is-user_src user tcp 10 20 permit
      alias good-term-destination-is-user_src user tcp 53 55 permit
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 100.0.0.0/8', 'networks')
        self.naming._ParseLine('DNS = 53-55/tcp 54/tcp 10-20/tcp 1/tcp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_DESTINATION_IS_USER, self.naming),
            EXP_INFO,
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testNegateWithNetwork(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    netdestination good-term-negate_src
      network 100.0.0.0 255.0.0.0
    !

    ip access-list session test-filter
      no alias good-term-negate_src any any deny
    !
    """
        self.naming._ParseLine('SOME_NETWORK = 100.0.0.0/8', 'networks')
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_NEGATE_1, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testNegateAny(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      no any any any permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_NEGATE_2, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testMissingPlatformTerm(self):
        self.naming._ParseLine('SOME_HOST = 100.0.0.0/8 10.0.0.1/32', 'networks')
        self.naming._ParseLine('TFTP = 69/udp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V4 + MISSING_PLATFORM_TERM + GOOD_TERMS_COMBINED_SINGLE_CASE,
                self.naming,
            ),
            EXP_INFO,
        )
        output = str(aru)
        self.assertNotIn('any any 1 permit', output, output)
        print(output)

    @capture.stdout
    def testPlatformTerm(self):
        self.naming._ParseLine('SOME_HOST = 100.0.0.0/8 10.0.0.1/32', 'networks')
        self.naming._ParseLine('TFTP = 69/udp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V4 + PLATFORM_TERM + GOOD_TERMS_COMBINED_SINGLE_CASE, self.naming
            ),
            EXP_INFO,
        )
        output = str(aru)
        self.assertIn('any any 1 permit', output, output)
        print(output)

    @capture.stdout
    def testPlatformExclude(self):
        self.naming._ParseLine('SOME_HOST = 100.0.0.0/8 10.0.0.1/32', 'networks')
        self.naming._ParseLine('TFTP = 69/udp', 'services')
        aru = aruba.Aruba(
            policy.ParsePolicy(
                GOOD_HEADER_V4 + PLATFORM_EXCLUDE_TERM + GOOD_TERMS_COMBINED_SINGLE_CASE,
                self.naming,
            ),
            EXP_INFO,
        )
        output = str(aru)
        self.assertNotIn('any any 1 permit', output)
        print(output)

    @capture.stdout
    def testProtocolMap(self):
        expected_result = """\
    # $Id:$
    # $Date:$
    # $Revision:$
    ip access-list session test-filter
      any any 1 permit
      any any 47 permit
      any any 50 permit
    !
    """
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_PROTOCOL_MAP, self.naming), EXP_INFO
        )
        self.assertEqual(textwrap.dedent(expected_result), str(aru))
        print(aru)

    @capture.stdout
    def testMultiplePorts(self):
        definitions = naming.Naming()
        definitions._ParseLine('SOME_NETWORK = 100.0.0.0/8', 'networks')
        definitions._ParseLine(
            'DNS = 53/tcp 54/tcp 55/tcp 60/tcp 61/tcp 62/tcp 63/tcp 65/tcp', 'services'
        )
        aru = aruba.Aruba(
            policy.ParsePolicy(GOOD_HEADER_V4 + GOOD_TERM_DESTINATION_IS_USER, definitions),
            EXP_INFO,
        )
        expect = """  alias good-term-destination-is-user_src user tcp 53 55 permit
  alias good-term-destination-is-user_src user tcp 60 63 permit
  alias good-term-destination-is-user_src user tcp 65 permit"""

        self.assertIn(expect, str(aru))
        print(aru)


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