aboutsummaryrefslogtreecommitdiff
path: root/test/unit/test_c_api.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit/test_c_api.cpp')
-rw-r--r--test/unit/test_c_api.cpp172
1 files changed, 72 insertions, 100 deletions
diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp
index 99d91e3b..90641bd1 100644
--- a/test/unit/test_c_api.cpp
+++ b/test/unit/test_c_api.cpp
@@ -47,6 +47,10 @@
#include <sqlite3.h>
+#ifndef __MINGW32__
+#include <thread>
+#endif
+
using namespace osgeo::proj::common;
using namespace osgeo::proj::crs;
using namespace osgeo::proj::cs;
@@ -4287,106 +4291,6 @@ TEST_F(CApi, proj_as_projjson) {
// ---------------------------------------------------------------------------
-struct Fixture_proj_context_set_autoclose_database : public CApi {
- void test(bool autoclose) {
- proj_context_set_autoclose_database(m_ctxt, autoclose);
-
- auto c_path = proj_context_get_database_path(m_ctxt);
- ASSERT_TRUE(c_path != nullptr);
- std::string path(c_path);
-
- FILE *f = fopen(path.c_str(), "rb");
- ASSERT_NE(f, nullptr);
- fseek(f, 0, SEEK_END);
- auto length = ftell(f);
- std::string content;
- content.resize(static_cast<size_t>(length));
- fseek(f, 0, SEEK_SET);
- auto read_bytes = fread(&content[0], 1, content.size(), f);
- ASSERT_EQ(read_bytes, content.size());
- fclose(f);
- const char *tempdir = getenv("TEMP");
- if (!tempdir) {
- tempdir = getenv("TMP");
- }
- if (!tempdir) {
- tempdir = "/tmp";
- }
- std::string tmp_filename(
- std::string(tempdir) +
- "/test_proj_context_set_autoclose_database.db");
- f = fopen(tmp_filename.c_str(), "wb");
- if (!f) {
- std::cerr << "Cannot create " << tmp_filename << std::endl;
- return;
- }
- fwrite(content.data(), 1, content.size(), f);
- fclose(f);
-
- {
- sqlite3 *db = nullptr;
- sqlite3_open_v2(tmp_filename.c_str(), &db, SQLITE_OPEN_READWRITE,
- nullptr);
- ASSERT_NE(db, nullptr);
- ASSERT_TRUE(sqlite3_exec(db,
- "UPDATE geodetic_crs SET name = 'foo' "
- "WHERE auth_name = 'EPSG' and code = "
- "'4326'",
- nullptr, nullptr, nullptr) == SQLITE_OK);
- sqlite3_close(db);
- }
-
- EXPECT_TRUE(proj_context_set_database_path(m_ctxt, tmp_filename.c_str(),
- nullptr, nullptr));
- {
- auto crs = proj_create_from_database(
- m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr);
- ObjectKeeper keeper(crs);
- ASSERT_NE(crs, nullptr);
- EXPECT_EQ(proj_get_name(crs), std::string("foo"));
- }
-
- {
- sqlite3 *db = nullptr;
- sqlite3_open_v2(tmp_filename.c_str(), &db, SQLITE_OPEN_READWRITE,
- nullptr);
- ASSERT_NE(db, nullptr);
- ASSERT_TRUE(sqlite3_exec(db,
- "UPDATE geodetic_crs SET name = 'bar' "
- "WHERE auth_name = 'EPSG' and code = "
- "'4326'",
- nullptr, nullptr, nullptr) == SQLITE_OK);
- sqlite3_close(db);
- }
- {
- auto crs = proj_create_from_database(
- m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr);
- ObjectKeeper keeper(crs);
- ASSERT_NE(crs, nullptr);
- EXPECT_EQ(proj_get_name(crs),
- std::string(autoclose ? "bar" : "foo"));
- }
-
- if (!autoclose) {
- proj_context_destroy(m_ctxt);
- m_ctxt = nullptr;
- }
- std::remove(tmp_filename.c_str());
- }
-};
-
-TEST_F(Fixture_proj_context_set_autoclose_database,
- proj_context_set_autoclose_database_true) {
- test(true);
-}
-
-TEST_F(Fixture_proj_context_set_autoclose_database,
- proj_context_set_autoclose_database_false) {
- test(false);
-}
-
-// ---------------------------------------------------------------------------
-
TEST_F(CApi, proj_context_copy_from_default) {
auto c_path = proj_context_get_database_path(m_ctxt);
ASSERT_TRUE(c_path != nullptr);
@@ -5644,4 +5548,72 @@ TEST_F(CApi, proj_get_geoid_models_from_database) {
EXPECT_FALSE(findInList(list, "OSGM15"));
}
+// ---------------------------------------------------------------------------
+
+#if !defined(_WIN32)
+TEST_F(CApi, open_plenty_of_contexts) {
+ // Test that we only consume 1 file handle for the connection to the
+ // database
+ std::vector<FILE *> dummyFilePointers;
+ std::vector<PJ_CONTEXT *> ctxts;
+ // 1024 is the number of file descriptors that can be opened simultaneously
+ // by a Linux process (by default)
+ for (int i = 0; i < 1024 - 50; i++) {
+ FILE *f = fopen("/dev/null", "rb");
+ ASSERT_TRUE(f != nullptr);
+ dummyFilePointers.push_back(f);
+ }
+ for (int i = 0; i < 100; i++) {
+ PJ_CONTEXT *ctxt = proj_context_create();
+ ASSERT_TRUE(ctxt != nullptr);
+ auto obj = proj_create(ctxt, "EPSG:4326");
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ ctxts.push_back(ctxt);
+ }
+ for (PJ_CONTEXT *ctxt : ctxts) {
+ proj_context_destroy(ctxt);
+ }
+ for (FILE *f : dummyFilePointers) {
+ fclose(f);
+ }
+ proj_cleanup();
+}
+#endif // !defined(_WIN32)
+
+// ---------------------------------------------------------------------------
+
+#ifndef __MINGW32__
+// We need std::thread support
+
+TEST_F(CApi, concurrent_context) {
+ // Test that concurrent access to the database is thread safe.
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 4; i++) {
+ threads.emplace_back(std::thread([] {
+ for (int j = 0; j < 60; j++) {
+ PJ_CONTEXT *ctxt = proj_context_create();
+ {
+ auto obj = proj_create(ctxt, "EPSG:4326");
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ }
+ {
+ auto obj = proj_create(
+ ctxt, ("EPSG:" + std::to_string(32600 + j)).c_str());
+ ObjectKeeper keeper(obj);
+ EXPECT_NE(obj, nullptr);
+ }
+ proj_context_destroy(ctxt);
+ }
+ }));
+ }
+ for (auto &t : threads) {
+ t.join();
+ }
+ proj_cleanup();
+}
+
+#endif // __MINGW32__
+
} // namespace