@@ -562,6 +562,253 @@ final class AcceptSuggestionTests: XCTestCase {
562562
563563 """ )
564564 }
565+
566+ func test_accept_suggestion_start_from_previous_line_has_emoji_inside( ) async throws {
567+ let content = """
568+ struct 😹😹 {
569+ }
570+ """
571+ let text = """
572+ struct 😹😹 {
573+ var name: String
574+ var age: String
575+ """
576+ let suggestion = CodeSuggestion (
577+ id: " " ,
578+ text: text,
579+ position: . init( line: 0 , character: 13 ) ,
580+ range: . init(
581+ start: . init( line: 0 , character: 0 ) ,
582+ end: . init( line: 0 , character: 13 )
583+ )
584+ )
585+
586+ var extraInfo = SuggestionInjector . ExtraInfo ( )
587+ var lines = content. breakIntoEditorStyleLines ( )
588+ var cursor = CursorPosition ( line: 0 , character: 13 )
589+ SuggestionInjector ( ) . acceptSuggestion (
590+ intoContentWithoutSuggestion: & lines,
591+ cursorPosition: & cursor,
592+ completion: suggestion,
593+ extraInfo: & extraInfo
594+ )
595+ XCTAssertTrue ( extraInfo. didChangeContent)
596+ XCTAssertTrue ( extraInfo. didChangeCursorPosition)
597+ XCTAssertNil ( extraInfo. suggestionRange)
598+ XCTAssertEqual ( lines, content. breakIntoEditorStyleLines ( ) . applying ( extraInfo. modifications) )
599+ XCTAssertEqual ( cursor, . init( line: 2 , character: 19 ) )
600+ XCTAssertEqual ( lines. joined ( separator: " " ) , """
601+ struct 😹😹 {
602+ var name: String
603+ var age: String
604+ }
605+
606+ """ )
607+ }
608+
609+ func test_accept_suggestion_overlap_with_emoji_in_the_previous_code( ) async throws {
610+ let content = """
611+ struct 😹😹 {
612+ var name
613+ }
614+ """
615+ let text = """
616+ var name: String
617+ var age: String
618+ """
619+ let suggestion = CodeSuggestion (
620+ id: " " ,
621+ text: text,
622+ position: . init( line: 1 , character: 13 ) ,
623+ range: . init(
624+ start: . init( line: 1 , character: 0 ) ,
625+ end: . init( line: 1 , character: 13 )
626+ )
627+ )
628+
629+ var extraInfo = SuggestionInjector . ExtraInfo ( )
630+ var lines = content. breakIntoEditorStyleLines ( )
631+ var cursor = CursorPosition ( line: 1 , character: 13 )
632+ SuggestionInjector ( ) . acceptSuggestion (
633+ intoContentWithoutSuggestion: & lines,
634+ cursorPosition: & cursor,
635+ completion: suggestion,
636+ extraInfo: & extraInfo
637+ )
638+ XCTAssertTrue ( extraInfo. didChangeContent)
639+ XCTAssertTrue ( extraInfo. didChangeCursorPosition)
640+ XCTAssertNil ( extraInfo. suggestionRange)
641+ XCTAssertEqual ( lines, content. breakIntoEditorStyleLines ( ) . applying ( extraInfo. modifications) )
642+ XCTAssertEqual ( cursor, . init( line: 2 , character: 19 ) )
643+ XCTAssertEqual ( lines. joined ( separator: " " ) , """
644+ struct 😹😹 {
645+ var name: String
646+ var age: String
647+ }
648+
649+ """ )
650+ }
651+
652+ func test_accept_suggestion_overlap_continue_typing_has_emoji_inside( ) async throws {
653+ let content = """
654+ struct 😹😹 {
655+ var name: Str
656+ }
657+ """
658+ let text = """
659+ var name: String
660+ var age: String
661+ """
662+ let suggestion = CodeSuggestion (
663+ id: " " ,
664+ text: text,
665+ position: . init( line: 1 , character: 13 ) ,
666+ range: . init(
667+ start: . init( line: 1 , character: 0 ) ,
668+ end: . init( line: 1 , character: 13 )
669+ )
670+ )
671+
672+ var extraInfo = SuggestionInjector . ExtraInfo ( )
673+ var lines = content. breakIntoEditorStyleLines ( )
674+ var cursor = CursorPosition ( line: 1 , character: 13 )
675+ SuggestionInjector ( ) . acceptSuggestion (
676+ intoContentWithoutSuggestion: & lines,
677+ cursorPosition: & cursor,
678+ completion: suggestion,
679+ extraInfo: & extraInfo
680+ )
681+ XCTAssertTrue ( extraInfo. didChangeContent)
682+ XCTAssertTrue ( extraInfo. didChangeCursorPosition)
683+ XCTAssertNil ( extraInfo. suggestionRange)
684+ XCTAssertEqual ( lines, content. breakIntoEditorStyleLines ( ) . applying ( extraInfo. modifications) )
685+ XCTAssertEqual ( cursor, . init( line: 2 , character: 19 ) )
686+ XCTAssertEqual ( lines. joined ( separator: " " ) , """
687+ struct 😹😹 {
688+ var name: String
689+ var age: String
690+ }
691+
692+ """ )
693+ }
694+
695+ func test_replacing_multiple_lines_with_emoji( ) async throws {
696+ let content = """
697+ struct 😹😹 {
698+ func speak() { print( " meow " ) }
699+ }
700+ """
701+ let text = """
702+ struct 🐶🐶 {
703+ func speak() {
704+ print( " woof " )
705+ }
706+ }
707+ """
708+ let suggestion = CodeSuggestion (
709+ id: " " ,
710+ text: text,
711+ position: . init( line: 0 , character: 7 ) ,
712+ range: . init(
713+ start: . init( line: 0 , character: 0 ) ,
714+ end: . init( line: 2 , character: 1 )
715+ )
716+ )
717+
718+ var extraInfo = SuggestionInjector . ExtraInfo ( )
719+ var lines = content. breakIntoEditorStyleLines ( )
720+ var cursor = CursorPosition ( line: 0 , character: 7 )
721+ SuggestionInjector ( ) . acceptSuggestion (
722+ intoContentWithoutSuggestion: & lines,
723+ cursorPosition: & cursor,
724+ completion: suggestion,
725+ extraInfo: & extraInfo
726+ )
727+
728+ XCTAssertTrue ( extraInfo. didChangeContent)
729+ XCTAssertTrue ( extraInfo. didChangeCursorPosition)
730+ XCTAssertNil ( extraInfo. suggestionRange)
731+ XCTAssertEqual ( lines, content. breakIntoEditorStyleLines ( ) . applying ( extraInfo. modifications) )
732+ XCTAssertEqual ( cursor, . init( line: 4 , character: 1 ) )
733+ XCTAssertEqual ( lines. joined ( separator: " " ) , """
734+ struct 🐶🐶 {
735+ func speak() {
736+ print( " woof " )
737+ }
738+ }
739+
740+ """ )
741+ }
742+
743+ func test_accept_suggestion_overlap_continue_typing_suggestion_with_emoji_in_the_middle( ) async throws {
744+ let content = """
745+ print( " 🐶 " )
746+ """
747+ let text = """
748+ print( " 🐶llo 🐶rld!
749+ """
750+ let suggestion = CodeSuggestion (
751+ id: " " ,
752+ text: text,
753+ position: . init( line: 0 , character: 6 ) ,
754+ range: . init(
755+ start: . init( line: 0 , character: 0 ) ,
756+ end: . init( line: 0 , character: 6 )
757+ )
758+ )
759+
760+ var extraInfo = SuggestionInjector . ExtraInfo ( )
761+ var lines = content. breakIntoEditorStyleLines ( )
762+ var cursor = CursorPosition ( line: 0 , character: 7 )
763+ SuggestionInjector ( ) . acceptSuggestion (
764+ intoContentWithoutSuggestion: & lines,
765+ cursorPosition: & cursor,
766+ completion: suggestion,
767+ extraInfo: & extraInfo
768+ )
769+ XCTAssertTrue ( extraInfo. didChangeContent)
770+ XCTAssertTrue ( extraInfo. didChangeCursorPosition)
771+ XCTAssertNil ( extraInfo. suggestionRange)
772+ XCTAssertEqual ( lines, content. breakIntoEditorStyleLines ( ) . applying ( extraInfo. modifications) )
773+ XCTAssertEqual ( cursor, . init( line: 0 , character: 19 ) )
774+ XCTAssertEqual ( lines. joined ( separator: " " ) , """
775+ print( " 🐶llo 🐶rld! " )
776+
777+ """ )
778+ }
779+
780+ func test_replacing_single_line_in_the_middle_should_not_remove_the_next_character_with_emoji(
781+ ) async throws {
782+ let content = """
783+ 🐶KeyName: ,,
784+ """
785+
786+ let suggestion = CodeSuggestion (
787+ id: " " ,
788+ text: " 🐶KeyName: azure👩❤️👨AIAPIKeyName " ,
789+ position: . init( line: 0 , character: 11 ) ,
790+ range: . init(
791+ start: . init( line: 0 , character: 0 ) ,
792+ end: . init( line: 0 , character: 11 )
793+ )
794+ )
795+
796+ var lines = content. breakIntoEditorStyleLines ( )
797+ var extraInfo = SuggestionInjector . ExtraInfo ( )
798+ var cursor = CursorPosition ( line: 5 , character: 34 )
799+ SuggestionInjector ( ) . acceptSuggestion (
800+ intoContentWithoutSuggestion: & lines,
801+ cursorPosition: & cursor,
802+ completion: suggestion,
803+ extraInfo: & extraInfo
804+ )
805+
806+ XCTAssertEqual ( cursor, . init( line: 0 , character: 36 ) )
807+ XCTAssertEqual ( lines. joined ( separator: " " ) , """
808+ 🐶KeyName: azure👩❤️👨AIAPIKeyName,,
809+
810+ """ )
811+ }
565812}
566813
567814extension String {
0 commit comments