36 foreach ($ring as $point) {
37 $binary .= pack(
'd2', $point[0], $point[1]);
42$packedTest =
new ReflectionMethod(LGV_TZ_Lookup_Query::class,
'_wn_PackedPoly');
43if (PHP_VERSION_ID < 80100) {
$packedTest->setAccessible(
true); }
44$rings = [[], [[1.0, 2.0]], [[0.0, 0.0], [2.0, 2.0]],
45 [[0, 0], [4, 0], [4, 4], [0, 4]],
46 [[0, 0], [4, 0], [4, 4], [2, 2], [0, 4], [0, 0]],
47 [[0, 0], [4, 4], [0, 4], [4, 0], [0, 0]],
48 [[0, 0], [0, 0], [4, 0], [4, 4], [0, 4], [0, 0]],
51foreach ([1023, 1024, 1025, 2048, 2049, 8193] as
$vertices) {
55 $radius = ($i % 2) ? 4 : 2;
56 $ring[] = [round(cos($angle) * $radius, 6), round(sin($angle) * $radius, 6)];
64 foreach ([$ring, array_reverse($ring)] as $oriented) {
66 $points = [[0, 0], [1, 1], [4, 4], [-4, -4], [0, 4], [4, 0]];
67 foreach ([0, 1, 1022, 1023, 1024, count($oriented) - 1] as $index) {
68 if (isset($oriented[$index])) {
69 $points[] = $oriented[$index];
70 $points[] = [$oriented[$index][0] + 1e-7, $oriented[$index][1] - 1e-7];
71 if (isset($oriented[$index + 1])) {
72 $points[] = [($oriented[$index][0] + $oriented[$index + 1][0]) / 2,
73 ($oriented[$index][1] + $oriented[$index + 1][1]) / 2];
77 for ($i = 0; $i < 100; ++$i) {
78 $points[] = [mt_rand(-5000000, 5000000) / 1e6, mt_rand(-5000000, 5000000) / 1e6];
80 foreach ($points as $point) {
82 'Winding result with '.count($oriented).
' vertices');
91 yield from parent::get_tz_polygons($ids);
99$rect = [
'east' => 4,
'west' => 0,
'north' => 4,
'south' => 0];
100$miss = [[0, 0], [4, 0], [4, 1], [0, 1], [0, 0]];
101$hit = [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]];
103check(
'Region/First',
$lookup->get_tz(2, 2),
'Existing single-named-candidate shortcut');
107check(
'Etc/GMT',
$lookup->get_tz(2, 2),
'Ocean fallback');
108check([[1, 2], [3]],
$database->polygonRequests,
'Fetch each candidate only once');
110check(
'Region/Third',
$lookup->get_tz(2, 2),
'Named zone takes precedence over oceans');
112check(
'Region/Third',
$lookup->get_tz(2, 2),
'Primary-key first-match precedence');
113check(
'',
$lookup->get_tz(10, 10),
'No bounding-box candidates');
114check([], iterator_to_array(
$database->get_tz_polygons([])),
'Empty polygon iterator');
116check(
'Etc/GMT',
$decoded[0][
'tzname'],
'Legacy decoded-entity API');
117check(
$hit, array_map(
static fn($p) => array_map(
'intval', $p),
$decoded[0][
'polygon']),
'Existing binary format');
120$pdo =
new PDO(
'sqlite::memory:');
121$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
122$wrapper = (
new ReflectionClass(LGV_TZ_Lookup_PDO::class))->newInstanceWithoutConstructor();
127$pdo->beginTransaction();
128check([[
'value' => 1]],
$wrapper->preparedStatement(
'SELECT 1 AS value', [],
true),
'Read API');
129check(
true,
$pdo->inTransaction(),
'Read leaves a caller transaction open');
131foreach (
$rows as $row) {
break; }
133check([[
'value' => 3]],
$wrapper->preparedStatement(
'SELECT 3 AS value', [],
true),
'Query after early return');
135check(
true,
$wrapper->preparedStatement(
'CREATE TABLE write_test (value INTEGER)'),
'Write API return value');
136$wrapper->preparedStatement(
'INSERT INTO write_test VALUES (?)', [7]);
137check([[
'value' => 7]],
$wrapper->preparedStatement(
'SELECT value FROM write_test', [],
true),
'Write commits successfully');
139 iterator_to_array(
$wrapper->preparedRows(
'SELECT * FROM missing_table'));
140 throw new RuntimeException(
'Expected a database exception.');
141}
catch (Exception
$error) {
142 check(
true,
$error->getPrevious() instanceof PDOException,
'Preserve database exception context');
147 if (!preg_match(
'/^lgv_tz_benchmark_[a-zA-Z0-9_]+$/D',
$options[
'mysql'])) {
148 throw new InvalidArgumentException(
'Use an isolated lgv_tz_benchmark_NAME database.');
151 getenv(
'LGV_TZ_BENCH_PASSWORD') ?:
'',
'mysql', getenv(
'LGV_TZ_BENCH_HOST') ?:
'localhost',
152 (
int)(getenv(
'LGV_TZ_BENCH_PORT') ?: 3306));
154 $attribute = class_exists(
'Pdo\\Mysql') ? \Pdo\Mysql::ATTR_USE_BUFFERED_QUERY : PDO::MYSQL_ATTR_USE_BUFFERED_QUERY;
155 $originalBuffering = $mysqlConnection->getAttribute($attribute);
156 $rows = $mysqlWrapper->preparedRows(
'SELECT 1 AS value UNION ALL SELECT 2', [],
false);
158 check(
false, $mysqlConnection->getAttribute($attribute),
'Unbuffered MySQL reader');
160 check($originalBuffering, $mysqlConnection->getAttribute($attribute),
'Restore buffering after early return');
161 check(3, (
int)$mysqlWrapper->preparedStatement(
'SELECT 3 AS value', [],
true)[0][
'value'],
'MySQL query after early return');
163 iterator_to_array($mysqlWrapper->preparedRows(
'SELECT * FROM lgv_tz_nonexistent_table', [],
false));
164 throw new RuntimeException(
'Expected a MySQL exception.');
165 }
catch (Exception
$error) {
166 check(
true,
$error->getPrevious() instanceof PDOException,
'MySQL exception context');
168 check($originalBuffering, $mysqlConnection->getAttribute($attribute),
'Restore buffering after database exception');
169 $mysqlConnection->beginTransaction();
170 $mysqlWrapper->preparedStatement(
'SELECT 1', [],
true);
171 check(
true, $mysqlConnection->inTransaction(),
'MySQL read leaves caller transaction open');
172 $mysqlConnection->rollBack();
173 check(
true, $mysqlWrapper->preparedStatement(
'CREATE TEMPORARY TABLE lgv_tz_write_test (value INTEGER)'),
'MySQL write API');
174 $mysqlWrapper->preparedStatement(
'INSERT INTO lgv_tz_write_test VALUES (?)', [7]);
175 check(7, (
int)$mysqlWrapper->preparedStatement(
'SELECT value FROM lgv_tz_write_test', [],
true)[0][
'value'],
'MySQL write commits successfully');
foreach([[1, 'America/New_York', [0, 0, 4, 0, 4, 1, 0, 1, 0, 0]], [2, 'America/Chicago', [0, 0, 4, 0, 4, 4, 0, 4, 0, 0]], [3, 'Etc/GMT', [0, 0, 4, 0, 4, 4, 0, 4, 0, 0]],] as[$id, $zone, $points]) $wrapper