PathMarkupParserTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. using System.Globalization;
  2. using System.IO;
  3. using Avalonia.Media;
  4. using Avalonia.Platform;
  5. using Avalonia.Visuals.Platform;
  6. using Moq;
  7. using Xunit;
  8. namespace Avalonia.Base.UnitTests.Media
  9. {
  10. public class PathMarkupParserTests
  11. {
  12. [Fact]
  13. public void Parses_Move()
  14. {
  15. var pathGeometry = new PathGeometry();
  16. using (var context = new PathGeometryContext(pathGeometry))
  17. using (var parser = new PathMarkupParser(context))
  18. {
  19. parser.Parse("M10 10");
  20. var figure = pathGeometry.Figures[0];
  21. Assert.Equal(new Point(10, 10), figure.StartPoint);
  22. }
  23. }
  24. [Fact]
  25. public void Parses_Line()
  26. {
  27. var pathGeometry = new PathGeometry();
  28. using (var context = new PathGeometryContext(pathGeometry))
  29. using (var parser = new PathMarkupParser(context))
  30. {
  31. parser.Parse("M0 0L10 10");
  32. var figure = pathGeometry.Figures[0];
  33. var segment = figure.Segments[0];
  34. Assert.IsType<LineSegment>(segment);
  35. var lineSegment = (LineSegment)segment;
  36. Assert.Equal(new Point(10, 10), lineSegment.Point);
  37. }
  38. }
  39. [Fact]
  40. public void Parses_Close()
  41. {
  42. var pathGeometry = new PathGeometry();
  43. using (var context = new PathGeometryContext(pathGeometry))
  44. using (var parser = new PathMarkupParser(context))
  45. {
  46. parser.Parse("M0 0L10 10z");
  47. var figure = pathGeometry.Figures[0];
  48. Assert.True(figure.IsClosed);
  49. }
  50. }
  51. [Fact]
  52. public void Parses_FillMode_Before_Move()
  53. {
  54. var pathGeometry = new PathGeometry();
  55. using (var context = new PathGeometryContext(pathGeometry))
  56. using (var parser = new PathMarkupParser(context))
  57. {
  58. parser.Parse("F 1M0,0");
  59. Assert.Equal(FillRule.NonZero, pathGeometry.FillRule);
  60. }
  61. }
  62. [Theory]
  63. [InlineData("M0 0 10 10 20 20")]
  64. [InlineData("M0,0 10,10 20,20")]
  65. [InlineData("M0,0,10,10,20,20")]
  66. public void Parses_Implicit_Line_Command_After_Move(string pathData)
  67. {
  68. var pathGeometry = new PathGeometry();
  69. using (var context = new PathGeometryContext(pathGeometry))
  70. using (var parser = new PathMarkupParser(context))
  71. {
  72. parser.Parse(pathData);
  73. var figure = pathGeometry.Figures[0];
  74. var segment = figure.Segments[0];
  75. Assert.IsType<LineSegment>(segment);
  76. var lineSegment = (LineSegment)segment;
  77. Assert.Equal(new Point(10, 10), lineSegment.Point);
  78. segment = figure.Segments[1];
  79. Assert.IsType<LineSegment>(segment);
  80. lineSegment = (LineSegment)segment;
  81. Assert.Equal(new Point(20, 20), lineSegment.Point);
  82. }
  83. }
  84. [Theory]
  85. [InlineData("m0 0 10 10 20 20")]
  86. [InlineData("m0,0 10,10 20,20")]
  87. [InlineData("m0,0,10,10,20,20")]
  88. public void Parses_Implicit_Line_Command_After_Relative_Move(string pathData)
  89. {
  90. var pathGeometry = new PathGeometry();
  91. using (var context = new PathGeometryContext(pathGeometry))
  92. using (var parser = new PathMarkupParser(context))
  93. {
  94. parser.Parse(pathData);
  95. var figure = pathGeometry.Figures[0];
  96. var segment = figure.Segments[0];
  97. Assert.IsType<LineSegment>(segment);
  98. var lineSegment = (LineSegment)segment;
  99. Assert.Equal(new Point(10, 10), lineSegment.Point);
  100. segment = figure.Segments[1];
  101. Assert.IsType<LineSegment>(segment);
  102. lineSegment = (LineSegment)segment;
  103. Assert.Equal(new Point(30, 30), lineSegment.Point);
  104. }
  105. }
  106. [Fact]
  107. public void Parses_Scientific_Notation_Double()
  108. {
  109. var pathGeometry = new PathGeometry();
  110. using (var context = new PathGeometryContext(pathGeometry))
  111. using (var parser = new PathMarkupParser(context))
  112. {
  113. parser.Parse("M -1.01725E-005 -1.01725e-005");
  114. var figure = pathGeometry.Figures[0];
  115. Assert.Equal(
  116. new Point(
  117. double.Parse("-1.01725E-005", NumberStyles.Float, CultureInfo.InvariantCulture),
  118. double.Parse("-1.01725E-005", NumberStyles.Float, CultureInfo.InvariantCulture)),
  119. figure.StartPoint);
  120. }
  121. }
  122. [Theory]
  123. [InlineData("M5.5.5 5.5.5 5.5.5")]
  124. [InlineData("F1M9.0771,11C9.1161,10.701,9.1801,10.352,9.3031,10L9.0001,10 9.0001,6.166 3.0001,9.767 3.0001,10 "
  125. + "9.99999999997669E-05,10 9.99999999997669E-05,0 3.0001,0 3.0001,0.234 9.0001,3.834 9.0001,0 "
  126. + "12.0001,0 12.0001,8.062C12.1861,8.043 12.3821,8.031 12.5941,8.031 15.3481,8.031 15.7961,9.826 "
  127. + "15.9201,11L16.0001,16 9.0001,16 9.0001,12.562 9.0001,11z")] // issue #1708
  128. [InlineData(" M0 0")]
  129. [InlineData("F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z")] // issue #1107
  130. [InlineData("M0 0L10 10z")]
  131. [InlineData("M50 50 L100 100 L150 50")]
  132. [InlineData("M50 50L100 100L150 50")]
  133. [InlineData("M50,50 L100,100 L150,50")]
  134. [InlineData("M50 50 L-10 -10 L10 50")]
  135. [InlineData("M50 50L-10-10L10 50")]
  136. [InlineData("M50 50 L100 100 L150 50zM50 50 L70 70 L120 50z")]
  137. [InlineData("M 50 50 L 100 100 L 150 50")]
  138. [InlineData("M50 50 L100 100 L150 50 H200 V100Z")]
  139. [InlineData("M 80 200 A 100 50 45 1 0 100 50")]
  140. [InlineData(
  141. "F1 M 16.6309 18.6563C 17.1309 8.15625 29.8809 14.1563 29.8809 14.1563C 30.8809 11.1563 34.1308 11.4063" +
  142. " 34.1308 11.4063C 33.5 12 34.6309 13.1563 34.6309 13.1563C 32.1309 13.1562 31.1309 14.9062 31.1309 14.9" +
  143. "062C 41.1309 23.9062 32.6309 27.9063 32.6309 27.9062C 24.6309 24.9063 21.1309 22.1562 16.6309 18.6563 Z" +
  144. " M 16.6309 19.9063C 21.6309 24.1563 25.1309 26.1562 31.6309 28.6562C 31.6309 28.6562 26.3809 39.1562 18" +
  145. ".3809 36.1563C 18.3809 36.1563 18 38 16.3809 36.9063C 15 36 16.3809 34.9063 16.3809 34.9063C 16.3809 34" +
  146. ".9063 10.1309 30.9062 16.6309 19.9063 Z ")]
  147. [InlineData(
  148. "F1M16,12C16,14.209 14.209,16 12,16 9.791,16 8,14.209 8,12 8,11.817 8.03,11.644 8.054,11.467L6.585,10 4,10 " +
  149. "4,6.414 2.5,7.914 0,5.414 0,3.586 3.586,0 4.414,0 7.414,3 7.586,3 9,1.586 11.914,4.5 10.414,6 " +
  150. "12.461,8.046C14.45,8.278,16,9.949,16,12")]
  151. public void Should_Parse(string pathData)
  152. {
  153. var pathGeometry = new PathGeometry();
  154. using (var context = new PathGeometryContext(pathGeometry))
  155. using (var parser = new PathMarkupParser(context))
  156. {
  157. parser.Parse(pathData);
  158. Assert.True(true);
  159. }
  160. }
  161. [Theory]
  162. [InlineData("M0 0L10 10")]
  163. [InlineData("M0 0L10 10z")]
  164. [InlineData("M0 0L10 10 \n ")]
  165. [InlineData("M0 0L10 10z \n ")]
  166. [InlineData("M0 0L10 10 ")]
  167. [InlineData("M0 0L10 10z ")]
  168. public void Should_AlwaysEndFigure(string pathData)
  169. {
  170. var context = new Mock<IGeometryContext>();
  171. using (var parser = new PathMarkupParser(context.Object))
  172. {
  173. parser.Parse(pathData);
  174. }
  175. context.Verify(v => v.EndFigure(It.IsAny<bool>()), Times.AtLeastOnce());
  176. }
  177. [Theory]
  178. [InlineData("M 5.5, 5 L 5.5, 5 L 5.5, 5")]
  179. [InlineData("F1 M 9.0771, 11 C 9.1161, 10.701 9.1801, 10.352 9.3031, 10 L 9.0001, 10 L 9.0001, 6.166 L 3.0001, 9.767 L 3.0001, 10 "
  180. + "L 9.99999999997669E-05, 10 L 9.99999999997669E-05, 0 L 3.0001, 0 L 3.0001, 0.234 L 9.0001, 3.834 L 9.0001, 0 "
  181. + "L 12.0001, 0 L 12.0001, 8.062 C 12.1861, 8.043 12.3821, 8.031 12.5941, 8.031 C 15.3481, 8.031 15.7961, 9.826 "
  182. + "15.9201, 11 L 16.0001, 16 L 9.0001, 16 L 9.0001, 12.562 L 9.0001, 11Z")]
  183. [InlineData("F1 M 24, 14 A 2, 2 0 1 1 20, 14 A 2, 2 0 1 1 24, 14Z")]
  184. [InlineData("M 0, 0 L 10, 10Z")]
  185. [InlineData("M 50, 50 L 100, 100 L 150, 50")]
  186. [InlineData("M 50, 50 L -10, -10 L 10, 50")]
  187. [InlineData("M 50, 50 L 100, 100 L 150, 50Z M 50, 50 L 70, 70 L 120, 50Z")]
  188. [InlineData("M 80, 200 A 100, 50 45 1 0 100, 50")]
  189. [InlineData("F1 M 16, 12 C 16, 14.209 14.209, 16 12, 16 C 9.791, 16 8, 14.209 8, 12 C 8, 11.817 8.03, 11.644 8.054, 11.467 L 6.585, 10 "
  190. + "L 4, 10 L 4, 6.414 L 2.5, 7.914 L 0, 5.414 L 0, 3.586 L 3.586, 0 L 4.414, 0 L 7.414, 3 L 7.586, 3 L 9, 1.586 L "
  191. + "11.914, 4.5 L 10.414, 6 L 12.461, 8.046 C 14.45, 8.278 16, 9.949 16, 12")]
  192. public void Parsed_Geometry_ToString_Should_Produce_Valid_Value(string pathData)
  193. {
  194. var target = PathGeometry.Parse(pathData);
  195. string output = target.ToString();
  196. Assert.Equal(pathData, output);
  197. }
  198. [Theory]
  199. [InlineData("M5.5.5 5.5.5 5.5.5", "M 5.5, 0.5 L 5.5, 0.5 L 5.5, 0.5")]
  200. [InlineData("F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z", "F1 M 24, 14 A 2, 2 0 1 1 20, 14 A 2, 2 0 1 1 24, 14Z")]
  201. [InlineData("F1M16,12C16,14.209 14.209,16 12,16 9.791,16 8,14.209 8,12 8,11.817 8.03,11.644 8.054,11.467L6.585,10 4,10 "
  202. + "4,6.414 2.5,7.914 0,5.414 0,3.586 3.586,0 4.414,0 7.414,3 7.586,3 9,1.586 11.914,4.5 10.414,6 "
  203. + "12.461,8.046C14.45,8.278,16,9.949,16,12",
  204. "F1 M 16, 12 C 16, 14.209 14.209, 16 12, 16 C 9.791, 16 8, 14.209 8, 12 C 8, 11.817 8.03, 11.644 8.054, 11.467 L 6.585, 10 "
  205. + "L 4, 10 L 4, 6.414 L 2.5, 7.914 L 0, 5.414 L 0, 3.586 L 3.586, 0 L 4.414, 0 L 7.414, 3 L 7.586, 3 L 9, 1.586 L "
  206. + "11.914, 4.5 L 10.414, 6 L 12.461, 8.046 C 14.45, 8.278 16, 9.949 16, 12")]
  207. public void Parsed_Geometry_ToString_Should_Format_Value(string pathData, string formattedPathData)
  208. {
  209. var target = PathGeometry.Parse(pathData);
  210. string output = target.ToString();
  211. Assert.Equal(formattedPathData, output);
  212. }
  213. [Theory]
  214. [InlineData("0 0")]
  215. [InlineData("j")]
  216. public void Throws_InvalidDataException_On_None_Defined_Command(string pathData)
  217. {
  218. var pathGeometry = new PathGeometry();
  219. using (var context = new PathGeometryContext(pathGeometry))
  220. using (var parser = new PathMarkupParser(context))
  221. {
  222. Assert.Throws<InvalidDataException>(() => parser.Parse(pathData));
  223. }
  224. }
  225. [Fact]
  226. public void CloseFigure_Should_Move_CurrentPoint_To_CreateFigurePoint()
  227. {
  228. var pathGeometry = new PathGeometry();
  229. using (var context = new PathGeometryContext(pathGeometry))
  230. using (var parser = new PathMarkupParser(context))
  231. {
  232. parser.Parse("M10,10L100,100Z m10,10");
  233. Assert.Equal(2, pathGeometry.Figures.Count);
  234. var figure = pathGeometry.Figures[0];
  235. Assert.Equal(new Point(10, 10), figure.StartPoint);
  236. Assert.Equal(true, figure.IsClosed);
  237. Assert.Equal(new Point(100, 100), ((LineSegment)figure.Segments[0]).Point);
  238. figure = pathGeometry.Figures[1];
  239. Assert.Equal(new Point(20, 20), figure.StartPoint);
  240. }
  241. }
  242. [Fact]
  243. public void Should_Parse_Flags_Without_Separator()
  244. {
  245. var pathGeometry = new PathGeometry();
  246. using (var context = new PathGeometryContext(pathGeometry))
  247. using (var parser = new PathMarkupParser(context))
  248. {
  249. parser.Parse("a.898.898 0 01.27.188");
  250. var figure = pathGeometry.Figures[0];
  251. var segments = figure.Segments;
  252. Assert.NotNull(segments);
  253. Assert.Equal(1, segments.Count);
  254. var arcSegment = segments[0];
  255. Assert.IsType<ArcSegment>(arcSegment);
  256. }
  257. }
  258. [Fact]
  259. public void Should_Handle_StartPoint_After_Empty_Figure()
  260. {
  261. var pathGeometry = new PathGeometry();
  262. using var context = new PathGeometryContext(pathGeometry);
  263. using var parser = new PathMarkupParser(context);
  264. parser.Parse("M50,50z l -5,-5");
  265. Assert.Equal(2, pathGeometry.Figures.Count);
  266. var firstFigure = pathGeometry.Figures[0];
  267. Assert.Equal(new Point(50, 50), firstFigure.StartPoint);
  268. var secondFigure = pathGeometry.Figures[1];
  269. Assert.Equal(new Point(50, 50), secondFigure.StartPoint);
  270. }
  271. }
  272. }