pcbjam/tests/apps/standalone/validators/validators_test.cpp
Viktor Vaczi a26b40c063 Reorganize project structure for clarity
- 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>
2025-12-27 14:06:23 +01:00

281 lines
10 KiB
C++

// wxValidator Test - Input validation like KiCad uses
// Tests: wxTextValidator, wxIntegerValidator, wxFloatingPointValidator, custom validators
#include "wx/wx.h"
#include "wx/valtext.h"
#include "wx/valnum.h"
// Custom validator similar to KiCad's NETNAME_VALIDATOR
class NetNameValidator : public wxTextValidator
{
public:
NetNameValidator() : wxTextValidator(wxFILTER_NONE)
{
// Allow alphanumeric, underscore, and some special chars
SetCharIncludes("_+-/");
}
virtual wxObject* Clone() const override
{
return new NetNameValidator(*this);
}
virtual bool Validate(wxWindow* parent) override
{
wxTextCtrl* tc = dynamic_cast<wxTextCtrl*>(GetWindow());
if (!tc) return true;
wxString val = tc->GetValue();
// Net name cannot start with a number
if (!val.IsEmpty() && wxIsdigit(val[0]))
{
wxMessageBox("Net name cannot start with a digit", "Validation Error",
wxOK | wxICON_ERROR, parent);
return false;
}
return wxTextValidator::Validate(parent);
}
};
// Custom validator for footprint names (like FOOTPRINT_NAME_VALIDATOR)
class FootprintNameValidator : public wxTextValidator
{
public:
FootprintNameValidator() : wxTextValidator(wxFILTER_ALPHANUMERIC)
{
SetCharIncludes("_-.");
}
virtual wxObject* Clone() const override
{
return new FootprintNameValidator(*this);
}
};
class ValidatorsFrame : public wxFrame
{
public:
ValidatorsFrame() : wxFrame(nullptr, wxID_ANY, "wxValidator Test",
wxDefaultPosition, wxSize(700, 600))
{
wxPanel* mainPanel = new wxPanel(this);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Description
wxStaticText* desc = new wxStaticText(mainPanel, wxID_ANY,
"KiCad uses validators for input validation in dialogs.\n"
"Tests: wxTextValidator, wxIntegerValidator, wxFloatingPointValidator, custom validators.");
mainSizer->Add(desc, 0, wxALL, 5);
// Grid for input fields
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 10, 10);
gridSizer->AddGrowableCol(1, 1);
// 1. Alpha-numeric validator
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Alphanumeric only:"),
0, wxALIGN_CENTER_VERTICAL);
m_alphaCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, 0,
wxTextValidator(wxFILTER_ALPHANUMERIC));
m_alphaCtrl->SetHint("Letters and numbers only");
gridSizer->Add(m_alphaCtrl, 1, wxEXPAND);
// 2. Numeric only validator
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Digits only:"),
0, wxALIGN_CENTER_VERTICAL);
m_digitCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, 0,
wxTextValidator(wxFILTER_DIGITS));
m_digitCtrl->SetHint("0-9 only");
gridSizer->Add(m_digitCtrl, 1, wxEXPAND);
// 3. Integer validator with range
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Integer (0-1000):"),
0, wxALIGN_CENTER_VERTICAL);
m_intValue = 100;
wxIntegerValidator<int> intValidator(&m_intValue);
intValidator.SetRange(0, 1000);
m_intCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "100",
wxDefaultPosition, wxDefaultSize, 0,
intValidator);
gridSizer->Add(m_intCtrl, 1, wxEXPAND);
// 4. Float validator with range
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Float (0.0-100.0):"),
0, wxALIGN_CENTER_VERTICAL);
m_floatValue = 50.0;
wxFloatingPointValidator<double> floatValidator(3, &m_floatValue);
floatValidator.SetRange(0.0, 100.0);
m_floatCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "50.0",
wxDefaultPosition, wxDefaultSize, 0,
floatValidator);
gridSizer->Add(m_floatCtrl, 1, wxEXPAND);
// 5. Include chars validator
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Email chars (a-z, @, .):"),
0, wxALIGN_CENTER_VERTICAL);
wxTextValidator emailValidator(wxFILTER_ALPHANUMERIC);
emailValidator.SetCharIncludes("@._-");
m_emailCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, 0,
emailValidator);
m_emailCtrl->SetHint("user@example.com");
gridSizer->Add(m_emailCtrl, 1, wxEXPAND);
// 6. Exclude chars validator
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "No spaces allowed:"),
0, wxALIGN_CENTER_VERTICAL);
wxTextValidator noSpaceValidator(wxFILTER_EXCLUDE_CHAR_LIST);
noSpaceValidator.SetCharExcludes(" \t\n");
m_noSpaceCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, 0,
noSpaceValidator);
m_noSpaceCtrl->SetHint("No whitespace");
gridSizer->Add(m_noSpaceCtrl, 1, wxEXPAND);
// 7. Net name validator (custom)
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Net name (custom):"),
0, wxALIGN_CENTER_VERTICAL);
m_netNameCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, 0,
NetNameValidator());
m_netNameCtrl->SetHint("Cannot start with digit");
gridSizer->Add(m_netNameCtrl, 1, wxEXPAND);
// 8. Footprint name validator (custom)
gridSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Footprint name:"),
0, wxALIGN_CENTER_VERTICAL);
m_footprintCtrl = new wxTextCtrl(mainPanel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize, 0,
FootprintNameValidator());
m_footprintCtrl->SetHint("Alphanumeric with _-.");
gridSizer->Add(m_footprintCtrl, 1, wxEXPAND);
mainSizer->Add(gridSizer, 0, wxEXPAND | wxALL, 10);
// Buttons
wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
wxButton* btnValidate = new wxButton(mainPanel, wxID_ANY, "Validate All");
wxButton* btnTransfer = new wxButton(mainPanel, wxID_ANY, "Transfer Data");
wxButton* btnClear = new wxButton(mainPanel, wxID_ANY, "Clear All");
btnValidate->Bind(wxEVT_BUTTON, &ValidatorsFrame::OnValidateAll, this);
btnTransfer->Bind(wxEVT_BUTTON, &ValidatorsFrame::OnTransferData, this);
btnClear->Bind(wxEVT_BUTTON, &ValidatorsFrame::OnClearAll, this);
btnSizer->Add(btnValidate, 0, wxRIGHT, 5);
btnSizer->Add(btnTransfer, 0, wxRIGHT, 5);
btnSizer->Add(btnClear, 0);
mainSizer->Add(btnSizer, 0, wxALL, 10);
// Event log
mainSizer->Add(new wxStaticText(mainPanel, wxID_ANY, "Event Log"), 0, wxLEFT | wxTOP, 5);
m_log = new wxTextCtrl(mainPanel, wxID_ANY, "", wxDefaultPosition, wxSize(-1, 150),
wxTE_MULTILINE | wxTE_READONLY);
mainSizer->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainPanel->SetSizer(mainSizer);
CreateStatusBar();
SetStatusText("Validator test app started");
Log("Validator test app started");
Log("Try typing invalid characters - they should be blocked");
}
private:
void OnValidateAll(wxCommandEvent& event)
{
Log("Validating all fields...");
bool allValid = true;
// Validate each control
wxTextCtrl* controls[] = {m_alphaCtrl, m_digitCtrl, m_intCtrl, m_floatCtrl,
m_emailCtrl, m_noSpaceCtrl, m_netNameCtrl, m_footprintCtrl};
const char* names[] = {"Alphanumeric", "Digits", "Integer", "Float",
"Email", "NoSpace", "NetName", "Footprint"};
for (int i = 0; i < 8; i++)
{
wxValidator* validator = controls[i]->GetValidator();
if (validator)
{
bool valid = validator->Validate(this);
Log(wxString::Format(" %s: %s", names[i], valid ? "VALID" : "INVALID"));
if (!valid) allValid = false;
}
}
Log(wxString::Format("Overall result: %s", allValid ? "ALL VALID" : "SOME INVALID"));
if (allValid)
{
wxMessageBox("All fields are valid!", "Validation", wxOK | wxICON_INFORMATION);
}
}
void OnTransferData(wxCommandEvent& event)
{
Log("Transferring data from controls...");
// TransferDataFromWindow updates the bound variables
if (TransferDataFromWindow())
{
Log(wxString::Format(" Integer value: %d", m_intValue));
Log(wxString::Format(" Float value: %.3f", m_floatValue));
Log("Transfer successful");
}
else
{
Log("Transfer failed - validation error");
}
}
void OnClearAll(wxCommandEvent& event)
{
m_alphaCtrl->Clear();
m_digitCtrl->Clear();
m_intCtrl->SetValue("0");
m_floatCtrl->SetValue("0.0");
m_emailCtrl->Clear();
m_noSpaceCtrl->Clear();
m_netNameCtrl->Clear();
m_footprintCtrl->Clear();
Log("All fields cleared");
}
void Log(const wxString& msg)
{
m_log->AppendText(msg + "\n");
}
wxTextCtrl* m_alphaCtrl;
wxTextCtrl* m_digitCtrl;
wxTextCtrl* m_intCtrl;
wxTextCtrl* m_floatCtrl;
wxTextCtrl* m_emailCtrl;
wxTextCtrl* m_noSpaceCtrl;
wxTextCtrl* m_netNameCtrl;
wxTextCtrl* m_footprintCtrl;
wxTextCtrl* m_log;
int m_intValue;
double m_floatValue;
};
class ValidatorsApp : public wxApp
{
public:
virtual bool OnInit() override
{
ValidatorsFrame* frame = new ValidatorsFrame();
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(ValidatorsApp);