- Rename tests/wasm-app/ to tests/apps/ for brevity - Move lib/gl_immediate_shim.js to wasm/shims/ (consolidates WASM files) - Delete docs/ directory (outdated Nov 2024 research docs) - Delete patches/ directory (already applied to fork submodules) - Delete wasm/patches/ and wasm/config/ (empty/unused) - Update all file references in scripts, configs, and documentation - Update .gitignore for new tests/apps/ paths Verified both build workflows pass: - wxWidgets tests: 255 passed - Docker KiCad build: completed successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
461 lines
15 KiB
C++
461 lines
15 KiB
C++
// WASM Edge Cases Test - Test WASM-specific behaviors and limitations
|
|
// Tests: Threading stubs, file system, memory, asyncify, clipboard permissions
|
|
|
|
#include "wx/wx.h"
|
|
#include "wx/file.h"
|
|
#include "wx/filename.h"
|
|
#include "wx/dir.h"
|
|
#include "wx/clipbrd.h"
|
|
#include "wx/thread.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/fontenum.h"
|
|
|
|
// Test if threading is stubbed or functional
|
|
class TestThread : public wxThread
|
|
{
|
|
public:
|
|
TestThread(wxTextCtrl* log) : wxThread(wxTHREAD_DETACHED), m_log(log) {}
|
|
|
|
virtual void* Entry() override
|
|
{
|
|
// In WASM, this may not actually run in a separate thread
|
|
m_ran = true;
|
|
return nullptr;
|
|
}
|
|
|
|
bool DidRun() const { return m_ran; }
|
|
|
|
private:
|
|
wxTextCtrl* m_log;
|
|
bool m_ran = false;
|
|
};
|
|
|
|
class WasmEdgeFrame : public wxFrame
|
|
{
|
|
public:
|
|
WasmEdgeFrame() : wxFrame(nullptr, wxID_ANY, "WASM Edge Cases Test",
|
|
wxDefaultPosition, wxSize(800, 700))
|
|
{
|
|
wxPanel* mainPanel = new wxPanel(this);
|
|
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
// Description
|
|
wxStaticText* desc = new wxStaticText(mainPanel, wxID_ANY,
|
|
"Tests WASM-specific behaviors: threading stubs, file limits, memory, asyncify.\n"
|
|
"These tests verify WASM port handles browser limitations correctly.");
|
|
mainSizer->Add(desc, 0, wxALL, 5);
|
|
|
|
// Test buttons
|
|
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 10, 10);
|
|
gridSizer->AddGrowableCol(1, 1);
|
|
|
|
// File System Tests
|
|
wxButton* btnFileWrite = new wxButton(mainPanel, wxID_ANY, "Test File Write (/tmp/)");
|
|
btnFileWrite->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestFileWrite, this);
|
|
gridSizer->Add(btnFileWrite, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Write to WASM virtual file system"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
wxButton* btnFileRead = new wxButton(mainPanel, wxID_ANY, "Test File Read");
|
|
btnFileRead->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestFileRead, this);
|
|
gridSizer->Add(btnFileRead, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Read from virtual file system"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
wxButton* btnDirList = new wxButton(mainPanel, wxID_ANY, "Test Dir Listing");
|
|
btnDirList->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestDirListing, this);
|
|
gridSizer->Add(btnDirList, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "List /tmp/ directory contents"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Threading Tests
|
|
wxButton* btnThread = new wxButton(mainPanel, wxID_ANY, "Test Threading");
|
|
btnThread->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestThreading, this);
|
|
gridSizer->Add(btnThread, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Check if wxThread is stubbed"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Font Enumeration Tests
|
|
wxButton* btnFonts = new wxButton(mainPanel, wxID_ANY, "Test Font Enumeration");
|
|
btnFonts->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestFontEnum, this);
|
|
gridSizer->Add(btnFonts, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Enumerate available fonts (may fail in WASM)"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Clipboard Tests
|
|
wxButton* btnClipboard = new wxButton(mainPanel, wxID_ANY, "Test Clipboard");
|
|
btnClipboard->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestClipboard, this);
|
|
gridSizer->Add(btnClipboard, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Test clipboard with asyncify"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Memory Tests
|
|
wxButton* btnMemory = new wxButton(mainPanel, wxID_ANY, "Test Memory Allocation");
|
|
btnMemory->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestMemory, this);
|
|
gridSizer->Add(btnMemory, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Test WASM memory growth"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// OS Info Tests
|
|
wxButton* btnOsInfo = new wxButton(mainPanel, wxID_ANY, "Test OS Info");
|
|
btnOsInfo->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestOsInfo, this);
|
|
gridSizer->Add(btnOsInfo, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Check wxGetOsVersion (may be stubbed)"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// wxLaunchDefaultBrowser Test
|
|
wxButton* btnBrowser = new wxButton(mainPanel, wxID_ANY, "Test URL Launch");
|
|
btnBrowser->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestBrowserLaunch, this);
|
|
gridSizer->Add(btnBrowser, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Test wxLaunchDefaultBrowser"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// wxFileName Tests
|
|
wxButton* btnFileName = new wxButton(mainPanel, wxID_ANY, "Test wxFileName");
|
|
btnFileName->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnTestFileName, this);
|
|
gridSizer->Add(btnFileName, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Path manipulation functions"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Run All Tests
|
|
wxButton* btnAll = new wxButton(mainPanel, wxID_ANY, "Run All Tests");
|
|
btnAll->Bind(wxEVT_BUTTON, &WasmEdgeFrame::OnRunAllTests, this);
|
|
gridSizer->Add(btnAll, 0, wxEXPAND);
|
|
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Execute all edge case tests"), 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
mainSizer->Add(gridSizer, 0, wxEXPAND | wxALL, 10);
|
|
|
|
// Event log
|
|
mainSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Test Results"), 0, wxLEFT | wxTOP, 5);
|
|
m_log = new wxTextCtrl(mainPanel, wxID_ANY, "", wxDefaultPosition, wxSize(-1, 300),
|
|
wxTE_MULTILINE | wxTE_READONLY);
|
|
m_log->SetFont(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
|
mainSizer->Add(m_log, 1, wxEXPAND | wxALL, 5);
|
|
|
|
mainPanel->SetSizer(mainSizer);
|
|
|
|
CreateStatusBar();
|
|
SetStatusText("WASM edge cases test app started");
|
|
Log("WASM Edge Cases Test App Started");
|
|
Log("====================================\n");
|
|
}
|
|
|
|
private:
|
|
void OnTestFileWrite(wxCommandEvent& event)
|
|
{
|
|
Log("=== File Write Test ===");
|
|
|
|
wxString testFile = "/tmp/wasm_test_file.txt";
|
|
wxString content = "Hello from WASM!\nLine 2\nLine 3";
|
|
|
|
wxFile file;
|
|
if (file.Create(testFile, true)) // true = overwrite
|
|
{
|
|
if (file.Write(content))
|
|
{
|
|
Log("SUCCESS: Wrote " + wxString::Format("%zu", content.Length()) + " bytes to " + testFile);
|
|
m_testFilePath = testFile;
|
|
}
|
|
else
|
|
{
|
|
Log("FAILED: Could not write to file");
|
|
}
|
|
file.Close();
|
|
}
|
|
else
|
|
{
|
|
Log("FAILED: Could not create file " + testFile);
|
|
}
|
|
Log("");
|
|
}
|
|
|
|
void OnTestFileRead(wxCommandEvent& event)
|
|
{
|
|
Log("=== File Read Test ===");
|
|
|
|
if (m_testFilePath.IsEmpty())
|
|
{
|
|
Log("No test file - run File Write test first");
|
|
Log("");
|
|
return;
|
|
}
|
|
|
|
wxFile file;
|
|
if (file.Open(m_testFilePath))
|
|
{
|
|
wxString content;
|
|
if (file.ReadAll(&content))
|
|
{
|
|
Log("SUCCESS: Read " + wxString::Format("%zu", content.Length()) + " bytes");
|
|
Log("Content:\n" + content);
|
|
}
|
|
else
|
|
{
|
|
Log("FAILED: Could not read file content");
|
|
}
|
|
file.Close();
|
|
}
|
|
else
|
|
{
|
|
Log("FAILED: Could not open " + m_testFilePath);
|
|
}
|
|
Log("");
|
|
}
|
|
|
|
void OnTestDirListing(wxCommandEvent& event)
|
|
{
|
|
Log("=== Directory Listing Test ===");
|
|
|
|
wxDir dir("/tmp");
|
|
if (dir.IsOpened())
|
|
{
|
|
Log("Contents of /tmp/:");
|
|
|
|
wxString filename;
|
|
int count = 0;
|
|
bool cont = dir.GetFirst(&filename);
|
|
while (cont)
|
|
{
|
|
Log(" " + filename);
|
|
count++;
|
|
cont = dir.GetNext(&filename);
|
|
}
|
|
|
|
if (count == 0)
|
|
Log(" (empty directory)");
|
|
else
|
|
Log(wxString::Format(" Total: %d files", count));
|
|
}
|
|
else
|
|
{
|
|
Log("FAILED: Could not open /tmp/ directory");
|
|
}
|
|
Log("");
|
|
}
|
|
|
|
void OnTestThreading(wxCommandEvent& event)
|
|
{
|
|
Log("=== Threading Test ===");
|
|
|
|
// In WASM, threading may be stubbed
|
|
Log("Creating wxThread...");
|
|
|
|
// Check if we can create a thread (may be no-op in WASM)
|
|
#if wxUSE_THREADS
|
|
Log("wxUSE_THREADS is defined");
|
|
|
|
// Note: Actually running threads in WASM is complex
|
|
// This test just checks if the API is available
|
|
Log("Thread API is available (may be stubbed in WASM)");
|
|
Log("WASM typically runs single-threaded");
|
|
Log("For async operations, use wxTimer or emscripten_async_*");
|
|
#else
|
|
Log("wxUSE_THREADS is NOT defined");
|
|
#endif
|
|
|
|
Log("");
|
|
}
|
|
|
|
void OnTestFontEnum(wxCommandEvent& event)
|
|
{
|
|
Log("=== Font Enumeration Test ===");
|
|
|
|
class FontEnumerator : public wxFontEnumerator
|
|
{
|
|
public:
|
|
wxArrayString fonts;
|
|
|
|
virtual bool OnFacename(const wxString& facename) override
|
|
{
|
|
fonts.Add(facename);
|
|
return true; // Continue enumeration
|
|
}
|
|
};
|
|
|
|
FontEnumerator enumerator;
|
|
bool result = enumerator.EnumerateFacenames();
|
|
|
|
if (result && enumerator.fonts.GetCount() > 0)
|
|
{
|
|
Log("SUCCESS: Found " + wxString::Format("%zu", enumerator.fonts.GetCount()) + " fonts:");
|
|
for (size_t i = 0; i < wxMin(enumerator.fonts.GetCount(), (size_t)10); i++)
|
|
{
|
|
Log(" " + enumerator.fonts[i]);
|
|
}
|
|
if (enumerator.fonts.GetCount() > 10)
|
|
Log(" ... and " + wxString::Format("%zu", enumerator.fonts.GetCount() - 10) + " more");
|
|
}
|
|
else
|
|
{
|
|
Log("NOTICE: Font enumeration returned false or empty");
|
|
Log("This is expected in WASM - fontenum.cpp returns false");
|
|
Log("Font pickers should use a predefined font list instead");
|
|
}
|
|
Log("");
|
|
}
|
|
|
|
void OnTestClipboard(wxCommandEvent& event)
|
|
{
|
|
Log("=== Clipboard Test ===");
|
|
|
|
wxString testText = "WASM Clipboard Test " + wxDateTime::Now().FormatISOCombined();
|
|
|
|
if (wxTheClipboard->Open())
|
|
{
|
|
// Write
|
|
wxTheClipboard->SetData(new wxTextDataObject(testText));
|
|
Log("Wrote to clipboard: " + testText);
|
|
|
|
// Read back
|
|
if (wxTheClipboard->IsSupported(wxDF_TEXT))
|
|
{
|
|
wxTextDataObject data;
|
|
if (wxTheClipboard->GetData(data))
|
|
{
|
|
Log("Read from clipboard: " + data.GetText());
|
|
if (data.GetText() == testText)
|
|
Log("SUCCESS: Clipboard round-trip works");
|
|
else
|
|
Log("WARNING: Read text differs from written text");
|
|
}
|
|
else
|
|
{
|
|
Log("NOTICE: Could not read clipboard (may need user interaction)");
|
|
}
|
|
}
|
|
|
|
wxTheClipboard->Close();
|
|
}
|
|
else
|
|
{
|
|
Log("FAILED: Could not open clipboard");
|
|
}
|
|
Log("");
|
|
}
|
|
|
|
void OnTestMemory(wxCommandEvent& event)
|
|
{
|
|
Log("=== Memory Allocation Test ===");
|
|
|
|
// Test small allocation
|
|
std::vector<char> small(1024 * 10); // 10 KB
|
|
Log("Allocated 10 KB: SUCCESS");
|
|
|
|
// Test medium allocation
|
|
std::vector<char> medium(1024 * 1024); // 1 MB
|
|
Log("Allocated 1 MB: SUCCESS");
|
|
|
|
// Test larger allocation (WASM memory growth)
|
|
try
|
|
{
|
|
std::vector<char> large(1024 * 1024 * 10); // 10 MB
|
|
Log("Allocated 10 MB: SUCCESS (WASM memory growth works)");
|
|
}
|
|
catch (const std::bad_alloc& e)
|
|
{
|
|
Log("FAILED: Could not allocate 10 MB");
|
|
Log(" Error: " + wxString(e.what()));
|
|
}
|
|
|
|
Log("");
|
|
}
|
|
|
|
void OnTestOsInfo(wxCommandEvent& event)
|
|
{
|
|
Log("=== OS Info Test ===");
|
|
|
|
int major, minor, micro;
|
|
wxOperatingSystemId os = wxGetOsVersion(&major, &minor, µ);
|
|
|
|
Log("wxGetOsVersion returned:");
|
|
Log(" OS ID: " + wxString::Format("%d", (int)os));
|
|
Log(" Version: " + wxString::Format("%d.%d.%d", major, minor, micro));
|
|
|
|
wxString osDesc = wxGetOsDescription();
|
|
Log(" Description: " + osDesc);
|
|
|
|
// In WASM, these may be stubbed
|
|
if (osDesc.IsEmpty() || osDesc == "Unknown")
|
|
{
|
|
Log("NOTICE: OS info may be stubbed in WASM");
|
|
}
|
|
|
|
Log("");
|
|
}
|
|
|
|
void OnTestBrowserLaunch(wxCommandEvent& event)
|
|
{
|
|
Log("=== URL Launch Test ===");
|
|
|
|
// In WASM, this should open in new tab via window.open()
|
|
wxString url = "https://www.kicad.org";
|
|
|
|
Log("Attempting to open: " + url);
|
|
bool result = wxLaunchDefaultBrowser(url);
|
|
|
|
if (result)
|
|
Log("SUCCESS: Browser launch returned true");
|
|
else
|
|
Log("NOTICE: Browser launch returned false (may still work via popup)");
|
|
|
|
Log("");
|
|
}
|
|
|
|
void OnTestFileName(wxCommandEvent& event)
|
|
{
|
|
Log("=== wxFileName Test ===");
|
|
|
|
// Test path manipulation
|
|
wxFileName fn("/tmp/test/file.kicad_pcb");
|
|
|
|
Log("Full path: " + fn.GetFullPath());
|
|
Log("Name: " + fn.GetName());
|
|
Log("Extension: " + fn.GetExt());
|
|
Log("Path: " + fn.GetPath());
|
|
Log("Volume: " + fn.GetVolume());
|
|
|
|
// Test path building
|
|
wxFileName fn2;
|
|
fn2.AssignDir("/home/user/projects");
|
|
fn2.AppendDir("kicad");
|
|
fn2.SetFullName("board.kicad_pcb");
|
|
|
|
Log("Built path: " + fn2.GetFullPath());
|
|
|
|
// Test relative path
|
|
wxFileName relative;
|
|
relative.Assign("../designs/board.kicad_pcb");
|
|
Log("Is relative: " + wxString(relative.IsRelative() ? "yes" : "no"));
|
|
|
|
Log("");
|
|
}
|
|
|
|
void OnRunAllTests(wxCommandEvent& event)
|
|
{
|
|
m_log->Clear();
|
|
Log("Running all WASM edge case tests...\n");
|
|
|
|
OnTestFileWrite(event);
|
|
OnTestFileRead(event);
|
|
OnTestDirListing(event);
|
|
OnTestThreading(event);
|
|
OnTestFontEnum(event);
|
|
OnTestClipboard(event);
|
|
OnTestMemory(event);
|
|
OnTestOsInfo(event);
|
|
OnTestFileName(event);
|
|
|
|
Log("=== All Tests Complete ===");
|
|
}
|
|
|
|
void Log(const wxString& msg)
|
|
{
|
|
m_log->AppendText(msg + "\n");
|
|
}
|
|
|
|
wxTextCtrl* m_log;
|
|
wxString m_testFilePath;
|
|
};
|
|
|
|
class WasmEdgeApp : public wxApp
|
|
{
|
|
public:
|
|
virtual bool OnInit() override
|
|
{
|
|
WasmEdgeFrame* frame = new WasmEdgeFrame();
|
|
frame->Show();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
wxIMPLEMENT_APP(WasmEdgeApp);
|