skipped 808 lines 809 809 return ft 810 810 }, 811 811 }, 812 + { 813 + desc: "tests maxTextCells length being applied - multiline", 814 + canvas: image.Rect(0, 0, 10, 3), 815 + opts: []Option{ 816 + MaxTextCells(10), 817 + RollContent(), 818 + }, 819 + writes: func(widget *Text) error { 820 + return widget.Write("line0\nline1\nline2\nline3\nline4") 821 + }, 822 + want: func(size image.Point) *faketerm.Terminal { 823 + ft := faketerm.MustNew(size) 824 + c := testcanvas.MustNew(ft.Area()) 825 + // \n still counts as a chacter in the string length 826 + testdraw.MustText(c, "ine3", image.Point{0, 0}) 827 + testdraw.MustText(c, "line4", image.Point{0, 1}) 828 + testcanvas.MustApply(c, ft) 829 + return ft 830 + }, 831 + }, 832 + { 833 + desc: "tests maxTextCells - multiple writes - first one fits", 834 + canvas: image.Rect(0, 0, 10, 3), 835 + opts: []Option{ 836 + MaxTextCells(10), 837 + RollContent(), 838 + }, 839 + writes: func(widget *Text) error { 840 + if err := widget.Write("line0\nline"); err != nil { 841 + return err 842 + } 843 + return widget.Write("1\nline2\nline3\nline4") 844 + }, 845 + want: func(size image.Point) *faketerm.Terminal { 846 + ft := faketerm.MustNew(size) 847 + c := testcanvas.MustNew(ft.Area()) 848 + // \n still counts as a chacter in the string length 849 + testdraw.MustText(c, "ine3", image.Point{0, 0}) 850 + testdraw.MustText(c, "line4", image.Point{0, 1}) 851 + testcanvas.MustApply(c, ft) 852 + return ft 853 + }, 854 + }, 855 + { 856 + desc: "tests maxTextCells - multiple writes - first one does not fit", 857 + canvas: image.Rect(0, 0, 10, 3), 858 + opts: []Option{ 859 + MaxTextCells(10), 860 + RollContent(), 861 + }, 862 + writes: func(widget *Text) error { 863 + if err := widget.Write("line0\nline123"); err != nil { 864 + return err 865 + } 866 + return widget.Write("1\nline2\nline3\nline4") 867 + }, 868 + want: func(size image.Point) *faketerm.Terminal { 869 + ft := faketerm.MustNew(size) 870 + c := testcanvas.MustNew(ft.Area()) 871 + testdraw.MustText(c, "ine3", image.Point{0, 0}) 872 + testdraw.MustText(c, "line4", image.Point{0, 1}) 873 + testcanvas.MustApply(c, ft) 874 + return ft 875 + }, 876 + }, 877 + { 878 + desc: "tests maxTextCells - accounts for pre-existing full-width runes on the content", 879 + canvas: image.Rect(0, 0, 10, 3), 880 + opts: []Option{ 881 + MaxTextCells(3), 882 + RollContent(), 883 + }, 884 + writes: func(widget *Text) error { 885 + if err := widget.Write("界"); err != nil { 886 + return err 887 + } 888 + return widget.Write("ab") 889 + }, 890 + want: func(size image.Point) *faketerm.Terminal { 891 + ft := faketerm.MustNew(size) 892 + c := testcanvas.MustNew(ft.Area()) 893 + testdraw.MustText(c, "ab", image.Point{0, 0}) 894 + testcanvas.MustApply(c, ft) 895 + return ft 896 + }, 897 + }, 898 + { 899 + desc: "tests maxTextCells exact length of 5", 900 + canvas: image.Rect(0, 0, 10, 1), 901 + opts: []Option{ 902 + RollContent(), 903 + MaxTextCells(5), 904 + }, 905 + writes: func(widget *Text) error { 906 + return widget.Write("12345") 907 + }, 908 + want: func(size image.Point) *faketerm.Terminal { 909 + ft := faketerm.MustNew(size) 910 + c := testcanvas.MustNew(ft.Area()) 911 + // Line return (\n) counts as one character 912 + testdraw.MustText( 913 + c, 914 + "12345", 915 + image.Point{0, 0}, 916 + ) 917 + testcanvas.MustApply(c, ft) 918 + return ft 919 + }, 920 + }, 921 + { 922 + desc: "tests maxTextCells partial bufffer replacement", 923 + canvas: image.Rect(0, 0, 10, 1), 924 + opts: []Option{ 925 + RollContent(), 926 + MaxTextCells(10), 927 + }, 928 + writes: func(widget *Text) error { 929 + return widget.Write("hello wor你12345678") 930 + }, 931 + want: func(size image.Point) *faketerm.Terminal { 932 + ft := faketerm.MustNew(size) 933 + c := testcanvas.MustNew(ft.Area()) 934 + testdraw.MustText( 935 + c, 936 + "你12345678", 937 + image.Point{0, 0}, 938 + ) 939 + testcanvas.MustApply(c, ft) 940 + return ft 941 + }, 942 + }, 943 + { 944 + desc: "tests maxTextCells length not being limited", 945 + canvas: image.Rect(0, 0, 72, 1), 946 + opts: []Option{ 947 + RollContent(), 948 + }, 949 + writes: func(widget *Text) error { 950 + return widget.Write("1234567890abcdefghijklmnopqrstuvwxyz") 951 + }, 952 + want: func(size image.Point) *faketerm.Terminal { 953 + ft := faketerm.MustNew(size) 954 + c := testcanvas.MustNew(ft.Area()) 955 + testdraw.MustText( 956 + c, 957 + "1234567890abcdefghijklmnopqrstuvwxyz", 958 + image.Point{0, 0}, 959 + ) 960 + testcanvas.MustApply(c, ft) 961 + return ft 962 + }, 963 + }, 964 + { 965 + desc: "tests maxTextCells length being applied - single line", 966 + canvas: image.Rect(0, 0, 10, 3), 967 + opts: []Option{ 968 + MaxTextCells(5), 969 + RollContent(), 970 + }, 971 + writes: func(widget *Text) error { 972 + return widget.Write("1234567890abcdefghijklmnopqrstuvwxyz") 973 + }, 974 + want: func(size image.Point) *faketerm.Terminal { 975 + ft := faketerm.MustNew(size) 976 + c := testcanvas.MustNew(ft.Area()) 977 + testdraw.MustText(c, "vwxyz", image.Point{0, 0}) 978 + testcanvas.MustApply(c, ft) 979 + return ft 980 + }, 981 + }, 812 982 } 813 983 814 984 for _, tc := range tests { skipped 87 lines 902 1072 } 903 1073 } 904 1074 1075 + func TestTruncateToCells(t *testing.T) { 1076 + tests := []struct { 1077 + desc string 1078 + text string 1079 + maxCells int 1080 + want string 1081 + }{ 1082 + { 1083 + desc: "returns empty on empty text", 1084 + text: "", 1085 + maxCells: 0, 1086 + want: "", 1087 + }, 1088 + { 1089 + desc: "no need to truncate, length matches max", 1090 + text: "a", 1091 + maxCells: 1, 1092 + want: "a", 1093 + }, 1094 + { 1095 + desc: "no need to truncate, shorter than max", 1096 + text: "a", 1097 + maxCells: 2, 1098 + want: "a", 1099 + }, 1100 + { 1101 + desc: "no need to truncate, maxCells set to zero", 1102 + text: "a", 1103 + maxCells: 0, 1104 + want: "a", 1105 + }, 1106 + { 1107 + desc: "truncates single rune to enforce max cells", 1108 + text: "abc", 1109 + maxCells: 2, 1110 + want: "bc", 1111 + }, 1112 + { 1113 + desc: "truncates multiple runes to enforce max cells", 1114 + text: "abcde", 1115 + maxCells: 3, 1116 + want: "cde", 1117 + }, 1118 + { 1119 + desc: "accounts for cells taken by newline characters", 1120 + text: "a\ncde", 1121 + maxCells: 3, 1122 + want: "cde", 1123 + }, 1124 + { 1125 + desc: "truncates full-width rune on its edge", 1126 + text: "世界", 1127 + maxCells: 2, 1128 + want: "界", 1129 + }, 1130 + { 1131 + desc: "truncates full-width rune because only half of it fits", 1132 + text: "世界", 1133 + maxCells: 3, 1134 + want: "界", 1135 + }, 1136 + { 1137 + desc: "full-width runes - truncating not needed", 1138 + text: "世界", 1139 + maxCells: 4, 1140 + want: "世界", 1141 + }, 1142 + } 1143 + 1144 + for _, tc := range tests { 1145 + t.Run(tc.desc, func(t *testing.T) { 1146 + got := truncateToCells(tc.text, tc.maxCells) 1147 + if diff := pretty.Compare(tc.want, got); diff != "" { 1148 + t.Errorf("truncateToCells => unexpected diff (-want, +got):\n%s", diff) 1149 + } 1150 + }) 1151 + } 1152 + } 1153 +