Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
7350a27
Renewed reporting
anngoroshi Aug 7, 2025
e040979
Fixed visualization in plotting of two graphics in 2d
anngoroshi Aug 8, 2025
821eae7
Fixed visualization in plotting of two graphics in 2d and added test …
anngoroshi Aug 8, 2025
f49bcb8
Renamed report.py
anngoroshi Aug 8, 2025
e28020f
added reporting by selecting test cases
anngoroshi Aug 8, 2025
10d32a0
added folder for reports
anngoroshi Aug 8, 2025
71378f1
added documentation page that describes how to use it.
anngoroshi Aug 8, 2025
0e78f3f
deleted unused import
anngoroshi Aug 11, 2025
f8a4a9a
added 3D visualization
anngoroshi Aug 11, 2025
625c48e
some small changes in texts
anngoroshi Aug 11, 2025
1dae499
some small changes in texts
anngoroshi Aug 11, 2025
f1c29fc
added embedding's filter for requirements
anngoroshi Aug 12, 2025
b2faa3b
added embeddings to test cases and filtering by them in report
anngoroshi Aug 13, 2025
d2d7fb2
added new and missed tests for embeddings
anngoroshi Aug 18, 2025
77a70c9
fixed small mistakes
anngoroshi Aug 19, 2025
71ccbc3
Merge branch 'master' into fixed#8-better-reporting
anngoroshi Aug 19, 2025
a50cf1e
merge with master
anngoroshi Aug 19, 2025
7b12c31
remove unused imports
anngoroshi Aug 19, 2025
1e9b74a
fixed formatting
anngoroshi Aug 19, 2025
a513d6f
improved documentation
anngoroshi Aug 19, 2025
8c9032e
updated documentation and README.md
anngoroshi Aug 20, 2025
4c99fac
added with operator for DBClient
anngoroshi Aug 20, 2025
a307b36
fixed documentation formatting
anngoroshi Aug 20, 2025
efd6bdb
added functions for counting entries
anngoroshi Aug 20, 2025
f4edf02
updated pyproject.toml
anngoroshi Aug 20, 2025
413e04c
fix some small mistakes
anngoroshi Aug 21, 2025
e9d00b2
fixed a text wrapping in radio boxes
anngoroshi Aug 21, 2025
a1ebd2e
fixed pyproject.toml
anngoroshi Aug 21, 2025
8f4cb3c
fixed formatting
anngoroshi Aug 21, 2025
9b7575b
fixed round distance and removed extra columns
anngoroshi Aug 21, 2025
38a02ec
fixed formatting
anngoroshi Aug 21, 2025
83a1c19
fixed controls page
anngoroshi Aug 21, 2025
1433462
removed tc id, added req summary to selectbox
anngoroshi Aug 21, 2025
de73623
added labels to plots
anngoroshi Aug 21, 2025
15e4a28
fixed formatting
anngoroshi Aug 21, 2025
3846c00
removed all sql text to services/db/client.py
anngoroshi Aug 21, 2025
b12c228
removed all sql text to services/db/client.py from tests
anngoroshi Aug 21, 2025
bc466b8
fixed formatting
anngoroshi Aug 21, 2025
b9338c6
fixed new methods in client.py
anngoroshi Aug 22, 2025
58b82c0
fixed extra fetches
anngoroshi Aug 22, 2025
4db9b3e
fixed formatting
anngoroshi Aug 22, 2025
fb83cd7
fixed extra fetches
anngoroshi Aug 22, 2025
73b513f
fixed extra import
anngoroshi Aug 22, 2025
53436df
fixed annotation's labels
anngoroshi Aug 22, 2025
298fa94
fixed annotation's labels
anngoroshi Aug 22, 2025
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ To install the dependencies, run the following command:
uv sync
```

To bring a code to a single format:

```bash
uvx ruff format
```

### PyTorch version

PyTorch is default set to CPU distributive:
Expand Down
86 changes: 44 additions & 42 deletions convert_trace_annos.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,52 @@ def is_empty(value):
return True if value == EMPTY else False


def trace_test_cases_to_annos(db_path: Path, trace_file_path: Path):
db = get_db_client()

insertions = list()
logger.info("Reading trace file and inserting annotations into table...")
with open(trace_file_path, mode="r", newline="", encoding="utf-8") as trace_file:
reader = csv.reader(trace_file)
current_tc = EMPTY
concat_summary = EMPTY
test_script = EMPTY
global_columns = next(reader)
for row in reader:
if row[0] == "TestCaseStart":
current_tc = row[1]
test_script = EMPTY
concat_summary = EMPTY
next(reader)
elif row[0] == "Summary":
continue
elif row[0] == "TestCaseEnd":
if not is_empty(current_tc) and not is_empty(concat_summary):
case_id = db.test_cases.get_or_insert(
test_script=test_script, test_case=current_tc
)
annotation_id = db.annotations.get_or_insert(summary=concat_summary)
insertions.append(
db.cases_to_annos.insert(
case_id=case_id, annotation_id=annotation_id
def trace_test_cases_to_annos(trace_file_path: Path):
with get_db_client() as db:
insertions = list()
logger.info("Reading trace file and inserting annotations into table...")
with open(
trace_file_path, mode="r", newline="", encoding="utf-8"
) as trace_file:
reader = csv.reader(trace_file)
current_tc = EMPTY
concat_summary = EMPTY
test_script = EMPTY
global_columns = next(reader)
for row in reader:
if row[0] == "TestCaseStart":
current_tc = row[1]
test_script = EMPTY
concat_summary = EMPTY
next(reader)
elif row[0] == "Summary":
continue
elif row[0] == "TestCaseEnd":
if not is_empty(current_tc) and not is_empty(concat_summary):
case_id = db.test_cases.get_or_insert(
test_script=test_script, test_case=current_tc
)
annotation_id = db.annotations.get_or_insert(
summary=concat_summary
)
insertions.append(
db.cases_to_annos.insert(
case_id=case_id, annotation_id=annotation_id
)
)
)
else:
if not is_empty(row[global_columns.index("TestCase")]):
if current_tc != row[global_columns.index("TestCase")]:
current_tc = row[global_columns.index("TestCase")]
if is_empty(test_script) and not is_empty(
row[global_columns.index("TestScript")]
):
test_script = row[global_columns.index("TestScript")]
concat_summary += row[0]
else:
if not is_empty(row[global_columns.index("TestCase")]):
if current_tc != row[global_columns.index("TestCase")]:
current_tc = row[global_columns.index("TestCase")]
if is_empty(test_script) and not is_empty(
row[global_columns.index("TestScript")]
):
test_script = row[global_columns.index("TestScript")]
concat_summary += row[0]

db.conn.commit()
logger.info(
f"Inserted {len(insertions)} testcase-annotations pairs to database. Successful: {sum(insertions)}"
)
logger.info(
f"Inserted {len(insertions)} testcase-annotations pairs to database. Successful: {sum(insertions)}"
)


if __name__ == "__main__":
Expand Down
20 changes: 16 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import streamlit as st

from test2text.pages.documentation import show_documentation
from test2text.pages.upload.annotations import show_annotations
from test2text.pages.upload.requirements import show_requirements
from test2text.pages.controls.controls_page import controls_page
from test2text.pages.report import make_a_report
from test2text.pages.reports.report_by_req import make_a_report
from test2text.pages.reports.report_by_tc import make_a_tc_report
from test2text.services.visualisation.visualize_vectors import visualize_vectors
from test2text.pages.controls.controls_page import controls_page


def add_logo():
Expand Down Expand Up @@ -37,21 +39,31 @@ def add_logo():
)
add_logo()

about = st.Page(
show_documentation, title="About application", icon=":material/info:"
)

annotations = st.Page(
show_annotations, title="Annotations", icon=":material/database_upload:"
)
requirements = st.Page(
show_requirements, title="Requirements", icon=":material/database_upload:"
)
cache_distances = st.Page(controls_page, title="Controls", icon=":material/cached:")
report = st.Page(make_a_report, title="Report", icon=":material/publish:")
report_by_req = st.Page(
make_a_report, title="Requirement's Report", icon=":material/publish:"
)
report_by_tc = st.Page(
make_a_tc_report, title="Test cases Report", icon=":material/publish:"
)
visualization = st.Page(
visualize_vectors, title="Visualize Vectors", icon=":material/dataset:"
)
pages = {
"Home": [about],
"Upload": [annotations, requirements],
"Update": [cache_distances],
"Inspect": [report, visualization],
"Inspect": [report_by_req, report_by_tc, visualization],
}
pg = st.navigation(pages)

Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ name = "test2text"
version = "0.1.0"
description = ""
authors = [
{name = "Nikolai Dorofeev - d0rich",email = "dorich2000@gmail.com"}
{name = "Nikolai Dorofeev - d0rich", email = "dorich2000@gmail.com"},
{name = "Anna Yamkovaya - anngoroshi", email = "avyamkovaya@gmail.com"}
]
readme = "README.md"
requires-python = ">=3.9"
Expand Down
19 changes: 10 additions & 9 deletions test2text/pages/controls/controls_page.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from test2text.services.db import get_db_client


def controls_page():
import streamlit as st
import plotly.express as px

from test2text.services.embeddings.annotation_embeddings_controls import (
count_all_annotations,
count_embedded_annotations,
)

st.header("Controls page")
embedding_col, distances_col = st.columns(2)
with embedding_col:
st.subheader("Embedding")

def refresh_counts():
st.session_state["all_annotations_count"] = count_all_annotations()
st.session_state["embedded_annotations_count"] = (
count_embedded_annotations()
)
with get_db_client() as db:
st.session_state["all_annotations_count"] = db.count_all_entries(
"Annotations"
)
st.session_state["embedded_annotations_count"] = (
db.count_notnull_entries("embedding", from_table="Annotations")
)

refresh_counts()

Expand Down
98 changes: 98 additions & 0 deletions test2text/pages/documentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import streamlit as st

from test2text.services.db import get_db_client


def show_documentation():
st.markdown("""
# Test2Text Application Documentation

## About the Application

**Test2Text** is a tool for computing requirement's coverage by tests and generating relevant reports.
The application provides a convenient interface for analysis the relationships between test cases and requirements.

""")
st.divider()
st.markdown("""
## HOW TO USE

### Upload data
Click :gray-badge[:material/database_upload: Annotations] or :gray-badge[:material/database_upload: Requirements] to upload annotations and requirements from CSV files to the app's database.
Then Annotations and Requirements are loaded and Test cases are linked to Annotations go to the next chapter.

### Renew data
Click :gray-badge[:material/cached: Controls] to transform missed and new texts into numeral vectors (embeddings).
Update distances by embeddings for intelligent matching of Requirements and Annotations.
After distances are refreshed (all Annotations linked with Requirement by distances) go to the next chapter.

### Generate reports
Click :gray-badge[:material/publish: Requirement's Report] or :gray-badge[:material/publish: Test cases Report] to make a report.
Use filters and Smart search based on embeddings to select desired information.
Analyze selected requirements or test cases by plotted distances.
List of all requirements/test cases and their annotations are shown here.

### Visualize saved data
Click :gray-badge[:material/dataset: Visualize vectors] to plot distances between vector representations of all requirements and annotations in multidimensional spaces.

""")
st.divider()
with get_db_client() as db:
st.markdown("""## Database overview""")
table, row_count = st.columns(2)
with table:
st.write("Table name")
with row_count:
st.write("Number of entries")
for table_name, count in db.get_db_full_info.items():
with table:
st.write(table_name)
with row_count:
st.write(count)
st.divider()
st.markdown("""
### Methodology
The application use a pre-trained transformer model from the [sentence-transformers library](https://huggingface.co/sentence-transformers), specifically [nomic-ai/nomic-embed-text-v1](https://huggingface.co/nomic-ai/nomic-embed-text-v1), a model trained to produce high-quality vector embeddings for text.
The model returns, for each input text, a high-dimensional NumPy array (vector) of floating point numbers (the embedding).
This arrays give a possibility to calculate Euclidian distances between test cases annotations and requirements to show how similar or dissimilar the two texts.
""")

st.markdown("""
#### Euclidean (L2) Distance Formula
The Euclidean (L2) distance is a measure of the straight-line distance between two points (or vectors) in a multidimensional space.
It is widely used to compute the similarity or dissimilarity between two vector representations, such as text embeddings.
""")
st.markdown("""
Suppose we have two vectors:
""")
st.latex(r"""
\mathbf{a} = [a_1, a_2, ..., a_n] ,
""")
st.latex(r"""
\mathbf{b} = [b_1, b_2, ..., b_n]
""")

st.markdown("""
The L2 distance between **a** and **b** is calculated as:
""")

st.latex(r"""
L_2(\mathbf{a}, \mathbf{b}) = \sqrt{(a_1 - b_1)^2 + (a_2 - b_2)^2 + \cdots + (a_n - b_n)^2}
""")

st.markdown("""
Or, more compactly:
""")

st.latex(r"""
L_2(\mathbf{a}, \mathbf{b}) = \sqrt{\sum_{i=1}^n (a_i - b_i)^2}
""")

st.markdown("""
- A **smaller L2 distance** means the vectors are more similar.
- A **larger L2 distance** indicates greater dissimilarity.
""")

st.markdown("""
This formula is commonly used for comparing the semantic similarity of embeddings generated from text using models like Sentence Transformers.
""")
Loading