diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..aa9f013 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,198 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:suggestion + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = true:silent +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/PdfAValidator.sln b/PdfAValidator.sln index 65b5fa4..2b0f21c 100644 --- a/PdfAValidator.sln +++ b/PdfAValidator.sln @@ -11,12 +11,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfAValidatorWebApi", "PdfA EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{49D9D2CB-EF79-4962-B4C3-2F1BAFD9DCC8}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig appveyor.yml = appveyor.yml LICENSE = LICENSE README.md = README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfAValidatorWebApiTest", "PdfAValidatorWebApiTest\PdfAValidatorWebApiTest.csproj", "{92E8D03D-F39B-46BD-98BF-1F2BB0AE21BA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfAValidatorWebApiTest", "PdfAValidatorWebApiTest\PdfAValidatorWebApiTest.csproj", "{92E8D03D-F39B-46BD-98BF-1F2BB0AE21BA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/PdfAValidator/IPdfAValidator.cs b/PdfAValidator/IPdfAValidator.cs new file mode 100644 index 0000000..292fdc6 --- /dev/null +++ b/PdfAValidator/IPdfAValidator.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading.Tasks; + +namespace Codeuctivity +{ + /// + /// PdfAValidator is a VeraPdf wrapper + /// + public interface IPdfAValidator : IDisposable + { + /// + /// Validates a pdf to be compliant with the pdfa standard claimed by its meta data + /// + /// + /// True for compliant PdfA Files + Task ValidateAsync(string pathToPdfFile); + + /// + /// Validates a pdf and returns a detailed compliance report + /// + /// + /// + Task ValidateWithDetailedReportAsync(string pathToPdfFile); + } +} \ No newline at end of file diff --git a/PdfAValidator/PdfAValidator.cs b/PdfAValidator/PdfAValidator.cs index fd60bd4..f04d5b7 100644 --- a/PdfAValidator/PdfAValidator.cs +++ b/PdfAValidator/PdfAValidator.cs @@ -1,26 +1,28 @@ -using System; +using Codeuctivity.Properties; +using System; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Reflection; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; -namespace PdfAValidator +namespace Codeuctivity { /// /// PdfAValidator is a VeraPdf wrapper /// - public class PdfAValidator : IDisposable + + public class PdfAValidator : IPdfAValidator { private const string maskedQuote = "\""; private const int maxLengthTempdirectoryThatVeraPdfFitsIn = 206; - private const string OsNotSupportedMessage = "Sorry, only supporting linux and windows."; - private readonly object lockObject = new object(); private string? pathVeraPdfDirectory; private bool disposed; + private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); /// /// Path to java jre used by windows @@ -57,12 +59,9 @@ protected virtual void Dispose(bool disposing) return; } - if (disposing) + if (disposing && !customVerapdfAndJavaLocations && Directory.Exists(pathVeraPdfDirectory)) { - if (!customVerapdfAndJavaLocations && Directory.Exists(pathVeraPdfDirectory)) - { - Directory.Delete(pathVeraPdfDirectory, true); - } + Directory.Delete(pathVeraPdfDirectory, true); } disposed = true; } @@ -84,16 +83,17 @@ public PdfAValidator(string pathToVeraPdfBin, string pathToJava) /// Use this constructor to use the embedded veraPdf binaries /// public PdfAValidator() - { } + { + } /// /// Validates a pdf to be compliant with the pdfa standard claimed by its meta data /// /// /// True for compliant PdfA Files - public bool Validate(string pathToPdfFile) + public async Task ValidateAsync(string pathToPdfFile) { - return ValidateWithDetailedReport(pathToPdfFile).BatchSummary.ValidationReports.Compliant == "1"; + return (await ValidateWithDetailedReportAsync(pathToPdfFile).ConfigureAwait(false)).BatchSummary.ValidationReports.Compliant == "1"; } /// @@ -101,9 +101,9 @@ public bool Validate(string pathToPdfFile) /// /// /// - public Report ValidateWithDetailedReport(string pathToPdfFile) + public async Task ValidateWithDetailedReportAsync(string pathToPdfFile) { - IntiPathToVeraPdfBinAndJava(); + await IntiPathToVeraPdfBinAndJava().ConfigureAwait(false); var absolutePathToPdfFile = Path.GetFullPath(pathToPdfFile); if (!File.Exists(absolutePathToPdfFile)) @@ -172,9 +172,10 @@ private static T DeserializeXml(string sourceXML) where T : class return (T)serializer.Deserialize(xmlReader); } - private void IntiPathToVeraPdfBinAndJava() + private async Task IntiPathToVeraPdfBinAndJava() { - lock (lockObject) + await semaphore.WaitAsync().ConfigureAwait(false); + try { if (IsInitialized) { @@ -191,24 +192,28 @@ private void IntiPathToVeraPdfBinAndJava() if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - ExtractBinaryFromManifest("PdfAValidator.VeraPdf.Windows.zip"); + await ExtractBinaryFromManifest("Codeuctivity.VeraPdf.Windows.zip").ConfigureAwait(false); VeraPdfStartScript = Path.Combine(pathVeraPdfDirectory, "verapdf", "verapdf.bat"); // took from https://adoptopenjdk.net/releases.html?variant=openjdk8&jvmVariant=hotspot#x64_win PathJava = Path.Combine(pathVeraPdfDirectory, "verapdf", "jdk8u202-b08-jre", "bin", "java"); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - ExtractBinaryFromManifest("PdfAValidator.VeraPdf.Linux.zip"); + await ExtractBinaryFromManifest("Codeuctivity.VeraPdf.Linux.zip").ConfigureAwait(false); VeraPdfStartScript = Path.Combine(pathVeraPdfDirectory, "verapdf", "verapdf"); SetLinuxFileExecuteable(VeraPdfStartScript); } else { - throw new NotImplementedException(OsNotSupportedMessage); + throw new NotImplementedException(Resources.OsNotSupportedMessage); } IsInitialized = true; } + finally + { + semaphore.Release(); + } } private static void SetLinuxFileExecuteable(string filePath) @@ -232,7 +237,7 @@ private static void SetLinuxFileExecuteable(string filePath) process.WaitForExit(); } - private void ExtractBinaryFromManifest(string resourceName) + private async Task ExtractBinaryFromManifest(string resourceName) { var pathZipVeraPdf = Path.Combine(pathVeraPdfDirectory, "VeraPdf.zip"); var assembly = Assembly.GetExecutingAssembly(); @@ -240,7 +245,7 @@ private void ExtractBinaryFromManifest(string resourceName) using (var fileStream = File.Create(pathZipVeraPdf)) { stream.Seek(0, SeekOrigin.Begin); - stream.CopyTo(fileStream); + await stream.CopyToAsync(fileStream).ConfigureAwait(false); } ZipFile.ExtractToDirectory(pathZipVeraPdf, pathVeraPdfDirectory); diff --git a/PdfAValidator/PdfAValidator.csproj b/PdfAValidator/PdfAValidator.csproj index 8abc167..913a540 100644 --- a/PdfAValidator/PdfAValidator.csproj +++ b/PdfAValidator/PdfAValidator.csproj @@ -1,5 +1,6 @@  + Api is now async netstandard2.0 true true @@ -24,6 +25,8 @@ true enable 8.0 + Codeuctivity + en @@ -43,10 +46,14 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -55,10 +62,21 @@ - + + + + + + True + True + Resources.resx + - + + ResXFileCodeGenerator + Resources.Designer.cs + diff --git a/PdfAValidatorTest/Properties/Resources.Designer.cs b/PdfAValidator/Properties/Resources.Designer.cs similarity index 84% rename from PdfAValidatorTest/Properties/Resources.Designer.cs rename to PdfAValidator/Properties/Resources.Designer.cs index 33df5fb..06e20ab 100644 --- a/PdfAValidatorTest/Properties/Resources.Designer.cs +++ b/PdfAValidator/Properties/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace PdfAValidatorTest.Properties { +namespace Codeuctivity.Properties { using System; @@ -39,7 +39,7 @@ internal Resources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PdfAValidatorTest.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Codeuctivity.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; @@ -59,5 +59,14 @@ internal Resources() { resourceCulture = value; } } + + /// + /// Looks up a localized string similar to Sorry, only supporting Linux and windows.. + /// + internal static string OsNotSupportedMessage { + get { + return ResourceManager.GetString("OsNotSupportedMessage", resourceCulture); + } + } } } diff --git a/PdfAValidatorTest/Properties/Resources.resx b/PdfAValidator/Properties/Resources.resx similarity index 97% rename from PdfAValidatorTest/Properties/Resources.resx rename to PdfAValidator/Properties/Resources.resx index 1af7de1..fd26da6 100644 --- a/PdfAValidatorTest/Properties/Resources.resx +++ b/PdfAValidator/Properties/Resources.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Sorry, only supporting Linux and windows. + \ No newline at end of file diff --git a/PdfAValidator/Report.cs b/PdfAValidator/Report.cs index 86477dc..7575fc0 100644 --- a/PdfAValidator/Report.cs +++ b/PdfAValidator/Report.cs @@ -1,10 +1,9 @@ -using System; +using System.Collections.Generic; using System.Xml.Serialization; -using System.Collections.Generic; // example report file https://docs.verapdf.org/policy/info-dict/report.xml -namespace PdfAValidator +namespace Codeuctivity { /// /// ReleaseDetails shows details to the used veraPdf version diff --git a/PdfAValidator/VeraPdfException.cs b/PdfAValidator/VeraPdfException.cs index 7e42c75..c121383 100644 --- a/PdfAValidator/VeraPdfException.cs +++ b/PdfAValidator/VeraPdfException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace PdfAValidator +namespace Codeuctivity { /// /// The exception that is thrown when the call of verapdf fails execution of a program. diff --git a/PdfAValidatorTest/GlobalSuppressions.cs b/PdfAValidatorTest/GlobalSuppressions.cs new file mode 100644 index 0000000..fe262c9 --- /dev/null +++ b/PdfAValidatorTest/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Test code will never be referenced with some undefind excution scope", Scope = "module")] \ No newline at end of file diff --git a/PdfAValidatorTest/PdfAValidatorTest.cs b/PdfAValidatorTest/PdfAValidatorTest.cs index c86fe1d..0fb5c34 100644 --- a/PdfAValidatorTest/PdfAValidatorTest.cs +++ b/PdfAValidatorTest/PdfAValidatorTest.cs @@ -1,19 +1,20 @@ -using PdfAValidator; +using Codeuctivity; using System.IO; using System.Runtime.InteropServices; +using System.Threading.Tasks; using Xunit; -namespace PDfAValidatorTest +namespace CodeuctivityTest { public static class PdfAValidatorTest { [Fact] - public static void ShouldUnpackNewDirectoryInTempdirectory() + public static async Task ShouldUnpackNewDirectoryInTempdirectory() { string? veraPdfStartScript; - using (var pdfAValidator = new PdfAValidator.PdfAValidator()) + using (var pdfAValidator = new PdfAValidator()) { - pdfAValidator.Validate("./TestPdfFiles/FromLibreOffice.pdf"); + await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOffice.pdf"); veraPdfStartScript = pdfAValidator.VeraPdfStartScript; AssertVeraPdfBinCreation(pdfAValidator.VeraPdfStartScript); } @@ -21,39 +22,39 @@ public static void ShouldUnpackNewDirectoryInTempdirectory() } [Fact] - public static void ShouldDetectCompliantPdfA() + public static async Task ShouldDetectCompliantPdfA() { - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new PdfAValidator(); Assert.True(File.Exists("./TestPdfFiles/FromLibreOffice.pdf")); - var result = pdfAValidator.Validate("./TestPdfFiles/FromLibreOffice.pdf"); + var result = await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOffice.pdf"); Assert.True(result); } [Fact] - public static void ShouldGetDetailedReportFromPdfA() + public static async Task ShouldGetDetailedReportFromPdfA() { - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new PdfAValidator(); Assert.True(File.Exists("./TestPdfFiles/FromLibreOffice.pdf")); - var result = pdfAValidator.ValidateWithDetailedReport("./TestPdfFiles/FromLibreOffice.pdf"); + var result = await pdfAValidator.ValidateWithDetailedReportAsync("./TestPdfFiles/FromLibreOffice.pdf"); Assert.True(result.Jobs.Job.ValidationReport.IsCompliant); Assert.True(result.Jobs.Job.ValidationReport.ProfileName == "PDF/A-1A validation profile"); } [Fact] - public static void ShouldDetectNonCompliantPdfA() + public static async Task ShouldDetectNonCompliantPdfA() { - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new PdfAValidator(); Assert.True(File.Exists("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf")); - var result = pdfAValidator.Validate("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); + var result = await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); Assert.False(result); } [Fact] - public static void ShouldGetDetailedReportFromNonCompliantPdfA() + public static async Task ShouldGetDetailedReportFromNonCompliantPdfA() { - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new PdfAValidator(); Assert.True(File.Exists("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf")); - var result = pdfAValidator.ValidateWithDetailedReport("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); + var result = await pdfAValidator.ValidateWithDetailedReportAsync("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); Assert.False(result.Jobs.Job.ValidationReport.IsCompliant); Assert.True(result.Jobs.Job.ValidationReport.ProfileName == "PDF/A-1B validation profile"); Assert.InRange(result.Jobs.Job.ValidationReport.Details.FailedRules, 1, 20); @@ -61,41 +62,39 @@ public static void ShouldGetDetailedReportFromNonCompliantPdfA() } [Fact] - public static void ShouldGetDetailedReportFromNonCompliantPdfAMissingFont() + public static async Task ShouldGetDetailedReportFromNonCompliantPdfAMissingFont() { - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new PdfAValidator(); Assert.True(File.Exists("./TestPdfFiles/FontsNotEmbedded.pdf")); - var result = pdfAValidator.ValidateWithDetailedReport("./TestPdfFiles/FontsNotEmbedded.pdf"); + var result = await pdfAValidator.ValidateWithDetailedReportAsync("./TestPdfFiles/FontsNotEmbedded.pdf"); Assert.False(result.Jobs.Job.ValidationReport.IsCompliant); Assert.True(result.Jobs.Job.ValidationReport.ProfileName == "PDF/A-1B validation profile"); Assert.Contains(result.Jobs.Job.ValidationReport.Details.Rule, _ => _.Clause == "6.3.5"); } [Fact] - public static void ShouldWorkWithCustomJavaAndVeraPdfLocation() + public static async Task ShouldWorkWithCustomJavaAndVeraPdfLocation() { string? veraPdfStartScript; // Using default ctor to get verapdf and Java bins for the test - using (var pdfAValidatorPrepareBins = new PdfAValidator.PdfAValidator()) + using (var pdfAValidatorPrepareBins = new PdfAValidator()) { + await pdfAValidatorPrepareBins.ValidateAsync("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); + using (var pdfAValidator = new PdfAValidator(pdfAValidatorPrepareBins.VeraPdfStartScript!, pdfAValidatorPrepareBins.PathJava!)) { - pdfAValidatorPrepareBins.Validate("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); - using (var pdfAValidator = new PdfAValidator.PdfAValidator(pdfAValidatorPrepareBins.VeraPdfStartScript!, pdfAValidatorPrepareBins.PathJava!)) - { - veraPdfStartScript = pdfAValidator.VeraPdfStartScript; - AssertVeraPdfBinCreation(veraPdfStartScript); - Assert.True(File.Exists("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf")); - var result = pdfAValidator.Validate("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); - Assert.False(result); - } - Assert.True(File.Exists(veraPdfStartScript)); + veraPdfStartScript = pdfAValidator.VeraPdfStartScript; + AssertVeraPdfBinCreation(veraPdfStartScript); + Assert.True(File.Exists("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf")); + var result = await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); + Assert.False(result); } + Assert.True(File.Exists(veraPdfStartScript)); } Assert.False(File.Exists(veraPdfStartScript)); } [Fact] - public static void ShouldFailGracefullWithUnrecognicedVeraPdfOutput() + public static async Task ShouldFailGracefullWithUnrecognicedVeraPdfOutput() { var somethingThatReturnsExitcode0 = "./TestExecuteables/exitcode0.bat"; @@ -104,17 +103,17 @@ public static void ShouldFailGracefullWithUnrecognicedVeraPdfOutput() somethingThatReturnsExitcode0 = "./TestExecuteables/exitcode0.sh"; } - var veraPdfException = Assert.Throws(() => + var veraPdfException = await Assert.ThrowsAsync(async () => { - using var pdfAValidator = new PdfAValidator.PdfAValidator(somethingThatReturnsExitcode0, "SomeValue"); - pdfAValidator.Validate("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); + using var pdfAValidator = new PdfAValidator(somethingThatReturnsExitcode0, "SomeValue"); + await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOfficeNonPdfA.pdf"); }); Assert.Equal($"Failed to parse VeraPdf Output: \nCustom JAVACMD: SomeValue\nveraPdfStartScriptPath: {somethingThatReturnsExitcode0}", veraPdfException.Message); } [Fact] - public static void ShouldFailGracefullWithExitcode1() + public static async Task ShouldFailGracefullWithExitcode1() { var somethingThatReturnsExitcode1 = "./TestExecuteables/exitcode1.bat"; @@ -123,11 +122,11 @@ public static void ShouldFailGracefullWithExitcode1() somethingThatReturnsExitcode1 = "./TestExecuteables/exitcode1.sh"; } - var veraPdfException = Assert.Throws(() => + var veraPdfException = await Assert.ThrowsAsync(async () => { // Using default ctor to get Java bins for the test - using var pdfAValidator = new PdfAValidator.PdfAValidator(somethingThatReturnsExitcode1, "SomeValue"); - pdfAValidator.Validate("./TestPdfFiles/FromLibreOffice.pdf"); + using var pdfAValidator = new PdfAValidator(somethingThatReturnsExitcode1, "SomeValue"); + await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOffice.pdf"); }); Assert.Equal($"Calling VeraPdf exited with 1 caused an error: \nCustom JAVACMD: SomeValue\nVeraPdfStartScript: {somethingThatReturnsExitcode1}", veraPdfException.Message); @@ -147,20 +146,27 @@ private static void AssertVeraPdfBinCreation(string? scriptPath) } [Fact] - public static void ShouldNotFailOnMultipleDisposeCalls() + public static async Task ShouldNotFailOnMultipleDisposeCalls() { - var postscriptValidator = new PdfAValidator.PdfAValidator(); - postscriptValidator.Validate("./TestPdfFiles/FromLibreOffice.pdf"); + var postscriptValidator = new PdfAValidator(); + _ = await postscriptValidator.ValidateAsync("./TestPdfFiles/FromLibreOffice.pdf"); postscriptValidator.Dispose(); +#pragma warning disable S3966 // Expecting multiple dispose calls to pass postscriptValidator.Dispose(); +#pragma warning restore S3966 // Expecting multiple dispose calls to pass } [Fact] public static void ShouldNotFailOnMultipleDisposeCallseWithoutInitialization() { - var postscriptValidator = new PdfAValidator.PdfAValidator(); + var postscriptValidator = new PdfAValidator(); + postscriptValidator.Dispose(); +#pragma warning disable S3966 // Expecting multiple dispose calls to pass postscriptValidator.Dispose(); +#pragma warning restore S3966 // Expecting multiple dispose calls to pass + + Assert.True(true); } } } \ No newline at end of file diff --git a/PdfAValidatorTest/PdfAValidatorTest.csproj b/PdfAValidatorTest/PdfAValidatorTest.csproj index 50ab858..4550dd1 100644 --- a/PdfAValidatorTest/PdfAValidatorTest.csproj +++ b/PdfAValidatorTest/PdfAValidatorTest.csproj @@ -43,11 +43,15 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all @@ -60,18 +64,7 @@ - - True - True - Resources.resx - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - + diff --git a/PdfAValidatorWebApi/Controllers/PdfAValidatorController.cs b/PdfAValidatorWebApi/Controllers/PdfAValidatorController.cs index f52b9d1..31abe41 100644 --- a/PdfAValidatorWebApi/Controllers/PdfAValidatorController.cs +++ b/PdfAValidatorWebApi/Controllers/PdfAValidatorController.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading.Tasks; -namespace PdfAValidatorWebApi.Controllers +namespace CodeuctivityWebApi.Controllers { /// /// @@ -25,22 +25,27 @@ public class PdfAValidatorController : ControllerBase [HttpPost] [ProducesResponseType(200)] [ProducesResponseType(400)] - public async Task Validate(IFormFile pdfFile) + public Task Validate(IFormFile pdfFile) { if (pdfFile is null) { throw new ArgumentNullException(nameof(pdfFile)); } + return InternalValidate(); + } + + private async Task InternalValidate() + { var uploadedFile = Request.Form.Files.Single(); var tempPdfFilePath = Path.Combine(Path.GetTempPath(), "VeraPdf" + Guid.NewGuid() + ".pdf"); try { using var fs = new FileStream(tempPdfFilePath, FileMode.CreateNew, FileAccess.Write); - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new Codeuctivity.PdfAValidator(); await uploadedFile.CopyToAsync(fs).ConfigureAwait(false); - var result = pdfAValidator.Validate(tempPdfFilePath); + var result = await pdfAValidator.ValidateAsync(tempPdfFilePath).ConfigureAwait(false); return Ok(result); } finally @@ -70,10 +75,10 @@ public async Task ValidateWithDetailedReport(IFormFile pdfFile) try { using var fs = new FileStream(tempPdfFilePath, FileMode.CreateNew, FileAccess.Write); - using var pdfAValidator = new PdfAValidator.PdfAValidator(); + using var pdfAValidator = new Codeuctivity.PdfAValidator(); await uploadedFile.CopyToAsync(fs).ConfigureAwait(false); - var result = pdfAValidator.ValidateWithDetailedReport(tempPdfFilePath); + var result = pdfAValidator.ValidateWithDetailedReportAsync(tempPdfFilePath); return Ok(result); } finally diff --git a/PdfAValidatorWebApi/PdfAValidatorWebApi.csproj b/PdfAValidatorWebApi/PdfAValidatorWebApi.csproj index 163f945..e6a58ba 100644 --- a/PdfAValidatorWebApi/PdfAValidatorWebApi.csproj +++ b/PdfAValidatorWebApi/PdfAValidatorWebApi.csproj @@ -12,13 +12,17 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/PdfAValidatorWebApi/Program.cs b/PdfAValidatorWebApi/Program.cs index 9b31698..2981676 100644 --- a/PdfAValidatorWebApi/Program.cs +++ b/PdfAValidatorWebApi/Program.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; -namespace PdfAValidatorWebApi +namespace CodeuctivityWebApi { /// /// The @@ -22,8 +22,9 @@ public static void Main(string[] args) /// /// /// - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup(); + public static IWebHostBuilder CreateWebHostBuilder(string[] args) + { + return WebHost.CreateDefaultBuilder(args).UseStartup(); + } } -} +} \ No newline at end of file diff --git a/PdfAValidatorWebApi/Startup.cs b/PdfAValidatorWebApi/Startup.cs index 46fe3cf..c9537bd 100644 --- a/PdfAValidatorWebApi/Startup.cs +++ b/PdfAValidatorWebApi/Startup.cs @@ -8,13 +8,15 @@ using System.IO; using System.Reflection; -namespace PdfAValidatorWebApi +namespace CodeuctivityWebApi { /// /// Startup Things comes in here /// public class Startup { + private const string GithubProjectAdress = "https://github.com/Codeuctivity/PdfAValidatorApi"; + /// /// This method gets called by the runtime. Use this method to add services to the container. ///For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 @@ -31,17 +33,17 @@ public void ConfigureServices(IServiceCollection services) Version = "v1", Title = "PdfAValidator", Description = "A simple ASP.NET Core Web API wrapping access to VeraPdf", - TermsOfService = new Uri("https://github.com/Codeuctivity/PdfAValidatorApi"), + TermsOfService = new Uri(GithubProjectAdress), Contact = new OpenApiContact { Name = "Codeuctivity", Email = string.Empty, - Url = new Uri("https://github.com/Codeuctivity/PdfAValidatorApi"), + Url = new Uri(GithubProjectAdress), }, License = new OpenApiLicense { Name = "Use under AGPL", - Url = new Uri("https://github.com/Codeuctivity/PdfAValidatorApi/blob/master/LICENSE"), + Url = new Uri($"{GithubProjectAdress}/blob/master/LICENSE"), } }); @@ -68,8 +70,7 @@ public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Enable middleware to serve generated Swagger as a JSON endpoint. app.UseSwagger(); - // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), - // specifying the Swagger JSON endpoint. + // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "PdfAValidator V1"); diff --git a/PdfAValidatorWebApiTest/PdfAValidatorWebApiTest.csproj b/PdfAValidatorWebApiTest/PdfAValidatorWebApiTest.csproj index 98886cf..35f43d8 100644 --- a/PdfAValidatorWebApiTest/PdfAValidatorWebApiTest.csproj +++ b/PdfAValidatorWebApiTest/PdfAValidatorWebApiTest.csproj @@ -8,17 +8,21 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/PdfAValidatorWebApiTest/PdfAValidatorWebApiTestFactory.cs b/PdfAValidatorWebApiTest/PdfAValidatorWebApiTestFactory.cs index bd18ac8..66fbf87 100644 --- a/PdfAValidatorWebApiTest/PdfAValidatorWebApiTestFactory.cs +++ b/PdfAValidatorWebApiTest/PdfAValidatorWebApiTestFactory.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; -namespace PdfAValidatorWebApiTest +namespace CodeuctivityWebApiTest { public class PdfAValidatorWebApiTestFactory : WebApplicationFactory where TStartup : class { @@ -10,7 +10,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) { // see https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1 for things you could place here - builder.ConfigureServices(services => + builder?.ConfigureServices(services => { // Build the service provider. services.BuildServiceProvider(); diff --git a/PdfAValidatorWebApiTest/ShouldStartSuccessfull.cs b/PdfAValidatorWebApiTest/ShouldStartSuccessfull.cs index 31ae85b..b77ce53 100644 --- a/PdfAValidatorWebApiTest/ShouldStartSuccessfull.cs +++ b/PdfAValidatorWebApiTest/ShouldStartSuccessfull.cs @@ -1,15 +1,15 @@ +using Microsoft.AspNetCore.Mvc.Testing; using System; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.Testing; using Xunit; -namespace PdfAValidatorWebApiTest +namespace CodeuctivityWebApiTest { - public class ShouldStartSuccessfull : IClassFixture> + public class ShouldStartSuccessfull : IClassFixture> { - private readonly WebApplicationFactory _factory; + private readonly WebApplicationFactory _factory; - public ShouldStartSuccessfull(WebApplicationFactory factory) + public ShouldStartSuccessfull(WebApplicationFactory factory) { _factory = factory; } diff --git a/README.md b/README.md index 2bdfcca..ad38a6f 100644 --- a/README.md +++ b/README.md @@ -15,31 +15,59 @@ dotnet add package PdfAValidator Sample - e.g. use it in your unit test to check compliance of some pdf: ```csharp -public void ShouldDetectCompliantPdfA() +public static async Task ShouldDetectCompliantPdfA() { - using (var pdfAValidator = new PdfAValidator.PdfAValidator()) - { - var result = pdfAValidator.Validate("./TestPdfFiles/FromLibreOffice.pdf"); - Assert.True(result); - } + using var pdfAValidator = new PdfAValidator(); + Assert.True(File.Exists("./TestPdfFiles/FromLibreOffice.pdf")); + var result = await pdfAValidator.ValidateAsync("./TestPdfFiles/FromLibreOffice.pdf"); + Assert.True(result); } ``` Sample - e.g. use it in your unit test to check the used sub standard of some pdf: ```csharp -public static void ShouldGetDetailedReportFromPdfA() +public static async Task ShouldGetDetailedReportFromPdfA() { - using (var pdfAValidator = new PdfAValidator.PdfAValidator()) - { - Assert.True(File.Exists("./TestPdfFiles/FromLibreOffice.pdf")); - var result = pdfAValidator.ValidateWithDetailedReport("./TestPdfFiles/FromLibreOffice.pdf"); - Assert.True(result.Jobs.Job.ValidationReport.IsCompliant); - Assert.True(result.Jobs.Job.ValidationReport.ProfileName == "PDF/A-1A validation profile"); - } + using var pdfAValidator = new PdfAValidator(); + Assert.True(File.Exists("./TestPdfFiles/FromLibreOffice.pdf")); + var result = await pdfAValidator.ValidateWithDetailedReportAsync("./TestPdfFiles/FromLibreOffice.pdf"); + Assert.True(result.Jobs.Job.ValidationReport.IsCompliant); + Assert.True(result.Jobs.Job.ValidationReport.ProfileName == "PDF/A-1A validation profile"); } ``` ## Demo OpenApi - PdfAValidatorWebApi Give a try, but dont be disappointed if it is offline. The demo azure account is running on limited budget. + +## Dependencies + +### Windows + +Everything comes with the nuget package + +### Ubuntu 20.04 + +Current PdfAValidatorApi depends on opnejdf-8-jre and .net core 3.1. + +```bash +sudo apt install openjdk-8-jre +sudo update-alternatives --config java +``` + +#### Additional things for developing this package + +#### Setup .net sdk + +Based on https://docs.microsoft.com/de-de/dotnet/core/install/linux-package-manager-ubuntu-2004 + +```bash +sudo snap remove dotnet-sdk +wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb +sudo dpkg -i packages-microsoft-prod.deb +sudo apt-get update +sudo apt-get install apt-transport-https +sudo apt-get update +sudo apt-get install dotnet-sdk-3.1 +``` \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 2358ed2..a648387 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.3.{build} +version: 2.0.{build} image: - Visual Studio 2019 - Ubuntu