TextSpanTests.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. using System;
  2. using System.Linq;
  3. using NUnit.Framework;
  4. using QuestPDF.Elements.Text;
  5. using QuestPDF.Elements.Text.Items;
  6. using QuestPDF.Fluent;
  7. using QuestPDF.Helpers;
  8. using QuestPDF.Infrastructure;
  9. using QuestPDF.Skia.Text;
  10. namespace QuestPDF.UnitTests;
  11. public class TextSpanTests
  12. {
  13. internal (TextSpanDescriptor, TextBlockSpan) CreateTextBlockSpan()
  14. {
  15. var container = EmptyContainer.Create();
  16. var descriptor = container.Text("test");
  17. var textElement = container.Child as TextBlock;
  18. var textBlockSpan = textElement?.Items.SingleOrDefault() as TextBlockSpan;
  19. return (descriptor, textBlockSpan);
  20. }
  21. #region Override Style
  22. [Test]
  23. public void OverridesStyle()
  24. {
  25. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  26. var customStyle = TextStyle
  27. .Default
  28. .FontColor(Colors.Black)
  29. .BackgroundColor(Colors.Transparent)
  30. .Underline()
  31. .DecorationColor(Colors.Red.Medium)
  32. .DecorationWavy();
  33. descriptor
  34. .FontSize(30)
  35. .FontColor(Colors.Blue.Darken4)
  36. .BackgroundColor(Colors.Blue.Lighten5)
  37. .Bold()
  38. .Style(customStyle);
  39. Assert.That(textBlockSpan.Style.Size, Is.EqualTo(30));
  40. Assert.That(textBlockSpan.Style.Color, Is.EqualTo(Colors.Black));
  41. Assert.That(textBlockSpan.Style.BackgroundColor, Is.EqualTo(Colors.Transparent));
  42. Assert.That(textBlockSpan.Style.HasUnderline, Is.True);
  43. Assert.That(textBlockSpan.Style.DecorationColor, Is.EqualTo(Colors.Red.Medium));
  44. Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Wavy));
  45. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Bold));
  46. }
  47. [Test]
  48. public void OverridesStyle_AcceptsNull()
  49. {
  50. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  51. descriptor
  52. .FontSize(30)
  53. .FontColor(Colors.Blue.Darken4)
  54. .BackgroundColor(Colors.Blue.Lighten5)
  55. .Bold()
  56. .Style(null);
  57. Assert.That(textBlockSpan.Style.Size, Is.EqualTo(30));
  58. Assert.That(textBlockSpan.Style.Color, Is.EqualTo(Colors.Blue.Darken4));
  59. Assert.That(textBlockSpan.Style.BackgroundColor, Is.EqualTo(Colors.Blue.Lighten5));
  60. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Bold));
  61. }
  62. #endregion
  63. #region Font Color
  64. [Test]
  65. public void SetsCorrectFontColor()
  66. {
  67. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  68. descriptor.FontColor(Colors.Blue.Medium);
  69. Assert.That(textBlockSpan.Style.Color, Is.EqualTo(Colors.Blue.Medium));
  70. }
  71. [Test]
  72. public void FontColor_AlsoSetsDecorationColor()
  73. {
  74. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  75. descriptor.FontColor(Colors.Green.Darken2);
  76. Assert.That(textBlockSpan.Style.DecorationColor, Is.EqualTo(Colors.Green.Darken2));
  77. }
  78. #endregion
  79. #region Background Color
  80. [Test]
  81. public void SetsCorrectBackgroundColor()
  82. {
  83. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  84. descriptor.BackgroundColor(Colors.Yellow.Lighten3);
  85. Assert.That(textBlockSpan.Style.BackgroundColor, Is.EqualTo(Colors.Yellow.Lighten3));
  86. }
  87. #endregion
  88. #region Font Family
  89. [Test]
  90. public void SetsCorrectFontFamily_Single()
  91. {
  92. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  93. descriptor.FontFamily("Arial");
  94. Assert.That(textBlockSpan.Style.FontFamilies, Is.EqualTo(new[] { "Arial" }));
  95. }
  96. [Test]
  97. public void SetsCorrectFontFamily_Multiple()
  98. {
  99. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  100. descriptor.FontFamily("Helvetica", "Arial", "sans-serif");
  101. Assert.That(textBlockSpan.Style.FontFamilies, Is.EqualTo(new[] { "Helvetica", "Arial", "sans-serif" }));
  102. }
  103. [Test]
  104. public void FontFamily_EmptyArray_ReturnsUnchanged()
  105. {
  106. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  107. descriptor.FontFamily([]);
  108. Assert.That(textBlockSpan.Style.FontFamilies, Is.Null);
  109. }
  110. [Test]
  111. public void FontFamily_Null_ReturnsUnchanged()
  112. {
  113. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  114. descriptor.FontFamily(null);
  115. Assert.That(textBlockSpan.Style.FontFamilies, Is.Null);
  116. }
  117. #endregion
  118. #region Font Size
  119. [Test]
  120. public void SetsCorrectFontSize()
  121. {
  122. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  123. descriptor.FontSize(18);
  124. Assert.That(textBlockSpan.Style.Size, Is.EqualTo(18));
  125. }
  126. [TestCase(-10)]
  127. [TestCase(-5)]
  128. [TestCase(-float.Epsilon)]
  129. [TestCase(0)]
  130. public void FontSize_MustBePositive(float fontSize)
  131. {
  132. var exception = Assert.Throws<ArgumentException>(() =>
  133. {
  134. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  135. descriptor.FontSize(fontSize);
  136. });
  137. Assert.That(exception.Message, Is.EqualTo("Font size must be greater than 0."));
  138. }
  139. #endregion
  140. #region Line Height
  141. [Test]
  142. public void SetsCorrectLineHeight()
  143. {
  144. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  145. descriptor.LineHeight(1.5f);
  146. Assert.That(textBlockSpan.Style.LineHeight, Is.EqualTo(1.5f));
  147. }
  148. [Test]
  149. public void LineHeight_Null_SetsToNormalLineHeight()
  150. {
  151. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  152. descriptor.LineHeight(null);
  153. Assert.That(textBlockSpan.Style.LineHeight, Is.EqualTo(TextStyle.NormalLineHeightCalculatedFromFontMetrics));
  154. }
  155. [TestCase(-5)]
  156. [TestCase(-float.Epsilon)]
  157. public void LineHeightMustBePositive(float lineHeight)
  158. {
  159. var exception = Assert.Throws<ArgumentException>(() =>
  160. {
  161. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  162. descriptor.LineHeight(lineHeight);
  163. });
  164. Assert.That(exception.Message, Is.EqualTo("Line height must be greater than 0."));
  165. }
  166. [Test]
  167. public void LineHeight_AllowsZero()
  168. {
  169. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  170. descriptor.LineHeight(0);
  171. Assert.That(textBlockSpan.Style.LineHeight, Is.Zero);
  172. }
  173. #endregion
  174. #region Letter Spacing
  175. [Test]
  176. public void SetsCorrectLetterSpacing_Positive()
  177. {
  178. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  179. descriptor.LetterSpacing(0.5f);
  180. Assert.That(textBlockSpan.Style.LetterSpacing, Is.EqualTo(0.5f));
  181. }
  182. [Test]
  183. public void SetsCorrectLetterSpacing_Negative()
  184. {
  185. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  186. descriptor.LetterSpacing(-0.2f);
  187. Assert.That(textBlockSpan.Style.LetterSpacing, Is.EqualTo(-0.2f));
  188. }
  189. [Test]
  190. public void LetterSpacing_DefaultParameterIsZero()
  191. {
  192. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  193. descriptor.LetterSpacing();
  194. Assert.That(textBlockSpan.Style.LetterSpacing, Is.Zero);
  195. }
  196. #endregion
  197. #region Word Spacing
  198. [Test]
  199. public void SetsCorrectWordSpacing_Positive()
  200. {
  201. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  202. descriptor.WordSpacing(2.0f);
  203. Assert.That(textBlockSpan.Style.WordSpacing, Is.EqualTo(2.0f));
  204. }
  205. [Test]
  206. public void SetsCorrectWordSpacing_Negative()
  207. {
  208. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  209. descriptor.WordSpacing(-1.0f);
  210. Assert.That(textBlockSpan.Style.WordSpacing, Is.EqualTo(-1.0f));
  211. }
  212. [Test]
  213. public void WordSpacing_DefaultParameterIsZero()
  214. {
  215. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  216. descriptor.WordSpacing();
  217. Assert.That(textBlockSpan.Style.WordSpacing, Is.Zero);
  218. }
  219. #endregion
  220. #region Italic
  221. [Test]
  222. public void SetsCorrectItalic_Enabled()
  223. {
  224. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  225. descriptor.Italic();
  226. Assert.That(textBlockSpan.Style.IsItalic, Is.True);
  227. }
  228. [Test]
  229. public void SetsCorrectItalic_Disabled()
  230. {
  231. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  232. descriptor.Italic().Italic(false);
  233. Assert.That(textBlockSpan.Style.IsItalic, Is.False);
  234. }
  235. #endregion
  236. #region Text Decoration
  237. [Test]
  238. public void SetsCorrectTextDecoration_Strikethrough()
  239. {
  240. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  241. descriptor.Strikethrough();
  242. Assert.That(textBlockSpan.Style.HasStrikethrough, Is.True);
  243. }
  244. [Test]
  245. public void SetsCorrectTextDecoration_StrikethroughDisabled()
  246. {
  247. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  248. descriptor.Strikethrough(false);
  249. Assert.That(textBlockSpan.Style.HasStrikethrough, Is.False);
  250. }
  251. [Test]
  252. public void SetsCorrectTextDecoration_Underline()
  253. {
  254. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  255. descriptor.Underline();
  256. Assert.That(textBlockSpan.Style.HasUnderline, Is.True);
  257. }
  258. [Test]
  259. public void SetsCorrectTextDecoration_UnderlineDisabled()
  260. {
  261. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  262. descriptor.Underline(false);
  263. Assert.That(textBlockSpan.Style.HasUnderline, Is.False);
  264. }
  265. [Test]
  266. public void SetsCorrectTextDecoration_Overline()
  267. {
  268. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  269. descriptor.Overline();
  270. Assert.That(textBlockSpan.Style.HasOverline, Is.True);
  271. }
  272. [Test]
  273. public void SetsCorrectTextDecoration_OverlineDisabled()
  274. {
  275. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  276. descriptor.Overline(false);
  277. Assert.That(textBlockSpan.Style.HasOverline, Is.False);
  278. }
  279. [Test]
  280. public void SetsCorrectTextDecoration_DecorationColor()
  281. {
  282. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  283. descriptor.DecorationColor(Colors.Red.Medium);
  284. Assert.That(textBlockSpan.Style.DecorationColor, Is.EqualTo(Colors.Red.Medium));
  285. }
  286. [Test]
  287. public void SetsCorrectTextDecoration_DecorationThickness()
  288. {
  289. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  290. descriptor.DecorationThickness(1.5f);
  291. Assert.That(textBlockSpan.Style.DecorationThickness, Is.EqualTo(1.5f));
  292. }
  293. [Test]
  294. public void SetsCorrectTextDecoration_DecorationSolid()
  295. {
  296. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  297. descriptor.DecorationSolid();
  298. Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Solid));
  299. }
  300. [Test]
  301. public void SetsCorrectTextDecoration_DecorationDouble()
  302. {
  303. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  304. descriptor.DecorationDouble();
  305. Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Double));
  306. }
  307. [Test]
  308. public void SetsCorrectTextDecoration_DecorationWavy()
  309. {
  310. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  311. descriptor.DecorationWavy();
  312. Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Wavy));
  313. }
  314. [Test]
  315. public void SetsCorrectTextDecoration_DecorationDotted()
  316. {
  317. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  318. descriptor.DecorationDotted();
  319. Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Dotted));
  320. }
  321. [Test]
  322. public void SetsCorrectTextDecoration_DecorationDashed()
  323. {
  324. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  325. descriptor.DecorationDashed();
  326. Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Dashed));
  327. }
  328. #endregion
  329. #region Font Weight
  330. [Test]
  331. public void SetsCorrectSetsCorrectFontWeight_Thin()
  332. {
  333. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  334. descriptor.Thin();
  335. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Thin));
  336. }
  337. [Test]
  338. public void SetsCorrectFontWeight_ExtraLight()
  339. {
  340. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  341. descriptor.ExtraLight();
  342. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.ExtraLight));
  343. }
  344. [Test]
  345. public void SetsCorrectFontWeight_Light()
  346. {
  347. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  348. descriptor.Light();
  349. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Light));
  350. }
  351. [Test]
  352. public void SetsCorrectFontWeight_Normal()
  353. {
  354. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  355. descriptor.NormalWeight();
  356. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Normal));
  357. }
  358. [Test]
  359. public void SetsCorrectFontWeight_Medium()
  360. {
  361. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  362. descriptor.Medium();
  363. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Medium));
  364. }
  365. [Test]
  366. public void SetsCorrectFontWeight_SemiBold()
  367. {
  368. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  369. descriptor.SemiBold();
  370. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.SemiBold));
  371. }
  372. [Test]
  373. public void SetsCorrectFontWeight_Bold()
  374. {
  375. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  376. descriptor.Bold();
  377. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Bold));
  378. }
  379. [Test]
  380. public void SetsCorrectFontWeight_ExtraBold()
  381. {
  382. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  383. descriptor.ExtraBold();
  384. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.ExtraBold));
  385. }
  386. [Test]
  387. public void SetsCorrectFontWeight_Black()
  388. {
  389. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  390. descriptor.Black();
  391. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Black));
  392. }
  393. [Test]
  394. public void SetsCorrectFontWeight_ExtraBlack()
  395. {
  396. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  397. descriptor.ExtraBlack();
  398. Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.ExtraBlack));
  399. }
  400. #endregion
  401. #region Text Position
  402. [Test]
  403. public void SetsCorrectTextPosition_Subscript()
  404. {
  405. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  406. descriptor.Subscript();
  407. Assert.That(textBlockSpan.Style.FontPosition, Is.EqualTo(FontPosition.Subscript));
  408. }
  409. [Test]
  410. public void SetsCorrectTextPosition_Normal()
  411. {
  412. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  413. descriptor.Superscript().NormalPosition(); // first change from default, then normal
  414. Assert.That(textBlockSpan.Style.FontPosition, Is.EqualTo(FontPosition.Normal));
  415. }
  416. [Test]
  417. public void SetsCorrectTextPosition_Superscript()
  418. {
  419. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  420. descriptor.Superscript();
  421. Assert.That(textBlockSpan.Style.FontPosition, Is.EqualTo(FontPosition.Superscript));
  422. }
  423. #endregion
  424. #region Text Direction
  425. [Test]
  426. public void SetsCorrectTextDirection_LeftToRight()
  427. {
  428. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  429. descriptor.DirectionFromLeftToRight();
  430. Assert.That(textBlockSpan.Style.Direction, Is.EqualTo(TextDirection.LeftToRight));
  431. }
  432. [Test]
  433. public void SetsCorrectTextDirection_RightToLeft()
  434. {
  435. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  436. descriptor.DirectionFromRightToLeft();
  437. Assert.That(textBlockSpan.Style.Direction, Is.EqualTo(TextDirection.RightToLeft));
  438. }
  439. [Test]
  440. public void SetsCorrectTextDirection_Auto()
  441. {
  442. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  443. descriptor.DirectionFromRightToLeft().DirectionAuto();
  444. Assert.That(textBlockSpan.Style.Direction, Is.EqualTo(TextDirection.Auto));
  445. }
  446. #endregion
  447. #region Font Features
  448. [Test]
  449. public void EnableFontFeature_SingleFeature()
  450. {
  451. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  452. descriptor.EnableFontFeature(FontFeatures.StandardLigatures);
  453. Assert.That(textBlockSpan.Style.FontFeatures, Has.Length.EqualTo(1));
  454. Assert.That(textBlockSpan.Style.FontFeatures[0], Is.EqualTo((FontFeatures.StandardLigatures, true)));
  455. }
  456. [Test]
  457. public void DisableFontFeature_SingleFeature()
  458. {
  459. var (descriptor, textBlockSpan) = CreateTextBlockSpan();
  460. descriptor.DisableFontFeature(FontFeatures.Kerning);
  461. Assert.That(textBlockSpan.Style.FontFeatures, Has.Length.EqualTo(1));
  462. Assert.That(textBlockSpan.Style.FontFeatures[0], Is.EqualTo((FontFeatures.Kerning, false)));
  463. }
  464. [Test]
  465. public void FontFeatures_MixedEnableDisable()
  466. {
  467. var textStyle = TextStyle.Default
  468. .EnableFontFeature(FontFeatures.StandardLigatures)
  469. .DisableFontFeature(FontFeatures.Kerning)
  470. .DisableFontFeature(FontFeatures.DiscretionaryLigatures)
  471. .EnableFontFeature(FontFeatures.Kerning);
  472. Assert.That(textStyle.FontFeatures, Has.Length.EqualTo(3));
  473. Assert.That(textStyle.FontFeatures[0], Is.EqualTo((FontFeatures.Kerning, true)));
  474. Assert.That(textStyle.FontFeatures[1], Is.EqualTo((FontFeatures.DiscretionaryLigatures, false)));
  475. Assert.That(textStyle.FontFeatures[2], Is.EqualTo((FontFeatures.StandardLigatures, true)));
  476. }
  477. #endregion
  478. }