Add cxyz Android project structure and initial configuration
- Introduced a new Flutter project for the cxyz Android manga/comic reader, including essential files such as pubspec.yaml, AndroidManifest.xml, and Gradle configuration. - Added .gitignore files to exclude unnecessary files and directories for both the main project and Android-specific files. - Implemented initial README.md with project description, features, setup instructions, and API details for ComicLand, MangaRead, and MangaTown. - Configured analysis options and dependencies in pubspec.yaml to support Flutter development. - Established a pnpm workspace and lockfile for dependency management. - Included various Android resources such as icons, styles, and launch backgrounds for a complete application setup.
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:cxyz_android/sources/source.dart';
|
||||
import 'package:cxyz_android/sources/source_flags.dart';
|
||||
import 'package:cxyz_android/sources/comicland/comicland_source.dart';
|
||||
import 'package:cxyz_android/sources/mangaread/mangaread_source.dart';
|
||||
import 'package:cxyz_android/sources/mangaread/urls.dart';
|
||||
import 'package:cxyz_android/sources/mangatown/mangatown_source.dart';
|
||||
import 'package:cxyz_android/sources/registry.dart';
|
||||
|
||||
void main() {
|
||||
group('parseEnabledSourceIds', () {
|
||||
test('default comicland token', () {
|
||||
expect(parseEnabledSourceIds('comicland'), {SourceId.comicland});
|
||||
});
|
||||
|
||||
test('comma-separated both', () {
|
||||
expect(
|
||||
parseEnabledSourceIds('comicland,mangaread'),
|
||||
{SourceId.comicland, SourceId.mangaread},
|
||||
);
|
||||
});
|
||||
|
||||
test('mangaread only', () {
|
||||
expect(parseEnabledSourceIds('mangaread'), {SourceId.mangaread});
|
||||
});
|
||||
|
||||
test('all enables every SourceId', () {
|
||||
expect(parseEnabledSourceIds('all'), SourceId.values.toSet());
|
||||
expect(parseEnabledSourceIds('ALL'), SourceId.values.toSet());
|
||||
expect(parseEnabledSourceIds('all,mangaread'), SourceId.values.toSet());
|
||||
});
|
||||
|
||||
test('mangatown token', () {
|
||||
expect(parseEnabledSourceIds('mangatown'), {SourceId.mangatown});
|
||||
});
|
||||
|
||||
test('ignores unknown and falls back when empty', () {
|
||||
expect(parseEnabledSourceIds(''), {SourceId.comicland});
|
||||
expect(parseEnabledSourceIds('nope,also-bad'), {SourceId.comicland});
|
||||
});
|
||||
|
||||
test('trims and is case-insensitive', () {
|
||||
expect(
|
||||
parseEnabledSourceIds(' MangaRead , ComicLand '),
|
||||
{SourceId.mangaread, SourceId.comicland},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('SourceRegistry gating', () {
|
||||
test('registers only enabled ids', () {
|
||||
final reg = SourceRegistry(
|
||||
enabled: {SourceId.mangaread},
|
||||
mangaRead: MangaReadSource(),
|
||||
);
|
||||
expect(reg.all.map((s) => s.id), [SourceId.mangaread]);
|
||||
expect(reg.hasMultiple, isFalse);
|
||||
});
|
||||
|
||||
test('dual sources preserve declaration order', () {
|
||||
final reg = SourceRegistry(
|
||||
enabled: {SourceId.mangaread, SourceId.comicland},
|
||||
comicLand: ComicLandSource(),
|
||||
mangaRead: MangaReadSource(),
|
||||
);
|
||||
expect(reg.all.map((s) => s.id).toList(), [
|
||||
SourceId.comicland,
|
||||
SourceId.mangaread,
|
||||
]);
|
||||
expect(reg.hasMultiple, isTrue);
|
||||
});
|
||||
|
||||
test('all three sources preserve declaration order', () {
|
||||
final reg = SourceRegistry(
|
||||
enabled: {
|
||||
SourceId.mangatown,
|
||||
SourceId.mangaread,
|
||||
SourceId.comicland,
|
||||
},
|
||||
comicLand: ComicLandSource(),
|
||||
mangaRead: MangaReadSource(),
|
||||
mangaTown: MangaTownSource(),
|
||||
);
|
||||
expect(reg.all.map((s) => s.id).toList(), [
|
||||
SourceId.comicland,
|
||||
SourceId.mangaread,
|
||||
SourceId.mangatown,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
group('catalogMenus capabilities', () {
|
||||
test('ComicLand exposes newest, popular, official, uncensored, recommended, search', () {
|
||||
final kinds =
|
||||
ComicLandSource().catalogMenus.map((m) => m.kind).toList();
|
||||
expect(kinds, [
|
||||
CatalogMenuKind.latest,
|
||||
CatalogMenuKind.popular,
|
||||
CatalogMenuKind.official,
|
||||
CatalogMenuKind.uncensored,
|
||||
CatalogMenuKind.recommended,
|
||||
CatalogMenuKind.search,
|
||||
]);
|
||||
expect(
|
||||
ComicLandSource().catalogMenus.first.title,
|
||||
'Newest',
|
||||
);
|
||||
});
|
||||
|
||||
test('MangaRead exposes latest and search only', () {
|
||||
final kinds =
|
||||
MangaReadSource().catalogMenus.map((m) => m.kind).toList();
|
||||
expect(kinds, [
|
||||
CatalogMenuKind.latest,
|
||||
CatalogMenuKind.search,
|
||||
]);
|
||||
expect(kinds.contains(CatalogMenuKind.popular), isFalse);
|
||||
});
|
||||
|
||||
test('MangaTown exposes latest, hot variants, directory, search', () {
|
||||
final kinds =
|
||||
MangaTownSource().catalogMenus.map((m) => m.kind).toList();
|
||||
expect(kinds, [
|
||||
CatalogMenuKind.latest,
|
||||
CatalogMenuKind.popular,
|
||||
CatalogMenuKind.hotToday,
|
||||
CatalogMenuKind.hotWeek,
|
||||
CatalogMenuKind.hotMonth,
|
||||
CatalogMenuKind.directory,
|
||||
CatalogMenuKind.search,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
group('mangaread urls', () {
|
||||
test('mangaSlugFromUrl', () {
|
||||
expect(
|
||||
mangaSlugFromUrl(
|
||||
'https://www.mangaread.org/manga/the-chaebeols-youngest-son/chapter-560/',
|
||||
),
|
||||
'the-chaebeols-youngest-son',
|
||||
);
|
||||
});
|
||||
|
||||
test('mangaBaseUrlFromListingUrl', () {
|
||||
expect(
|
||||
mangaBaseUrlFromListingUrl(
|
||||
'https://www.mangaread.org/manga/foo-bar/chapter-1/',
|
||||
),
|
||||
'https://www.mangaread.org/manga/foo-bar/',
|
||||
);
|
||||
});
|
||||
|
||||
test('listingUrlForSlug', () {
|
||||
expect(
|
||||
listingUrlForSlug('foo-bar'),
|
||||
'https://www.mangaread.org/manga/foo-bar/',
|
||||
);
|
||||
});
|
||||
|
||||
test('chapterNumberFromTitle', () {
|
||||
expect(chapterNumberFromTitle('Chapter 560'), '560');
|
||||
expect(chapterNumberFromTitle('Ch. 12.5'), '12.5');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user