GraphViewTests.cs 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Terminal.Gui;
  5. using Xunit;
  6. using Terminal.Gui.Graphs;
  7. using Point = Terminal.Gui.Point;
  8. using Attribute = Terminal.Gui.Attribute;
  9. using System.Text;
  10. using System.Text.RegularExpressions;
  11. namespace Terminal.Gui.Views {
  12. #region Helper Classes
  13. class FakeHAxis : HorizontalAxis {
  14. public List<Point> DrawAxisLinePoints = new List<Point> ();
  15. public List<int> LabelPoints = new List<int>();
  16. protected override void DrawAxisLine (GraphView graph, int x, int y)
  17. {
  18. base.DrawAxisLine (graph, x, y);
  19. DrawAxisLinePoints.Add (new Point(x, y));
  20. }
  21. public override void DrawAxisLabel (GraphView graph, int screenPosition, string text)
  22. {
  23. base.DrawAxisLabel (graph, screenPosition, text);
  24. LabelPoints.Add(screenPosition);
  25. }
  26. }
  27. class FakeVAxis : VerticalAxis {
  28. public List<Point> DrawAxisLinePoints = new List<Point> ();
  29. public List<int> LabelPoints = new List<int>();
  30. protected override void DrawAxisLine (GraphView graph, int x, int y)
  31. {
  32. base.DrawAxisLine (graph, x, y);
  33. DrawAxisLinePoints.Add (new Point(x, y));
  34. }
  35. public override void DrawAxisLabel (GraphView graph, int screenPosition, string text)
  36. {
  37. base.DrawAxisLabel (graph, screenPosition, text);
  38. LabelPoints.Add(screenPosition);
  39. }
  40. }
  41. #endregion
  42. public class GraphViewTests {
  43. public static FakeDriver InitFakeDriver ()
  44. {
  45. var driver = new FakeDriver ();
  46. Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
  47. driver.Init (() => { });
  48. return driver;
  49. }
  50. /// <summary>
  51. /// Returns a basic very small graph (10 x 5)
  52. /// </summary>
  53. /// <returns></returns>
  54. public static GraphView GetGraph ()
  55. {
  56. GraphViewTests.InitFakeDriver ();
  57. var gv = new GraphView ();
  58. gv.ColorScheme = new ColorScheme ();
  59. gv.MarginBottom = 1;
  60. gv.MarginLeft = 1;
  61. gv.Bounds = new Rect (0, 0, 10, 5);
  62. return gv;
  63. }
  64. #pragma warning disable xUnit1013 // Public method should be marked as test
  65. public static void AssertDriverContentsAre (string expectedLook)
  66. {
  67. #pragma warning restore xUnit1013 // Public method should be marked as test
  68. var sb = new StringBuilder ();
  69. var driver = ((FakeDriver)Application.Driver);
  70. var contents = driver.Contents;
  71. for (int r = 0; r < driver.Rows; r++) {
  72. for (int c = 0; c < driver.Cols; c++) {
  73. sb.Append ((char)contents [r, c, 0]);
  74. }
  75. sb.AppendLine ();
  76. }
  77. var actualLook = sb.ToString ();
  78. if (!string.Equals (expectedLook, actualLook)) {
  79. // ignore trailing whitespace on each line
  80. var trailingWhitespace = new Regex (@"\s+$",RegexOptions.Multiline);
  81. // get rid of trailing whitespace on each line (and leading/trailing whitespace of start/end of full string)
  82. expectedLook = trailingWhitespace.Replace(expectedLook,"").Trim();
  83. actualLook = trailingWhitespace.Replace (actualLook, "").Trim ();
  84. // standardise line endings for the comparison
  85. expectedLook = expectedLook.Replace ("\r\n", "\n");
  86. actualLook = actualLook.Replace ("\r\n", "\n");
  87. Console.WriteLine ("Expected:" + Environment.NewLine + expectedLook);
  88. Console.WriteLine ("But Was:" + Environment.NewLine + actualLook);
  89. Assert.Equal (expectedLook, actualLook);
  90. }
  91. }
  92. #region Screen to Graph Tests
  93. [Fact]
  94. public void ScreenToGraphSpace_DefaultCellSize ()
  95. {
  96. var gv = new GraphView ();
  97. gv.Bounds = new Rect (0, 0, 20, 10);
  98. // origin should be bottom left
  99. var botLeft = gv.ScreenToGraphSpace (0, 9);
  100. Assert.Equal (0, botLeft.X);
  101. Assert.Equal (0, botLeft.Y);
  102. Assert.Equal (1, botLeft.Width);
  103. Assert.Equal (1, botLeft.Height);
  104. // up 2 rows of the console and along 1 col
  105. var up2along1 = gv.ScreenToGraphSpace (1, 7);
  106. Assert.Equal (1, up2along1.X);
  107. Assert.Equal (2, up2along1.Y);
  108. }
  109. [Fact]
  110. public void ScreenToGraphSpace_DefaultCellSize_WithMargin ()
  111. {
  112. var gv = new GraphView ();
  113. gv.Bounds = new Rect (0, 0, 20, 10);
  114. // origin should be bottom left
  115. var botLeft = gv.ScreenToGraphSpace (0, 9);
  116. Assert.Equal (0, botLeft.X);
  117. Assert.Equal (0, botLeft.Y);
  118. Assert.Equal (1, botLeft.Width);
  119. Assert.Equal (1, botLeft.Height);
  120. gv.MarginLeft = 1;
  121. botLeft = gv.ScreenToGraphSpace (0, 9);
  122. // Origin should be at 1,9 now to leave a margin of 1
  123. // so screen position 0,9 would be data space -1,0
  124. Assert.Equal (-1, botLeft.X);
  125. Assert.Equal (0, botLeft.Y);
  126. Assert.Equal (1, botLeft.Width);
  127. Assert.Equal (1, botLeft.Height);
  128. gv.MarginLeft = 1;
  129. gv.MarginBottom = 1;
  130. botLeft = gv.ScreenToGraphSpace (0, 9);
  131. // Origin should be at 1,0 (to leave a margin of 1 in both sides)
  132. // so screen position 0,9 would be data space -1,-1
  133. Assert.Equal (-1, botLeft.X);
  134. Assert.Equal (-1, botLeft.Y);
  135. Assert.Equal (1, botLeft.Width);
  136. Assert.Equal (1, botLeft.Height);
  137. }
  138. [Fact]
  139. public void ScreenToGraphSpace_CustomCellSize ()
  140. {
  141. var gv = new GraphView ();
  142. gv.Bounds = new Rect (0, 0, 20, 10);
  143. // Each cell of screen measures 5 units in graph data model vertically and 1/4 horizontally
  144. gv.CellSize = new PointF (0.25f, 5);
  145. // origin should be bottom left
  146. // (note that y=10 is actually overspilling the control, the last row is 9)
  147. var botLeft = gv.ScreenToGraphSpace (0, 9);
  148. Assert.Equal (0, botLeft.X);
  149. Assert.Equal (0, botLeft.Y);
  150. Assert.Equal (0.25f, botLeft.Width);
  151. Assert.Equal (5, botLeft.Height);
  152. // up 2 rows of the console and along 1 col
  153. var up2along1 = gv.ScreenToGraphSpace (1, 7);
  154. Assert.Equal (0.25f, up2along1.X);
  155. Assert.Equal (10, up2along1.Y);
  156. Assert.Equal (0.25f, botLeft.Width);
  157. Assert.Equal (5, botLeft.Height);
  158. }
  159. #endregion
  160. #region Graph to Screen Tests
  161. [Fact]
  162. public void GraphSpaceToScreen_DefaultCellSize ()
  163. {
  164. var gv = new GraphView ();
  165. gv.Bounds = new Rect (0, 0, 20, 10);
  166. // origin should be bottom left
  167. var botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  168. Assert.Equal (0, botLeft.X);
  169. Assert.Equal (9, botLeft.Y); // row 9 of the view is the bottom left
  170. // along 2 and up 1 in graph space
  171. var along2up1 = gv.GraphSpaceToScreen (new PointF (2, 1));
  172. Assert.Equal (2, along2up1.X);
  173. Assert.Equal (8, along2up1.Y);
  174. }
  175. [Fact]
  176. public void GraphSpaceToScreen_DefaultCellSize_WithMargin ()
  177. {
  178. var gv = new GraphView ();
  179. gv.Bounds = new Rect (0, 0, 20, 10);
  180. // origin should be bottom left
  181. var botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  182. Assert.Equal (0, botLeft.X);
  183. Assert.Equal (9, botLeft.Y); // row 9 of the view is the bottom left
  184. gv.MarginLeft = 1;
  185. // With a margin of 1 the origin should be at x=1 y= 9
  186. botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  187. Assert.Equal (1, botLeft.X);
  188. Assert.Equal (9, botLeft.Y); // row 9 of the view is the bottom left
  189. gv.MarginLeft = 1;
  190. gv.MarginBottom = 1;
  191. // With a margin of 1 in both directions the origin should be at x=1 y= 9
  192. botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  193. Assert.Equal (1, botLeft.X);
  194. Assert.Equal (8, botLeft.Y); // row 8 of the view is the bottom left up 1 cell
  195. }
  196. [Fact]
  197. public void GraphSpaceToScreen_ScrollOffset ()
  198. {
  199. var gv = new GraphView ();
  200. gv.Bounds = new Rect (0, 0, 20, 10);
  201. //graph is scrolled to present chart space -5 to 5 in both axes
  202. gv.ScrollOffset = new PointF (-5, -5);
  203. // origin should be right in the middle of the control
  204. var botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  205. Assert.Equal (5, botLeft.X);
  206. Assert.Equal (4, botLeft.Y);
  207. // along 2 and up 1 in graph space
  208. var along2up1 = gv.GraphSpaceToScreen (new PointF (2, 1));
  209. Assert.Equal (7, along2up1.X);
  210. Assert.Equal (3, along2up1.Y);
  211. }
  212. [Fact]
  213. public void GraphSpaceToScreen_CustomCellSize ()
  214. {
  215. var gv = new GraphView ();
  216. gv.Bounds = new Rect (0, 0, 20, 10);
  217. // Each cell of screen is responsible for rendering 5 units in graph data model
  218. // vertically and 1/4 horizontally
  219. gv.CellSize = new PointF (0.25f, 5);
  220. // origin should be bottom left
  221. var botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  222. Assert.Equal (0, botLeft.X);
  223. // row 9 of the view is the bottom left (height is 10 so 0,1,2,3..9)
  224. Assert.Equal (9, botLeft.Y);
  225. // along 2 and up 1 in graph space
  226. var along2up1 = gv.GraphSpaceToScreen (new PointF (2, 1));
  227. Assert.Equal (8, along2up1.X);
  228. Assert.Equal (9, along2up1.Y);
  229. // Y value 4 should be rendered in bottom most row
  230. Assert.Equal (9, gv.GraphSpaceToScreen (new PointF (2, 4)).Y);
  231. // Cell height is 5 so this is the first point of graph space that should
  232. // be rendered in the graph in next row up (row 9)
  233. Assert.Equal (8, gv.GraphSpaceToScreen (new PointF (2, 5)).Y);
  234. // More boundary testing for this cell size
  235. Assert.Equal (8, gv.GraphSpaceToScreen (new PointF (2, 6)).Y);
  236. Assert.Equal (8, gv.GraphSpaceToScreen (new PointF (2, 7)).Y);
  237. Assert.Equal (8, gv.GraphSpaceToScreen (new PointF (2, 8)).Y);
  238. Assert.Equal (8, gv.GraphSpaceToScreen (new PointF (2, 9)).Y);
  239. Assert.Equal (7, gv.GraphSpaceToScreen (new PointF (2, 10)).Y);
  240. Assert.Equal (7, gv.GraphSpaceToScreen (new PointF (2, 11)).Y);
  241. }
  242. [Fact]
  243. public void GraphSpaceToScreen_CustomCellSize_WithScrollOffset ()
  244. {
  245. var gv = new GraphView ();
  246. gv.Bounds = new Rect (0, 0, 20, 10);
  247. // Each cell of screen is responsible for rendering 5 units in graph data model
  248. // vertically and 1/4 horizontally
  249. gv.CellSize = new PointF (0.25f, 5);
  250. //graph is scrolled to present some negative chart (4 negative cols and 2 negative rows)
  251. gv.ScrollOffset = new PointF (-1, -10);
  252. // origin should be in the lower left (but not right at the bottom)
  253. var botLeft = gv.GraphSpaceToScreen (new PointF (0, 0));
  254. Assert.Equal (4, botLeft.X);
  255. Assert.Equal (7, botLeft.Y);
  256. // along 2 and up 1 in graph space
  257. var along2up1 = gv.GraphSpaceToScreen (new PointF (2, 1));
  258. Assert.Equal (12, along2up1.X);
  259. Assert.Equal (7, along2up1.Y);
  260. // More boundary testing for this cell size/offset
  261. Assert.Equal (6, gv.GraphSpaceToScreen (new PointF (2, 6)).Y);
  262. Assert.Equal (6, gv.GraphSpaceToScreen (new PointF (2, 7)).Y);
  263. Assert.Equal (6, gv.GraphSpaceToScreen (new PointF (2, 8)).Y);
  264. Assert.Equal (6, gv.GraphSpaceToScreen (new PointF (2, 9)).Y);
  265. Assert.Equal (5, gv.GraphSpaceToScreen (new PointF (2, 10)).Y);
  266. Assert.Equal (5, gv.GraphSpaceToScreen (new PointF (2, 11)).Y);
  267. }
  268. #endregion
  269. /// <summary>
  270. /// A cell size of 0 would result in mapping all graph space into the
  271. /// same cell of the console. Since <see cref="GraphView.CellSize"/>
  272. /// is mutable a sensible place to check this is in redraw.
  273. /// </summary>
  274. [Fact]
  275. public void CellSizeZero()
  276. {
  277. InitFakeDriver ();
  278. var gv = new GraphView ();
  279. gv.ColorScheme = new ColorScheme ();
  280. gv.Bounds = new Rect (0, 0, 50, 30);
  281. gv.Series.Add (new ScatterSeries () { Points = new List<PointF> { new PointF (1, 1) } });
  282. gv.CellSize= new PointF(0,5);
  283. var ex = Assert.Throws<Exception>(()=>gv.Redraw (gv.Bounds));
  284. Assert.Equal ("CellSize cannot be 0", ex.Message);
  285. }
  286. /// <summary>
  287. /// Tests that each point in the screen space maps to a rectangle of
  288. /// (float) graph space and that each corner of that rectangle of graph
  289. /// space maps back to the same row/col of the graph that was fed in
  290. /// </summary>
  291. [Fact]
  292. public void TestReversing_ScreenToGraphSpace ()
  293. {
  294. var gv = new GraphView ();
  295. gv.Bounds = new Rect (0, 0, 50, 30);
  296. // How much graph space each cell of the console depicts
  297. gv.CellSize = new PointF (0.1f, 0.25f);
  298. gv.AxisX.Increment = 1;
  299. gv.AxisX.ShowLabelsEvery = 1;
  300. gv.AxisY.Increment = 1;
  301. gv.AxisY.ShowLabelsEvery = 1;
  302. // Start the graph at 80
  303. gv.ScrollOffset = new PointF (0, 80);
  304. for (int x = 0; x < gv.Bounds.Width; x++) {
  305. for (int y = 0; y < gv.Bounds.Height; y++) {
  306. var graphSpace = gv.ScreenToGraphSpace (x, y);
  307. // See
  308. // https://en.wikipedia.org/wiki/Machine_epsilon
  309. float epsilon = 0.0001f;
  310. var p = gv.GraphSpaceToScreen (new PointF (graphSpace.Left + epsilon, graphSpace.Top + epsilon));
  311. Assert.Equal (x, p.X);
  312. Assert.Equal (y, p.Y);
  313. p = gv.GraphSpaceToScreen (new PointF (graphSpace.Right - epsilon , graphSpace.Top + epsilon));
  314. Assert.Equal (x, p.X);
  315. Assert.Equal (y, p.Y);
  316. p = gv.GraphSpaceToScreen (new PointF (graphSpace.Left + epsilon, graphSpace.Bottom - epsilon));
  317. Assert.Equal (x, p.X);
  318. Assert.Equal (y, p.Y);
  319. p = gv.GraphSpaceToScreen (new PointF (graphSpace.Right - epsilon, graphSpace.Bottom - epsilon));
  320. Assert.Equal (x, p.X);
  321. Assert.Equal (y, p.Y);
  322. }
  323. }
  324. }
  325. }
  326. public class SeriesTests {
  327. [Fact]
  328. public void Series_GetsPassedCorrectBounds_AllAtOnce ()
  329. {
  330. GraphViewTests.InitFakeDriver ();
  331. var gv = new GraphView ();
  332. gv.ColorScheme = new ColorScheme ();
  333. gv.Bounds = new Rect (0, 0, 50, 30);
  334. RectangleF fullGraphBounds = RectangleF.Empty;
  335. Rect graphScreenBounds = Rect.Empty;
  336. var series = new FakeSeries ((v, s, g) => { graphScreenBounds = s; fullGraphBounds = g; });
  337. gv.Series.Add (series);
  338. gv.Redraw (gv.Bounds);
  339. Assert.Equal (new RectangleF (0, 0, 50, 30), fullGraphBounds);
  340. Assert.Equal (new Rect (0, 0, 50, 30), graphScreenBounds);
  341. // Now we put a margin in
  342. // Graph should not spill into the margins
  343. gv.MarginBottom = 2;
  344. gv.MarginLeft = 5;
  345. // Even with a margin the graph should be drawn from
  346. // the origin, we just get less visible width/height
  347. gv.Redraw (gv.Bounds);
  348. Assert.Equal (new RectangleF (0, 0, 45, 28), fullGraphBounds);
  349. // The screen space the graph will be rendered into should
  350. // not overspill the margins
  351. Assert.Equal (new Rect (5, 0, 45, 28), graphScreenBounds);
  352. }
  353. /// <summary>
  354. /// Tests that the bounds passed to the ISeries for drawing into are
  355. /// correct even when the <see cref="GraphView.CellSize"/> results in
  356. /// multiple units of graph space being condensed into each cell of
  357. /// console
  358. /// </summary>
  359. [Fact]
  360. public void Series_GetsPassedCorrectBounds_AllAtOnce_LargeCellSize ()
  361. {
  362. GraphViewTests.InitFakeDriver ();
  363. var gv = new GraphView ();
  364. gv.ColorScheme = new ColorScheme ();
  365. gv.Bounds = new Rect (0, 0, 50, 30);
  366. // the larger the cell size the more condensed (smaller) the graph space is
  367. gv.CellSize = new PointF (2, 5);
  368. RectangleF fullGraphBounds = RectangleF.Empty;
  369. Rect graphScreenBounds = Rect.Empty;
  370. var series = new FakeSeries ((v, s, g) => { graphScreenBounds = s; fullGraphBounds = g; });
  371. gv.Series.Add (series);
  372. gv.Redraw (gv.Bounds);
  373. // Since each cell of the console is 2x5 of graph space the graph
  374. // bounds to be rendered are larger
  375. Assert.Equal (new RectangleF (0, 0, 100, 150), fullGraphBounds);
  376. Assert.Equal (new Rect (0, 0, 50, 30), graphScreenBounds);
  377. // Graph should not spill into the margins
  378. gv.MarginBottom = 2;
  379. gv.MarginLeft = 5;
  380. // Even with a margin the graph should be drawn from
  381. // the origin, we just get less visible width/height
  382. gv.Redraw (gv.Bounds);
  383. Assert.Equal (new RectangleF (0, 0, 90, 140), fullGraphBounds);
  384. // The screen space the graph will be rendered into should
  385. // not overspill the margins
  386. Assert.Equal (new Rect (5, 0, 45, 28), graphScreenBounds);
  387. }
  388. private class FakeSeries : ISeries {
  389. readonly Action<GraphView, Rect, RectangleF> drawSeries;
  390. public FakeSeries (
  391. Action<GraphView, Rect, RectangleF> drawSeries
  392. )
  393. {
  394. this.drawSeries = drawSeries;
  395. }
  396. public void DrawSeries (GraphView graph, Rect bounds, RectangleF graphBounds)
  397. {
  398. drawSeries (graph, bounds, graphBounds);
  399. }
  400. }
  401. }
  402. public class MultiBarSeriesTests{
  403. [Fact]
  404. public void MultiBarSeries_BarSpacing(){
  405. // Creates clusters of 5 adjacent bars with 2 spaces between clusters
  406. var series = new MultiBarSeries(5,7,1);
  407. Assert.Equal(5,series.SubSeries.Count);
  408. Assert.Equal(0,series.SubSeries.ElementAt(0).Offset);
  409. Assert.Equal(1,series.SubSeries.ElementAt(1).Offset);
  410. Assert.Equal(2,series.SubSeries.ElementAt(2).Offset);
  411. Assert.Equal(3,series.SubSeries.ElementAt(3).Offset);
  412. Assert.Equal(4,series.SubSeries.ElementAt(4).Offset);
  413. }
  414. [Fact]
  415. public void MultiBarSeriesColors_WrongNumber(){
  416. var fake = new FakeDriver ();
  417. var colors = new []{
  418. fake.MakeAttribute(Color.Green,Color.Black)
  419. };
  420. // user passes 1 color only but asks for 5 bars
  421. var ex = Assert.Throws<ArgumentException>(()=>new MultiBarSeries(5,7,1,colors));
  422. Assert.Equal("Number of colors must match the number of bars (Parameter 'numberOfBarsPerCategory')",ex.Message);
  423. }
  424. [Fact]
  425. public void MultiBarSeriesColors_RightNumber(){
  426. var fake = new FakeDriver ();
  427. var colors = new []{
  428. fake.MakeAttribute(Color.Green,Color.Black),
  429. fake.MakeAttribute(Color.Green,Color.White),
  430. fake.MakeAttribute(Color.BrightYellow,Color.White)
  431. };
  432. // user passes 3 colors and asks for 3 bars
  433. var series = new MultiBarSeries(3,7,1,colors);
  434. Assert.Equal(series.SubSeries.ElementAt(0).OverrideBarColor,colors[0]);
  435. Assert.Equal(series.SubSeries.ElementAt(1).OverrideBarColor,colors[1]);
  436. Assert.Equal(series.SubSeries.ElementAt(2).OverrideBarColor,colors[2]);
  437. }
  438. [Fact]
  439. public void MultiBarSeriesAddValues_WrongNumber(){
  440. // user asks for 3 bars per category
  441. var series = new MultiBarSeries(3,7,1);
  442. var ex = Assert.Throws<ArgumentException>(()=>series.AddBars("Cars",'#',1));
  443. Assert.Equal("Number of values must match the number of bars per category (Parameter 'values')",ex.Message);
  444. }
  445. [Fact]
  446. public void TestRendering_MultibarSeries(){
  447. GraphViewTests.InitFakeDriver ();
  448. var gv = new GraphView ();
  449. gv.ColorScheme = new ColorScheme ();
  450. // y axis goes from 0.1 to 1 across 10 console rows
  451. // x axis goes from 0 to 20 across 20 console columns
  452. gv.Bounds = new Rect (0, 0, 20, 10);
  453. gv.CellSize = new PointF(1f,0.1f);
  454. gv.MarginBottom = 1;
  455. gv.MarginLeft = 1;
  456. var multibarSeries = new MultiBarSeries (2,4,1);
  457. //nudge them left to avoid float rounding errors at the boundaries of cells
  458. foreach(var sub in multibarSeries.SubSeries) {
  459. sub.Offset -= 0.001f;
  460. }
  461. gv.Series.Add (multibarSeries);
  462. FakeHAxis fakeXAxis;
  463. // don't show axis labels that means any labels
  464. // that appaer are explicitly from the bars
  465. gv.AxisX = fakeXAxis = new FakeHAxis(){Increment=0};
  466. gv.AxisY = new FakeVAxis(){Increment=0};
  467. gv.Redraw(gv.Bounds);
  468. // Since bar series has no bars yet no labels should be displayed
  469. Assert.Empty(fakeXAxis.LabelPoints);
  470. multibarSeries.AddBars("hey",'M',0.5001f, 0.5001f);
  471. fakeXAxis.LabelPoints.Clear();
  472. gv.Redraw(gv.Bounds);
  473. Assert.Equal(4,fakeXAxis.LabelPoints.Single());
  474. multibarSeries.AddBars("there",'M',0.24999f,0.74999f);
  475. multibarSeries.AddBars("bob",'M',1,2);
  476. fakeXAxis.LabelPoints.Clear();
  477. gv.Redraw(gv.Bounds);
  478. Assert.Equal(3,fakeXAxis.LabelPoints.Count);
  479. Assert.Equal(4,fakeXAxis.LabelPoints[0]);
  480. Assert.Equal(8,fakeXAxis.LabelPoints[1]);
  481. Assert.Equal (12, fakeXAxis.LabelPoints [2]);
  482. string looksLike =
  483. @"
  484. │ MM
  485. │ M MM
  486. │ M MM
  487. │ MM M MM
  488. │ MM M MM
  489. │ MM M MM
  490. │ MM MM MM
  491. │ MM MM MM
  492. ┼──┬M──┬M──┬M──────
  493. heytherebob ";
  494. GraphViewTests.AssertDriverContentsAre (looksLike);
  495. }
  496. }
  497. public class BarSeriesTests{
  498. private GraphView GetGraph (out FakeBarSeries series, out FakeHAxis axisX, out FakeVAxis axisY)
  499. {
  500. GraphViewTests.InitFakeDriver ();
  501. var gv = new GraphView ();
  502. gv.ColorScheme = new ColorScheme ();
  503. // y axis goes from 0.1 to 1 across 10 console rows
  504. // x axis goes from 0 to 10 across 20 console columns
  505. gv.Bounds = new Rect (0, 0, 20, 10);
  506. gv.CellSize = new PointF(0.5f,0.1f);
  507. gv.Series.Add (series = new FakeBarSeries ());
  508. // don't show axis labels that means any labels
  509. // that appaer are explicitly from the bars
  510. gv.AxisX = axisX = new FakeHAxis(){Increment=0};
  511. gv.AxisY = axisY = new FakeVAxis(){Increment=0};
  512. return gv;
  513. }
  514. [Fact]
  515. public void TestZeroHeightBar_WithName(){
  516. var graph = GetGraph(out FakeBarSeries barSeries, out FakeHAxis axisX, out FakeVAxis axisY);
  517. graph.Redraw(graph.Bounds);
  518. // no bars
  519. Assert.Empty(barSeries.BarScreenStarts);
  520. Assert.Empty(axisX.LabelPoints);
  521. Assert.Empty(axisY.LabelPoints);
  522. // bar of height 0
  523. barSeries.Bars.Add(new BarSeries.Bar("hi",new GraphCellToRender('.'),0));
  524. barSeries.Orientation = Orientation.Vertical;
  525. // redraw graph
  526. graph.Redraw(graph.Bounds);
  527. // bar should not be drawn
  528. Assert.Empty(barSeries.BarScreenStarts);
  529. Assert.NotEmpty(axisX.LabelPoints);
  530. Assert.Empty(axisY.LabelPoints);
  531. // but bar name should be
  532. // Screen position x=2 because bars are drawn every 1f of
  533. // graph space and CellSize.X is 0.5f
  534. Assert.Contains(2, axisX.LabelPoints);
  535. }
  536. [Fact]
  537. public void TestTwoTallBars_WithOffset(){
  538. var graph = GetGraph(out FakeBarSeries barSeries, out FakeHAxis axisX, out FakeVAxis axisY);
  539. graph.Redraw(graph.Bounds);
  540. // no bars
  541. Assert.Empty(barSeries.BarScreenStarts);
  542. Assert.Empty(axisX.LabelPoints);
  543. Assert.Empty(axisY.LabelPoints);
  544. // 0.5 units of graph fit every screen cell
  545. // so 1 unit of graph space is 2 screen columns
  546. graph.CellSize = new PointF(0.5f,0.1f);
  547. // Start bar 1 screen unit along
  548. barSeries.Offset = 0.5f;
  549. barSeries.BarEvery = 1f;
  550. barSeries.Bars.Add(
  551. new BarSeries.Bar("hi1",new GraphCellToRender('.'),100));
  552. barSeries.Bars.Add(
  553. new BarSeries.Bar("hi2",new GraphCellToRender('.'),100));
  554. barSeries.Orientation = Orientation.Vertical;
  555. // redraw graph
  556. graph.Redraw(graph.Bounds);
  557. // bar should be drawn at BarEvery 1f + offset 0.5f = 3 screen units
  558. Assert.Equal(3,barSeries.BarScreenStarts[0].X);
  559. Assert.Equal(3,barSeries.BarScreenEnds[0].X);
  560. // second bar should be BarEveryx2 = 2f + offset 0.5f = 5 screen units
  561. Assert.Equal(5,barSeries.BarScreenStarts[1].X);
  562. Assert.Equal(5,barSeries.BarScreenEnds[1].X);
  563. // both bars should have labels
  564. Assert.Equal(2,axisX.LabelPoints.Count);
  565. Assert.Contains(3, axisX.LabelPoints);
  566. Assert.Contains(5, axisX.LabelPoints);
  567. // bars are very tall but should not draw up off top of screen
  568. Assert.Equal(9,barSeries.BarScreenStarts[0].Y);
  569. Assert.Equal(0,barSeries.BarScreenEnds[0].Y);
  570. Assert.Equal(9,barSeries.BarScreenStarts[1].Y);
  571. Assert.Equal(0,barSeries.BarScreenEnds[1].Y);
  572. }
  573. [Fact]
  574. public void TestOneLongOneShortHorizontalBars_WithOffset(){
  575. var graph = GetGraph(out FakeBarSeries barSeries, out FakeHAxis axisX, out FakeVAxis axisY);
  576. graph.Redraw(graph.Bounds);
  577. // no bars
  578. Assert.Empty(barSeries.BarScreenStarts);
  579. Assert.Empty(axisX.LabelPoints);
  580. Assert.Empty(axisY.LabelPoints);
  581. // 0.1 units of graph y fit every screen row
  582. // so 1 unit of graph y space is 10 screen rows
  583. graph.CellSize = new PointF(0.5f,0.1f);
  584. // Start bar 3 screen units up (y = height-3)
  585. barSeries.Offset = 0.25f;
  586. // 1 bar every 3 rows of screen
  587. barSeries.BarEvery = 0.3f;
  588. barSeries.Orientation = Orientation.Horizontal;
  589. // 1 bar that is very wide (100 graph units horizontally = screen pos 50 but bounded by screen)
  590. barSeries.Bars.Add(
  591. new BarSeries.Bar("hi1",new GraphCellToRender('.'),100));
  592. // 1 bar that is shorter
  593. barSeries.Bars.Add(
  594. new BarSeries.Bar("hi2",new GraphCellToRender('.'),5));
  595. // redraw graph
  596. graph.Redraw(graph.Bounds);
  597. // since bars are horizontal all have the same X start cordinates
  598. Assert.Equal(0,barSeries.BarScreenStarts[0].X);
  599. Assert.Equal(0,barSeries.BarScreenStarts[1].X);
  600. // bar goes all the way to the end so bumps up against right screen boundary
  601. // width of graph is 20
  602. Assert.Equal(19,barSeries.BarScreenEnds[0].X);
  603. // shorter bar is 5 graph units wide which is 10 screen units
  604. Assert.Equal(10,barSeries.BarScreenEnds[1].X);
  605. // first bar should be offset 6 screen units (0.25f + 0.3f graph units)
  606. // since height of control is 10 then first bar should be at screen row 4 (10-6)
  607. Assert.Equal(4,barSeries.BarScreenStarts[0].Y);
  608. // second bar should be offset 9 screen units (0.25f + 0.6f graph units)
  609. // since height of control is 10 then second bar should be at screen row 1 (10-9)
  610. Assert.Equal(1,barSeries.BarScreenStarts[1].Y);
  611. // both bars should have labels but on the y axis
  612. Assert.Equal(2,axisY.LabelPoints.Count);
  613. Assert.Empty(axisX.LabelPoints);
  614. // labels should align with the bars (same screen y axis point)
  615. Assert.Contains(4, axisY.LabelPoints);
  616. Assert.Contains(1, axisY.LabelPoints);
  617. }
  618. private class FakeBarSeries : BarSeries{
  619. public GraphCellToRender FinalColor { get; private set; }
  620. public List<Point> BarScreenStarts { get; private set; } = new List<Point>();
  621. public List<Point> BarScreenEnds { get; private set; } = new List<Point>();
  622. protected override GraphCellToRender AdjustColor (GraphCellToRender graphCellToRender)
  623. {
  624. return FinalColor = base.AdjustColor (graphCellToRender);
  625. }
  626. protected override void DrawBarLine (GraphView graph, Point start, Point end, Bar beingDrawn)
  627. {
  628. base.DrawBarLine (graph, start, end, beingDrawn);
  629. BarScreenStarts.Add(start);
  630. BarScreenEnds.Add(end);
  631. }
  632. }
  633. }
  634. public class AxisTests {
  635. private GraphView GetGraph (out FakeHAxis axis)
  636. {
  637. return GetGraph(out axis, out _);
  638. }
  639. private GraphView GetGraph (out FakeVAxis axis)
  640. {
  641. return GetGraph(out _, out axis);
  642. }
  643. private GraphView GetGraph (out FakeHAxis axisX, out FakeVAxis axisY)
  644. {
  645. GraphViewTests.InitFakeDriver ();
  646. var gv = new GraphView ();
  647. gv.ColorScheme = new ColorScheme ();
  648. gv.Bounds = new Rect (0, 0, 50, 30);
  649. // graph can't be completely empty or it won't draw
  650. gv.Series.Add (new ScatterSeries ());
  651. axisX = new FakeHAxis ();
  652. axisY = new FakeVAxis ();
  653. gv.AxisX = axisX;
  654. gv.AxisY = axisY;
  655. return gv;
  656. }
  657. #region HorizontalAxis Tests
  658. /// <summary>
  659. /// Tests that the horizontal axis is computed correctly and does not over spill
  660. /// it's bounds
  661. /// </summary>
  662. [Fact]
  663. public void TestHAxisLocation_NoMargin ()
  664. {
  665. var gv = GetGraph (out FakeHAxis axis);
  666. gv.Redraw (gv.Bounds);
  667. Assert.DoesNotContain (new Point (-1, 29), axis.DrawAxisLinePoints);
  668. Assert.Contains (new Point (0, 29),axis.DrawAxisLinePoints);
  669. Assert.Contains (new Point (1, 29), axis.DrawAxisLinePoints);
  670. Assert.Contains (new Point (48, 29), axis.DrawAxisLinePoints);
  671. Assert.Contains (new Point (49, 29), axis.DrawAxisLinePoints);
  672. Assert.DoesNotContain (new Point (50, 29), axis.DrawAxisLinePoints);
  673. Assert.InRange(axis.LabelPoints.Max(),0,49);
  674. Assert.InRange(axis.LabelPoints.Min(),0,49);
  675. }
  676. [Fact]
  677. public void TestHAxisLocation_MarginBottom ()
  678. {
  679. var gv = GetGraph (out FakeHAxis axis);
  680. gv.MarginBottom = 10;
  681. gv.Redraw (gv.Bounds);
  682. Assert.DoesNotContain (new Point (-1, 19), axis.DrawAxisLinePoints);
  683. Assert.Contains (new Point (0, 19), axis.DrawAxisLinePoints);
  684. Assert.Contains (new Point (1, 19), axis.DrawAxisLinePoints);
  685. Assert.Contains (new Point (48, 19), axis.DrawAxisLinePoints);
  686. Assert.Contains (new Point (49, 19), axis.DrawAxisLinePoints);
  687. Assert.DoesNotContain (new Point (50, 19), axis.DrawAxisLinePoints);
  688. Assert.InRange(axis.LabelPoints.Max(),0,49);
  689. Assert.InRange(axis.LabelPoints.Min(),0,49);
  690. }
  691. [Fact]
  692. public void TestHAxisLocation_MarginLeft ()
  693. {
  694. var gv = GetGraph (out FakeHAxis axis);
  695. gv.MarginLeft = 5;
  696. gv.Redraw (gv.Bounds);
  697. Assert.DoesNotContain (new Point (4, 29), axis.DrawAxisLinePoints);
  698. Assert.Contains (new Point (5, 29), axis.DrawAxisLinePoints);
  699. Assert.Contains (new Point (6, 29), axis.DrawAxisLinePoints);
  700. Assert.Contains (new Point (48, 29), axis.DrawAxisLinePoints);
  701. Assert.Contains (new Point (49, 29), axis.DrawAxisLinePoints);
  702. Assert.DoesNotContain (new Point (50, 29), axis.DrawAxisLinePoints);
  703. // Axis lables should not be drawn in the margin
  704. Assert.InRange(axis.LabelPoints.Max(),5,49);
  705. Assert.InRange(axis.LabelPoints.Min(),5,49);
  706. }
  707. #endregion
  708. #region VerticalAxisTests
  709. /// <summary>
  710. /// Tests that the horizontal axis is computed correctly and does not over spill
  711. /// it's bounds
  712. /// </summary>
  713. [Fact]
  714. public void TestVAxisLocation_NoMargin ()
  715. {
  716. var gv = GetGraph (out FakeVAxis axis);
  717. gv.Redraw (gv.Bounds);
  718. Assert.DoesNotContain (new Point (0, -1), axis.DrawAxisLinePoints);
  719. Assert.Contains (new Point (0, 1),axis.DrawAxisLinePoints);
  720. Assert.Contains (new Point (0, 2), axis.DrawAxisLinePoints);
  721. Assert.Contains (new Point (0, 28), axis.DrawAxisLinePoints);
  722. Assert.Contains (new Point (0, 29), axis.DrawAxisLinePoints);
  723. Assert.DoesNotContain (new Point (0, 30), axis.DrawAxisLinePoints);
  724. Assert.InRange(axis.LabelPoints.Max(),0,29);
  725. Assert.InRange(axis.LabelPoints.Min(),0,29);
  726. }
  727. [Fact]
  728. public void TestVAxisLocation_MarginBottom ()
  729. {
  730. var gv = GetGraph (out FakeVAxis axis);
  731. gv.MarginBottom = 10;
  732. gv.Redraw (gv.Bounds);
  733. Assert.DoesNotContain (new Point (0, -1), axis.DrawAxisLinePoints);
  734. Assert.Contains (new Point (0, 1),axis.DrawAxisLinePoints);
  735. Assert.Contains (new Point (0, 2), axis.DrawAxisLinePoints);
  736. Assert.Contains (new Point (0, 18), axis.DrawAxisLinePoints);
  737. Assert.Contains (new Point (0, 19), axis.DrawAxisLinePoints);
  738. Assert.DoesNotContain (new Point (0, 20), axis.DrawAxisLinePoints);
  739. // Labels should not be drawn into the axis
  740. Assert.InRange(axis.LabelPoints.Max(),0,19);
  741. Assert.InRange(axis.LabelPoints.Min(),0,19);
  742. }
  743. [Fact]
  744. public void TestVAxisLocation_MarginLeft ()
  745. {
  746. var gv = GetGraph (out FakeVAxis axis);
  747. gv.MarginLeft = 5;
  748. gv.Redraw (gv.Bounds);
  749. Assert.DoesNotContain (new Point (5, -1), axis.DrawAxisLinePoints);
  750. Assert.Contains (new Point (5, 1),axis.DrawAxisLinePoints);
  751. Assert.Contains (new Point (5, 2), axis.DrawAxisLinePoints);
  752. Assert.Contains (new Point (5, 28), axis.DrawAxisLinePoints);
  753. Assert.Contains (new Point (5, 29), axis.DrawAxisLinePoints);
  754. Assert.DoesNotContain (new Point (5, 30), axis.DrawAxisLinePoints);
  755. Assert.InRange(axis.LabelPoints.Max(),0,29);
  756. Assert.InRange(axis.LabelPoints.Min(),0,29);
  757. }
  758. #endregion
  759. }
  760. public class TextAnnotationTests {
  761. [Fact]
  762. public void TestTextAnnotation_ScreenUnits()
  763. {
  764. var gv = GraphViewTests.GetGraph ();
  765. gv.Annotations.Add (new TextAnnotation () {
  766. Text = "hey!",
  767. ScreenPosition = new Point (3, 1)
  768. });
  769. gv.Redraw (gv.Bounds);
  770. var expected =
  771. @"
  772. ┤ hey!
  773. 0┼┬┬┬┬┬┬┬┬
  774. 0 5";
  775. GraphViewTests.AssertDriverContentsAre (expected);
  776. // user scrolls up one unit of graph space
  777. gv.ScrollOffset = new PointF (0, 1f);
  778. gv.Redraw (gv.Bounds);
  779. // we expect no change in the location of the annotation (only the axis label changes)
  780. // this is because screen units are constant and do not change as the viewport into
  781. // graph space scrolls to different areas of the graph
  782. expected =
  783. @"
  784. ┤ hey!
  785. 1┼┬┬┬┬┬┬┬┬
  786. 0 5";
  787. GraphViewTests.AssertDriverContentsAre (expected);
  788. }
  789. [Fact]
  790. public void TestTextAnnotation_GraphUnits ()
  791. {
  792. var gv = GraphViewTests.GetGraph ();
  793. gv.Annotations.Add (new TextAnnotation () {
  794. Text = "hey!",
  795. GraphPosition = new PointF (2, 2)
  796. });
  797. gv.Redraw (gv.Bounds);
  798. var expected =
  799. @"
  800. ┤ hey!
  801. 0┼┬┬┬┬┬┬┬┬
  802. 0 5";
  803. GraphViewTests.AssertDriverContentsAre (expected);
  804. // user scrolls up one unit of graph space
  805. gv.ScrollOffset = new PointF (0, 1f);
  806. gv.Redraw (gv.Bounds);
  807. // we expect the text annotation to go down one line since
  808. // the scroll offset means that that point of graph space is
  809. // lower down in the view. Note the 1 on the axis too, our viewport
  810. // (excluding margins) now shows y of 1 to 4 (previously 0 to 5)
  811. expected =
  812. @"
  813. ┤ hey!
  814. 1┼┬┬┬┬┬┬┬┬
  815. 0 5";
  816. GraphViewTests.AssertDriverContentsAre (expected);
  817. }
  818. [Fact]
  819. public void TestTextAnnotation_LongText ()
  820. {
  821. var gv = GraphViewTests.GetGraph ();
  822. gv.Annotations.Add (new TextAnnotation () {
  823. Text = "hey there partner hows it going boy its great",
  824. GraphPosition = new PointF (2, 2)
  825. });
  826. gv.Redraw (gv.Bounds);
  827. // long text should get truncated
  828. // margin takes up 1 units
  829. // the GraphPosition of the anntation is 2
  830. // Leaving 7 characters of the annotation renderable (including space)
  831. var expected =
  832. @"
  833. ┤ hey the
  834. 0┼┬┬┬┬┬┬┬┬
  835. 0 5";
  836. GraphViewTests.AssertDriverContentsAre (expected);
  837. }
  838. [Fact]
  839. public void TestTextAnnotation_Offscreen ()
  840. {
  841. var gv = GraphViewTests.GetGraph ();
  842. gv.Annotations.Add (new TextAnnotation () {
  843. Text = "hey there partner hows it going boy its great",
  844. GraphPosition = new PointF (9, 2)
  845. });
  846. gv.Redraw (gv.Bounds);
  847. // Text is off the screen (graph x axis runs to 8 not 9)
  848. var expected =
  849. @"
  850. 0┼┬┬┬┬┬┬┬┬
  851. 0 5";
  852. GraphViewTests.AssertDriverContentsAre (expected);
  853. }
  854. [Theory]
  855. [InlineData(null)]
  856. [InlineData (" ")]
  857. [InlineData ("\t\t")]
  858. public void TestTextAnnotation_EmptyText (string whitespace)
  859. {
  860. var gv = GraphViewTests.GetGraph ();
  861. gv.Annotations.Add (new TextAnnotation () {
  862. Text = whitespace,
  863. GraphPosition = new PointF (4, 2)
  864. });
  865. // add a point a bit further along the graph so if the whitespace were rendered
  866. // the test would pick it up (AssertDriverContentsAre ignores trailing whitespace on lines)
  867. var points = new ScatterSeries ();
  868. points.Points.Add(new PointF(7, 2));
  869. gv.Series.Add (points);
  870. gv.Redraw (gv.Bounds);
  871. var expected =
  872. @"
  873. ┤ x
  874. 0┼┬┬┬┬┬┬┬┬
  875. 0 5";
  876. GraphViewTests.AssertDriverContentsAre (expected);
  877. }
  878. }
  879. public class LegendTests {
  880. [Fact]
  881. public void LegendNormalUsage_WithBorder ()
  882. {
  883. var gv = GraphViewTests.GetGraph ();
  884. var legend = new LegendAnnotation(new Rect(2,0,5,3));
  885. legend.AddEntry (new GraphCellToRender ('A'), "Ant");
  886. legend.AddEntry (new GraphCellToRender ('B'), "Bat");
  887. gv.Annotations.Add (legend);
  888. gv.Redraw (gv.Bounds);
  889. var expected =
  890. @"
  891. │┌───┐
  892. ┤│AAn│
  893. ┤└───┘
  894. 0┼┬┬┬┬┬┬┬┬
  895. 0 5";
  896. GraphViewTests.AssertDriverContentsAre (expected);
  897. }
  898. [Fact]
  899. public void LegendNormalUsage_WithoutBorder ()
  900. {
  901. var gv = GraphViewTests.GetGraph ();
  902. var legend = new LegendAnnotation (new Rect (2, 0, 5, 3));
  903. legend.AddEntry (new GraphCellToRender ('A'), "Ant");
  904. legend.AddEntry (new GraphCellToRender ('B'), "?"); // this will exercise pad
  905. legend.AddEntry (new GraphCellToRender ('C'), "Cat");
  906. legend.AddEntry (new GraphCellToRender ('H'), "Hattter"); // not enough space for this oen
  907. legend.Border = false;
  908. gv.Annotations.Add (legend);
  909. gv.Redraw (gv.Bounds);
  910. var expected =
  911. @"
  912. │AAnt
  913. ┤B?
  914. ┤CCat
  915. 0┼┬┬┬┬┬┬┬┬
  916. 0 5";
  917. GraphViewTests.AssertDriverContentsAre (expected);
  918. }
  919. }
  920. public class PathAnnotationTests {
  921. [Fact]
  922. public void PathAnnotation_Box()
  923. {
  924. var gv = GraphViewTests.GetGraph ();
  925. var path = new PathAnnotation ();
  926. path.Points.Add (new PointF (1, 1));
  927. path.Points.Add (new PointF (1, 3));
  928. path.Points.Add (new PointF (6, 3));
  929. path.Points.Add (new PointF (6, 1));
  930. // list the starting point again so that it draws a complete square
  931. // (otherwise it will miss out the last line along the bottom)
  932. path.Points.Add (new PointF (1, 1));
  933. gv.Annotations.Add (path);
  934. gv.Redraw (gv.Bounds);
  935. var expected =
  936. @"
  937. │......
  938. ┤. .
  939. ┤......
  940. 0┼┬┬┬┬┬┬┬┬
  941. 0 5";
  942. GraphViewTests.AssertDriverContentsAre (expected);
  943. }
  944. [Fact]
  945. public void PathAnnotation_Diamond ()
  946. {
  947. var gv = GraphViewTests.GetGraph ();
  948. var path = new PathAnnotation ();
  949. path.Points.Add (new PointF (1, 2));
  950. path.Points.Add (new PointF (3, 3));
  951. path.Points.Add (new PointF (6, 2));
  952. path.Points.Add (new PointF (3, 1));
  953. // list the starting point again to close the shape
  954. path.Points.Add (new PointF (1, 2));
  955. gv.Annotations.Add (path);
  956. gv.Redraw (gv.Bounds);
  957. var expected =
  958. @"
  959. │ ..
  960. ┤.. ..
  961. ┤ ...
  962. 0┼┬┬┬┬┬┬┬┬
  963. 0 5";
  964. GraphViewTests.AssertDriverContentsAre (expected);
  965. }
  966. }
  967. public class AxisIncrementToRenderTests {
  968. [Fact]
  969. public void AxisIncrementToRenderTests_Constructor ()
  970. {
  971. var render = new AxisIncrementToRender (Orientation.Horizontal,1,6.6f);
  972. Assert.Equal (Orientation.Horizontal, render.Orientation);
  973. Assert.Equal (1, render.ScreenLocation);
  974. Assert.Equal (6.6f, render.Value);
  975. }
  976. }
  977. }