Files
Pixelplanet--Pixel-VR-Player/tests/test_vault.cpp
T
Pixelplanet 7987fffed4 feat(vault): hidden vault, file actions submenu, dual controller models, and display sharpness
- Add Hidden Vault system:
  - Secure directory storage under ~/.pixelvr_vault with 0700 permissions.
  - Cheat-code combo unlocking triggered on full grip squeeze (A-B-B-A-X-Y default, customizable).
  - Headset removal / face detection gating and inactivity auto-lock.
  - Automatic download history clearing upon vault lock.
- Add File Actions Submenu (Button Y):
  - In-browser file/folder submenu with Move to Vault, Delete, Move, and Rename.
  - Recursive folder move to vault with collision handling.
  - Folder deletion with confirmation dialog.
- Enhance VR controllers and interactions:
  - Dynamic left and right Steam Frame controller render models.
  - Single laser pointer priority with hand swapping via full grip squeeze.
- Fix video format detection:
  - Correct auto-detection and default projection for high-resolution VR180 SBS media (e.g. 7200x3600).
- Visual sharpness & rendering stability:
  - Render swapchain at native 2160x2160 per eye.
  - SDF font rendering with RMS pixel footprint and stem darkening.
  - Razor-sharp procedural UI anti-aliasing and crisp border highlights without distortion.
- Add unit test suite (tests/test_vault.cpp) and documentation specs.
2026-10-17 18:06:19 +02:00

199 lines
8.7 KiB
C++

#include "app/vault_manager.hpp"
#include <cassert>
#include <iostream>
#include <fstream>
#include <filesystem>
using namespace pixelvr;
namespace fs = std::filesystem;
int main() {
std::cout << "[TEST] Starting VaultManager verification..." << std::endl;
auto& vm = VaultManager::instance();
// Reset to default combo sequence for reproducible testing
vm.startRecordingCombo();
vm.feedRecordButton(XrInputState::BtnA);
vm.feedRecordButton(XrInputState::BtnB);
vm.feedRecordButton(XrInputState::BtnB);
vm.feedRecordButton(XrInputState::BtnA);
vm.feedRecordButton(XrInputState::BtnX);
vm.feedRecordButton(XrInputState::BtnY);
// 1. Initial locked state
vm.lock();
assert(!vm.isUnlocked());
std::cout << "[PASS] Initial state is locked." << std::endl;
// 2. Discrete grip requirement (soft squeeze / grip=false should not advance)
auto now = std::chrono::steady_clock::now();
assert(vm.feedInput(XrInputState::BtnA, false, now) == VaultManager::ComboResult::None);
assert(vm.feedInput(XrInputState::BtnB, false, now) == VaultManager::ComboResult::None);
assert(!vm.isUnlocked());
std::cout << "[PASS] Soft squeeze / no grip full press does not trigger combo." << std::endl;
// 3. Step through default combo: A -> B -> B -> A -> X -> Y
assert(vm.feedInput(XrInputState::BtnA, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnB, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnB, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnA, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnX, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnY, true, now) == VaultManager::ComboResult::Unlocked);
assert(vm.isUnlocked());
std::cout << "[PASS] Cheat code A-B-B-A-X-Y with grip full press unlocks vault!" << std::endl;
// Verify vault directories exist and have 0700 permissions
assert(fs::exists(vm.vaultDir()));
assert(fs::exists(vm.thumbsDir()));
auto perms = fs::status(vm.vaultDir()).permissions();
assert((perms & fs::perms::others_all) == fs::perms::none);
std::cout << "[PASS] Vault directory created with secure 0700 permissions: " << vm.vaultDir() << std::endl;
// 4. Test re-lock via combo
assert(vm.feedInput(XrInputState::BtnA, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnB, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnB, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnA, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnX, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnY, true, now) == VaultManager::ComboResult::Locked);
assert(!vm.isUnlocked());
std::cout << "[PASS] Entering combo again locks the vault." << std::endl;
// 5. Test Headset removal auto-lock with 3-second debounce
vm.unlock();
assert(vm.isUnlocked());
assert(!vm.tick(now, false)); // Momentary flicker (<3s) does NOT lock
assert(vm.isUnlocked());
assert(vm.tick(now + std::chrono::milliseconds(3100), false)); // >=3s continuous loss locks
assert(!vm.isUnlocked());
std::cout << "[PASS] Auto-lock on headset removal successfully locks vault after 3s debounce." << std::endl;
// 6. Test Inactivity timeout (enabled vs disabled)
vm.unlock();
vm.setAutoLockTimeoutSec(2); // 2 seconds for test
vm.recordActivity(now);
assert(!vm.tick(now, true)); // immediate tick does not lock
assert(vm.isUnlocked());
assert(vm.tick(now + std::chrono::seconds(3), true)); // 3s later -> timeout
assert(!vm.isUnlocked());
std::cout << "[PASS] Inactivity timeout successfully locks vault when enabled." << std::endl;
// Test Inactivity timeout disabled (default)
vm.unlock();
vm.setAutoLockTimeoutSec(0); // 0 = disabled
vm.recordActivity(now);
assert(!vm.tick(now + std::chrono::hours(1), true)); // 1 hour later -> still unlocked because disabled
assert(vm.isUnlocked());
std::cout << "[PASS] Inactivity timeout = 0 disables timeout auto-lock." << std::endl;
// 7. Test Move-to-Vault for single file and collision resolution
vm.unlock();
std::string testSrc = "/tmp/pixelvr_test_clip.mp4";
{
std::ofstream f(testSrc);
f << "dummy video content 12345";
}
std::string outPath1;
std::string err1 = vm.moveFileToVault(testSrc, outPath1);
assert(err1.empty());
assert(!fs::exists(testSrc));
assert(fs::exists(outPath1));
std::cout << "[PASS] Move file to vault succeeded: " << outPath1 << std::endl;
// Collision test: create another file with same name
{
std::ofstream f(testSrc);
f << "dummy video content second version";
}
std::string outPath2;
std::string err2 = vm.moveFileToVault(testSrc, outPath2);
assert(err2.empty());
assert(!fs::exists(testSrc));
assert(fs::exists(outPath2));
assert(outPath1 != outPath2);
std::cout << "[PASS] Collision resolved properly: " << outPath2 << std::endl;
// Clean up test files
fs::remove(outPath1);
fs::remove(outPath2);
// 8. Test Move-to-Vault for entire directory and recursive permissions
std::string testDir = "/tmp/pixelvr_test_folder";
fs::create_directories(testDir);
{
std::ofstream f1(testDir + "/subvideo1.mp4");
f1 << "sub video 1 content";
std::ofstream f2(testDir + "/subvideo2.mp4");
f2 << "sub video 2 content";
}
std::string outDir1;
std::string errDir1 = vm.moveFileToVault(testDir, outDir1);
assert(errDir1.empty());
assert(!fs::exists(testDir));
assert(fs::exists(outDir1));
assert(fs::is_directory(outDir1));
assert(fs::exists(outDir1 + "/subvideo1.mp4"));
assert(fs::exists(outDir1 + "/subvideo2.mp4"));
// Check directory permissions
auto dirPerms = fs::status(outDir1).permissions();
assert((dirPerms & fs::perms::others_all) == fs::perms::none);
std::cout << "[PASS] Move entire folder to vault succeeded with 0700 permissions: " << outDir1 << std::endl;
// Folder collision test: recreate folder and move again
fs::create_directories(testDir);
{
std::ofstream f(testDir + "/subvideo3.mp4");
f << "sub video 3 content";
}
std::string outDir2;
std::string errDir2 = vm.moveFileToVault(testDir, outDir2);
assert(errDir2.empty());
assert(!fs::exists(testDir));
assert(fs::exists(outDir2));
assert(outDir1 != outDir2);
assert(fs::exists(outDir2 + "/subvideo3.mp4"));
std::cout << "[PASS] Folder collision resolved properly: " << outDir2 << std::endl;
// Clean up test directories
fs::remove_all(outDir1);
fs::remove_all(outDir2);
// 9. Custom combo recording
vm.startRecordingCombo();
assert(vm.isRecordingCombo());
assert(!vm.feedRecordButton(XrInputState::BtnX));
assert(!vm.feedRecordButton(XrInputState::BtnX));
assert(!vm.feedRecordButton(XrInputState::BtnY));
assert(!vm.feedRecordButton(XrInputState::BtnY));
assert(!vm.feedRecordButton(XrInputState::BtnA));
assert(vm.feedRecordButton(XrInputState::BtnB)); // 6th button finishes
assert(!vm.isRecordingCombo());
assert(vm.comboString() == "X X Y Y A B");
std::cout << "[PASS] Custom combo recording verified: " << vm.comboString() << std::endl;
// Test new combo works
vm.lock();
assert(vm.feedInput(XrInputState::BtnX, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnX, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnY, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnY, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnA, true, now) == VaultManager::ComboResult::StepMatched);
assert(vm.feedInput(XrInputState::BtnB, true, now) == VaultManager::ComboResult::Unlocked);
assert(vm.isUnlocked());
std::cout << "[PASS] New custom combo successfully unlocked vault!" << std::endl;
// Restore default combo
vm.startRecordingCombo();
vm.feedRecordButton(XrInputState::BtnA);
vm.feedRecordButton(XrInputState::BtnB);
vm.feedRecordButton(XrInputState::BtnB);
vm.feedRecordButton(XrInputState::BtnA);
vm.feedRecordButton(XrInputState::BtnX);
vm.feedRecordButton(XrInputState::BtnY);
vm.lock();
std::cout << "\n*** ALL VAULT MANAGER UNIT TESTS PASSED PERFECTLY! ***" << std::endl;
return 0;
}