diff --git a/src/ImageSharp/Bootstrapper.cs b/src/ImageSharp/Bootstrapper.cs
index 3c91f2274..de4bcc938 100644
--- a/src/ImageSharp/Bootstrapper.cs
+++ b/src/ImageSharp/Bootstrapper.cs
@@ -64,9 +64,41 @@ namespace ImageSharp
/// The new format to add.
public void AddImageFormat(IImageFormat format)
{
- if (this.imageFormats.All(i => i.GetType() != format.GetType()))
+ Guard.NotNull(format, nameof(format));
+ Guard.NotNull(format.Encoder, nameof(format), "The encoder should not be null.");
+ Guard.NotNull(format.Decoder, nameof(format), "The decoder should not be null.");
+ Guard.NotNullOrEmpty(format.MimeType, nameof(format), "The mime type should not be null or empty.");
+ Guard.NotNullOrEmpty(format.Extension, nameof(format), "The extension should not be null or empty.");
+ Guard.NotNullOrEmpty(format.SupportedExtensions, nameof(format), "The supported extensions not be null or empty.");
+
+ GuardDuplicate(format);
+
+ this.imageFormats.Add(format);
+ }
+
+ private void GuardDuplicate(IImageFormat format)
+ {
+ if (!format.SupportedExtensions.Contains(format.Extension, StringComparer.OrdinalIgnoreCase))
+ {
+ throw new ArgumentException("The supported extensions should contain the default extension.", nameof(format));
+ }
+
+ if (format.SupportedExtensions.Any(e => string.IsNullOrWhiteSpace(e)))
+ {
+ throw new ArgumentException("The supported extensions should not contain empty values.", nameof(format));
+ }
+
+ foreach (var imageFormat in this.imageFormats)
{
- this.imageFormats.Add(format);
+ if (imageFormat.Extension.Equals(format.Extension, StringComparison.OrdinalIgnoreCase))
+ {
+ throw new ArgumentException("There is already a format with the same extension.", nameof(format));
+ }
+
+ if (imageFormat.SupportedExtensions.Intersect(format.SupportedExtensions, StringComparer.OrdinalIgnoreCase).Any())
+ {
+ throw new ArgumentException("There is already a format that supports the same extension.", nameof(format));
+ }
}
}
}
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index ecb497d3e..b67512525 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -6,7 +6,9 @@
namespace ImageSharp
{
using System;
+ using System.Collections.Generic;
using System.Diagnostics;
+ using System.Linq;
///
/// Provides methods to protect against invalid parameters.
@@ -42,21 +44,47 @@ namespace ImageSharp
///
/// The target string, which should be checked against being null or empty.
/// Name of the parameter.
+ /// The error message, if any to add to the exception.
/// is null.
/// is empty or contains only blanks.
- public static void NotNullOrEmpty(string target, string parameterName)
+ public static void NotNullOrEmpty(string target, string parameterName, string message = "")
{
- if (target == null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ NotNull(target, parameterName, message);
if (string.IsNullOrWhiteSpace(target))
{
+ if (!string.IsNullOrWhiteSpace(message))
+ {
+ throw new ArgumentException(message, parameterName);
+ }
+
throw new ArgumentException("Value cannot be null or empty and cannot contain only blanks.", parameterName);
}
}
+ ///
+ /// Verifies, that the enumeration is not null and not empty.
+ ///
+ /// The target enumeration, which should be checked against being null or empty.
+ /// Name of the parameter.
+ /// The error message, if any to add to the exception.
+ /// is null.
+ /// is empty.
+ public static void NotNullOrEmpty(IEnumerable target, string parameterName, string message = "")
+ {
+ NotNull(target, parameterName, message);
+
+ if (!target.Any())
+ {
+ if (!string.IsNullOrWhiteSpace(message))
+ {
+ throw new ArgumentException(message, parameterName);
+ }
+
+ throw new ArgumentException("Value cannot be empty.", parameterName);
+ }
+ }
+
///
/// Verifies that the specified value is less than a maximum value
/// and throws an exception if it is not.
diff --git a/tests/ImageSharp.Tests/BootstrapperTests.cs b/tests/ImageSharp.Tests/BootstrapperTests.cs
new file mode 100644
index 000000000..4c8ca7f8f
--- /dev/null
+++ b/tests/ImageSharp.Tests/BootstrapperTests.cs
@@ -0,0 +1,160 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests
+{
+ using System;
+ using System.Collections.Generic;
+ using ImageSharp.Formats;
+ using Xunit;
+ using System.Linq;
+
+ public class BootstrapperTests
+ {
+ private class TestFormat : IImageFormat
+ {
+ private IImageDecoder decoder;
+ private IImageEncoder encoder;
+ private string mimeType;
+ private string extension;
+ private IEnumerable supportedExtensions;
+
+ public TestFormat()
+ {
+ this.decoder = new JpegDecoder();
+ this.encoder = new JpegEncoder();
+ this.extension = "jpg";
+ this.mimeType = "image/test";
+ this.supportedExtensions = new string[] { "jpg" };
+ }
+
+ public IImageDecoder Decoder { get { return this.decoder; } set { this.decoder = value; } }
+
+ public IImageEncoder Encoder { get { return this.encoder; } set { this.encoder = value; } }
+
+ public string MimeType { get { return this.mimeType; } set { this.mimeType = value; } }
+
+ public string Extension { get { return this.extension; } set { this.extension = value; } }
+
+ public IEnumerable SupportedExtensions { get { return this.supportedExtensions; } set { this.supportedExtensions = value; } }
+ }
+
+ [Fact]
+ public void AddImageFormatGuardNull()
+ {
+ ArgumentException exception;
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(null);
+ });
+
+ var format = new TestFormat();
+ format.Decoder = null;
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("decoder", exception.Message);
+
+ format = new TestFormat();
+ format.Encoder = null;
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("encoder", exception.Message);
+
+ format = new TestFormat();
+ format.MimeType = null;
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("mime type", exception.Message);
+
+ format = new TestFormat();
+ format.MimeType = "";
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("mime type", exception.Message);
+
+ format = new TestFormat();
+ format.Extension = null;
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("extension", exception.Message);
+
+ format = new TestFormat();
+ format.Extension = "";
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("extension", exception.Message);
+
+ format = new TestFormat();
+ format.SupportedExtensions = null;
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("supported extensions", exception.Message);
+
+ format = new TestFormat();
+ format.SupportedExtensions = Enumerable.Empty();
+
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("supported extensions", exception.Message);
+ }
+
+ [Fact]
+ public void AddImageFormatChecks()
+ {
+ var format = new TestFormat();
+
+ var exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("format with the same", exception.Message);
+
+ format.Extension = "test";
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("should contain", exception.Message);
+
+ format.SupportedExtensions = new string[] { "test", "jpg" };
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("supports the same", exception.Message);
+
+ format.SupportedExtensions = new string[] { "test", "" };
+ exception = Assert.Throws(() =>
+ {
+ Bootstrapper.Instance.AddImageFormat(format);
+ });
+ Assert.Contains("empty values", exception.Message);
+ }
+ }
+}