mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-27 21:19:56 +00:00
fix: retire legacy map tile fallback
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "MapScreen.h"
|
||||
#include "MapTileLookupPolicy.h"
|
||||
#include "MapTileStreamReader.h"
|
||||
|
||||
#ifdef ARDUINO
|
||||
@@ -26,8 +25,6 @@ namespace LXMF {
|
||||
namespace {
|
||||
|
||||
constexpr std::size_t TILE_PIXEL_COUNT = 256U * 256U;
|
||||
constexpr std::uint32_t STORE_BYTE_QUOTA = 64U * 1024U * 1024U;
|
||||
constexpr std::uint16_t STORE_ENTRY_CAPACITY = 128U;
|
||||
|
||||
class PackReadStream final : public Pyxis::MapTileReadStream {
|
||||
public:
|
||||
@@ -61,35 +58,6 @@ private:
|
||||
Hardware::TDeck::MapTilePack& pack_;
|
||||
};
|
||||
|
||||
class LiveReadStream final : public Pyxis::MapTileReadStream {
|
||||
public:
|
||||
explicit LiveReadStream(Hardware::TDeck::MapTileStore& store) : store_(store) {}
|
||||
Pyxis::MapTileStreamResult begin(const Hardware::TDeck::TileKey& key,
|
||||
std::uint32_t& size) override {
|
||||
const Hardware::TDeck::TileStoreResult result = store_.beginGet(key, size);
|
||||
if (result == Hardware::TDeck::TileStoreResult::OK) return Pyxis::MapTileStreamResult::OK;
|
||||
if (result == Hardware::TDeck::TileStoreResult::MISS) return Pyxis::MapTileStreamResult::MISS;
|
||||
if (result == Hardware::TDeck::TileStoreResult::STORAGE_UNAVAILABLE ||
|
||||
result == Hardware::TDeck::TileStoreResult::NOT_INITIALIZED) {
|
||||
return Pyxis::MapTileStreamResult::STORAGE_UNAVAILABLE;
|
||||
}
|
||||
return Pyxis::MapTileStreamResult::IO_ERROR;
|
||||
}
|
||||
Pyxis::MapTileStreamResult read(std::uint8_t* output, std::size_t capacity,
|
||||
std::size_t& count) override {
|
||||
const Hardware::TDeck::TileStoreResult result =
|
||||
store_.readGetChunk(output, capacity, count);
|
||||
if (result == Hardware::TDeck::TileStoreResult::OK) return Pyxis::MapTileStreamResult::OK;
|
||||
if (result == Hardware::TDeck::TileStoreResult::STORAGE_UNAVAILABLE) {
|
||||
return Pyxis::MapTileStreamResult::STORAGE_UNAVAILABLE;
|
||||
}
|
||||
return Pyxis::MapTileStreamResult::IO_ERROR;
|
||||
}
|
||||
void end() override { store_.endGet(); }
|
||||
private:
|
||||
Hardware::TDeck::MapTileStore& store_;
|
||||
};
|
||||
|
||||
class AtomicStopSource final : public Pyxis::MapTileStopSource {
|
||||
public:
|
||||
explicit AtomicStopSource(const std::atomic<bool>& stop) : stop_(stop) {}
|
||||
@@ -117,10 +85,6 @@ lv_obj_t* createToolbarButton(lv_obj_t* parent, const char* text,
|
||||
|
||||
} // namespace
|
||||
|
||||
using Hardware::TDeck::MapTileStore;
|
||||
|
||||
static_assert(MapTileStore::HARD_MAX_ENTRIES == 128,
|
||||
"map cache index contract changed; revisit bounded RAM budget");
|
||||
static_assert(sizeof(lv_color_t) == 2U,
|
||||
"offline tile buffers assume LVGL RGB565 true color");
|
||||
|
||||
@@ -131,14 +95,11 @@ MapScreen::MapScreen(lv_obj_t* parent)
|
||||
recenter_button_(nullptr), pan_buttons_{}, tile_images_{},
|
||||
tile_descriptors_{}, tile_pixels_{}, decoded_tile_cache_(TILE_PIXEL_COUNT),
|
||||
decoded_cache_pixels_{}, approximation_halos_{}, markers_{}, marker_labels_{},
|
||||
presenter_(), storage_(),
|
||||
store_config_{STORE_ENTRY_CAPACITY, STORE_BYTE_QUOTA,
|
||||
MAX_COMPRESSED_TILE_BYTES},
|
||||
store_(storage_, store_config_), pack_(storage_), pack_attribution_{},
|
||||
presenter_(), storage_(), pack_(storage_), pack_attribution_{},
|
||||
screen_visible_(false), pack_refresh_epoch_(0U),
|
||||
compressed_staging_(nullptr),
|
||||
state_mutex_(nullptr), worker_task_(nullptr),
|
||||
worker_exited_(true), worker_started_(false), store_initialized_(false),
|
||||
worker_exited_(true), worker_started_(false),
|
||||
requests_released_(false),
|
||||
has_location_fix_(false), center_initialized_(false), current_location_{}, dragging_(false),
|
||||
last_drag_point_{0, 0}, back_callback_() {
|
||||
@@ -372,8 +333,6 @@ void MapScreen::publishPackAttribution() {
|
||||
}
|
||||
|
||||
void MapScreen::workerLoop() {
|
||||
Hardware::TDeck::TileStoreResult initialized = store_.initialize();
|
||||
store_initialized_ = initialized == Hardware::TDeck::TileStoreResult::OK;
|
||||
std::uint32_t handled_pack_refresh_epoch =
|
||||
pack_refresh_epoch_.load(std::memory_order_acquire);
|
||||
(void)pack_.initialize();
|
||||
@@ -446,37 +405,16 @@ Pyxis::MapTileLoadResult MapScreen::readTile(
|
||||
return Pyxis::MapTileLoadResult::READY;
|
||||
}
|
||||
|
||||
struct LocalReadContext {
|
||||
MapScreen* screen;
|
||||
const Pyxis::MapTileRequest* request;
|
||||
} context = {this, &request};
|
||||
return Pyxis::MapTileLookupPolicy::readLocal(
|
||||
&context,
|
||||
[](void* opaque, Pyxis::MapTileLookupPolicy::LocalSource source) ->
|
||||
Pyxis::MapTileLoadResult {
|
||||
LocalReadContext* local = static_cast<LocalReadContext*>(opaque);
|
||||
const CompressedTileSource mapped =
|
||||
source == Pyxis::MapTileLookupPolicy::LocalSource::PACK
|
||||
? CompressedTileSource::PACK
|
||||
: CompressedTileSource::LIVE_STORE;
|
||||
return local->screen->readCompressedTile(*local->request, mapped);
|
||||
});
|
||||
return readCompressedTile(request);
|
||||
}
|
||||
|
||||
Pyxis::MapTileLoadResult MapScreen::readCompressedTile(
|
||||
const Pyxis::MapTileRequest& request, CompressedTileSource source) {
|
||||
if (source == CompressedTileSource::LIVE_STORE && !store_initialized_) {
|
||||
return Pyxis::MapTileLoadResult::STORAGE_UNAVAILABLE;
|
||||
}
|
||||
const Pyxis::MapTileRequest& request) {
|
||||
PackReadStream pack_stream(pack_);
|
||||
LiveReadStream live_stream(store_);
|
||||
Pyxis::MapTileReadStream& stream = source == CompressedTileSource::PACK
|
||||
? static_cast<Pyxis::MapTileReadStream&>(pack_stream)
|
||||
: static_cast<Pyxis::MapTileReadStream&>(live_stream);
|
||||
AtomicStopSource stop(stop_requested_);
|
||||
std::size_t total = 0U;
|
||||
const Pyxis::MapTileStreamResult read = Pyxis::MapTileStreamReader::readExact(
|
||||
stream, stop, request.key, compressed_staging_, MAX_COMPRESSED_TILE_BYTES,
|
||||
pack_stream, stop, request.key, compressed_staging_, MAX_COMPRESSED_TILE_BYTES,
|
||||
READ_CHUNK_BYTES, total);
|
||||
if (read == Pyxis::MapTileStreamResult::MISS) {
|
||||
return Pyxis::MapTileLoadResult::MISS;
|
||||
@@ -503,14 +441,6 @@ Pyxis::MapTileLoadResult MapScreen::readCompressedTile(
|
||||
&width, &height, &decode_state, compressed_staging_, total);
|
||||
if (decode_error != 0U || width != 256U || height != 256U) {
|
||||
lodepng_state_cleanup(&decode_state);
|
||||
if (source == CompressedTileSource::LIVE_STORE) {
|
||||
const Hardware::TDeck::TileStoreResult removed =
|
||||
store_.removeTile(request.key);
|
||||
return (removed == Hardware::TDeck::TileStoreResult::OK ||
|
||||
removed == Hardware::TDeck::TileStoreResult::MISS)
|
||||
? Pyxis::MapTileLoadResult::INVALID_PNG
|
||||
: Pyxis::MapTileLoadResult::IO_ERROR;
|
||||
}
|
||||
return Pyxis::MapTileLoadResult::INVALID_PNG;
|
||||
}
|
||||
decode_state.info_raw.colortype = LCT_RGB;
|
||||
@@ -520,14 +450,6 @@ Pyxis::MapTileLoadResult MapScreen::readCompressedTile(
|
||||
lodepng_state_cleanup(&decode_state);
|
||||
if (decode_error != 0U || rgb == nullptr || width != 256U || height != 256U) {
|
||||
if (rgb) lv_mem_free(rgb);
|
||||
if (source == CompressedTileSource::LIVE_STORE) {
|
||||
const Hardware::TDeck::TileStoreResult removed =
|
||||
store_.removeTile(request.key);
|
||||
return (removed == Hardware::TDeck::TileStoreResult::OK ||
|
||||
removed == Hardware::TDeck::TileStoreResult::MISS)
|
||||
? Pyxis::MapTileLoadResult::INVALID_PNG
|
||||
: Pyxis::MapTileLoadResult::IO_ERROR;
|
||||
}
|
||||
return Pyxis::MapTileLoadResult::INVALID_PNG;
|
||||
}
|
||||
if (request.slot_index >= TILE_COUNT || !tile_pixels_[request.slot_index]) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include "Hardware/TDeck/MapTileStore.h"
|
||||
#include "Hardware/TDeck/MapTileStoreSD.h"
|
||||
#include "Hardware/TDeck/MapTilePack.h"
|
||||
|
||||
@@ -77,8 +76,6 @@ private:
|
||||
|
||||
Pyxis::MapScreenPresenter presenter_;
|
||||
Hardware::TDeck::MapTileStoreSD storage_;
|
||||
Hardware::TDeck::TileStoreConfig store_config_;
|
||||
Hardware::TDeck::MapTileStore store_;
|
||||
Hardware::TDeck::MapTilePack pack_;
|
||||
char pack_attribution_[Pyxis::MapPackManifest::ATTRIBUTION_CAPACITY];
|
||||
std::atomic<bool> screen_visible_;
|
||||
@@ -89,7 +86,6 @@ private:
|
||||
std::atomic<bool> stop_requested_;
|
||||
std::atomic<bool> worker_exited_;
|
||||
bool worker_started_;
|
||||
bool store_initialized_;
|
||||
bool requests_released_;
|
||||
bool has_location_fix_;
|
||||
bool center_initialized_;
|
||||
@@ -99,16 +95,11 @@ private:
|
||||
BackCallback back_callback_;
|
||||
|
||||
static void workerEntry(void* context);
|
||||
enum class CompressedTileSource : std::uint8_t {
|
||||
PACK = 0,
|
||||
LIVE_STORE
|
||||
};
|
||||
void workerLoop();
|
||||
void publishPackAttribution();
|
||||
Pyxis::MapTileLoadResult loadTile(const Pyxis::MapTileRequest& request);
|
||||
Pyxis::MapTileLoadResult readTile(const Pyxis::MapTileRequest& request);
|
||||
Pyxis::MapTileLoadResult readCompressedTile(
|
||||
const Pyxis::MapTileRequest& request, CompressedTileSource source);
|
||||
Pyxis::MapTileLoadResult readCompressedTile(const Pyxis::MapTileRequest& request);
|
||||
bool startWorker();
|
||||
void stopWorker();
|
||||
bool lockState(TickType_t ticks = portMAX_DELAY);
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright (c) 2026 Pyxis contributors
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef UI_LXMF_MAP_TILE_LOOKUP_POLICY_H
|
||||
#define UI_LXMF_MAP_TILE_LOOKUP_POLICY_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "MapScreenPresenter.h"
|
||||
|
||||
namespace Pyxis {
|
||||
|
||||
/** Portable policy for pack -> live cache -> optional network orchestration. */
|
||||
class MapTileLookupPolicy {
|
||||
public:
|
||||
enum class LocalSource : std::uint8_t { PACK = 0, LIVE_STORE };
|
||||
typedef MapTileLoadResult (*ReadLocalSource)(void*, LocalSource);
|
||||
|
||||
static MapTileLoadResult readLocal(void* context, ReadLocalSource read) {
|
||||
if (read == NULL) return MapTileLoadResult::IO_ERROR;
|
||||
const MapTileLoadResult pack = read(context, LocalSource::PACK);
|
||||
if (pack == MapTileLoadResult::READY) return pack;
|
||||
const MapTileLoadResult live = read(context, LocalSource::LIVE_STORE);
|
||||
return resolveLocal(pack, live);
|
||||
}
|
||||
|
||||
static MapTileLoadResult resolveLocal(MapTileLoadResult pack,
|
||||
MapTileLoadResult live) {
|
||||
if (pack == MapTileLoadResult::READY) return pack;
|
||||
if (live != MapTileLoadResult::MISS) return live;
|
||||
if (pack == MapTileLoadResult::IO_ERROR ||
|
||||
pack == MapTileLoadResult::STORAGE_UNAVAILABLE) return pack;
|
||||
return MapTileLoadResult::MISS;
|
||||
}
|
||||
|
||||
static bool shouldStartOnline(MapTileLoadResult local,
|
||||
bool enabled,
|
||||
bool visible,
|
||||
bool decode_failed,
|
||||
std::uint32_t request_epoch,
|
||||
std::uint32_t current_epoch) {
|
||||
return enabled && visible && !decode_failed &&
|
||||
request_epoch == current_epoch &&
|
||||
(local == MapTileLoadResult::MISS ||
|
||||
local == MapTileLoadResult::INVALID_PNG);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Pyxis
|
||||
|
||||
#endif
|
||||
@@ -41,7 +41,9 @@ def test_fixed_pool_and_cache_contracts():
|
||||
assert re.search(r"#define\s+LV_IMG_CACHE_DEF_SIZE\s+0\b", lv_conf)
|
||||
assert "std::vector" not in presenter + screen_h + screen_cpp
|
||||
assert "std::map" not in presenter + screen_h + screen_cpp
|
||||
assert "static_assert(MapTileStore::HARD_MAX_ENTRIES == 128" in screen_cpp
|
||||
assert '#include "Hardware/TDeck/MapTileStore.h"' not in screen_h
|
||||
assert "Hardware::TDeck::MapTileStore store_;" not in screen_h
|
||||
assert "TileStoreConfig" not in screen_h + screen_cpp
|
||||
assert "pack_.metadata().attribution" in screen_cpp
|
||||
assert '"No active map pack"' in screen_cpp
|
||||
assert "presenter_.visibleTileStatus" in screen_cpp
|
||||
@@ -59,7 +61,7 @@ def test_worker_predecodes_and_render_path_has_no_io():
|
||||
assert "lodepng_decode(" in source
|
||||
assert "lodepng_inspect" in source
|
||||
assert "max_output_size" in source
|
||||
assert "store_.removeTile(request.key)" in source
|
||||
assert "store_.removeTile(request.key)" not in source
|
||||
assert "decode_failed_keys_" not in header
|
||||
assert "decodeFailedFor" not in source
|
||||
assert "markDecodeFailed" not in source
|
||||
@@ -75,7 +77,7 @@ def test_worker_predecodes_and_render_path_has_no_io():
|
||||
assert "MAX_COMPLETIONS_PER_TICK = 1" in text(UI / "MapScreen.h")
|
||||
|
||||
|
||||
def test_selected_pack_is_worker_owned_read_only_and_precedes_live_cache():
|
||||
def test_selected_pack_is_the_only_sd_tile_source():
|
||||
source = text(UI / "MapScreen.cpp")
|
||||
header = text(UI / "MapScreen.h")
|
||||
assert '#include "Hardware/TDeck/MapTilePack.h"' in header
|
||||
@@ -85,51 +87,39 @@ def test_selected_pack_is_worker_owned_read_only_and_precedes_live_cache():
|
||||
assert "pack_(storage_)" in constructor
|
||||
|
||||
worker = function_body(source, "void MapScreen::workerLoop()")
|
||||
assert worker.index("store_.initialize()") < worker.index("pack_.initialize()")
|
||||
assert "pack_.initialize()" in worker
|
||||
assert "store_.initialize()" not in worker
|
||||
|
||||
read_tile = function_body(source, "Pyxis::MapTileLoadResult MapScreen::readTile(")
|
||||
assert read_tile.index("decoded_tile_cache_.get") < read_tile.index("PACK")
|
||||
assert read_tile.index("PACK") < read_tile.index("LIVE_STORE")
|
||||
assert (read_tile.index("decoded_tile_cache_.get") <
|
||||
read_tile.index("readCompressedTile(request)"))
|
||||
assert "LIVE_STORE" not in read_tile
|
||||
|
||||
pack_read = function_body(
|
||||
source, "Pyxis::MapTileLoadResult MapScreen::readCompressedTile(")
|
||||
assert ("source == CompressedTileSource::LIVE_STORE && !store_initialized_"
|
||||
in pack_read)
|
||||
assert "MapTileStreamReader::readExact" in pack_read
|
||||
assert "PackReadStream pack_stream(pack_)" in pack_read
|
||||
assert "LiveReadStream live_stream(store_)" in pack_read
|
||||
assert "LiveReadStream" not in source
|
||||
pack_adapter = source[source.index("class PackReadStream"):
|
||||
source.index("class LiveReadStream")]
|
||||
live_adapter = source[source.index("class LiveReadStream"):
|
||||
source.index("class AtomicStopSource")]
|
||||
assert "pack_.beginGet" in pack_adapter
|
||||
assert "pack_.readGetChunk" in pack_adapter
|
||||
assert "pack_.endGet" in pack_adapter
|
||||
assert "remove" not in pack_adapter
|
||||
assert "store_.beginGet" in live_adapter
|
||||
assert "store_.readGetChunk" in live_adapter
|
||||
assert "store_.endGet" in live_adapter
|
||||
remove_token = "store_.removeTile(request.key)"
|
||||
remove_offsets = []
|
||||
cursor = 0
|
||||
while True:
|
||||
offset = pack_read.find(remove_token, cursor)
|
||||
if offset < 0:
|
||||
break
|
||||
remove_offsets.append(offset)
|
||||
cursor = offset + len(remove_token)
|
||||
assert len(remove_offsets) == 2
|
||||
for offset in remove_offsets:
|
||||
remove_block = pack_read[max(0, offset - 220):offset + 80]
|
||||
assert "source == CompressedTileSource::LIVE_STORE" in remove_block
|
||||
assert '#include "Hardware/TDeck/MapTileStore.h"' not in header
|
||||
assert "Hardware::TDeck::MapTileStore store_;" not in header
|
||||
assert "MapTileLookupPolicy" not in source + header
|
||||
assert not (UI / "MapTileLookupPolicy.h").exists()
|
||||
assert not (UI / "MapTileLookupPolicy.cpp").exists()
|
||||
assert "store_initialized_" not in source + header
|
||||
assert "store_config_" not in source + header
|
||||
assert "LIVE_STORE" not in source + header
|
||||
assert "/pyxis-map/tiles" not in source + header
|
||||
|
||||
# Covered-missing, uncovered, and corrupt immutable-pack tiles all continue
|
||||
# to the mutable legacy cache, but production never starts online acquisition.
|
||||
# Covered-missing, uncovered, and corrupt immutable-pack tiles remain typed
|
||||
# pack results. Production never falls through to an untyped style-less cache.
|
||||
assert "MapTilePackResult::UNCOVERED" in pack_adapter
|
||||
assert "MapTilePackResult::TILE_MISSING" in pack_adapter
|
||||
assert "MapTileLookupPolicy::readLocal" in read_tile
|
||||
assert "static MapTileLoadResult resolveLocal" in text(UI / "MapTileLookupPolicy.h")
|
||||
assert "MapTileLookupPolicy::shouldStartOnline" not in source
|
||||
load_tile = function_body(source, "Pyxis::MapTileLoadResult MapScreen::loadTile(")
|
||||
assert "return readTile(request);" in load_tile
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ def test_dormant_downloader_chain_remains_verified_but_is_not_map_screen_wired()
|
||||
for value in fingerprints)
|
||||
|
||||
|
||||
def test_production_map_screen_is_strictly_sd_pack_first_without_network_acquisition():
|
||||
def test_production_map_screen_uses_only_sd_packs_without_network_acquisition():
|
||||
screen = MAP_SCREEN.read_text()
|
||||
header = (ROOT / "lib/tdeck_ui/UI/LXMF/MapScreen.h").read_text()
|
||||
settings = SETTINGS.read_text()
|
||||
@@ -92,7 +92,10 @@ def test_production_map_screen_is_strictly_sd_pack_first_without_network_acquisi
|
||||
assert forbidden not in screen
|
||||
assert forbidden not in header
|
||||
assert "return readTile(request);" in screen
|
||||
assert "MapTileLookupPolicy::readLocal" in screen
|
||||
assert "MapTileLookupPolicy" not in screen + header
|
||||
assert "LiveReadStream" not in screen
|
||||
assert "LIVE_STORE" not in screen + header
|
||||
assert "store_.initialize()" not in screen
|
||||
assert "MapTilePack pack_" in header
|
||||
assert "pack_.initialize()" in screen
|
||||
assert "pack_refresh_epoch_.fetch_add" in screen
|
||||
@@ -126,7 +129,8 @@ def test_recent_decoded_tiles_use_a_fixed_psram_lru_before_sd_decode():
|
||||
assert "decoded_tile_cache_.get" in screen
|
||||
read_tile = screen[screen.index("Pyxis::MapTileLoadResult MapScreen::readTile("):
|
||||
screen.index("Pyxis::MapTileLoadResult MapScreen::readCompressedTile(")]
|
||||
assert read_tile.index("decoded_tile_cache_.get") < read_tile.index("MapTileLookupPolicy::readLocal")
|
||||
assert (read_tile.index("decoded_tile_cache_.get") <
|
||||
read_tile.index("readCompressedTile(request)"))
|
||||
assert "decoded_tile_cache_.put" in screen
|
||||
assert "MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT" in screen
|
||||
assert "decoded_cache_pixels_[Pyxis::DecodedTileCache::CAPACITY]" in header
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
#include "UI/LXMF/MapTileLookupPolicy.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
using Pyxis::MapTileLoadResult;
|
||||
using Pyxis::MapTileLookupPolicy;
|
||||
|
||||
namespace {
|
||||
std::size_t tests_run = 0U;
|
||||
void fail(const char* expression, int line) {
|
||||
std::cerr << "line " << line << ": " << expression << '\n';
|
||||
std::exit(1);
|
||||
}
|
||||
#define CHECK(expression) do { if (!(expression)) fail(#expression, __LINE__); } while (false)
|
||||
void beginTest() { ++tests_run; }
|
||||
|
||||
void testLocalPrecedenceTable() {
|
||||
beginTest();
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(MapTileLoadResult::READY,
|
||||
MapTileLoadResult::IO_ERROR) ==
|
||||
MapTileLoadResult::READY);
|
||||
const MapTileLoadResult fallthrough[] = {
|
||||
MapTileLoadResult::MISS, MapTileLoadResult::INVALID_PNG,
|
||||
MapTileLoadResult::TOO_LARGE
|
||||
};
|
||||
for (std::size_t index = 0U; index < sizeof(fallthrough) / sizeof(fallthrough[0]); ++index) {
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(fallthrough[index],
|
||||
MapTileLoadResult::READY) ==
|
||||
MapTileLoadResult::READY);
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(fallthrough[index],
|
||||
MapTileLoadResult::MISS) ==
|
||||
MapTileLoadResult::MISS);
|
||||
}
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(MapTileLoadResult::IO_ERROR,
|
||||
MapTileLoadResult::MISS) ==
|
||||
MapTileLoadResult::IO_ERROR);
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(MapTileLoadResult::STORAGE_UNAVAILABLE,
|
||||
MapTileLoadResult::MISS) ==
|
||||
MapTileLoadResult::STORAGE_UNAVAILABLE);
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(MapTileLoadResult::IO_ERROR,
|
||||
MapTileLoadResult::READY) ==
|
||||
MapTileLoadResult::READY);
|
||||
CHECK(MapTileLookupPolicy::resolveLocal(MapTileLoadResult::MISS,
|
||||
MapTileLoadResult::INVALID_PNG) ==
|
||||
MapTileLoadResult::INVALID_PNG);
|
||||
}
|
||||
|
||||
void testOnlineGate() {
|
||||
beginTest();
|
||||
CHECK(MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::MISS,
|
||||
true, true, false, 7U, 7U));
|
||||
CHECK(MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::INVALID_PNG,
|
||||
true, true, false, 7U, 7U));
|
||||
CHECK(!MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::READY,
|
||||
true, true, false, 7U, 7U));
|
||||
CHECK(!MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::MISS,
|
||||
false, true, false, 7U, 7U));
|
||||
CHECK(!MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::MISS,
|
||||
true, false, false, 7U, 7U));
|
||||
CHECK(!MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::MISS,
|
||||
true, true, true, 7U, 7U));
|
||||
CHECK(!MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::MISS,
|
||||
true, true, false, 7U, 8U));
|
||||
CHECK(!MapTileLookupPolicy::shouldStartOnline(MapTileLoadResult::IO_ERROR,
|
||||
true, true, false, 7U, 7U));
|
||||
}
|
||||
|
||||
struct FakeLocalSources {
|
||||
MapTileLoadResult pack;
|
||||
MapTileLoadResult live;
|
||||
int calls[2];
|
||||
std::size_t count;
|
||||
};
|
||||
|
||||
MapTileLoadResult readFake(void* opaque, MapTileLookupPolicy::LocalSource source) {
|
||||
FakeLocalSources* fake = static_cast<FakeLocalSources*>(opaque);
|
||||
fake->calls[fake->count++] = source == MapTileLookupPolicy::LocalSource::PACK ? 0 : 1;
|
||||
return source == MapTileLookupPolicy::LocalSource::PACK ? fake->pack : fake->live;
|
||||
}
|
||||
|
||||
void testExecutableSourceOrderAndFallback() {
|
||||
beginTest();
|
||||
FakeLocalSources ready = {MapTileLoadResult::READY, MapTileLoadResult::IO_ERROR, {0, 0}, 0U};
|
||||
CHECK(MapTileLookupPolicy::readLocal(&ready, readFake) == MapTileLoadResult::READY);
|
||||
CHECK(ready.count == 1U && ready.calls[0] == 0);
|
||||
const MapTileLoadResult fallthrough[] = {
|
||||
MapTileLoadResult::MISS, MapTileLoadResult::INVALID_PNG,
|
||||
MapTileLoadResult::TOO_LARGE, MapTileLoadResult::IO_ERROR
|
||||
};
|
||||
for (std::size_t index = 0U; index < sizeof(fallthrough) / sizeof(fallthrough[0]); ++index) {
|
||||
FakeLocalSources fake = {fallthrough[index], MapTileLoadResult::READY, {0, 0}, 0U};
|
||||
CHECK(MapTileLookupPolicy::readLocal(&fake, readFake) == MapTileLoadResult::READY);
|
||||
CHECK(fake.count == 2U && fake.calls[0] == 0 && fake.calls[1] == 1);
|
||||
}
|
||||
CHECK(MapTileLookupPolicy::readLocal(NULL, NULL) == MapTileLoadResult::IO_ERROR);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
testLocalPrecedenceTable();
|
||||
testOnlineGate();
|
||||
testExecutableSourceOrderAndFallback();
|
||||
std::cout << "map tile lookup policy: " << tests_run << " tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from native_test import find_cxx
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SOURCE = ROOT / "tests/native/test_map_tile_lookup_policy.cpp"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sanitize", [False, True], ids=["strict-cxx11", "asan-ubsan"])
|
||||
def test_map_tile_lookup_policy(tmp_path: Path, sanitize: bool) -> None:
|
||||
binary = tmp_path / "test_map_tile_lookup_policy"
|
||||
command = [
|
||||
find_cxx(), "-std=c++11", "-Wall", "-Wextra", "-Werror", "-pedantic",
|
||||
"-Wconversion", "-Wsign-conversion", f"-I{ROOT / 'lib/tdeck_ui'}",
|
||||
str(SOURCE), "-o", str(binary),
|
||||
]
|
||||
if sanitize:
|
||||
command[1:1] = ["-fsanitize=address,undefined", "-fno-omit-frame-pointer"]
|
||||
compiled = subprocess.run(command, capture_output=True, text=True, timeout=60)
|
||||
assert compiled.returncode == 0, compiled.stdout + compiled.stderr
|
||||
env = os.environ.copy()
|
||||
if sanitize:
|
||||
env["ASAN_OPTIONS"] = "detect_leaks=1:halt_on_error=1"
|
||||
env["UBSAN_OPTIONS"] = "halt_on_error=1:print_stacktrace=1"
|
||||
ran = subprocess.run([str(binary)], capture_output=True, text=True, timeout=60, env=env)
|
||||
assert ran.returncode == 0, ran.stdout + ran.stderr
|
||||
assert ran.stdout == "map tile lookup policy: 3 tests passed\n"
|
||||
Reference in New Issue
Block a user