Skip to content

Commit 5e75853

Browse files
committed
Added some more tests
1 parent cfbea3b commit 5e75853

3 files changed

Lines changed: 366 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
def analyze_invalid_queries():
12+
"""Analyze the invalid queries from invalid_queries_comments.txt"""
13+
14+
# Read the queries from the file
15+
queries_file = os.path.join(os.path.dirname(__file__), '..', 'invalid_queries_comments.txt')
16+
17+
with open(queries_file, 'r', encoding='utf-8') as f:
18+
queries = [line.strip() for line in f if line.strip()]
19+
20+
print(f"Found {len(queries)} queries to analyze\n")
21+
22+
checker = OverpassQLSyntaxChecker()
23+
24+
valid_count = 0
25+
invalid_count = 0
26+
error_patterns = {}
27+
28+
for i, query in enumerate(queries, 1):
29+
print(f"Query {i}: {query[:80]}{'...' if len(query) > 80 else ''}")
30+
31+
try:
32+
result = checker.check_syntax(query)
33+
is_valid = result['valid']
34+
if is_valid:
35+
print(" ✓ Current checker considers this VALID")
36+
valid_count += 1
37+
else:
38+
print(" ✗ Current checker considers this INVALID")
39+
invalid_count += 1
40+
41+
# Get detailed error info
42+
errors = result.get('errors', [])
43+
if errors:
44+
for error in errors[:2]: # Show first 2 errors
45+
print(f" Error: {error}")
46+
47+
# Categorize error patterns by type of error message
48+
if "Expected" in error:
49+
error_type = "Expected Token"
50+
elif "Unexpected" in error:
51+
error_type = "Unexpected Token"
52+
elif "Invalid" in error:
53+
error_type = "Invalid Syntax"
54+
elif "Unknown" in error:
55+
error_type = "Unknown Element"
56+
else:
57+
error_type = "Other Error"
58+
59+
if error_type not in error_patterns:
60+
error_patterns[error_type] = 0
61+
error_patterns[error_type] += 1
62+
63+
except Exception as e:
64+
print(f" ! Exception during validation: {e}")
65+
invalid_count += 1
66+
67+
print()
68+
69+
print("\n=== Summary ===")
70+
print(f"Total queries: {len(queries)}")
71+
print(f"Currently detected as valid: {valid_count}")
72+
print(f"Currently detected as invalid: {invalid_count}")
73+
74+
if error_patterns:
75+
print("\nError pattern distribution:")
76+
for pattern, count in sorted(error_patterns.items()):
77+
print(f" {pattern}: {count}")
78+
79+
if __name__ == "__main__":
80+
analyze_invalid_queries()

tests/categorize_error_patterns.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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+
def categorize_invalid_query_errors():
12+
"""Categorize the specific types of errors in the invalid queries"""
13+
14+
# Read the queries from the file
15+
queries_file = os.path.join(os.path.dirname(__file__), '..', 'invalid_queries_comments.txt')
16+
17+
with open(queries_file, 'r', encoding='utf-8') as f:
18+
queries = [line.strip() for line in f if line.strip()]
19+
20+
print(f"Analyzing error patterns in {len(queries)} invalid queries\n")
21+
22+
checker = OverpassQLSyntaxChecker()
23+
24+
# Categories of errors we'll track
25+
error_categories = {
26+
'arrow_operator': [], # Issues with -> operator
27+
'output_format': [], # Invalid output formats
28+
'date_format': [], # Date format issues
29+
'set_names': [], # Set name parsing issues
30+
'foreach_loops': [], # Issues with foreach syntax
31+
'area_parameters': [], # Area parameter issues
32+
'convert_statement': [], # Issues with convert statements
33+
'other': [] # Other unclassified errors
34+
}
35+
36+
for i, query in enumerate(queries, 1):
37+
print(f"\nQuery {i}:")
38+
print(f" {query[:100]}{'...' if len(query) > 100 else ''}")
39+
40+
result = checker.check_syntax(query)
41+
errors = result.get('errors', [])
42+
43+
for error in errors[:1]: # Look at first error for categorization
44+
error_lower = error.lower()
45+
46+
if 'unexpected token: ->' in error_lower or 'expected ), got .' in error_lower:
47+
error_categories['arrow_operator'].append((i, query, error))
48+
print(f" → ARROW OPERATOR: {error}")
49+
elif 'invalid output format' in error_lower:
50+
error_categories['output_format'].append((i, query, error))
51+
print(f" → OUTPUT FORMAT: {error}")
52+
elif 'invalid date format' in error_lower:
53+
error_categories['date_format'].append((i, query, error))
54+
print(f" → DATE FORMAT: {error}")
55+
elif 'expected set name after' in error_lower:
56+
error_categories['set_names'].append((i, query, error))
57+
print(f" → SET NAMES: {error}")
58+
elif 'foreach' in error_lower:
59+
error_categories['foreach_loops'].append((i, query, error))
60+
print(f" → FOREACH: {error}")
61+
elif 'expected area parameter' in error_lower:
62+
error_categories['area_parameters'].append((i, query, error))
63+
print(f" → AREA PARAM: {error}")
64+
elif 'convert' in error_lower:
65+
error_categories['convert_statement'].append((i, query, error))
66+
print(f" → CONVERT: {error}")
67+
else:
68+
error_categories['other'].append((i, query, error))
69+
print(f" → OTHER: {error}")
70+
71+
print("\n" + "="*60)
72+
print("ERROR CATEGORY SUMMARY")
73+
print("="*60)
74+
75+
for category, errors in error_categories.items():
76+
if errors:
77+
print(f"\n{category.upper().replace('_', ' ')} ({len(errors)} queries):")
78+
for query_num, query, error in errors:
79+
print(f" Query {query_num}: {error}")
80+
81+
# Analysis of what might need fixing
82+
print("\n" + "="*60)
83+
print("POTENTIAL IMPROVEMENTS NEEDED")
84+
print("="*60)
85+
86+
if error_categories['arrow_operator']:
87+
print(f"\n• Arrow operator parsing ({len(error_categories['arrow_operator'])} cases)")
88+
print(" Many queries use complex arrow syntax that might be valid in real Overpass QL")
89+
90+
if error_categories['output_format']:
91+
print(f"\n• Output format support ({len(error_categories['output_format'])} cases)")
92+
print(" Missing support for: osm, xlsx, pjsonl formats")
93+
94+
if error_categories['date_format']:
95+
print(f"\n• Date format parsing ({len(error_categories['date_format'])} cases)")
96+
print(" Missing support for timezone suffixes like +09:00")
97+
98+
if error_categories['set_names']:
99+
print(f"\n• Set name handling ({len(error_categories['set_names'])} cases)")
100+
print(" Issues with foreach loops and set operations")
101+
102+
if error_categories['area_parameters']:
103+
print(f"\n• Area parameter parsing ({len(error_categories['area_parameters'])} cases)")
104+
print(" Issues with complex area expressions")
105+
106+
if __name__ == "__main__":
107+
categorize_invalid_query_errors()
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
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

Comments
 (0)