Add indexed eight-profile catalog

This commit is contained in:
Joey Yakimowich-Payne 2026-09-04 17:50:09 -06:00
commit 541ca49201
18 changed files with 2033 additions and 1970 deletions

View file

@ -1,8 +1,9 @@
#include "core/controller_identity.h"
#include "profile/controller_profile.h"
#include "platform/pico/pico_profile_storage.h"
#include "profile/controller_profile.h"
#include "profile/profile_service.h"
#include "profile/profile_storage.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
@ -10,428 +11,216 @@
namespace {
struct FakeFlash {
uint8_t bytes[PROFILE_STORAGE_BANK_COUNT][PROFILE_STORAGE_BANK_SIZE];
int bank_replacements = 0;
uint8_t bytes[PROFILE_STORAGE_ARENA_COUNT][PROFILE_STORAGE_ARENA_SIZE];
};
FakeFlash flash{};
void require(bool condition, const char* message) {
if (!condition) {
std::cerr << message << '\n';
std::exit(1);
}
void require(bool condition, const char *message) {
if (!condition) {
std::cerr << message << '\n';
std::exit(1);
}
}
bool fake_read(void* context, uint8_t bank, size_t offset,
uint8_t* output, size_t size) {
auto* storage = static_cast<FakeFlash*>(context);
if (bank >= PROFILE_STORAGE_BANK_COUNT || output == nullptr ||
offset > PROFILE_STORAGE_BANK_SIZE ||
size > PROFILE_STORAGE_BANK_SIZE - offset) {
return false;
}
memcpy(output, &storage->bytes[bank][offset], size);
return true;
bool fake_read(void *context, uint8_t arena, size_t offset, uint8_t *output,
size_t size) {
auto *storage = static_cast<FakeFlash *>(context);
if (arena >= PROFILE_STORAGE_ARENA_COUNT || output == nullptr ||
offset > PROFILE_STORAGE_ARENA_SIZE ||
size > PROFILE_STORAGE_ARENA_SIZE - offset) {
return false;
}
memcpy(output, &storage->bytes[arena][offset], size);
return true;
}
bool fake_replace_bank(void* context, uint8_t bank,
const uint8_t* payload, size_t payload_size,
const uint8_t* header, size_t header_size) {
auto* storage = static_cast<FakeFlash*>(context);
if (bank >= PROFILE_STORAGE_BANK_COUNT || payload == nullptr ||
header == nullptr ||
payload_size != CONTROLLER_PROFILE_DATABASE_ENCODED_SIZE ||
header_size != PROFILE_STORAGE_RECORD_HEADER_SIZE) {
return false;
}
++storage->bank_replacements;
memset(storage->bytes[bank], 0xff, PROFILE_STORAGE_BANK_SIZE);
memcpy(
&storage->bytes[bank][PROFILE_STORAGE_RECORD_HEADER_SIZE],
payload, payload_size);
memcpy(storage->bytes[bank], header, header_size);
return memcmp(
&storage->bytes[bank][
PROFILE_STORAGE_RECORD_HEADER_SIZE],
payload, payload_size) == 0 &&
memcmp(storage->bytes[bank], header, header_size) == 0;
bool fake_erase(void *context, uint8_t arena) {
auto *storage = static_cast<FakeFlash *>(context);
if (arena >= PROFILE_STORAGE_ARENA_COUNT) {
return false;
}
memset(storage->bytes[arena], 0xff, PROFILE_STORAGE_ARENA_SIZE);
return true;
}
bool fake_program(void *context, uint8_t arena, size_t offset,
const uint8_t *page, size_t size) {
auto *storage = static_cast<FakeFlash *>(context);
if (arena >= PROFILE_STORAGE_ARENA_COUNT || page == nullptr ||
size != PROFILE_STORAGE_PAGE_SIZE ||
offset % PROFILE_STORAGE_PAGE_SIZE != 0 ||
offset + size > PROFILE_STORAGE_ARENA_SIZE) {
return false;
}
for (size_t index = 0; index < size; ++index) {
storage->bytes[arena][offset + index] &= page[index];
}
return memcmp(&storage->bytes[arena][offset], page, size) == 0;
}
ProfileStorageIo fake_io() {
return {
&flash,
PROFILE_STORAGE_BANK_SIZE,
PROFILE_STORAGE_SECTOR_SIZE,
PROFILE_STORAGE_PAGE_SIZE,
fake_read,
fake_replace_bank,
};
return {
&flash,
PROFILE_STORAGE_ARENA_SIZE,
PROFILE_STORAGE_SECTOR_SIZE,
PROFILE_STORAGE_PAGE_SIZE,
fake_read,
fake_erase,
fake_program,
};
}
ControllerIdentity stable_identity() {
ControllerIdentity identity{};
identity.stable = true;
identity.transport = ControllerTransport::kClassic;
identity.address[5] = 7;
identity.vendor_id = 0x054c;
identity.product_id = 0x0ce6;
return identity;
}
ProfileServiceTransactionSnapshot transaction_snapshot() {
ProfileServiceTransactionSnapshot snapshot{};
profile_service_transaction_snapshot(&snapshot);
return snapshot;
ProfileServiceTransactionSnapshot snapshot{};
profile_service_transaction_snapshot(&snapshot);
return snapshot;
}
ProfileServiceActiveProfileSnapshot active_profile_snapshot(
const ControllerIdentity& identity) {
ProfileServiceActiveProfileSnapshot snapshot{};
profile_service_active_profile_snapshot(identity, &snapshot);
return snapshot;
ProfileServiceActiveProfileSnapshot
active_snapshot(const ControllerIdentity &identity) {
ProfileServiceActiveProfileSnapshot snapshot{};
profile_service_active_profile_snapshot(identity, &snapshot);
return snapshot;
}
ControllerProfileDatabase reload_database(
const ProfileServiceTransactionSnapshot& transaction,
uint32_t expected_generation) {
ControllerProfileDatabase recovered{};
ProfileStorage storage;
require(storage.initialize(fake_io(), &recovered) &&
storage.snapshot().valid &&
storage.snapshot().generation == expected_generation &&
storage.snapshot().generation ==
transaction.transaction.stored_generation &&
storage.snapshot().payload_crc ==
transaction.transaction.stored_crc,
"terminal transaction status did not identify persisted storage");
return recovered;
void write_profile(uint32_t transaction_id, const ControllerIdentity &identity,
uint8_t profile_index, const ControllerProfile &profile,
uint32_t now_ms) {
uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{};
require(controller_profile_encode(profile, encoded, sizeof(encoded)),
"profile did not encode");
require(
profile_service_begin(transaction_id, identity, profile_index,
CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded),
profile_storage_crc32(encoded, sizeof(encoded))) ==
ConfigurationTransactionStatus::kReceiving,
"profile transaction did not begin");
require(profile_service_append(transaction_id, 0, encoded, 117) ==
ConfigurationTransactionStatus::kReceiving &&
profile_service_append(transaction_id, 117, encoded + 117,
sizeof(encoded) - 117) ==
ConfigurationTransactionStatus::kReceiving,
"profile chunks were not accepted");
require(profile_service_commit(transaction_id) ==
ConfigurationTransactionStatus::kPending,
"profile transaction did not become pending");
profile_service_task_on_storage_core(now_ms);
require(transaction_snapshot().transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"profile transaction did not persist");
}
void test_pending_commands_are_not_decoded_as_profile_writes() {
memset(flash.bytes, 0xff, sizeof(flash.bytes));
profile_service_prepare();
profile_service_initialize_on_storage_core();
ProfileServiceActiveProfileSnapshot active =
active_profile_snapshot(controller_identity_global());
require(active.valid &&
active.metadata.state == ProfileServiceState::kReady &&
active.metadata.generation == 0 &&
profile_service_database_generation() == 0 &&
active.profile_index == 0,
"initial active profile snapshot was not coherent");
void test_eight_profile_transactions_and_active_cache() {
memset(flash.bytes, 0xff, sizeof(flash.bytes));
profile_service_prepare();
profile_service_initialize_on_storage_core();
const ControllerIdentity global = controller_identity_global();
ProfileServiceActiveProfileSnapshot active = active_snapshot(global);
require(active.valid && active.profile_index == 0 &&
active.metadata.state == ProfileServiceState::kReady,
"fallback active cache did not initialize");
const ControllerIdentity identity = controller_identity_global();
constexpr uint8_t kProfileIndex = 2;
ControllerProfile customized =
controller_profile_default(identity, kProfileIndex);
customized.strong_rumble_scale = 17;
uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{};
require(controller_profile_encode(customized, encoded, sizeof(encoded)),
"customized profile did not encode");
ControllerProfile eighth = controller_profile_default(global, 7);
eighth.strong_rumble_scale = 37;
write_profile(1, global, 7, eighth, 0);
require(profile_service_select(global, 7) ==
ConfigurationTransactionStatus::kCommitted,
"profile eight was not selectable");
ProfileServiceSelectedSnapshot selected{};
profile_service_selected_snapshot(&selected);
require(selected.valid && selected.profile_index == 7 &&
selected.profile.strong_rumble_scale == 37,
"selected profile eight was not decoded on demand");
constexpr uint32_t kWriteTransactionId = 0x10203040;
require(profile_service_begin(
kWriteTransactionId, identity, kProfileIndex,
CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded),
profile_storage_crc32(encoded, sizeof(encoded))) ==
ConfigurationTransactionStatus::kReceiving &&
profile_service_append(kWriteTransactionId, 0, encoded,
sizeof(encoded)) ==
ConfigurationTransactionStatus::kReceiving &&
profile_service_commit(kWriteTransactionId) ==
ConfigurationTransactionStatus::kPending,
"profile write did not reach pending");
profile_service_task_on_storage_core(0);
require(transaction_snapshot().transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"profile write baseline did not commit");
active = active_profile_snapshot(identity);
require(active.valid && active.metadata.generation == 1 &&
profile_service_database_generation() == 1 &&
active.profile_index == 0,
"profile write did not publish one coherent generation");
require(profile_service_activate(2, global, 7) ==
ConfigurationTransactionStatus::kPending,
"profile eight activation was not queued");
profile_service_task_on_storage_core(1000);
require(transaction_snapshot().transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"profile eight activation did not persist");
active = active_snapshot(global);
require(active.valid && active.profile_index == 7 &&
active.profile.strong_rumble_scale == 37,
"active cache did not publish profile eight");
constexpr uint32_t kReservedInternalTransactionId = 0x80000019u;
require(
profile_service_begin(
kReservedInternalTransactionId, identity, kProfileIndex,
CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded),
profile_storage_crc32(encoded, sizeof(encoded))) ==
ConfigurationTransactionStatus::kMalformed &&
profile_service_reset(kReservedInternalTransactionId, identity,
kProfileIndex) ==
ConfigurationTransactionStatus::kMalformed &&
profile_service_activate(kReservedInternalTransactionId, identity,
kProfileIndex) ==
ConfigurationTransactionStatus::kMalformed,
"host profile mutations admitted the internal transaction namespace");
const ControllerIdentity connected = stable_identity();
require(profile_service_observe_identity_on_storage_core(connected),
"stable identity was not added to the catalog");
ProfileServiceListSnapshot list{};
profile_service_list_snapshot(&list);
require(list.count == 2 &&
controller_identity_equal(list.rows[1].identity, connected),
"profile list did not publish the stable identity");
active = active_snapshot(connected);
require(active.valid && active.profile_index == 0,
"new identity did not publish its default active profile");
constexpr uint32_t kResetTransactionId = 0x25a55a5a;
require(profile_service_reset(kResetTransactionId, identity,
kProfileIndex) ==
ConfigurationTransactionStatus::kPending,
"profile reset did not reach pending");
ProfileServiceTransactionSnapshot reset = transaction_snapshot();
require(reset.transaction.transaction_id == kResetTransactionId &&
reset.transaction.status ==
ConfigurationTransactionStatus::kPending,
"pending reset lost its transaction identity");
ControllerProfile seventh = controller_profile_default(connected, 6);
seventh.weak_rumble_scale = 61;
write_profile(3, connected, 6, seventh, 3000);
require(profile_service_activate_internal(0x80000007u, connected, 6) ==
ConfigurationTransactionStatus::kPending,
"controller activation was not queued");
profile_service_task_on_storage_core(4000);
active = active_snapshot(connected);
require(active.valid && active.profile_index == 6 &&
active.profile.weak_rumble_scale == 61,
"controller activation did not refresh the active cache");
profile_service_task_on_storage_core(1000);
reset = transaction_snapshot();
require(reset.transaction.transaction_id == kResetTransactionId &&
reset.transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"one reset tick decoded profile payload or published a malformed result");
ControllerProfileDatabase recovered = reload_database(reset, 2);
require(recovered.fallback_profiles[kProfileIndex].strong_rumble_scale ==
UINT8_MAX,
"terminal reset status was published before reset persisted");
active = active_profile_snapshot(identity);
require(active.valid && active.metadata.generation == 2 &&
profile_service_database_generation() == 2 &&
active.profile_index == 0,
"profile reset did not refresh the active snapshot generation");
require(profile_service_reset(4, global, CONTROLLER_PROFILE_ALL) ==
ConfigurationTransactionStatus::kPending,
"reset-all was not queued");
profile_service_task_on_storage_core(5000);
active = active_snapshot(global);
require(active.valid && active.profile_index == 0 &&
active.profile.strong_rumble_scale == UINT8_MAX,
"reset-all did not restore defaults and activation");
constexpr uint32_t kActivateTransactionId = 0x50607080;
constexpr uint8_t kActivatedProfile = 3;
require(profile_service_activate(kActivateTransactionId, identity,
kActivatedProfile) ==
ConfigurationTransactionStatus::kPending,
"profile activation did not reach pending");
ProfileServiceTransactionSnapshot activate = transaction_snapshot();
require(activate.transaction.transaction_id == kActivateTransactionId &&
activate.transaction.status ==
ConfigurationTransactionStatus::kPending,
"pending activation lost its transaction identity");
active = active_profile_snapshot(identity);
require(active.valid && active.metadata.generation == 2 &&
active.profile_index == 0,
"pending activation leaked an uncommitted active profile");
profile_service_task_on_storage_core(2000);
activate = transaction_snapshot();
require(activate.transaction.transaction_id == kActivateTransactionId &&
activate.transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"one activation tick decoded profile payload or published a malformed result");
recovered = reload_database(activate, 3);
require(recovered.fallback_active_profile == kActivatedProfile,
"terminal activation status was published before activation persisted");
active = active_profile_snapshot(identity);
require(active.valid && active.metadata.generation == 3 &&
profile_service_database_generation() == 3 &&
active.profile_index == kActivatedProfile &&
active.profile.strong_rumble_scale ==
recovered.fallback_profiles[kActivatedProfile]
.strong_rumble_scale,
"activation did not publish profile, index, and generation together");
ProfileStorage reloaded;
ControllerProfile persisted{};
require(
reloaded.initialize(fake_io()) && reloaded.find(connected) != nullptr &&
reloaded.find(connected)->active_profile == 6 &&
reloaded.get(connected, 6, &persisted) == ProfileStorageResult::kOk &&
persisted.weak_rumble_scale == 61,
"service mutations did not survive catalog reload");
}
void test_host_and_controller_mutations_are_serialized() {
const ControllerIdentity identity = controller_identity_global();
ControllerProfile profile =
controller_profile_default(identity, 1);
profile.weak_rumble_scale = 23;
uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{};
require(controller_profile_encode(profile, encoded, sizeof(encoded)),
"serialization fixture profile did not encode");
constexpr uint32_t kHostTransactionId = 0x11223344;
constexpr uint32_t kInternalTransactionId = 0x80000019;
require(profile_service_begin(
kHostTransactionId, identity, 1,
CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded),
profile_storage_crc32(encoded, sizeof(encoded))) ==
ConfigurationTransactionStatus::kReceiving,
"host write did not acquire the profile mutation boundary");
require(profile_service_activate_internal(
kInternalTransactionId, identity, 2) ==
ConfigurationTransactionStatus::kBusy,
"controller activation raced a receiving host write");
ProfileServiceTransactionSnapshot snapshot =
transaction_snapshot();
require(snapshot.transaction.transaction_id ==
kHostTransactionId &&
snapshot.transaction.status ==
ConfigurationTransactionStatus::kReceiving,
"busy controller activation replaced the host transaction");
require(
profile_service_append(kInternalTransactionId, 0, encoded,
sizeof(encoded)) ==
ConfigurationTransactionStatus::kMalformed &&
profile_service_commit(kInternalTransactionId) ==
ConfigurationTransactionStatus::kMalformed &&
transaction_snapshot().transaction.transaction_id ==
kHostTransactionId &&
transaction_snapshot().transaction.status ==
ConfigurationTransactionStatus::kReceiving,
"reserved internal IDs corrupted a receiving host transaction");
require(profile_service_append(
kHostTransactionId, 0, encoded, sizeof(encoded)) ==
ConfigurationTransactionStatus::kReceiving &&
profile_service_commit(kHostTransactionId) ==
ConfigurationTransactionStatus::kPending,
"host write did not reach pending after controller contention");
profile_service_task_on_storage_core(3000);
require(transaction_snapshot().transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"serialized host write did not commit");
constexpr uint32_t kHostActivationTransactionId = 0x22334455;
require(profile_service_activate(
kHostActivationTransactionId, identity, 0) ==
ConfigurationTransactionStatus::kPending,
"host activation did not acquire the released boundary");
require(profile_service_activate_internal(
kInternalTransactionId, identity, 2) ==
ConfigurationTransactionStatus::kBusy,
"controller activation raced a pending host activation");
snapshot = transaction_snapshot();
require(snapshot.transaction.transaction_id ==
kHostActivationTransactionId &&
snapshot.transaction.status ==
ConfigurationTransactionStatus::kPending &&
active_profile_snapshot(identity).profile_index == 3,
"pending host activation was replaced or leaked before commit");
profile_service_task_on_storage_core(4000);
require(active_profile_snapshot(identity).profile_index == 0,
"serialized host activation did not commit");
require(profile_service_activate_internal(
0x19, identity, 2) ==
ConfigurationTransactionStatus::kMalformed,
"internal activation admitted a transaction without the high bit");
require(profile_service_activate_internal(
kInternalTransactionId, identity, 2) ==
ConfigurationTransactionStatus::kPending,
"controller activation did not acquire the released boundary");
require(profile_service_begin(
0x55667788, identity, 0,
CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded),
profile_storage_crc32(encoded, sizeof(encoded))) ==
ConfigurationTransactionStatus::kBusy,
"host write raced a pending controller activation");
snapshot = transaction_snapshot();
require(snapshot.transaction.transaction_id ==
kHostActivationTransactionId &&
snapshot.transaction.status ==
ConfigurationTransactionStatus::kCommitted &&
active_profile_snapshot(identity).profile_index == 0,
"pending controller activation replaced host-visible status or leaked before commit");
profile_service_task_on_storage_core(5000);
const ProfileServiceActiveProfileSnapshot active =
active_profile_snapshot(identity);
snapshot = transaction_snapshot();
require(active.valid && active.profile_index == 2 &&
snapshot.transaction.transaction_id ==
kHostActivationTransactionId &&
snapshot.transaction.status ==
ConfigurationTransactionStatus::kCommitted,
"controller activation did not publish while preserving host-visible status");
void test_profile_bounds_and_transaction_namespace() {
const ControllerIdentity global = controller_identity_global();
require(profile_service_select(global, 8) ==
ConfigurationTransactionStatus::kMalformed &&
profile_service_activate(10, global, 8) ==
ConfigurationTransactionStatus::kMalformed &&
profile_service_reset(11, global, 8) ==
ConfigurationTransactionStatus::kMalformed,
"profile index beyond eight was admitted");
require(profile_service_activate(0x80000001u, global, 0) ==
ConfigurationTransactionStatus::kMalformed &&
profile_service_activate_internal(12, global, 0) ==
ConfigurationTransactionStatus::kMalformed,
"transaction namespaces were not enforced");
}
void test_completed_write_then_dirty_identity_activation() {
const int replacements_before = flash.bank_replacements;
const ControllerIdentity global = controller_identity_global();
constexpr uint8_t kWrittenProfileIndex = 1;
ControllerProfile customized =
controller_profile_default(global, kWrittenProfileIndex);
customized.strong_rumble_scale = 31;
customized.weak_rumble_scale = 47;
uint8_t encoded[CONTROLLER_PROFILE_ENCODED_SIZE]{};
require(controller_profile_encode(customized, encoded, sizeof(encoded)),
"sequential mutation fixture profile did not encode");
} // namespace
constexpr uint32_t kWriteTransactionId = 0x31415926;
require(profile_service_begin(
kWriteTransactionId, global, kWrittenProfileIndex,
CONTROLLER_PROFILE_SCHEMA_VERSION, sizeof(encoded),
profile_storage_crc32(encoded, sizeof(encoded))) ==
ConfigurationTransactionStatus::kReceiving &&
profile_service_append(kWriteTransactionId, 0, encoded,
sizeof(encoded)) ==
ConfigurationTransactionStatus::kReceiving &&
profile_service_commit(kWriteTransactionId) ==
ConfigurationTransactionStatus::kPending,
"sequential profile write did not reach pending");
profile_service_task_on_storage_core(6000);
const ProfileServiceTransactionSnapshot written =
transaction_snapshot();
require(written.transaction.transaction_id == kWriteTransactionId &&
written.transaction.status ==
ConfigurationTransactionStatus::kCommitted &&
flash.bank_replacements == replacements_before + 1,
"completed write lost correlation or used multiple bank replacements");
ControllerIdentity connected{};
connected.stable = true;
connected.transport = ControllerTransport::kClassic;
connected.address[0] = 0x10;
connected.address[1] = 0x20;
connected.address[2] = 0x30;
connected.address[3] = 0x40;
connected.address[4] = 0x50;
connected.address[5] = 0x60;
connected.vendor_id = 0x1234;
connected.product_id = 0xabcd;
require(profile_service_observe_identity_on_storage_core(connected),
"connected identity did not enter the dirty database");
constexpr uint32_t kActivateTransactionId = 0x27182818;
constexpr uint8_t kActivatedProfileIndex = 2;
require(profile_service_activate(
kActivateTransactionId, connected,
kActivatedProfileIndex) ==
ConfigurationTransactionStatus::kPending,
"activation after completed write did not reach pending");
const ProfileServiceTransactionSnapshot pending =
transaction_snapshot();
require(pending.transaction.transaction_id ==
kActivateTransactionId &&
pending.transaction.status ==
ConfigurationTransactionStatus::kPending &&
pending.transaction.stored_generation == 0 &&
pending.transaction.stored_crc == 0,
"pending activation was not correlated to its own transaction");
profile_service_task_on_storage_core(7000);
const ProfileServiceTransactionSnapshot activated =
transaction_snapshot();
require(activated.transaction.transaction_id ==
kActivateTransactionId &&
activated.transaction.status ==
ConfigurationTransactionStatus::kCommitted &&
activated.transaction.stored_generation ==
written.transaction.stored_generation + 1 &&
flash.bank_replacements == replacements_before + 2,
"activation did not complete as one next correlated bank replacement");
const ControllerProfileDatabase recovered = reload_database(
activated, activated.transaction.stored_generation);
const ControllerProfileDatabaseEntry* connected_entry =
controller_profile_database_find(recovered, connected);
require(connected_entry != nullptr &&
connected_entry->active_profile ==
kActivatedProfileIndex &&
recovered.fallback_profiles[kWrittenProfileIndex]
.strong_rumble_scale ==
customized.strong_rumble_scale &&
recovered.fallback_profiles[kWrittenProfileIndex]
.weak_rumble_scale ==
customized.weak_rumble_scale,
"activation did not atomically persist the dirty identity and prior write");
const ProfileServiceActiveProfileSnapshot active =
active_profile_snapshot(connected);
require(active.valid &&
active.metadata.generation ==
activated.transaction.stored_generation &&
active.profile_index == kActivatedProfileIndex,
"completed activation did not publish the dirty identity");
}
} // namespace
ProfileStorageIo pico_profile_storage_io() {
return fake_io();
}
ProfileStorageIo pico_profile_storage_io() { return fake_io(); }
int main() {
test_pending_commands_are_not_decoded_as_profile_writes();
test_host_and_controller_mutations_are_serialized();
test_completed_write_then_dirty_identity_activation();
return 0;
test_eight_profile_transactions_and_active_cache();
test_profile_bounds_and_transaction_namespace();
std::cout << "profile service tests passed\n";
return 0;
}