| 1 | using CascadeIDE.Models; |
| 2 | using CascadeIDE.Views.SkiaKit; |
| 3 | using SkiaSharp; |
| 4 | using Xunit; |
| 5 | |
| 6 | namespace CascadeIDE.Tests; |
| 7 | |
| 8 | public sealed class SkiaTciTextFieldTests |
| 9 | { |
| 10 | [Fact] |
| 11 | public void CommandLine_hit_test_returns_caret_inside_mono_buffer() |
| 12 | { |
| 13 | const string text = "/intercom anchor peek"; |
| 14 | const float fontSize = 12f; |
| 15 | var bounds = new SKRect(0, 0, 400, SkiaCommandLineStrip.MeasureHeight(null, fontSize, 10f)); |
| 16 | Assert.True(SkiaCommandLineStrip.TryHitTestCaretAtPoint( |
| 17 | bounds, |
| 18 | text, |
| 19 | pointX: 120f, |
| 20 | pointY: bounds.Top + SkiaCommandLineStrip.VerticalPadding + 10f, |
| 21 | fontSize, |
| 22 | scrollOffsetX: 0f, |
| 23 | out var index)); |
| 24 | Assert.InRange(index, 1, text.Length); |
| 25 | } |
| 26 | |
| 27 | [Fact] |
| 28 | public void CommandLine_caret_rect_follows_index() |
| 29 | { |
| 30 | const string text = "/build"; |
| 31 | const float fontSize = 12f; |
| 32 | var bounds = new SKRect(0, 0, 300, SkiaCommandLineStrip.MeasureHeight(null, fontSize, 10f)); |
| 33 | const int caret = 3; |
| 34 | Assert.True(SkiaCommandLineStrip.TryGetCaretRect( |
| 35 | bounds, |
| 36 | text, |
| 37 | caret, |
| 38 | fontSize, |
| 39 | scrollOffsetX: 0f, |
| 40 | out var rect)); |
| 41 | Assert.True(rect.Width >= 1f); |
| 42 | Assert.True(rect.Height > 4f); |
| 43 | } |
| 44 | |
| 45 | [Fact] |
| 46 | public void Horizontal_scroll_increases_when_text_wider_than_viewport() |
| 47 | { |
| 48 | var longText = new string('x', 120); |
| 49 | var max = SkiaCommandLineStrip.MaxHorizontalScroll(longText, contentWidth: 80f, fontSize: 12f); |
| 50 | Assert.True(max > 0f); |
| 51 | } |
| 52 | |
| 53 | [Fact] |
| 54 | public void MeasureHeight_scales_with_default_command_line_pt() |
| 55 | { |
| 56 | var h12 = SkiaCommandLineStrip.MeasureHeight("err", 12f, 10f); |
| 57 | var h15 = SkiaCommandLineStrip.MeasureHeight("err", 15f, 12.5f); |
| 58 | Assert.True(h15 > h12); |
| 59 | Assert.True(h15 >= 15f + SkiaCommandLineStrip.VerticalPadding * 2); |
| 60 | } |
| 61 | |
| 62 | [Fact] |
| 63 | public void Leading_chip_gutter_only_when_icon_on_left() |
| 64 | { |
| 65 | const float fontSize = 12f; |
| 66 | var bounds = new SKRect(0, 0, 400, SkiaCommandLineStrip.MeasureHeight("/x", fontSize, 10f)); |
| 67 | try |
| 68 | { |
| 69 | SkiaSlashCommandChip.ConfigureIconPlacement(TciValidationIconModes.Left); |
| 70 | var plain = SkiaCommandLineStrip.ComputeInputRegion(bounds, fontSize); |
| 71 | var withChip = SkiaCommandLineStrip.ComputeInputRegion(bounds, fontSize, reserveLeadingChip: true); |
| 72 | Assert.True(withChip.TextBounds.Left > plain.TextBounds.Left); |
| 73 | } |
| 74 | finally |
| 75 | { |
| 76 | SkiaSlashCommandChip.ConfigureIconPlacement(TciValidationIconModes.Right); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | [Fact] |
| 81 | public void Input_region_fits_measured_glyph_height() |
| 82 | { |
| 83 | const float fontSize = 15f; |
| 84 | var bounds = new SKRect(0, 0, 400, SkiaCommandLineStrip.MeasureHeight("Нет такой команды.", fontSize, fontSize * (10f / 12f))); |
| 85 | var region = SkiaCommandLineStrip.ComputeInputRegion(bounds, fontSize); |
| 86 | var bodyHeight = SkiaPlainTextLayout.MeasureBodyHeight( |
| 87 | "/test", |
| 88 | region.ContentWidth, |
| 89 | fontSize, |
| 90 | SkiaCommandLineStrip.InputLineHeightFor(fontSize), |
| 91 | maxLines: 1, |
| 92 | SkiaCommandLineStrip.MonoFontFamily); |
| 93 | Assert.True(bodyHeight + region.TextTopInset * 2 <= region.TextBounds.Height + 1f); |
| 94 | } |
| 95 | } |
| 96 | |