Catalog · How the catalog works
loader
Программа, реализующая динамическую загрузку dll, и работу с функционалом в них через интерфейсы
- ★ 1 on GitHub
Anyone may press Interesting, signed in or not. It helps others find this project.
README
Проект loader — Описание архитектуры и функциональности
Общая архитектура
Проект loader — это модульное Delphi-приложение с архитектурой плагинов, реализованное на основе COM-интерфейсов (через safecall). Проект состоит из трёх основных частей:
Common— разделяемая библиотека (ядро), содержащая интерфейсы, менеджер плагинов, пул потоков, хелперы для виртуальных деревьев и мониторинг FireDAC.CommonModules— общие модули данных (в частности,dmSkinsдля централизованного управления скинами DevExpress).Loader— основное приложение (loader.exe) и набор плагинов в виде DLL (7 зарегистрированных плагинов + вспомогательные библиотеки).
Часть 1: Common (ядро системы)
Интерфейсы
Определяется иерархия интерфейсов:
IDLLIntf— базовый интерфейс любого плагина:GetDescription,Init,Fin.IDllIntfRun(наследникIDLLIntf) — плагин с методомRun(Callback, Handle)— основной контракт для запускаемых плагинов.IUsesDllManager— плагин, который умеет получать ссылку наIDllManagerдля подгрузки зависимостей.IDllIntfRunWithDeps— объединяетIDllIntfRun+IUsesDllManager. Плагины этого типа могут самостоятельно подгружать свои зависимости черезIDllManager.IDllManager— менеджер DLL:Load,UnLoad,UnloadAll,GetIntf,IsLoaded. Централизованно загружает DLL, кэширует их и раздаёт интерфейсы по GUID.IRunTask— интерфейс асинхронной задачи:Start(Command, Params) → Handle,Stop(Handle),Info.IRunTaskFindInDir— поиск файлов по маске в каталоге (наследникIRunTask).IRunTaskFindInExeFile— поиск байтовых последовательностей внутри exe-файла (наследникIRunTask).IRunTaskShellExecute— асинхронный запуск shell-команд (наследникIRunTask).ISimpleNumbers,ICalcPrice,IExplorer,IRunTasks,ILogData,IPartsCatalog,IAnalyticDashboard— доменные интерфейсы конкретных плагинов.
Тип TDLLInfo — структура-дескриптор DLL (имя файла, имя init-функции, имя интерфейса, GUID), используется для регистрации/загрузки. В intf_common.pas определены функции-фабрики: DISimpleNumbers, DICalcPrice, DIExplorer, DIRunTaskFindInDir, DIRunTaskFindInExeFile, DIRunTaskShellExecute, DIRunTasks, DILogData, DICatalogParts, DIAnalyticDashboard.
DllManager.pas
Класс TDllManager реализует IDllManager. Ключевые особенности:
- Потокобезопасность через
TCriticalSection. - Хранит два словаря:
FProviders(имя интерфейса →IInterface) иFModules(имя файла →THandleмодуля). - При загрузке DLL (
Load) вызываетGetProcAddressпо имени init-процедуры, получая фабричную функцию, создаёт интерфейс и, если плагин поддерживаетIUsesDllManager, внедряет в него самIDllManager. - При выгрузке (
UnLoad) корректно обнуляет интерфейсные ссылки после снятия блокировки, чтобы избежать дедлоков при удалении объектов из DLL. - Имеет generic-обёртки
LoadGeneric<T>иGetIntfGeneric<T>для удобства.
cxVirtualTreeListHelper.pas
Мощный дженерик-фреймворк для TcxVirtualTreeList (DevExpress):
TVTBase/TVTBaseRecord: Базовые классы для узлов дерева с поддержкой иерархии, безопасного удаления и методаNodeMoveTo.TVTBaseDataSource<T>: Абстрактный источник данных, связывающий объекты Pascal сTcxVirtualTreeList.TVTSmartDataSource<T>: Стратегия SmartLoad (ленивая загрузка). Дети создаются только при раскрытии узла (через методInitChildrenи анонимный метод). Используется вPartsCatalogDLLиAnalyticDashboardDLLдля экономии памяти.TVTLoadAllDataSource<T>: Стратегия LoadAll (жадная загрузка). Всё дерево строится заранее, доступ осуществляется по индексу через внутреннийTObjectList. Используется для логов и статистики.
vstHelper.pas
Хелпер для TBaseVirtualTree (библиотека VirtualTree). Позволяет хранить произвольные объекты в узлах дерева через паттерн TBase → TBaseRecord с generic-методами Add<T>, Obj<T>, CurrentObj<T>.
Пул потоков
Абстракция над выполнением фоновых задач с возможностью выбора реализации через условную компиляцию:
pool_config.inc: Файл конфигурации. Содержит директиву{$define use_otl}для переключения между реализациями.uAutonomiusThreadPool.pas:TThreadPoolManager— пул потоков на базе обычныхTThread. Создаёт анонимные потоки, отслеживает их вTThreadList, при завершении потока автоматически удаляет его из списка. ПоддерживаетTerminateиFreeOnTerminate.uOmniThreadPoolManager.pas:TOmniThreadPoolManager— аналогичный пул, но на базе библиотеки OmniThreadLibrary (OTL) (IOmniTaskControl). Используется, если определёнuse_otl.
Мониторинг и логирование FireDAC
Обеспечивает перехват, форматирование и отправку SQL-запросов и их параметров во внешнее окно отладки (SQL Logger) в реальном времени:
FireDAC.Moni.Custom.Logger.pas: Базовая реализация кастомного клиента мониторинга FireDAC (TFDMoniCustomClientLinkиTFDMoniCustomClient). Позволяет перехватывать события FireDAC (выполнение команд, SQL) и передавать их через кастомный обработчик вывода (IFDMoniCustomClient), поддерживая синхронизацию с главным потоком.FDMoniCustomLoggerHelper.pas: Хелпер для удобного использования кастомного логгера. КлассTFDMoniCustomLoggerнастраивает соединение (TFDConnection) на использование кастомного мониторинга (mbCustom) и фильтрует события (толькоekCmdExecute,ekSQL). ФункцияGetFDParamsStrформатирует параметры запроса в читаемый вид SQL-переменных. ПроцедураSendMonitorMessageотправляет отформатированный SQL-запрос через механизмWM_COPYDATAв окно "SQL Logger" для отображения.
Управление скинами (intf_skin.pas, uSkinManager.pas, uSkinHelper.pas)
intf_skin.pas: Определяет контрактыISkinAware(плагин, получающий уведомления о смене темы) иISkinProvider(получение списка доступных скинов).uSkinManager.pas: Центральный классTSkinManager. Читает и сохраняет настройки (skin_name,native_style) в файлsettings.jsonрядом с EXE. Ведёт список подписчиков (FSubscribers: TInterfaceList) и рассылает им командуApplySkinпри изменении темы (Live Update). МетодPopulateSkinListзаполняетTcxComboBoxдоступными скинами DevExpress.uSkinHelper.pas: УтилитыApplySkinToFormиApplySkinToDataModuleдля быстрого применения скина кTForm,TdxRibbonиTdxLayoutControl.
Часть 2: Loader (приложение и плагины)
Главное приложение (loader.exe)
uMain.pas + uMain.dfm — основная форма с ленточным интерфейсом (DevExpress dxRibbon).
Реализует паттерн Registry + Plugin Loader:
- В
FormCreateсоздаётсяTDllManager, списокFButtons: TButtonEntryList, экземплярTdmSkinиTSkinManager. - Каждая запись
TButtonEntryсвязывает кнопку на ленте с определённым плагином (TDLLInfo). Зарегистрированы 7 кнопок:- SimpleNumbers — вычисление простых чисел
- CalcPrice — пересчёт цен с НДС
- Explorer — сканирование дисков
- RunTasks — запуск заданий
- LogData — логирование БД
- CatalogParts — каталог деталей (EAV)
- AnalyticDashboard — аналитическая панель событий PostgreSQL
LoadAllDllsзагружает все DLL черезFDllManager.Load(...), получаетGetDescriptionи устанавливает единый обработчикOnButtonClick. При загрузке каждого плагина проверяется поддержкаISkinAware, и если он реализован, плагин регистрируется вTSkinManagerдля live-обновления скинов.- При нажатии кнопки вызывается
IDllIntfRun.Run(callback, AppHandle), где callback — это лямбда, добавляющая сообщения вcxVirtualTreeList(лог). - Дополнительно инициализируется FastReport (
InitializeFastReport) — загружаетсяfrxDevDS.dllи настраивается выпадающая кнопка с действиямиDesignReportиPreviewReport.
Визуально: лента с 7 кнопками, комбобокс выбора скина, область логов внизу в виде cxVirtualTreeList с колонками «Дата» и «Сообщение», группа FastReport с выпадающей кнопкой.
Плагины (DLL)
1. SimpleNumbers (SimpleNumbersDLL)
- Интерфейс:
ISimpleNumbers : IDllIntfRun(+ методSilentRun). - Функциональность: вычисление простых чисел в диапазоне до N с использованием двух потоков.
- Два режима:
- GUI (
Run): показывает форму с двумяVirtualStringTree(по одному на поток), кнопкой запуска и спиннером для задания предела. - Silent (
SilentRun): без UI, чисто вычисление с callback-уведомлениями.
- GUI (
- Потоки используют
TInterlocked.Incrementдля атомарного раздачи чисел на проверку. Каждый поток сохраняет результаты в свой файл (thread1.txt,thread2.txt). - Проверка простоты: перебор делителей до
sqrt(N).
2. CalcPrice (CalcPriceDLL)
- Интерфейс:
ICalcPrice : IDllIntfRun(+ методCalcPrices). - Функциональность: пересчёт цен с учётом НДС. Алгоритм:
- Находит такие значения цены с НДС, чтобы цена без НДС была «красивым» числом (без дробной части после деления на
(1 + procNDS/100)). - Перебирает значения вверх и вниз с шагом 0.01, пока не найдёт подходящее.
- Находит такие значения цены с НДС, чтобы цена без НДС была «красивым» числом (без дробной части после деления на
- Форма с полями: исходная цена с НДС, процент НДС, скорректированная цена с НДС, скорректированная цена без НДС. Вычисление запускается при любом изменении значения.
- Чистая бизнес-логика вынесена в
uCalcPricesProc.pasи покрыта модульными тестами DUnitX (33 теста).
3. Explorer (ExplorerDLL)
- Интерфейс:
IExplorer : IDllIntfRunWithDeps(+ методinitFindIntf). - Функциональность: сканирование локальных дисков / конкретного каталога с фильтрацией по расширениям файлов.
- Реализует ленивую загрузку зависимости: хранит ссылку на
IRunTaskFindInDir, которое подгружает черезIDllManagerвTryLoadDependencies. - Форма: чекбоксы для выбора дисков (A–Z), поле фильтра расширений, кнопка «Сканировать». Результаты отображаются в
VirtualStringTreeс иерархией папок/файлов. При клике на файл — показ превью (текст или картинка). - Сканирование работает асинхронно через
IRunTaskFindInDir.Start(dir, extensions).
4. RunTasks (RunTasksDLL)
- Интерфейс:
IRunTasks : IDllIntfRunWithDeps. - Функциональность: оркестратор заданий. Объединяет три типа задач в единый интерфейс:
IRunTaskFindInDir— поиск файловIRunTaskFindInExeFile— поиск в exeIRunTaskShellExecute— shell-выполнение
- Поддерживает два режима инициализации зависимостей: вручную (через
initRunTasks) или автоматически черезInitViaDllManager. - Форма: комбобокс выбора типа задачи, поля для команды/параметров, кнопки Start/Stop/Show Results. Таблица заданий со статусами (выполняется, прервано, завершено, ошибка). Результаты отображаются во всплывающей панели.
5. RunTaskFind (RunTaskFindDLL)
- Интерфейсы:
IRunTaskFindInDir+IRunTaskFindInExeFile(два класса в одной DLL). TRunTaskFindInDir— рекурсивный асинхронный поиск файлов:- Используется
TScanContext— изолированный контекст на каждый запуск (защита от гонок данных). - Поддержка нескольких каталогов через
;. - Фильтрация по расширениям.
- Вызовы callback'ов с ограничением частоты (не чаще 1 раза в 2 секунды для RunCallback).
- Используется
TRunTaskFindInExeFile— поиск байтовых последовательностей в exe-файле:- Реализован алгоритм Boyer-Moore для быстрого поиска подстрок.
- Чтение файла блоками по 4 МБ с перекрытием для поиска на границах чанков.
- Поддержка поиска нескольких шаблонов через запятую.
6. RunTaskShellExecute (RunTaskShellExecuteDLL)
- Интерфейс:
IRunTaskShellExecute. - Функциональность: асинхронный запуск shell-команд через
CreateProcess. - Отслеживает хэндлы процессов, поддерживает принудительное завершение (
TerminateProcess).
7. LogData (LogDataDLL)
- Интерфейс:
ILogData : IDllIntfRun(+IUsesDllManager). - Функциональность: система логирования изменений в базах данных (PostgreSQL, MS SQL Server, Oracle).
- Три этапа работы:
- Подключение: через
TfrmConnectionsзадаётся тип БД, сервер, логин/пароль (FireDAC). - Анализ: выполняется SQL-запрос (из ресурсов
.rc), который находит все таблицы с колонками и показывает, у каких уже есть лог-таблица (_log) и триггер. - Генерация и создание: пользователь выбирает таблицы и колонки → плагин генерирует
CREATE TABLEдля лог-таблицы иCREATE TRIGGERдля отслеживания INSERT/UPDATE/DELETE, подставляя специфичный синтаксис для каждой СУБД.
- Подключение: через
- SQL-шаблоны хранятся в ресурсах (
CreateTableMSSQLTemplate.sql,logTriggerMSSQLTemplate.sqlи т.д. для PostgreSQL и Oracle). Поддерживаются типы данных, специфичные для каждой СУБД.
8. PartsCatalog (PartsCatalogDLL)
- Интерфейс:
IPartsCatalog : IDllIntfRun. - Функциональность: десктопное приложение для управления иерархическим каталогом деталей с динамическими атрибутами. Реализует паттерн Entity-Attribute-Value (EAV) для гибкого хранения характеристик деталей различных категорий.
- Технологический стек: Delphi + VCL + DevExpress (
TcxVirtualTreeList,TdxLayoutControl), PostgreSQL 12+, FireDAC. - Архитектурные особенности:
- Используется кастомный дженерик-хелпер
cxVirtualTreeListHelper.pasдля типобезопасной работы сTcxVirtualTreeList. - Реализована ленивая загрузка (SmartLoad) дерева категорий: дочерние узлы загружаются из БД только при раскрытии родительского узла, что экономит память и ускоряет отклик.
- Динамическое создание полей ввода на форме редактирования детали (
fPartEdit.pas) на основе атрибутов выбранной категории (TcxTextEditдля строк/чисел,TcxDateEditдля дат,TcxCheckBoxдля булевых значений). - Целостность данных на уровне СУБД: CHECK-ограничение
chk_single_value, триггерыtrgfn_check_required_attributesиtrgfn_check_value_type. - Разделение ответственности: UI Forms,
TCatalogService(бизнес-логика),uEntities(модели). - Импорт и Экспорт XML с upsert-логикой.
- Поддержка скинов DevExpress через
ISkinAware.
- Используется кастомный дженерик-хелпер
- Структура:
Source/(исходный код),SQL/(скрипты БД),docs/(документация),Exe/(исполняемые файлы).
9. AnalyticDashboard (AnalyticDashboardDLL)
- Интерфейс:
IAnalyticDashboard : IDllIntfRun. - Функциональность: DLL-модуль аналитической панели для основного приложения. Отображает события из PostgreSQL, предоставляет агрегированную статистику и обновляет список событий в режиме, близком к реальному времени.
- Ключевые возможности:
- Список событий:
TcxGridTableViewработает в unbound-режиме. Сначала выполняетсяCOUNT(*), затемTVirtualDataCache<TEventRecord>асинхронно загружает страницы по 1000 записей. Пока страница не загружена, отображается плейсхолдер⌛ .... Кэш хранит не более 50 страниц и вытесняет давно использовавшиеся по LRU. - Статистика:
TcxVirtualTreeListсTVTLoadAllDataSource<TEventStatsRecord>. Показывает час, источник, количество событий, среднюю задержку, скользящий тренд, процентный рост и общее количество событий. - Real-time обновления:
TRealTimePoller— отдельный поток, который раз в 1000 мс проверяет новыйMAX(id)таблицыevents, загружает дельту и добавляет новые записи в начало кэша черезPrependRecord. - Защита пула соединений:
TConnectionSemaphoreи RAII-обёрткаTSemaphoreGuardограничивают одновременные операции с пулом FireDAC. Количество слотов =PoolMaxItems - 1.
- Список событий:
- PostgreSQL: схема содержит таблицы
usersиeventsсJSONB-полемmetadata, вычисляемымTSVECTOR, индексами. Функцииget_events(постраничная выборка) иget_hourly_agg(почасовая агрегация с оконными функциями). - Архитектура:
main.pas(форма, гриды, загрузка),VirtualDataCache.pas(потокобезопасный кэш),RealTimePoller.pas(polling),uConnectionSemaphore.pas(семафор).
Схема взаимодействия
loader.exe (uMain)
├── TDllManager (загружает и кэширует все DLL)
├── TSkinManager (управление скинами, live-обновление)
├── btnSimpleNumbers → SimpleNumbers.dll (ISimpleNumbers)
├── btnCalcPrice → CalcPrice.dll (ICalcPrice)
├── btnExplorer → Explorer.dll (IExplorer)
│ └── зависит от → RunTaskFind.dll (IRunTaskFindInDir)
├── btnRunTasks → RunTasks.dll (IRunTasks)
│ └── зависит от → RunTaskFind.dll (IRunTaskFindInDir)
│ RunTaskFind.dll (IRunTaskFindInExeFile)
│ RunTaskShellExecute.dll (IRunTaskShellExecute)
├── btnLogData → LogData.dll (ILogData)
│ └── подключение к PostgreSQL / MS SQL / Oracle через FireDAC
├── btnCatalogParts → PartsCatalog.dll (IPartsCatalog)
│ └── PostgreSQL + EAV + SmartLoad через cxVirtualTreeListHelper
├── btnAnalyticDashboard → AnalyticDashboard.dll (IAnalyticDashboard)
│ └── PostgreSQL + VirtualDataCache + RealTimePoller + ConnectionSemaphore
└── bFastReport → frxDevDS.dll (IFrxDevDS)
└── DesignReport / PreviewReport для TVTBaseDataSource и TDataSetЧасть 3: Единый механизм управления скинами DevExpress
Для обеспечения согласованного внешнего вида всего приложения (главного окна и всех плагинов) реализован централизованный механизм управления скинами DevExpress, построенный на паттерне Издатель-Подписчик (Publisher-Subscriber).
Архитектура
Механизм включает следующие ключевые компоненты:
Common\intf_skin.pas— определяет контракты взаимодействия:ISkinAware— интерфейс, который реализует любой плагин (DLL), желающий получать уведомления о смене скина и применять его к своим формам.ISkinProvider— интерфейс для получения списка доступных скинов.
Common\uSkinManager.pas— центральный классTSkinManager, выступающий в роли издателя:- Хранение настроек: читает и записывает текущий скин (
skin_name) и флагnative_styleв файлsettings.jsonв папке с исполняемым файлом. - Управление UI: метод
PopulateSkinListзаполняетTcxComboBoxсписком всех доступных в системе скинов DevExpress. - Применение к главной форме: метод
ApplyToMainFormмгновенно обновляетTcxLookAndFeelи цветовую схемуTdxRibbonглавного приложения. - Live-обновление плагинов: при смене скина менеджер автоматически рассылает вызов
ApplySkinвсем зарегистрированным подписчикам (ISkinAware), обеспечивая мгновенное изменение внешнего вида открытых окон DLL без их перезагрузки.
- Хранение настроек: читает и записывает текущий скин (
Common\uSkinHelper.pas— утилитыApplySkinToFormиApplySkinToDataModuleдля быстрого применения скина к формам и дата-модулям.CommonModules\dmSkins.pas— общий DataModuleTdmSkin, содержащийTdxSkinControllerиTdxLayoutLookAndFeelListдля централизованного управления скинами на уровне приложения.
Интеграция в главное приложение (loader.exe)
- При старте создается экземпляр
TSkinManager, загружаются настройки изsettings.json. - На главной форме (
uMain.pas) размещенTcxComboBoxдля выбора скина. При его изменении вызываетсяTSkinManager.CurrentSkin := SelectedSkin, что триггерит обновление главной формы и всех подключенных DLL. - При загрузке каждого плагина главное приложение проверяет поддержку интерфейса
ISkinAware. Если он реализован, плагин регистрируется вTSkinManager, и к нему сразу применяется текущий скин. dmSkinсоздается вFormCreateи владеетTdxSkinController, который применяется ко всем формам черезuSkinHelper.
Интеграция в плагины (DLL)
Чтобы плагин поддерживал единую систему скинов, необходимо:
- Добавить модуль
intf_skinв секциюuses. - Реализовать интерфейс
ISkinAwareв главном классе плагина (например, в классе, реализующемIDllIntfRun). - В методе
ApplySkinприменить переданные параметры кRootLookAndFeelактивной формы плагина с помощьюuSkinHelper.ApplySkinToForm.
Преимущества
- Единая точка конфигурации: пользователь выбирает тему только в главном окне, настройка надежно сохраняется в
settings.json. - Отсутствие дублирования кода: логика выбора, сохранения и применения скина вынесена в переиспользуемый модуль
uSkinManager. - Мгновенное обновление (Live Update): смена скина применяется ко всем открытым окнам плагинов "на лету" без необходимости их закрывать и открывать заново.
- Масштабируемость: добавление поддержки скинов в новый плагин требует реализации всего одного короткого метода интерфейса
ISkinAware.
Часть 4: FastReport — фактическая интеграция
frxDevDS.dll
Плагин загружается отдельно от списка запускаемых DLL: Source\uMain.pas вызывает FDllManager.Load(DIFrxDevDS, False), получает IFrxDevDS и вызывает Init. Плагин не реализует IDllIntfRun, поэтому его кнопка не входит в FButtons и не обрабатывается общим OnButtonClick.
frxDevDS.dll предоставляет:
DesignReportиPreviewReportдля данныхTVTBaseDataSourceиTcxVirtualTreeList;DesignDBReportиPreviewDBReportдля отчётов с FireDAC (поддержкаTDataSet);SetCustomFunctionдля вызовов из FastScript;- экспортные компоненты PDF, XLS/XLSX, DOCX, RTF, BMP, JPEG и Mail в
dmFastReport.
loader.exe
В Source\uMain.dfm создана группа bFastReport с выпадающей кнопкой btnFastReport и действиями:
btnFRDesigner— открывает дизайнер;btnFRPreview— открывает предварительный просмотр.
Оба действия используют журнал FSLog и vtlLog как источник данных и шаблон FastReportTemplates\loader.fr3 рядом с исполняемым файлом.
PartsCatalog.dll
В PartsCatalogDLL\Source\uMain.dfm создана группа brReport с выпадающей кнопкой btnFastReport:
btnFRDesignerвызываетDesignDBReport;btnPreviewвызываетPreviewDBReport.
Перед вызовом формируется строка соединения из dmDB.PGConn, включая пароль, а запросы qryReportCategories и qryReportParts передаются в DesignDBReport. Используется шаблон FastReportTemplates\PartsCatalog.fr3 рядом с loader.exe.
Шаблон PartsCatalog.fr3 уже содержит внутренние TfrxFDQuery с именами Categories и Parts, master-detail-связь Parts.Master = Categories, а также SQL для построения дерева категорий и списка деталей. Поэтому при открытии дизайнера с существующим шаблоном SQL, переданный из PartsCatalog, фактически не применяется: текущая реализация DesignDBReport загружает шаблон вместо добавления переданных наборов.
Ограничения текущей реализации
PreviewReportиPreviewDBReportоткрывают отчёт только при непустом существующем шаблоне; иначе завершаются без уведомления вызывающего кода.CreateReportPageне создаёт страницу для полностью пустогоTfrxReport, поскольку выполняется только приPagesCount > 0.
Часть 5: Модульное тестирование (DUnitX)
Проект включает набор модульных тестов на базе DUnitX для ключевых компонентов. Тесты расположены в loader\loader\DUnitXTests\ и организованы по подкаталогам:
Структура тестов
| Подкаталог | Тестируемый компонент | Приоритет |
|---|---|---|
DLLManagerTests |
Common\DllManager.pas — загрузка/выгрузка DLL, потокобезопасность |
P0 |
cxVirtualTreeListHelperTests |
Common\cxVirtualTreeListHelper.pas — дженерик-фреймворк TVT |
P0 |
frxDevCustomDataSetTests |
loader\frxDevDS\frxDevCustomDataSet.pas — адаптер для FastReport |
P1 |
CalcPriceTests |
loader\CalcPriceDLL\uCalcPricesProc.pas — расчёт цен с НДС |
P1 |
VirtualDataCacheTests |
loader\AnalyticDashboardDLL\Source\VirtualDataCache.pas — виртуальный кэш |
P2 |
CatalogServiceTests |
loader\PartsCatalogDLL\Source\uCatalogService.pas — сервис каталога |
P2 |
Примеры тестов
- DllManager: успешная загрузка/выгрузка, обработка ошибок (файл не найден, функция не найдена, InitProc вернул nil), потокобезопасность (4 потока × 20 циклов Load/Unload), generic-обёртки.
- cxVirtualTreeListHelper: создание иерархии (
TVTBase),DeleteChildren,NodeMoveTo,InsertRecordHandle,DeleteRecord,Clear, LRU-переупорядочивание. - VirtualDataCache: попадание/промах кэша, LRU eviction,
PrependRecord, защита от дубликатов загрузки страниц. - CatalogService: CRUD операции, транзакции, обработка FK-нарушений, валидация типов атрибутов.
- CalcPrice: функция
CheckNum(проверка денежного представления),CalcPricesProcдля различных ставок НДС (0%, 10%, 20%), граничные случаи (0.00, 0.01, 1_200_000.00).
Организация
Каждый подкаталог содержит:
*Fixture.dpr— главный файл проекта DUnitX (консольное приложение)*Fixture.dproj— файл проекта Delphiu*Fixture.pas— исходный код тестовых кейсов*Fixture.md— подробная спецификация и дизайн-документ тестовexe\— каталог выходных файлов (содержит*Fixture.exeиdunitx-results.xml)
Текущий статус: Все тесты проходят успешно.
Итого
Проект представляет собой фреймворк плагинной архитектуры на Delphi с демонстрационными и продуктовыми плагинами. Ядром фреймворка является Common с определениями интерфейсов, менеджером загрузки DLL, пулом потоков, фреймворком для виртуальных деревьев и мониторингом FireDAC.
Приложение-лоадер динамически подгружает 7 DLL-плагинов, каждый из которых предоставляет свою функциональность:
- SimpleNumbers — вычисление простых чисел
- CalcPrice — расчёт цен с НДС
- Explorer — файловый менеджер
- RunTasks — оркестратор задач
- LogData — генерация SQL-триггеров для аудита БД
- PartsCatalog — управление каталогом деталей (EAV) с PostgreSQL
- AnalyticDashboard — аналитическая панель событий с real-time polling и виртуальным кэшем
Дополнительно интегрирована библиотека FastReport (frxDevDS.dll) для построения отчётов, а также реализован единый механизм управления скинами DevExpress с live-обновлением всех плагинов.
Проект покрыт модульными тестами DUnitX для ключевых компонентов, что обеспечивает надёжность и возможность рефакторинга.

