diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ba4838b38..b00f1acdba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,9 @@ mark_as_advanced(CMAKE_VERBOSE_MAKEFILE) # Path to additional CMake modules set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules" ${CMAKE_MODULE_PATH}) +# Provided modules +include(CMakeDependentOption) + #------------------------------------------------------------------------------ # PDAL general settings @@ -381,6 +384,13 @@ if (WITH_SQLITE) endif() option(WITH_PGPOINTCLOUD "Choose if PostgreSQL PointCloud support should be built" TRUE) +cmake_dependent_option( + WITH_PGPOINTCLOUD_TESTS + "Choose if PostgreSQL PointCloud tests should be built" + OFF + WITH_PGPOINTCLOUD + OFF + ) if (WITH_PGPOINTCLOUD) find_package(PostgreSQL) if (POSTGRESQL_FOUND) diff --git a/include/pdal/filters/PCLBlock.hpp b/include/pdal/filters/PCLBlock.hpp index 6a9979ad12..1d7a37e2b6 100644 --- a/include/pdal/filters/PCLBlock.hpp +++ b/include/pdal/filters/PCLBlock.hpp @@ -99,7 +99,6 @@ class PDAL_DLL PCLBlock : public pdal::FilterSequentialIterator boost::uint64_t skipImpl(boost::uint64_t); boost::uint32_t readBufferImpl(PointBuffer&); bool atEndImpl() const; - const pdal::filters::PCLBlock& m_pclblockFilter; }; diff --git a/include/pdal/filters/Scaling.hpp b/include/pdal/filters/Scaling.hpp index 30156b7898..c1236461a4 100644 --- a/include/pdal/filters/Scaling.hpp +++ b/include/pdal/filters/Scaling.hpp @@ -78,11 +78,8 @@ class PDAL_DLL Scaling: public Filter SET_STAGE_LINK("http://pdal.io/stages/filters.scaling.html") SET_STAGE_ENABLED(true) - Scaling(const Options& options) : Filter(options) {} - Scaling& operator=(const Scaling&) = delete; - Scaling(const Scaling&) = delete; static Options getDefaultOptions(); @@ -98,6 +95,11 @@ class PDAL_DLL Scaling: public Filter dimension::Interpretation getInterpretation(std::string t) const; private: + // Not implemented + Scaling& operator=(const Scaling&); + // Not implemented + Scaling(const Scaling&); + void checkImpedance(); Schema alterSchema(Schema const& schema); virtual void initialize(); diff --git a/src/drivers/pgpointcloud/Reader.cpp b/src/drivers/pgpointcloud/Reader.cpp index 626c3448c2..929a1947c9 100644 --- a/src/drivers/pgpointcloud/Reader.cpp +++ b/src/drivers/pgpointcloud/Reader.cpp @@ -277,6 +277,10 @@ pdal::Schema Reader::fetchSchema() const oss << "SELECT schema FROM pointcloud_formats WHERE pcid = " << pcid; char *xml_str = pg_query_once(m_session, oss.str()); + if (!xml_str) + { + throw pdal_error("Unable to fetch schema from `pointcloud_formats`"); + } std::string xml = std::string(xml_str); free(xml_str); diff --git a/src/drivers/pgpointcloud/Writer.cpp b/src/drivers/pgpointcloud/Writer.cpp index 056b203820..7b62042288 100644 --- a/src/drivers/pgpointcloud/Writer.cpp +++ b/src/drivers/pgpointcloud/Writer.cpp @@ -264,6 +264,10 @@ boost::uint32_t Writer::SetupSchema(Schema const& buffer_schema, boost::uint32_t { oss << "SELECT Count(pcid) FROM pointcloud_formats WHERE pcid = " << m_pcid; char *count_str = pg_query_once(m_session, oss.str()); + if (!count_str) + { + throw pdal_error("Unable to count pcid's in table `pointcloud_formats`"); + } schema_count = atoi(count_str); free(count_str); oss.str(""); @@ -280,6 +284,10 @@ boost::uint32_t Writer::SetupSchema(Schema const& buffer_schema, boost::uint32_t bool bCreatePCPointSchema = true; oss << "SELECT Count(pcid) FROM pointcloud_formats"; char *schema_count_str = pg_query_once(m_session, oss.str()); + if (!schema_count_str) + { + throw pdal_error("Unable to count pcid's in table `pointcloud_formats`"); + } schema_count = atoi(schema_count_str); free(schema_count_str); oss.str(""); @@ -316,6 +324,10 @@ boost::uint32_t Writer::SetupSchema(Schema const& buffer_schema, boost::uint32_t else { char *pcid_str = pg_query_once(m_session, "SELECT Max(pcid)+1 AS pcid FROM pointcloud_formats"); + if (!pcid_str) + { + throw pdal_error("Unable to get the max pcid from `pointcloud_formats`"); + } pcid = atoi(pcid_str); } @@ -412,6 +424,10 @@ bool Writer::CheckTableExists(std::string const& name) log()->get(logDEBUG) << "checking for table '" << name << "' existence ... " << std::endl; char *count_str = pg_query_once(m_session, oss.str()); + if (!count_str) + { + throw pdal_error("Unable to check for the existence of `pg_table`"); + } int count = atoi(count_str); free(count_str); diff --git a/src/filters/PCLBlock.cpp b/src/filters/PCLBlock.cpp index 7cec31550d..4ab1e9d486 100644 --- a/src/filters/PCLBlock.cpp +++ b/src/filters/PCLBlock.cpp @@ -154,7 +154,6 @@ namespace sequential PCLBlock::PCLBlock(const pdal::filters::PCLBlock& filter, PointBuffer& buffer) : pdal::FilterSequentialIterator(filter, buffer) - , m_pclblockFilter(filter) { return; } diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 0ce815d074..f7903362c2 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -166,6 +166,29 @@ if (WITH_HDF5) ENDFOREACH(file) endif(WITH_HDF5) +if (WITH_PGPOINTCLOUD AND WITH_PGPOINTCLOUD_TESTS) + set(PDAL_PGPOINTCLOUD_TEST_CPP + drivers/pgpointcloud/PgpointcloudWriterTest.cpp + ) + + set(PGPOINTCLOUD_TEST_DB_HOST localhost CACHE STRING "Postgres test database host") + set(PGPOINTCLOUD_TEST_DB_PORT 5432 CACHE STRING "Postgres test database port") + set(PGPOINTCLOUD_TEST_DB_NAME pdal_test CACHE STRING + "Postgres test database name, must exist and must be able to create databases") + set(PGPOINTCLOUD_TEST_DB_TEMPNAME pdal_test_tmp CACHE STRING "Postgres test database temp database name") + + configure_file( + drivers/pgpointcloud/Support.hpp.in + ${CMAKE_CURRENT_BINARY_DIR}/drivers/pgpointcloud/Support.hpp + ) + + set(PDAL_UNITTEST_TEST_SRC + ${PDAL_UNITTEST_TEST_SRC} + ${PDAL_PGPOINTCLOUD_TEST_CPP} + CACHE INTERNAL "source files for test" + ) +endif (WITH_PGPOINTCLOUD AND WITH_PGPOINTCLOUD_TESTS) + set(PDAL_UNITTEST_SOURCES "") FOREACH(file ${PDAL_UNITTEST_TEST_SRC}) SET(PDAL_UNITTEST_SOURCES "${PDAL_UNITTEST_SOURCES};${file}" @@ -194,6 +217,7 @@ source_group("Source Files\\config" FILES ${PDAL_UNITTEST_CONFIG_SRC}) INCLUDE_DIRECTORIES( . + ${CMAKE_CURRENT_BINARY_DIR} ../../include ${GDAL_INCLUDE_DIR} ${GEOTIFF_INCLUDE_DIR} diff --git a/test/unit/drivers/pgpointcloud/PgpointcloudWriterTest.cpp b/test/unit/drivers/pgpointcloud/PgpointcloudWriterTest.cpp new file mode 100644 index 0000000000..5fc2fe877d --- /dev/null +++ b/test/unit/drivers/pgpointcloud/PgpointcloudWriterTest.cpp @@ -0,0 +1,156 @@ +/****************************************************************************** +* Copyright (c) 2014, Pete Gadomski (pete.gadomski@gmail.com) +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following +* conditions are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided +* with the distribution. +* * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the +* names of its contributors may be used to endorse or promote +* products derived from this software without specific prior +* written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +* OF SUCH DAMAGE. +****************************************************************************/ + +#include + +#include +#include + +#include "Support.hpp" +#include "drivers/pgpointcloud/Support.hpp" + + +pdal::Options getWriterOptions() +{ + pdal::Options options; + + options.add(pdal::Option("connection", pdal::drivers::pgpointcloud::testDbTempConn)); + options.add(pdal::Option("table", "pdal_test_table")); + options.add(pdal::Option("srid", "4326")); + options.add(pdal::Option("capacity", "10000")); + + return options; +} + +struct PgpointcloudWriterTestFixture +{ + PgpointcloudWriterTestFixture() + : m_masterConnection( + pdal::drivers::pgpointcloud::pg_connect( + pdal::drivers::pgpointcloud::testDbConn)) + , m_testConnection(NULL) + { + // Silence those pesky notices + executeOnMasterDb("SET client_min_messages TO WARNING"); + + dropTestDb(); + + std::stringstream createDbSql; + createDbSql << "CREATE DATABASE " << + pdal::drivers::pgpointcloud::testDbTempname << " TEMPLATE template0"; + executeOnMasterDb(createDbSql.str()); + m_testConnection = pdal::drivers::pgpointcloud::pg_connect( + pdal::drivers::pgpointcloud::testDbTempConn); + + executeOnTestDb("CREATE EXTENSION pointcloud"); + } + + void executeOnTestDb(const std::string& sql) + { + pdal::drivers::pgpointcloud::pg_execute(m_testConnection, sql); + } + + ~PgpointcloudWriterTestFixture() + { + if (m_testConnection) + { + PQfinish(m_testConnection); + } + dropTestDb(); + if (m_masterConnection) + { + PQfinish(m_masterConnection); + } + } + +private: + + void executeOnMasterDb(const std::string& sql) + { + pdal::drivers::pgpointcloud::pg_execute(m_masterConnection, sql); + } + + void execute(PGconn* connection, const std::string& sql) + { + if (connection) + { + pdal::drivers::pgpointcloud::pg_execute(connection, sql); + } + else + { + throw std::runtime_error("Not connected to database for testing"); + } + } + + void dropTestDb() + { + std::stringstream dropDbSql; + dropDbSql << "DROP DATABASE IF EXISTS " << pdal::drivers::pgpointcloud::testDbTempname; + executeOnMasterDb(dropDbSql.str()); + } + + PGconn* m_masterConnection; + PGconn* m_testConnection; + +}; + +BOOST_FIXTURE_TEST_SUITE(PgpointcloudWriterTest, PgpointcloudWriterTestFixture) + + +BOOST_AUTO_TEST_CASE(testWrite) +{ + pdal::drivers::las::Reader reader(Support::datapath("1.2-with-color.las")); + pdal::drivers::pgpointcloud::Writer writer(reader, getWriterOptions()); + + writer.initialize(); + + boost::uint64_t numPointsWritten = writer.write(0); + BOOST_CHECK_EQUAL(numPointsWritten, 1065); +} + + +BOOST_AUTO_TEST_CASE(testNoPointcloudExtension) +{ + executeOnTestDb("DROP EXTENSION pointcloud"); + + pdal::drivers::las::Reader reader(Support::datapath("1.2-with-color.las")); + pdal::drivers::pgpointcloud::Writer writer(reader, getWriterOptions()); + + writer.initialize(); + + BOOST_CHECK_THROW(writer.write(0), pdal::pdal_error); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit/drivers/pgpointcloud/Support.hpp.in b/test/unit/drivers/pgpointcloud/Support.hpp.in new file mode 100644 index 0000000000..54376dd40b --- /dev/null +++ b/test/unit/drivers/pgpointcloud/Support.hpp.in @@ -0,0 +1,63 @@ +/****************************************************************************** +* Copyright (c) 2014, Peter J. Gadomski (pete.gadomski@gmail.com) +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following +* conditions are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided +* with the distribution. +* * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the +* names of its contributors may be used to endorse or promote +* products derived from this software without specific prior +* written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +* OF SUCH DAMAGE. +****************************************************************************/ + +#ifndef UNITTEST_DRIVERS_PGPOINTCLOUD_SUPPORT_INCLUDED +#define UNITTEST_DRIVERS_PGPOINTCLOUD_SUPPORT_INCLUDED + + +namespace pdal +{ +namespace drivers +{ +namespace pgpointcloud +{ + + +static const std::string testDbHost("@PGPOINTCLOUD_TEST_DB_HOST@"); +static const std::string testDbPort("@PGPOINTCLOUD_TEST_DB_PORT@"); +static const std::string testDbName("@PGPOINTCLOUD_TEST_DB_NAME@"); +static const std::string testDbTempname("@PGPOINTCLOUD_TEST_DB_TEMPNAME@"); + +static const std::string testDbConn(std::string("dbname='@PGPOINTCLOUD_TEST_DB_NAME@' ") + + "host='@PGPOINTCLOUD_TEST_DB_HOST@' port='@PGPOINTCLOUD_TEST_DB_PORT@'"); +static const std::string testDbTempConn(std::string("dbname='@PGPOINTCLOUD_TEST_DB_TEMPNAME@'") + + "host='@PGPOINTCLOUD_TEST_DB_HOST@' port='@PGPOINTCLOUD_TEST_DB_PORT@'"); + + +} +} +} // namespace pdal::drivers::pgpointcloud + + +#endif // UNITTEST_DRIVERS_PGPOINTCLOUD_SUPPORT_INCLUDED