TextStyleTests.cs 21 KB

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