File size: 7,184 Bytes
8429e5e
 
 
 
ad8201c
8429e5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61f1033
 
 
8429e5e
 
 
 
61f1033
 
 
8429e5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
"""Tests for gazet.search — fuzzy search and ID lookup against real parquet data."""

import pandas as pd

from gazet.schemas import Place
from gazet.search import (
    get_by_id,
    get_division_by_id,
    get_natural_earth_by_id,
    search_candidates,
    search_divisions_area,
    search_natural_earth,
)


class TestSearchDivisionsArea:
    def test_returns_dataframe(self, con):
        df = search_divisions_area(con, Place(place="India"))
        assert isinstance(df, pd.DataFrame)
        assert "source" in df.columns
        assert "id" in df.columns

    def test_matches_known_country(self, con):
        df = search_divisions_area(con, Place(place="India"))
        assert not df.empty
        # At least one result should be India
        names = df["name"].str.lower().tolist()
        assert any("india" in name for name in names)

    def test_limits_results(self, con):
        df = search_divisions_area(con, Place(place="a"), limit=3)
        assert len(df) <= 3

    def test_empty_result(self, con):
        # Extremely unlikely string — Jaro-Winkler always returns top N,
        # but similarity should be very low
        df = search_divisions_area(con, Place(place="Xyzz98765"))
        # Results may still be returned (always top-5) but with low similarity
        assert len(df) <= 5

    def test_source_column(self, con):
        df = search_divisions_area(con, Place(place="India"))
        if not df.empty:
            assert (df["source"] == "divisions_area").all()

    def test_case_insensitive(self, con):
        df_upper = search_divisions_area(con, Place(place="INDIA"))
        df_lower = search_divisions_area(con, Place(place="india"))
        # Both should return results (even if different similarity scores)
        assert not df_upper.empty
        assert not df_lower.empty

    def test_with_country_filter(self, con):
        df = search_divisions_area(con, Place(place="Loja", country="EC"))
        # Should find Loja in Ecuador
        if not df.empty:
            assert "source" in df.columns

    def test_similar_names_different_country(self, con):
        df = search_divisions_area(con, Place(place="Manchester"))
        # Should return results (multiple Manchesters exist)
        assert isinstance(df, pd.DataFrame)

    def test_include_geometry_flag(self, con):
        df = search_divisions_area(
            con, Place(place="India"), include_geometry=True, limit=1
        )
        if not df.empty:
            assert "geometry" in df.columns

    def test_include_bbox_flag(self, con):
        df = search_divisions_area(
            con, Place(place="India"), include_bbox=True, limit=1
        )
        if not df.empty:
            assert "bbox" in df.columns

    def test_column_presence(self, con):
        df = search_divisions_area(con, Place(place="India"), limit=1)
        if not df.empty:
            expected_cols = ["source", "id", "name", "country", "subtype", "similarity"]
            for col in expected_cols:
                assert col in df.columns


class TestSearchNaturalEarth:
    def test_returns_dataframe(self, con):
        df = search_natural_earth(con, Place(place="Nile"))
        assert isinstance(df, pd.DataFrame)

    def test_searches_ocean(self, con):
        df = search_natural_earth(con, Place(place="Pacific"))
        assert isinstance(df, pd.DataFrame)

    def test_source_column(self, con):
        df = search_natural_earth(con, Place(place="Nile"))
        if not df.empty:
            assert (df["source"] == "natural_earth").all()

    def test_empty_result(self, con):
        df = search_natural_earth(con, Place(place="Xyzz98765"))
        # Jaro-Winkler always returns top 5, similarity is very low
        assert len(df) <= 5

    def test_limits_results(self, con):
        df = search_natural_earth(con, Place(place="a"), limit=2)
        assert len(df) <= 2

    def test_include_geometry(self, con):
        df = search_natural_earth(con, Place(place="Nile"), include_geometry=True)
        if not df.empty:
            assert "geometry" in df.columns


class TestSearchCandidates:
    def test_searches_both_sources(self, con):
        results = search_candidates(con, Place(place="India"))
        # Should get at least one source
        assert len(results) >= 1
        sources = {df["source"].iloc[0] for df in results if not df.empty}
        assert "divisions_area" in sources

    def test_restricts_to_single_source(self, con):
        results = search_candidates(
            con,
            Place(place="Nile"),
            sources=("natural_earth",),
        )
        for df in results:
            if not df.empty:
                assert df["source"].iloc[0] == "natural_earth"

    def test_empty_place(self, con):
        # Even random strings get fuzzy matches — check results exist
        # but have low similarity
        results = search_candidates(con, Place(place="Xyzz98765"))
        # Results may be non-empty due to fuzzy matching, but similarity low
        for df in results:
            assert len(df) <= 5

    def test_combine_multiple_places(self, con):
        # Search for a place that exists in both sources
        results = search_candidates(
            con,
            Place(place="Brazil"),
            sources=("divisions_area", "natural_earth"),
        )
        for df in results:
            assert isinstance(df, pd.DataFrame)


class TestGetById:
    def test_get_division_by_id(self, con):
        # First get a valid ID from search
        df = search_divisions_area(con, Place(place="India"), limit=1)
        if not df.empty:
            rid = df["id"].iloc[0]
            result = get_division_by_id(con, rid)
            assert not result.empty
            assert result["id"].iloc[0] == rid

    def test_get_natural_earth_by_id(self, con):
        df = search_natural_earth(con, Place(place="Nile"), limit=1)
        if not df.empty:
            rid = df["id"].iloc[0]
            result = get_natural_earth_by_id(con, rid)
            assert not result.empty
            assert result["id"].iloc[0] == rid

    def test_get_by_id_auto_infer_divisions(self, con):
        df = search_divisions_area(con, Place(place="India"), limit=1)
        if not df.empty:
            rid = df["id"].iloc[0]
            result = get_by_id(con, rid)
            assert not result.empty

    def test_get_by_id_auto_infer_natural_earth(self, con):
        df = search_natural_earth(con, Place(place="Nile"), limit=1)
        if not df.empty:
            rid = df["id"].iloc[0]
            # NE IDs start with "ne_"
            assert rid.startswith("ne_")
            result = get_by_id(con, rid)
            assert not result.empty

    def test_get_by_id_invalid(self, con):
        result = get_by_id(con, "nonexistent_id_999")
        assert result.empty

    def test_get_by_id_with_source(self, con):
        df = search_divisions_area(con, Place(place="India"), limit=1)
        if not df.empty:
            rid = df["id"].iloc[0]
            result = get_by_id(con, rid, source="divisions_area")
            assert not result.empty
            assert result["source"].iloc[0] == "divisions_area"