Files
jpmschweitzerandClaude 05948b41a6 fix(analysis): clear the five findings blocking the pre-push gate
flutter analyze exits non-zero on info-level findings too, so all five had to
go for `make pre-push` to pass. Four were mechanical. The fifth was not.

envApiUser was reported as an unused declaration. Removing it revealed that the
field behind it, _envApiUser, was then unused as well -- and the pair turns out
to be a closed loop nothing could enter: the getter is public but sits on
_DashboardContentState, a private class, so no caller outside this file could
ever have reached it. The field was written once per session and never read.
The debugPrint next to it logs envData.user directly, so the logging the
comment describes never depended on the stored copy. Field, getter and
assignment removed; _hasLoggedEnvUser stays, because it genuinely guards the
log-once.

Deleting the first warning exposing the second is the useful part: unused_field
could not fire while a dead getter was "using" it. Dead code hides dead code.

The two `if (x != null) x` collection entries become null-aware elements, which
is the same intent spelled the way the SDK now expects. The two casts in
data_grid_test were the second cast of a pair -- `mode as InfiniteDataMode` on
the preceding line already promotes the local.

flutter analyze: No issues found. The edited test file still passes all 37.

Note the gate still prints "not gated here yet: test (T-56)" -- analysis is
green, tests remain unwired, and that is deliberately left visible.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-11 12:49:05 +02:00

411 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tatlock_ui/shared/components/data_grid/data_grid_column.dart';
import 'package:tatlock_ui/shared/components/data_grid/data_grid_config.dart';
import 'package:tatlock_ui/shared/components/data_grid/data_grid_state.dart';
import '../../../harness/test_harness.dart';
/// Test data class for DataGrid tests.
class TestItem {
const TestItem({
required this.id,
required this.name,
required this.value,
this.isActive = true,
});
final String id;
final String name;
final int value;
final bool isActive;
}
void main() {
final harness = TestHarness();
setUp(() => harness.setUp());
tearDown(() => harness.tearDown());
group('DataGridColumn', () {
test('creates column with required fields', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
);
expect(column.id, 'name');
expect(column.header, 'Name');
expect(column.sortable, isFalse);
expect(column.searchable, isFalse);
});
test('creates sortable column', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
sortable: true,
);
expect(column.sortable, isTrue);
});
test('creates searchable column', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
searchable: true,
);
expect(column.searchable, isTrue);
});
test('valueBuilder extracts correct value', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
);
final item = TestItem(id: '1', name: 'Test Item', value: 42);
expect(column.valueBuilder(item), 'Test Item');
});
test('supports fixed width', () {
final column = DataGridColumn<TestItem>(
id: 'id',
header: 'ID',
valueBuilder: (item) => item.id,
width: const DataGridColumnWidth.fixed(100),
);
expect(column.width, isA<GridFixedWidth>());
expect((column.width as GridFixedWidth).width, 100);
});
test('supports flex width', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
width: const DataGridColumnWidth.flex(2),
);
expect(column.width, isA<GridFlexWidth>());
expect((column.width as GridFlexWidth).flex, 2);
});
test('default width is flex(1)', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
);
expect(column.width, isA<GridFlexWidth>());
expect((column.width as GridFlexWidth).flex, 1);
});
test('supports custom alignment', () {
final column = DataGridColumn<TestItem>(
id: 'value',
header: 'Value',
valueBuilder: (item) => item.value.toString(),
alignment: DataGridColumnAlignment.end,
);
expect(column.alignment, DataGridColumnAlignment.end);
expect(column.textAlign, TextAlign.end);
expect(column.crossAxisAlignment, CrossAxisAlignment.end);
});
test('effectiveSortField defaults to lowercase header', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Full Name',
valueBuilder: (item) => item.name,
);
expect(column.effectiveSortField, 'full name');
});
test('effectiveSortField uses sortField when provided', () {
final column = DataGridColumn<TestItem>(
id: 'name',
header: 'Full Name',
valueBuilder: (item) => item.name,
sortField: 'name',
);
expect(column.effectiveSortField, 'name');
});
});
group('DataGridConfig', () {
test('creates config with columns', () {
final config = DataGridConfig<TestItem>(
columns: [
DataGridColumn<TestItem>(
id: 'id',
header: 'ID',
valueBuilder: (item) => item.id,
),
DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
),
],
);
expect(config.columns.length, 2);
});
test('enableSearch defaults to false', () {
final config = DataGridConfig<TestItem>(
columns: [],
);
expect(config.enableSearch, isFalse);
});
test('enables search when specified', () {
final config = DataGridConfig<TestItem>(
columns: [
DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
searchable: true,
),
],
enableSearch: true,
);
expect(config.enableSearch, isTrue);
});
test('supports custom search hint', () {
final config = DataGridConfig<TestItem>(
columns: [],
enableSearch: true,
searchHint: 'Search items...',
);
expect(config.searchHint, 'Search items...');
});
test('supports row selection mode', () {
final config = DataGridConfig<TestItem>(
columns: [],
rowsSelectable: true,
);
expect(config.rowsSelectable, isTrue);
});
test('visibleColumns filters hidden columns', () {
final config = DataGridConfig<TestItem>(
columns: [
DataGridColumn<TestItem>(
id: 'id',
header: 'ID',
valueBuilder: (item) => item.id,
visible: false,
),
DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
),
],
);
expect(config.visibleColumns.length, 1);
expect(config.visibleColumns.first.id, 'name');
});
test('searchableColumnIndices returns correct indices', () {
final config = DataGridConfig<TestItem>(
columns: [
DataGridColumn<TestItem>(
id: 'id',
header: 'ID',
valueBuilder: (item) => item.id,
),
DataGridColumn<TestItem>(
id: 'name',
header: 'Name',
valueBuilder: (item) => item.name,
searchable: true,
),
DataGridColumn<TestItem>(
id: 'value',
header: 'Value',
valueBuilder: (item) => item.value.toString(),
searchable: true,
),
],
);
expect(config.searchableColumnIndices, [1, 2]);
});
});
group('DataGridState', () {
test('creates initial state with defaults', () {
const state = DataGridState<TestItem>();
expect(state.items, isEmpty);
expect(state.isLoading, isFalse);
expect(state.selectedIds, isEmpty);
expect(state.searchQuery, isEmpty);
expect(state.isInitialLoad, isTrue);
});
test('creates loading state', () {
const state = DataGridState<TestItem>(
isLoading: true,
);
expect(state.isLoading, isTrue);
});
test('stores items', () {
final items = [
const TestItem(id: '1', name: 'Item 1', value: 10),
const TestItem(id: '2', name: 'Item 2', value: 20),
];
final state = DataGridState<TestItem>(
items: items,
isLoading: false,
);
expect(state.items.length, 2);
expect(state.items[0].name, 'Item 1');
});
test('stores selected IDs', () {
const state = DataGridState<TestItem>(
selectedIds: {'1', '2', '3'},
);
expect(state.selectedIds.length, 3);
expect(state.selectedIds.contains('1'), isTrue);
});
test('stores search query', () {
const state = DataGridState<TestItem>(
searchQuery: 'test query',
);
expect(state.searchQuery, 'test query');
});
test('stores sort column index', () {
const state = DataGridState<TestItem>(
sortColumnIndex: 1,
sortDescending: true,
);
expect(state.sortColumnIndex, 1);
expect(state.sortDescending, isTrue);
});
test('stores error', () {
const state = DataGridState<TestItem>(
error: 'Something went wrong',
);
expect(state.error, 'Something went wrong');
});
test('stores pagination info', () {
const state = DataGridState<TestItem>(
currentPage: 2,
totalCount: 100,
);
expect(state.currentPage, 2);
expect(state.totalCount, 100);
});
});
group('DataGridColumnWidth', () {
test('fixed width creates GridFixedWidth', () {
const width = DataGridColumnWidth.fixed(150);
expect(width, isA<GridFixedWidth>());
expect((width as GridFixedWidth).width, 150);
});
test('flex width creates GridFlexWidth', () {
const width = DataGridColumnWidth.flex(2);
expect(width, isA<GridFlexWidth>());
expect((width as GridFlexWidth).flex, 2);
});
test('default flex is 1', () {
const width = DataGridColumnWidth.flex();
expect((width as GridFlexWidth).flex, 1);
});
test('fraction width creates GridFractionWidth', () {
const width = DataGridColumnWidth.fraction(0.5);
expect(width, isA<GridFractionWidth>());
expect((width as GridFractionWidth).fraction, 0.5);
});
});
group('DataGridColumnAlignment', () {
test('has start alignment', () {
expect(DataGridColumnAlignment.start, isNotNull);
});
test('has center alignment', () {
expect(DataGridColumnAlignment.center, isNotNull);
});
test('has end alignment', () {
expect(DataGridColumnAlignment.end, isNotNull);
});
});
group('DataGridDataMode', () {
test('all mode', () {
const mode = DataGridDataMode.all();
expect(mode, isA<AllDataMode>());
});
test('paginated mode with default page size', () {
const mode = DataGridDataMode.paginated();
expect(mode, isA<PaginatedDataMode>());
expect((mode as PaginatedDataMode).pageSize, 25);
});
test('paginated mode with custom page size', () {
const mode = DataGridDataMode.paginated(pageSize: 50);
expect((mode as PaginatedDataMode).pageSize, 50);
});
test('infinite mode with defaults', () {
const mode = DataGridDataMode.infinite();
expect(mode, isA<InfiniteDataMode>());
expect((mode as InfiniteDataMode).initialLoad, 50);
expect(mode.loadMoreThreshold, 10);
});
test('infinite mode with custom values', () {
const mode = DataGridDataMode.infinite(
initialLoad: 100,
loadMoreThreshold: 20,
);
expect((mode as InfiniteDataMode).initialLoad, 100);
expect(mode.loadMoreThreshold, 20);
});
});
}