300 lines
14 KiB
Python
300 lines
14 KiB
Python
import re
|
|
import unittest
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add `src` directory to the import paths
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))
|
|
|
|
from mapcss import parseCondition
|
|
from mapcss.Condition import Condition
|
|
|
|
class ConditionTest(unittest.TestCase):
|
|
|
|
def test_parser_eq(self):
|
|
cond:Condition = parseCondition("natural=coastline")
|
|
self.assertEqual(cond.type, "eq")
|
|
self.assertEqual(cond.params, ("natural", "coastline"))
|
|
self.assertTrue(cond.test({'natural': 'coastline'}))
|
|
self.assertFalse(cond.test({'Natural': 'Coastline'}))
|
|
|
|
cond = parseCondition(" highway\t=\tprimary")
|
|
self.assertEqual(cond.type, "eq")
|
|
self.assertEqual(cond.params, ("highway", "primary"))
|
|
self.assertTrue(cond.test({'highway': 'primary'}))
|
|
self.assertFalse(cond.test({'highway': 'secondary'}))
|
|
|
|
cond = parseCondition(" admin_level = 3")
|
|
self.assertEqual(cond.type, "eq")
|
|
self.assertEqual(cond.params, ("admin_level", "3"))
|
|
self.assertTrue(cond.test({'admin_level': '3'}))
|
|
self.assertFalse(cond.test({'admin_level': '32'}))
|
|
|
|
cond = Condition('eq', ("::class", "::*"))
|
|
self.assertEqual(cond.type, "eq")
|
|
self.assertEqual(cond.params, ("::class", "::*"))
|
|
self.assertEqual(cond.extract_tag(), "*")
|
|
self.assertEqual(cond.test({'any_key': 'any_value'}), "::*")
|
|
self.assertTrue(cond.test({'any_key': 'any_value'}))
|
|
|
|
cond = Condition('eq', ("::class", "::int_name"))
|
|
self.assertEqual(cond.type, "eq")
|
|
self.assertEqual(cond.params, ("::class", "::int_name"))
|
|
self.assertEqual(cond.extract_tag(), "*")
|
|
self.assertEqual(cond.test({'any_key': 'any_value'}), "::int_name")
|
|
self.assertTrue(cond.test({'any_key': 'any_value'}))
|
|
|
|
def test_parser_regex(self):
|
|
""" Test conditions in format natural =~/water.+/
|
|
Note that such conditions are not used by Organic Maps styles.
|
|
"""
|
|
cond:Condition = parseCondition("natural =~/water.+/")
|
|
self.assertEqual(cond.type, "regex")
|
|
self.assertEqual(cond.params, ("natural", "water.+"))
|
|
self.assertEqual(type(cond.regex), re.Pattern)
|
|
self.assertTrue(cond.test({"natural": "waterway"}))
|
|
self.assertTrue(cond.test({"natural": "water123"}))
|
|
self.assertFalse(cond.test({"natural": "water"}))
|
|
self.assertFalse(cond.test({"natural": " waterway "}))
|
|
|
|
def test_parser_ge(self):
|
|
cond:Condition = parseCondition("population>=0")
|
|
self.assertEqual(cond.type, ">=")
|
|
self.assertEqual(cond.params, ("population", "0"))
|
|
self.assertTrue(cond.test({"population": "0"}))
|
|
self.assertTrue(cond.test({"population": "100000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"population": "-1"}))
|
|
|
|
cond:Condition = parseCondition("population >= 150000")
|
|
self.assertEqual(cond.type, ">=")
|
|
self.assertEqual(cond.params, ("population", "150000"))
|
|
self.assertTrue(cond.test({"population": "150000"}))
|
|
self.assertTrue(cond.test({"population": "250000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"population": "10000"}))
|
|
|
|
cond:Condition = parseCondition("\tbbox_area >= 4000000")
|
|
self.assertEqual(cond.type, ">=")
|
|
self.assertEqual(cond.params, ("bbox_area", "4000000"))
|
|
self.assertTrue(cond.test({"bbox_area": "4000000"}))
|
|
self.assertTrue(cond.test({"bbox_area": "8000000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"bbox_area": "999"}))
|
|
|
|
def test_parser_gt(self):
|
|
""" Test conditions in format population > 100000
|
|
Note that such conditions are not used by Organic Maps styles.
|
|
"""
|
|
cond:Condition = parseCondition("population>0")
|
|
self.assertEqual(cond.type, ">")
|
|
self.assertEqual(cond.params, ("population", "0"))
|
|
self.assertTrue(cond.test({"population": "100"}))
|
|
self.assertFalse(cond.test({"population": "000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"population": "-1"}))
|
|
|
|
cond:Condition = parseCondition("population > 150000")
|
|
self.assertEqual(cond.type, ">")
|
|
self.assertEqual(cond.params, ("population", "150000"))
|
|
self.assertTrue(cond.test({"population": "250000"}))
|
|
self.assertFalse(cond.test({"population": "150000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"population": "10000"}))
|
|
|
|
cond:Condition = parseCondition("\tbbox_area > 4000000 ")
|
|
self.assertEqual(cond.type, ">")
|
|
self.assertEqual(cond.params, ("bbox_area", "4000000 ")) # TODO fix parser to exclude trailing space
|
|
self.assertTrue(cond.test({"bbox_area": "8000000"}))
|
|
self.assertFalse(cond.test({"bbox_area": "4000000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"bbox_area": "999"}))
|
|
|
|
def test_parser_lt(self):
|
|
cond:Condition = parseCondition("population<40000")
|
|
self.assertEqual(cond.type, "<")
|
|
self.assertEqual(cond.params, ("population", "40000"))
|
|
self.assertTrue(cond.test({"population": "100"}))
|
|
self.assertTrue(cond.test({"population": "-1"}))
|
|
self.assertFalse(cond.test({"population": "40000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"population": "500000"}))
|
|
|
|
cond:Condition = parseCondition("\tbbox_area < 4000000\n")
|
|
self.assertEqual(cond.type, "<")
|
|
self.assertEqual(cond.params, ("bbox_area", "4000000\n")) # TODO fix parser to exclude trailing \n
|
|
self.assertTrue(cond.test({"bbox_area": "100"}))
|
|
self.assertTrue(cond.test({"bbox_area": "-1"}))
|
|
self.assertTrue(cond.test({"bbox_area": "000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"bbox_area": "4000000"}))
|
|
self.assertFalse(cond.test({"bbox_area": "8000000"}))
|
|
|
|
def test_parser_le(self):
|
|
""" Test conditions in format population <= 100000
|
|
Note that such conditions are not used by Organic Maps styles.
|
|
"""
|
|
cond:Condition = parseCondition("population<=40000")
|
|
self.assertEqual(cond.type, "<=")
|
|
self.assertEqual(cond.params, ("population", "40000"))
|
|
self.assertTrue(cond.test({"population": "100"}))
|
|
self.assertTrue(cond.test({"population": "-1"}))
|
|
self.assertTrue(cond.test({"population": "40000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"population": "500000"}))
|
|
|
|
cond:Condition = parseCondition("\tbbox_area <= 4000000\n")
|
|
self.assertEqual(cond.type, "<=")
|
|
self.assertEqual(cond.params, ("bbox_area", "4000000\n")) # TODO fix parser to exclude trailing \n
|
|
self.assertTrue(cond.test({"bbox_area": "100"}))
|
|
self.assertTrue(cond.test({"bbox_area": "-1"}))
|
|
self.assertTrue(cond.test({"bbox_area": "000"}))
|
|
self.assertTrue(cond.test({"bbox_area": "4000000"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"bbox_area": "8000000"}))
|
|
|
|
def test_parser_ne(self):
|
|
cond:Condition = parseCondition("capital!=2")
|
|
self.assertEqual(cond.type, "ne")
|
|
self.assertEqual(cond.params, ("capital", "2"))
|
|
self.assertTrue(cond.test({"capital": "1"}))
|
|
self.assertTrue(cond.test({"capital": "22"}))
|
|
self.assertTrue(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"capital": "2"}))
|
|
|
|
cond:Condition = parseCondition("\tcapital != 2")
|
|
self.assertEqual(cond.type, "ne")
|
|
self.assertEqual(cond.params, ("capital", "2"))
|
|
self.assertTrue(cond.test({"capital": "1"}))
|
|
self.assertTrue(cond.test({"capital": "22"}))
|
|
self.assertTrue(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"capital": "2"}))
|
|
|
|
cond:Condition = parseCondition("garden:type != residential")
|
|
self.assertEqual(cond.type, "ne")
|
|
self.assertEqual(cond.params, ("garden:type", "residential"))
|
|
self.assertTrue(cond.test({"garden:type": "public"}))
|
|
self.assertTrue(cond.test({"garden:type": "res"}))
|
|
self.assertTrue(cond.test({"garden:type": "residential_plus"}))
|
|
self.assertTrue(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"garden:type": "residential"}))
|
|
|
|
def test_parser_set(self):
|
|
cond:Condition = parseCondition("tunnel")
|
|
self.assertEqual(cond.type, "set")
|
|
self.assertEqual(cond.params, ("tunnel", ))
|
|
self.assertTrue(cond.test({"tunnel": "yes"}))
|
|
self.assertTrue(cond.test({"tunnel": "maybe"}))
|
|
self.assertTrue(cond.test({"tunnel": "+1"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
|
|
cond:Condition = parseCondition("building\t")
|
|
self.assertEqual(cond.type, "set")
|
|
self.assertEqual(cond.params, ("building", ))
|
|
self.assertTrue(cond.test({"building": "yes"}))
|
|
self.assertTrue(cond.test({"building": "apartment"}))
|
|
self.assertTrue(cond.test({"building": "1"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"building:part": "yes"}))
|
|
|
|
cond:Condition = parseCondition(" addr:housenumber ")
|
|
self.assertEqual(cond.type, "set")
|
|
self.assertEqual(cond.params, ("addr:housenumber", ))
|
|
self.assertTrue(cond.test({"addr:housenumber": "1"}))
|
|
self.assertTrue(cond.test({"addr:housenumber": "yes"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"addr:street": "Baker st"}))
|
|
|
|
cond:Condition = parseCondition(" some-tag ")
|
|
self.assertEqual(cond.type, "set")
|
|
self.assertEqual(cond.params, ("some-tag", ))
|
|
self.assertTrue(cond.test({"some-tag": "1"}))
|
|
self.assertTrue(cond.test({"some-tag": "yes"}))
|
|
self.assertFalse(cond.test({"highway": "secondary"}))
|
|
self.assertFalse(cond.test({"some": "tag"}))
|
|
|
|
def test_parser_unset(self):
|
|
cond:Condition = parseCondition("!tunnel")
|
|
self.assertEqual(cond.type, "unset")
|
|
self.assertEqual(cond.params, ("tunnel", ))
|
|
self.assertTrue(cond.test({"capital": "1"}))
|
|
self.assertFalse(cond.test({"tunnel": "yes"}))
|
|
self.assertFalse(cond.test({"tunnel": "no"}))
|
|
|
|
cond:Condition = parseCondition("\t!name ")
|
|
self.assertEqual(cond.type, "unset")
|
|
self.assertEqual(cond.params, ("name", ))
|
|
self.assertTrue(cond.test({"capital": "1"}))
|
|
self.assertTrue(cond.test({"int_name": "1"}))
|
|
self.assertFalse(cond.test({"name": "London"}))
|
|
|
|
def test_parser_false(self):
|
|
""" Test conditions in format some_tag = no
|
|
Note that such conditions are not used by Organic Maps styles.
|
|
"""
|
|
cond:Condition = parseCondition("access=no")
|
|
self.assertEqual(cond.type, "false")
|
|
self.assertEqual(cond.params, ("access", ))
|
|
#self.assertTrue(cond.test({"access": "no"})) # test is not implemented for `false` condition
|
|
#self.assertTrue(cond.test({"access": "private"})) # test is not implemented for `false` condition
|
|
self.assertFalse(cond.test({"tunnel": "yes"}))
|
|
|
|
def test_parser_invTrue(self):
|
|
""" Test conditions in format [!some_tag?] It works the same way as [some_tag != yes]
|
|
Note that such conditions are not used by Organic Maps styles.
|
|
"""
|
|
cond:Condition = parseCondition("!oneway?")
|
|
self.assertEqual(cond.type, "ne")
|
|
self.assertEqual(cond.params, ("oneway", "yes"))
|
|
self.assertTrue(cond.test({"oneway": "no"}))
|
|
self.assertTrue(cond.test({"oneway": "nobody_knows"}))
|
|
self.assertTrue(cond.test({"access": "private"}))
|
|
self.assertFalse(cond.test({"oneway": "yes"}))
|
|
|
|
cond:Condition = parseCondition("\t! intermittent ?\n")
|
|
self.assertEqual(cond.type, "ne")
|
|
self.assertEqual(cond.params, ("intermittent", "yes"))
|
|
self.assertTrue(cond.test({"intermittent": "no"}))
|
|
self.assertTrue(cond.test({"intermittent": "maybe"}))
|
|
self.assertTrue(cond.test({"access": "private"}))
|
|
self.assertFalse(cond.test({"intermittent": "yes"}))
|
|
|
|
def test_parser_true(self):
|
|
""" Test conditions in format [some_tag?] It works the same way as [some_tag = yes] """
|
|
cond:Condition = parseCondition("area?")
|
|
self.assertEqual(cond.type, "true")
|
|
self.assertEqual(cond.params, ("area", ))
|
|
self.assertTrue(cond.test({"area": "yes"}))
|
|
self.assertFalse(cond.test({"area": "no"}))
|
|
self.assertFalse(cond.test({"access": "private"}))
|
|
self.assertFalse(cond.test({"oneway": "nobody_knows"}))
|
|
|
|
cond:Condition = parseCondition("\tbridge ? ")
|
|
self.assertEqual(cond.type, "true")
|
|
self.assertEqual(cond.params, ("bridge", ))
|
|
self.assertTrue(cond.test({"bridge": "yes"}))
|
|
self.assertFalse(cond.test({"bridge": "no"}))
|
|
self.assertFalse(cond.test({"access": "private"}))
|
|
self.assertFalse(cond.test({"bridge": "maybe"}))
|
|
|
|
def test_untrue(self):
|
|
""" parseCondition(...) doesn't support this type of condition.
|
|
Not sure if it's ever used.
|
|
"""
|
|
cond:Condition = Condition("untrue", "access")
|
|
self.assertEqual(cond.type, "untrue")
|
|
self.assertEqual(cond.params, ("access", ))
|
|
self.assertTrue(cond.test({"access": "no"}))
|
|
self.assertFalse(cond.test({"access": "private"}))
|
|
self.assertFalse(cond.test({"oneway": "yes"}))
|
|
|
|
def test_parser_errors(self):
|
|
with self.assertRaises(Exception):
|
|
parseCondition("! tunnel")
|
|
with self.assertRaises(Exception):
|
|
""" Symbol '-' is only supported in simple 'set' rule. E.g. [key-with-dash]
|
|
But not in 'unset' rule [!key-with-dash] """
|
|
parseCondition("key-with-dash?")
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|