binary-versions.test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /**
  2. * Binary Version Management Tests
  3. * Tests for version checking, comparison, and display functionality
  4. */
  5. import { describe, it, expect, beforeEach } from 'vitest';
  6. /**
  7. * Mock version comparison function (same logic as in main.js)
  8. * Compares two version strings (e.g., "2024.01.15" vs "2024.01.10")
  9. * @param {string} v1 - First version string
  10. * @param {string} v2 - Second version string
  11. * @returns {number} 1 if v1 > v2, -1 if v1 < v2, 0 if equal
  12. */
  13. function compareVersions(v1, v2) {
  14. if (!v1 || !v2) return 0;
  15. const parts1 = v1.split('.').map(p => parseInt(p, 10));
  16. const parts2 = v2.split('.').map(p => parseInt(p, 10));
  17. const maxLength = Math.max(parts1.length, parts2.length);
  18. for (let i = 0; i < maxLength; i++) {
  19. const num1 = parts1[i] || 0;
  20. const num2 = parts2[i] || 0;
  21. if (num1 > num2) return 1;
  22. if (num1 < num2) return -1;
  23. }
  24. return 0;
  25. }
  26. /**
  27. * Format version string for display
  28. * @param {string} version - Version string from binary
  29. * @returns {string} Formatted version
  30. */
  31. function formatVersion(version) {
  32. if (!version || version === 'unknown') return '--';
  33. // Truncate long versions (ffmpeg has very long version strings)
  34. if (version.length > 20) {
  35. return version.substring(0, 17) + '...';
  36. }
  37. return version;
  38. }
  39. /**
  40. * Parse binary version object
  41. * @param {Object} versionData - Version data from IPC
  42. * @returns {Object} Parsed version info
  43. */
  44. function parseBinaryVersion(versionData) {
  45. if (!versionData) {
  46. return {
  47. available: false,
  48. version: null,
  49. updateAvailable: false,
  50. latestVersion: null
  51. };
  52. }
  53. return {
  54. available: versionData.available || false,
  55. version: versionData.version || null,
  56. updateAvailable: versionData.updateAvailable || false,
  57. latestVersion: versionData.latestVersion || null
  58. };
  59. }
  60. describe('Version Comparison Logic', () => {
  61. describe('compareVersions', () => {
  62. it('should compare versions correctly - newer is greater', () => {
  63. expect(compareVersions('2024.01.15', '2024.01.10')).toBe(1);
  64. expect(compareVersions('2024.02.01', '2024.01.31')).toBe(1);
  65. expect(compareVersions('2025.01.01', '2024.12.31')).toBe(1);
  66. });
  67. it('should compare versions correctly - older is less', () => {
  68. expect(compareVersions('2024.01.10', '2024.01.15')).toBe(-1);
  69. expect(compareVersions('2024.01.31', '2024.02.01')).toBe(-1);
  70. expect(compareVersions('2024.12.31', '2025.01.01')).toBe(-1);
  71. });
  72. it('should return 0 for equal versions', () => {
  73. expect(compareVersions('2024.01.15', '2024.01.15')).toBe(0);
  74. expect(compareVersions('1.0.0', '1.0.0')).toBe(0);
  75. });
  76. it('should handle different length version strings', () => {
  77. expect(compareVersions('1.0', '1.0.0')).toBe(0);
  78. expect(compareVersions('1.2', '1.2.0.0')).toBe(0);
  79. expect(compareVersions('2.0', '1.9.9.9')).toBe(1);
  80. });
  81. it('should handle null or undefined versions', () => {
  82. expect(compareVersions(null, '1.0.0')).toBe(0);
  83. expect(compareVersions('1.0.0', null)).toBe(0);
  84. expect(compareVersions(null, null)).toBe(0);
  85. });
  86. it('should handle semantic versioning', () => {
  87. expect(compareVersions('2.0.0', '1.9.9')).toBe(1);
  88. expect(compareVersions('1.10.0', '1.9.0')).toBe(1);
  89. expect(compareVersions('1.0.10', '1.0.9')).toBe(1);
  90. });
  91. });
  92. describe('formatVersion', () => {
  93. it('should format normal versions unchanged', () => {
  94. expect(formatVersion('2024.01.15')).toBe('2024.01.15');
  95. expect(formatVersion('1.2.3')).toBe('1.2.3');
  96. });
  97. it('should truncate long version strings', () => {
  98. const longVersion = 'ffmpeg version 6.0.1-full_build-www.gyan.dev Copyright';
  99. const formatted = formatVersion(longVersion);
  100. expect(formatted.length).toBeLessThanOrEqual(20);
  101. expect(formatted).toContain('...');
  102. });
  103. it('should handle unknown versions', () => {
  104. expect(formatVersion('unknown')).toBe('--');
  105. expect(formatVersion(null)).toBe('--');
  106. expect(formatVersion('')).toBe('--');
  107. });
  108. });
  109. describe('parseBinaryVersion', () => {
  110. it('should parse valid version data', () => {
  111. const versionData = {
  112. available: true,
  113. version: '2024.01.15',
  114. updateAvailable: true,
  115. latestVersion: '2024.01.20'
  116. };
  117. const parsed = parseBinaryVersion(versionData);
  118. expect(parsed.available).toBe(true);
  119. expect(parsed.version).toBe('2024.01.15');
  120. expect(parsed.updateAvailable).toBe(true);
  121. expect(parsed.latestVersion).toBe('2024.01.20');
  122. });
  123. it('should handle missing binary', () => {
  124. const versionData = {
  125. available: false
  126. };
  127. const parsed = parseBinaryVersion(versionData);
  128. expect(parsed.available).toBe(false);
  129. expect(parsed.version).toBe(null);
  130. expect(parsed.updateAvailable).toBe(false);
  131. });
  132. it('should handle null or undefined data', () => {
  133. const parsed = parseBinaryVersion(null);
  134. expect(parsed.available).toBe(false);
  135. expect(parsed.version).toBe(null);
  136. });
  137. it('should handle partial data with defaults', () => {
  138. const versionData = {
  139. version: '2024.01.15'
  140. // Missing available, updateAvailable, latestVersion
  141. };
  142. const parsed = parseBinaryVersion(versionData);
  143. expect(parsed.available).toBe(false); // default
  144. expect(parsed.version).toBe('2024.01.15');
  145. expect(parsed.updateAvailable).toBe(false); // default
  146. });
  147. });
  148. });
  149. describe('Update Detection Logic', () => {
  150. it('should detect when update is available', () => {
  151. const installed = '2024.01.10';
  152. const latest = '2024.01.15';
  153. const updateAvailable = compareVersions(latest, installed) > 0;
  154. expect(updateAvailable).toBe(true);
  155. });
  156. it('should detect when no update is available', () => {
  157. const installed = '2024.01.15';
  158. const latest = '2024.01.15';
  159. const updateAvailable = compareVersions(latest, installed) > 0;
  160. expect(updateAvailable).toBe(false);
  161. });
  162. it('should handle downgrade scenario', () => {
  163. const installed = '2024.01.20';
  164. const latest = '2024.01.15';
  165. const updateAvailable = compareVersions(latest, installed) > 0;
  166. expect(updateAvailable).toBe(false);
  167. });
  168. });
  169. describe('Version Display State', () => {
  170. it('should generate correct display state for available binary', () => {
  171. const versionData = {
  172. ytDlp: {
  173. available: true,
  174. version: '2024.01.15',
  175. updateAvailable: false,
  176. latestVersion: '2024.01.15'
  177. },
  178. ffmpeg: {
  179. available: true,
  180. version: '6.0.1',
  181. updateAvailable: false
  182. }
  183. };
  184. expect(versionData.ytDlp.available).toBe(true);
  185. expect(formatVersion(versionData.ytDlp.version)).toBe('2024.01.15');
  186. expect(versionData.ytDlp.updateAvailable).toBe(false);
  187. });
  188. it('should generate correct display state for missing binary', () => {
  189. const versionData = {
  190. ytDlp: {
  191. available: false
  192. },
  193. ffmpeg: {
  194. available: false
  195. }
  196. };
  197. expect(versionData.ytDlp.available).toBe(false);
  198. expect(formatVersion(versionData.ytDlp.version)).toBe('--');
  199. });
  200. it('should generate correct display state when update available', () => {
  201. const versionData = {
  202. ytDlp: {
  203. available: true,
  204. version: '2024.01.10',
  205. updateAvailable: true,
  206. latestVersion: '2024.01.15'
  207. }
  208. };
  209. expect(versionData.ytDlp.updateAvailable).toBe(true);
  210. expect(versionData.ytDlp.latestVersion).toBe('2024.01.15');
  211. });
  212. });
  213. describe('Error Handling', () => {
  214. it('should handle malformed version strings gracefully', () => {
  215. expect(() => compareVersions('invalid', '1.0.0')).not.toThrow();
  216. expect(() => formatVersion('x.y.z')).not.toThrow();
  217. });
  218. it('should handle empty version data', () => {
  219. const parsed = parseBinaryVersion({});
  220. expect(parsed.available).toBe(false);
  221. expect(parsed.version).toBe(null);
  222. });
  223. it('should handle missing fields in version comparison', () => {
  224. const result1 = compareVersions(undefined, '1.0.0');
  225. const result2 = compareVersions('1.0.0', undefined);
  226. expect(result1).toBe(0);
  227. expect(result2).toBe(0);
  228. });
  229. });
  230. describe('Real-World Version Scenarios', () => {
  231. it('should handle yt-dlp date-based versions', () => {
  232. const versions = [
  233. '2024.01.01',
  234. '2024.01.15',
  235. '2024.02.01',
  236. '2024.12.31'
  237. ];
  238. // Should be in ascending order
  239. for (let i = 0; i < versions.length - 1; i++) {
  240. expect(compareVersions(versions[i + 1], versions[i])).toBe(1);
  241. }
  242. });
  243. it('should handle ffmpeg semantic versions', () => {
  244. const versions = [
  245. '5.1.0',
  246. '5.1.2',
  247. '6.0.0',
  248. '6.0.1'
  249. ];
  250. // Should be in ascending order
  251. for (let i = 0; i < versions.length - 1; i++) {
  252. expect(compareVersions(versions[i + 1], versions[i])).toBe(1);
  253. }
  254. });
  255. it('should handle complex ffmpeg version strings', () => {
  256. const version = 'ffmpeg version 6.0.1-full_build-www.gyan.dev Copyright (c) 2000-2024';
  257. const formatted = formatVersion(version);
  258. // Should be truncated
  259. expect(formatted.length).toBeLessThanOrEqual(20);
  260. });
  261. });