From d0d3cb2158e9dfb6b278cf1a50af64ee58f49ac9 Mon Sep 17 00:00:00 2001 From: Paul Anderson Date: Tue, 26 May 2026 16:15:33 +0530 Subject: [PATCH 1/5] Perf: Eliminate per-frame List allocations in SunburstChart SeriesView.OnDraw Replace OrderBy().ToList() / .ToList() allocations on every draw frame with zero-allocation two-pass iteration using indexed for-loops. Before: Every OnDraw call allocated a new List via LINQ (.ToList() or OrderBy().ToList()), creating GC pressure on every render frame. After: Iterate the existing Segments collection directly with for-loops. When selection is active, use two passes (unselected first, selected on top) to maintain the same visual z-order without any allocation. Also removes the now-unused System.Linq import. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- maui/src/SunburstChart/Views/SeriesView.cs | 74 ++++++++-- .../Sunburst/SfSunburstChartUnitTests.cs | 139 ++++++++++++++++++ 2 files changed, 201 insertions(+), 12 deletions(-) diff --git a/maui/src/SunburstChart/Views/SeriesView.cs b/maui/src/SunburstChart/Views/SeriesView.cs index 9d4365f7..65b59655 100644 --- a/maui/src/SunburstChart/Views/SeriesView.cs +++ b/maui/src/SunburstChart/Views/SeriesView.cs @@ -1,7 +1,6 @@ using Microsoft.Maui.Controls; using Microsoft.Maui.Graphics; using Syncfusion.Maui.Toolkit.Graphics.Internals; -using System.Linq; namespace Syncfusion.Maui.Toolkit.SunburstChart { @@ -42,27 +41,78 @@ protected override void OnDraw(ICanvas canvas, RectF rect) canvas.SaveState(); canvas.Translate(0, 0); - if (_chart.Segments.Count > 0) + var segments = _chart.Segments; + + if (segments.Count > 0) { - // Determine if selection is active var hasSelection = _chart.SelectionSettings != null && _chart.SelectedSunburstItems.Count > 0; - var segmentsCollection = hasSelection ? _chart.Segments.OrderBy(s => s.IsSelected ? 1 : 0).ToList() : _chart.Segments.ToList(); #if WINDOWS - foreach (var segment in segmentsCollection) + if (hasSelection) + { + // Draw unselected segments first, then selected on top (two passes, zero allocation) + for (int i = 0; i < segments.Count; i++) + { + var segment = segments[i]; + if (!segment.IsSelected) + { + canvas.SaveState(); + segment.Draw(canvas); + canvas.RestoreState(); + } + } + + for (int i = 0; i < segments.Count; i++) + { + var segment = segments[i]; + if (segment.IsSelected) + { + canvas.SaveState(); + segment.Draw(canvas); + canvas.RestoreState(); + } + } + } + else { - canvas.SaveState(); - segment.Draw(canvas); - canvas.RestoreState(); + for (int i = 0; i < segments.Count; i++) + { + canvas.SaveState(); + segments[i].Draw(canvas); + canvas.RestoreState(); + } } #else // Other platforms drawing approach canvas.SaveState(); - foreach (var segment in segmentsCollection) - { - segment.Draw(canvas); - } + if (hasSelection) + { + for (int i = 0; i < segments.Count; i++) + { + var segment = segments[i]; + if (!segment.IsSelected) + { + segment.Draw(canvas); + } + } + + for (int i = 0; i < segments.Count; i++) + { + var segment = segments[i]; + if (segment.IsSelected) + { + segment.Draw(canvas); + } + } + } + else + { + for (int i = 0; i < segments.Count; i++) + { + segments[i].Draw(canvas); + } + } canvas.RestoreState(); #endif diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs index fc82cc6d..b2a175a4 100644 --- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs +++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs @@ -1,3 +1,5 @@ +using Microsoft.Maui.Graphics; +using System.Numerics; using Syncfusion.Maui.Toolkit.SunburstChart; namespace Syncfusion.Maui.Toolkit.UnitTest.Sunburst @@ -1778,7 +1780,144 @@ public void SelectedSunburstItems_Clear_TriggersCollectionChanged() #endregion + #region SeriesView OnDraw Performance Tests + [Fact] + public void SeriesView_OnDraw_WithEmptySegments_DoesNotThrow() + { + // Arrange + SfSunburstChart sunburstChart = new(); + var seriesView = new SeriesView(sunburstChart); + + // Act & Assert - Should not throw with empty segments + var exception = Record.Exception(() => + InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 100, 100))); + + Assert.Null(exception); + } + + [Fact] + public void SeriesView_OnDraw_WithSegments_NoSelection_DoesNotThrow() + { + // Arrange + SfSunburstChart sunburstChart = new(); + var segment = new SunburstSegment(); + sunburstChart.Segments.Add(segment); + var seriesView = new SeriesView(sunburstChart); + + // Act & Assert - Should not throw when drawing without selection + var exception = Record.Exception(() => + InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 100, 100))); + + Assert.Null(exception); + } + + [Fact] + public void SeriesView_OnDraw_WithSegments_WithSelection_DoesNotThrow() + { + // Arrange + SfSunburstChart sunburstChart = new(); + sunburstChart.SelectionSettings = new SunburstSelectionSettings(); + + var selectedSegment = new SunburstSegment(); + selectedSegment.IsSelected = true; + var unselectedSegment = new SunburstSegment(); + unselectedSegment.IsSelected = false; + + sunburstChart.Segments.Add(unselectedSegment); + sunburstChart.Segments.Add(selectedSegment); + sunburstChart.SelectedSunburstItems.Add(new SunburstItem()); + + var seriesView = new SeriesView(sunburstChart); + + // Act & Assert - Should not throw when drawing with selection active + var exception = Record.Exception(() => + InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 100, 100))); + + Assert.Null(exception); + } + + [Fact] + public void SeriesView_OnDraw_WithMixedSelection_DrawsAllSegments() + { + // Arrange + SfSunburstChart sunburstChart = new(); + sunburstChart.SelectionSettings = new SunburstSelectionSettings(); + + var segment1 = new SunburstSegment { IsSelected = false }; + var segment2 = new SunburstSegment { IsSelected = true }; + var segment3 = new SunburstSegment { IsSelected = false }; + + sunburstChart.Segments.Add(segment1); + sunburstChart.Segments.Add(segment2); + sunburstChart.Segments.Add(segment3); + sunburstChart.SelectedSunburstItems.Add(new SunburstItem()); + + var seriesView = new SeriesView(sunburstChart); + + // Act & Assert - Verify all segments are handled without error + var exception = Record.Exception(() => + InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 200, 200))); + + Assert.Null(exception); + } + + #endregion + + + } + + /// + /// Minimal mock ICanvas implementation for unit testing draw operations. + /// + internal class MockCanvas : ICanvas + { + public float DisplayScale { get; set; } = 1; + public float StrokeSize { get; set; } + public float StrokeDashOffset { get; set; } + public float MiterLimit { get; set; } = 10; + public Color StrokeColor { get; set; } = Colors.Black; + public LineCap StrokeLineCap { get; set; } + public LineJoin StrokeLineJoin { get; set; } + public float[] StrokeDashPattern { get; set; } = []; + public Color FillColor { get; set; } = Colors.White; + public Color FontColor { get; set; } = Colors.Black; + public IFont Font { get; set; } = Microsoft.Maui.Graphics.Font.Default; + public float FontSize { get; set; } = 12; + public float Alpha { get; set; } = 1; + public bool Antialias { get; set; } = true; + public BlendMode BlendMode { get; set; } + + public void ClipPath(PathF path, WindingMode windingMode = WindingMode.NonZero) { } + public void ClipRectangle(float x, float y, float width, float height) { } + public void ConcatenateTransform(Matrix3x2 transform) { } + public void DrawArc(float x, float y, float width, float height, float startAngle, float endAngle, bool clockwise, bool closed) { } + public void DrawEllipse(float x, float y, float width, float height) { } + public void DrawImage(Microsoft.Maui.Graphics.IImage image, float x, float y, float width, float height) { } + public void DrawLine(float x1, float y1, float x2, float y2) { } + public void DrawPath(PathF path) { } + public void DrawRectangle(float x, float y, float width, float height) { } + public void DrawRoundedRectangle(float x, float y, float width, float height, float cornerRadius) { } + public void DrawString(string value, float x, float y, HorizontalAlignment horizontalAlignment) { } + public void DrawString(string value, float x, float y, float width, float height, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, TextFlow textFlow = TextFlow.ClipBounds, float lineSpacingAdjustment = 0) { } + public void DrawText(Microsoft.Maui.Graphics.Text.IAttributedText value, float x, float y, float width, float height) { } + public void FillArc(float x, float y, float width, float height, float startAngle, float endAngle, bool clockwise) { } + public void FillEllipse(float x, float y, float width, float height) { } + public void FillPath(PathF path, WindingMode windingMode = WindingMode.NonZero) { } + public void FillRectangle(float x, float y, float width, float height) { } + public void FillRoundedRectangle(float x, float y, float width, float height, float cornerRadius) { } + public SizeF GetStringSize(string value, IFont font, float fontSize) => new(100, 20); + public SizeF GetStringSize(string value, IFont font, float fontSize, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) => new(100, 20); + public void ResetState() { } + public bool RestoreState() => true; + public void Rotate(float degrees, float x, float y) { } + public void Rotate(float degrees) { } + public void SaveState() { } + public void Scale(float sx, float sy) { } + public void SetFillPaint(Paint paint, RectF rectangle) { } + public void SetShadow(SizeF offset, float blur, Color color) { } + public void SubtractFromClip(float x, float y, float width, float height) { } + public void Translate(float tx, float ty) { } } } From b522a1b4fa36bbf278bc0e1cbc4c4db929d13052 Mon Sep 17 00:00:00 2001 From: SaiyathAliFathima <103025761+SaiyathAliFathima@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:35:55 +0530 Subject: [PATCH 2/5] Update SfSunburstChartUnitTests.cs Removed exception related unit test cases --- .../Sunburst/SfSunburstChartUnitTests.cs | 88 ------------------- 1 file changed, 88 deletions(-) diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs index b2a175a4..d9d896ec 100644 --- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs +++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs @@ -1,5 +1,3 @@ -using Microsoft.Maui.Graphics; -using System.Numerics; using Syncfusion.Maui.Toolkit.SunburstChart; namespace Syncfusion.Maui.Toolkit.UnitTest.Sunburst @@ -1779,92 +1777,6 @@ public void SelectedSunburstItems_Clear_TriggersCollectionChanged() } #endregion - - #region SeriesView OnDraw Performance Tests - - [Fact] - public void SeriesView_OnDraw_WithEmptySegments_DoesNotThrow() - { - // Arrange - SfSunburstChart sunburstChart = new(); - var seriesView = new SeriesView(sunburstChart); - - // Act & Assert - Should not throw with empty segments - var exception = Record.Exception(() => - InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 100, 100))); - - Assert.Null(exception); - } - - [Fact] - public void SeriesView_OnDraw_WithSegments_NoSelection_DoesNotThrow() - { - // Arrange - SfSunburstChart sunburstChart = new(); - var segment = new SunburstSegment(); - sunburstChart.Segments.Add(segment); - var seriesView = new SeriesView(sunburstChart); - - // Act & Assert - Should not throw when drawing without selection - var exception = Record.Exception(() => - InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 100, 100))); - - Assert.Null(exception); - } - - [Fact] - public void SeriesView_OnDraw_WithSegments_WithSelection_DoesNotThrow() - { - // Arrange - SfSunburstChart sunburstChart = new(); - sunburstChart.SelectionSettings = new SunburstSelectionSettings(); - - var selectedSegment = new SunburstSegment(); - selectedSegment.IsSelected = true; - var unselectedSegment = new SunburstSegment(); - unselectedSegment.IsSelected = false; - - sunburstChart.Segments.Add(unselectedSegment); - sunburstChart.Segments.Add(selectedSegment); - sunburstChart.SelectedSunburstItems.Add(new SunburstItem()); - - var seriesView = new SeriesView(sunburstChart); - - // Act & Assert - Should not throw when drawing with selection active - var exception = Record.Exception(() => - InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 100, 100))); - - Assert.Null(exception); - } - - [Fact] - public void SeriesView_OnDraw_WithMixedSelection_DrawsAllSegments() - { - // Arrange - SfSunburstChart sunburstChart = new(); - sunburstChart.SelectionSettings = new SunburstSelectionSettings(); - - var segment1 = new SunburstSegment { IsSelected = false }; - var segment2 = new SunburstSegment { IsSelected = true }; - var segment3 = new SunburstSegment { IsSelected = false }; - - sunburstChart.Segments.Add(segment1); - sunburstChart.Segments.Add(segment2); - sunburstChart.Segments.Add(segment3); - sunburstChart.SelectedSunburstItems.Add(new SunburstItem()); - - var seriesView = new SeriesView(sunburstChart); - - // Act & Assert - Verify all segments are handled without error - var exception = Record.Exception(() => - InvokePrivateMethod(seriesView, "OnDraw", new MockCanvas(), new RectF(0, 0, 200, 200))); - - Assert.Null(exception); - } - - #endregion - - } /// From 6ee8d7df503fb27b4b657459bd1c07b7323ef54c Mon Sep 17 00:00:00 2001 From: SaiyathAliFathima <103025761+SaiyathAliFathima@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:37:01 +0530 Subject: [PATCH 3/5] Update SfSunburstChartUnitTests.cs --- .../Sunburst/SfSunburstChartUnitTests.cs | 54 ------------------- 1 file changed, 54 deletions(-) diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs index d9d896ec..cd180625 100644 --- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs +++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs @@ -1777,59 +1777,5 @@ public void SelectedSunburstItems_Clear_TriggersCollectionChanged() } #endregion - } - - /// - /// Minimal mock ICanvas implementation for unit testing draw operations. - /// - internal class MockCanvas : ICanvas - { - public float DisplayScale { get; set; } = 1; - public float StrokeSize { get; set; } - public float StrokeDashOffset { get; set; } - public float MiterLimit { get; set; } = 10; - public Color StrokeColor { get; set; } = Colors.Black; - public LineCap StrokeLineCap { get; set; } - public LineJoin StrokeLineJoin { get; set; } - public float[] StrokeDashPattern { get; set; } = []; - public Color FillColor { get; set; } = Colors.White; - public Color FontColor { get; set; } = Colors.Black; - public IFont Font { get; set; } = Microsoft.Maui.Graphics.Font.Default; - public float FontSize { get; set; } = 12; - public float Alpha { get; set; } = 1; - public bool Antialias { get; set; } = true; - public BlendMode BlendMode { get; set; } - - public void ClipPath(PathF path, WindingMode windingMode = WindingMode.NonZero) { } - public void ClipRectangle(float x, float y, float width, float height) { } - public void ConcatenateTransform(Matrix3x2 transform) { } - public void DrawArc(float x, float y, float width, float height, float startAngle, float endAngle, bool clockwise, bool closed) { } - public void DrawEllipse(float x, float y, float width, float height) { } - public void DrawImage(Microsoft.Maui.Graphics.IImage image, float x, float y, float width, float height) { } - public void DrawLine(float x1, float y1, float x2, float y2) { } - public void DrawPath(PathF path) { } - public void DrawRectangle(float x, float y, float width, float height) { } - public void DrawRoundedRectangle(float x, float y, float width, float height, float cornerRadius) { } - public void DrawString(string value, float x, float y, HorizontalAlignment horizontalAlignment) { } - public void DrawString(string value, float x, float y, float width, float height, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, TextFlow textFlow = TextFlow.ClipBounds, float lineSpacingAdjustment = 0) { } - public void DrawText(Microsoft.Maui.Graphics.Text.IAttributedText value, float x, float y, float width, float height) { } - public void FillArc(float x, float y, float width, float height, float startAngle, float endAngle, bool clockwise) { } - public void FillEllipse(float x, float y, float width, float height) { } - public void FillPath(PathF path, WindingMode windingMode = WindingMode.NonZero) { } - public void FillRectangle(float x, float y, float width, float height) { } - public void FillRoundedRectangle(float x, float y, float width, float height, float cornerRadius) { } - public SizeF GetStringSize(string value, IFont font, float fontSize) => new(100, 20); - public SizeF GetStringSize(string value, IFont font, float fontSize, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) => new(100, 20); - public void ResetState() { } - public bool RestoreState() => true; - public void Rotate(float degrees, float x, float y) { } - public void Rotate(float degrees) { } - public void SaveState() { } - public void Scale(float sx, float sy) { } - public void SetFillPaint(Paint paint, RectF rectangle) { } - public void SetShadow(SizeF offset, float blur, Color color) { } - public void SubtractFromClip(float x, float y, float width, float height) { } - public void Translate(float tx, float ty) { } - } } From f36e0b9fbf422cfaae6d0c9d58bc95ce80eac3a1 Mon Sep 17 00:00:00 2001 From: SaiyathAliFathima <103025761+SaiyathAliFathima@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:38:08 +0530 Subject: [PATCH 4/5] Update SfSunburstChartUnitTests.cs --- .../Sunburst/SfSunburstChartUnitTests.cs | 94 ++++++++++--------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs index cd180625..eb3aadc4 100644 --- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs +++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs @@ -994,7 +994,7 @@ public void OnTapAction_WithSelectionDisabled_DoesNotSelectSegment() SfSunburstChart sunburstChart = new(); Point tapPoint = new(100, 100); bool selectionChanged = false; - + sunburstChart.SelectionChanged += (s, e) => selectionChanged = true; InvokePrivateMethod(sunburstChart, "OnTapAction", sunburstChart, tapPoint, 1); @@ -1010,12 +1010,12 @@ public void GetSelectedSegment_WithPointOutsideSegments_ReturnsNull() // Use the two-parameter overload by specifying the exact parameter types var getSelectedSegmentMethod = typeof(SfSunburstChart).GetMethod( - "GetSelectedSegment", + "GetSelectedSegment", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(float), typeof(float) }, null); - + Assert.NotNull(getSelectedSegmentMethod); var result = getSelectedSegmentMethod.Invoke(sunburstChart, new object[] { 100000f, 100000f }); @@ -1030,9 +1030,9 @@ public void IsSegmentSelected_WithEmptySegment_ReturnsFalse() // Act // Pass a new segment that's not part of the chart SunburstSegment emptySegment = new(); - + var result = InvokePrivateMethod(sunburstChart, "IsSegmentSelected", new object[] { emptySegment }); - + // Verify result is not null before casting Assert.NotNull(result); Assert.False(result is bool value && value); @@ -1063,11 +1063,11 @@ public void SelectSegment_WithSelectionDisabled_DoesNotSelectSegment() SfSunburstChart sunburstChart = new(); SunburstSegment segment = new(); bool selectionChanged = false; - + sunburstChart.SelectionChanged += (s, e) => selectionChanged = true; - + InvokePrivateMethod(sunburstChart, "SelectSegments", segment); - + Assert.Empty(sunburstChart.SelectedSunburstItems); Assert.False(selectionChanged); } @@ -1087,7 +1087,7 @@ public void SelectSegment_WithAlreadySelectedSegment_DoesNothing() InvokePrivateMethod(sunburstChart, "SelectSegments", segment); // Since the SelectSegments method is called without proper setup, no actual changes should occur - Assert.False(selectionChanged); + Assert.False(selectionChanged); } [Fact] @@ -1095,11 +1095,11 @@ public void ClearSelection_WithNoSelectedSegments_DoesNothing() { SfSunburstChart sunburstChart = new(); bool selectionChanged = false; - + sunburstChart.SelectionChanged += (s, e) => selectionChanged = true; - + InvokePrivateMethod(sunburstChart, "ClearSelection"); - + Assert.Empty(sunburstChart.SelectedSunburstItems); Assert.False(selectionChanged); } @@ -1111,14 +1111,15 @@ public void RaiseSelectionChanged_WhenCalled_InvokesEvent() SunburstSegment segment = new(); bool eventRaised = false; SunburstSelectionChangedEventArgs? capturedArgs = null; - - sunburstChart.SelectionChanged += (s, e) => { + + sunburstChart.SelectionChanged += (s, e) => + { eventRaised = true; capturedArgs = e; }; - + InvokePrivateMethod(sunburstChart, "RaiseSelectionChanged", segment, segment, true); - + Assert.True(eventRaised); Assert.NotNull(capturedArgs); Assert.Equal(segment, capturedArgs.NewSegment); @@ -1169,7 +1170,7 @@ public void SelectSegments_WithValidSegment_AddsToSelection() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Single }; - + SunburstSegment segment = new(); SunburstItem item = new() { Key = "Test" }; segment.SunburstItems = item; @@ -1188,7 +1189,7 @@ public void SelectSegments_WithChildType_SelectsChildrenToo() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Child }; - + SunburstSegment segment = new(); SunburstItem parentItem = new() { Key = "Parent" }; SunburstItem childItem = new() { Key = "Child" }; @@ -1210,15 +1211,15 @@ public void SelectSegments_WithGroupType_SelectsAllSegmentsWithSameIndex() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Group }; - + SunburstSegment segment1 = new() { Index = 1 }; SunburstSegment segment2 = new() { Index = 1 }; SunburstSegment segment3 = new() { Index = 2 }; - + SunburstItem item1 = new() { Key = "Item1" }; SunburstItem item2 = new() { Key = "Item2" }; SunburstItem item3 = new() { Key = "Item3" }; - + segment1.SunburstItems = item1; segment2.SunburstItems = item2; segment3.SunburstItems = item3; @@ -1242,19 +1243,19 @@ public void SelectSegments_WithParentType_SelectsParentChain() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Parent }; - + SunburstSegment grandParent = new(); SunburstSegment parent = new(); SunburstSegment child = new(); - + SunburstItem grandParentItem = new() { Key = "GrandParent" }; SunburstItem parentItem = new() { Key = "Parent" }; SunburstItem childItem = new() { Key = "Child" }; - + grandParent.SunburstItems = grandParentItem; parent.SunburstItems = parentItem; child.SunburstItems = childItem; - + child.Parent = parent; parent.Parent = grandParent; @@ -1278,7 +1279,8 @@ public void RaiseSelectionChanged_WithValidArguments_InvokesEvent() bool eventRaised = false; SunburstSelectionChangedEventArgs? capturedArgs = null; - sunburstChart.SelectionChanged += (s, e) => { + sunburstChart.SelectionChanged += (s, e) => + { eventRaised = true; capturedArgs = e; }; @@ -1318,7 +1320,8 @@ public void RaiseSelectionChanging_WithCancellingHandler_ReturnsFalse() SunburstSegment oldSegment = new(); SunburstSegment newSegment = new(); - sunburstChart.SelectionChanging += (s, e) => { + sunburstChart.SelectionChanging += (s, e) => + { e.Cancel = true; }; @@ -1340,7 +1343,8 @@ public void RaiseSelectionChanging_WithNonCancellingHandler_ReturnsTrue() bool eventRaised = false; SunburstSelectionChangingEventArgs? capturedArgs = null; - sunburstChart.SelectionChanging += (s, e) => { + sunburstChart.SelectionChanging += (s, e) => + { eventRaised = true; capturedArgs = e; }; @@ -1424,12 +1428,12 @@ public void GetSelectedSegment_WithValidItem_ReturnsSegment() // Use the one-parameter overload by specifying the exact parameter types var getSelectedSegmentMethod = typeof(SfSunburstChart).GetMethod( - "GetSelectedSegment", + "GetSelectedSegment", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(SunburstItem) }, null); - + Assert.NotNull(getSelectedSegmentMethod); // Act @@ -1467,18 +1471,18 @@ public void ApplyHighlightByOpacity_WithSelectedSegments_SetsOpacityCorrectly() { // Arrange SfSunburstChart sunburstChart = new(); - sunburstChart.SelectionSettings = new SunburstSelectionSettings - { + sunburstChart.SelectionSettings = new SunburstSelectionSettings + { DisplayMode = SunburstSelectionDisplayMode.HighlightByOpacity, Opacity = 0.5 }; SunburstSegment selectedSegment = new() { IsSelected = true }; SunburstSegment unselectedSegment = new() { IsSelected = false }; - + sunburstChart.Segments.Add(selectedSegment); sunburstChart.Segments.Add(unselectedSegment); - + SunburstItem item = new(); sunburstChart.SelectedSunburstItems.Add(item); @@ -1497,7 +1501,7 @@ public void ResetOpacity_WithNoSelection_ResetsAllOpacityToOne() SfSunburstChart sunburstChart = new(); SunburstSegment segment1 = new() { Opacity = 0.5f }; SunburstSegment segment2 = new() { Opacity = 0.3f }; - + sunburstChart.Segments.Add(segment1); sunburstChart.Segments.Add(segment2); @@ -1514,9 +1518,9 @@ public void SelectionInvalidate_CallsInvalidateDrawable() { // Arrange SfSunburstChart sunburstChart = new(); - + // Act - Should not throw exception - var exception = Record.Exception(() => + var exception = Record.Exception(() => InvokePrivateMethod(sunburstChart, "SelectionInvalidate")); // Assert @@ -1533,7 +1537,7 @@ public void SetFillColor_WithSelectedSegmentAndBrushMode_AppliesSelectionFill() DisplayMode = SunburstSelectionDisplayMode.HighlightByBrush, Fill = new SolidColorBrush(Colors.Red) }; - + SunburstSegment segment = new() { IsSelected = true, Index = 0 }; // Act @@ -1553,7 +1557,7 @@ public void SetOpacity_WithSelectedSegmentAndOpacityMode_MaintainsFullOpacity() DisplayMode = SunburstSelectionDisplayMode.HighlightByOpacity, Opacity = 0.5 }; - + SunburstSegment segment = new() { IsSelected = true }; // Act @@ -1573,7 +1577,7 @@ public void SetOpacity_WithUnselectedSegmentAndOpacityMode_AppliesSelectionOpaci DisplayMode = SunburstSelectionDisplayMode.HighlightByOpacity, Opacity = 0.3 }; - + SunburstSegment segment = new() { IsSelected = false }; // Act @@ -1594,7 +1598,7 @@ public void SetStroke_WithSelectedSegmentAndStrokeMode_AppliesSelectionStroke() Stroke = new SolidColorBrush(Colors.Green), StrokeWidth = 3.0 }; - + SunburstSegment segment = new() { IsSelected = true }; // Act @@ -1668,7 +1672,7 @@ public void SelectionSettings_PropertyChanged_ClearsExistingSelection() SfSunburstChart sunburstChart = new(); SunburstItem item = new(); sunburstChart.SelectedSunburstItems.Add(item); - + var settings = new SunburstSelectionSettings(); sunburstChart.SelectionSettings = settings; @@ -1686,7 +1690,7 @@ public void SelectionSettings_DisplayModeChange_ClearsExistingSelection() SfSunburstChart sunburstChart = new(); SunburstItem item = new(); sunburstChart.SelectedSunburstItems.Add(item); - + var settings = new SunburstSelectionSettings(); sunburstChart.SelectionSettings = settings; @@ -1705,7 +1709,7 @@ public void OnTapAction_WithValidTapAndSelectionEnabled_ProcessesSelection() sunburstChart.SelectionSettings = new SunburstSelectionSettings(); Point tapPoint = new(100, 100); bool selectionEventRaised = false; - + sunburstChart.SelectionChanged += (s, e) => selectionEventRaised = true; // Act @@ -1777,5 +1781,5 @@ public void SelectedSunburstItems_Clear_TriggersCollectionChanged() } #endregion + } } - From 347f7a2ff996eac9e0c36f214e8c2fd780f533e0 Mon Sep 17 00:00:00 2001 From: SaiyathAliFathima <103025761+SaiyathAliFathima@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:39:51 +0530 Subject: [PATCH 5/5] Update SfSunburstChartUnitTests.cs --- .../Sunburst/SfSunburstChartUnitTests.cs | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs index eb3aadc4..fc82cc6d 100644 --- a/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs +++ b/maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Sunburst/SfSunburstChartUnitTests.cs @@ -994,7 +994,7 @@ public void OnTapAction_WithSelectionDisabled_DoesNotSelectSegment() SfSunburstChart sunburstChart = new(); Point tapPoint = new(100, 100); bool selectionChanged = false; - + sunburstChart.SelectionChanged += (s, e) => selectionChanged = true; InvokePrivateMethod(sunburstChart, "OnTapAction", sunburstChart, tapPoint, 1); @@ -1010,12 +1010,12 @@ public void GetSelectedSegment_WithPointOutsideSegments_ReturnsNull() // Use the two-parameter overload by specifying the exact parameter types var getSelectedSegmentMethod = typeof(SfSunburstChart).GetMethod( - "GetSelectedSegment", + "GetSelectedSegment", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(float), typeof(float) }, null); - + Assert.NotNull(getSelectedSegmentMethod); var result = getSelectedSegmentMethod.Invoke(sunburstChart, new object[] { 100000f, 100000f }); @@ -1030,9 +1030,9 @@ public void IsSegmentSelected_WithEmptySegment_ReturnsFalse() // Act // Pass a new segment that's not part of the chart SunburstSegment emptySegment = new(); - + var result = InvokePrivateMethod(sunburstChart, "IsSegmentSelected", new object[] { emptySegment }); - + // Verify result is not null before casting Assert.NotNull(result); Assert.False(result is bool value && value); @@ -1063,11 +1063,11 @@ public void SelectSegment_WithSelectionDisabled_DoesNotSelectSegment() SfSunburstChart sunburstChart = new(); SunburstSegment segment = new(); bool selectionChanged = false; - + sunburstChart.SelectionChanged += (s, e) => selectionChanged = true; - + InvokePrivateMethod(sunburstChart, "SelectSegments", segment); - + Assert.Empty(sunburstChart.SelectedSunburstItems); Assert.False(selectionChanged); } @@ -1087,7 +1087,7 @@ public void SelectSegment_WithAlreadySelectedSegment_DoesNothing() InvokePrivateMethod(sunburstChart, "SelectSegments", segment); // Since the SelectSegments method is called without proper setup, no actual changes should occur - Assert.False(selectionChanged); + Assert.False(selectionChanged); } [Fact] @@ -1095,11 +1095,11 @@ public void ClearSelection_WithNoSelectedSegments_DoesNothing() { SfSunburstChart sunburstChart = new(); bool selectionChanged = false; - + sunburstChart.SelectionChanged += (s, e) => selectionChanged = true; - + InvokePrivateMethod(sunburstChart, "ClearSelection"); - + Assert.Empty(sunburstChart.SelectedSunburstItems); Assert.False(selectionChanged); } @@ -1111,15 +1111,14 @@ public void RaiseSelectionChanged_WhenCalled_InvokesEvent() SunburstSegment segment = new(); bool eventRaised = false; SunburstSelectionChangedEventArgs? capturedArgs = null; - - sunburstChart.SelectionChanged += (s, e) => - { + + sunburstChart.SelectionChanged += (s, e) => { eventRaised = true; capturedArgs = e; }; - + InvokePrivateMethod(sunburstChart, "RaiseSelectionChanged", segment, segment, true); - + Assert.True(eventRaised); Assert.NotNull(capturedArgs); Assert.Equal(segment, capturedArgs.NewSegment); @@ -1170,7 +1169,7 @@ public void SelectSegments_WithValidSegment_AddsToSelection() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Single }; - + SunburstSegment segment = new(); SunburstItem item = new() { Key = "Test" }; segment.SunburstItems = item; @@ -1189,7 +1188,7 @@ public void SelectSegments_WithChildType_SelectsChildrenToo() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Child }; - + SunburstSegment segment = new(); SunburstItem parentItem = new() { Key = "Parent" }; SunburstItem childItem = new() { Key = "Child" }; @@ -1211,15 +1210,15 @@ public void SelectSegments_WithGroupType_SelectsAllSegmentsWithSameIndex() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Group }; - + SunburstSegment segment1 = new() { Index = 1 }; SunburstSegment segment2 = new() { Index = 1 }; SunburstSegment segment3 = new() { Index = 2 }; - + SunburstItem item1 = new() { Key = "Item1" }; SunburstItem item2 = new() { Key = "Item2" }; SunburstItem item3 = new() { Key = "Item3" }; - + segment1.SunburstItems = item1; segment2.SunburstItems = item2; segment3.SunburstItems = item3; @@ -1243,19 +1242,19 @@ public void SelectSegments_WithParentType_SelectsParentChain() // Arrange SfSunburstChart sunburstChart = new(); sunburstChart.SelectionSettings = new SunburstSelectionSettings { Type = SunburstSelectionType.Parent }; - + SunburstSegment grandParent = new(); SunburstSegment parent = new(); SunburstSegment child = new(); - + SunburstItem grandParentItem = new() { Key = "GrandParent" }; SunburstItem parentItem = new() { Key = "Parent" }; SunburstItem childItem = new() { Key = "Child" }; - + grandParent.SunburstItems = grandParentItem; parent.SunburstItems = parentItem; child.SunburstItems = childItem; - + child.Parent = parent; parent.Parent = grandParent; @@ -1279,8 +1278,7 @@ public void RaiseSelectionChanged_WithValidArguments_InvokesEvent() bool eventRaised = false; SunburstSelectionChangedEventArgs? capturedArgs = null; - sunburstChart.SelectionChanged += (s, e) => - { + sunburstChart.SelectionChanged += (s, e) => { eventRaised = true; capturedArgs = e; }; @@ -1320,8 +1318,7 @@ public void RaiseSelectionChanging_WithCancellingHandler_ReturnsFalse() SunburstSegment oldSegment = new(); SunburstSegment newSegment = new(); - sunburstChart.SelectionChanging += (s, e) => - { + sunburstChart.SelectionChanging += (s, e) => { e.Cancel = true; }; @@ -1343,8 +1340,7 @@ public void RaiseSelectionChanging_WithNonCancellingHandler_ReturnsTrue() bool eventRaised = false; SunburstSelectionChangingEventArgs? capturedArgs = null; - sunburstChart.SelectionChanging += (s, e) => - { + sunburstChart.SelectionChanging += (s, e) => { eventRaised = true; capturedArgs = e; }; @@ -1428,12 +1424,12 @@ public void GetSelectedSegment_WithValidItem_ReturnsSegment() // Use the one-parameter overload by specifying the exact parameter types var getSelectedSegmentMethod = typeof(SfSunburstChart).GetMethod( - "GetSelectedSegment", + "GetSelectedSegment", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(SunburstItem) }, null); - + Assert.NotNull(getSelectedSegmentMethod); // Act @@ -1471,18 +1467,18 @@ public void ApplyHighlightByOpacity_WithSelectedSegments_SetsOpacityCorrectly() { // Arrange SfSunburstChart sunburstChart = new(); - sunburstChart.SelectionSettings = new SunburstSelectionSettings - { + sunburstChart.SelectionSettings = new SunburstSelectionSettings + { DisplayMode = SunburstSelectionDisplayMode.HighlightByOpacity, Opacity = 0.5 }; SunburstSegment selectedSegment = new() { IsSelected = true }; SunburstSegment unselectedSegment = new() { IsSelected = false }; - + sunburstChart.Segments.Add(selectedSegment); sunburstChart.Segments.Add(unselectedSegment); - + SunburstItem item = new(); sunburstChart.SelectedSunburstItems.Add(item); @@ -1501,7 +1497,7 @@ public void ResetOpacity_WithNoSelection_ResetsAllOpacityToOne() SfSunburstChart sunburstChart = new(); SunburstSegment segment1 = new() { Opacity = 0.5f }; SunburstSegment segment2 = new() { Opacity = 0.3f }; - + sunburstChart.Segments.Add(segment1); sunburstChart.Segments.Add(segment2); @@ -1518,9 +1514,9 @@ public void SelectionInvalidate_CallsInvalidateDrawable() { // Arrange SfSunburstChart sunburstChart = new(); - + // Act - Should not throw exception - var exception = Record.Exception(() => + var exception = Record.Exception(() => InvokePrivateMethod(sunburstChart, "SelectionInvalidate")); // Assert @@ -1537,7 +1533,7 @@ public void SetFillColor_WithSelectedSegmentAndBrushMode_AppliesSelectionFill() DisplayMode = SunburstSelectionDisplayMode.HighlightByBrush, Fill = new SolidColorBrush(Colors.Red) }; - + SunburstSegment segment = new() { IsSelected = true, Index = 0 }; // Act @@ -1557,7 +1553,7 @@ public void SetOpacity_WithSelectedSegmentAndOpacityMode_MaintainsFullOpacity() DisplayMode = SunburstSelectionDisplayMode.HighlightByOpacity, Opacity = 0.5 }; - + SunburstSegment segment = new() { IsSelected = true }; // Act @@ -1577,7 +1573,7 @@ public void SetOpacity_WithUnselectedSegmentAndOpacityMode_AppliesSelectionOpaci DisplayMode = SunburstSelectionDisplayMode.HighlightByOpacity, Opacity = 0.3 }; - + SunburstSegment segment = new() { IsSelected = false }; // Act @@ -1598,7 +1594,7 @@ public void SetStroke_WithSelectedSegmentAndStrokeMode_AppliesSelectionStroke() Stroke = new SolidColorBrush(Colors.Green), StrokeWidth = 3.0 }; - + SunburstSegment segment = new() { IsSelected = true }; // Act @@ -1672,7 +1668,7 @@ public void SelectionSettings_PropertyChanged_ClearsExistingSelection() SfSunburstChart sunburstChart = new(); SunburstItem item = new(); sunburstChart.SelectedSunburstItems.Add(item); - + var settings = new SunburstSelectionSettings(); sunburstChart.SelectionSettings = settings; @@ -1690,7 +1686,7 @@ public void SelectionSettings_DisplayModeChange_ClearsExistingSelection() SfSunburstChart sunburstChart = new(); SunburstItem item = new(); sunburstChart.SelectedSunburstItems.Add(item); - + var settings = new SunburstSelectionSettings(); sunburstChart.SelectionSettings = settings; @@ -1709,7 +1705,7 @@ public void OnTapAction_WithValidTapAndSelectionEnabled_ProcessesSelection() sunburstChart.SelectionSettings = new SunburstSelectionSettings(); Point tapPoint = new(100, 100); bool selectionEventRaised = false; - + sunburstChart.SelectionChanged += (s, e) => selectionEventRaised = true; // Act @@ -1781,5 +1777,8 @@ public void SelectedSunburstItems_Clear_TriggersCollectionChanged() } #endregion + + } } +