Initial commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/features/detail/android/android_detail_geometry.dart';
|
||||
import 'package:smplayer/features/detail/widgets/detail_scroll_progress.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('landscape banner height respects the body height limit', (
|
||||
tester,
|
||||
) async {
|
||||
late double bannerHeight;
|
||||
late double collapseExtent;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
size: Size(800, 400),
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
bannerHeight = computeAndroidDetailBannerHeight(context);
|
||||
collapseExtent = computeAndroidDetailCollapseExtent(context);
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(bannerHeight, closeTo(206.8, 0.01));
|
||||
expect(collapseExtent, closeTo(138.8, 0.01));
|
||||
});
|
||||
|
||||
testWidgets('scroll progress reaches one at the collapse extent', (
|
||||
tester,
|
||||
) async {
|
||||
late double halfProgress;
|
||||
late double completeProgress;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MediaQuery(
|
||||
data: const MediaQueryData(size: Size(400, 800)),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
halfProgress = computeDetailScrollProgress(
|
||||
context,
|
||||
120,
|
||||
collapseExtent: 240,
|
||||
);
|
||||
completeProgress = computeDetailScrollProgress(
|
||||
context,
|
||||
240,
|
||||
collapseExtent: 240,
|
||||
);
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(halfProgress, 0.5);
|
||||
expect(completeProgress, 1.0);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/core/contracts/library.dart';
|
||||
import 'package:smplayer/features/detail/emby_detail_helpers.dart';
|
||||
|
||||
void main() {
|
||||
group('detailNavTitle', () {
|
||||
test('uses series name for selected episode', () {
|
||||
const episode = EmbyRawItem(
|
||||
Id: 'ep1',
|
||||
Name: '第 1 集',
|
||||
Type: 'Episode',
|
||||
SeriesName: '我的剧',
|
||||
);
|
||||
|
||||
expect(detailNavTitle(episode, null), '我的剧');
|
||||
});
|
||||
|
||||
test('uses loaded series item before episode name', () {
|
||||
const episode = EmbyRawItem(
|
||||
Id: 'ep1',
|
||||
Name: '第 1 集',
|
||||
Type: 'Episode',
|
||||
);
|
||||
const series = EmbyRawItem(Id: 'series1', Name: '正片剧名', Type: 'Series');
|
||||
|
||||
expect(detailNavTitle(episode, series), '正片剧名');
|
||||
});
|
||||
|
||||
test('keeps movie title', () {
|
||||
const movie = EmbyRawItem(Id: 'movie1', Name: '电影名', Type: 'Movie');
|
||||
|
||||
expect(detailNavTitle(movie, null), '电影名');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/core/contracts/library.dart';
|
||||
import 'package:smplayer/features/detail/model/selected_episode_merge.dart';
|
||||
|
||||
void main() {
|
||||
group('applyPlaybackReturnProgress', () {
|
||||
test('overrides stale playback position', () {
|
||||
const item = EmbyRawItem(
|
||||
Id: 'ep1',
|
||||
Name: 'Episode 1',
|
||||
UserData: EmbyRawUserData(PlaybackPositionTicks: 10),
|
||||
);
|
||||
|
||||
final updated = applyPlaybackReturnProgress(item, 500);
|
||||
|
||||
expect(updated.UserData?.PlaybackPositionTicks, 500);
|
||||
});
|
||||
|
||||
test('creates UserData when detail has none', () {
|
||||
const item = EmbyRawItem(Id: 'movie1', Name: 'Movie 1');
|
||||
|
||||
final updated = applyPlaybackReturnProgress(item, 300);
|
||||
|
||||
expect(updated.UserData?.PlaybackPositionTicks, 300);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/core/contracts/library.dart';
|
||||
import 'package:smplayer/features/detail/widgets/stream_selector_actions.dart';
|
||||
|
||||
void main() {
|
||||
const chineseSubtitle = EmbyRawMediaStream(
|
||||
Type: 'Subtitle',
|
||||
Language: 'chi',
|
||||
DisplayTitle: 'Chinese Simplified (SRT)',
|
||||
);
|
||||
const untitledSubtitle = EmbyRawMediaStream(Type: 'Subtitle');
|
||||
const dtsAudio = EmbyRawMediaStream(
|
||||
Type: 'Audio',
|
||||
Language: 'eng',
|
||||
DisplayTitle: 'DTS 5.1',
|
||||
);
|
||||
const untitledAudio = EmbyRawMediaStream(Type: 'Audio');
|
||||
|
||||
group('subtitleSummaryLabel', () {
|
||||
test('returns 关闭 when no subtitle selected', () {
|
||||
expect(subtitleSummaryLabel(const [chineseSubtitle], null), '关闭');
|
||||
});
|
||||
|
||||
test('returns 关闭 when index is out of range', () {
|
||||
expect(subtitleSummaryLabel(const [chineseSubtitle], 5), '关闭');
|
||||
});
|
||||
|
||||
test('prefers Language over DisplayTitle for the compact button', () {
|
||||
expect(subtitleSummaryLabel(const [chineseSubtitle], 0), 'chi');
|
||||
});
|
||||
|
||||
test('falls back to positional label when stream has no metadata', () {
|
||||
expect(
|
||||
subtitleSummaryLabel(const [chineseSubtitle, untitledSubtitle], 1),
|
||||
'字幕 2',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('audioSummaryLabel', () {
|
||||
test('returns 默认 when index is out of range', () {
|
||||
expect(audioSummaryLabel(const [dtsAudio], 3), '默认');
|
||||
});
|
||||
|
||||
test('prefers Language over DisplayTitle for the compact button', () {
|
||||
expect(audioSummaryLabel(const [dtsAudio], 0), 'eng');
|
||||
});
|
||||
|
||||
test('falls back to positional label when stream has no metadata', () {
|
||||
expect(audioSummaryLabel(const [dtsAudio, untitledAudio], 1), '音轨 2');
|
||||
});
|
||||
});
|
||||
|
||||
group('versionSummaryLabel', () {
|
||||
const namedSource = EmbyRawMediaSource(Id: 'a', Name: '4K HDR 版本');
|
||||
const unnamedSource = EmbyRawMediaSource(Id: 'b');
|
||||
|
||||
test('uses the source name when present', () {
|
||||
expect(
|
||||
versionSummaryLabel(const [namedSource, unnamedSource], 0),
|
||||
'4K HDR 版本',
|
||||
);
|
||||
});
|
||||
|
||||
test('falls back to positional label when the source has no name', () {
|
||||
expect(
|
||||
versionSummaryLabel(const [namedSource, unnamedSource], 1),
|
||||
'版本 2',
|
||||
);
|
||||
});
|
||||
|
||||
test('falls back to 版本 when index is out of range', () {
|
||||
expect(versionSummaryLabel(const [namedSource], 9), '版本');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user