Cobertura de testes#
Acreditamos que testes são essenciais para manter a qualidade do projeto. A cobertura atual já cobre boa parte do motor e do editor visual, e está sendo expandida a cada release.
Números gerais#
| Métrica | Valor |
|---|---|
| Testes unitários (sulfite_core) | 1049 |
| Testes unitários (sulfite_studio) | 982 |
| Testes unitários (sulfite_chat) | 85 |
| Testes unitários (sulfite_datasources) | 47 |
| Testes integração/e2e (macOS) | 92 |
| Total | 2255 |
| Cobertura sulfite_core | ~84% |
| Cobertura sulfite_studio | ~73% |
Por pacote#
sulfite_core — 1049 testes#
| Área | O que cobre |
|---|---|
| ExpressionEvaluator |
Aritmética
+−×÷^
, funções math (
sqrt
,
abs
,
sin
), 6 modos de arredondamento (
half_up
,
half_even
,
up
,
down
,
truncate
,
half_down
), divisão por zero, expressões inválidas
|
| ValueFormatter |
currency:BRL/USD
,
date:dd/MM/yyyy
,
datetime
,
number:N
,
integer
, null/empty
|
| ImageCache | Cache hit/miss, LRU eviction, base64 decode |
| SulfiteEngineImpl | API pública render(), pipeline completo (parse → process → render) |
| PdfRenderer | Todos os tipos de elemento, multi-banda, Header/Detail/Summary/Footer |
| FontLoader | Carregamento de fontes customizadas, cache, fallback |
| DataProcessor | Separação de rows por band, múltiplos dataSources, __bandId |
| Parser | Parsing de ReportDefinition do JSON, campos opcionais |
| ChartRenderer | Bar/Line/Pie em PDF, multi-series, ChartOptions, série vazia |
| ChartElement (model) | Parse JSON bar/line/pie, serialização, ChartSeries, ChartOptions |
| HtmlRenderer (aggregates mode) |
HtmlAggregatesSectionMode
(
always
,
fallback
,
never
) para evitar duplicação de seção de agregados no HTML
|
| invoice_chart_report | DataProcessor + PdfRenderer com 4 dataSources e 3 gráficos |
| Multiformat Export | HTML, CSV (delimitador, header), Excel (.xlsx válido) |
| Models Serialization |
fromJson/toJson
de todos os tipos de
ReportElement
, incluindo
SpacerElement
|
| IO (real / stub) | dart:io — salvar/ler arquivo; stubs para web/mobile |
| rendering_integration |
FieldElement
binding,
AggregateElement
(SUM/COUNT/AVG/MIN/MAX), relatório completo
|
| ScriptEngine | filter/sort/limit/distinct/addField, AND/OR/NOT, parâmetros injetados, printWhen |
| DataProcessor | Processamento via Stream, GroupBands; transforms replaced by scripts (RFC-016) |
| GroupBands | groupHeader/groupFooter, agregação por grupo, renderização intercalada |
| ReportParameter | Serialização JSON, campos opcionais (lookup, dependsOn, validation) |
| LookupConfig |
Round-trip JSON para variante
http
e
db
, discriminador
"source"
, fallback backward-compat, LookupOption, ValidationRule, todos os ValidationRuleTypes, campos
pageSize
/
searchOnOpen
|
| HttpLookupResolver |
Placeholders URL, cache, SSRF (reject + bypass), localhost,
127.0.0.1
, https, non-2xx, paginação com
fetchPage
, leitura de
meta.total/page/perPage
, heurística
items.length >= pageSize
|
| RestDataSourceResolver | HTTP GET/POST, expansão de {paramId}, modos strict/resilient |
| Rect/RoundedRect unification | borderRadius, migração automática de roundedRect |
| Print Filters (param injection) | Injeção de parâmetros no ScriptEngine e URLs REST |
| TablePivotHelper |
Pivot de dados flat em matriz dinâmica, aggregação (SUM/AVG/COUNT/MIN/MAX),
columnSort
(alpha/alpha_desc/value_asc/value_desc/natural),
columnOrder
fixo, totais por linha/coluna
|
| CellStyleResolver |
Avaliação de
CellStyleRule.when
, contexto com row +
value
, first-match-wins, valores truthy
|
| Table Pivot (e2e) |
Pipeline completo: dados ICMS 8 estados × 12 meses, PDF + HTML, altura dinâmica (
height: 0
),
columnOverrides
com formato/largura/align, estilos condicionais por coluna
|
| Example Reports (e2e) |
3 exemplos reais (06-grouped-sales, 07-dashboard, 08-hr-report) — 67 testes profundos: parse, geração de arquivos físicos PDF/HTML/CSV/Excel em
test_output/
, validação de conteúdo (nomes, produtos, valores formatados), estrutura HTML (DOCTYPE, Chart.js, CSS classes), cross-format data consistency, backward compat com 01-invoice
|
Guardas de performance automatizadas#
O teste test/stress/nfe_benchmark_test.dart agora inclui budgets de tempo para detectar regressões:
| Volume | Process | HTML | |
|---|---|---|---|
| 5.000 itens | <= 1200ms |
<= 3000ms |
<= 15000ms |
| 10.000 itens | <= 1800ms |
<= 5000ms |
<= 30000ms |
| 20.000 itens | <= 3000ms |
<= 9000ms |
<= 60000ms |
Para execução diagnóstica (sem falhar por budget), use:
SULFITE_SKIP_PERF_GUARD=1 flutter test test/stress/nfe_benchmark_test.dart
sulfite_datasources — 47 testes#
| Área | O que cobre |
|---|---|
| DbLookupResolver |
Query parametrizada com placeholders
{_search}
/
{_page}
/
{_page_size}
/
{_offset}
, substituição de
{_schema}
, cache por chave composta,
fetchPage
com
hasMore
,
UnresolvedConnectionException
para
connectionRef
inválido
|
| RestDataSourceResolver | HTTP GET/POST, expansão de {paramId}, modos strict/resilient |
| PostgresDataSourceResolver | Conexão, query parametrizada, mapeamento de tipos, erro de conexão |
sulfite_studio — 982 testes#
| Área | O que cobre |
|---|---|
| DesignerViewModel | addElement, removeElement, updateElement, seleção, multi-select, loadReport |
| UndoRedoManager | push, undo, redo, pilha vazia, limite de histórico |
| JSON ↔ Canvas sync | Editar JSON reflete no canvas; mover elemento atualiza o JSON editor |
| ChartEditorDialog | Trocar ChartType, add/remove série, drag-reorder, preview em tempo real |
| ChartUI (ViewModel) | Add/remove/reorder series via ViewModel, tipo muda opções disponíveis |
| PreferencesService | get/set themeMode, primaryColor, locale, reset para defaults |
| PreferencesProvider | Notificações Riverpod ao mudar prefs, propagação pelo widget tree |
| SulfiteTheme | buildTheme com cor customizada, modo claro/escuro, 8 presets animados |
| ThemeEditor | Segmented button idioma, color swatches, botão Personalizado → picker |
| SettingsScreen | 3 abas (Geral, Tema, Avançado), troca idioma, aplica tema |
| ReportValidator | IDs duplicados, bands sem elementos, dataSources sem referências |
| BandManagerDialog | Reorder bands, remover band, integração com undo |
| AddBandDialog / AddAggregateDialog | Formulários de criação, validação de campos |
| ValidationDialog | Exibição de erros e warnings com severidade |
| CanvasInteraction | Click para selecionar, drag para mover, Ctrl+Click multi-select, Escape deselect |
| CanvasRenderer | Paint, zoom, grid |
| Ruler / SnapLines | Marcações de régua, guias magnéticas |
| PropertyField / Editors | ColorPickerField, FormatPickerField, RoundingConfigEditor |
| PageSettingsPanel | Formato de página, margens |
| Toolbar / SpeedDial | Botões, estado selecionado, ações |
| chart_integration | Pipeline completo Studio: add element → edita → preview → serializa |
| TransformPipelineEditor | Adicionar/remover/reordenar operações, preview com debounce, IDs únicos |
| PrintParamsDialog | Delegação para SulfiteFilterScreen |
| SulfiteFilterScreen |
text/number/date/select, required validation, lookup loading/loaded, confirm/cancel, novos tipos
currency
/
datetime
, campo
format
|
| FilterFields (date/currency) |
Campos
date
com formatos
dd/MM/yyyy
,
yyyy-MM-dd
,
MM/dd/yyyy
; campo
currency
com máscaras BRL e US;
rounding
no blur; campo
datetime
|
| LookupListBody |
Estado de loading, erro, lista vazia,
hasMore
(scroll infinito),
awaitingInput
, seleção de item
|
| SingleSelectLookupDialog | Carregamento inicial, busca com debounce, loading state, erro com retry, seleção confirma, cancelamento, cascata de parâmetros |
| MultiselectLookupDialog |
Seleção múltipla, paginação com
fetchPage
, busca incremental,
hasMore
, confirmação/cancelamento, estado de loading por página
|
| DatasourceInspectorDialog | Renderização dos campos, edição de nome/tipo/source, validação inline |
| BandManagerDialog (integração) | Reorder completo, undo, groupHeader/groupFooter com groupBy |
| ParameterEditor | Adicionar/remover parâmetros, edição inline |
| DartEvalScriptRunner (preview) |
runForPreview
: captura de mutations via
print()
, múltiplas chamadas
setDatasource
, script Pokémon Duel completo (fighters/duel_stats/verdict_ds)
|
| DesignerViewModel (preview mutations) |
Pipeline ponta a ponta: resolver → dart_eval fallback → apply mutations →
processedData
com rows preenchidos
|
| SulfiteConsumerScreen (dart_eval) |
Contrato
runForPreview → mutations → payload.addAll
quando nenhum handler nativo está registrado
|
| RFC-022/023 (ScriptTokenContext) |
ScriptTokenContext
,
ReportIdRegistry
,
DartScriptValidator
, datasource inspector
|
| TableEditorDialog (pivot) |
Toggle pivot, campos
rowFields
/
columnField
/
valueField
, dropdown
verb
, toggles totais,
columnSort
,
columnOrder
,
columnOverrides
,
cellConditionalStyles
|
| CellStyleRulesEditor |
Add/remove regras, edição de
when
/
textColor
/
fill
/
bold
/
fontSize
, validação de expressão, color picker inline
|
| PivotTableWidget | Renderização de TableElement em modo pivot no canvas do Studio, aplicação de estilos condicionais, preview em tempo real |
sulfite_chat — 85 testes#
| Arquivo | O que cobre |
|---|---|
chat_config_test.dart |
Construção/defaults, getter
color
, getter
icon
(8 iconNames + fallback),
copyWith
(7 casos),
availableModels
(5 providers)
|
schema_validator_test.dart |
JSON válido, JSON mal-formado, campos obrigatórios (
reportId
,
reportName
,
pageSettings
,
bands
), validação por tipo de elemento (text, field, image, aggregate, line, rect, circle, chart, richText), referências de dataSource, múltiplos erros
|
report_generator_test.dart |
Extração de JSON de bloco
```json
, bloco genérico e JSON bruto; tag
<explanation>
; auto-correção em 2ª tentativa; falha após
maxAttempts
; detecção de erros de provedor (rate limit, quota, no authentication);
GenerationResult` (success/failure/attempts)
|
Integração / E2E (macOS) — 52 testes#
Executados via all_studio_tests.dart no app host (example/) com flutter test integration_test/ -d macos.
| Arquivo | Testes | O que cobre |
|---|---|---|
| validation_flow_test.dart | 7 | Validação de relatório, erros/warnings, severidade |
| end_to_end_test.dart | 4 | Pipeline completo: criar → editar → serializar → renderizar |
| designer_workflow_test.dart | 8 | Fluxo do designer: add/move/resize elementos, undo/redo |
| multi_selection_test.dart | 9 | Ctrl+Click, seleção múltipla, operações em lote |
| rfc_features_test.dart | 13 | RFCs 011-015: filtros, lookups, cascata, params REST |
| filter_flow_test.dart | 6 | RFC-015: field types, lookup loading, cascade, validação, cross-field, integração Studio |
| json_editor_perf_test.dart | 5 | Performance do JSON editor: fold/unfold, highlight, edição grande |
| rfc_022_023_test.dart | ~40 | RFC-022/023: script console, datasource inspector, validação de código Dart |
Executando os testes#
# sulfite_core
cd packages/sulfite_core
fvm flutter test
# sulfite_studio
cd packages/sulfite_studio
fvm flutter test
# sulfite_chat
cd packages/sulfite_chat
flutter test test/
# Integração / E2E (requer macOS)
cd examples/app
flutter test integration_test/all_studio_tests.dart -d macos
# Todos os e2e do example (inclui testes avulsos)
cd examples/app
flutter test integration_test/ -d macos
# RFC-043: permissões por grupo contra Postgres real
cd packages/sulfite_server
RFC043_E2E_ENABLED=1 \
SULFITE_RFC043_E2E_DATABASE_URL="$DATABASE_URL" \
dart test test/rfc043_postgres_e2e_test.dart
O E2E da RFC-043 cria um schema temporário sulfite_rfc043_e2e_*, sobe o
server com PostgresReportRepository, PostgresReportGroupRepository
e
GroupPermissionResolver, valida C3 via HTTP real e remove o schema ao final.
Ele fica desligado por padrão para não depender de rede nem de credenciais em
CI local.