Files
SpotiFLAC-Mobile/test/log_selection_test.dart
T
zarzet 019257541b refactor(logging): rename Go-era log names to native
The log buffer polls the native backend, so isFromGo, the Go log polling
methods and their private state now use native names. Comments that still
described the backend as Go are reworded. No string literals changed.
2026-10-18 22:12:29 +07:00

154 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:spotiflac_android/l10n/l10n.dart';
import 'package:spotiflac_android/screens/settings/log_screen.dart';
import 'package:spotiflac_android/utils/logger.dart';
import 'support/app_icon_finder.dart';
void main() {
test(
'native log batches notify once and preserve redaction and capacity',
() {
final buffer = LogBuffer()..clear();
var updates = 0;
void listener() => updates++;
buffer.addListener(listener);
addTearDown(() {
buffer.removeListener(listener);
buffer.clear();
});
buffer.addAll([
for (var index = 0; index < 600; index++)
LogEntry(
timestamp: DateTime(2026),
level: 'ERROR',
tag: 'Native',
message: '$index -decryption_key secret-value',
),
]);
expect(updates, 1);
expect(buffer.length, LogBuffer.maxEntries);
expect(buffer.entries.first.message, startsWith('100 '));
expect(buffer.entries.last.message, startsWith('599 '));
expect(formatLogEntries(buffer.entries), isNot(contains('secret-value')));
buffer.addAll(const []);
expect(updates, 1);
},
);
test('selected log export keeps chronological lines only', () {
final entries = [
LogEntry(
timestamp: DateTime(2026, 8, 11, 10, 20, 30, 40),
level: 'INFO',
tag: 'Search',
message: 'first',
),
LogEntry(
timestamp: DateTime(2026, 8, 11, 10, 20, 31, 50),
level: 'ERROR',
tag: 'Download',
message: 'second',
error: 'failed',
isFromNative: true,
),
];
expect(
formatLogEntries(entries),
'[10:20:30.040] [INFO] [Search] first\n'
'[10:20:31.050] [ERROR] [Native] [Download] second | failed',
);
});
test('log buffer redacts media keys and bounds exported payloads', () {
final buffer = LogBuffer()..clear();
addTearDown(buffer.clear);
buffer.add(
LogEntry(
timestamp: DateTime(2026, 8, 31),
level: 'ERROR',
tag: 'FFmpeg',
message:
'-decryption_key raw-media-key ${List.filled(5000, 'x').join()}',
),
);
final stored = buffer.entries.single.message;
expect(stored, isNot(contains('raw-media-key')));
expect(stored, contains('[REDACTED]'));
expect(stored, endsWith('...[truncated]'));
expect(stored.length, lessThan(4100));
});
testWidgets('long press selects multiple log rows for copying', (
tester,
) async {
String? clipboardText;
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
(call) async {
if (call.method == 'Clipboard.setData') {
clipboardText = (call.arguments as Map<Object?, Object?>)['text']
?.toString();
}
return null;
},
);
addTearDown(
() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
null,
),
);
LogBuffer().clear();
addTearDown(LogBuffer().clear);
LogBuffer().add(
LogEntry(
timestamp: DateTime(2026, 8, 11, 10),
level: 'ERROR',
tag: 'One',
message: 'first selected message',
),
);
LogBuffer().add(
LogEntry(
timestamp: DateTime(2026, 8, 11, 10, 0, 1),
level: 'ERROR',
tag: 'Two',
message: 'second selected message',
),
);
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const LogScreen(),
),
);
await tester.longPress(find.text('first selected message'));
await tester.pump();
expect(find.text('1 selected'), findsOneWidget);
await tester.ensureVisible(find.text('second selected message'));
await tester.pump();
await tester.tap(find.text('second selected message'));
await tester.pump();
expect(find.text('2 selected'), findsOneWidget);
await tester.tap(findAppIcon(Icons.copy));
await tester.pump();
expect(clipboardText, contains('first selected message'));
expect(clipboardText, contains('second selected message'));
expect(find.text('2 selected'), findsNothing);
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();
});
}