1 /** 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * 4 * This file is part of osm2pgsql (https://osm2pgsql.org/). 5 * 6 * Copyright (C) 2006-2021 by the osm2pgsql developer community. 7 * For a full list of authors see the git log. 8 */ 9 10 #include <catch.hpp> 11 12 #include "common-import.hpp" 13 #include "common-options.hpp" 14 15 static testing::db::import_t db; 16 17 static char const *const conf_file = "test_output_flex_types.lua"; 18 19 TEST_CASE("type nil") 20 { 21 testing::opt_t const options = testing::opt_t().flex(conf_file); 22 23 REQUIRE_NOTHROW( 24 db.run_import(options, "n10 v1 dV x10.0 y10.0 Ttype=nil\n")); 25 26 auto conn = db.db().connect(); 27 28 CHECK(1 == conn.get_count("nodes")); 29 CHECK(1 == 30 conn.get_count( 31 "nodes", 32 "ttext IS NULL AND tbool IS NULL AND tint2 IS NULL AND " 33 "tint4 IS NULL AND tint8 IS NULL AND treal IS NULL AND " 34 "thstr IS NULL AND tjson IS NULL AND tdirn IS NULL AND " 35 "tsqlt IS NULL")); 36 } 37 38 TEST_CASE("type boolean") 39 { 40 testing::opt_t const options = testing::opt_t().flex(conf_file); 41 42 REQUIRE_NOTHROW( 43 db.run_import(options, "n10 v1 dV x10.0 y10.0 Ttype=boolean\n")); 44 45 auto conn = db.db().connect(); 46 47 CHECK(2 == conn.get_count("nodes")); 48 CHECK(1 == conn.get_count("nodes", "tbool = true AND tint2 = 1 AND " 49 "tint4 = 1 AND tint8 = 1 AND " 50 "tjson = 'true'::jsonb AND tdirn = 1")); 51 CHECK(1 == conn.get_count("nodes", "tbool = false AND tint2 = 0 AND " 52 "tint4 = 0 AND tint8 = 0 AND " 53 "tjson = 'false'::jsonb AND tdirn = 0")); 54 } 55 56 TEST_CASE("type boolean in column where it doesn't belong") 57 { 58 testing::opt_t const options = testing::opt_t().flex(conf_file); 59 60 REQUIRE_THROWS(db.run_import( 61 options, "n10 v1 dV x10.0 y10.0 Ttype=boolean-fail column=ttext\n")); 62 REQUIRE_THROWS(db.run_import( 63 options, "n10 v1 dV x10.0 y10.0 Ttype=boolean-fail column=treal\n")); 64 REQUIRE_THROWS(db.run_import( 65 options, "n10 v1 dV x10.0 y10.0 Ttype=boolean-fail column=thstr\n")); 66 REQUIRE_THROWS(db.run_import( 67 options, "n10 v1 dV x10.0 y10.0 Ttype=boolean-fail column=tsqlt\n")); 68 69 auto conn = db.db().connect(); 70 71 CHECK(0 == conn.get_count("nodes")); 72 } 73 74 TEST_CASE("type number") 75 { 76 testing::opt_t const options = testing::opt_t().flex(conf_file); 77 78 REQUIRE_NOTHROW( 79 db.run_import(options, "n10 v1 dV x10.0 y10.0 Ttype=number\n")); 80 81 auto conn = db.db().connect(); 82 83 CHECK(19 == conn.get_count("nodes")); 84 85 // clang-format off 86 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2147483649' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 IS NULL AND tint8 = -2147483649 AND tjson = '-2147483649'::jsonb AND tdirn = -1")); 87 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2147483648' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 = -2147483648 AND tint8 = -2147483648 AND tjson = '-2147483648'::jsonb AND tdirn = -1")); 88 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2147483647' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 = -2147483647 AND tint8 = -2147483647 AND tjson = '-2147483647'::jsonb AND tdirn = -1")); 89 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-32769' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 = -32769 AND tint8 = -32769 AND treal = -32769 AND tjson = '-32769'::jsonb AND tdirn = -1")); 90 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-32768' AND ttext = tsqlt AND tbool = true AND tint2 = -32768 AND tint4 = -32768 AND tint8 = -32768 AND treal = -32768 AND tjson = '-32768'::jsonb AND tdirn = -1")); 91 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-32767' AND ttext = tsqlt AND tbool = true AND tint2 = -32767 AND tint4 = -32767 AND tint8 = -32767 AND treal = -32767 AND tjson = '-32767'::jsonb AND tdirn = -1")); 92 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2' AND ttext = tsqlt AND tbool = true AND tint2 = -2 AND tint4 = -2 AND tint8 = -2 AND treal = -2 AND tjson = '-2'::jsonb AND tdirn = -1")); 93 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-1' AND ttext = tsqlt AND tbool = true AND tint2 = -1 AND tint4 = -1 AND tint8 = -1 AND treal = -1 AND tjson = '-1'::jsonb AND tdirn = -1")); 94 CHECK(1 == conn.get_count("nodes", " tsqlt = '-0.5' AND ttext = tsqlt AND tbool = true AND tint2 = 0 AND tint4 = 0 AND tint8 = 0 AND treal = -0.5 AND tjson = '-0.5'::jsonb AND tdirn = -1")); 95 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '0' AND ttext = tsqlt AND tbool = false AND tint2 = 0 AND tint4 = 0 AND tint8 = 0 AND treal = 0 AND tjson = '0'::jsonb AND tdirn = 0")); 96 CHECK(1 == conn.get_count("nodes", " tsqlt = '0.5' AND ttext = tsqlt AND tbool = true AND tint2 = 0 AND tint4 = 0 AND tint8 = 0 AND treal = 0.5 AND tjson = '0.5'::jsonb AND tdirn = 1")); 97 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '1' AND ttext = tsqlt AND tbool = true AND tint2 = 1 AND tint4 = 1 AND tint8 = 1 AND treal = 1 AND tjson = '1'::jsonb AND tdirn = 1")); 98 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2' AND ttext = tsqlt AND tbool = true AND tint2 = 2 AND tint4 = 2 AND tint8 = 2 AND treal = 2 AND tjson = '2'::jsonb AND tdirn = 1")); 99 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '32767' AND ttext = tsqlt AND tbool = true AND tint2 = 32767 AND tint4 = 32767 AND tint8 = 32767 AND treal = 32767 AND tjson = '32767'::jsonb AND tdirn = 1")); 100 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '32768' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 = 32768 AND tint8 = 32768 AND treal = 32768 AND tjson = '32768'::jsonb AND tdirn = 1")); 101 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '32769' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 = 32769 AND tint8 = 32769 AND treal = 32769 AND tjson = '32769'::jsonb AND tdirn = 1")); 102 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2147483647' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 = 2147483647 AND tint8 = 2147483647 AND tjson = '2147483647'::jsonb AND tdirn = 1")); 103 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2147483648' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483648 AND tjson = '2147483648'::jsonb AND tdirn = 1")); 104 CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2147483649' AND ttext = tsqlt AND tbool = true AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483649 AND tjson = '2147483649'::jsonb AND tdirn = 1")); 105 // clang-format on 106 } 107 108 TEST_CASE("type string (with bool)") 109 { 110 testing::opt_t const options = testing::opt_t().flex(conf_file); 111 112 REQUIRE_NOTHROW( 113 db.run_import(options, "n10 v1 dV x10.0 y10.0 Ttype=string-bool\n")); 114 115 auto conn = db.db().connect(); 116 117 CHECK(9 == conn.get_count("nodes")); 118 CHECK(3 == conn.get_count("nodes", "tbool = true AND ttext = 'istrue'")); 119 CHECK(3 == conn.get_count("nodes", "tbool = false AND ttext = 'isfalse'")); 120 CHECK(3 == conn.get_count("nodes", "tbool IS NULL AND ttext = 'isnull'")); 121 } 122 123 TEST_CASE("type string (with direction)") 124 { 125 testing::opt_t const options = testing::opt_t().flex(conf_file); 126 127 REQUIRE_NOTHROW(db.run_import( 128 options, "n10 v1 dV x10.0 y10.0 Ttype=string-direction\n")); 129 130 auto conn = db.db().connect(); 131 132 CHECK(9 == conn.get_count("nodes")); 133 CHECK(5 == conn.get_count("nodes", "tdirn = tint2")); 134 CHECK(4 == conn.get_count("nodes", "tdirn IS NULL AND tint2 IS NULL")); 135 } 136 137 TEST_CASE("type string (with number)") 138 { 139 testing::opt_t const options = testing::opt_t().flex(conf_file); 140 141 REQUIRE_NOTHROW(db.run_import( 142 options, "n10 v1 dV x10.0 y10.0 Ttype=string-with-number\n")); 143 144 auto conn = db.db().connect(); 145 146 CHECK(18 == conn.get_count("nodes")); 147 148 // clang-format off 149 CHECK(1 == conn.get_count("nodes", "tsqlt = '-2147483649' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = -2147483649 ")); 150 CHECK(1 == conn.get_count("nodes", "tsqlt = '-2147483648' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -2147483648 AND tint8 = -2147483648 ")); 151 CHECK(1 == conn.get_count("nodes", "tsqlt = '-2147483647' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -2147483647 AND tint8 = -2147483647 ")); 152 CHECK(1 == conn.get_count("nodes", "tsqlt = '-32769' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -32769 AND tint8 = -32769 AND treal = -32769")); 153 CHECK(1 == conn.get_count("nodes", "tsqlt = '-32768' AND ttext = tsqlt AND tint2 = -32768 AND tint4 = -32768 AND tint8 = -32768 AND treal = -32768")); 154 CHECK(1 == conn.get_count("nodes", "tsqlt = '-32767' AND ttext = tsqlt AND tint2 = -32767 AND tint4 = -32767 AND tint8 = -32767 AND treal = -32767")); 155 CHECK(1 == conn.get_count("nodes", "tsqlt = '-2' AND ttext = tsqlt AND tint2 = -2 AND tint4 = -2 AND tint8 = -2 AND treal = -2 ")); 156 CHECK(1 == conn.get_count("nodes", "tsqlt = '-1' AND ttext = tsqlt AND tint2 = -1 AND tint4 = -1 AND tint8 = -1 AND treal = -1 ")); 157 CHECK(1 == conn.get_count("nodes", "tsqlt = '0' AND ttext = tsqlt AND tint2 = 0 AND tint4 = 0 AND tint8 = 0 AND treal = 0 ")); 158 CHECK(1 == conn.get_count("nodes", "tsqlt = '1' AND ttext = tsqlt AND tint2 = 1 AND tint4 = 1 AND tint8 = 1 AND treal = 1 ")); 159 CHECK(1 == conn.get_count("nodes", "tsqlt = '2' AND ttext = tsqlt AND tint2 = 2 AND tint4 = 2 AND tint8 = 2 AND treal = 2 ")); 160 CHECK(1 == conn.get_count("nodes", "tsqlt = '32767' AND ttext = tsqlt AND tint2 = 32767 AND tint4 = 32767 AND tint8 = 32767 AND treal = 32767 ")); 161 CHECK(1 == conn.get_count("nodes", "tsqlt = '32768' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 32768 AND tint8 = 32768 AND treal = 32768 ")); 162 CHECK(1 == conn.get_count("nodes", "tsqlt = '32769' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 32769 AND tint8 = 32769 AND treal = 32769 ")); 163 CHECK(1 == conn.get_count("nodes", "tsqlt = '2147483647' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 2147483647 AND tint8 = 2147483647 ")); 164 CHECK(1 == conn.get_count("nodes", "tsqlt = '2147483648' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483648 ")); 165 CHECK(1 == conn.get_count("nodes", "tsqlt = '2147483649' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483649 ")); 166 CHECK(1 == conn.get_count("nodes", "tsqlt = ' 42' AND ttext = tsqlt AND tint2 = 42 AND tint4 = 42 AND tint8 = 42 AND treal = 42 ")); 167 // clang-format on 168 } 169 170 TEST_CASE("type string (with invalid number)") 171 { 172 testing::opt_t const options = testing::opt_t().flex(conf_file); 173 174 REQUIRE_NOTHROW(db.run_import( 175 options, "n10 v1 dV x10.0 y10.0 Ttype=string-with-invalid-number\n")); 176 177 auto conn = db.db().connect(); 178 179 CHECK(7 == conn.get_count("nodes")); 180 181 // clang-format off 182 CHECK(1 == conn.get_count("nodes", "ttext = '' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND treal IS NULL")); 183 CHECK(1 == conn.get_count("nodes", "ttext = 'abc' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND treal IS NULL")); 184 CHECK(1 == conn.get_count("nodes", "ttext = '0a' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND treal IS NULL")); 185 CHECK(1 == conn.get_count("nodes", "ttext = '0xa' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND abs(treal - 10) < 0.0000001")); 186 CHECK(1 == conn.get_count("nodes", "ttext = '--1' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND treal IS NULL")); 187 CHECK(1 == conn.get_count("nodes", "ttext = '1foo' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND treal IS NULL")); 188 CHECK(1 == conn.get_count("nodes", "ttext = '1.2' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL AND abs(treal - 1.2) < 0.0000001")); 189 // clang-format on 190 } 191 192 TEST_CASE("type number in column where it doesn't belong") 193 { 194 testing::opt_t const options = testing::opt_t().flex(conf_file); 195 196 REQUIRE_THROWS(db.run_import( 197 options, "n10 v1 dV x10.0 y10.0 Ttype=number-fail column=thstr\n")); 198 199 auto conn = db.db().connect(); 200 201 CHECK(0 == conn.get_count("nodes")); 202 } 203 204 TEST_CASE("Adding a function should always fail") 205 { 206 testing::opt_t const options = testing::opt_t().flex(conf_file); 207 208 std::string const types[] = {"ttext", "tbool", "tint2", "tint4", "tint8", 209 "treal", "thstr", "tdirn", "tsqlt"}; 210 211 for (auto const &type : types) { 212 auto const line = 213 "n10 v1 dV x10.0 y10.0 Ttype=function-fail column=" + type + "\n"; 214 REQUIRE_THROWS(db.run_import(options, line.c_str())); 215 } 216 217 auto conn = db.db().connect(); 218 219 CHECK(0 == conn.get_count("nodes")); 220 } 221 222 TEST_CASE("type table") 223 { 224 testing::opt_t const options = testing::opt_t().flex(conf_file); 225 226 REQUIRE_NOTHROW( 227 db.run_import(options, "n10 v1 dV x10.0 y10.0 Ttype=table\n")); 228 229 auto conn = db.db().connect(); 230 231 CHECK(2 == conn.get_count("nodes")); 232 233 CHECK(1 == conn.get_count("nodes", "thstr = '' AND tjson = '{}'::jsonb")); 234 CHECK(1 == conn.get_count("nodes", 235 "thstr = 'a=>b,c=>d' AND " 236 "tjson = '{\"a\": \"b\", \"c\": \"d\"}'::jsonb")); 237 } 238 239 TEST_CASE("Adding a table with non-strings should fail for hstore") 240 { 241 testing::opt_t const options = testing::opt_t().flex(conf_file); 242 243 char const *const line = "n10 v1 dV x10.0 y10.0 Ttype=table-hstore-fail\n"; 244 REQUIRE_THROWS(db.run_import(options, line)); 245 246 auto conn = db.db().connect(); 247 248 CHECK(0 == conn.get_count("nodes")); 249 } 250 251 TEST_CASE("Adding a table should fail except for hstore and json/jsonb") 252 { 253 testing::opt_t const options = testing::opt_t().flex(conf_file); 254 255 std::string const types[] = {"ttext", "tbool", "tint2", "tint4", 256 "tint8", "treal", "tdirn", "tsqlt"}; 257 258 for (auto const &type : types) { 259 auto const line = 260 "n10 v1 dV x10.0 y10.0 Ttype=table-fail column=" + type + "\n"; 261 REQUIRE_THROWS(db.run_import(options, line.c_str())); 262 } 263 264 auto conn = db.db().connect(); 265 266 CHECK(0 == conn.get_count("nodes")); 267 } 268 269 TEST_CASE("Adding a complex table in jsonb") 270 { 271 testing::opt_t const options = testing::opt_t().flex(conf_file); 272 273 char const *const line = "n10 v1 dV x10.0 y10.0 Ttype=json\n"; 274 REQUIRE_NOTHROW(db.run_import(options, line)); 275 276 auto conn = db.db().connect(); 277 278 CHECK(1 == 279 conn.get_count( 280 "nodes", 281 "tjson = '{" 282 "\"astring\": \"123\", \"aninteger\": 124, \"anumber\": 12.5, " 283 "\"atrue\": true, \"afalse\": false, " 284 "\"atable\": {\"a\": \"nested\", \"tab\": \"le\"}, " 285 "\"anarray\": [4, 3, 7]" 286 "}'::jsonb")); 287 } 288 289 TEST_CASE("Adding a table with a loop should fail") 290 { 291 testing::opt_t const options = testing::opt_t().flex(conf_file); 292 293 char const *const line = "n10 v1 dV x10.0 y10.0 Ttype=json-loop\n"; 294 REQUIRE_THROWS(db.run_import(options, line)); 295 296 auto conn = db.db().connect(); 297 298 CHECK(0 == conn.get_count("nodes")); 299 } 300