registry_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package imagetype
  2. import (
  3. "bytes"
  4. "io"
  5. "reflect"
  6. "runtime"
  7. "strings"
  8. "testing"
  9. "github.com/imgproxy/imgproxy/v3/bufreader"
  10. "github.com/stretchr/testify/require"
  11. )
  12. func TestRegisterType(t *testing.T) {
  13. // Create a separate registry for testing to avoid conflicts with global registry
  14. testRegistry := NewRegistry()
  15. // Register a custom type
  16. customDesc := &TypeDesc{
  17. String: "custom",
  18. Ext: ".custom",
  19. Mime: "image/custom",
  20. IsVector: false,
  21. SupportsAlpha: true,
  22. SupportsColourProfile: true,
  23. }
  24. customType := testRegistry.RegisterType(customDesc)
  25. // Verify the type is now registered
  26. result := testRegistry.GetTypeDesc(customType)
  27. require.NotNil(t, result)
  28. require.Equal(t, customDesc.String, result.String)
  29. require.Equal(t, customDesc.Ext, result.Ext)
  30. require.Equal(t, customDesc.Mime, result.Mime)
  31. require.Equal(t, customDesc.IsVector, result.IsVector)
  32. require.Equal(t, customDesc.SupportsAlpha, result.SupportsAlpha)
  33. require.Equal(t, customDesc.SupportsColourProfile, result.SupportsColourProfile)
  34. }
  35. func TestTypeProperties(t *testing.T) {
  36. // Test that Type methods use TypeDesc fields correctly
  37. tests := []struct {
  38. name string
  39. typ Type
  40. expectVector bool
  41. expectAlpha bool
  42. expectColourProfile bool
  43. expectQuality bool
  44. expectAnimationLoad bool
  45. expectAnimationSave bool
  46. expectThumbnail bool
  47. }{
  48. {
  49. name: "JPEG",
  50. typ: JPEG,
  51. expectVector: false,
  52. expectAlpha: false,
  53. expectColourProfile: true,
  54. expectQuality: true,
  55. expectAnimationLoad: false,
  56. expectAnimationSave: false,
  57. expectThumbnail: false,
  58. },
  59. {
  60. name: "PNG",
  61. typ: PNG,
  62. expectVector: false,
  63. expectAlpha: true,
  64. expectColourProfile: true,
  65. expectQuality: false,
  66. expectAnimationLoad: false,
  67. expectAnimationSave: false,
  68. expectThumbnail: false,
  69. },
  70. {
  71. name: "WEBP",
  72. typ: WEBP,
  73. expectVector: false,
  74. expectAlpha: true,
  75. expectColourProfile: true,
  76. expectQuality: true,
  77. expectAnimationLoad: true,
  78. expectAnimationSave: true,
  79. expectThumbnail: false,
  80. },
  81. {
  82. name: "SVG",
  83. typ: SVG,
  84. expectVector: true,
  85. expectAlpha: true,
  86. expectColourProfile: false,
  87. expectQuality: false,
  88. expectAnimationLoad: false,
  89. expectAnimationSave: false,
  90. expectThumbnail: false,
  91. },
  92. {
  93. name: "GIF",
  94. typ: GIF,
  95. expectVector: false,
  96. expectAlpha: true,
  97. expectColourProfile: false,
  98. expectQuality: false,
  99. expectAnimationLoad: true,
  100. expectAnimationSave: true,
  101. expectThumbnail: false,
  102. },
  103. {
  104. name: "HEIC",
  105. typ: HEIC,
  106. expectVector: false,
  107. expectAlpha: true,
  108. expectColourProfile: true,
  109. expectQuality: true,
  110. expectAnimationLoad: false,
  111. expectAnimationSave: false,
  112. expectThumbnail: true,
  113. },
  114. {
  115. name: "AVIF",
  116. typ: AVIF,
  117. expectVector: false,
  118. expectAlpha: true,
  119. expectColourProfile: true,
  120. expectQuality: true,
  121. expectAnimationLoad: false,
  122. expectAnimationSave: false,
  123. expectThumbnail: true,
  124. },
  125. }
  126. for _, tt := range tests {
  127. t.Run(tt.name, func(t *testing.T) {
  128. require.Equal(t, tt.expectVector, tt.typ.IsVector())
  129. require.Equal(t, tt.expectAlpha, tt.typ.SupportsAlpha())
  130. require.Equal(t, tt.expectColourProfile, tt.typ.SupportsColourProfile())
  131. require.Equal(t, tt.expectQuality, tt.typ.SupportsQuality())
  132. require.Equal(t, tt.expectAnimationLoad, tt.typ.SupportsAnimationLoad())
  133. require.Equal(t, tt.expectAnimationSave, tt.typ.SupportsAnimationSave())
  134. require.Equal(t, tt.expectThumbnail, tt.typ.SupportsThumbnail())
  135. })
  136. }
  137. }
  138. func TestRegisterDetector(t *testing.T) {
  139. // Create a test registry to avoid interfering with global state
  140. testRegistry := NewRegistry()
  141. functionsEqual := func(fn1, fn2 DetectFunc) {
  142. // Compare function names to check if they are the same
  143. fnName1 := runtime.FuncForPC(reflect.ValueOf(fn1).Pointer()).Name()
  144. fnName2 := runtime.FuncForPC(reflect.ValueOf(fn2).Pointer()).Name()
  145. require.Equal(t, fnName1, fnName2)
  146. }
  147. // Create a test detector functions
  148. testDetector1 := func(r bufreader.ReadPeeker) (Type, error) { return JPEG, nil }
  149. testDetector2 := func(r bufreader.ReadPeeker) (Type, error) { return PNG, nil }
  150. testDetector3 := func(r bufreader.ReadPeeker) (Type, error) { return GIF, nil }
  151. testDetector4 := func(r bufreader.ReadPeeker) (Type, error) { return SVG, nil }
  152. // Register the detectors using the method
  153. testRegistry.RegisterDetector(0, testDetector1)
  154. testRegistry.RegisterDetector(0, testDetector2)
  155. testRegistry.RegisterDetector(10, testDetector3)
  156. testRegistry.RegisterDetector(5, testDetector4)
  157. // Verify the detectors are registered
  158. require.Len(t, testRegistry.detectors, 4)
  159. // Verify the order of detectors based on priority
  160. require.Equal(t, 0, testRegistry.detectors[0].priority)
  161. functionsEqual(testDetector1, testRegistry.detectors[0].fn)
  162. require.Equal(t, 0, testRegistry.detectors[1].priority)
  163. functionsEqual(testDetector2, testRegistry.detectors[1].fn)
  164. require.Equal(t, 5, testRegistry.detectors[2].priority)
  165. functionsEqual(testDetector4, testRegistry.detectors[2].fn)
  166. require.Equal(t, 10, testRegistry.detectors[3].priority)
  167. functionsEqual(testDetector3, testRegistry.detectors[3].fn)
  168. }
  169. func TestRegisterMagicBytes(t *testing.T) {
  170. // Create a test registry to avoid interfering with global state
  171. testRegistry := NewRegistry()
  172. require.Empty(t, testRegistry.detectors)
  173. // Register magic bytes for JPEG using the method
  174. jpegMagic := []byte{0xFF, 0xD8}
  175. testRegistry.RegisterMagicBytes(JPEG, jpegMagic)
  176. // Verify the magic bytes are registered
  177. require.Len(t, testRegistry.detectors, 1)
  178. require.Equal(t, -1, testRegistry.detectors[0].priority)
  179. typ, err := testRegistry.Detect(bufreader.New(bytes.NewReader(jpegMagic)))
  180. require.NoError(t, err)
  181. require.Equal(t, JPEG, typ)
  182. }
  183. func TestDetectionErrorReturns(t *testing.T) {
  184. // Create a test registry to avoid interfering with global state
  185. testRegistry := NewRegistry()
  186. detErr := error(nil)
  187. // The first detector will fail with detErr
  188. testRegistry.RegisterDetector(0, func(r bufreader.ReadPeeker) (Type, error) {
  189. return Unknown, detErr
  190. })
  191. // The second detector will succeed
  192. testRegistry.RegisterDetector(1, func(r bufreader.ReadPeeker) (Type, error) {
  193. return JPEG, nil
  194. })
  195. // We don't actually need to read anything, just create a reader
  196. r := strings.NewReader("")
  197. // Should not fail with io.EOF
  198. detErr = io.EOF
  199. typ, err := testRegistry.Detect(r)
  200. require.Equal(t, JPEG, typ)
  201. require.NoError(t, err)
  202. // Should not fail with io.ErrUnexpectedEOF
  203. detErr = io.ErrUnexpectedEOF
  204. typ, err = testRegistry.Detect(r)
  205. require.Equal(t, JPEG, typ)
  206. require.NoError(t, err)
  207. // Should fail with other read errors
  208. detErr = io.ErrClosedPipe
  209. typ, err = testRegistry.Detect(r)
  210. require.Equal(t, Unknown, typ)
  211. require.Error(t, err)
  212. require.ErrorAs(t, err, &TypeDetectionError{})
  213. require.ErrorIs(t, err, io.ErrClosedPipe)
  214. }