jellyfin_genre_catalog_test.dart 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. import 'package:cardash_launcher/data/models/jellyfin_library.dart';
  2. import 'package:cardash_launcher/data/services/jellyfin_genre_catalog.dart';
  3. import 'package:flutter_test/flutter_test.dart';
  4. const _userGenres = <String>[
  5. '1989',
  6. 'Acoustic',
  7. 'Alternative',
  8. 'Alternative Metal',
  9. 'Alternative Rock',
  10. 'ambient',
  11. 'atmospheric black metal',
  12. 'Avant-Garde',
  13. 'avant-garde metal',
  14. 'Black',
  15. 'Black Metal',
  16. 'Blues',
  17. 'Blues Rock',
  18. 'Canzone Italiana',
  19. 'Classical',
  20. 'Comedy',
  21. 'Composer',
  22. 'Conductor',
  23. 'Country',
  24. 'country rock',
  25. 'Dance',
  26. 'dark ambient',
  27. 'dark folk',
  28. 'Death',
  29. 'Death Metal',
  30. 'death-doom metal',
  31. 'depressive black metal',
  32. 'Doom Metal',
  33. 'dungeon synth',
  34. 'Electro',
  35. 'electronic',
  36. 'Film Scores',
  37. 'Films/Games',
  38. 'Folk',
  39. 'Folk Metal',
  40. 'funeral doom metal',
  41. 'Funk',
  42. 'Fusion',
  43. 'glam metal',
  44. 'gothic',
  45. 'Gothic Doom Metal',
  46. 'Gothic Metal',
  47. 'Gothic Rock',
  48. 'groove metal',
  49. 'Grunge',
  50. 'Hard Rock',
  51. 'Hardcore',
  52. 'Heavy metal',
  53. 'Indie Rock',
  54. 'industrial metal',
  55. 'International Pop',
  56. 'Jazz',
  57. 'Latin',
  58. 'Latin Music',
  59. 'medieval',
  60. 'Melodic Black Metal',
  61. 'Melodic Death Metal',
  62. 'Melodic Metal',
  63. 'Metal',
  64. 'neofolk',
  65. 'New Age',
  66. 'Pagan',
  67. 'pagan black metal',
  68. 'pagan folk',
  69. 'Pop',
  70. 'Pop-Rock',
  71. 'Progressive',
  72. 'Progressive Metal',
  73. 'Progressive Rock',
  74. 'punk',
  75. 'R&B',
  76. 'ritual ambient',
  77. 'Rock',
  78. 'Rock & Roll',
  79. 'Rock Pop',
  80. 'Rock Singer-Songwriter',
  81. 'Rockabilly',
  82. 'Singer & Songwriter',
  83. 'Soul',
  84. 'Soul & Funk',
  85. 'Swing',
  86. 'Symphonic Metal',
  87. 'Symphonic Power Metal',
  88. 'symphonic rock',
  89. 'Thrash Metal',
  90. 'Viking',
  91. 'Viking Metal',
  92. 'Vocal jazz',
  93. 'Метъл',
  94. 'Рок',
  95. 'Хард рок',
  96. ];
  97. void main() {
  98. const catalog = JellyfinGenreCatalog();
  99. test('groups the whole library without losing a raw genre', () {
  100. final families = catalog.group(_userGenres);
  101. final total = families.fold<int>(
  102. 0,
  103. (sum, family) => sum + family.rawGenres.length,
  104. );
  105. expect(total, _userGenres.length);
  106. final labels = families.map((family) => family.label).toList();
  107. expect(labels.first, 'Metal');
  108. expect(labels[1], 'Rock');
  109. expect(labels[2], 'Jazz');
  110. expect(labels, contains('1989'));
  111. expect(labels, contains('Canzone Italiana'));
  112. });
  113. test('maps the requested Metal, Jazz and Rock variants', () {
  114. final families = catalog.group(_userGenres);
  115. final byLabel = {for (final family in families) family.label: family};
  116. expect(
  117. byLabel['Metal']!.rawGenres,
  118. containsAll([
  119. 'Metal',
  120. 'Melodic Metal',
  121. 'Heavy metal',
  122. 'Folk Metal',
  123. 'Gothic Metal',
  124. 'Метъл',
  125. 'Black',
  126. 'Death',
  127. 'Viking',
  128. ]),
  129. );
  130. expect(
  131. byLabel['Rock']!.rawGenres,
  132. containsAll([
  133. 'Rock',
  134. 'Hard Rock',
  135. 'Pop-Rock',
  136. 'Alternative',
  137. 'Alternative Rock',
  138. 'Grunge',
  139. 'Progressive',
  140. 'Rock & Roll',
  141. 'Rock Singer-Songwriter',
  142. 'Рок',
  143. 'Хард рок',
  144. ]),
  145. );
  146. expect(
  147. byLabel['Jazz']!.rawGenres,
  148. containsAll(['Jazz', 'Vocal jazz', 'Fusion', 'Swing']),
  149. );
  150. expect(
  151. byLabel['Pop']!.rawGenres,
  152. containsAll(['Pop', 'Rock Pop', 'International Pop']),
  153. );
  154. expect(
  155. byLabel['Folk']!.rawGenres,
  156. containsAll(['Folk', 'dark folk', 'neofolk', 'pagan folk', 'medieval']),
  157. );
  158. });
  159. test('keeps the head noun correct for hybrids', () {
  160. expect(catalog.match('Pop-Rock').id, 'rock');
  161. expect(catalog.match('Rock Pop').id, 'pop');
  162. expect(catalog.match('Blues Rock').id, 'rock');
  163. expect(catalog.match('Country Rock').id, 'rock');
  164. expect(catalog.match('Folk Metal').id, 'metal');
  165. expect(catalog.match('Gothic Metal').id, 'metal');
  166. expect(catalog.match('Gothic Rock').id, 'rock');
  167. expect(catalog.match('Symphonic Power Metal').id, 'metal');
  168. expect(catalog.match('Progressive Metal').id, 'metal');
  169. expect(catalog.match('Progressive Rock').id, 'rock');
  170. });
  171. test('maps the remaining canonical families', () {
  172. final families = catalog.group(_userGenres);
  173. final byLabel = {for (final family in families) family.label: family};
  174. expect(byLabel['Blues']!.rawGenres, contains('Blues'));
  175. expect(byLabel['Soul']!.rawGenres, containsAll(['Soul', 'Soul & Funk']));
  176. expect(byLabel['R&B']!.rawGenres, contains('R&B'));
  177. expect(
  178. byLabel['Classical']!.rawGenres,
  179. containsAll(['Classical', 'Composer', 'Conductor']),
  180. );
  181. expect(
  182. byLabel['Soundtrack']!.rawGenres,
  183. containsAll(['Film Scores', 'Films/Games']),
  184. );
  185. expect(
  186. byLabel['Electronic']!.rawGenres,
  187. containsAll(['Electro', 'electronic', 'Dance']),
  188. );
  189. expect(
  190. byLabel['Ambient']!.rawGenres,
  191. containsAll([
  192. 'ambient',
  193. 'dark ambient',
  194. 'ritual ambient',
  195. 'dungeon synth',
  196. 'New Age',
  197. ]),
  198. );
  199. expect(byLabel['Punk']!.rawGenres, containsAll(['punk', 'Hardcore']));
  200. expect(byLabel['Latin']!.rawGenres, containsAll(['Latin', 'Latin Music']));
  201. expect(byLabel['Acoustic']!.rawGenres, contains('Acoustic'));
  202. expect(byLabel['Avant-Garde']!.rawGenres, contains('Avant-Garde'));
  203. expect(byLabel['Gothic']!.rawGenres, contains('gothic'));
  204. expect(byLabel['Pagan']!.rawGenres, contains('Pagan'));
  205. expect(
  206. byLabel['Singer-Songwriter']!.rawGenres,
  207. contains('Singer & Songwriter'),
  208. );
  209. expect(byLabel['Comedy']!.rawGenres, contains('Comedy'));
  210. });
  211. test('unknown tags stay standalone', () {
  212. final match = catalog.match('Future Bass');
  213. expect(match.id, 'raw:future bass');
  214. expect(match.label, 'Future Bass');
  215. final families = catalog.group(['Future Bass', 'Metal']);
  216. expect(families.last.label, 'Future Bass');
  217. expect(families.last.isStandalone, isTrue);
  218. });
  219. test('expands selected families to raw server tags', () {
  220. final families = catalog.group(_userGenres);
  221. final raw = catalog.rawGenresFor(
  222. families: families,
  223. selectedIds: ['metal', 'jazz'],
  224. );
  225. expect(raw, contains('Метъл'));
  226. expect(raw, contains('Melodic Metal'));
  227. expect(raw, contains('Jazz'));
  228. expect(raw, contains('Swing'));
  229. expect(raw, isNot(contains('Rock')));
  230. expect(raw, isNot(contains('Pop')));
  231. });
  232. test('resolves saved selections and drops missing families', () {
  233. final families = catalog.group(_userGenres);
  234. final resolved = catalog.resolveSelections(
  235. families: families,
  236. selections: const [
  237. JellyfinGenreSelection(id: 'metal', label: 'Old metal label'),
  238. JellyfinGenreSelection(id: 'missing', label: 'Missing'),
  239. JellyfinGenreSelection(id: 'raw:1989', label: '1989'),
  240. ],
  241. );
  242. expect(resolved.length, 2);
  243. expect(resolved.first.label, 'Metal');
  244. expect(resolved.last.label, '1989');
  245. });
  246. }