Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kirill's branch #1892

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cdc3e8a
The instrumented code for is_dimension() function and a coverage test…
knikolaevskii Jun 19, 2024
ab9afba
Enhanced test for is_dimension()
knikolaevskii Jun 19, 2024
bb1d1f2
The instrumented code for _commonprefix() function and a coverage tes…
knikolaevskii Jun 19, 2024
f7743cf
Enhanced test for _commonprefix()
knikolaevskii Jun 19, 2024
15f93db
to_dimension unenhanced
Jun 20, 2024
f8e6d56
to_dimension enhanced
Jun 20, 2024
d5af7fd
to_dimension enhanced
Jun 20, 2024
67343f6
merge_processors unenhanced
Jun 20, 2024
6fadf7d
merge_processors enhanced
Jun 20, 2024
e9e7dc6
Edited document.py
DanMalygin Jun 22, 2024
06947d0
Test file for "find_next_matching_line"
DanMalygin Jun 22, 2024
57b6f3e
Test file for "find_prev_matching_line"
DanMalygin Jun 22, 2024
d2a478d
Added extra print statements
DanMalygin Jun 23, 2024
3e6b501
Added extra print statements
DanMalygin Jun 23, 2024
6c4e8c8
Last minor changes
DanMalygin Jun 23, 2024
e7dc22d
Reversed stuff so I can do it again in correct order and paste a good…
DanMalygin Jun 23, 2024
ae26bfd
find_next_matching_line
DanMalygin Jun 23, 2024
dd1c578
find_previous_matching_line
DanMalygin Jun 23, 2024
b71160d
test cases for find_next_matching_line
DanMalygin Jun 23, 2024
5bfd91a
test cases for find_previous_matching_line
DanMalygin Jun 23, 2024
daeccc3
Added modified src and tests
BMatajsz Jun 24, 2024
6110a0f
test_row_col_to_index bug fix
BMatajsz Jun 24, 2024
a7b8ea8
Fixed tests
BMatajsz Jun 24, 2024
3dbcc15
Merge pull request #1 from knikolaevskii/Kirill's-branch
knikolaevskii Jun 26, 2024
e1e7959
Merge pull request #2 from knikolaevskii/Rov's-branch
knikolaevskii Jun 26, 2024
82ec747
Merge pull request #3 from knikolaevskii/Bence's-branch
BMatajsz Jun 26, 2024
76ce491
added branch_coverage_translate
DanMalygin Jun 26, 2024
0b238ac
Merge branch 'master' into Daniil's-branch
BMatajsz Jun 26, 2024
5f8fcd6
Merge pull request #4 from knikolaevskii/Daniil's-branch
BMatajsz Jun 26, 2024
ff98c4b
Minor bug fix
BMatajsz Jun 26, 2024
e490969
Invisible else statements are added to is_dimension function
knikolaevskii Jun 27, 2024
3e6985f
Invisible else statements are added to _commonprefix function
knikolaevskii Jun 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/prompt_toolkit/buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
from .utils import Event, to_str
from .validation import ValidationError, Validator

branch_coverage_insert = {
"insert_1": False, # Branch for copy_margin = True
"insert_2": False, # Branch for copy_margin = False
}

__all__ = [
"EditReadOnlyBuffer",
"Buffer",
Expand Down Expand Up @@ -1179,13 +1184,17 @@ def newline(self, copy_margin: bool = True) -> None:
self.insert_text("\n")

def insert_line_above(self, copy_margin: bool = True) -> None:
"""
Insert a new line above the current one.
"""
"""Insert a new line above the current one."""
global branch_coverage_insert

if copy_margin:
insert = self.document.leading_whitespace_in_current_line + "\n"
branch_coverage_insert["insert_1"] = True
print("Branch 1 was hit!")
else:
insert = "\n"
branch_coverage_insert["insert_2"] = True
print("Branch 2 was hit!")

self.cursor_position += self.document.get_start_of_line_position()
self.insert_text(insert)
Expand Down
18 changes: 17 additions & 1 deletion src/prompt_toolkit/completion/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,17 +422,33 @@ def get_suffix(completion: Completion) -> str:
return _commonprefix([get_suffix(c) for c in completions2])


# Data structures that hold coverage information about the conditional branches
branch_coverage = {
"_commonprefix_1": False, # Branch for checking if not strings
"_commonprefix_2": False, # Branch for comparing characters
"_commonprefix_3": False, # Branch for when the characters do not match
"_commonprefix_3_else": False, # Branch for else case of when the characters match
}

def _commonprefix(strings: Iterable[str]) -> str:
# Similar to os.path.commonprefix
if not strings:
branch_coverage["_commonprefix_1"] = True
print("Branch 1 was hit")
return ""

else:
branch_coverage["_commonprefix_2"] = True
print("Branch 2 was hit")
s1 = min(strings)
s2 = max(strings)

for i, c in enumerate(s1):
if c != s2[i]:
branch_coverage["_commonprefix_3"] = True
print("Branch 3 was hit")
return s1[:i]
else:
branch_coverage["_commonprefix_3_else"] = True
print("Branch 3 was not hit")

return s1
40 changes: 37 additions & 3 deletions src/prompt_toolkit/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,28 @@
from .filters import vi_mode
from .selection import PasteMode, SelectionState, SelectionType

branch_coverage_next = {
"find_next_1": False,
"find_next_2": False,
}

branch_coverage_prev = {
"find_prev_1": False,
"find_prev_2": False
}

branch_coverage_translate = {
"translate_1": False, # Branch for successful try block execution
"translate_2": False, # Branch for entering except block
"translate_3": False, # Branch for IndexError with row < 0
"translate_4": False, # Branch for IndexError with row >= number of lines
"translate_5": False, # Branch for ensuring col is within valid range
}

__all__ = [
"Document",
]


# Regex for finding "words" in documents. (We consider a group of alnum
# characters a word, but also a group of special characters a word, as long as
# it doesn't contain a space.)
Expand Down Expand Up @@ -323,18 +340,30 @@ def translate_row_col_to_index(self, row: int, col: int) -> int:

Negative row/col values are turned into zero.
"""
global branch_coverage_translate

try:
result = self._line_start_indexes[row]
line = self.lines[row]
branch_coverage_translate["translate_1"] = True
print("Try branch was hit!")
except IndexError:
branch_coverage_translate["translate_2"] = True
print("Except branch was hit!")
if row < 0:
result = self._line_start_indexes[0]
line = self.lines[0]
branch_coverage_translate["translate_3"] = True
print("Branch 1 was hit!")
else:
result = self._line_start_indexes[-1]
line = self.lines[-1]
branch_coverage_translate["translate_4"] = True
print("Branch 2 was hit!")

result += max(0, min(col, len(line)))
branch_coverage_translate["translate_5"] = True
print("Result was hit!")

# Keep in range. (len(self.text) is included, because the cursor can be
# right after the end of the text as well.)
Expand Down Expand Up @@ -652,7 +681,7 @@ def find_previous_word_ending(
except StopIteration:
pass
return None

def find_next_matching_line(
self, match_func: Callable[[str], bool], count: int = 1
) -> int | None:
Expand All @@ -664,10 +693,12 @@ def find_next_matching_line(

for index, line in enumerate(self.lines[self.cursor_position_row + 1 :]):
if match_func(line):
branch_coverage_next["find_next_1"] = True
result = 1 + index
count -= 1

if count == 0:
branch_coverage_next["find_next_2"] = True
break

return result
Expand All @@ -683,14 +714,16 @@ def find_previous_matching_line(

for index, line in enumerate(self.lines[: self.cursor_position_row][::-1]):
if match_func(line):
branch_coverage_prev["find_prev_1"] = True
result = -1 - index
count -= 1

if count == 0:
branch_coverage_prev["find_prev_2"] = True
break

return result

def get_cursor_left_position(self, count: int = 1) -> int:
"""
Relative position for cursor left.
Expand Down Expand Up @@ -1180,3 +1213,4 @@ def insert_before(self, text: str) -> Document:
cursor_position=self.cursor_position + len(text),
selection=selection_state,
)

59 changes: 53 additions & 6 deletions src/prompt_toolkit/layout/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,37 +182,84 @@ def max_layout_dimensions(dimensions: list[Dimension]) -> Dimension:
Callable[[], Any],
]

from typing import Any, Callable, Union

to_dimension_coverage = {
"to_dimension_1": False,
"to_dimension_2": False,
"to_dimension_3": False,
"to_dimension_4": False,
"to_dimension_5": False
}

def to_dimension(value: AnyDimension) -> Dimension:
"""
Turn the given object into a `Dimension` object.
"""
if value is None:
to_dimension_coverage["to_dimension_1"] = True
print("Branch 1 was hit")
return Dimension()
if isinstance(value, int):
to_dimension_coverage["to_dimension_2"] = True
print("Branch 2 was hit")
return Dimension.exact(value)
if isinstance(value, Dimension):
to_dimension_coverage["to_dimension_3"] = True
print("Branch 3 was hit")
return value
if callable(value):
to_dimension_coverage["to_dimension_4"] = True
print("Branch 4 was hit")
return to_dimension(value())

to_dimension_coverage["to_dimension_5"] = True
print("Branch 5 was hit")
raise ValueError("Not an integer or Dimension object.")


def is_dimension(value: object) -> TypeGuard[AnyDimension]:
"""
Test whether the given value could be a valid dimension.
(For usage in an assertion. It's not guaranteed in case of a callable.)
"""
# Initialize coverage tracking global variable
branch_coverage = {
"is_dimension_1": False, # Branch for checking if value is None
"is_dimension_1_else": False, # Branch for else case of checking if value is None
"is_dimension_2": False, # Branch for checking if value is callable
"is_dimension_2_else": False, # Branch for else case of checking if value is callable
"is_dimension_3": False, # Branch for checking if value is int or Dimension
"is_dimension_3_else": False, # Branch for else case of checking if value is int or Dimension
"is_dimension_4": False # Branch for default case
}

def is_dimension(value: object) -> bool:
if value is None:
branch_coverage["is_dimension_1"] = True
print("Branch 1 was hit")
return True
else:
branch_coverage["is_dimension_1_else"] = True
print("Branch 1 was not hit")

if callable(value):
return True # Assume it's a callable that doesn't take arguments.
branch_coverage["is_dimension_2"] = True
print("Branch 2 was hit")
return True
else:
branch_coverage["is_dimension_2_else"] = True
print("Branch 2 was not hit")

if isinstance(value, (int, Dimension)):
branch_coverage["is_dimension_3"] = True
print("Branch 3 was hit")
return True
else:
branch_coverage["is_dimension_3_else"] = True
print("Branch 3 was not hit")

branch_coverage["is_dimension_4"] = True
print("Branch 4 was hit")
return False



# Common alias.
D = Dimension

Expand Down
9 changes: 9 additions & 0 deletions src/prompt_toolkit/layout/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,16 +943,25 @@ def apply_transformation(self, ti: TransformationInput) -> Transformation:
return processor.apply_transformation(ti)


merge_processors_coverage = {
"merge_processors_1": False, # Branch for empty list of processors
"merge_processors_2": False, # Branch for a single processor
"merge_processors_3": False # Branch for multiple processors
}

def merge_processors(processors: list[Processor]) -> Processor:
"""
Merge multiple `Processor` objects into one.
"""
if len(processors) == 0:
merge_processors_coverage["merge_processors_1"] = True
return DummyProcessor()

if len(processors) == 1:
merge_processors_coverage["merge_processors_2"] = True
return processors[0] # Nothing to merge.

merge_processors_coverage["merge_processors_3"] = True
return _MergedProcessor(processors)


Expand Down
28 changes: 28 additions & 0 deletions tests/test_commonprefix_coverage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from __future__ import annotations
from typing import Iterable, List, Tuple
from prompt_toolkit.completion.base import branch_coverage,_commonprefix

def print_coverage():
print("\nCoverage report:")
hit_branches = sum(branch_coverage.values())
total_branches = len(branch_coverage)
coverage_percentage = (hit_branches / total_branches) * 100
for branch, hit in branch_coverage.items():
print(f"{branch} was {'hit' if hit else 'not hit'}")
print(f"Coverage: {hit_branches}/{total_branches} branches hit ({coverage_percentage:.2f}%)\n")


# Tests
test_cases: List[Tuple[List[str], str]] = [
(["car", "car"], "Test 1: Same words"),
([], "Test 2: Empty list"),
(["car", "dog"], "Test 2: Different words")
]

for strings, description in test_cases:
print(f"\nTesting case: {description} - Input: {strings}")
result = _commonprefix(strings)
print("Common prefix:", result)

print_coverage()

53 changes: 53 additions & 0 deletions tests/test_find_next_matching_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from prompt_toolkit.document import Document, branch_coverage_next

def print_coverage():
print("\nCoverage report:")
hit_branches = sum(branch_coverage_next.values())
total_branches = len(branch_coverage_next)
coverage_percentage = (hit_branches / total_branches) * 100
for branch, hit in branch_coverage_next.items():
print(f"{branch} was {'hit' if hit else 'not hit'}")
print(f"Coverage: {hit_branches}/{total_branches} branches hit ({coverage_percentage:.2f}%)\n")

test_cases = [
{
"description": "Find the second next empty line",
"text": "line 1\n\nline 3\n\nline 5",
"cursor_position": 0,
"match_func": lambda line: line.strip() == "",
"count": 2,
"expected_result": 3
},
{
"description": "No match found",
"text": "line 1\nline 2\nline 3\nline 4",
"cursor_position": 0,
"match_func": lambda line: line.strip() == "",
"count": 1,
"expected_result": None
},
{
"description": "Match after cursor position",
"text": "line 1\nline 2\n\nline 4",
"cursor_position": 7,
"match_func": lambda line: line.strip() == "",
"count": 1,
"expected_result": 1
}
]

for case in test_cases:
document = Document(text=case["text"], cursor_position=case["cursor_position"])
result = document.find_next_matching_line(case["match_func"], case["count"])
assert result == case["expected_result"], f"Test failed for: {case['description']}"

print("\n")
print(f"Test case: {case['description']}")
print(f"Expected result: {case['expected_result']}")
print(f"Actual result: {result}")
print("Branches hit:")
for branch, hit in branch_coverage_next.items():
if hit:
print(f" {branch}")

print_coverage()
Loading
Loading