import 'dart:io'; import 'package:path/path.dart' as p; import 'package:test/test.dart'; import '../../../bin/util/vips.dart'; void main() { late Directory tempDir; late Directory cacheDir; setUp(() async { tempDir = await Directory.systemTemp.createTemp('vips_test_'); cacheDir = await Directory.systemTemp.createTemp('vips_cache_'); }); tearDown(() async { if (await tempDir.exists()) { await tempDir.delete(recursive: true); } if (await cacheDir.exists()) { await cacheDir.delete(recursive: true); } }); group('Vips', () { test('should construct with required parameters', () { final v = Vips(cacheDir: '/some/cache/path'); expect(v.cacheDir, '/some/cache/path'); expect(v.vipsExecuteFile, isNull); }); test('should construct with custom vips executable', () { final v = Vips( vipsExecuteFile: '/custom/path/vips', cacheDir: '/some/cache/path', ); expect(v.vipsExecuteFile, '/custom/path/vips'); expect(v.cacheDir, '/some/cache/path'); }); }); group('generatePreview', () { test('should throw when source file does not exist', () async { final v = Vips(cacheDir: cacheDir.path); expect( () => v.generatePreview('/nonexistent/file.jpg'), throwsA(isA()), ); }); test('should throw when vips is not installed', () async { final v = Vips(cacheDir: cacheDir.path); // Create a dummy file but vips likely isn't installed in test env final dummyFile = File(p.join(tempDir.path, 'dummy.jpg')); dummyFile.writeAsBytesSync(List.filled(100, 0)); expect( () => v.generatePreview(dummyFile.path), throwsA(isA()), ); }); test('should create cache directory if it does not exist', () async { final customCacheDir = p.join(tempDir.path, 'new_cache'); final previewDirPath = p.join(customCacheDir, 'preview'); final v = Vips(cacheDir: customCacheDir); final dummyFile = File(p.join(tempDir.path, 'test.png')); dummyFile.writeAsBytesSync(List.filled(100, 0)); // This will likely fail due to missing vips, but we verify // the cache directory creation attempt happens before the process call try { await v.generatePreview(dummyFile.path); } catch (_) { // Expected - vips not installed } // The preview subdirectory should have been created expect(Directory(previewDirPath).existsSync(), isTrue); }); }); group('caching behavior', () { test('should return cached file when it already exists', () async { final v = Vips(cacheDir: cacheDir.path); // Create source file final sourceFile = File(p.join(tempDir.path, 'test_image.jpg')); sourceFile.writeAsBytesSync(List.filled(100, 0)); // Pre-create the expected cached file final baseName = sourceFile.path.hashCode.toString(); final cachedFile = File( p.join(cacheDir.path, 'preview', '${baseName}_100x100.webp'), ); cachedFile.parent.createSync(recursive: true); cachedFile.writeAsBytesSync([0x52, 0x49, 0x46, 0x46]); // RIFF header // Now call generatePreview - it should return the cached file final result = await v.generatePreview(sourceFile.path, w: 100, h: 100); expect(p.normalize(result.path), p.normalize(cachedFile.path)); expect(result.existsSync(), isTrue); }); test('should not call vips when cache hit', () async { final v = Vips(cacheDir: cacheDir.path); // Create source file final sourceFile = File(p.join(tempDir.path, 'cached.jpg')); sourceFile.writeAsBytesSync(List.filled(100, 0)); // Create the expected cached file final baseName = sourceFile.path.hashCode.toString(); final cachedFile = File( p.join(cacheDir.path, 'preview', '${baseName}_200x100.webp'), ); cachedFile.parent.createSync(recursive: true); cachedFile.writeAsBytesSync([0x01, 0x02, 0x03]); final result = await v.generatePreview(sourceFile.path, w: 200, h: 100); // Should return the cached file without calling vips expect(p.normalize(result.path), p.normalize(cachedFile.path)); expect(result.existsSync(), isTrue); }); test( 'should use correct cache filename format for different sizes', () async { final v = Vips(cacheDir: cacheDir.path); // Create source file final sourceFile = File(p.join(tempDir.path, 'sizing.jpg')); sourceFile.writeAsBytesSync(List.filled(100, 0)); // Create cached file for 400x300 final baseName = sourceFile.path.hashCode.toString(); final cachedFile = File( p.join(cacheDir.path, 'preview', '${baseName}_400x300.webp'), ); cachedFile.parent.createSync(recursive: true); cachedFile.writeAsBytesSync([0xAA]); final result = await v.generatePreview(sourceFile.path, w: 400, h: 300); expect(p.normalize(result.path), p.normalize(cachedFile.path)); }, ); test('should use correct cache filename format for width only', () async { final v = Vips(cacheDir: cacheDir.path); final sourceFile = File(p.join(tempDir.path, 'width_only.jpg')); sourceFile.writeAsBytesSync(List.filled(100, 0)); final baseName = sourceFile.path.hashCode.toString(); final cachedFile = File( p.join(cacheDir.path, 'preview', '${baseName}_500x0.webp'), ); cachedFile.parent.createSync(recursive: true); cachedFile.writeAsBytesSync([0xBB]); final result = await v.generatePreview(sourceFile.path, w: 500); expect(p.normalize(result.path), p.normalize(cachedFile.path)); }); test('should use correct cache filename format for height only', () async { final v = Vips(cacheDir: cacheDir.path); final sourceFile = File(p.join(tempDir.path, 'height_only.jpg')); sourceFile.writeAsBytesSync(List.filled(100, 0)); final baseName = sourceFile.path.hashCode.toString(); final cachedFile = File( p.join(cacheDir.path, 'preview', '${baseName}_0x600.webp'), ); cachedFile.parent.createSync(recursive: true); cachedFile.writeAsBytesSync([0xCC]); final result = await v.generatePreview(sourceFile.path, h: 600); expect(p.normalize(result.path), p.normalize(cachedFile.path)); }); }); }