Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Test OSRSetPROJSearchPaths()
6 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2019, Even Rouault <even dot rouault at spatialys dot com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include <stdlib.h>
31 :
32 : #include "cpl_error.h"
33 : #include "cpl_string.h"
34 : #include "ogr_srs_api.h"
35 : #include "cpl_multiproc.h"
36 :
37 : #include "test_data.h"
38 : #include "gtest_include.h"
39 :
40 : namespace
41 : {
42 :
43 : // ---------------------------------------------------------------------------
44 :
45 2 : static void func1(void *)
46 : {
47 2 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr);
48 2 : CPLPushErrorHandler(CPLQuietErrorHandler);
49 2 : auto ret = OSRImportFromEPSG(hSRS, 32631);
50 2 : CPLPopErrorHandler();
51 2 : EXPECT_NE(ret, OGRERR_NONE);
52 2 : OSRDestroySpatialReference(hSRS);
53 2 : }
54 :
55 2 : static void func2(void *)
56 : {
57 2 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr);
58 2 : EXPECT_EQ(OSRImportFromEPSG(hSRS, 32631), OGRERR_NONE);
59 2 : OSRDestroySpatialReference(hSRS);
60 2 : }
61 :
62 4 : TEST(test_osr_set_proj_search_paths, test)
63 : {
64 1 : auto tokens = OSRGetPROJSearchPaths();
65 :
66 : // Overriding PROJ_LIB and PROJ_DATA
67 : static char szPROJ_LIB[] = "PROJ_LIB=/i_do/not_exist";
68 1 : putenv(szPROJ_LIB);
69 : static char szPROJ_DATA[] = "PROJ_DATA=/i_do/not_exist";
70 1 : putenv(szPROJ_DATA);
71 :
72 : // Test we can no longer find the database
73 1 : func1(nullptr);
74 :
75 : // In a thread as well
76 1 : auto t1 = CPLCreateJoinableThread(func1, nullptr);
77 1 : CPLJoinThread(t1);
78 :
79 : {
80 1 : const char *const apszDummyPaths[] = {"/i/am/dummy", nullptr};
81 1 : OSRSetPROJSearchPaths(apszDummyPaths);
82 1 : auto tokens2 = OSRGetPROJSearchPaths();
83 1 : EXPECT_STREQ(tokens2[0], "/i/am/dummy");
84 1 : CSLDestroy(tokens2);
85 : }
86 :
87 : // Use OSRSetPROJSearchPaths to restore search paths
88 1 : OSRSetPROJSearchPaths(tokens);
89 :
90 : // This time this should work
91 1 : func2(nullptr);
92 :
93 : // In a thread as well
94 1 : auto t2 = CPLCreateJoinableThread(func2, nullptr);
95 1 : CPLJoinThread(t2);
96 :
97 1 : CSLDestroy(tokens);
98 1 : OSRCleanup();
99 1 : }
100 :
101 4 : static void osr_cleanup_in_threads_thread_func(void *)
102 : {
103 4 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr);
104 4 : EXPECT_EQ(OSRImportFromEPSG(hSRS, 32631), OGRERR_NONE);
105 :
106 : // Test cleanup effect
107 4 : OSRCleanup();
108 :
109 248 : for (int epsg = 32601; epsg <= 32661; epsg++)
110 : {
111 244 : EXPECT_EQ(OSRImportFromEPSG(hSRS, epsg), OGRERR_NONE);
112 244 : EXPECT_EQ(OSRImportFromEPSG(hSRS, epsg + 100), OGRERR_NONE);
113 : }
114 4 : OSRDestroySpatialReference(hSRS);
115 4 : }
116 :
117 4 : TEST(test_osr_set_proj_search_paths, osr_cleanup_in_threads)
118 : {
119 : // Test fix for #2744
120 : CPLJoinableThread *ahThreads[4];
121 5 : for (int i = 0; i < 4; i++)
122 : {
123 4 : ahThreads[i] = CPLCreateJoinableThread(
124 : osr_cleanup_in_threads_thread_func, nullptr);
125 : }
126 5 : for (int i = 0; i < 4; i++)
127 : {
128 4 : CPLJoinThread(ahThreads[i]);
129 : }
130 1 : }
131 :
132 4 : TEST(test_osr_set_proj_search_paths, auxiliary_db)
133 : {
134 : // This test use auxiliary database created with proj 6.3.2
135 : // (tested up to 8.0.0) and can be sensitive to future
136 : // database structure change.
137 : //
138 : // See PR https://github.com/OSGeo/gdal/pull/3590
139 : //
140 : // Starting with sqlite 3.41, and commit
141 : // https://github.com/sqlite/sqlite/commit/ed07d0ea765386c5bdf52891154c70f048046e60
142 : // we must use the same exact table definition in the auxiliary db, otherwise
143 : // SQLite3 is confused regarding column types. Hence this PROJ >= 9 check,
144 : // to use a table structure identical to proj.db of PROJ 9.
145 1 : int nPROJMajor = 0;
146 1 : OSRGetPROJVersion(&nPROJMajor, nullptr, nullptr);
147 1 : const char *apszAux0[] = {nPROJMajor >= 9
148 1 : ? TUT_ROOT_DATA_DIR "/test_aux_proj_9.db"
149 : : TUT_ROOT_DATA_DIR "/test_aux.db",
150 1 : nullptr};
151 1 : OSRSetPROJAuxDbPaths(apszAux0);
152 :
153 1 : CPLStringList aosAux1(OSRGetPROJAuxDbPaths());
154 1 : ASSERT_EQ(aosAux1.size(), 1);
155 1 : ASSERT_STREQ(apszAux0[0], aosAux1[0]);
156 1 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr);
157 1 : EXPECT_EQ(OSRImportFromEPSG(hSRS, 4326), OGRERR_NONE);
158 1 : EXPECT_EQ(OSRImportFromEPSG(hSRS, 111111), OGRERR_NONE);
159 1 : OSRDestroySpatialReference(hSRS);
160 : }
161 :
162 : } // namespace
|