From 9f783ddef067c568c83621ca4ed216add43a8ae2 Mon Sep 17 00:00:00 2001 From: Eliot Jones Date: Sun, 25 Nov 2018 13:06:54 +0000 Subject: [PATCH] add some more tests for truetype and tokens --- .../Fonts/TrueType/Andada-Regular.ttf | Bin 0 -> 108416 bytes .../Parser/TrueTypeFontParserTests.cs | 31 +++++++----- .../Tokens/BooleanTokenTests.cs | 45 ++++++++++++++++++ .../Tokens/DictionaryTokenTests.cs | 39 +++++++++++++++ .../Tokens/TestPdfTokenScanner.cs | 43 +++++++++++++++++ .../UglyToad.PdfPig.Tests.csproj | 12 +++++ .../Parser/Handlers/TrueTypeFontHandler.cs | 2 +- .../Fonts/Simple/TrueTypeSimpleFont.cs | 20 ++++---- .../Fonts/TrueType/Parser/TableRegister.cs | 2 +- .../TrueType/Parser/TrueTypeFontParser.cs | 6 +-- ...TrueTypeFont.cs => TrueTypeFontProgram.cs} | 4 +- src/UglyToad.PdfPig/Tokens/BooleanToken.cs | 12 +---- src/UglyToad.PdfPig/Tokens/DictionaryToken.cs | 4 +- 13 files changed, 180 insertions(+), 40 deletions(-) create mode 100644 src/UglyToad.PdfPig.Tests/Fonts/TrueType/Andada-Regular.ttf create mode 100644 src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs create mode 100644 src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs rename src/UglyToad.PdfPig/Fonts/TrueType/{TrueTypeFont.cs => TrueTypeFontProgram.cs} (94%) diff --git a/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Andada-Regular.ttf b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Andada-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f235bfb33dd529e82d1c02f17410d2c68f774b40 GIT binary patch literal 108416 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 literal 0 HcmV?d00001 diff --git a/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs index 47fe9316..56535361 100644 --- a/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs +++ b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs @@ -2,7 +2,6 @@ { using System; using System.IO; - using System.Linq; using System.Text.RegularExpressions; using PdfPig.Fonts.TrueType; using PdfPig.Fonts.TrueType.Parser; @@ -14,17 +13,13 @@ { private static byte[] GetFileBytes(string name) { - var manifestFiles = typeof(TrueTypeFontParserTests).Assembly.GetManifestResourceNames(); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts", "TrueType"); - var match = manifestFiles.Single(x => x.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) >= 0); + name = name.EndsWith(".ttf") ? name : name + ".ttf"; - using (var memoryStream = new MemoryStream()) - using (var stream = typeof(TrueTypeFontParserTests).Assembly.GetManifestResourceStream(match)) - { - stream.CopyTo(memoryStream); + var file = Path.Combine(path, name); - return memoryStream.ToArray(); - } + return File.ReadAllBytes(file); } private readonly TrueTypeFontParser parser = new TrueTypeFontParser(); @@ -136,13 +131,27 @@ } [Fact] - public void ParseEmbeddedSimpleGoogleDocssGautmi() + public void ParseSimpleGoogleDocssGautmi() { var bytes = GetFileBytes("google-simple-doc"); var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes)); - parser.Parse(input); + var font = parser.Parse(input); + + Assert.NotNull(font.GlyphTable); + } + + [Fact] + public void ParseAndadaRegular() + { + var bytes = GetFileBytes("Andada-Regular"); + + var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes)); + + var font = parser.Parse(input); + + Assert.NotNull(font.GlyphTable); } [Fact] diff --git a/src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs b/src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs new file mode 100644 index 00000000..d01d4c3f --- /dev/null +++ b/src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs @@ -0,0 +1,45 @@ +namespace UglyToad.PdfPig.Tests.Tokens +{ + using PdfPig.Tokens; + using Xunit; + + public class BooleanTokenTests + { + [Fact] + public void BooleanTokensObjectEquals() + { + var one = BooleanToken.True; + var two = (object) BooleanToken.True; + + Assert.True(one.Equals(two)); + } + + [Fact] + public void BooleanTokensObjectNotEqual() + { + var one = BooleanToken.False; + var two = (object)BooleanToken.True; + + Assert.False(one.Equals(two)); + } + + [Fact] + public void BooleanTokensHashCodeMatch() + { + Assert.Equal(BooleanToken.True.GetHashCode(), BooleanToken.True.GetHashCode()); + } + + [Fact] + public void BooleanTokensHashCodeNotMatch() + { + Assert.NotEqual(BooleanToken.True.GetHashCode(), BooleanToken.False.GetHashCode()); + } + + [Fact] + public void BooleanTokensStringRepresentationCorrect() + { + Assert.Equal("True", BooleanToken.True.ToString()); + Assert.Equal("False", BooleanToken.False.ToString()); + } + } +} diff --git a/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs b/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs index 3b89a82b..13dabd33 100644 --- a/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs +++ b/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs @@ -3,6 +3,7 @@ namespace UglyToad.PdfPig.Tests.Tokens { using System; using System.Collections.Generic; + using Exceptions; using PdfPig.Tokens; using Xunit; @@ -73,5 +74,43 @@ namespace UglyToad.PdfPig.Tests.Tokens Assert.True(result); Assert.Equal("None", Assert.IsType(token).Data); } + + [Fact] + public void CreateWithNonNameTokensThrows() + { + Action action = () => new DictionaryToken(new Dictionary + { + { new NumericToken(7), NameToken.N } + }); + + Assert.Throws(action); + } + + [Fact] + public void GetWithObjectNotOfTypeOrReferenceThrows() + { + var dictionary = new DictionaryToken(new Dictionary + { + { NameToken.Count, new StringToken("twelve") } + }); + + Action action = () => dictionary.Get(NameToken.Count, new TestPdfTokenScanner()); + + Assert.Throws(action); + } + + [Fact] + public void WithCorrectlyAddsKey() + { + var dictionary = new DictionaryToken(new Dictionary + { + { NameToken.Count, new StringToken("12") } + }); + + var newDictionary = dictionary.With(NameToken.ActualText, new StringToken("The text")); + + Assert.True(newDictionary.ContainsKey(NameToken.ActualText)); + Assert.Equal("The text", newDictionary.Get(NameToken.ActualText, new TestPdfTokenScanner()).Data); + } } } diff --git a/src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs b/src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs new file mode 100644 index 00000000..c28e43fa --- /dev/null +++ b/src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs @@ -0,0 +1,43 @@ +// ReSharper disable ObjectCreationAsStatement +namespace UglyToad.PdfPig.Tests.Tokens +{ + using System; + using PdfPig.Tokenization; + using PdfPig.Tokenization.Scanner; + using PdfPig.Tokens; + + internal class TestPdfTokenScanner : IPdfTokenScanner + { + public bool MoveNext() + { + throw new NotImplementedException(); + } + + public IToken CurrentToken { get; set; } + public bool TryReadToken(out T token) where T : class, IToken + { + throw new NotImplementedException(); + } + + public void Seek(long position) + { + throw new NotImplementedException(); + } + + public long CurrentPosition { get; set; } + public void RegisterCustomTokenizer(byte firstByte, ITokenizer tokenizer) + { + throw new NotImplementedException(); + } + + public void DeregisterCustomTokenizer(ITokenizer tokenizer) + { + throw new NotImplementedException(); + } + + public ObjectToken Get(IndirectReference reference) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj b/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj index a2dcc646..1cba82ba 100644 --- a/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj +++ b/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj @@ -30,6 +30,9 @@ + + + @@ -45,6 +48,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs index 9e3faa55..b0495a4a 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs @@ -71,7 +71,7 @@ return new TrueTypeSimpleFont(name, descriptor, toUnicodeCMap, encoding, font, firstCharacter, widths); } - private TrueTypeFont ParseTrueTypeFont(FontDescriptor descriptor) + private TrueTypeFontProgram ParseTrueTypeFont(FontDescriptor descriptor) { if (descriptor?.FontFile == null) { diff --git a/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs b/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs index 4729c728..479f6f41 100644 --- a/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs +++ b/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs @@ -22,7 +22,7 @@ private readonly Encoding encoding; [CanBeNull] - private readonly TrueTypeFont font; + private readonly TrueTypeFontProgram fontProgram; private readonly int firstCharacter; @@ -39,13 +39,13 @@ FontDescriptor descriptor, [CanBeNull] CMap toUnicodeCMap, [CanBeNull] Encoding encoding, - [CanBeNull] TrueTypeFont font, + [CanBeNull] TrueTypeFontProgram fontProgram, int firstCharacter, decimal[] widths) { this.descriptor = descriptor; this.encoding = encoding; - this.font = font; + this.fontProgram = fontProgram; this.firstCharacter = firstCharacter; this.widths = widths; @@ -115,9 +115,9 @@ fromFont = false; width = widths[index]; } - else if (font != null) + else if (fontProgram != null) { - if (!font.TryGetBoundingAdvancedWidth(characterCode, out width)) + if (!fontProgram.TryGetBoundingAdvancedWidth(characterCode, out width)) { width = boundingBoxPreTransform; } @@ -143,17 +143,17 @@ { fromFont = true; - if (font == null) + if (fontProgram == null) { return descriptor.BoundingBox; } - if (font.TryGetBoundingBox(characterCode, out var bounds)) + if (fontProgram.TryGetBoundingBox(characterCode, out var bounds)) { return bounds; } - if (font.TryGetBoundingAdvancedWidth(characterCode, out var width)) + if (fontProgram.TryGetBoundingAdvancedWidth(characterCode, out var width)) { return new PdfRectangle(0, 0, width, 0); } @@ -179,9 +179,9 @@ { var scale = 1000m; - if (font?.HeaderTable != null) + if (fontProgram?.HeaderTable != null) { - scale = font.GetFontMatrixMultiplier(); + scale = fontProgram.GetFontMatrixMultiplier(); } return TransformationMatrix.FromValues(1m / scale, 0, 0, 1m / scale, 0, 0); diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs index b997bc80..d5554b2f 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs @@ -23,7 +23,7 @@ /// /// Defines mapping of character codes to glyph index values in the font. - /// Can contain mutliple sub-tables to support multiple encoding schemes. + /// Can contain multiple sub-tables to support multiple encoding schemes. /// Where a character code isn't found it should map to index 0. /// public CMapTable CMapTable { get; set; } diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs index 1cd6c9ad..a36436df 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs @@ -7,7 +7,7 @@ internal class TrueTypeFontParser { - public TrueTypeFont Parse(TrueTypeDataBytes data) + public TrueTypeFontProgram Parse(TrueTypeDataBytes data) { var version = (decimal)data.Read32Fixed(); int numberOfTables = data.ReadUnsignedShort(); @@ -53,7 +53,7 @@ return new TrueTypeHeaderTable(tag, checksum, offset, length); } - private static TrueTypeFont ParseTables(decimal version, IReadOnlyDictionary tables, TrueTypeDataBytes data) + private static TrueTypeFontProgram ParseTables(decimal version, IReadOnlyDictionary tables, TrueTypeDataBytes data) { var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff); @@ -111,7 +111,7 @@ OptionallyParseTables(tables, data, tableRegister); } - return new TrueTypeFont(version, tables, tableRegister); + return new TrueTypeFontProgram(version, tables, tableRegister); } private static void OptionallyParseTables(IReadOnlyDictionary tables, TrueTypeDataBytes data, TableRegister tableRegister) diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFont.cs b/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFontProgram.cs similarity index 94% rename from src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFont.cs rename to src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFontProgram.cs index ec0b1f91..838f7d46 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFont.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFontProgram.cs @@ -7,7 +7,7 @@ using Parser; using Tables; - internal class TrueTypeFont : ICidFontProgram + internal class TrueTypeFontProgram : ICidFontProgram { public decimal Version { get; } @@ -18,7 +18,7 @@ public GlyphDataTable GlyphTable { get; } public TableRegister TableRegister { get; } - public TrueTypeFont(decimal version, IReadOnlyDictionary tableHeaders, TableRegister tableRegister) + public TrueTypeFontProgram(decimal version, IReadOnlyDictionary tableHeaders, TableRegister tableRegister) { Version = version; TableHeaders = tableHeaders; diff --git a/src/UglyToad.PdfPig/Tokens/BooleanToken.cs b/src/UglyToad.PdfPig/Tokens/BooleanToken.cs index c037ce37..95e16168 100644 --- a/src/UglyToad.PdfPig/Tokens/BooleanToken.cs +++ b/src/UglyToad.PdfPig/Tokens/BooleanToken.cs @@ -5,7 +5,7 @@ /// /// The boolean object either () or (). /// - public class BooleanToken : IDataToken + public sealed class BooleanToken : IDataToken { /// /// The boolean token corresponding to . @@ -43,15 +43,7 @@ return other.Data == Data; } - - /// - /// Check if two boolean tokens are equal in value. - /// - protected bool Equals(BooleanToken other) - { - return Data == other.Data; - } - + /// public override int GetHashCode() { diff --git a/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs b/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs index 356d257b..622a0efe 100644 --- a/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs +++ b/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs @@ -42,7 +42,7 @@ else { // For now: - throw new PdfDocumentFormatException("Key for dictionary token was not a string! " + keyValuePair.Key); + throw new PdfDocumentFormatException($"Key for dictionary token was not a name! {keyValuePair.Key}"); } } @@ -60,7 +60,7 @@ { if (!(token is IndirectReferenceToken indirectReference)) { - throw new InvalidOperationException($"Dictionary does not contain token with name {name} of type {typeof(T).Name}."); + throw new PdfDocumentFormatException($"Dictionary does not contain token with name {name} of type {typeof(T).Name}."); } typedToken = DirectObjectFinder.Get(indirectReference, scanner);