|
| 1 | +"""Tests for GitHub utility functions.""" |
| 2 | + |
| 3 | +from openhands.sdk.utils.github import ZWJ, sanitize_openhands_mentions |
| 4 | + |
| 5 | + |
| 6 | +def test_sanitize_basic_mention(): |
| 7 | + """Test basic @OpenHands mention is sanitized.""" |
| 8 | + text = "Thanks @OpenHands for the help!" |
| 9 | + expected = f"Thanks @{ZWJ}OpenHands for the help!" |
| 10 | + assert sanitize_openhands_mentions(text) == expected |
| 11 | + |
| 12 | + |
| 13 | +def test_sanitize_case_insensitive(): |
| 14 | + """Test that mentions are sanitized regardless of case.""" |
| 15 | + test_cases = [ |
| 16 | + ("Check @OpenHands here", f"Check @{ZWJ}OpenHands here"), |
| 17 | + ("Check @openhands here", f"Check @{ZWJ}openhands here"), |
| 18 | + ("Check @OPENHANDS here", f"Check @{ZWJ}OPENHANDS here"), |
| 19 | + ("Check @oPeNhAnDs here", f"Check @{ZWJ}oPeNhAnDs here"), |
| 20 | + ] |
| 21 | + for input_text, expected in test_cases: |
| 22 | + assert sanitize_openhands_mentions(input_text) == expected |
| 23 | + |
| 24 | + |
| 25 | +def test_sanitize_multiple_mentions(): |
| 26 | + """Test multiple mentions in the same text.""" |
| 27 | + text = "Both @OpenHands and @openhands should be sanitized" |
| 28 | + expected = f"Both @{ZWJ}OpenHands and @{ZWJ}openhands should be sanitized" |
| 29 | + assert sanitize_openhands_mentions(text) == expected |
| 30 | + |
| 31 | + |
| 32 | +def test_sanitize_with_punctuation(): |
| 33 | + """Test mentions followed by punctuation.""" |
| 34 | + test_cases = [ |
| 35 | + ("Thanks @OpenHands!", f"Thanks @{ZWJ}OpenHands!"), |
| 36 | + ("Hello @OpenHands.", f"Hello @{ZWJ}OpenHands."), |
| 37 | + ("See @OpenHands,", f"See @{ZWJ}OpenHands,"), |
| 38 | + ("By @OpenHands:", f"By @{ZWJ}OpenHands:"), |
| 39 | + ("From @OpenHands;", f"From @{ZWJ}OpenHands;"), |
| 40 | + ("Hi @OpenHands?", f"Hi @{ZWJ}OpenHands?"), |
| 41 | + ("Use @OpenHands)", f"Use @{ZWJ}OpenHands)"), |
| 42 | + ("Try (@OpenHands)", f"Try (@{ZWJ}OpenHands)"), |
| 43 | + ] |
| 44 | + for input_text, expected in test_cases: |
| 45 | + assert sanitize_openhands_mentions(input_text) == expected |
| 46 | + |
| 47 | + |
| 48 | +def test_no_sanitize_partial_words(): |
| 49 | + """Test that partial word matches are NOT sanitized.""" |
| 50 | + test_cases = [ |
| 51 | + "OpenHandsTeam", |
| 52 | + "MyOpenHands", |
| 53 | + "OpenHandsBot", |
| 54 | + "#OpenHands", |
| 55 | + ] |
| 56 | + for text in test_cases: |
| 57 | + # Partial words without @ should remain unchanged |
| 58 | + assert sanitize_openhands_mentions(text) == text |
| 59 | + |
| 60 | + |
| 61 | +def test_no_op_cases(): |
| 62 | + """Test cases where no sanitization should occur.""" |
| 63 | + test_cases = [ |
| 64 | + "", |
| 65 | + "No mentions here", |
| 66 | + "Just some text", |
| 67 | + "@GitHub", |
| 68 | + "@Other", |
| 69 | + "OpenHands without @", |
| 70 | + ] |
| 71 | + for text in test_cases: |
| 72 | + assert sanitize_openhands_mentions(text) == text |
| 73 | + |
| 74 | + |
| 75 | +def test_sanitize_at_line_boundaries(): |
| 76 | + """Test mentions at the start and end of lines.""" |
| 77 | + test_cases = [ |
| 78 | + ("@OpenHands at start", f"@{ZWJ}OpenHands at start"), |
| 79 | + ("at end @OpenHands", f"at end @{ZWJ}OpenHands"), |
| 80 | + ("@OpenHands", f"@{ZWJ}OpenHands"), |
| 81 | + ] |
| 82 | + for input_text, expected in test_cases: |
| 83 | + assert sanitize_openhands_mentions(input_text) == expected |
| 84 | + |
| 85 | + |
| 86 | +def test_sanitize_multiline_text(): |
| 87 | + """Test sanitization in multiline text.""" |
| 88 | + text = """Hello @OpenHands! |
| 89 | +
|
| 90 | +This is a test with @openhands mentioned. |
| 91 | +
|
| 92 | +Thanks @OPENHANDS for everything!""" |
| 93 | + |
| 94 | + expected = f"""Hello @{ZWJ}OpenHands! |
| 95 | +
|
| 96 | +This is a test with @{ZWJ}openhands mentioned. |
| 97 | +
|
| 98 | +Thanks @{ZWJ}OPENHANDS for everything!""" |
| 99 | + |
| 100 | + assert sanitize_openhands_mentions(text) == expected |
| 101 | + |
| 102 | + |
| 103 | +def test_sanitize_with_urls(): |
| 104 | + """Test that URLs containing OpenHands are handled correctly.""" |
| 105 | + test_cases = [ |
| 106 | + # URL should not be sanitized |
| 107 | + ("Visit https://github.com/OpenHands", "Visit https://github.com/OpenHands"), |
| 108 | + # But mention should be sanitized |
| 109 | + ( |
| 110 | + "See @OpenHands at https://github.com/OpenHands", |
| 111 | + f"See @{ZWJ}OpenHands at https://github.com/OpenHands", |
| 112 | + ), |
| 113 | + ] |
| 114 | + for input_text, expected in test_cases: |
| 115 | + assert sanitize_openhands_mentions(input_text) == expected |
| 116 | + |
| 117 | + |
| 118 | +def test_sanitize_preserves_whitespace(): |
| 119 | + """Test that whitespace is preserved correctly.""" |
| 120 | + text = " @OpenHands \n @openhands " |
| 121 | + expected = f" @{ZWJ}OpenHands \n @{ZWJ}openhands " |
| 122 | + assert sanitize_openhands_mentions(text) == expected |
| 123 | + |
| 124 | + |
| 125 | +def test_zwj_constant(): |
| 126 | + """Test that ZWJ constant is correctly defined.""" |
| 127 | + assert ZWJ == "\u200d" |
| 128 | + assert len(ZWJ) == 1 |
| 129 | + assert ord(ZWJ) == 0x200D |
0 commit comments