tenseleyflow/fackr / 0c15f94

Browse files

test: add LSP test files

Add Python test files for manually testing LSP features:
- Hover, completion, diagnostics, go-to-definition
- References, rename, formatting, multi-cursor
Authored by espadonne
SHA
0c15f94d4acf5f0385a33dacd74d045f5c15633f
Parents
5b2d0d0
Tree
1e7804f

9 changed files

StatusFile+-
A test_lsp/01_hover.py 49 0
A test_lsp/02_completion.py 57 0
A test_lsp/03_diagnostics.py 62 0
A test_lsp/04_goto_definition.py 74 0
A test_lsp/05_references.py 81 0
A test_lsp/06_rename.py 88 0
A test_lsp/07_formatting.py 72 0
A test_lsp/08_multi_cursor.py 121 0
A test_lsp/README.md 47 0
test_lsp/01_hover.pyadded
@@ -0,0 +1,49 @@
1
+# LSP Test 1: Hover Information (F1)
2
+# ===================================
3
+#
4
+# Instructions:
5
+# 1. Place cursor on any symbol below
6
+# 2. Press F1 to see hover information
7
+# 3. Press Escape to dismiss the hover popup
8
+#
9
+# Try hovering over:
10
+# - Function names (greet, calculate_area)
11
+# - Variable names (message, radius)
12
+# - Built-in functions (print, len, range)
13
+# - Type names (str, int, float, list)
14
+
15
+def greet(name: str) -> str:
16
+    """Return a greeting message for the given name."""
17
+    message = f"Hello, {name}!"
18
+    return message
19
+
20
+
21
+def calculate_area(radius: float) -> float:
22
+    """Calculate the area of a circle given its radius."""
23
+    import math
24
+    return math.pi * radius ** 2
25
+
26
+
27
+class Person:
28
+    """A simple Person class for testing hover."""
29
+
30
+    def __init__(self, name: str, age: int):
31
+        self.name = name
32
+        self.age = age
33
+
34
+    def introduce(self) -> str:
35
+        """Return an introduction string."""
36
+        return f"I'm {self.name}, {self.age} years old."
37
+
38
+
39
+# Test area - place cursor on these and press F1:
40
+result = greet("World")
41
+area = calculate_area(5.0)
42
+person = Person("Alice", 30)
43
+intro = person.introduce()
44
+
45
+numbers = [1, 2, 3, 4, 5]
46
+length = len(numbers)
47
+
48
+for i in range(10):
49
+    print(i)
test_lsp/02_completion.pyadded
@@ -0,0 +1,57 @@
1
+# LSP Test 2: Code Completion (Ctrl+Space)
2
+# =========================================
3
+#
4
+# Instructions:
5
+# 1. Place cursor after a dot or partial word
6
+# 2. Press Ctrl+Space to trigger completion
7
+# 3. Use Up/Down arrows to navigate suggestions
8
+# 4. Press Enter or Tab to accept a completion
9
+# 5. Press Escape to dismiss without completing
10
+#
11
+# Try completing at the marked positions below:
12
+
13
+import os
14
+import json
15
+from pathlib import Path
16
+
17
+# Test 1: Module completions
18
+# Place cursor after "os." and press Ctrl+Space
19
+path = os.  # <- complete here (try: getcwd, path, environ)
20
+
21
+# Test 2: String method completions
22
+# Place cursor after "text." and press Ctrl+Space
23
+text = "hello world"
24
+upper = text.  # <- complete here (try: upper, lower, split, strip)
25
+
26
+# Test 3: List method completions
27
+numbers = [3, 1, 4, 1, 5]
28
+numbers.  # <- complete here (try: append, sort, reverse, pop)
29
+
30
+# Test 4: Dict method completions
31
+data = {"name": "test", "value": 42}
32
+keys = data.  # <- complete here (try: keys, values, items, get)
33
+
34
+# Test 5: Path object completions
35
+p = Path("/tmp")
36
+p.  # <- complete here (try: exists, is_file, read_text, mkdir)
37
+
38
+# Test 6: Partial word completion
39
+# Type "pri" and press Ctrl+Space to complete to "print"
40
+# pri  # <- uncomment and complete
41
+
42
+# Test 7: Import completion
43
+# from pathlib import P  # <- complete after P (Path, PurePath, etc.)
44
+
45
+
46
+class MyClass:
47
+    def __init__(self):
48
+        self.value = 100
49
+        self.name = "test"
50
+
51
+    def process(self):
52
+        # Test 8: Self completions
53
+        return self.  # <- complete here (try: value, name)
54
+
55
+
56
+obj = MyClass()
57
+obj.  # <- complete here (try: value, name, process)
test_lsp/03_diagnostics.pyadded
@@ -0,0 +1,62 @@
1
+# LSP Test 3: Diagnostics (Automatic)
2
+# ====================================
3
+#
4
+# Instructions:
5
+# 1. Diagnostics appear automatically as you edit
6
+# 2. Look for underlined/highlighted code indicating errors or warnings
7
+# 3. Errors and warnings should appear in the editor
8
+# 4. The status bar may show diagnostic counts
9
+#
10
+# This file contains intentional errors for testing:
11
+
12
+# Error 1: Undefined variable
13
+result = undefined_variable + 10
14
+
15
+# Error 2: Type mismatch (if using type checker)
16
+def add_numbers(a: int, b: int) -> int:
17
+    return a + b
18
+
19
+wrong_type = add_numbers("hello", "world")
20
+
21
+# Error 3: Import error
22
+from nonexistent_module import something
23
+
24
+# Error 4: Syntax-like issues
25
+def broken_function(x, y)  # Missing colon - uncomment to test
26
+    return x + y
27
+
28
+# Error 5: Unused variable (warning)
29
+unused_var = 42
30
+
31
+# Error 6: Undefined name in expression
32
+value = some_undefined_function()
33
+
34
+# Error 7: Wrong number of arguments
35
+def takes_two(a, b):
36
+    return a + b
37
+
38
+takes_two(1)  # Missing argument
39
+takes_two(1, 2, 3)  # Too many arguments
40
+
41
+# Error 8: Attribute error
42
+my_string = "hello"
43
+my_string.nonexistent_method()
44
+
45
+# Error 9: Invalid operation
46
+result = "string" + 42
47
+
48
+# Error 10: Redefinition (warning in some linters)
49
+def duplicate():
50
+    pass
51
+
52
+def duplicate():  # Redefined function
53
+    pass
54
+
55
+
56
+# Working code for comparison - this should have no errors:
57
+def working_function(name: str) -> str:
58
+    """This function works correctly."""
59
+    return f"Hello, {name}!"
60
+
61
+greeting = working_function("World")
62
+print(greeting)
test_lsp/04_goto_definition.pyadded
@@ -0,0 +1,74 @@
1
+# LSP Test 4: Go to Definition (F12 or Ctrl+Click)
2
+# =================================================
3
+#
4
+# Instructions:
5
+# 1. Place cursor on a symbol (function, class, variable)
6
+# 2. Press F12 to jump to its definition
7
+# 3. This works for:
8
+#    - Functions defined in this file
9
+#    - Classes defined in this file
10
+#    - Imported modules/functions
11
+#    - Variables (jumps to assignment)
12
+#
13
+# Try going to definition on the marked symbols:
14
+
15
+
16
+def helper_function(x: int) -> int:
17
+    """A helper function defined at the top of the file."""
18
+    return x * 2
19
+
20
+
21
+class DataProcessor:
22
+    """A class for processing data."""
23
+
24
+    def __init__(self, data: list):
25
+        self.data = data
26
+
27
+    def process(self) -> list:
28
+        """Process the data and return results."""
29
+        return [self.transform(item) for item in self.data]
30
+
31
+    def transform(self, item):
32
+        """Transform a single item."""
33
+        return item * 2
34
+
35
+
36
+# Test 1: Go to function definition
37
+# Place cursor on "helper_function" and press F12
38
+result = helper_function(42)  # <- F12 on helper_function
39
+
40
+# Test 2: Go to class definition
41
+# Place cursor on "DataProcessor" and press F12
42
+processor = DataProcessor([1, 2, 3])  # <- F12 on DataProcessor
43
+
44
+# Test 3: Go to method definition
45
+# Place cursor on "process" and press F12
46
+output = processor.process()  # <- F12 on process
47
+
48
+# Test 4: Go to variable definition
49
+# Place cursor on "result" below and press F12
50
+print(result)  # <- F12 on result (should go to line 31)
51
+
52
+# Test 5: Go to imported function definition
53
+# Place cursor on "path" and press F12
54
+from os import path
55
+exists = path.exists("/tmp")  # <- F12 on path or exists
56
+
57
+# Test 6: Go to standard library
58
+# Place cursor on "print" and press F12 (may open stdlib)
59
+print("hello")  # <- F12 on print
60
+
61
+
62
+# Nested definitions for testing
63
+def outer_function():
64
+    """Outer function containing nested definitions."""
65
+
66
+    def inner_function():
67
+        """Inner function."""
68
+        return "inner"
69
+
70
+    return inner_function()
71
+
72
+
73
+# Test 7: Go to nested function
74
+nested_result = outer_function()  # <- F12 on outer_function
test_lsp/05_references.pyadded
@@ -0,0 +1,81 @@
1
+# LSP Test 5: Find References (Shift+F12)
2
+# ========================================
3
+#
4
+# Instructions:
5
+# 1. Place cursor on a symbol
6
+# 2. Press Shift+F12 to find all references
7
+# 3. A list of locations should appear
8
+# 4. Navigate the list to jump to each reference
9
+#
10
+# This file has symbols used multiple times for testing:
11
+
12
+
13
+# A function that is called multiple times
14
+def calculate(value: int) -> int:
15
+    """Calculate something with the value."""
16
+    return value * 2 + 1
17
+
18
+
19
+# Test: Find all references to "calculate"
20
+# Place cursor on any "calculate" and press Shift+F12
21
+result1 = calculate(10)
22
+result2 = calculate(20)
23
+result3 = calculate(30)
24
+combined = calculate(result1) + calculate(result2)
25
+
26
+
27
+# A class used in multiple places
28
+class Counter:
29
+    """A simple counter class."""
30
+
31
+    def __init__(self):
32
+        self.count = 0
33
+
34
+    def increment(self):
35
+        self.count += 1
36
+
37
+    def get_count(self):
38
+        return self.count
39
+
40
+
41
+# Test: Find all references to "Counter"
42
+counter1 = Counter()
43
+counter2 = Counter()
44
+counters = [Counter(), Counter(), Counter()]
45
+
46
+# Test: Find all references to "increment"
47
+counter1.increment()
48
+counter1.increment()
49
+counter2.increment()
50
+for c in counters:
51
+    c.increment()
52
+
53
+
54
+# A variable used throughout
55
+MULTIPLIER = 10
56
+
57
+# Test: Find all references to "MULTIPLIER"
58
+value1 = 5 * MULTIPLIER
59
+value2 = 3 * MULTIPLIER
60
+value3 = MULTIPLIER * MULTIPLIER
61
+
62
+
63
+def use_multiplier(x):
64
+    return x * MULTIPLIER
65
+
66
+
67
+# A parameter used multiple times in a function
68
+def process_data(data):
69
+    """Process data in multiple ways."""
70
+    # Test: Find references to "data" parameter
71
+    if data is None:
72
+        return None
73
+    length = len(data)
74
+    first = data[0] if data else None
75
+    last = data[-1] if data else None
76
+    return {"data": data, "length": length, "first": first, "last": last}
77
+
78
+
79
+# Call the function
80
+process_data([1, 2, 3])
81
+process_data(["a", "b", "c"])
test_lsp/06_rename.pyadded
@@ -0,0 +1,88 @@
1
+# LSP Test 6: Rename Symbol (F2)
2
+# ===============================
3
+#
4
+# Instructions:
5
+# 1. Place cursor on a symbol you want to rename
6
+# 2. Press F2 to start rename
7
+# 3. Type the new name in the prompt
8
+# 4. Press Enter to apply the rename
9
+# 5. All references should be updated automatically
10
+#
11
+# WARNING: This modifies the file! You may want to save a backup first.
12
+# Use Ctrl+Z to undo if needed.
13
+
14
+
15
+# Test 1: Rename a function
16
+# Place cursor on "old_function_name" and press F2
17
+# Try renaming it to "new_function_name"
18
+def old_function_name(x):
19
+    """A function with a name that should be renamed."""
20
+    return x + 1
21
+
22
+
23
+result1 = old_function_name(10)
24
+result2 = old_function_name(20)
25
+result3 = old_function_name(old_function_name(5))
26
+
27
+
28
+# Test 2: Rename a class
29
+# Place cursor on "OldClassName" and press F2
30
+class OldClassName:
31
+    """A class that should be renamed."""
32
+
33
+    def __init__(self, value):
34
+        self.value = value
35
+
36
+
37
+obj1 = OldClassName(100)
38
+obj2 = OldClassName(200)
39
+instances = [OldClassName(i) for i in range(5)]
40
+
41
+
42
+# Test 3: Rename a variable
43
+# Place cursor on "counter" and press F2
44
+counter = 0
45
+counter += 1
46
+counter += 1
47
+print(counter)
48
+if counter > 0:
49
+    counter = counter * 2
50
+
51
+
52
+# Test 4: Rename a method
53
+# Place cursor on "old_method" and press F2
54
+class MyClass:
55
+    def old_method(self):
56
+        """Method to be renamed."""
57
+        return "old"
58
+
59
+    def caller(self):
60
+        return self.old_method()
61
+
62
+
63
+instance = MyClass()
64
+instance.old_method()
65
+result = instance.old_method()
66
+
67
+
68
+# Test 5: Rename a parameter
69
+# Place cursor on "param" and press F2
70
+def function_with_param(param):
71
+    """Function with a parameter to rename."""
72
+    if param is None:
73
+        return 0
74
+    return param * 2 + param
75
+
76
+
77
+function_with_param(10)
78
+function_with_param(param=20)
79
+
80
+
81
+# Test 6: Rename a constant
82
+# Place cursor on "MAX_VALUE" and press F2
83
+MAX_VALUE = 100
84
+
85
+if result1 < MAX_VALUE:
86
+    print("Under limit")
87
+
88
+threshold = MAX_VALUE // 2
test_lsp/07_formatting.pyadded
@@ -0,0 +1,72 @@
1
+# LSP Test 7: Code Formatting (Ctrl+Shift+F)
2
+# ==========================================
3
+#
4
+# Instructions:
5
+# 1. Press Ctrl+Shift+F to format the entire file
6
+# 2. The LSP server (ruff or black via pylsp) will reformat the code
7
+# 3. Observe the changes in whitespace, line breaks, etc.
8
+#
9
+# This file has intentionally poor formatting for testing:
10
+
11
+x=1+2+3
12
+y    =    4    *    5
13
+z=x+y
14
+
15
+def badly_formatted(   a,b,c   ):
16
+    return a+b+c
17
+
18
+result=badly_formatted(1,2,3)
19
+
20
+my_list=[1,2,3,4,5,6,7,8,9,10]
21
+my_dict={"key1":"value1","key2":"value2","key3":"value3"}
22
+
23
+class BadlyFormatted:
24
+    def __init__(self,x,y):
25
+        self.x=x
26
+        self.y=y
27
+    def method(self):
28
+        return self.x+self.y
29
+
30
+if x>0:
31
+    print("positive")
32
+elif x<0:
33
+    print("negative")
34
+else:
35
+    print("zero")
36
+
37
+for i in range(10):
38
+    if i%2==0:
39
+        print(i)
40
+
41
+data=[{"name":"alice","age":30},{"name":"bob","age":25},{"name":"charlie","age":35}]
42
+
43
+long_string="this is a very long string that should probably be wrapped or reformatted in some way by the formatter"
44
+
45
+# Inconsistent quotes
46
+single = 'single quotes'
47
+double = "double quotes"
48
+mixed = 'mixed' + "quotes"
49
+
50
+# Extra blank lines
51
+
52
+
53
+
54
+# and missing blank lines
55
+def func1():
56
+    pass
57
+def func2():
58
+    pass
59
+def func3():
60
+    pass
61
+
62
+# Trailing whitespace on next line (may not be visible):
63
+x = 1
64
+
65
+# Long function call
66
+result = some_function_with_long_name(argument1, argument2, argument3, argument4, argument5, argument6)
67
+
68
+# Lambda
69
+f=lambda x:x*2
70
+
71
+# Comprehension
72
+squares=[x**2 for x in range(10)if x%2==0]
test_lsp/08_multi_cursor.pyadded
@@ -0,0 +1,121 @@
1
+# Multi-Cursor Test: Ctrl+D Select Next Match
2
+# =============================================
3
+#
4
+# Instructions:
5
+# 1. Place cursor on any word (e.g., "value" below)
6
+# 2. Press Ctrl+D to select that word
7
+# 3. Press Ctrl+D again to select the next occurrence and add a cursor
8
+# 4. Keep pressing Ctrl+D to select all occurrences
9
+# 5. Now type to replace all selected occurrences at once!
10
+# 6. Press Escape to collapse back to a single cursor
11
+#
12
+# Other multi-cursor shortcuts:
13
+# - Ctrl+Alt+Up: Add cursor above
14
+# - Ctrl+Alt+Down: Add cursor below
15
+# - Ctrl+Click: Add/remove cursor at click position
16
+# - Escape: Collapse to single cursor
17
+#
18
+# Test Area - Try selecting "value" with repeated Ctrl+D:
19
+
20
+value = 10
21
+another_value = value * 2
22
+third_value = value + another_value
23
+print(f"The value is {value}")
24
+
25
+def process_value(value):
26
+    """Process the value and return a new value."""
27
+    return value * value
28
+
29
+result = process_value(value)
30
+final_value = result + value
31
+
32
+
33
+# Test with "item" - has many occurrences:
34
+
35
+items = ["apple", "banana", "cherry"]
36
+
37
+for item in items:
38
+    print(item)
39
+    process_item(item)
40
+    if item == "banana":
41
+        special_item = item
42
+
43
+def process_item(item):
44
+    """Process a single item."""
45
+    return item.upper()
46
+
47
+first_item = items[0]
48
+last_item = items[-1]
49
+
50
+
51
+# Test with "count" - various contexts:
52
+
53
+count = 0
54
+max_count = 100
55
+
56
+while count < max_count:
57
+    count += 1
58
+    if count % 10 == 0:
59
+        print(f"count = {count}")
60
+
61
+final_count = count
62
+print(f"Final count: {final_count}")
63
+
64
+
65
+# Test with "data" - in a class:
66
+
67
+class DataProcessor:
68
+    def __init__(self, data):
69
+        self.data = data
70
+        self.processed_data = None
71
+
72
+    def process(self):
73
+        self.processed_data = self.transform_data(self.data)
74
+        return self.processed_data
75
+
76
+    def transform_data(self, data):
77
+        return [x * 2 for x in data]
78
+
79
+    def get_data(self):
80
+        return self.data
81
+
82
+processor = DataProcessor([1, 2, 3])
83
+data = processor.get_data()
84
+new_data = processor.process()
85
+
86
+
87
+# Test with "name" - strings and variables:
88
+
89
+name = "Alice"
90
+user_name = name
91
+full_name = f"{name} Smith"
92
+
93
+def greet_by_name(name):
94
+    print(f"Hello, {name}!")
95
+    return f"Greeted {name}"
96
+
97
+greet_by_name(name)
98
+greet_by_name("Bob")  # Different name
99
+
100
+names = [name, "Bob", "Charlie"]
101
+for n in names:
102
+    print(f"Name: {n}")
103
+
104
+
105
+# Test edge cases:
106
+
107
+# Same word at start and end of line
108
+test test test test test
109
+
110
+# Word appears in comments too
111
+# The word appears here and in code: word = "word"
112
+word = "word"
113
+print(word)  # prints the word
114
+
115
+
116
+# Numbers and underscores in identifiers:
117
+var_1 = 100
118
+var_2 = var_1 + var_1
119
+var_3 = var_1 * 2
120
+
121
+my_var_1 = var_1
test_lsp/README.mdadded
@@ -0,0 +1,47 @@
1
+# LSP Test Files for fackr
2
+
3
+This directory contains Python files for testing LSP (Language Server Protocol)
4
+features in the fackr editor.
5
+
6
+## Prerequisites
7
+
8
+Make sure you have a Python LSP server installed:
9
+- `pylsp` (python-lsp-server): `pip install python-lsp-server`
10
+- `ruff`: `pip install ruff` (for linting/formatting)
11
+- `pyright`: `pip install pyright` (for type checking)
12
+
13
+## Test Files
14
+
15
+| File | Feature | Keybinding |
16
+|------|---------|------------|
17
+| 01_hover.py | Hover Information | F1 |
18
+| 02_completion.py | Code Completion | Ctrl+Space |
19
+| 03_diagnostics.py | Diagnostics | Automatic |
20
+| 04_goto_definition.py | Go to Definition | F12 |
21
+| 05_references.py | Find References | Shift+F12 |
22
+| 06_rename.py | Rename Symbol | F2 |
23
+| 07_formatting.py | Code Formatting | Ctrl+Shift+F |
24
+
25
+## How to Test
26
+
27
+1. Open fackr: `fackr test_lsp/01_hover.py`
28
+2. Follow the instructions in the comments at the top of each file
29
+3. Each file is self-contained and tests a specific LSP feature
30
+
31
+## LSP Keybindings Reference
32
+
33
+| Key | Action |
34
+|-----|--------|
35
+| F1 | Show hover information |
36
+| Ctrl+Space | Trigger code completion |
37
+| F12 | Go to definition |
38
+| Shift+F12 | Find all references |
39
+| F2 | Rename symbol |
40
+| Ctrl+Shift+F | Format document |
41
+| Alt+M | Open LSP server manager |
42
+
43
+## Troubleshooting
44
+
45
+- If LSP features don't work, check that the language server is running
46
+- Use Alt+M to open the server manager and verify server status
47
+- Some features may take a moment to initialize when first opening a file