Release RuleGel 1.0.1 with Realbooru
This commit is contained in:
@@ -72,6 +72,7 @@ void main() {
|
||||
'yandere',
|
||||
'e621',
|
||||
'e926',
|
||||
'realbooru',
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:gel_rule_app/app/motion.dart';
|
||||
import 'package:gel_rule_app/backend/services/settings_service.dart';
|
||||
|
||||
void main() {
|
||||
test('app settings json roundtrip keeps motion settings', () {
|
||||
final settings = AppSettings.defaults.copyWith(
|
||||
motionRefreshMode: MotionRefreshMode.hz144.name,
|
||||
autoBatterySaver60Hz: false,
|
||||
);
|
||||
|
||||
final restored = AppSettings.fromJson(settings.toJson());
|
||||
|
||||
expect(restored.motionRefreshMode, MotionRefreshMode.hz144.name);
|
||||
expect(restored.autoBatterySaver60Hz, isFalse);
|
||||
});
|
||||
|
||||
test('battery saver forces effective 60hz below 20 percent', () {
|
||||
final motion = resolveMotionSettings(
|
||||
settings: AppSettings.defaults.copyWith(
|
||||
motionRefreshMode: MotionRefreshMode.hz165.name,
|
||||
autoBatterySaver60Hz: true,
|
||||
),
|
||||
detectedHz: 165,
|
||||
device: const DeviceMotionInfo(
|
||||
batteryLevel: 12,
|
||||
supportedRefreshRates: [60, 120, 165],
|
||||
),
|
||||
);
|
||||
|
||||
expect(motion.batterySaverActive, isTrue);
|
||||
expect(motion.effectiveHz, 60);
|
||||
});
|
||||
|
||||
test('unsupported requested refresh uses nearest supported mode', () {
|
||||
final motion = resolveMotionSettings(
|
||||
settings: AppSettings.defaults.copyWith(
|
||||
motionRefreshMode: MotionRefreshMode.hz144.name,
|
||||
),
|
||||
detectedHz: 144,
|
||||
device: const DeviceMotionInfo(
|
||||
supportedRefreshRates: [60, 120],
|
||||
),
|
||||
);
|
||||
|
||||
expect(motion.effectiveHz, 120);
|
||||
});
|
||||
}
|
||||
@@ -4,6 +4,10 @@ import 'package:gel_rule_app/backend/mappers/e621_mapper.dart';
|
||||
import 'package:gel_rule_app/backend/mappers/gelbooru_mapper.dart';
|
||||
import 'package:gel_rule_app/backend/mappers/moebooru_mapper.dart';
|
||||
import 'package:gel_rule_app/backend/mappers/rule34_mapper.dart';
|
||||
import 'package:gel_rule_app/backend/models/content_provider_config.dart';
|
||||
import 'package:gel_rule_app/backend/providers/provider_factory.dart';
|
||||
import 'package:gel_rule_app/backend/providers/realbooru_provider.dart';
|
||||
import 'package:gel_rule_app/backend/repositories/provider_repository.dart';
|
||||
|
||||
void main() {
|
||||
test('parses Gelbooru array response', () {
|
||||
@@ -46,6 +50,23 @@ void main() {
|
||||
expect(posts.single.fileType, 'gif');
|
||||
});
|
||||
|
||||
test('parses Gelbooru compatible XML post response', () {
|
||||
final posts = GelbooruMapper.postsFromResponse(
|
||||
'''
|
||||
<posts count="1">
|
||||
<post id="7" file_url="https://example.test/r.jpg" preview_url="https://example.test/r-preview.jpg" tags="real booru" rating="explicit" width="300" height="400" score="12" />
|
||||
</posts>
|
||||
''',
|
||||
providerId: 'realbooru',
|
||||
providerName: 'Realbooru',
|
||||
);
|
||||
|
||||
expect(posts.single.id, '7');
|
||||
expect(posts.single.providerId, 'realbooru');
|
||||
expect(posts.single.tags, ['real', 'booru']);
|
||||
expect(posts.single.rating, 'explicit');
|
||||
});
|
||||
|
||||
test('parses Rule34 compatible response', () {
|
||||
final posts = Rule34Mapper.postsFromResponse(
|
||||
{
|
||||
@@ -183,4 +204,32 @@ void main() {
|
||||
expect(posts.single.fileUrl, '');
|
||||
expect(posts.single.rating, 'unknown');
|
||||
});
|
||||
|
||||
test('seed providers include enabled Realbooru', () {
|
||||
final realbooru = ProviderRepository.seedProviders()
|
||||
.where((provider) => provider.id == 'realbooru')
|
||||
.single;
|
||||
|
||||
expect(realbooru.enabled, isTrue);
|
||||
expect(realbooru.apiType, 'realbooru');
|
||||
expect(realbooru.baseUrl, 'https://realbooru.com');
|
||||
});
|
||||
|
||||
test('provider factory creates Realbooru provider', () {
|
||||
final now = DateTime(2026);
|
||||
final provider = ProviderFactory().create(ContentProviderConfig(
|
||||
id: 'realbooru',
|
||||
name: 'Realbooru',
|
||||
baseUrl: 'https://realbooru.com',
|
||||
apiType: 'realbooru',
|
||||
enabled: true,
|
||||
priority: 7,
|
||||
timeoutSeconds: 20,
|
||||
customHeaders: const {},
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
));
|
||||
|
||||
expect(provider, isA<RealbooruProvider>());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:gel_rule_app/backend/models/post.dart';
|
||||
import 'package:gel_rule_app/features/post/presentation/widgets/post_tags_panel.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('post tags panel renders category rows compactly',
|
||||
(tester) async {
|
||||
final router = GoRouter(
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (_, __) => Scaffold(
|
||||
body: PostTagsPanel(
|
||||
post: _post(
|
||||
tagGroups: {
|
||||
'artist': ['artist_name'],
|
||||
'character': ['hero'],
|
||||
'general': List.generate(30, (index) => 'tag_$index'),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(MaterialApp.router(routerConfig: router));
|
||||
|
||||
expect(find.text('Artist'), findsOneWidget);
|
||||
expect(find.text('Character'), findsOneWidget);
|
||||
expect(find.text('General'), findsOneWidget);
|
||||
expect(find.text('tag_0'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
Post _post({required Map<String, List<String>> tagGroups}) {
|
||||
return Post(
|
||||
id: '1',
|
||||
providerId: 'test',
|
||||
providerName: 'Test',
|
||||
previewUrl: 'https://example.test/preview.jpg',
|
||||
sampleUrl: 'https://example.test/sample.jpg',
|
||||
fileUrl: 'https://example.test/file.jpg',
|
||||
tags: const [],
|
||||
rating: 'general',
|
||||
width: 100,
|
||||
height: 100,
|
||||
createdAt: DateTime(2026),
|
||||
fileType: 'photo',
|
||||
score: 1,
|
||||
tagGroups: tagGroups,
|
||||
);
|
||||
}
|
||||
@@ -84,6 +84,24 @@ void main() {
|
||||
expect(find.text('touhou'), findsWidgets);
|
||||
expect(applied, 'touhou');
|
||||
});
|
||||
|
||||
testWidgets('many chips stay in a single compact row', (tester) async {
|
||||
await tester.pumpWidget(_Harness(
|
||||
child: SizedBox(
|
||||
width: 320,
|
||||
child: TagInputSearchBar(
|
||||
initialValue:
|
||||
'touhou video hakurei_reimu kirisame_marisa kochiya_sanae cirno',
|
||||
onSubmitted: (_) {},
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final size = tester.getSize(find.byType(TagInputSearchBar));
|
||||
|
||||
expect(size.height, lessThan(96));
|
||||
expect(find.text('touhou'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
class _Harness extends StatelessWidget {
|
||||
|
||||
Reference in New Issue
Block a user