mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-07-29 15:28:48 +02:00
fix(convert): simplify output names and harden writes
This commit is contained in:
@@ -47,20 +47,18 @@ void main() {
|
||||
});
|
||||
|
||||
group('kept conversion output identity', () {
|
||||
test('uses a distinct filename when the original is retained', () {
|
||||
test('keeps the original base name and only changes the extension', () {
|
||||
expect(
|
||||
convertedOutputFileName(
|
||||
originalFileName: 'Track.flac',
|
||||
targetFormat: 'FLAC',
|
||||
keepOriginal: true,
|
||||
),
|
||||
'Track_converted.flac',
|
||||
'Track.flac',
|
||||
);
|
||||
expect(
|
||||
convertedOutputFileName(
|
||||
originalFileName: 'Track.flac',
|
||||
targetFormat: 'MP3',
|
||||
keepOriginal: false,
|
||||
),
|
||||
'Track.mp3',
|
||||
);
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:spotiflac_android/l10n/app_localizations.dart';
|
||||
import 'package:spotiflac_android/models/unified_library_item.dart';
|
||||
import 'package:spotiflac_android/services/batch_track_actions.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets(
|
||||
'batch conversion keeps a valid context after its launcher is removed',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(
|
||||
const ProviderScope(
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: _BatchConvertHarness(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(const Key('open-batch-convert')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final convertButton = find.widgetWithText(
|
||||
FilledButton,
|
||||
'Convert 1 track',
|
||||
);
|
||||
await tester.scrollUntilVisible(
|
||||
convertButton,
|
||||
300,
|
||||
scrollable: find.byType(Scrollable).last,
|
||||
);
|
||||
await tester.tap(convertButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(AlertDialog), findsOneWidget);
|
||||
expect(
|
||||
find.textContaining('Original files will be deleted'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _BatchConvertHarness extends ConsumerStatefulWidget {
|
||||
const _BatchConvertHarness();
|
||||
|
||||
@override
|
||||
ConsumerState<_BatchConvertHarness> createState() =>
|
||||
_BatchConvertHarnessState();
|
||||
}
|
||||
|
||||
class _BatchConvertHarnessState extends ConsumerState<_BatchConvertHarness> {
|
||||
bool _showLauncher = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: _showLauncher
|
||||
? Builder(
|
||||
builder: (launcherContext) => FilledButton(
|
||||
key: const Key('open-batch-convert'),
|
||||
onPressed: () => showBatchConvertSheet(
|
||||
launcherContext,
|
||||
ref,
|
||||
[
|
||||
UnifiedLibraryItem(
|
||||
id: 'track-1',
|
||||
trackName: 'Track',
|
||||
artistName: 'Artist',
|
||||
albumName: 'Album',
|
||||
filePath: '/music/track.flac',
|
||||
addedAt: DateTime(2026),
|
||||
source: LibraryItemSource.local,
|
||||
),
|
||||
],
|
||||
onExitSelectionMode: () {},
|
||||
onSheetOpen: () => setState(() => _showLauncher = false),
|
||||
),
|
||||
child: const Text('Open'),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:spotiflac_android/services/conversion_library_service.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
const channel = MethodChannel('com.zarz.spotiflac/backend');
|
||||
|
||||
tearDown(() async {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(channel, null);
|
||||
});
|
||||
|
||||
test(
|
||||
'SAF conversion removes _converted and retries a transient write',
|
||||
() async {
|
||||
var attempts = 0;
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(channel, (call) async {
|
||||
expect(call.method, 'safCreateUniqueFromPath');
|
||||
expect((call.arguments as Map)['file_name'], 'Song.mp3');
|
||||
attempts++;
|
||||
if (attempts == 1) {
|
||||
throw PlatformException(code: 'temporary_io');
|
||||
}
|
||||
return jsonEncode({
|
||||
'uri': 'content://music/Song%20(2).mp3',
|
||||
'file_name': 'Song (2).mp3',
|
||||
});
|
||||
});
|
||||
|
||||
final published = await ConversionLibraryService.publishSafConversion(
|
||||
treeUri: 'content://music/tree/root',
|
||||
relativeDir: 'Album',
|
||||
originalFileName: 'Song.flac',
|
||||
targetFormat: 'mp3',
|
||||
sourcePath: '/tmp/Song.mp3',
|
||||
keepOriginal: true,
|
||||
);
|
||||
|
||||
expect(attempts, 2);
|
||||
expect(published?.fileName, 'Song (2).mp3');
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'same-format replacement reuses the original SAF document name',
|
||||
() async {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(channel, (call) async {
|
||||
expect(call.method, 'safCreateFromPath');
|
||||
expect((call.arguments as Map)['file_name'], 'Song.flac');
|
||||
return 'content://music/Song.flac';
|
||||
});
|
||||
|
||||
final published = await ConversionLibraryService.publishSafConversion(
|
||||
treeUri: 'content://music/tree/root',
|
||||
relativeDir: 'Album',
|
||||
originalFileName: 'Song.flac',
|
||||
targetFormat: 'flac',
|
||||
sourcePath: '/tmp/Song.flac',
|
||||
keepOriginal: false,
|
||||
);
|
||||
|
||||
expect(published?.fileName, 'Song.flac');
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user