1+ #!/usr/bin/env python3
2+
3+ import os
4+ import sys
5+
6+ # Add the src directory to Python path to import the checker
7+ sys .path .insert (0 , os .path .join (os .path .dirname (__file__ ), '..' , 'src' ))
8+
9+ from overpass_ql_checker .checker import OverpassQLSyntaxChecker
10+
11+
12+ def test_invalid_output_formats ():
13+ """Test that invalid output formats are properly rejected"""
14+ checker = OverpassQLSyntaxChecker ()
15+
16+ invalid_formats = [
17+ '[out:osm];node[name="test"];out;' ,
18+ '[out:xlsx];node[name="test"];out;' ,
19+ '[out:pjsonl];way[highway];out;' ,
20+ '[timeout:25][out:osm];node["place"];out;' ,
21+ ]
22+
23+ print ("Testing invalid output formats..." )
24+ for i , query in enumerate (invalid_formats , 1 ):
25+ result = checker .check_syntax (query )
26+ assert not result ['valid' ], f"Query { i } should be invalid: { query } "
27+ assert any ("Invalid output format" in error for error in result ['errors' ]), \
28+ f"Query { i } should have output format error"
29+ print (f" ✓ Query { i } : Correctly rejected invalid output format" )
30+
31+
32+ def test_invalid_date_formats ():
33+ """Test that invalid date formats with timezone suffixes are rejected"""
34+ checker = OverpassQLSyntaxChecker ()
35+
36+ invalid_dates = [
37+ '[date:"2014-05-13T00:00:00H"];node["building"];out;' ,
38+ '[date:"2020-03-01T00:00:00+09:00"];node["amenity"];out;' ,
39+ '[date:"2020-04-01T00:00:00+09:00"];way["highway"];out;' ,
40+ '[date:"2020-05-01T00:00:00+09:00"];relation["type"];out;' ,
41+ ]
42+
43+ print ("Testing invalid date formats..." )
44+ for i , query in enumerate (invalid_dates , 1 ):
45+ result = checker .check_syntax (query )
46+ assert not result ['valid' ], f"Query { i } should be invalid: { query } "
47+ assert any ("Invalid date format" in error for error in result ['errors' ]), \
48+ f"Query { i } should have date format error"
49+ print (f" ✓ Query { i } : Correctly rejected invalid date format" )
50+
51+
52+ def test_complex_arrow_operator_issues ():
53+ """Test complex arrow operator syntax issues"""
54+ checker = OverpassQLSyntaxChecker ()
55+
56+ arrow_issues = [
57+ 'relation["route"~"^hiking$"]({{bbox}});>->.r;((way["colour"]({{bbox}});-way.r;);>->.x;<;);out;' ,
58+ 'way["waterway"="stream"]({{bbox}})->.CurrentWaterWay;node(w.CurrentWaterWay)->.NodesOfCurrentWaterWay;.NodesOfCurrentWaterWay out;for.NodesOfCurrentWaterWay->.z(id()){make debug Nodes=z.val;out;if(..count_members==..count_members){}.z->.lastNode;}make debug enters="------------";out;.lastNode out;' ,
59+ '((way["highway"]["colour"]["area"!~"."](area:3601473946);way(165060349););(._;>->.x;<;);out;' ,
60+ ]
61+
62+ print ("Testing complex arrow operator issues..." )
63+ for i , query in enumerate (arrow_issues , 1 ):
64+ result = checker .check_syntax (query )
65+ assert not result ['valid' ], f"Query { i } should be invalid: { query } "
66+ # These should have syntax errors related to arrow operators or unexpected tokens
67+ has_arrow_error = any ("Unexpected token: ->" in error or "Expected ), got ." in error
68+ for error in result ['errors' ])
69+ assert has_arrow_error , f"Query { i } should have arrow operator error"
70+ print (f" ✓ Query { i } : Correctly rejected complex arrow syntax" )
71+
72+
73+ def test_foreach_and_set_issues ():
74+ """Test foreach loop and set name parsing issues"""
75+ checker = OverpassQLSyntaxChecker ()
76+
77+ set_issues = [
78+ 'relation(416351);foreach->.rel{way["wikidata"](r.rel)->.ways;relation.rel;out;}' ,
79+ 'way["wikidata"]({{bbox}});foreach->.rel{way.all(r.rel)->.ways;relation.rel;out;}' ,
80+ 'area[name="test"];relation["boundary"](area);map_to_area;foreach->.rel{relation.rel;out;}' ,
81+ ]
82+
83+ print ("Testing foreach and set name issues..." )
84+ for i , query in enumerate (set_issues , 1 ):
85+ result = checker .check_syntax (query )
86+ assert not result ['valid' ], f"Query { i } should be invalid: { query } "
87+ # These should have syntax errors related to set names
88+ has_set_error = any ("Expected set name after" in error or "Expected ;, got" in error
89+ for error in result ['errors' ])
90+ assert has_set_error , f"Query { i } should have set name error"
91+ print (f" ✓ Query { i } : Correctly rejected set name syntax" )
92+
93+
94+ def test_area_parameter_issues ():
95+ """Test area parameter and geocode syntax issues"""
96+ checker = OverpassQLSyntaxChecker ()
97+
98+ area_issues = [
99+ '[date:"2014-05-13T00:00:00H"];{{geocodeArea:"El Segundo"}}->.searchArea;(node["building"](area.searchArea);way["building"](area.searchArea);relation["building"](area.searchArea););out qt geom;' ,
100+ '[out:json][timeout:25];{{geocodeArea:"Duisburg"}}->.searchArea;(node["memorial:type"="stolperstein"](area.searchArea);area(area.searchArea););out;>;out skel qt;' ,
101+ ]
102+
103+ print ("Testing area parameter issues..." )
104+ for i , query in enumerate (area_issues , 1 ):
105+ result = checker .check_syntax (query )
106+ assert not result ['valid' ], f"Query { i } should be invalid: { query } "
107+ print (f" ✓ Query { i } : Correctly rejected area syntax issue" )
108+
109+
110+ def test_convert_statement_issues ():
111+ """Test convert statement syntax issues"""
112+ checker = OverpassQLSyntaxChecker ()
113+
114+ convert_issues = [
115+ '[out:json][timeout:1000];node["public_transport"="stop_position"]["name"]["bus"="yes"](around:100,45.1933211,5.7326121)->.bus_stop;foreach.bus_stop->.stop{(node.bus_stop;<;)->.bus_way_rel;relation.bus_way_rel["route"="bus"]["ref"]->.bus_rel;convert bus_stop_info ::=id(),!lines;out;}(node.bus_stop;<;)->.bus_way_rel;relation.bus_way_rel["route"="bus"]["ref"]->.bus_rel;.bus_rel out count;.bus_rel out;.bus_stop out count;.bus_stop out;' ,
116+ ]
117+
118+ print ("Testing convert statement issues..." )
119+ for i , query in enumerate (convert_issues , 1 ):
120+ result = checker .check_syntax (query )
121+ assert not result ['valid' ], f"Query { i } should be invalid: { query } "
122+ print (f" ✓ Query { i } : Correctly rejected convert statement syntax" )
123+
124+
125+ def test_all_invalid_query_samples ():
126+ """Test all 30 invalid queries from the file to ensure they're caught"""
127+ checker = OverpassQLSyntaxChecker ()
128+
129+ # Read the queries from the file
130+ queries_file = os .path .join (os .path .dirname (__file__ ), '..' , 'invalid_queries_comments.txt' )
131+
132+ with open (queries_file , 'r' , encoding = 'utf-8' ) as f :
133+ queries = [line .strip () for line in f if line .strip ()]
134+
135+ print (f"Testing all { len (queries )} invalid queries from file..." )
136+
137+ for i , query in enumerate (queries , 1 ):
138+ result = checker .check_syntax (query )
139+ assert not result ['valid' ], f"Query { i } should be invalid: { query [:50 ]} ..."
140+ assert len (result ['errors' ]) > 0 , f"Query { i } should have error messages"
141+
142+ print (f" ✓ All { len (queries )} queries correctly identified as invalid" )
143+
144+
145+ def run_comprehensive_invalid_tests ():
146+ """Run all invalid query tests"""
147+ print ("=" * 60 )
148+ print ("COMPREHENSIVE INVALID QUERY TESTS" )
149+ print ("=" * 60 )
150+
151+ test_invalid_output_formats ()
152+ print ()
153+
154+ test_invalid_date_formats ()
155+ print ()
156+
157+ test_complex_arrow_operator_issues ()
158+ print ()
159+
160+ test_foreach_and_set_issues ()
161+ print ()
162+
163+ test_area_parameter_issues ()
164+ print ()
165+
166+ test_convert_statement_issues ()
167+ print ()
168+
169+ test_all_invalid_query_samples ()
170+ print ()
171+
172+ print ("=" * 60 )
173+ print ("✅ ALL TESTS PASSED!" )
174+ print ("The checker correctly identifies all invalid query patterns." )
175+ print ("=" * 60 )
176+
177+
178+ if __name__ == "__main__" :
179+ run_comprehensive_invalid_tests ()
0 commit comments