1
- // RUN: %target-run-simple -swift
1
+ // RUN: %target-run-stdlib -swift %S/Inputs/
2
2
// REQUIRES: executable_test
3
3
// UNSUPPORTED: freestanding
4
4
5
5
import StdlibUnittest
6
6
#if _runtime(_ObjC)
7
7
import Foundation
8
8
#endif
9
+ import StdlibUnicodeUnittest
9
10
10
11
var suite = TestSuite ( " StringIndexTests " )
11
12
defer { runAllTests ( ) }
@@ -18,40 +19,6 @@ enum SimpleString: String {
18
19
case emoji = " 😀😃🤢🤮👩🏿🎤🧛🏻♂️🧛🏻♂️👩👩👦👦 "
19
20
}
20
21
21
- /// Print out a full list of indices in every view of `string`.
22
- /// This is useful while debugging test failures in this test.
23
- func dumpIndices( _ string: String ) {
24
- print ( " ------------------------------------------------------------------- " )
25
- print ( " String: \( String ( reflecting: string) ) " )
26
- print ( " Characters: " )
27
- string. indices. forEach { i in
28
- let char = string [ i]
29
- print ( " \( i) -> \( String ( reflecting: char) ) " )
30
- }
31
- print ( " Scalars: " )
32
- string. unicodeScalars. indices. forEach { i in
33
- let scalar = string. unicodeScalars [ i]
34
- let value = String ( scalar. value, radix: 16 , uppercase: true )
35
- let padding = String ( repeating: " 0 " , count: max ( 0 , 4 - value. count) )
36
- let name = scalar. properties. name ?? " \( scalar. debugDescription) "
37
- print ( " \( i) -> U+ \( padding) \( value) \( name) " )
38
- }
39
- print ( " UTF-8: " )
40
- string. utf8. indices. forEach { i in
41
- let code = string. utf8 [ i]
42
- let value = String ( code, radix: 16 , uppercase: true )
43
- let padding = value. count < 2 ? " 0 " : " "
44
- print ( " \( i) -> \( padding) \( value) " )
45
- }
46
- print ( " UTF-16: " )
47
- string. utf16. indices. forEach { i in
48
- let code = string. utf16 [ i]
49
- let value = String ( code, radix: 16 , uppercase: true )
50
- let padding = String ( repeating: " 0 " , count: 4 - value. count)
51
- print ( " \( i) -> \( padding) \( value) " )
52
- }
53
- }
54
-
55
22
let simpleStrings : [ String ] = [
56
23
SimpleString . smallASCII. rawValue,
57
24
SimpleString . smallUnicode. rawValue,
@@ -352,7 +319,7 @@ suite.test("Exhaustive Index Interchange")
352
319
return
353
320
}
354
321
355
- //dumpIndices(str )
322
+ //str. dumpIndices()
356
323
357
324
var curCharIdx = str. startIndex
358
325
var curScalarIdx = str. startIndex
@@ -482,111 +449,7 @@ suite.test("Exhaustive Index Interchange")
482
449
}
483
450
#endif
484
451
485
- extension Collection {
486
- // Assuming both `self` and `other` use the same index space, call `body` for
487
- // each index `i` in `other`, along with the slice in `self` that begins at
488
- // `i` and ends at the index following it in `other`.
489
- //
490
- // `other` must start with an item that is less than or equal to the first
491
- // item in `self`.
492
- func forEachIndexGroup< G: Collection > (
493
- by other: G ,
494
- body: ( G . Index , Self . SubSequence , Int ) throws -> Void
495
- ) rethrows
496
- where G. Index == Self . Index
497
- {
498
- if other. isEmpty {
499
- assert ( self . isEmpty)
500
- return
501
- }
502
- var i = other. startIndex
503
- var j = self . startIndex
504
- var offset = 0
505
- while i != other. endIndex {
506
- let current = i
507
- other. formIndex ( after: & i)
508
- let start = j
509
- while j < i, j < self . endIndex {
510
- self . formIndex ( after: & j)
511
- }
512
- let end = j
513
- try body ( current, self [ start ..< end] , offset)
514
- offset += 1
515
- }
516
- }
517
- }
518
-
519
- extension String {
520
- // Returns a list of every valid index in every string view, optionally
521
- // including end indices. We keep equal indices originating from different
522
- // views because they may have different grapheme size caches or flags etc.
523
- func allIndices( includingEnd: Bool = true ) -> [ String . Index ] {
524
- var r = Array ( self . indices)
525
- if includingEnd { r. append ( self . endIndex) }
526
- r += Array ( self . unicodeScalars. indices)
527
- if includingEnd { r. append ( self . unicodeScalars. endIndex) }
528
- r += Array ( self . utf8. indices)
529
- if includingEnd { r. append ( self . utf8. endIndex) }
530
- r += Array ( self . utf16. indices)
531
- if includingEnd { r. append ( self . utf16. endIndex) }
532
- return r
533
- }
534
-
535
- /// Returns a dictionary mapping each valid index to the index that lies on
536
- /// the nearest scalar boundary, rounding down.
537
- func scalarMap( ) -> [ String . Index : ( index: String . Index , offset: Int ) ] {
538
- var map : [ String . Index : ( index: String . Index , offset: Int ) ] = [ : ]
539
-
540
- self . utf8. forEachIndexGroup ( by: self . unicodeScalars) { scalar, slice, offset in
541
- for i in slice. indices { map [ i] = ( scalar, offset) }
542
- }
543
- self . utf16. forEachIndexGroup ( by: self . unicodeScalars) { scalar, slice, offset in
544
- for i in slice. indices { map [ i] = ( scalar, offset) }
545
- }
546
- self . forEachIndexGroup ( by: self . unicodeScalars) { scalar, slice, offset in
547
- for i in slice. indices { map [ i] = ( scalar, offset) }
548
- }
549
- map [ endIndex] = ( endIndex, self . unicodeScalars. count)
550
- return map
551
- }
552
-
553
- /// Returns a dictionary mapping each valid index to the index that lies on
554
- /// the nearest character boundary, rounding down.
555
- func characterMap( ) -> [ String . Index : ( index: String . Index , offset: Int ) ] {
556
- var map : [ String . Index : ( index: String . Index , offset: Int ) ] = [ : ]
557
- self . utf8. forEachIndexGroup ( by: self ) { char, slice, offset in
558
- for i in slice. indices { map [ i] = ( char, offset) }
559
- }
560
- self . utf16. forEachIndexGroup ( by: self ) { char, slice, offset in
561
- for i in slice. indices { map [ i] = ( char, offset) }
562
- }
563
- self . unicodeScalars. forEachIndexGroup ( by: self ) { char, slice, offset in
564
- for i in slice. indices { map [ i] = ( char, offset) }
565
- }
566
- map [ endIndex] = ( endIndex, count)
567
- return map
568
- }
569
- }
570
-
571
- extension Substring {
572
- // Returns a list of every valid index in every string view, optionally
573
- // including end indices. We keep equal indices originating from different
574
- // views because they may have different grapheme size caches or flags etc.
575
- func allIndices( includingEnd: Bool = true ) -> [ String . Index ] {
576
- var r = Array ( self . indices)
577
- if includingEnd { r. append ( self . endIndex) }
578
- r += Array ( self . unicodeScalars. indices)
579
- if includingEnd { r. append ( self . unicodeScalars. endIndex) }
580
- r += Array ( self . utf8. indices)
581
- if includingEnd { r. append ( self . utf8. endIndex) }
582
- r += Array ( self . utf16. indices)
583
- if includingEnd { r. append ( self . utf16. endIndex) }
584
- return r
585
- }
586
- }
587
-
588
- suite. test ( " Fully exhaustive index interchange " )
589
- . forEach ( in: examples) { string in
452
+ func fullyExhaustiveIndexInterchange( _ string: String ) {
590
453
guard #available( SwiftStdlib 5 . 7 , * ) else {
591
454
// Index navigation in 5.7 always rounds input indices down to the nearest
592
455
// Character, so that we always have a well-defined distance between
@@ -596,7 +459,7 @@ suite.test("Fully exhaustive index interchange")
596
459
return
597
460
}
598
461
599
- //dumpIndices(string )
462
+ //string. dumpIndices()
600
463
601
464
let scalarMap = string. scalarMap ( )
602
465
let characterMap = string. characterMap ( )
@@ -736,6 +599,18 @@ suite.test("Fully exhaustive index interchange")
736
599
}
737
600
}
738
601
602
+ suite. test ( " Fully exhaustive index interchange " )
603
+ . forEach ( in: examples) { string in
604
+ fullyExhaustiveIndexInterchange ( string)
605
+ }
606
+
607
+ suite. test ( " Fully exhaustive index interchange/GraphemeBreakTests " ) {
608
+ for string in graphemeBreakTests . map { $0. 0 } {
609
+ fullyExhaustiveIndexInterchange ( string)
610
+ }
611
+ }
612
+
613
+
739
614
suite. test ( " Global vs local grapheme cluster boundaries " ) {
740
615
guard #available( SwiftStdlib 5 . 7 , * ) else {
741
616
// Index navigation in 5.7 always rounds input indices down to the nearest
@@ -864,14 +739,14 @@ suite.test("Index encoding correction") {
864
739
// If the mutation's effect included the data addressed by the original index,
865
740
// then we may still get nonsensical results.
866
741
var s = ( " 🫱🏼🫲🏽 a 🧑🏽🌾 b " as NSString ) as String
867
- //dumpIndices(s )
742
+ //s. dumpIndices()
868
743
869
744
let originals = s. allIndices ( includingEnd: false ) . map {
870
745
( $0, s [ $0] , s. unicodeScalars [ $0] , s. utf8 [ $0] , s. utf16 [ $0] )
871
746
}
872
747
873
748
s. append ( " . " )
874
- //dumpIndices(s )
749
+ //s. dumpIndices()
875
750
876
751
for (i, char, scalar, u8, u16) in originals {
877
752
expectEqual ( s [ i] , char, " i: \( i) " )
@@ -893,7 +768,7 @@ suite.test("String.replaceSubrange index validation")
893
768
return
894
769
}
895
770
896
- //dumpIndices(string )
771
+ //string. dumpIndices()
897
772
898
773
let scalarMap = string. scalarMap ( )
899
774
let allIndices = string. allIndices ( )
@@ -958,12 +833,13 @@ suite.test("Substring.replaceSubrange index validation")
958
833
return
959
834
}
960
835
961
- dumpIndices ( string )
836
+ string . dumpIndices ( )
962
837
963
838
let scalarMap = string. scalarMap ( )
964
839
let allIndices = string. allIndices ( )
965
840
966
841
for i in allIndices {
842
+ print ( i)
967
843
for j in allIndices {
968
844
guard i <= j else { continue }
969
845
let si = scalarMap [ i] !. index
@@ -1021,3 +897,4 @@ suite.test("Substring.replaceSubrange index validation")
1021
897
}
1022
898
}
1023
899
}
900
+
0 commit comments