aboutsummaryrefslogtreecommitdiffstats
path: root/test/src
diff options
context:
space:
mode:
authorJens Schmidt2025-12-17 22:20:15 +0100
committerStefan Monnier2025-12-20 13:23:29 -0500
commit0aabe62b64b4698340e8414d28b0fa0a3eabbf82 (patch)
treeb0dcd8b62c796fcc0a08f68b0b17dd2591ae7b3c /test/src
parent875e42d501df262fcd9903528657997d025e5c68 (diff)
downloademacs-0aabe62b64b4698340e8414d28b0fa0a3eabbf82.tar.gz
emacs-0aabe62b64b4698340e8414d28b0fa0a3eabbf82.zip
Improve handling of non-ASCII characters in 'transpose-regions'
* src/editfns.c (Ftranspose_regions): Separate code related to character semantics from that related to byte semantics and in that way leverage optimizations for regions of equal length with respect to both semantics. Move and update comments dating back to the initial implementation. * test/src/editfns-tests.el (editfns-tests--transpose-regions-tests) (editfns-tests--transpose-regions-markups) (editfns-tests--transpose-regions): New test and accompanying variables.
Diffstat (limited to 'test/src')
-rw-r--r--test/src/editfns-tests.el204
1 files changed, 204 insertions, 0 deletions
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index 2fce2315edb..4e0ca4c9d2a 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -190,6 +190,210 @@
190 (should (equal-including-properties 190 (should (equal-including-properties
191 str1 (buffer-substring (+ (point-min) 5) (+ (point-min) 7))))))) 191 str1 (buffer-substring (+ (point-min) 5) (+ (point-min) 7)))))))
192 192
193(defconst editfns-tests--transpose-regions-tests
194 '(;; adjacent regions with one being empty
195 ("" "foo" "" "" "" [0 3 0 0 0])
196 ("" "" "" "baz" "" [0 0 0 3 0])
197
198 ;; For the following tests, assume that characters from the range
199 ;; [a-z] are 1 byte long in Emacs's internal text representation,
200 ;; while LATIN SMALL LETTER [AO] WITH DIAERESIS is 2 bytes long.
201
202 ;; (len1 == len2) && (end1 == start2) && (len1_byte == len2_byte)
203 ("" "fo(o" "" "b)az" "" [0 3 0 3 0])
204 ;; (len1 == len2) && (end1 != start2) && (len1_byte == len2_byte)
205 ("" "fo(o" "[bar]" "b)az" "" [0 3 3 3 0])
206
207 ;; (len1 != len2) && (end1 != start2) && (len1_byte < len2_byte)
208 ("" "fo(o" "[bar]" "baaz)" "" [0 3 3 4 0])
209 ;; (len1 != len2) && (end1 != start2) && (len1_byte > len2_byte)
210 ("" "(fooo" "[bar]" "baz)" "" [0 4 3 3 0])
211
212 ;; (len1 == len2) && (end1 == start2) && (len1_byte < len2_byte)
213 ("" "fo(o" "" "b)äz" "" [0 3 0 4 0])
214 ;; (len1 == len2) && (end1 == start2) && (len1_byte > len2_byte)
215 ("" "fo(ö" "" "b)az" "" [0 4 0 3 0])
216 ;; (len1 == len2) && (end1 != start2) && (len1_byte > len2_byte)
217 ("" "fo(o" "[bar]" "b)äz" "" [0 3 3 4 0])
218 ;; (len1 == len2) && (end1 != start2) && (len1_byte > len2_byte)
219 ("" "fo(ö" "[bar]" "b)az" "" [0 4 3 3 0])
220
221 ;; (len1 != len2) && (end1 == start2) && (len1_byte == len2_byte)
222 ("" "fo(ö" "" "baaz)" "" [0 4 0 4 0])
223 ;; (len1 != len2) && (end1 == start2) && (len1_byte == len2_byte)
224 ("" "(fooo" "" "bäz)" "" [0 4 0 4 0])
225 ;; (len1 != len2) && (end1 != start2) && (len1_byte == len2_byte)
226 ("" "fo(ö" "[bar]" "baaz)" "" [0 4 3 4 0])
227 ;; (len1 != len2) && (end1 != start2) && (len1_byte == len2_byte)
228 ("" "(fooo" "[bar]" "bäz)" "" [0 4 3 4 0])
229
230 ;; Going entirely non-ASCII. Assume plain greek small letters are
231 ;; two bytes long in Emacs's internal text representation, GREEK
232 ;; SMALL LETTER ALPHA WITH PSILI is three bytes long.
233
234 ;; To cover the initial patch from bug#70122, define a test
235 ;; consisting of three three-letter strings REG1 MID REG2, with
236 ;; (length REG1) == (length REG2) but (byte-length REG1) !=
237 ;; (byte-length REG2) ...
238 ("ἀ(ρχή" "φ[ωω" "β){αρ" "β<ἀ]ζ}" "τέλ>ος" [9 6 6 7 10])
239 ;; ... and a test with (length REG1) == (length REG2) and
240 ;; (byte-length REG1) == (byte-length REG2).
241 ("ἀ(ρχή" "φ[ωω" "β){αρ" "β<α]ζ}" "τέλ>ος" [9 6 6 6 10])
242
243 ;; Define the moral equivalent of
244 ;; `editfns-tests--transpose-equal-but-not'.
245 (" " "(ab)" "[SPC]" "{é}" " " [1 2 3 2 1])
246
247 ;; Likewise, for the testcase from bug#70122 in
248 ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=70122#5.
249 ("" "" "(a):\n[b]: \x2113\x2080\n" "{v}: scaling" "" [0 0 13 10 0])
250
251 ;; Likewise, for the testcase from bug#70122 in
252 ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=70122#52.
253 ("(Query replace (default abc → d): )" "abc" "[ → ]" "d" "" [35 3 5 1 0]))
254 "List of test strings and their markup to test `transpose-regions'.
255Each element of this list should be a list
256
257 HEAD REG1 MID REG2 TAIL BYTE-LENGTHS
258
259where the first five elements are (possibly empty) string snippets and
260the sixth element is a five-element vector providing the lengths of the
261string snippets, counted in bytes in Emacs's internal text
262representation.
263
264Test `editfns-tests--transpose-regions' inserts the five snippets into
265its temporary buffer, adds text properties to them as described for
266variable `editfns-tests--transpose-regions-markups', transposes REG1 and
267REG2, probably undoes the change, and at each stage ensures that all
268involved entities look as expected.")
269
270(defconst editfns-tests--transpose-regions-markups
271 '("()" "[]" "{}" "<>")
272 "List of two-characters strings \"BE\" describing text property markup.
273For each element in this list, test `editfns-tests--transpose-regions'
274searches once for regular expression \"B.+E\" in its temporary buffer,
275adds a text property `markup' with value \"BE\" to the matching text,
276and then removes the markup characters B and E around the matching text.
277
278The test searches in the buffer with all test snippets already inserted,
279so characters B and E can originate from different snippets, and the
280various B's and E's of different markup items do not need to nest.")
281
282(ert-deftest editfns-tests--transpose-regions ()
283 "Test function `transpose-regions'.
284Execute tests as described by `editfns-tests--transpose-regions-tests'."
285 (dolist (test editfns-tests--transpose-regions-tests)
286 (dolist (leave-markers '(nil t))
287 (message "test: %S leave-markers: %S" test leave-markers)
288 (with-temp-buffer
289 (let ((test (take 5 test))
290 (blengthv (nth 5 test))
291 (smarkers nil) ; Separator markers.
292 (pmarkers nil) ; Property markers.
293 (pmpos nil) ; Their positions before transposing.
294 (strings nil) ; Net text snippets, propertized.
295 (blengths nil) ; Their lengths in bytes.
296 (tstrings nil) ; Net text snippets with REG1/2 transposed.
297 (test-undo nil)
298 p beg end beg2 end2)
299 (buffer-enable-undo)
300 ;; Insert text snippets. While doing so, create the separator
301 ;; markers which we need later to determine the net text
302 ;; snippets.
303 (cl-assert (eq (length test) 5))
304 (setq p test)
305 (while (cdr p)
306 (insert (car p))
307 (push (point-marker) smarkers)
308 (setq p (cdr p)))
309 (insert (car p))
310 (setq smarkers (nreverse smarkers))
311 ;; Propertize them according to markup, remove markup
312 ;; characters, add property markers.
313 (dolist (markup editfns-tests--transpose-regions-markups)
314 (cl-assert (eq (length markup) 2))
315 (goto-char (point-min))
316 (when (search-forward-regexp
317 (concat "\\("
318 (regexp-quote (substring markup 0 1))
319 ".+"
320 (regexp-quote (substring markup 1 2))
321 "\\)")
322 nil t)
323 (setq beg (copy-marker (match-beginning 1))
324 end (copy-marker (match-end 1)))
325 (delete-region beg (1+ beg))
326 (delete-region (1- end) end)
327 (add-text-properties beg end (list 'markup markup))
328 (push beg pmarkers)
329 (push end pmarkers)))
330 (setq pmarkers (sort pmarkers)
331 pmpos (mapcar #'marker-position pmarkers))
332 ;; Determine net text snippets, plain and with transposed REG1
333 ;; and REG2. Determine the byte lengths of the net text
334 ;; snippets and ensure they meet our expectation.
335 (setq p smarkers
336 beg (point-min))
337 (while p
338 (push (buffer-substring beg (car p)) strings)
339 (push (- (position-bytes (car p)) (position-bytes beg))
340 blengths)
341 (setq beg (car p) p (cdr p)))
342 (push (buffer-substring beg (point-max)) strings)
343 (push (- (position-bytes (point-max)) (position-bytes beg))
344 blengths)
345 (setq strings (nreverse strings)
346 blengths (nreverse blengths))
347 (setq tstrings (list (nth 0 strings) (nth 3 strings)
348 (nth 2 strings) (nth 1 strings)
349 (nth 4 strings)))
350 (should (equal blengthv (apply #'vector blengths)))
351 ;; Transpose REG1 and REG2. Some transpositions might not
352 ;; generate undo, keep track of that in flag `test-undo'.
353 (setq beg (+ 1 (length (nth 0 strings)))
354 end (+ beg (length (nth 1 strings)))
355 beg2 (+ end (length (nth 2 strings)))
356 end2 (+ beg2 (length (nth 3 strings))))
357 (undo-boundary)
358 (transpose-regions beg end beg2 end2 leave-markers)
359 (when (car buffer-undo-list)
360 (setq test-undo t))
361 (undo-boundary)
362 ;; Check resulting buffer text and its properties.
363 (should (equal-including-properties
364 (buffer-string)
365 (mapconcat #'identity tstrings)))
366 ;; Check property marker positions.
367 (if leave-markers
368 (should (equal (mapcar #'marker-position pmarkers) pmpos))
369 ;; Meh. This more or less blindly duplicates function
370 ;; transpose_markers, since I have been too lazy to
371 ;; reproduce the arithmetics myself.
372 (setq pmpos
373 (mapcar
374 (lambda (pos)
375 (cond
376 ((< pos beg) pos)
377 ((>= pos end2) pos)
378 ((< pos end) (+ pos (+ (- end2 beg2) (- beg2 end))))
379 ((< pos beg2) (+ pos (- (- end2 beg2) (- end beg))))
380 (t (- pos (+ (- end beg) (- beg2 end))))))
381 pmpos))
382 (should (equal (mapcar #'marker-position pmarkers) pmpos)))
383 ;; Undo the transposition and check text and properties again,
384 ;; if needed. This does not undo any marker transpositions as
385 ;; per the comment before the call to transpose_markers in
386 ;; Ftranspose_regions, so nothing to check on the marker side
387 ;; after the undo.
388 (when test-undo
389 (undo)
390 (should (equal-including-properties
391 (buffer-string)
392 (mapconcat #'identity strings))))
393 ;; Be nice and clean up markers.
394 (dolist (marker smarkers) (set-marker marker nil))
395 (dolist (marker pmarkers) (set-marker marker nil)))))))
396
193(ert-deftest format-c-float () 397(ert-deftest format-c-float ()
194 (should-error (format "%c" 0.5))) 398 (should-error (format "%c" 0.5)))
195 399